जवाबों:
वास्तव में तीन विकल्प हैं, उनमें से तीन अलग-अलग स्थितियों में बेहतर हैं।
कहते हैं, अब आपको कुछ प्राचीन डेटा प्रारूप के लिए एक पार्सर बनाने के लिए कहा जाता है। या आपको अपने पार्सर को तेज़ होने की आवश्यकता है। या आप आसानी से बनाए रखने के लिए अपने पार्सर की जरूरत है।
इन मामलों में, आप शायद पार्सर जनरेटर का उपयोग कर रहे हैं। आपको विवरणों के बारे में जानने की आवश्यकता नहीं है, आपको ठीक से काम करने के लिए बहुत सारे जटिल कोड प्राप्त करने की आवश्यकता नहीं है, आप बस व्याकरण लिखें जो इनपुट का पालन करेगा, कुछ हैंडलिंग कोड और प्रेस्टो लिखें: तत्काल पार्सर।
लाभ स्पष्ट हैं:
एक बात है जो आपको पार्सर-जनरेटर के साथ सावधान रहना होगा: कभी-कभी आपके व्याकरण को अस्वीकार कर सकता है। विभिन्न प्रकार के पार्सर्स के अवलोकन के लिए और वे आपको कैसे काट सकते हैं, आप यहां शुरू करना चाहते हैं । यहां आप बहुत सारे कार्यान्वयन और व्याकरण के प्रकारों का अवलोकन पा सकते हैं, जिन्हें वे स्वीकार करते हैं।
पार्सर जनरेटर अच्छे हैं, लेकिन वे बहुत उपयोगकर्ता (अंत-उपयोगकर्ता, आप नहीं) के अनुकूल नहीं हैं। आप आमतौर पर अच्छे त्रुटि संदेश नहीं दे सकते हैं, न ही आप त्रुटि सुधार प्रदान कर सकते हैं। शायद आपकी भाषा बहुत ही अजीब है और पार्सर आपके व्याकरण को अस्वीकार कर देते हैं या आपको जनरेटर द्वारा आपको अधिक नियंत्रण की आवश्यकता होती है।
इन मामलों में, हाथ से लिखे गए पुनरावर्ती-वंशीय पार्सर का उपयोग करना संभवतः सबसे अच्छा है। यह सही होने पर जटिल हो सकता है, आपके पास अपने पार्सर पर पूरा नियंत्रण है, ताकि आप सभी प्रकार के अच्छे सामान कर सकें जो आप पार्सर जनरेटर के साथ नहीं कर सकते हैं, जैसे त्रुटि संदेश और यहां तक कि त्रुटि पुनर्प्राप्ति (सी # फ़ाइल से सभी अर्धविरामों को हटाने का प्रयास करें) : C # कंपाइलर शिकायत करेगा, लेकिन अर्धविराम की मौजूदगी की परवाह किए बिना ज्यादातर अन्य त्रुटियों का पता लगाएगा)।
हाथ से लिखे गए पार्सर आमतौर पर उत्पन्न लोगों की तुलना में बेहतर प्रदर्शन करते हैं, यह मानते हुए कि पार्सर की गुणवत्ता काफी अधिक है। दूसरी ओर, यदि आप एक अच्छा पार्सर लिखने का प्रबंधन नहीं करते हैं - आमतौर पर अनुभव (ज्ञान) या डिजाइन की कमी (संयोजन) के कारण - तो प्रदर्शन आमतौर पर धीमा होता है। लेक्सर्स के लिए इसके विपरीत सच है: आम तौर पर उत्पन्न लेकर्स टेबल लुकअप का उपयोग करते हैं, जिससे वे (सबसे) हाथ से लिखे गए लोगों की तुलना में तेज होते हैं।
शिक्षा-वार, अपने स्वयं के पार्सर को लिखना आपको एक जनरेटर का उपयोग करने से अधिक सिखाएगा। आपको अधिक से अधिक जटिल कोड लिखना होगा, इसके अलावा आपको यह समझना होगा कि आप किसी भाषा को कैसे पार्स करते हैं। दूसरी ओर, यदि आप सीखना चाहते हैं कि अपनी भाषा कैसे बनाएं (तो, भाषा डिजाइन में अनुभव प्राप्त करें), या तो विकल्प 1 या विकल्प 3 बेहतर है: यदि आप एक भाषा विकसित कर रहे हैं, तो यह संभवतः बहुत कुछ बदल देगा। और विकल्प 1 और 3 आपको इसके साथ एक आसान समय देते हैं।
यह वह रास्ता है जिस पर मैं वर्तमान में चल रहा हूं: आप अपना स्वयं का पार्सर जनरेटर लिखें । अत्यधिक अनौपचारिक होते हुए, ऐसा करना संभवतः आपको सबसे अधिक सिखाएगा।
आपको एक विचार देने के लिए कि इस तरह की परियोजना में क्या शामिल है, मैं आपको अपनी प्रगति के बारे में बताऊंगा।
लेसर जेनरेटर
मैंने पहले अपना खुद का लेक्सर जनरेटर बनाया। मैं आमतौर पर सॉफ़्टवेयर डिज़ाइन करता हूं, जिसके साथ कोड का उपयोग कैसे किया जाएगा, इसलिए मैंने सोचा कि मैं कैसे अपने कोड का उपयोग करने में सक्षम होना चाहता हूं और कोड का यह टुकड़ा लिखा है (यह C # में है):
Lexer<CalculatorToken> calculatorLexer = new Lexer<CalculatorToken>(
new List<StringTokenPair>()
{ // This is just like a lex specification:
// regex token
new StringTokenPair("\\+", CalculatorToken.Plus),
new StringTokenPair("\\*", CalculatorToken.Times),
new StringTokenPair("(", CalculatorToken.LeftParenthesis),
new StringTokenPair(")", CalculatorToken.RightParenthesis),
new StringTokenPair("\\d+", CalculatorToken.Number),
});
foreach (CalculatorToken token in
calculatorLexer.GetLexer(new StringReader("15+4*10")))
{ // This will iterate over all tokens in the string.
Console.WriteLine(token.Value);
}
// Prints:
// 15
// +
// 4
// *
// 10
इनपुट स्ट्रिंग-टोकन जोड़े को एक समान पुनरावर्ती संरचना में परिवर्तित किया जाता है, जो नियमित अभिव्यक्तियों का वर्णन करता है जो वे एक अंकगणितीय स्टैक के विचारों का उपयोग करते हैं। इसके बाद इसे NFA (nondeterministic finite automaton) में बदल दिया जाता है, जो बदले में DFA (निर्धारक परिमित ऑटोमेटन) में परिवर्तित हो जाता है। फिर आप डीएफए के खिलाफ तार का मिलान कर सकते हैं।
इस तरह, आप एक अच्छा विचार प्राप्त करते हैं कि कैसे लेक्सर्स काम करते हैं। इसके अलावा, यदि आप इसे सही तरीके से करते हैं तो आपके लेक्सर जनरेटर से परिणाम पेशेवर कार्यान्वयन के रूप में तेजी से हो सकते हैं। आप विकल्प 2 की तुलना में किसी भी अभिव्यंजकता को नहीं खोते हैं, और विकल्प 1 की तुलना में बहुत अधिक अभिव्यक्ति नहीं है।
मैंने कोड के 1600 से अधिक लाइनों में अपने लेक्सर जनरेटर को लागू किया। यह कोड उपरोक्त काम करता है, लेकिन यह अभी भी हर बार जब आप कार्यक्रम शुरू करते हैं, तो मक्खी पर लेक्सर उत्पन्न करता है: मैं इसे किसी बिंदु पर डिस्क पर लिखने के लिए कोड जोड़ने जा रहा हूं।
यदि आप जानना चाहते हैं कि अपना खुद का लेख लिखने का तरीका, यह शुरू करने के लिए एक अच्छी जगह है।
पार्सर जनरेटर
आप फिर अपना पार्सर जनरेटर लिखें। मैं विभिन्न प्रकार के पार्सरों पर एक सिंहावलोकन के लिए यहां फिर से उल्लेख करता हूं - अंगूठे के एक नियम के रूप में, वे जितना अधिक पार्स कर सकते हैं, उतना ही धीमा।
गति मेरे लिए कोई समस्या नहीं है, मैंने एक एली पार्सर को लागू करने के लिए चुना। एक अर्ली पार्सर के उन्नत कार्यान्वयन को अन्य पार्सर प्रकारों के मुकाबले लगभग दोगुना दिखाया गया है ।
उस गति हिट के बदले में, आपको किसी भी तरह के व्याकरण, यहां तक कि अस्पष्ट लोगों को पार्स करने की क्षमता मिलती है। इसका मतलब है कि आपको इस बारे में कभी चिंता करने की आवश्यकता नहीं है कि क्या आपके पार्सर में कोई लेफ्ट-रिकर्सन है, या एक शिफ्ट-कम संघर्ष क्या है। आप व्याकरण का अधिक आसानी से अस्पष्ट व्याकरणों का उपयोग कर परिभाषित कर सकते हैं यदि यह कोई फर्क नहीं पड़ता कि कौन सा तोता पेड़ परिणाम है, जैसे कि यह कोई फर्क नहीं पड़ता कि आप 1 + 2 + 3 के रूप में पार्स करते हैं (1 + 2) +3 या 1 के रूप में + (2 + 3)।
यह मेरे पार्सर जनरेटर का उपयोग कर कोड का एक टुकड़ा जैसा दिख सकता है:
Lexer<CalculatorToken> calculatorLexer = new Lexer<CalculatorToken>(
new List<StringTokenPair>()
{
new StringTokenPair("\\+", CalculatorToken.Plus),
new StringTokenPair("\\*", CalculatorToken.Times),
new StringTokenPair("(", CalculatorToken.LeftParenthesis),
new StringTokenPair(")", CalculatorToken.RightParenthesis),
new StringTokenPair("\\d+", CalculatorToken.Number),
});
Grammar<IntWrapper, CalculatorToken> calculator
= new Grammar<IntWrapper, CalculatorToken>(calculatorLexer);
// Declaring the nonterminals.
INonTerminal<IntWrapper> expr = calculator.AddNonTerminal<IntWrapper>();
INonTerminal<IntWrapper> term = calculator.AddNonTerminal<IntWrapper>();
INonTerminal<IntWrapper> factor = calculator.AddNonTerminal<IntWrapper>();
// expr will be our head nonterminal.
calculator.SetAsMainNonTerminal(expr);
// expr: term | expr Plus term;
calculator.AddProduction(expr, term.GetDefault());
calculator.AddProduction(expr,
expr.GetDefault(),
CalculatorToken.Plus.GetDefault(),
term.AddCode(
(x, r) => { x.Result.Value += r.Value; return x; }
));
// term: factor | term Times factor;
calculator.AddProduction(term, factor.GetDefault());
calculator.AddProduction(term,
term.GetDefault(),
CalculatorToken.Times.GetDefault(),
factor.AddCode
(
(x, r) => { x.Result.Value *= r.Value; return x; }
));
// factor: LeftParenthesis expr RightParenthesis
// | Number;
calculator.AddProduction(factor,
CalculatorToken.LeftParenthesis.GetDefault(),
expr.GetDefault(),
CalculatorToken.RightParenthesis.GetDefault());
calculator.AddProduction(factor,
CalculatorToken.Number.AddCode
(
(x, s) => { x.Result = new IntWrapper(int.Parse(s));
return x; }
));
IntWrapper result = calculator.Parse("15+4*10");
// result == 55
(ध्यान दें कि IntWrapper बस एक Int32 है, सिवाय इसके कि C # के लिए इसे एक वर्ग की आवश्यकता है, इसलिए मुझे एक आवरण वर्ग शुरू करना पड़ा)
मुझे आशा है कि आप देख सकते हैं कि उपरोक्त कोड बहुत शक्तिशाली है: किसी भी व्याकरण के साथ आप आ सकते हैं। आप बहुत सारे कार्य करने में सक्षम व्याकरण में मनमाने ढंग से कोड जोड़ सकते हैं। यदि आप इस सभी कार्य को प्राप्त करने का प्रबंधन करते हैं, तो आप बहुत आसानी से बहुत सारे कार्य करने के लिए परिणामी कोड का फिर से उपयोग कर सकते हैं: कोड के इस टुकड़े का उपयोग करके कमांड-लाइन दुभाषिया बनाने की कल्पना करें।
यदि आपने कभी नहीं लिखा है, तो कभी एक पार्सर लिखा है मैं आपको यह करने की सलाह दूंगा। यह मजेदार है, और आप सीखते हैं कि चीजें कैसे काम करती हैं, और आप उस प्रयास की सराहना करना सीखते हैं जो पार्सर और लेक्सर जनरेटर आपको अगली बार आपको पार्सर की आवश्यकता होने से बचाते हैं ।
मैं यह भी सुझाव देता हूं कि आप http://compilers.iecc.com/crenshaw/ को पढ़ने का प्रयास करें, क्योंकि यह कैसे करना है, इसके बारे में एक बहुत ही डाउन-टू-अर्थ रवैया है।
अपने स्वयं के पुनरावर्ती वंश पार्सर को लिखने का लाभ यह है कि आप सिंटैक्स त्रुटियों पर उच्च-गुणवत्ता वाले त्रुटि संदेश उत्पन्न कर सकते हैं। पार्सर जनरेटर का उपयोग करना, आप त्रुटि निर्माण कर सकते हैं और कुछ बिंदुओं पर कस्टम त्रुटि संदेश जोड़ सकते हैं, लेकिन पार्सर जनरेटर केवल पार्सिंग पर पूर्ण नियंत्रण होने की शक्ति से मेल नहीं खाते हैं।
अपना खुद का लिखने का एक और फायदा यह है कि एक सरल प्रतिनिधित्व के लिए पार्स करना आसान है, जिसमें आपके व्याकरण के लिए एक से एक पत्राचार नहीं है।
यदि आपका व्याकरण निर्धारित है, और त्रुटि संदेश महत्वपूर्ण हैं, तो अपना स्वयं का रोल करने पर विचार करें, या कम से कम एक पार्सर जनरेटर का उपयोग करें जो आपको आवश्यक त्रुटि संदेश देता है। यदि आपका व्याकरण लगातार बदल रहा है, तो आपको इसके बजाय पार्सर जनरेटर का उपयोग करने पर विचार करना चाहिए।
Bjarne Stroustrup इस बारे में बात करते हैं कि उन्होंने C ++ के पहले कार्यान्वयन के लिए YACC का उपयोग कैसे किया (देखें C ++ का डिज़ाइन और विकास )। उस पहले मामले में, उन्होंने चाहा कि उन्होंने इसके बजाय अपने स्वयं के पुनरावर्ती वंश पार्सर लिखा!
विकल्प 3: न तो (अपने स्वयं के पार्सर जनरेटर को रोल करें)
सिर्फ इसलिए कि ANTLR , bison , Coco / R , Grammatica , JavaCC , Lemon , Parboiled , SableCC , Quex , इत्यादि का उपयोग न करने का एक कारण है - इसका मतलब यह नहीं है कि आपको तुरंत अपने स्वयं के पार्सर या लेसर को रोल करना चाहिए।
पहचानें कि ये सभी उपकरण पर्याप्त अच्छे क्यों नहीं हैं - वे आपको अपना लक्ष्य हासिल करने क्यों नहीं देते?
जब तक आप निश्चित नहीं होते कि जिस व्याकरण में आप काम कर रहे हैं उसमें विषमताएँ अद्वितीय हैं, तो आपको इसके लिए केवल एक ही कस्टम पार्सर + लेक्सर नहीं बनाना चाहिए। इसके बजाय, एक ऐसा उपकरण बनाएं जो आप चाहते हैं, लेकिन भविष्य की जरूरतों को पूरा करने के लिए भी इस्तेमाल किया जा सकता है, फिर इसे अन्य लोगों की समस्या को रोकने के लिए फ्री सॉफ्टवेयर के रूप में जारी करें।
अपने स्वयं के पार्सर को रोल करना आपको अपनी भाषा की जटिलता के बारे में सीधे सोचने के लिए मजबूर करता है। अगर भाषा को छांटना कठिन है, तो शायद समझना कठिन है।
शुरुआती दिनों में पार्सर जनरेटर में बहुत रुचि थी, अत्यधिक-जटिल से प्रेरित (कुछ कहेंगे "अत्याचार") भाषा वाक्य रचना। JOVIAL एक विशेष रूप से खराब उदाहरण था: इसे दो प्रतीक लुकहेड की आवश्यकता थी, एक ऐसे समय में जब किसी एक चीज को सबसे अधिक एक प्रतीक की आवश्यकता होती है। इसने JOVIAL कंपाइलर के लिए पार्सर का निर्माण करना अपेक्षा से अधिक कठिन बना दिया (क्योंकि जनरल डायनेमिक्स / फोर्ट वर्थ डिवीजन ने F-16 प्रोग्राम के लिए JOVIAL कंपाइलरों की खरीद के लिए कठिन तरीका सीखा)।
आज, पुनरावर्ती वंश सार्वभौमिक रूप से पसंदीदा तरीका है, क्योंकि यह संकलक लेखकों के लिए आसान है। पुनरावर्ती वंश संकलक सरल, स्वच्छ भाषा डिजाइन को पुरजोर रूप से पुरस्कृत करते हैं, जिसमें एक सरल, स्वच्छ भाषा के लिए पुनरावर्ती, गन्दा की तुलना में एक पुनरावर्ती-वंशीय पार्सर लिखना बहुत आसान है।
अंत में: क्या आपने अपनी भाषा को LISP में एम्बेड करने और LISP दुभाषिया को आपके लिए भारी उठाने की अनुमति देने पर विचार किया है? ऑटोकैड ने ऐसा किया, और पाया कि इससे उनका जीवन बहुत आसान हो गया। वहाँ कुछ हल्के LISP दुभाषिए हैं, कुछ एम्बेड करने योग्य हैं।
मैंने एक बार व्यावसायिक अनुप्रयोग के लिए एक पार्सर लिखा है और मैंने yacc का उपयोग किया है । एक प्रतिस्पर्धी प्रोटोटाइप था जहां एक डेवलपर ने सी ++ में हाथ से पूरी बात लिखी थी और इसने लगभग पांच बार धीमी गति से काम किया था।
इस पार्सर के लिए लेसर के रूप में, मैंने इसे पूरी तरह से हाथ से लिखा था। यह लिया - क्षमा करें, यह लगभग 10 साल पहले था, इसलिए मुझे यह ठीक से याद नहीं है - सी में लगभग 1000 लाइनें ।
लेसर को हाथ से लिखने का कारण पार्सर का इनपुट व्याकरण था। यह एक आवश्यकता थी, कुछ मेरे पार्सर कार्यान्वयन का अनुपालन करना था, जैसा कि मैंने कुछ डिज़ाइन किया था। (बेशक मैंने इसे अलग तरह से डिज़ाइन किया होगा। और बेहतर!) व्याकरण गंभीर रूप से संदर्भ-निर्भर था और यहां तक कि कुछ स्थानों पर शब्दार्थ पर निर्भर था। उदाहरण के लिए एक अर्धविराम एक स्थान पर एक टोकन का हिस्सा हो सकता है, लेकिन एक अलग जगह में एक विभाजक - कुछ तत्व की एक अर्थपूर्ण व्याख्या के आधार पर जो पहले से बाहर था। इसलिए, मैंने हाथ से लिखे गए लेसर में इस तरह के शब्दार्थ पर निर्भरता को "दफन" कर दिया और मुझे काफी सीधी बीएनएफ के साथ छोड़ दिया जो कि याक में लागू करना आसान था।
Macneil के जवाब में जोड़ा गया : yacc एक बहुत शक्तिशाली अमूर्तता प्रदान करता है जो प्रोग्रामर को टर्मिनलों, गैर-टर्मिनलों, प्रस्तुतियों और उस तरह के सामान के संदर्भ में सोचने देता है। साथ ही, yylex()
फ़ंक्शन को लागू करते समय, इससे मुझे वर्तमान टोकन वापस करने पर ध्यान केंद्रित करने में मदद मिली और इसके बारे में चिंता नहीं हुई कि इसके पहले या बाद में क्या था। सी ++ प्रोग्रामर ने चरित्र स्तर पर काम किया, इस तरह के अमूर्तता के लाभ के बिना और अधिक जटिल और कम कुशल एल्गोरिदम बनाने के लिए समाप्त हो गया। हमने निष्कर्ष निकाला कि धीमी गति का सी ++ या किसी भी पुस्तकालय से कोई लेना-देना नहीं था। हमने मेमोरी में लोड की गई फ़ाइलों के साथ शुद्ध पार्सिंग गति को मापा; अगर हमारे पास फ़ाइल बफरिंग की समस्या थी, तो इसे हल करने के लिए yacc हमारी पसंद का उपकरण नहीं होगा।
इसके अलावा ADD करना चाहते हैं : यह सामान्य रूप से पार्सर्स लिखने के लिए एक नुस्खा नहीं है, यह एक उदाहरण है कि यह एक विशेष स्थिति में कैसे काम करता है।
यह पूरी तरह से निर्भर करता है कि आपको क्या करना है। क्या आप अपने खुद के रोल को तेजी से रोल कर सकते हैं जितना कि आप एक लक्सर के सीखने की अवस्था को मार सकते हैं? क्या सामान को स्थिर रूप से पार्स किया जा सकता है जो आपको बाद में निर्णय पर पछतावा नहीं होगा? क्या आप मौजूदा कार्यान्वयन को अत्यधिक जटिल पाते हैं? यदि ऐसा है, तो मज़े से अपनी भूमिका निभाएँ, लेकिन केवल तभी जब आप सीखने की अवस्था को कम नहीं कर रहे हों।
हाल ही में, मैं वास्तव में नींबू के पार्सर की तरह आया हूं , जो यकीनन सबसे सरल और सबसे आसान है जिसका मैंने कभी उपयोग किया है। चीजों को बनाए रखना आसान बनाने के लिए, मैं ज्यादातर जरूरतों के लिए इसका इस्तेमाल करता हूं। SQLite इसे और साथ ही कुछ अन्य उल्लेखनीय परियोजनाओं का उपयोग करता है।
लेकिन, मुझे लेक्सर्स में बिल्कुल भी दिलचस्पी नहीं है, इससे परे वे मेरे रास्ते में नहीं आते हैं जब मुझे एक (इसलिए, नींबू) का उपयोग करने की आवश्यकता होती है। आप हो सकते हैं, और यदि हां, तो क्यों नहीं? मुझे लगता है कि आप मौजूद हैं का उपयोग करके वापस आ जाएंगे, लेकिन अगर आपको चाहिए तो खुजली खरोंचें :)
यह इस बात पर निर्भर करता है कि आपका लक्ष्य क्या है।
क्या आप सीखने की कोशिश कर रहे हैं कि पार्सर / कंपाइलर कैसे काम करते हैं? फिर खरोंच से अपना खुद का लिखें। एकमात्र तरीका है कि आप वास्तव में सभी इन्स और बाहरी लोगों की सराहना करना सीखेंगे कि वे क्या कर रहे हैं। मैं पिछले कुछ महीनों से एक लिख रहा हूं, और यह एक दिलचस्प और मूल्यवान अनुभव रहा है, वास्तव में 'आह, तो भाषा एक्स ऐसा क्यों करती है ...' क्षण।
क्या आपको एक समय सीमा पर एक आवेदन के लिए जल्दी से कुछ डालने की ज़रूरत है? तो शायद एक पार्सर उपकरण का उपयोग करें।
क्या आपको कुछ ऐसा चाहिए जो आप अगले 10, 20, शायद 30 वर्षों में भी बढ़ाना चाहें? अपना खुद का लिखें, और अपना समय लें। यह अच्छी तरह से इसके लायक होगा।
क्या आपने मार्टिन फाउलर भाषा कार्यक्षेत्र दृष्टिकोण पर विचार किया है ? लेख से उद्धरण
सबसे स्पष्ट परिवर्तन जो एक भाषा कार्यक्षेत्र समीकरण को बनाता है वह बाहरी डीएसएल बनाने में आसानी है। अब आपको पार्सर लिखना नहीं होगा। आपको सार सिंटैक्स को परिभाषित करना होगा - लेकिन यह वास्तव में एक बहुत ही सीधा डेटा मॉडलिंग कदम है। इसके अलावा आपके डीएसएल को एक शक्तिशाली आईडीई मिलता है - हालांकि आपको उस संपादक को परिभाषित करने में कुछ समय बिताना होगा। जनरेटर अभी भी कुछ ऐसा है जो आपको करना है, और मेरी समझ यह है कि यह पहले से कहीं ज्यादा आसान नहीं है। लेकिन फिर एक अच्छे और सरल डीएसएल के लिए जनरेटर का निर्माण करना व्यायाम के सबसे आसान हिस्सों में से एक है।
इसे पढ़कर, मैं कहूंगा कि आपके खुद के पार्सर लिखने के दिन खत्म हो गए हैं और यह उपलब्ध पुस्तकालयों में से एक का उपयोग करना बेहतर है। एक बार जब आप पुस्तकालय में महारत हासिल कर लेते हैं तो भविष्य में आपके द्वारा बनाए गए सभी डीएसएल उस ज्ञान से लाभान्वित होते हैं। इसके अलावा, दूसरों को पार्स करने के लिए आपके दृष्टिकोण को सीखना नहीं है।
टिप्पणी को कवर करने के लिए संपादित करें (और संशोधित प्रश्न)
खुद के रोल करने के फायदे
तो संक्षेप में, आपको अपना खुद का रोल करना चाहिए जब आप वास्तव में एक गंभीर रूप से कठिन समस्या के आंत्र में गहरी हैक करना चाहते हैं जिसे आप मास्टर करने के लिए दृढ़ता से प्रेरित महसूस करते हैं।
किसी और के पुस्तकालय का उपयोग करने के लाभ
इसलिए, यदि आप एक त्वरित अंतिम परिणाम चाहते हैं तो किसी और के पुस्तकालय का उपयोग करें।
कुल मिलाकर, यह इस विकल्प पर निर्भर करता है कि आप समस्या का कितना समाधान करना चाहते हैं, और इस प्रकार समाधान। अगर आप यह सब चाहते हैं तो अपना रोल करें।
अपने खुद के लिखने के लिए बड़ा फायदा यह है कि आप जानेंगे कि कैसे लिखा जाए। याक जैसे उपकरण का उपयोग करने का बड़ा फायदा यह है कि आप जानेंगे कि उपकरण का उपयोग कैसे किया जाता है। मैं शुरुआती अन्वेषण के लिए treetop का प्रशंसक हूं ।
क्यों नहीं एक खुले स्रोत पार्सर जनरेटर कांटा और इसे अपना बना लें? यदि आप पार्सर जनरेटर का उपयोग नहीं करते हैं, तो आपको बनाए रखने के लिए कोड बहुत कठिन होगा, यदि आपने अपनी भाषा के सिंटैक्स में बड़े बदलाव किए हैं।
मेरे पार्सर में, मैंने नियमित अभिव्यक्ति (मेरा मतलब है, पर्ल-स्टाइल) का उपयोग टोकन के लिए किया, और कोड पठनीयता को बढ़ाने के लिए कुछ सुविधा कार्यों का उपयोग किया। हालांकि, एक पार्सर उत्पन्न कोड तेजी से राज्य टेबल और लंबे समय तक बना कर किया जा सकता है switch
- case
रों है, जो जब तक आप स्रोत कोड आकार में वृद्धि हो सकती .gitignore
है उन्हें।
यहाँ मेरे कस्टम लिखित पार्सर के दो उदाहरण हैं:
https://github.com/SHiNKiROU/DesignScript - एक मूलभूत बोली, क्योंकि मैं सरणी संकेतन में लुकाहेड्स लिखने के लिए बहुत आलसी था, मैंने त्रुटि संदेश की गुणवत्ता का त्याग किया था https://github.com/SHiNKROROU/ExprParser - एक सूत्र कैलकुलेटर। अजीब मेटाप्रोग्रामिंग ट्रिक्स पर ध्यान दें
"क्या मुझे इस कोशिश और परीक्षण किए गए 'पहिया' का उपयोग करना चाहिए या इसे फिर से मजबूत करना चाहिए?"