मैं अपने द्वारा तैयार किए गए कुछ एक्सेल जैसे सूत्रों को पार्स करने के लिए एक व्याकरण बनाने की कोशिश कर रहा हूं, जहां एक स्ट्रिंग की शुरुआत में एक विशेष चरित्र एक अलग स्रोत का संकेत देता है। उदाहरण के लिए, $
एक स्ट्रिंग को सूचित कर सकता है, इसलिए " $This is text
" को प्रोग्राम में एक स्ट्रिंग इनपुट के रूप में माना जाएगा और &
एक फ़ंक्शन को सूचित &foo()
कर सकता है , इसलिए इसे आंतरिक फ़ंक्शन के लिए कॉल के रूप में माना जा सकता है foo
।
समस्या यह है कि मैं व्याकरण का निर्माण ठीक से कैसे करूं। उदाहरण के लिए, यह MWE के रूप में एक सरलीकृत संस्करण है:
grammar = r'''start: instruction
?instruction: simple
| func
STARTSYMBOL: "!"|"#"|"$"|"&"|"~"
SINGLESTR: (LETTER+|DIGIT+|"_"|" ")*
simple: STARTSYMBOL [SINGLESTR] (WORDSEP SINGLESTR)*
ARGSEP: ",," // argument separator
WORDSEP: "," // word separator
CONDSEP: ";;" // condition separator
STAR: "*"
func: STARTSYMBOL SINGLESTR "(" [simple|func] (ARGSEP simple|func)* ")"
%import common.LETTER
%import common.WORD
%import common.DIGIT
%ignore ARGSEP
%ignore WORDSEP
'''
parser = lark.Lark(grammar, parser='earley')
तो, यह व्याकरण के साथ, जैसी चीजों: $This is a string
, &foo()
, &foo(#arg1)
, &foo($arg1,,#arg2)
और &foo(!w1,w2,w3,,!w4,w5,w6)
सब की उम्मीद के रूप में पार्स कर रहे हैं। लेकिन अगर मैं अपने simple
टर्मिनल में अधिक लचीलापन जोड़ना चाहता हूं , तो मुझे SINGLESTR
टोकन परिभाषा के साथ चक्कर लगाना शुरू करना होगा जो सुविधाजनक नहीं है।
मैंने क्या कोशिश की है
जो हिस्सा मुझे नहीं मिल सकता है, वह यह है कि अगर मैं कोष्ठक (जिसमें शाब्दिक func
) सहित एक स्ट्रिंग रखना चाहता हूं , तो मैं अपनी वर्तमान स्थिति में उन्हें संभाल नहीं सकता।
- यदि मैं कोष्ठकों को जोड़ता हूं
SINGLESTR
, तो मैं प्राप्त करता हूंExpected STARTSYMBOL
, क्योंकि यहfunc
परिभाषा के साथ मिश्रित हो रहा है और यह सोचता है कि एक फ़ंक्शन तर्क पारित किया जाना चाहिए, जो समझ में आता है। - यदि मैं केवल कार्यों के लिए एम्परसेंड प्रतीक को आरक्षित करने के लिए व्याकरण को पुनर्परिभाषित करता हूं और कोष्ठक को जोड़ता
SINGLESTR
हूं, तो मैं कोष्ठक के साथ एक स्ट्रिंग पार्स कर सकता हूं, लेकिन हर फ़ंक्शन मैं पार्स करने की कोशिश कर रहा हूंExpected LPAR
।
मेरा इरादा यह है कि किसी भी चीज की शुरुआत $
एक SINGLESTR
टोकन के रूप में की जाएगी और फिर मैं चीजों को पार्स कर सकता हूं &foo($first arg (has) parentheses,,$second arg)
।
मेरा समाधान, अभी के लिए, मैं अपने तार में LEFTPAR और RIGHTPAR जैसे 'बच' शब्दों का उपयोग कर रहा हूं और जब मैं पेड़ को संसाधित करता हूं तो उन को कोष्ठक में बदलने के लिए सहायक कार्य लिखा होता है। इसलिए, $This is a LEFTPARtestRIGHTPAR
सही पेड़ का उत्पादन करता है और जब मैं इसे संसाधित करता हूं, तो इसका अनुवाद किया जाता है This is a (test)
।
एक सामान्य प्रश्न तैयार करने के लिए: क्या मैं अपने व्याकरण को इस तरह से परिभाषित कर सकता हूं कि कुछ वर्ण जो व्याकरण के लिए विशेष हैं, उन्हें कुछ स्थितियों में सामान्य पात्रों के रूप में और किसी अन्य मामले में विशेष माना जाता है?
EDIT 1
एक टिप्पणी के आधार पर से jbndlr
मैं अलग-अलग प्रारंभ प्रतीक के आधार पर मोड बनाने के लिए मेरी व्याकरण संशोधित:
grammar = r'''start: instruction
?instruction: simple
| func
SINGLESTR: (LETTER+|DIGIT+|"_"|" ") (LETTER+|DIGIT+|"_"|" "|"("|")")*
FUNCNAME: (LETTER+) (LETTER+|DIGIT+|"_")* // no parentheses allowed in the func name
DB: "!" SINGLESTR (WORDSEP SINGLESTR)*
TEXT: "$" SINGLESTR
MD: "#" SINGLESTR
simple: TEXT|DB|MD
ARGSEP: ",," // argument separator
WORDSEP: "," // word separator
CONDSEP: ";;" // condition separator
STAR: "*"
func: "&" FUNCNAME "(" [simple|func] (ARGSEP simple|func)* ")"
%import common.LETTER
%import common.WORD
%import common.DIGIT
%ignore ARGSEP
%ignore WORDSEP
'''
यह मेरे दूसरे परीक्षण के मामले में आता है (कुछ हद तक)। मैं सभी simple
प्रकार के तार (पाठ, एमडी या डीबी टोकन जिसमें कोष्ठक हो सकते हैं) और रिक्त होने वाले कार्यों को पार्स कर सकता हूं ; उदाहरण के लिए, &foo()
या &foo(&bar())
सही ढंग से पार्स। जिस क्षण मैंने एक फ़ंक्शन के भीतर एक तर्क रखा (कोई फर्क नहीं पड़ता कि किस प्रकार), मुझे ए UnexpectedEOF Error: Expected ampersand, RPAR or ARGSEP
। अवधारणा के प्रमाण के रूप में, यदि मैं ऊपर दिए गए नए व्याकरण में SINGLESTR की परिभाषा से कोष्ठक हटाता हूं, तो सब कुछ उसी तरह काम करता है, जैसा कि मुझे करना चाहिए, लेकिन मैं एक वर्ग में वापस आ गया हूं।
STARTSYMBOL
) और आप विभाजक और कोष्ठक जोड़ते हैं जहाँ स्पष्ट होना आवश्यक है; मैं यहाँ कोई अस्पष्टता नहीं देखता। आपको अभी भी अपनीSTARTSYMBOL
सूची को अलग-अलग मदों में विभाजित करना होगा।