संकलक डिजाइन में, व्याकरण में क्यों छोड़ दिया जाना चाहिए? मैं पढ़ रहा हूं कि यह इसलिए है क्योंकि यह एक अनंत पुनरावृत्ति का कारण बन सकता है, लेकिन क्या यह सही पुनरावर्ती व्याकरण के लिए भी सही नहीं है?
संकलक डिजाइन में, व्याकरण में क्यों छोड़ दिया जाना चाहिए? मैं पढ़ रहा हूं कि यह इसलिए है क्योंकि यह एक अनंत पुनरावृत्ति का कारण बन सकता है, लेकिन क्या यह सही पुनरावर्ती व्याकरण के लिए भी सही नहीं है?
जवाबों:
बाएं पुनरावर्ती व्याकरण जरूरी एक बुरी चीज नहीं है। ये व्याकरण पहले से ही पार्स किए गए वाक्यांशों का ट्रैक रखने के लिए एक स्टैक का उपयोग करके आसानी से पार्स किए जाते हैं, क्योंकि यह एलआर पार्सर में मामला है ।
स्मरण करें कि CF ग्रामर का बायाँ पुनरावर्ती नियम है :
साथ का एक तत्व और का एक तत्व । (टपल के लिए पूर्ण औपचारिक परिभाषा देखें वहाँ )।वी β वी ∪ Σ ( वी , Σ , आर , एस )
आमतौर पर, वास्तव में टर्मिनलों और गैर-टर्मिनलों का एक क्रम है, और लिए एक अन्य नियम है जहां दाहिने हाथ की तरफ दिखाई नहीं देता है।अल्फा अल्फा
जब भी व्याकरण पार्सर (लेसर से) द्वारा एक नया टर्मिनल प्राप्त किया जाता है, तो इस टर्मिनल को स्टैक के ऊपर धकेल दिया जाता है: इस ऑपरेशन को एक शिफ्ट कहा जाता है ।
जब भी किसी नियम के दाहिने हाथ को स्टैक के शीर्ष पर लगातार तत्वों के समूह द्वारा मिलान किया जाता है, तो इस समूह को एकल तत्व द्वारा प्रतिस्थापित किया जाता है जो वाक्यांश से मेल खाता है। इस प्रतिस्थापन को कमी कहा जाता है ।
सही पुनरावर्ती व्याकरण के साथ, स्टैक अनिश्चित काल तक बढ़ सकता है जब तक कि कमी नहीं होती है, इस प्रकार नाटकीय रूप से पार्स संभावनाओं को सीमित करता है। हालांकि, बाएं पुनरावर्ती लोग संकलक को पहले से ही कटौती करने देंगे (वास्तव में, जितनी जल्दी हो सके)। देखें विकिपीडिया प्रविष्टि अधिक जानकारी के लिए।
इस नियम पर विचार करें:
example : 'a' | example 'b' ;
अब एक एलएल पार्सर पर विचार करें जो 'b'
इस नियम की तरह एक गैर-मिलान स्ट्रिंग से मेल खाने की कोशिश कर रहा है । चूंकि 'a'
यह मेल नहीं खाता, इसलिए यह मिलान करने की कोशिश करेगा example 'b'
। लेकिन ऐसा करने के लिए, इसे मैच करना होगा example
... जो कि पहले स्थान पर करने की कोशिश कर रहा था। यह देखने के लिए हमेशा के लिए कोशिश कर रहा है कि यह मैच हो सकता है अटक गया, क्योंकि यह हमेशा एक ही नियम के टोकन की एक ही धारा से मिलान करने की कोशिश कर रहा है।
इसे रोकने के लिए, आपको या तो दाईं ओर से पार्स करना होगा (जो कि काफी असामान्य है, जहां तक मैंने देखा है, और इसके बजाय समस्या को सही पुनरावृत्ति करेगा), अनुमति दी गई घोंसले के शिकार की मात्रा को सीमित करें, या मेल करें पुनरावृत्ति शुरू होने से पहले एक टोकन तो हमेशा एक आधार मामला होता है (अर्थात्, जहां सभी टोकन का उपभोग किया गया है और अभी भी कोई पूर्ण मैच नहीं है)। चूंकि एक सही-पुनरावर्ती नियम पहले से ही तीसरा करता है, इसलिए इसमें समान समस्या नहीं है।
(मैं अब तक इस सवाल का बहुत पुराना पता है, लेकिन मामले में अन्य लोगों को एक ही सवाल है ...)
क्या आप पुनरावर्ती वंश पार्सर्स के संदर्भ में पूछ रहे हैं? उदाहरण के लिए, व्याकरण के लिए expr:: = expr + term | term
, ऐसा क्यों होता है (बाएं पुनरावर्ती):
// expr:: = expr + term
expr() {
expr();
if (token == '+') {
getNextToken();
}
term();
}
समस्याग्रस्त है, लेकिन यह (सही पुनरावर्ती) नहीं है?
// expr:: = term + expr
expr() {
term();
if (token == '+') {
getNextToken();
expr();
}
}
यह expr()
कॉल के दोनों संस्करणों की तरह दिखता है । लेकिन महत्वपूर्ण अंतर संदर्भ है - जब उस पुनरावर्ती कॉल किया जाता है, तो वर्तमान टोकन।
बाएं पुनरावर्ती मामले में, expr()
लगातार एक ही टोकन के साथ कॉल करता है और कोई प्रगति नहीं होती है। सही पुनरावर्ती मामले में, यह कॉल में इनपुट के कुछ term()
और कॉल करने से पहले PLUS टोकन का उपभोग करता है expr()
। तो इस बिंदु पर, पुनरावर्ती कॉल शब्द को कॉल कर सकता है और फिर यदि परीक्षण फिर से पहुंचने से पहले समाप्त कर सकता है।
उदाहरण के लिए, 2 + 3 + 4. पार्स करने पर विचार करें। बाएं पुनरावर्ती पार्सर expr()
पहले टोकन पर अटकते समय असीम रूप से कॉल करता है , जबकि सही पुनरावर्ती पार्सर expr()
फिर से कॉल करने से पहले "2 +" खपत करता है । दूसरी कॉल expr()
"3 +" से मेल खाती है और expr()
केवल 4 बचे हैं। एक पद के लिए 4 मैच और पार्सिंग किसी भी अधिक कॉल के बिना समाप्त होता है expr()
।
बायसन मैनुअल से:
"किसी भी तरह के अनुक्रम को या तो बाएं पुनरावृत्ति या दाएं पुनरावर्तन का उपयोग करके परिभाषित किया जा सकता है, लेकिन आपको हमेशा बाएं पुनरावृत्ति का उपयोग करना चाहिए , क्योंकि यह किसी भी संख्या के तत्वों के अनुक्रम को बाउंड स्टैक स्पेस के साथ पार्स कर सकता है। राइट रिकर्सन बाइसन स्टैक पर जगह का उपयोग करता है। अनुक्रम में तत्वों की संख्या के अनुपात में, क्योंकि सभी तत्वों को एक बार भी नियम लागू होने से पहले स्टैक पर स्थानांतरित किया जाना चाहिए। आगे की व्याख्या के लिए बाइसन पार्सर एल्गोरिथम देखें। "
http://www.gnu.org/software/bison/manual/html_node/Recursion.html
तो यह पार्सर के एल्गोरिथ्म पर निर्भर करता है, लेकिन जैसा कि अन्य जवाबों में कहा गया है, कुछ पार्सर केवल बाएं पुनरावृत्ति के साथ काम नहीं कर सकते हैं