यह एक बड़ा विषय है, लेकिन ब्रश के बजाय आप एक धूमधाम से "एक किताब पढ़ें, बच्चे"। इसके बजाय मैं ख़ुशी से आपको अपने सिर को उसके चारों ओर लपेटने में मदद करने के लिए संकेत देता हूँ।
अधिकांश संकलक और / या व्याख्याकार इस तरह काम करते हैं:
टोकन : कोड टेक्स्ट को स्कैन करें और इसे टोकन की सूची में तोड़ दें।
यह कदम मुश्किल हो सकता है क्योंकि आप रिक्त स्थान पर स्ट्रिंग विभाजित नहीं कर सकते हैं, आपको यह पहचानना होगा कि if (bar) foo += "a string";
8 टोकन की एक सूची है: WORD, OPEN_PAREN, WORD, CLOSE_PAREN, WORD, ASIGN__DD, STRING_LITERAL, TERMINATOR। जैसा कि आप देख सकते हैं, केवल रिक्त स्थान पर स्रोत कोड को विभाजित करने से काम नहीं चलेगा, आपको प्रत्येक वर्ण को एक अनुक्रम के रूप में पढ़ना होगा, इसलिए यदि आप एक अल्फ़ान्यूमेरिक वर्ण से सामना करते हैं, तो आप तब तक वर्णों को पढ़ते रहते हैं जब तक कि आप एक गैर-अल्फ़ान्यूम वर्ण और उस स्ट्रिंग को हिट नहीं करते हैं अभी पढ़ा है एक बाद में वर्गीकृत किया जा करने के लिए एक शब्द है। आप अपने लिए तय कर सकते हैं कि आपका टोकन कितना दानेदार है: क्या यह "a string"
एक टोकन के रूप में निगलता है, जिसे STRING_LITERAL कहा जाता है, जिसे बाद में पार्स किया जाता है, या क्या यह देखता है"a string"
OPEN_QUOTE, UNPARSED_TEXT, CLOSE_QUOTE, या जो भी हो, यह सिर्फ कई विकल्पों में से एक है, जिसे आपको खुद तय करना है जैसे आप इसे कोड कर रहे हैं।
लेक्स : तो अब आपके पास टोकन की एक सूची है। आपने संभवतः WORD जैसे अस्पष्ट वर्गीकरण के साथ कुछ टोकन को टैग किया है क्योंकि पहले पास के दौरान आप प्रत्येक स्ट्रिंग के संदर्भ को जानने की कोशिश में बहुत अधिक प्रयास खर्च नहीं करते हैं। तो अब आप स्रोत के टोकन की फिर से सूची को पढ़ें और अपनी भाषा में कीवर्ड के आधार पर अधिक विशिष्ट टोकन प्रकार के साथ प्रत्येक अस्पष्ट टोकन को पुन: लिखें। तो आपके पास एक WORD है जैसे कि "if", और "if" यदि आपके द्वारा बनाए गए विशेष कीवर्ड्स की सूची में है, जिसे IF कहा जाता है, तो आप WORD से IF तक के प्रतीक प्रकार को बदल दें, और कोई भी WORD जो आपके विशेष कीवर्ड सूची में नहीं है , जैसे WORD foo, एक IDENTIFIER है।
पार्स : तो अब आप बदल गया if (bar) foo += "a string";
lexed टोकन कि इस तरह दिखता है की एक सूची: यदि OPEN_PAREN पहचानकर्ता CLOSE_PAREN IDENTIFIER ASIGN_ADD STRING_LITERAL TERMINATOR। कदम बयानों के रूप में टोकन के दृश्यों को पहचान रहा है। यह पार्सिंग है। आप ऐसा व्याकरण का उपयोग करके करते हैं जैसे:
STATEMENT: = ASIGN_EXPRESSION | IF_STATEMENT
IF_STATEMENT: = IF, PAREN_EXPRESSION, STATEMENT
ASIGN_EXPRESSION: = IDENTIFIER, ASIGN_OP, मूल्य
PAREN_EXPRESSSION: = OPEN_PAREN, VALUE, CLOSE_PAREN
VALUE: = IDENTIFIER | STRING_LITERAL | PAREN_EXPRESSION
ASIGN_OP: = EQUAL | ASIGN_ADD | ASIGN_SUBTRACT | ASIGN_MULT
जो प्रोडक्शंस "का उपयोग करते हैं।" शब्दों के बीच का अर्थ है "इनमें से किसी से भी मिलान करें", यदि यह शर्तों के बीच कॉमा हैं तो इसका अर्थ है "शब्दों के इस क्रम से मेल खाएं"
आप इसका उपयोग कैसे करते हैं? पहले टोकन से शुरू करते हुए, इन प्रस्तुतियों के साथ टोकन के अपने क्रम से मिलान करने का प्रयास करें। इसलिए पहले आप STATEMENT के साथ अपनी टोकन सूची का मिलान करने का प्रयास करें, इसलिए आप STATEMENT के लिए नियम पढ़ें और यह कहता है कि "STATEMENT या तो ASIGN_EXPRESSION या IF_STATEMENT" है, इसलिए आप पहले ASAS_EXPRESSION से मिलान करने का प्रयास करें, इसलिए आप ASIGN_EXPRESSION के लिए व्याकरण नियम देखें। और यह कहता है "ASIGN_EXPRESSION एक IDENTIFIER है जिसके बाद एक ASUE_OP है, जिसके बाद एक VALUE है, इसलिए आप IDENTIFIER के लिए व्याकरण नियम की खोज करते हैं और आप देखते हैं कि IDFIFIER के लिए कोई व्याकरण रूक नहीं है, इसलिए IDENTIFIER का अर्थ है" टर्मिनल "जिसका अर्थ है कि इसे आगे की आवश्यकता नहीं है" इसे मिलान करने के लिए पार्स करना ताकि आप इसे अपने टोकन से सीधे मिलान करने का प्रयास कर सकें। लेकिन आपका पहला स्रोत टोकन एक IF है, और IF एक IDENTIFIER के समान नहीं है इसलिए मैच विफल हो गया। अब क्या? आप स्थिति नियम पर वापस जाते हैं और अगले कार्यकाल से मेल खाने का प्रयास करते हैं: IF_STATEMENT। यदि आप IF_STATEMENT देख रहे हैं, तो यह IF के साथ शुरू होता है, IF, लुकअप IF है, यदि टर्मिनल है, तो अपने पहले टोकन के साथ टर्मिनल की तुलना करें, यदि टोकन मेल खाता है, तो भयानक चलता रहता है, अगला शब्द PAREN_EXPRESSION है, PAREN_EXPRESSION देखना, यह कोई टर्मिनल नहीं है, यह पहला शब्द क्या है, PAREN_EXPRESSION OPEN_PAREN के साथ शुरू होता है, OPEN_PAREN को देखते हुए, यह एक टर्मिनल है, OPEN_PAREN को अपने अगले टोकन से मिलाएं, यह मेल खाता है, .... और इसी तरह।
इस चरण को प्राप्त करने का सबसे आसान तरीका यह है कि आपके पास एक फ़ंक्शन है जिसे पार्स () कहा जाता है, जिसे आप इसे स्रोत कोड टोकन देते हैं जिसे आप मिलान करने की कोशिश कर रहे हैं और व्याकरण शब्द जिसे आप इसके साथ मिलान करने का प्रयास कर रहे हैं। यदि व्याकरण शब्द टर्मिनल नहीं है, तो आप पुनरावृत्ति करते हैं: आप पार्स () को फिर से उसी स्रोत टोकन और इस व्याकरण नियम के पहले कार्यकाल को पारित करते हैं। यही कारण है कि इसे एक "पुनरावर्ती वंश पार्सर" कहा जाता है। पार्स () फ़ंक्शन रिटर्न (या संशोधित) स्रोत टोकन को पढ़ने में आपकी वर्तमान स्थिति, यह अनिवार्य रूप से मिलान क्रम में अंतिम टोकन वापस करता है, और आप अगले कॉल को जारी रखते हैं वहाँ से पार्स ()।
हर बार पार्स () ASIGN_EXPRESSION जैसे एक उत्पादन से मेल खाता है जो आप उस कोड का प्रतिनिधित्व करते हुए एक संरचना बनाते हैं। इस संरचना में मूल स्रोत टोकन के संदर्भ शामिल हैं। आप इन संरचनाओं की एक सूची बनाना शुरू करते हैं। हम इस पूरे ढांचे को सार सिंटैक्स ट्री (एएसटी) कहेंगे
संकलन और / या निष्पादित करें : अपने व्याकरण में कुछ प्रस्तुतियों के लिए आपने हैंडलर फ़ंक्शंस बनाए हैं जो यदि एक एएसटी संरचना को दिए गए हैं तो यह एएसटी के उस भाग को संकलित या निष्पादित करेगा।
तो आइए आपके एएसटी के टुकड़े को देखें जिसमें ASIGN_ADD टाइप है। तो एक दुभाषिया के रूप में आपके पास ASIGN_ADD_execute () फ़ंक्शन है। इस फ़ंक्शन को एएसटी के टुकड़े के रूप में पारित किया जाता है जो पार्स ट्री से मेल खाता है foo += "a string"
, इसलिए यह फ़ंक्शन उस संरचना को देखता है और यह जानता है कि संरचना में पहला शब्द एक IDENTIFIER होना चाहिए, और दूसरा शब्द VALUE है, इसलिए ASIGN_DD_execute () VALUE_eval () फ़ंक्शन के लिए VALUE शब्द को पास करता है, जो स्मृति में मूल्यांकित मान का प्रतिनिधित्व करने वाली एक वस्तु देता है, फिर ASIGN_ADD_execute () आपके चर तालिका में "foo" की खोज करता है, और eval_value () द्वारा जो कुछ भी लौटाया गया था, उसका संदर्भ संग्रहीत करता है समारोह।
वह एक दुभाषिया है। एक संकलक के बजाय हैंडलर के कार्य एएसटी को बाइट कोड या मशीन कोड में निष्पादित करने के बजाय अनुवाद करेंगे।
चरण 1 से 3, और कुछ 4, फ्लेक्स और बाइसन जैसे उपकरणों का उपयोग करके आसान बनाया जा सकता है। (उर्फ। लेक्स और याक) लेकिन स्क्रैच से अपने आप को एक दुभाषिया लिखना संभवत: सबसे सशक्त अभ्यास है जिसे कोई भी प्रोग्रामर हासिल कर सकता है। अन्य सभी प्रोग्रामिंग चुनौतियों को समिट-टिंग के बाद तुच्छ लगता है।
मेरी सलाह छोटी है: एक छोटी सी भाषा, एक छोटे से व्याकरण के साथ, और कुछ सरल कथनों को पार्स करने और निष्पादित करने का प्रयास करें, फिर वहां से बढ़ें।
इन्हें पढ़ें, और शुभकामनाएँ!
http://www.iro.umontreal.ca/~felipe/IFT2030-Automne2002/Complements/tinyc.c
http://en.wikipedia.org/wiki/Recursive_descent_parser
lex
,yacc
औरbison
।