मनमाने ढंग से संदर्भ मुक्त व्याकरण, ज्यादातर लघु स्निपेट को पार्स करना


20

मैं उपयोगकर्ता-परिभाषित डोमेन विशिष्ट भाषाओं को पार्स करना चाहता हूं। ये भाषाएं आम तौर पर गणितीय संकेतन के करीब होती हैं (मैं एक प्राकृतिक भाषा को पार्स नहीं कर रहा हूं)। उपयोगकर्ता अपने DSL को BNF संकेतन में इस तरह परिभाषित करते हैं:

expr ::= LiteralInteger
       | ( expr )
       | expr + expr
       | expr * expr

इनपुट 1 + ( 2 * 3 )को स्वीकार किया जाना चाहिए, जबकि इनपुट 1 +को गलत के रूप में अस्वीकार किया जाना चाहिए, और इनपुट 1 + 2 * 3को अस्पष्ट के रूप में अस्वीकार किया जाना चाहिए।

यहां एक केंद्रीय कठिनाई उपयोगकर्ता के अनुकूल तरीके से अस्पष्ट व्याकरण का सामना कर रही है। व्याकरण को असंदिग्ध होने के लिए प्रतिबंधित करना एक विकल्प नहीं है: यही वह तरीका है कि भाषा है - विचार यह है कि लेखक पितृपक्ष को छोड़ना पसंद करते हैं जब वे अस्पष्टता से बचने के लिए आवश्यक नहीं होते हैं। जब तक एक अभिव्यक्ति अस्पष्ट नहीं है, मुझे इसे पार्स करने की आवश्यकता है, और यदि ऐसा नहीं है, तो मुझे इसे अस्वीकार करने की आवश्यकता है।

मेरे पार्सर को किसी भी संदर्भ-मुक्त व्याकरण, यहां तक ​​कि अस्पष्ट लोगों पर भी काम करना चाहिए, और सभी अस्पष्ट इनपुट को स्वीकार करना चाहिए। मुझे सभी स्वीकृत इनपुट के लिए पार्स ट्री की आवश्यकता है। अमान्य या अस्पष्ट इनपुट के लिए, मैं आदर्श रूप से अच्छे त्रुटि संदेश चाहता हूं, लेकिन इसके साथ शुरू करने के लिए मैं वही ले सकता हूं जो मुझे मिल सकता है।

मैं आमतौर पर कभी-कभार इनपुट के साथ पार्सर को अपेक्षाकृत कम इनपुट पर आमंत्रित करता हूं। तो asymptotically तेज एल्गोरिथ्म सबसे अच्छा विकल्प नहीं हो सकता है। मैं 20 प्रतीकों से कम लगभग 80% इनपुट्स के वितरण के लिए अनुकूलन करना चाहता हूं, 20 और 50 प्रतीकों के बीच 19%, और 1% दुर्लभ इनपुट इनपुटों के बीच। अमान्य इनपुट के लिए गति एक बड़ी चिंता का विषय नहीं है। इसके अलावा, मैं हर 1000 से 100000 इनपुट के आसपास DSL के संशोधन की उम्मीद करता हूं; मैं एक-दो मिनट नहीं, बल्कि अपने व्याकरण के बारे में कुछ सेकंड पहले ही खर्च कर सकता हूं।

मेरे विशिष्ट इनपुट आकारों को देखते हुए मुझे क्या एल्गोरिथ्म की जांच करनी चाहिए? क्या त्रुटि रिपोर्टिंग मेरे चयन में एक कारक होनी चाहिए, या क्या मुझे अस्पष्ट इनपुटों को पार्स करने पर ध्यान केंद्रित करना चाहिए और संभवतः त्रुटि प्रतिक्रिया प्रदान करने के लिए पूरी तरह से अलग, धीमी गति से चलने वाला पार्सर चलाना चाहिए?

