2010-05-07 6 views
20

Tim Sweeney एपिक मेगागेम्स का अवास्तविक और programming language geek के लिए अग्रणी डेवलपर है। कई साल पहले VoodooExtreme के लिए निम्न स्क्रीन शॉट पोस्ट:टिम स्वीनी क्या सोच रहा था? (यह सी ++ पार्सर कैसे काम करता है?)

Tim Sweeney's screenshot

एक सी ++ प्रोग्रामर और स्वीनी प्रशंसक के रूप में, मैं इस से मोहित हो गया था। यह जेनेरिक सी ++ कोड दिखाता है जो किसी प्रकार की स्क्रिप्टिंग भाषा लागू करता है जहां वह भाषा खुद को सामान्य रूप से सामान्य मानती है कि यह अपने व्याकरण को परिभाषित कर सकती है।

श्री स्वीनी ने कभी खुद को समझाया नहीं। :-)

टेम्पलेट प्रोग्रामिंग के इस स्तर को देखना दुर्लभ है, लेकिन आप इसे समय-समय पर देखते हैं जब लोग संकलक को महान कोड उत्पन्न करने के लिए धक्का देना चाहते हैं या क्योंकि वे जेनेरिक कोड बनाना चाहते हैं (उदाहरण के लिए, Modern C++ Design)।

टिम Parser.cpp में व्याकरण बनाने के लिए इसका उपयोग कर रहा है - आप देख सकते हैं कि प्राथमिकता वाले बाइनरी ऑपरेटरों की तरह क्या दिखता है। यदि ऐसा है, तो Test.ae ऐसा क्यों दिखता है भी व्याकरण को परिभाषित करता है?

स्पष्ट रूप से यह एक पहेली है जिसे हल करने की आवश्यकता है। विजय इस कोड के एक वर्किंग वर्जन, या सबसे व्यावहारिक स्पष्टीकरण के साथ जवाब देती है, या टिम स्वीनी खुद को जवाब देती है। :-)

+9

मुझे लगता है कि विषय/रंग चौंकाने वाला हैं। अन्यथा, दिलचस्प सवाल है। – ChristopheD

+1

@ क्रिस्टोफेड हाहा हाँ। उस समय मैं इतना प्रशंसक था कि मैंने अपना डेस्कटॉप बदल दिया - यह होना चाहिए कि कैसे * वास्तविक * प्रोग्रामर काम करते थे! मैंने हमेशा सोचा कि क्या वह सिर्फ मजाक कर रहा था। और मैंने जो तस्वीर पोस्ट की है, वह फसल है, यहां पूरी बात है: http://praeclarum.org/so/sweeney-full.png –

+2

शायद वह जेडजेड-ओओपी के अगली पीढ़ी के संस्करण पर काम कर रहा था ... :) http : //en.wikipedia.org/wiki/ZZT-oop –

उत्तर

3

निश्चित रूप से नहीं बता सकता है, लेकिन सी ++ कोड थोडा सॉर्टा Spirit जैसा दिखता है, एक सी ++ पार्सर जेनरेटर जो टेम्पलेट्स का व्यापक उपयोग करता है। Test.ae ऐसा लगता है कि यह मेटाप्रोग्रामिंग (भाषा में भाषा विवरण परिभाषित करना) है, जो सी ++ में करना कठिन है (टेम्पलेट्स एक शुरुआत है, लेकिन त्रुटि प्रवण और बदसूरत है) यह किसी अन्य लक्ष्य भाषा में होगी (उदाहरण के लिए, अवास्तविक स्क्रिप्ट , जो मुझे लगता है कि test.ae लिखा है)।

तो - ऐसा लगता है कि Parser.cpp UnrealScript के लिए आधार व्याकरण को परिभाषित करता है (Spirit का उपयोग करके), और Test.ae अवास्तविक स्क्रिप्ट में एक्सटेंशन को परिभाषित कर रहा है।

+0

जबकि आत्मा और यह कोड दोनों टेम्पलेट का उपयोग करते हैं, वे एक ही लाइब्रेरी नहीं दिखते हैं। या क्या मैं कुछ न कुछ भूल रहा हूं? यह ऐसा नहीं लगता है कि कैसे आत्मा ऑपरेटर प्राथमिकता को हल करती है। और आपकी धारणा गलत नहीं है। ये एई फ़ाइलें अवास्तविक स्क्रिप्ट से एक लंबा रास्ता हैं। इस समय, टिम अवास्तविक स्क्रिप्ट के कंपाइलर को बदलने के बारे में सार्वजनिक रूप से बात कर रहा था, लेकिन यह निश्चित रूप से उस वाक्यविन्यास से एक ब्रेक था। –

+0

