लेफ्ट रिकर्सन खराब क्यों है?


20

संकलक डिजाइन में, व्याकरण में क्यों छोड़ दिया जाना चाहिए? मैं पढ़ रहा हूं कि यह इसलिए है क्योंकि यह एक अनंत पुनरावृत्ति का कारण बन सकता है, लेकिन क्या यह सही पुनरावर्ती व्याकरण के लिए भी सही नहीं है?


2
आमतौर पर, कंपाइलर टॉप-डाउन पार्सिंग का उपयोग करते हैं। यदि आपके पास बाईं-पुनरावृत्ति है, तो पार्सर एक अनंत पुनरावृत्ति में चला जाता है। हालाँकि, राइट-रिकर्सशन में, पार्सर स्ट्रिंग के उपसर्ग को देख सकता है जो अब तक है। इस प्रकार, यह जांच कर सकता है कि व्युत्पत्ति "बहुत दूर" गई या नहीं। आप निश्चित रूप से, भूमिकाओं की अदला-बदली कर सकते हैं और सही से अभिव्यक्ति की व्याख्या कर सकते हैं, जिससे सही-पुनरावृत्ति खराब हो सकती है, और बाईं-पुनरावृत्ति ठीक हो सकती है।
शाल

6
लेफ्ट रिकर्सन खराब है क्योंकि पुराने दिनों में जब कंप्यूटर में 16 केबी रैम होता था तो सबसे अधिक इस्तेमाल किया जाने वाला पार्सर जनरेटर इसके साथ सामना नहीं कर सकता था।
एंड्रेज बॉयर

जवाबों:


15

बाएं पुनरावर्ती व्याकरण जरूरी एक बुरी चीज नहीं है। ये व्याकरण पहले से ही पार्स किए गए वाक्यांशों का ट्रैक रखने के लिए एक स्टैक का उपयोग करके आसानी से पार्स किए जाते हैं, क्योंकि यह एलआर पार्सर में मामला है ।

स्मरण करें कि CF ग्रामर का बायाँ पुनरावर्ती नियम है :G=(V,Σ,R,S)

ααβ

साथ का एक तत्व और का एक तत्व । (टपल के लिए पूर्ण औपचारिक परिभाषा देखें वहाँ )।वी β वी Σ ( वी , Σ , आर , एस )αVβVΣ(V,Σ,R,S)

आमतौर पर, वास्तव में टर्मिनलों और गैर-टर्मिनलों का एक क्रम है, और लिए एक अन्य नियम है जहां दाहिने हाथ की तरफ दिखाई नहीं देता है।अल्फा अल्फाβαα

जब भी व्याकरण पार्सर (लेसर से) द्वारा एक नया टर्मिनल प्राप्त किया जाता है, तो इस टर्मिनल को स्टैक के ऊपर धकेल दिया जाता है: इस ऑपरेशन को एक शिफ्ट कहा जाता है ।

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

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


यदि आप अपने चर को परिभाषित करते हैं तो यह मदद करेगा।
एंड्रयू एस

12

इस नियम पर विचार करें:

example : 'a' | example 'b' ;

अब एक एलएल पार्सर पर विचार करें जो 'b'इस नियम की तरह एक गैर-मिलान स्ट्रिंग से मेल खाने की कोशिश कर रहा है । चूंकि 'a'यह मेल नहीं खाता, इसलिए यह मिलान करने की कोशिश करेगा example 'b'। लेकिन ऐसा करने के लिए, इसे मैच करना होगा example... जो कि पहले स्थान पर करने की कोशिश कर रहा था। यह देखने के लिए हमेशा के लिए कोशिश कर रहा है कि यह मैच हो सकता है अटक गया, क्योंकि यह हमेशा एक ही नियम के टोकन की एक ही धारा से मिलान करने की कोशिश कर रहा है।

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


3
आप आँख बंद करके यह मान रहे हैं कि पार्सिंग जरूरी भोला-भाला पार्सिंग है।
रीयरियरपोस्ट

मैं पार्स करने के एक सामान्य तरीके के नुकसान को उजागर कर रहा हूं - एक ऐसी समस्या जिसे आसानी से टाला जा सकता है। बाएं-पुनरावृत्ति को संभालना निश्चित रूप से संभव है, लेकिन इसे बनाए रखना पार्सर के प्रकार पर लगभग-हमेशा-अनावश्यक सीमा बनाता है जो इसका उपयोग कर सकते हैं।
cHao

हां, इसे लगाने का अधिक रचनात्मक और उपयोगी तरीका है।
रिस्टोरियरपोस्ट

4

(मैं अब तक इस सवाल का बहुत पुराना पता है, लेकिन मामले में अन्य लोगों को एक ही सवाल है ...)

क्या आप पुनरावर्ती वंश पार्सर्स के संदर्भ में पूछ रहे हैं? उदाहरण के लिए, व्याकरण के लिए 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()


2

बायसन मैनुअल से:

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

http://www.gnu.org/software/bison/manual/html_node/Recursion.html

तो यह पार्सर के एल्गोरिथ्म पर निर्भर करता है, लेकिन जैसा कि अन्य जवाबों में कहा गया है, कुछ पार्सर केवल बाएं पुनरावृत्ति के साथ काम नहीं कर सकते हैं

हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.