प्रॉम्प्ट और दायरा
अंकगणितीय अभिव्यक्तियों (arithmetic expressions) और वेरिएबल घोषणाओं (variable declarations) के लिए एक छोटा पार्सर डिज़ाइन करें। इनपुट में कई सिंटैक्स त्रुटियाँ हो सकती हैं, फिर भी पार्सर को स्थितियों की रिपोर्ट करनी चाहिए, बाद के कथनों (statements) के साथ जारी रखना चाहिए, और एक IDE के लिए आंशिक AST प्रदान करना चाहिए।
यह लेक्सिंग, पार्सिंग, रिकवरी और डेटा संरचनाओं के बीच की सीमाओं का परीक्षण करता है। Bison एक सिंक्रोनाइज़ेशन बिंदु तक इनपुट को छोड़ने और जारी रखने की अनुशंसा करता है; IDEs को एरर नोड्स, स्थिर रेंज और पहली त्रुटि के बाद भी रिकवरी की आवश्यकता होती है।
इंटरव्यूअर क्या मूल्यांकन करता है
उम्मीदवार को रिकर्सिव डिसेंट या LR चुनने से पहले टोकन और व्याकरण को परिभाषित करना चाहिए, लेक्सिकल और सिंटैक्स त्रुटियों के बीच अंतर करना चाहिए, सुरक्षित सिंक्रोनाइज़ेशन बिंदु चुनने चाहिए, कैस्केड एरर्स को दबाना चाहिए, आंशिक ASTs को संरक्षित करना चाहिए, और नेस्टेड डेलीमीटर, छूटे हुए सेपरेटर और अनटर्मिनेटेड स्ट्रिंग्स का परीक्षण करना चाहिए।
30-सेकंड उत्तर रूपरेखा
"मैं लेक्सर, पार्सर और डायग्नोस्टिक्स को अलग करता हूँ। पार्सर एक टोकन कर्सर और स्रोत सीमाओं (source ranges) को ट्रैक करता है; किसी त्रुटि के बाद यह अपेक्षित और वास्तविक टोकन रिकॉर्ड करता है, सेमीकोलन, क्लोजिंग डेलीमीटर या EOF तक स्किप करता है, एक ErrorNode सम्मिलित करता है, और जारी रखता है। रिकवरी डुप्लिकेट्स को तब तक दबाती है जब तक कि कई टोकन सफल न हो जाएं। AST नोड्स छूटी हुई सीमाओं को बनाए रखते हैं ताकि कॉल करने वाले सख्त (strict) या सहनशील (tolerant) मोड चुन सकें।"
चरण-दर-चरण गहन उत्तर
चरण 1: टोकन और व्याकरण परिभाषित करें
लेक्सर आइडेंटिफायर्स, संख्याओं, ऑपरेटरों, डेलीमीटर, सेमीकोलन और अमान्य वर्णों के लिए प्रकार (kind), टेक्स्ट, ऑफसेट और लाइन व कॉलम की स्थिति उत्सर्जित करता है। व्याकरण प्राथमिकता (precedence) और साहचर्यता (associativity) तय करता है ताकि रिकवरी एक्सप्रेशन फ़ंक्शंस में बिखरी न रहे।
चरण 2: पार्सर संरचना चुनें
एक छोटे व्याकरण के लिए रिकर्सिव डिसेंट पठनीय है; precedence climbing एक्सप्रेशन्स को संभालती है। एक बड़ा व्याकरण स्पष्ट एरर रणनीति वाले जनरेटर का उपयोग कर सकता है। किसी भी तरह से, पार्सर को लुकअहेड, बाउंडेड टोकन रिकवरी और स्रोत सीमाओं की आवश्यकता होती है।
चरण 3: लेक्सिकल और सिंटैक्स त्रुटियों को अलग करें
एक अमान्य वर्ण या अनटर्मिनेटेड स्ट्रिंग एक लेक्सिकल त्रुटि है: एक एरर टोकन उत्सर्जित करें और स्कैनिंग जारी रखें। एक छूटा हुआ ऑपरेंड, डेलीमीटर या सेमीकोलन संदर्भ में पार्सर द्वारा रिपोर्ट की गई सिंटैक्स त्रुटि है। हर समस्या को "Unexpected token" का लेबल न दें।
चरण 4: सिंक्रोनाइज़ेशन बिंदु चुनें
कथन-स्तरीय (statement-level) बिंदु सेमीकोलन, क्लोजिंग ब्रेस या EOF हैं। एक्सप्रेशन्स के अंदर, कॉमा, क्लोजिंग पैरेंथेसिस या ऑपरेटर सीमाओं पर सिंक्रोनाइज़ करें। स्किपिंग को हमेशा कर्सर को आगे बढ़ाना चाहिए या EOF तक पहुंचना चाहिए, अन्यथा वही त्रुटि हमेशा लूप में चलती रहेगी।
चरण 5: आंशिक AST बनाएं
नोड्स पर एरर रेंज बनाए रखें। एक छूटे हुए चाइल्ड को MissingNode के साथ और एक अप्राप्य स्पैन को मूल टोकन युक्त ErrorNode के साथ दर्शाएं। स्वरूपण (formatting), हाइलाइटिंग और ऑटोकम्प्लीशन को एक पूर्ण ट्री मानने के बजाय इन नोड्स को संभालना चाहिए।
चरण 6: कैस्केडेड डायग्नोस्टिक्स को दबाएं
एक रिकवरी कई सतही त्रुटियों को उजागर कर सकती है। अंतिम सिंक्रोनाइज़ेशन बिंदु और सफल-टोकन गणना को ट्रैक करें; दूसरा डायग्नोस्टिक रिपोर्ट करने से पहले कई सफल शिफ्ट्स की प्रतीक्षा करें। प्रति फ़ाइल त्रुटियों को सीमित करें ताकि लॉग और UI उपयोगी बने रहें।
चरण 7: इंक्रीमेंटल पार्सिंग का समर्थन करें
जब संपादक टेक्स्ट बदलता है, तो अपरिवर्तित सब-ट्रीज़ का पुन: उपयोग करते हुए प्रभावित टोकन रेंज और नजदीकी व्याकरण संदर्भ को फिर से पार्स करें। नोड रेंज और टोकन आईडी को स्थिर रखें; केवल कैरेक्टर ऑफसेट द्वारा नहीं, बल्कि पैरेंट सीमाओं और पार्सर स्थिति द्वारा कैश को अमान्य करें।
चरण 8: परीक्षण और माप करें
वैध इनपुट, एक त्रुटि, कई त्रुटियां, नेस्टेड त्रुटियां, लंबी स्ट्रिंग्स और बहुत बड़े एक्सप्रेशन्स का परीक्षण करें। स्थितियों, गणनाओं, एरर नोड्स और समाप्ति (termination) की पुष्टि करें। लंबे इनपुट पर लीनियर स्कैनिंग, रिकर्सन डेप्थ, मेमोरी और सबसे खराब स्थिति में रिकवरी लागत को मापें।
ट्रेड-ऑफ और सीमाएं
फेल फास्ट बनाम जारी रखना
बेहतर फीडबैक के लिए बैच कंपाइलर डायग्नोस्टिक्स के बाद जारी रख सकते हैं; कॉन्फ़िगरेशन सत्यापन पहली त्रुटि के बाद अस्वीकार कर सकता है। बहाव (drift) से बचने के लिए लेक्सर, टोकन और डायग्नोस्टिक्स साझा करते हुए इसे एक मोड बनाएं।
कई बनाम कुछ सिंक्रोनाइज़ेशन बिंदु
अधिक बिंदु त्रुटि के दायरे को सीमित करते हैं लेकिन पुनर्प्राप्त करने योग्य टोकन को छोड़ सकते हैं; कम बिंदु संदर्भ को संरक्षित करते हैं लेकिन कैस्केड बढ़ाते हैं। बयानों और डेलीमीटर्स द्वारा बिंदुओं को परिभाषित करें, फिर प्रतिनिधि कॉर्पस के साथ परीक्षण करें।
रिकर्सिव डिसेंट बनाम एक जनरेटर
रिकर्सिव डिसेंट कस्टम डायग्नोस्टिक्स को आसान बनाता है; एक जनरेटर बड़े स्थिर व्याकरण के लिए उपयुक्त है। रिकवरी अप्रयुक्त जनरेटर डिफॉल्ट्स के बजाय एक स्पष्ट इंटरफ़ेस होनी चाहिए।
विफलता अभ्यास और विकास
एक क्लोजिंग पैरेंथेसिस गायब है
अगला कथन जोड़ें और उसके सेमीकोलन या EOF पर सिंक्रोनाइज़ेशन, एक मिसिंग-डेलीमीटर डायग्नोस्टिक और बाद के कथन के संरक्षण को सत्यापित करें।
अमान्य वर्ण और अनटर्मिनेटेड स्ट्रिंग
सत्यापित करें कि लेक्सर एक एरर टोकन उत्सर्जित करता है और पार्सर के एक वर्ण पर अटके बिना लाइन या स्ट्रिंग के अंत तक पहुंचता है।
लगातार त्रुटियों की भरमार
ऐसा इनपुट दें जहां हर टोकन अमान्य हो। कर्सर को आगे बढ़ना चाहिए, एरर काउंट सीमित होना चाहिए, और CPU का उपयोग द्विघातीय (quadratically) रूप से नहीं बढ़ना चाहिए।
सामान्य गलतियाँ और फॉलो-अप
गलती 1: पहली त्रुटि पर null वापस करना
पूछें कि IDE हाइलाइटिंग और ऑटोकम्प्लीशन कैसे जारी रखता है; इसके बजाय रेंज युक्त ErrorNode या MissingNode लौटाएं।
गलती 2: रिकवरी के दौरान आगे न बढ़ना
एक समाप्ति तर्क (termination argument) मांगें जो एक ही टोकन पर लूपिंग को खारिज करता हो।
गलती 3: पार्सर में हर त्रुटि की रिपोर्ट करना
पूछें कि क्या एक अनटर्मिनेटेड स्ट्रिंग और अमान्य वर्ण लेक्सर या पार्सर डायग्नोस्टिक्स से संबंधित हैं।
गलती 4: कैस्केडेड-एरर सप्रेशन को अनदेखा करना
पूछें कि एक छूटे हुए सेमीकोलन पर दस बार दोहराई गई त्रुटियां क्यों नहीं प्रिंट होनी चाहिए।
गलती 5: केवल ऑफसेट द्वारा इंक्रीमेंटल पार्स को कैश करना
पूछें कि एक डेलीमीटर डालने के बाद कौन से पैरेंट नोड्स और पार्सर स्थितियाँ अमान्य हो जाती हैं।
विस्तारित फॉलो-अप और संदर्भ उत्तर
एरर नोड्स क्यों रखें?
स्वरूपण (formatting), ऑटोकम्प्लीशन और हाइलाइटिंग को अभी भी संरचना और रेंज की आवश्यकता होती है। एरर नोड्स डाउनस्ट्रीम टूल्स को क्रैश होने के बजाय अपूर्ण इनपुट को स्पष्ट रूप से संभालने की अनुमति देते हैं।
आप यह कैसे गारंटी देते हैं कि रिकवरी समाप्त हो जाएगी?
प्रत्येक रिकवरी एक टोकन की खपत करती है या अधिकतम त्रुटि और रिकर्सन सीमाओं के साथ EOF तक पहुंचती है।
आप डायग्नोस्टिक गुणवत्ता को कैसे मान्य करते हैं?
कई स्वतंत्र त्रुटियों वाले कॉर्पस का उपयोग करें और केवल पहली त्रुटि का परीक्षण करने के बजाय स्थितियों, गणनाओं, बाद के AST और रनटाइम की पुष्टि करें।