मुझे उस मामले के लिए अवास्तविक, या आत्मा के बारे में * कुछ भी नहीं पता है; आत्मा की शैली में सी ++ के लिए कई टेम्पलेट-आधारित पार्सर जेनरेटर हैं। कहा जा रहा है कि, हालांकि, मुझे विश्वास है कि मैंने मेटाप्रोग्रामिंग के सामान्य विचार को सही ढंग से चित्रित किया है; ईरा का जवाब है कि शुद्ध सी ++ टेम्पलेट्स का उपयोग करना बहुत ही अपठनीय त्रुटि संदेशों को संकलित और उत्पन्न करने में धीमा हो सकता है, सी ++ में मूल भाषा को परिभाषित करने का एक और कारण है और फिर मूल भाषा के संदर्भ में उन्नत भाषा को परिभाषित करता है। इस तकनीक को 'बूटस्ट्रैपिंग' के रूप में भी जाना जाता है। –

1

मुझे नहीं पता कि स्वीनी ने क्या किया, और मैं मानता हूं कि आत्मा का उपयोग करने के बारे में अन्य उत्तर सही हैं, ओह, सही भावना। मुझे आत्मा टेम्पलेट्स के साथ कोई अनुभव नहीं है, लेकिन मेरी समझ यह है कि यदि आप इसके साथ एक जटिल व्याकरण को परिभाषित करते हैं, तो इसे संभालना बहुत मुश्किल हो जाता है (साथ ही संकलन धीमा)। इस तथ्य की गवाही देने के लिए अन्य लोगों के वास्तविक अनुभव का उपयोग किया जाना चाहिए।

सी ++ में एक्सटेंशन को लागू करने के अन्य तरीके हैं, उदाहरण के लिए, प्रोग्राम ट्रांसफॉर्मेशन और विस्तारणीय व्याकरण का उपयोग करना। मनमाने ढंग से एक्सटेंशन के साथ this SO answer on augmenting the C++ grammar स्वयं देखें, जहां बहुत ही जटिल एक्सटेंशन संभव हैं और वास्तव में उपयोग किए जाते थे।

टेम्पलेट मेटाप्रोग्रामिंग दिलचस्प कोड उत्पन्न करता है जहां टेम्पलेट्स विशेष रूप से बुलाए जाते हैं। प्रोग्राम ट्रांसफॉर्मेशन का उपयोग करके आप प्रोग्राम में किसी भी बिंदु पर मनमाने ढंग से दिलचस्प कोड उत्पन्न कर सकते हैं, उदाहरण के लिए, जैसे कि "टेम्पलेट्स" (अतिरिक्त वाक्यविन्यास) अर्थशास्त्र को किसी भी तरह से बदलता है जो आपको लगता है उपयोगी है।

1

स्क्रीनशॉट एक MSVC 6.0 या उससे पहले के समय सीमा है, जो वास्तव में जटिल टेम्पलेट्स (और निश्चित रूप से आंशिक टेम्पलेट विशेषज्ञता का समर्थन नहीं किया) की सराहना करते नहीं था से स्पष्ट रूप से है। मैंने आत्मा का उपयोग नहीं किया है। इन स्क्रीनशॉट से, यह कहना असंभव है कि स्वीनी वास्तव में टेस्ट.ए. में डीएसएल की तरह दिखने से परे क्या कर रही है।

केवल पूर्ण सी ++ बयान कि आप देख सकते Parser.cpp में हैं - और वे छोड़कर वह 3 प्रकार की घोषणा है आप कुछ भी की ज्यादा नहीं बताते। आप वास्तव में कुछ भी नहीं बता सकते हैं - 'टेस्ट द्वारा बहुत ज्यादा अस्पष्ट है।ए 'खिड़की।

8

मैं ईमेल के माध्यम से श्री स्वीनी पूछा और इस उत्तर प्राप्त किया: टेम्पलेट वर्गों

सी ++ कोड उपयोग कर रहा है मैं ने लिखा है कि लागू पार्सर संयोजक। विचार कुछ मूल पार्सर्स के साथ शुरू करना है, जैसे कि अक्षर < 'ए'> एक शाब्दिक चरित्र 'ए' पार्स करता है, पैनी <> किसी भी चरित्र को पार करता है लेकिन विफल होने के अंत में विफल रहता है, जब तक हम विफल नहीं होते फ़ाइल के अंत में, आदि। और फिर हम उन्हें पैन जैसे संयोजकों का उपयोग करके मनमाने ढंग से पेड़ में जोड़ते हैं जो एक बी को पार करते हैं, और केवल सफल होते हैं यदि दोनों सफल होते हैं - अन्यथा यह पार्स बिंदु से मुक्त हो जाता है। और यदि यह सफल होता है, तो नतीजा एक संरचना है जिसमें दो फ़ील्ड होते हैं, एक के परिणामस्वरूप, और बी के परिणामस्वरूप एक। और इसी तरह।

कार्यान्वयन कई कारणों से सी ++ में गन्दा है, जिसमें टेम्पलेट्स मनमानी वैरिएडिक पैरामीटर का समर्थन नहीं करते हैं, और बिना प्रथम श्रेणी के लैम्ब्स के हम पार्सर के साथ परिणाम इनलाइन को आसानी से संसाधित नहीं कर सकते हैं।