(उस परियोजना में जहां मुझे जरूरत थी (थोड़ी देर पहले), मैंने CYK का उपयोग किया , जिसे लागू करना बहुत मुश्किल नहीं था और अपने इनपुट आकारों के लिए पर्याप्त रूप से काम किया लेकिन बहुत अच्छी त्रुटियों का उत्पादन नहीं किया।)


विशेष रूप से अच्छी त्रुटि रिपोर्ट प्राप्त करना कठिन लगता है। आपके पास एक से अधिक स्थानीय परिवर्तन हो सकते हैं जो अस्पष्ट व्याकरण के मामले में एक स्वीकृत इनपुट की ओर ले जाते हैं।
राफेल

मैंने बस नीचे उत्तर दिया। एक पुराने प्रश्न के एक संशोधन का जवाब देना थोड़ा अजीब है जो पहले से ही एक अच्छी तरह से प्राप्त उत्तर है। जाहिर है कि मैं एक समान तरीके से जवाब देने वाला नहीं हूं, लेकिन उपयोगकर्ता दोनों उत्तरों को पढ़ेंगे जैसे कि वे एक ही प्रश्न का उत्तर दे रहे थे।
Babou

क्या आप वास्तव में अस्पष्ट इनपुट के लिए एक त्रुटि संदेश की उम्मीद करते हैं, यदि कोई उपयोगकर्ता लिखता है x+y+z
बबौ

@babou मैंने सवाल नहीं बदला, मैंने केवल टिप्पणियों में अनुरोध किए गए स्पष्टीकरण (अब हटाए गए) जोड़े। यहाँ दिए गए छोटे व्याकरण के लिए, मैंने इसके लिए संबद्धता निर्दिष्ट नहीं की है +, इसलिए x+y+zयह वास्तव में अस्पष्ट है इसलिए गलत है।
गिल्स एसओ- बुराई को रोकना '

ठीक है, यह आपका अंतिम वाक्य है, सिर्फ जोड़ा, भले ही कोष्ठक के बीच। आप कहते हैं: मैंने अंत में इसे CYK के साथ किया था, लेकिन यह कुछ कारणों से पर्याप्त नहीं है। और मुझे आश्चर्य है कि सटीक कारण क्या हो सकते हैं ... आप अब , अपनी तरह की समस्या और आपके द्वारा उपयोग किए जाने वाले समाधान के साथ सबसे अधिक अनुभव वाले व्यक्ति हैं, इसलिए यदि आपसे आगे उत्तर दिए जाने हैं, तो आपसे अधिक जानकारी की उम्मीद होगी।
बबौ

जवाबों:


19

संभवतः आपकी आवश्यकताओं के लिए आदर्श एल्गोरिथ्म सामान्यीकृत एलएल पार्सिंग , या जीएलएल है। यह एक बहुत ही नया एल्गोरिथ्म है (पेपर 2010 में प्रकाशित हुआ था)। एक तरह से, यह एक ग्राफ संरचित स्टैक (जीएसएस) के साथ संवर्धित ईयरली एल्गोरिदम है, और एलएल (1) लुकहेड का उपयोग कर रहा है।

एल्गोरिथ्म सादे पुराने एलएल (1) के समान है, सिवाय इसके कि यह व्याकरण को अस्वीकार नहीं करता है यदि वे एलएल (1) नहीं हैं: यह सिर्फ सभी संभावित एलएल (1) पर्स की कोशिश करता है। यह पार्स में हर बिंदु के लिए एक निर्देशित ग्राफ का उपयोग करता है, जिसका अर्थ है कि अगर एक पार्स राज्य का सामना किया गया है जो पहले से निपटा गया है, तो यह बस इन दो शीर्षों को मिला देता है। यह एलएल के विपरीत, बाएं-पुनरावर्ती व्याकरण के लिए भी उपयुक्त बनाता है। अपने आंतरिक कामकाज पर सटीक विवरण के लिए, पेपर पढ़ें (यह काफी पठनीय पेपर है, हालांकि लेबल सूप के लिए कुछ दृढ़ता की आवश्यकता होती है)।

