बस समस्या को बताने के लिए, डेंग्लिंग एल्स प्रॉब्लम कोड सिंटैक्स स्पेसिफिकेशन में एक अस्पष्टता है जहां यह अगले इफ़्स और इलसेस के मामलों में अस्पष्ट हो सकता है, जो अन्य के अंतर्गत आता है।
सबसे सरल और क्लासिक उदाहरण:
if(conditionA)
if(conditionB)
doFoo();
else
doBar();
यह जो लोग जो दिल से भाषा विनिर्देश, की बारीकियों पता नहीं है करने के लिए स्पष्ट नहीं है, if
हो जाता है else
(और इस विशेष कोड का टुकड़ा आधा दर्जन भाषाओं में मान्य है, लेकिन प्रत्येक में अलग ढंग से प्रदर्शन कर सकते हैं)।
डैंग्लिंग एल्स निर्माण स्केनरलेस पार्सर कार्यान्वयन के लिए एक संभावित समस्या खड़ी करता है, क्योंकि रणनीति एक समय में फ़ाइल स्ट्रीम एक चरित्र को खत्म करना है, जब तक कि पार्सर यह नहीं देखता कि यह टोकन के लिए पर्याप्त है (विधानसभा या मध्यवर्ती भाषा में इसे संकलित करें) । यह पार्सर को न्यूनतम स्थिति बनाए रखने की अनुमति देता है; जैसे ही उसे लगता है कि उसके पास फ़ाइल में पार्स किए गए टोकन को लिखने के लिए पर्याप्त जानकारी है, वह ऐसा करेगा। यह एक स्केनरलेस पार्सर का अंतिम लक्ष्य है; तेज, सरल, हल्के संकलन।
विराम चिह्न के पहले या बाद में नई कहानियों और व्हाट्सएप को निरर्थक मान लेना (जैसा कि वे अधिकांश सी-शैली भाषाओं में हैं), यह कथन संकलक के रूप में प्रकट होगा:
if(conditionA)if(conditionB)doFoo();else doBar;
पूरी तरह से एक कंप्यूटर के लिए सक्षम है, तो चलो देखते हैं। मेरे पास एक समय में एक ही चरित्र मिलता है:
if(conditionA)
ओह, मुझे पता है कि इसका क्या मतलब है (सी # में), इसका मतलब है " push
eval स्टैक पर कंडीशन और फिर brfalse
अगले अर्धविराम के बाद बयान में कूदने के लिए कॉल करें यदि यह सच नहीं है"। अभी मुझे अर्धविराम नहीं दिखाई देता है, इसलिए अभी के लिए मैं इस निर्देश के बाद अपनी छलांग ऑफ़सेट अगले स्थान पर लगाऊंगा, और जब तक मैं एक अर्धविराम नहीं देखता तब तक मैं उतनी ही वृद्धि करूँगा जितना कि मैं और निर्देश डालता हूँ। जारी रखने के लिए ...
if(conditionB)
ठीक है, यह आईएल संचालन की एक समान जोड़ी से बाहर निकलता है, और यह निर्देश के तुरंत बाद जाता है जिसे मैंने अभी पार्स किया था। मुझे एक अर्धविराम नहीं दिखता है, इसलिए मैं अपने दो आदेशों की लंबाई (पुश के लिए एक और ब्रेक के लिए एक) द्वारा अपने पिछले बयान की कूद ऑफसेट बढ़ाऊंगा और देखता रहूंगा।
doFoo();
ठीक है, यह आसान है। वह " call
doFoo" है। और क्या वह अर्धविराम है जो मैं देख रहा हूं? खैर, यह बहुत अच्छा है, यह पंक्ति का अंत है। मैं इन दोनों आदेशों की लंबाई से अपने दोनों ब्लॉकों के कूदने की संख्या बढ़ाता हूँ और भूल जाता हूँ कि मैंने कभी परवाह की है। ठीक है, आगे बढ़ रहे हैं ...
else
... उह ओह। यह उतना सरल नहीं है जितना कि यह दिखता है। ठीक है, मैं भूल गया था कि मैं क्या कर रहा था, लेकिन else
इसका मतलब है कि कहीं न कहीं एक सशर्त विराम कथन है जो मैंने पहले ही देखा है, इसलिए मुझे वापस देखने दें ... हां, यह है brfalse
, ठीक है, जब मैं कुछ "कंडीशनबी" पर धक्का देता हूं ढेर, जो कुछ भी था। ठीक है, अब मुझे break
अगले बयान के रूप में बिना शर्त की आवश्यकता है । उसके बाद जो बयान आएगा, वह निश्चित रूप से मेरे सशर्त विराम का लक्ष्य है, इसलिए मैं यह सुनिश्चित करूंगा कि मेरे पास यह सही है, और मैं बिना शर्त विराम को बढ़ाऊंगा जो मैं आगे बढ़ रहा हूं ...
doBar();
यह आसान है। " call
दोबार"। और एक अर्धविराम है, और मैंने कभी कोई ब्रेसिज़ नहीं देखा। इसलिए, बिना शर्त break
अगले बयान पर कूदना चाहिए, चाहे वह कुछ भी हो, और मैं भूल सकता हूं कि मैंने कभी परवाह की।
तो, हमारे पास क्या है ... (ध्यान दें: यह 10:00 बजे है और मुझे ऐसा महसूस नहीं होता है कि बिट ऑफ़सेट को हेक्साडेसिमल में बदल दिया जाए या इन कमांड के साथ फंक्शन का पूरा IL शेल खोल दिया जाए, इसलिए यह सिर्फ छद्म आईएल है। लाइन नंबर का उपयोग करना जहां सामान्य रूप से बाइट ऑफ़सेट होंगे):
ldarg.1 //conditionA
brfalse <line 6> //jumps to "break"
ldarg.2 //conditionB
brfalse <line 7> //jumps to "call doBar"
call doFoo
break <line 8> //jumps beyond statement in scope
call doBar
<line 8 is here>
ठीक है, यह वास्तव में सही ढंग से निष्पादित करता है, यदि नियम (अधिकांश सी-शैली भाषाओं में) यह है कि else
निकटतम के साथ जाता है if
। निष्पादन घोंसले का पालन करने के लिए प्रेरित, यह इस तरह से निष्पादित करेगा, जहां अगर स्थिति झूठी है, तो स्निपेट का पूरा शेष छोड़ दिया जाता है:
if(conditionA)
if(conditionB)
doFoo();
else
doBar();
... लेकिन यह ऐसा बहुत गंभीरता से होता है, क्योंकि बाहरी if
कथन से जुड़ा विराम भीतरbreak
के अंत में बयान के लिए कूदता है , जो पूरे विवरण से परे निष्पादन सूचक को ले जाता है। यह एक अतिरिक्त अनावश्यक कूद है, और यदि यह उदाहरण किसी भी अधिक जटिल थे, तो इस तरह से पार्स और टोकन किए जाने पर यह अब कार्य नहीं कर सकता है। if
इसके अलावा, अगर भाषा के विनिर्देश ने कहा कि एक झूलना else
पहले का है if
, और यदि शर्त झूठी है तो doBar निष्पादित किया जाता है, जबकि अगर conditiona सही है, लेकिन conditionB नहीं है, तो ऐसा कुछ भी नहीं होता है?
if(conditionA)
if(conditionB)
doFoo();
else
doBar();
पार्सर पहले if
मौजूद अस्तित्व को भूल गया था, और इसलिए यह सरल पार्सर एल्गोरिदम सही कोड का उत्पादन नहीं करेगा, कुशल कोड के बारे में कुछ भी कहने के लिए नहीं।
अब, पार्सर उस समय को याद रखने के लिए काफी स्मार्ट हो सकता है if
और else
उसके पास अधिक समय के लिए है, लेकिन अगर भाषा की युक्ति पहले else
दो if
मैचों के बाद एक एकल कहती है if
, तो इससे if
मेल खाने वाले else
s के साथ दो s की समस्या होती है :
if(conditionA)
if(conditionB)
doFoo();
else
doBar();
else
doBaz();
पार्सर पहले को देखेगा, पहले else
को मैच करेगा if
, फिर दूसरे को देखेगा और घबराहट में जाएगा "मैं फिर से क्या कर रहा था" मोड। इस बिंदु पर पार्सर को एक उत्परिवर्ती राज्य में बहुत अधिक कोड मिला है, लेकिन यह बहुत पहले से ही आउटपुट फाइल करने के लिए बाहर धकेल दिया है।
इन सभी समस्याओं के समाधान और क्या-क्या हैं। लेकिन, या तो कोड की आवश्यकता है कि स्मार्ट पार्सर एल्गोरिथ्म की जटिलता को बढ़ाता है, या भाषा युक्ति पार्सर को इस गूंगा होने की अनुमति देता है, भाषा स्रोत कोड की वर्बोसिटी बढ़ाता है, जैसे कि समाप्त होने वाले बयानों की आवश्यकता होती है end if
, या ब्रैकेट्स नेस्टेड का संकेत देते हैं। यदि if
कथन में ब्लॉक है else
(दोनों जिनमें से आमतौर पर अन्य भाषा शैलियों में देखा जाता है)।
यह सिर्फ एक-दो का सरल उदाहरण है if
, और उन सभी निर्णयों पर गौर करें जिन्हें कंपाइलर को करना था, और जहां यह बहुत आसानी से गड़बड़ कर सकता था। यह आपके प्रश्न में विकिपीडिया के उस सहज कथन के पीछे का विवरण है।