यहां टेम्पलेट कोड के कुछ स्निपेट हैं, जिनसे आप शायद ढांचे के विवरण को समझ सकते हैं।

// Parses a literal item. 
UBOOL LiteralEvaluate (UClass* C,class FParseInBase& In,class FParseOutBase& Out) 
{ 
FParseInMark M(In); 
NNode* e = In.GetNextSource(); 
if (e && e->IsA(C)) 
{ 
    Out.Callback(e); 
    return 1; 
} 
M.Restore(In); 
return 0; 
} 
// Optional item of the specified type. 
template <class U> struct Optional 
{ 
static UBOOL Evaluate (class FParseInBase& In,FParseOutBase& Out) 
{ 
    U::Evaluate(In,Out); 
    return 1; 
} 
}; 
// Ignore items by absorbing them; retains boolean logic but not callback. 
template <class T> struct Ignore 
{ 
static UBOOL Evaluate (class FParseInBase& In,FParseOutBase& Out) 
{ 
    return T::Evaluate(In,GIgnore); 
} 
}; 
// Zero or more items of the specified type. 
template <class T> struct ZeroOrMore 
{ 
static UBOOL Evaluate (class FParseInBase& In,FParseOutBase& Out) 
{ 
    while (T::Evaluate(In,Out)); 
    return 1; 
} 
}; 
// One or more items of the specified type. 
template <class T> struct OneOrMore 
{ 
static UBOOL Evaluate (class FParseInBase& In,FParseOutBase& Out) 
{ 
    for(INT i=0; T::Evaluate(In,Out); i++); 
    return i>0; 
} 
}; 
// Always fails. 
struct RFalse 
{ 
static UBOOL Evaluate (class FParseInBase& In,FParseOutBase& Out) 
{ 
    return 0; 
} 
}; 
// Always succeeds. 
struct RTrue 
{ 
static UBOOL Evaluate (class FParseInBase& In,FParseOutBase& Out) 
{ 
    return 1; 
} 
}; 
// Parses the first matching items of the specified subtypes of T. 
template <class A,class B=RFalse,class C=RFalse,class D=RFalse > struct Or 
{ 
static UBOOL Evaluate (class FParseInBase& In,FParseOutBase& Out) 
{ 
    return A::Evaluate(In,Out) || B::Evaluate(In,Out) || C::Evaluate(In,Out) || D::Evaluate(In,Out); 
} 
}; 
// Parses all the specified items. 
template <class A,class B=RTrue,class C=RTrue,class D=RTrue> struct And 
{ 
static UBOOL Evaluate (class FParseInBase& In,FParseOutBase& Out) 
{ 
    FParseInMark Mark(In); 
    Conjunction<NNode> Q; 
    if(A::Evaluate(In,Q) && B::Evaluate(In,Q) && C::Evaluate(In,Q) && D::Evaluate(In,Q)) 
    { 
    Q.Forward(Out); 
    return 1; 
    } 
    Mark.Restore(In); 
    return 0; 
} 
}; 
// A separated list. 
template <class A,class B> class SeparatedList : public Or<And<A,B,SeparatedList>,A> {}; 
// Integer comparison. 
template <INT A,INT B> struct IsAtLeast 
{ 
static UBOOL Evaluate (class FParseInBase& In,FParseOutBase& Out) 
{ 
    return A>=B; 
} 
}; 

Test.ae एक प्रयोगात्मक पटकथा भाषा मैं 1999-2001 में लागू करने गया था कि - कि रंग योजना ट्रेंडी था वापस तो, मैं कसम खाता हूँ। :-)

दिखाया गया कोड भाषा संरचनाओं के लिए मेटाडेटा को परिभाषित करता है। भाषा स्मालटाक "सबकुछ एक वस्तु है" मार्ग से एक लंबा रास्ता तय करती है, जो प्रथम श्रेणी के मेटाक्लास और संबंधित मुद्दों से निपटती है, लेकिन अंततः जब मैं हास्केल, केयेन, कोक और अन्य में उन्नत प्रकार के सिस्टम काम से परिचित हो गया तो मैंने इसे छोड़ दिया भाषाओं।

आजकल -

मैं के बाद से कोड हास्केल की तरह एक आधुनिक कार्यात्मक भाषा में एक ऐसी ही कार्यान्वयन की तुलना में 70-80% से फूला हुआ हो जाता है, सी ++ में पारसर्स या compilers को लागू करने के एक प्रशंसक नहीं हूँ। अधिक विस्तार के लिए हास्केल पार्सर संयोजकों पर पढ़ें - परिणामी सादगी और प्रत्यक्षता अनुकरणीय है और यह एक कठोर, प्रकार-सुरक्षित तरीके से किया जाता है।

+0

ओह वाह, मुझे उड़ा दिया गया है। मुझे नहीं पता था कि स्वीनी एक भाषा गीक थी, लेकिन यहां वह 1 999 में पार्सर संयोजक कर रहा है और अब हास्सेल लिखने के लिए हास्केल की सिफारिश कर रहा है। मेरा नया नायक! – CodexArcanum

संबंधित मुद्दे