सामान्य पार्सर के रूप में वे आम तौर पर सिखाया जाता है इससे पहले कि पार्सर इनपुट को छूता है, एक लेसर चरण होता है। लेक्सर ("स्कैनर" या "टोकन") भी इनपुट को छोटे टोकन में काटता है जो एक प्रकार से एनोटेट होते हैं। यह मुख्य पार्सर को प्रत्येक चरित्र को एक टर्मिनल के रूप में मानने के बजाय टर्मिनल तत्वों के रूप में टोकन का उपयोग करने की अनुमति देता है, जिससे ध्यान देने योग्य दक्षता लाभ होता है। विशेष रूप से, लेक्सर सभी टिप्पणियों और सफेद स्थान को भी हटा सकता है। हालांकि, एक अलग टोकन चरण का अर्थ है कि कीवर्ड का उपयोग पहचानकर्ता के रूप में भी नहीं किया जा सकता है (जब तक कि भाषा उस स्ट्रैपिंग का समर्थन नहीं करती है जो पक्ष से बाहर हो गई है, या सभी पहचानकर्ताओं को एक सर्जन की तरह उपसर्ग करता है $foo
)।
क्यों? मान लेते हैं कि हमारे पास एक सरल टोकन है जो निम्नलिखित टोकन को समझता है:
FOR = 'for'
LPAREN = '('
RPAREN = ')'
IN = 'in'
IDENT = /\w+/
COLON = ':'
SEMICOLON = ';'
टोकनधारक हमेशा सबसे लंबे टोकन से मेल खाएगा, और पहचानकर्ताओं पर कीवर्ड पसंद करेगा। तो के interesting
रूप में lexed किया जाएगा IDENT:interesting
, लेकिन के रूप में lexed किया in
जाएगा IN
, कभी नहीं के रूप में IDENT:interesting
। एक कोड स्निपेट की तरह
for(var in expression)
टोकन स्ट्रीम में अनुवादित किया जाएगा
FOR LPAREN IDENT:var IN IDENT:expression RPAREN
अब तक, यह काम करता है। लेकिन किसी भी वेरिएबल in
को वेरिएबल के IN
बजाय कीवर्ड के रूप में रखा जाएगा, जो कोड को तोड़ देगा। लेक्सर टोकन के बीच कोई स्थिति नहीं रखता है, और यह नहीं जान सकता है कि in
आमतौर पर एक चर होना चाहिए जब हम एक लूप में होते हैं। साथ ही, निम्न कोड कानूनी होना चाहिए:
for(in in expression)
पहला in
एक पहचानकर्ता होगा, दूसरा एक कीवर्ड होगा।
इस समस्या पर दो प्रतिक्रियाएँ हैं:
प्रासंगिक कीवर्ड भ्रमित कर रहे हैं, आइए इसके बजाय कीवर्ड का पुन: उपयोग करें।
जावा में कई आरक्षित शब्द हैं, जिनमें से कुछ को प्रोग्रामर को C ++ से जावा में स्विच करने के लिए अधिक उपयोगी त्रुटि संदेश प्रदान करने के अलावा कोई उपयोग नहीं है। नए कीवर्ड जोड़ने से कोड टूट जाता है। प्रासंगिक कीवर्ड जोड़ना कोड के एक पाठक को भ्रमित कर रहा है जब तक कि उनके पास अच्छा सिंटैक्स हाइलाइटिंग नहीं है, और टूलिंग को लागू करना मुश्किल है क्योंकि उन्हें अधिक उन्नत पार्सिंग तकनीकों (नीचे देखें) का उपयोग करना होगा।
जब हम भाषा का विस्तार करना चाहते हैं, केवल एकमात्र दृष्टिकोण उन प्रतीकों का उपयोग करना है जो पहले भाषा में कानूनी नहीं थे। विशेष रूप से, ये पहचानकर्ता नहीं हो सकते। फ़ॉरच लूप सिंटैक्स के साथ, जावा ने मौजूदा :
कीवर्ड को नए अर्थ के साथ पुन: उपयोग किया । लैम्ब्डा के साथ, जावा ने एक ->
कीवर्ड जोड़ा जो पहले किसी भी कानूनी कार्यक्रम में नहीं हो सकता था ( -->
अभी भी वैसा ही होगा जैसा '--' '>'
कि कानूनी है, और ->
पहले जैसा हो सकता है '-', '>'
, लेकिन उस अनुक्रम को पार्सर द्वारा अस्वीकार कर दिया जाएगा)।
प्रासंगिक कीवर्ड भाषाओं को सरल बनाते हैं, उन्हें लागू करते हैं
लेक्सर्स निर्विवाद रूप से उपयोगी हैं। लेकिन पार्सर से पहले एक लेसर चलाने के बजाय, हम उन्हें पार्सर के साथ मिलकर चला सकते हैं। बॉटम-अप पार्सर हमेशा टोकन प्रकार के सेट को जानते हैं जो किसी भी स्थान पर स्वीकार्य होगा। पार्सर फिर लेक्सर से अनुरोध कर सकता है कि वह वर्तमान स्थिति में इनमें से किसी भी प्रकार से मेल खाए। प्रत्येक लूप के लिए, पार्सर उस स्थिति ·
में होगा, जो चर के पाए जाने के बाद (सरलीकृत) व्याकरण द्वारा दर्शाया गया है:
for_loop = for_loop_cstyle | for_each_loop
for_loop_cstyle = 'for' '(' declaration · ';' expression ';' expression ')'
for_each_loop = 'for' '(' declaration · 'in' expression ')'
उस स्थिति में, कानूनी टोकन SEMICOLON
या हैं IN
, लेकिन नहीं IDENT
। एक कीवर्ड in
पूरी तरह से अस्पष्ट होगा।
इस विशेष उदाहरण में, टॉप-डाउन पार्सर्स को कोई समस्या नहीं होगी क्योंकि हम उपरोक्त व्याकरण को फिर से लिख सकते हैं
for_loop = 'for' '(' declaration · for_loop_rest ')'
for_loop_rest = · ';' expression ';' expression
for_loop_rest = · 'in' expression
और निर्णय के लिए आवश्यक सभी टोकन बैकट्रैकिंग के बिना देखे जा सकते हैं।
प्रयोज्यता पर विचार करें
जावा ने हमेशा शब्दार्थ और वाक्य-विन्यास सरलता की ओर प्रवृत्त किया है। उदाहरण के लिए, भाषा ऑपरेटर ओवरलोडिंग का समर्थन नहीं करती है क्योंकि यह कोड को अधिक जटिल बना देगा। इसलिए जब प्रत्येक लूप सिंटैक्स के लिए in
और उसके बीच निर्णय लेते हैं :
, तो हमें विचार करना होगा कि कौन सा कम भ्रमित है और उपयोगकर्ताओं के लिए अधिक स्पष्ट है। चरम मामला शायद होगा
for (in in in in())
for (in in : in())
(नोट: जावा के नाम प्रकार, चर और विधियों के लिए अलग-अलग नामस्थान हैं। मुझे लगता है कि यह एक गलती थी, ज्यादातर इसका मतलब यह नहीं है कि बाद में भाषा के डिजाइन में अधिक गलतियाँ जोड़नी होंगी।)
कौन सा विकल्प पुनरावृत्ति चर और पुनरावृत्त संग्रह के बीच स्पष्ट दृश्य पृथक्करण प्रदान करता है? जब आप कोड को देखते हैं तो कौन से विकल्प को अधिक तेज़ी से पहचाना जा सकता है? मैंने पाया है कि जब इन मानदंडों की बात आती है, तो शब्दों को अलग करना प्रतीकों से बेहतर होता है। अन्य भाषाओं के अलग-अलग मूल्य हैं। उदाहरण के लिए, पायथन अंग्रेजी में कई ऑपरेटरों को मंत्र देता है ताकि उन्हें स्वाभाविक रूप से पढ़ा जा सके और समझने में आसान हो, लेकिन उन्हीं गुणों को एक नज़र में पायथन के एक टुकड़े को समझना काफी मुश्किल हो सकता है।