एल्गोरिथ्म में अन्य सामान्य पार्सिंग एल्गोरिदम (जो मुझे पता है) पर आपकी आवश्यकताओं के लिए प्रासंगिक कई स्पष्ट लाभ हैं। सबसे पहले, कार्यान्वयन बहुत आसान है: मुझे लगता है कि केवल अर्ली को लागू करना आसान है। दूसरे, प्रदर्शन काफी अच्छा है: वास्तव में, यह एलएल (1) के व्याकरण पर एलएल (1) के समान ही तेज हो जाता है। तीसरा, पार्स को पुनर्प्राप्त करना काफी आसान है, और यह जांचना कि क्या एक से अधिक संभावित पार्स भी है।

जीएलएल का मुख्य लाभ यह है कि यह एलएल (1) पर आधारित है और इसलिए इसे समझना और डिबग करना बहुत आसान है, जब इसे लागू किया जाता है, तो व्याकरण डिजाइन करने के साथ-साथ इनपुट को पार्स करते समय। इसके अलावा, यह त्रुटि से निपटने में भी आसान बनाता है: आप ठीक से जानते हैं कि संभावित पार्स कहां फंसे हैं और वे कैसे जारी रख सकते हैं। आप त्रुटि के बिंदु पर संभावित पार्स को आसानी से दे सकते हैं और, कह सकते हैं, अंतिम 3 बिंदु जहां पार्स फंसे थे। आप इसके बजाय त्रुटि से उबरने का प्रयास करने का विकल्प चुन सकते हैं, और उत्पादन को चिह्नित कर सकते हैं कि जिस पार्स को फुर्सत मिली, वह उस पार्स के लिए 'पूर्ण' के रूप में काम कर रहा था, और देखें कि क्या पार्सिंग उसके बाद भी जारी रह सकता है (जैसे कोई किसी को कोष्ठक को भूल गया)। आप ऐसा भी कर सकते हैं, कहते हैं, 5 परसेंट जो सबसे दूर मिले।

एल्गोरिथ्म का एकमात्र नकारात्मक पहलू यह है कि यह नया है, जिसका अर्थ है कि कोई अच्छी तरह से स्थापित कार्यान्वयन आसानी से उपलब्ध नहीं हैं। यह आपके लिए एक समस्या नहीं हो सकती है - मैंने एल्गोरिथ्म को स्वयं लागू किया है, और यह करना काफी आसान था।


कुछ नया सीखकर अच्छा लगा। जब मुझे इसकी आवश्यकता थी (कुछ साल पहले, एक परियोजना में जिसे मैं किसी दिन पुनर्जीवित करना चाहूंगा), मैंने CYK का उपयोग किया, मोटे तौर पर क्योंकि यह पहला एल्गोरिथ्म था जो मुझे मिला। GLL अस्पष्ट इनपुट कैसे संभालती है? लेख इस पर चर्चा नहीं करता है, लेकिन मैंने केवल इसे स्किम किया है।
गिल्स एसओ- बुराई को रोकें '

@ गिल्स: यह एक ग्राफ स्ट्रक्चर्ड स्टैक का निर्माण करता है, और सभी (संभावित रूप से बहुत सारे) पार्स को इस ग्राफ में कॉम्पैक्ट रूप से दर्शाया जाता है, जीएलआर कैसे काम करता है। अगर मुझे सही से याद है, तो cstheory.stackexchange.com/questions/7374/… में उल्लिखित पेपर इससे संबंधित है।
एलेक्स दस ब्रिंक

