क्या कोई मुझे एलएल पार्सिंग बनाम एलआर पार्सिंग का एक सरल उदाहरण दे सकता है?
क्या कोई मुझे एलएल पार्सिंग बनाम एलआर पार्सिंग का एक सरल उदाहरण दे सकता है?
जवाबों:
उच्च स्तर पर, एलएल पार्सिंग और एलआर पार्सिंग के बीच का अंतर यह है कि एलएल पार्सर्स स्टार्ट सिंबल पर शुरू होते हैं और प्रोडक्शन को लक्ष्य स्ट्रिंग पर पहुंचने के लिए लागू करने की कोशिश करते हैं, जबकि एलआर पार्सर्स लक्ष्य स्ट्रिंग पर शुरू होते हैं और शुरुआत में वापस आने की कोशिश करते हैं। प्रतीक।
एक एलएल पार्स एक बाएं से दाएं, सबसे बाएं व्युत्पत्ति है। यही है, हम इनपुट प्रतीकों को बाईं ओर से दाईं ओर मानते हैं और बाईं ओर व्युत्पत्ति के निर्माण का प्रयास करते हैं। यह स्टार्ट सिंबल पर शुरू करके और लक्ष्य स्ट्रिंग पर पहुंचने तक बार-बार सबसे बाईं नॉनटर्मिनल का विस्तार करके किया जाता है। एलआर पार्स एक बाएं से दाएं, सबसे दाहिनी व्युत्पत्ति है, जिसका अर्थ है कि हम बाएं से दाएं स्कैन करते हैं और एक सही व्युत्पत्ति का निर्माण करने का प्रयास करते हैं। पार्सर लगातार इनपुट का एक विकल्प चुनता है और इसे एक गैर-वापस करने के लिए उल्टा करने का प्रयास करता है।
एलएल पार्स के दौरान, पार्सर लगातार दो कार्यों के बीच चयन करता है:
एक उदाहरण के रूप में, यह व्याकरण दिया गया है:
int
फिर स्ट्रिंग दी जाती है int + int + int
, एक LL (2) पार्सर (जो लुकहेड के दो टोकन का उपयोग करता है) स्ट्रिंग को पार्स करेगा:
Production Input Action
---------------------------------------------------------
S int + int + int Predict S -> E
E int + int + int Predict E -> T + E
T + E int + int + int Predict T -> int
int + E int + int + int Match int
+ E + int + int Match +
E int + int Predict E -> T + E
T + E int + int Predict T -> int
int + E int + int Match int
+ E + int Match +
E int Predict E -> T
T int Predict T -> int
int int Match int
Accept
ध्यान दें कि प्रत्येक चरण में हम अपने उत्पादन में सबसे बाएं प्रतीक को देखते हैं। यदि यह एक टर्मिनल है, तो हम इसे मेल खाते हैं, और यदि यह एक गैर-वस्तु है, तो हम भविष्यवाणी करते हैं कि नियमों में से एक को चुनने से क्या होने वाला है।
LR पार्सर में, दो क्रियाएं होती हैं:
एक उदाहरण के रूप में, एक LR (1) पार्सर (लुकहेड के एक टोकन के साथ) उसी स्ट्रिंग को पार्स कर सकता है:
Workspace Input Action
---------------------------------------------------------
int + int + int Shift
int + int + int Reduce T -> int
T + int + int Shift
T + int + int Shift
T + int + int Reduce T -> int
T + T + int Shift
T + T + int Shift
T + T + int Reduce T -> int
T + T + T Reduce E -> T
T + T + E Reduce E -> T + E
T + E Reduce E -> T + E
E Reduce S -> E
S Accept
आपके द्वारा उल्लिखित दो पार्सिंग एल्गोरिदम (एलएल और एलआर) में अलग-अलग विशेषताएं हैं। एलएल पार्सर हाथ से लिखने में आसान होते हैं, लेकिन वे LR पार्सर की तुलना में कम शक्तिशाली होते हैं और LR पार्सर की तुलना में व्याकरण के बहुत छोटे सेट को स्वीकार करते हैं। LR पार्सर कई फ्लेवर (LR (0), SLR (1), LALR (1), LR (1), IELR (1), GLR (0), आदि में आते हैं और कहीं अधिक शक्तिशाली हैं। उन्होंने यह भी और अधिक जटिल हो जाते हैं और लगभग हमेशा जैसे उपकरणों द्वारा उत्पन्न कर रहे yacc
या bison
। एलएल पार्सर भी कई स्वादों में आते हैं (एलएल (*) सहित, जो ANTLR
उपकरण द्वारा उपयोग किया जाता है ), हालांकि व्यवहार में एलएल (1) सबसे व्यापक रूप से उपयोग किया जाता है।
एक बेशर्म प्लग के रूप में, यदि आप LL और LR पार्सिंग के बारे में अधिक जानना चाहते हैं, तो मैंने अभी एक कम्पाइलर कोर्स पढ़ाना समाप्त किया है और कोर्स की वेबसाइट पर कुछ हैंडआउट्स और लेक्चर स्लाइड्स हैं । अगर आपको लगता है कि यह उपयोगी होगा, तो मैं उनमें से किसी पर विस्तार से खुशी मनाऊँगा।
जोश हैबरमैन ने अपने लेख एलएल और एलआर पार्सिंग डेमिस्टिफ़ाइड में दावा किया है कि एलएल पार्सिंग सीधे पोलिश नोटेशन से मेल खाती है, जबकि एलआर रिवर्स पोलिश नोटेशन से मेल खाती है । पीएन और आरपीएन के बीच का अंतर समीकरण के द्विआधारी पेड़ का पता लगाने का क्रम है:
+ 1 * 2 3 // Polish (prefix) expression; pre-order traversal.
1 2 3 * + // Reverse Polish (postfix) expression; post-order traversal.
हैबरमैन के अनुसार, यह एलएल और एलआर पार्सरों के बीच मुख्य अंतर को दर्शाता है:
एलएल और एलआर पार्सर्स कैसे संचालित होते हैं, इसके बीच का प्राथमिक अंतर यह है कि एक एलएल पार्सर पार्स ट्री के एक प्री-ऑर्डर ट्रैवर्सल और एक एलआर पार्सर पोस्ट-ऑर्डर ट्रैवर्सल आउटपुट करता है।
गहराई से स्पष्टीकरण के लिए, उदाहरण और निष्कर्ष हैबरमैन के लेख की जांच करते हैं ।
एलएल टॉप-डाउन का उपयोग करता है, जबकि एलआर नीचे-अप दृष्टिकोण का उपयोग करता है।
यदि आप एक गँवार भाषा बोलते हैं:
एलआर पार्सिंग विकलांग हैं, जब एलआर की तुलना में। यहाँ एक व्याकरण है जो एक LL पार्सर जनरेटर के लिए एक बुरा सपना है:
Goal -> (FunctionDef | FunctionDecl)* <eof>
FunctionDef -> TypeSpec FuncName '(' [Arg/','+] ')' '{' '}'
FunctionDecl -> TypeSpec FuncName '(' [Arg/','+] ')' ';'
TypeSpec -> int
-> char '*' '*'
-> long
-> short
FuncName -> IDENTIFIER
Arg -> TypeSpec ArgName
ArgName -> IDENTIFIER
एक FunctionDef बिल्कुल ',' तक 'FunctionDecl' जैसा दिखता है। या '{' का सामना किया जाता है।
एक LL पार्सर एक ही समय में दो नियमों को संभाल नहीं सकता है, इसलिए इसे या तो FunctionDef या FunctionDecl चुनना होगा। लेकिन यह जानने के लिए कि यह सही है कि ';' या '{'। व्याकरण विश्लेषण के समय, लुकहेड (k) अनंत प्रतीत होता है। पार्सिंग के समय यह परिमित होता है, लेकिन बड़ा हो सकता है।
एक LR पार्सर को लुकहेड करने की आवश्यकता नहीं है, क्योंकि यह एक ही समय में दो नियमों को संभाल सकता है। तो LALR (1) पार्सर जनरेटर आसानी से इस व्याकरण को संभाल सकते हैं।
इनपुट कोड दिया गया:
int main (int na, char** arg);
int main (int na, char** arg)
{
}
एक LR पार्सर को पार्स कर सकता है
int main (int na, char** arg)
बिना परवाह किए कि किस नियम को मान्यता दी जा रही है जब तक कि उसका सामना ';' या '{'।
एक एलएल पार्सर 'इंट' पर लटका हुआ हो जाता है क्योंकि उसे यह जानना होता है कि किस नियम को मान्यता दी जा रही है। इसलिए इसे ';' के लिए देखना चाहिए या '{'।
एलएल पार्सर्स के लिए अन्य दुःस्वप्न एक व्याकरण में पुनरावृत्ति छोड़ दिया जाता है। व्याकरण में वाम पुनरावृत्ति एक सामान्य बात है, एलआर पार्सर जनरेटर के लिए कोई समस्या नहीं है, लेकिन एलएल इसे संभाल नहीं सकता है।
तो आपको एलएल के साथ अपने व्याकरण को अप्राकृतिक तरीके से लिखना होगा।
वाम सबसे व्युत्पन्न उदाहरण: एक व्याकरण G जो संदर्भ-मुक्त है, जिसमें निर्माण है
z → xXY (नियम: 1) X → Yx (नियम: 2) Y → bY (नियम: 3) Y → c (नियम: 4)
स्ट्रिंग w = 'xcbxbc' की तुलना बाएं सबसे अधिक व्युत्पत्ति से करें।
z ⇒ xXY (नियम: 1) ⇒ xYbxY (नियम: २) ⇒ xcbxY (नियम: ४) ⇒ xcbxbY (नियम: ३) ⇒ xcbxbc (नियम: ४)
सबसे अधिक व्युत्पत्ति का उदाहरण: K → aKK (नियम: 1) A → b (नियम: 2)
स्ट्रिंग w = 'aababbb' की तुलना सबसे सही व्युत्पत्ति के साथ करें।
K ⇒ aKK (नियम: 1) ⇒ aKb (नियम: 2) ⇒ aaKKb (नियम: 1) ⇒ aaKaKKb (नियम: १) ⇒ aaKaKbb (नियम: २: २) ⇒ aaKabbb (नियम: २) ⇒ aababbb (नियम: २)