LL और LR पार्सिंग में क्या अंतर है?


225

क्या कोई मुझे एलएल पार्सिंग बनाम एलआर पार्सिंग का एक सरल उदाहरण दे सकता है?

जवाबों:


483

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

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

एलएल पार्स के दौरान, पार्सर लगातार दो कार्यों के बीच चयन करता है:

  1. भविष्यवाणी : सबसे बाईं नॉनटर्मिनल और लुकहेड टोकन की कुछ संख्या के आधार पर, चुनें कि इनपुट स्ट्रिंग के करीब पहुंचने के लिए कौन सा उत्पादन लागू किया जाना चाहिए।
  2. मैच : इनपुट के सबसे बाईं बिना आकार के प्रतीक के साथ बाईं ओर के अनुमानित टर्मिनल प्रतीक का मिलान करें।

एक उदाहरण के रूप में, यह व्याकरण दिया गया है:

  • एस → ई
  • ई → टी + ई
  • ई → टी
  • टी → 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 पार्सर में, दो क्रियाएं होती हैं:

  1. पारी : इनपुट के अगले टोकन को विचारार्थ बफर में जोड़ें।
  2. कम करें : इस बफर में टर्मिनलों और नॉनटर्मिनल का एक संग्रह कम करें ताकि एक उत्पादन को उलट कर कुछ गैर-पेटी में वापस किया जा सके।

एक उदाहरण के रूप में, एक 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 पार्सिंग के बारे में अधिक जानना चाहते हैं, तो मैंने अभी एक कम्पाइलर कोर्स पढ़ाना समाप्त किया है और कोर्स की वेबसाइट पर कुछ हैंडआउट्स और लेक्चर स्लाइड्स हैं । अगर आपको लगता है कि यह उपयोगी होगा, तो मैं उनमें से किसी पर विस्तार से खुशी मनाऊँगा।


40
आपकी व्याख्यान स्लाइड अभूतपूर्व हैं, आसानी से सबसे मजेदार स्पष्टीकरण जो मैंने देखा है :) यह एक ऐसी चीज है जो वास्तव में हितों को उगलती है।
kizzx2

1
मुझे स्लाइड्स पर भी टिप्पणी करनी होगी! अब उन सभी के माध्यम से जा रहे हैं। बहुत मदद करता है! धन्यवाद!
कोर्नफ्रिज

वास्तव में स्लाइड का आनंद भी ले रहे हैं। मुझे नहीं लगता कि आप प्रोजेक्ट फ़ाइलों के गैर-विंडोज संस्करण (और pp2 के लिए Scan.l फ़ाइल) पोस्ट कर सकते हैं? :)
एरिक पी।

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

1
बहुत बढ़िया संसाधन! स्लाइड, हैंडआउट, प्रोजेक्ट प्रदान करने के लिए धन्यवाद।
पी। हिनकर

58

जोश हैबरमैन ने अपने लेख एलएल और एलआर पार्सिंग डेमिस्टिफ़ाइड में दावा किया है कि एलएल पार्सिंग सीधे पोलिश नोटेशन से मेल खाती है, जबकि एलआर रिवर्स पोलिश नोटेशन से मेल खाती है । पीएन और आरपीएन के बीच का अंतर समीकरण के द्विआधारी पेड़ का पता लगाने का क्रम है:

एक समीकरण का द्विआधारी वृक्ष

+ 1 * 2 3  // Polish (prefix) expression; pre-order traversal.
1 2 3 * +  // Reverse Polish (postfix) expression; post-order traversal.

हैबरमैन के अनुसार, यह एलएल और एलआर पार्सरों के बीच मुख्य अंतर को दर्शाता है:

एलएल और एलआर पार्सर्स कैसे संचालित होते हैं, इसके बीच का प्राथमिक अंतर यह है कि एक एलएल पार्सर पार्स ट्री के एक प्री-ऑर्डर ट्रैवर्सल और एक एलआर पार्सर पोस्ट-ऑर्डर ट्रैवर्सल आउटपुट करता है।

गहराई से स्पष्टीकरण के लिए, उदाहरण और निष्कर्ष हैबरमैन के लेख की जांच करते हैं ।


9

एलएल टॉप-डाउन का उपयोग करता है, जबकि एलआर नीचे-अप दृष्टिकोण का उपयोग करता है।

यदि आप एक गँवार भाषा बोलते हैं:

  • LL एक स्रोत कोड देखता है, जिसमें फ़ंक्शन होते हैं, जिसमें अभिव्यक्ति होती है।
  • एलआर अभिव्यक्ति को देखता है, जो कार्यों से संबंधित है, जिसके परिणामस्वरूप पूर्ण स्रोत है।

6

एलआर पार्सिंग विकलांग हैं, जब एलआर की तुलना में। यहाँ एक व्याकरण है जो एक 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)

बिना परवाह किए कि किस नियम को मान्यता दी जा रही है जब तक कि उसका सामना ';' या '{'।

एक एलएल पार्सर 'इंट' पर लटका हुआ हो जाता है क्योंकि उसे यह जानना होता है कि किस नियम को मान्यता दी जा रही है। इसलिए इसे ';' के लिए देखना चाहिए या '{'।

एलएल पार्सर्स के लिए अन्य दुःस्वप्न एक व्याकरण में पुनरावृत्ति छोड़ दिया जाता है। व्याकरण में वाम पुनरावृत्ति एक सामान्य बात है, एलआर पार्सर जनरेटर के लिए कोई समस्या नहीं है, लेकिन एलएल इसे संभाल नहीं सकता है।

तो आपको एलएल के साथ अपने व्याकरण को अप्राकृतिक तरीके से लिखना होगा।


0

वाम सबसे व्युत्पन्न उदाहरण: एक व्याकरण 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 (नियम: २)

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