@ गिल्स 2010 के इस पार्सर को व्याकरण से हाथ से प्रोग्राम किया हुआ प्रतीत होता है, यदि आपके पास कई भाषाएं हैं, या यदि आप अक्सर भाषा को संशोधित करते हैं, तो यह पर्याप्त नहीं है। किसी भी चुने हुए रणनीति (एलएल, एलआर या अन्य) के बाद सामान्य पार्सर के व्याकरण से स्वचालित पीढ़ी के लिए तकनीक और सभी पार्स के जंगल का निर्माण लगभग 40 वर्षों से जाना जाता है। हालांकि पार्स का प्रतिनिधित्व करने वाले ग्राफ की जटिलता और संगठन के बारे में छिपे हुए मुद्दे हैं। पार्स की संख्या घातीय से भी बदतर हो सकती है: अनंत। त्रुटि सुधार अधिक व्यवस्थित, पार्सर स्वतंत्र तकनीकों का उपयोग कर सकता है।
बबौ

ANLLR में पाया जाने वाला LLL LL (*) से कैसे संबंधित है?
राफेल

6

मेरी कंपनी (सिमेंटिक डिज़ाइन्स) ने जीएलआर पार्सर्स का उपयोग बहुत ही सफलतापूर्वक किया है, जो ओपी को डोमेन डीपवेयर भाषाओं में, और हमारे डीएमएस सॉफ्टवेयर रीइंजीनियरिंग टूलकिट के साथ "क्लासिक" प्रोग्रामिंग भाषाओं को पार्स करने का सुझाव देता है। यह बड़े पैमाने पर कार्यक्रम के पुनर्गठन / रिवर्स इंजीनियरिंग / फॉरवर्ड कोड पीढ़ी के लिए उपयोग किए जाने वाले स्रोत-से-स्रोत कार्यक्रम परिवर्तनों का समर्थन करता है । इसमें काफी व्यावहारिक तरीके से वाक्य रचना त्रुटियों की स्वचालित मरम्मत शामिल है। एक नींव के रूप में जीएलआर का उपयोग करना, और कुछ अन्य परिवर्तन (सिमेंटिक भविष्यवाणी करता है, टोकन सेट इनपुट के बजाय सिर्फ टोकन इनपुट, ...) हमने कुछ 40 भाषाओं के लिए पार्सर बनाने में कामयाबी हासिल की है।

पूरी भाषाओं के उदाहरणों को पार्स करने की क्षमता जितनी महत्वपूर्ण है, GLR भी स्रोत-से-स्रोत पुनर्लेखन नियमों को पार्स करने में बेहद उपयोगी साबित हुई है । ये एक पूर्ण कार्यक्रम की तुलना में बहुत कम संदर्भ के साथ कार्यक्रम के टुकड़े हैं, और इस प्रकार आम तौर पर अधिक अस्पष्टता है। हम नियमों का पालन करने के दौरान / बाद में उन अस्पष्टताओं को हल करने में मदद करने के लिए विशेष एनोटेशन (उदाहरण के लिए, एक वाक्यांश एक विशिष्ट व्याकरण के लिए अनुरूप) का उपयोग करते हैं। जीएलआर पार्सिंग मशीनरी और उसके आस-पास के उपकरणों को व्यवस्थित करने से, हमें इसकी भाषा के लिए पार्सर होने के बाद "फ्री" के लिए नियमों को फिर से लिखने के लिए पार्सर मिलते हैं। डीएमएस इंजन में एक बिल्ट-इन रीराइट-रूल एप्लायड है जो तब वांछित कोड परिवर्तन करने के लिए इन नियम को लागू करने के लिए इस्तेमाल किया जा सकता है।

संभवतः हमारा सबसे शानदार परिणाम आधार के रूप में एक संदर्भ-मुक्त व्याकरण का उपयोग करके, सभी अस्पष्टताओं के बावजूद, पूर्ण C ++ 14 को पार्स करने की क्षमता है । मैं ध्यान देता हूं कि सभी क्लासिक सी ++ कंपाइलर (जीसीसी, क्लैंग) ने ऐसा करने और हाथ से लिखे पर्सर्स का उपयोग करने की क्षमता को छोड़ दिया है (जो कि आईएमएचओ उन्हें बनाए रखने के लिए बहुत कठिन बनाता है, लेकिन फिर, वे मेरी समस्या नहीं हैं)। हमने इस मशीनरी का उपयोग बड़े C ++ सिस्टम की वास्तुकला में बड़े पैमाने पर बदलाव करने के लिए किया है।

प्रदर्शन-वार, हमारे जीएलआर पार्सर यथोचित रूप से तेज हैं: प्रति सेकंड हजारों लाइनें। यह कला की स्थिति से काफी नीचे है, लेकिन हमने इसे अनुकूलित करने के लिए कोई गंभीर प्रयास नहीं किया है, और कुछ अड़चनें चरित्र प्रवाह प्रसंस्करण (पूर्ण यूनिकोड) में हैं। ऐसे पार्सर्स के निर्माण के लिए, हम संदर्भ मुक्त व्याकरणों को एक LR (1) पार्सर जनरेटर के काफी करीब का उपयोग करके पूर्व-संसाधित करते हैं; यह सामान्य रूप से बड़े व्याकरणों पर C ++ के आकार में एक आधुनिक कार्य केंद्र पर दस सेकंड में चलता है। हैरानी की बात है, आधुनिक कॉबोल और सी ++ जैसी बहुत ही जटिल भाषाओं के लिए, लेकर्स की पीढ़ी लगभग एक मिनट लेती है; यूनिकोड पर परिभाषित डीएफए में से कुछ सुंदर बालों वाले मिलते हैं। मैंने सिर्फ रूबी (एक पूर्ण सबग्रमर के साथ अपने अविश्वसनीय रेगेक्स के लिए) एक उंगली-व्यायाम के रूप में किया; डीएमएस अपने लेसर और व्याकरण को लगभग 8 सेकंड में एक साथ प्रोसेस कर सकता है।


@ रिपेल: "बड़े पैमाने पर परिवर्तन" लिंक शैक्षणिक शैली के तकनीकी कागजात के एक सेट की ओर इशारा करता है, जिसमें सी ++ आर्किटेक्चर री-इंजीनियरिंग पर कुछ, डीएमएस इंजन पर ही एक है (बल्कि पुराने हैं लेकिन मूल रूप से अच्छी तरह से वर्णन करता है), और एक पर। डिजाइन पर कब्जा करने और पुन: उपयोग का विदेशी विषय, जो डीएमएस के लिए मूल प्रेरणा था (अभी भी अस्वीकार्य है, दुर्भाग्य से, लेकिन डीएमएस वैसे भी बहुत उपयोगी निकला है)।
इरा बैक्सटर

1

कई सामान्य संदर्भ-मुक्त पार्सर हैं जो अस्पष्ट वाक्यों (एक अस्पष्ट व्याकरण के अनुसार) को पार्स कर सकते हैं। वे विभिन्न नामों के अंतर्गत आते हैं, विशेष रूप से गतिशील-प्रोग्रामिंग या चार्ट पार्सर। सबसे अच्छा ज्ञात एक, और सबसे सरल के बगल में, संभवतः CYK पार्सर है जो आप उपयोग कर रहे हैं। उस सामान्यता की आवश्यकता तब होती है जब आपको कई पर्स को संभालना होता है और अंत तक पता नहीं चलता है कि आप अस्पष्टता से निपट रहे हैं या नहीं।

आप जो कहते हैं, उससे मुझे लगता है कि CYK इतना बुरा विकल्प नहीं है। संभवतः आपके पास भविष्यवाणियां (एलएल या एलआर) जोड़कर अधिक लाभ नहीं है, और यह वास्तव में भेदभाव की गणना करके लागत हो सकती है जिसे भेदभाव (विशेष रूप से एलआर मामले में) के बजाय विलय किया जाना चाहिए। वे उत्पादित होने वाले पार्स वन के आकार में भी एक समान लागत रख सकते हैं (जिसमें अस्पष्टता त्रुटियों में भूमिका हो सकती है)। दरअसल, जबकि मुझे यकीन नहीं है कि औपचारिक रूप से अधिक परिष्कृत एल्गोरिदम की तुलना कैसे की जाए, मुझे पता है कि CYK अच्छी संगणना साझा करता है।

अब, मुझे विश्वास नहीं है कि अस्पष्ट व्याकरण के लिए सामान्य सीएफ पार्सर पर बहुत साहित्य है जो केवल अस्पष्ट इनपुट को स्वीकार करना चाहिए। मुझे किसी को देखकर याद नहीं है, शायद इसलिए भी कि तकनीकी दस्तावेजों के लिए, या यहां तक ​​कि प्रोग्रामिंग भाषाओं के लिए, वाक्यविन्यास अस्पष्टता स्वीकार्य है जब तक कि इसे अन्य साधनों (जैसे एडीए अभिव्यक्तियों में अस्पष्टता) द्वारा हल किया जा सकता है।

मैं वास्तव में सोच रहा हूं कि आप अपने एल्गोरिथ्म को क्यों बदलना चाहते हैं, बजाय इसके कि आपके पास क्या है। इससे मुझे यह समझने में मदद मिल सकती है कि किस तरह का बदलाव आपकी सबसे अच्छी मदद कर सकता है। क्या यह गति का मुद्दा है, क्या यह पार्स का प्रतिनिधित्व है, या यह त्रुटि का पता लगाने और पुनर्प्राप्ति है?

कई पार्स का प्रतिनिधित्व करने का सबसे अच्छा तरीका एक साझा वन के साथ है, जो केवल एक संदर्भ-मुक्त व्याकरण है जो केवल आपके इनपुट को उत्पन्न करता है, लेकिन बिल्कुल समान पार्स पेड़ों के साथ डीएसएल व्याकरण। यह समझने और प्रक्रिया करने में बहुत आसान बनाता है। अधिक जानकारी के लिए, मेरा सुझाव है कि आप इस उत्तर को देखें जो मैंने भाषाई साइट पर दिया था। मैं समझता हूं कि आप एक पार्स वन प्राप्त करने में रुचि नहीं रखते हैं, लेकिन पार्स वन का एक उचित प्रतिनिधित्व आपको बेहतर संदेश देने में मदद कर सकता है कि अस्पष्टता प्रोबलन क्या है। इससे आपको यह तय करने में भी मदद मिल सकती है कि यदि आप ऐसा करना चाहते हैं तो अस्पष्टता कुछ मामलों (सहानुभूति) में मायने नहीं रखती है।

आप अपने DSL व्याकरण के प्रसंस्करण समय की कमी का उल्लेख करते हैं, लेकिन इसके आकार के अनुसार कोई संकेत नहीं देते हैं (इसका मतलब यह नहीं है कि मैं आपके द्वारा किए गए आंकड़ों के साथ उत्तर दे सकता है)।

कुछ त्रुटि प्रसंस्करण को इन सामान्य सीएफ एल्गोरिदम में सरल तरीकों से एकीकृत किया जा सकता है। लेकिन मुझे यह समझने की आवश्यकता है कि किस प्रकार की त्रुटि प्रसंस्करण आप अधिक सकारात्मक होने की उम्मीद करते हैं। क्या आपके पास कुछ उदाहरण होंगे।

मैं अधिक कहने में आसानी से थोड़ा बीमार हूं, क्योंकि मुझे समझ नहीं आ रहा है कि वास्तव में आपकी प्रेरणाएं और बाधाएं क्या हैं। आप जो कहते हैं, उसके आधार पर, मैं CYK (और मैं अन्य एल्गोरिदम और उनके कुछ गुणों को जानता हूं) से चिपके रहेंगे।

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