ANTLR: क्या एक सरल उदाहरण है?


230

मैं ANTLR के साथ शुरुआत करना चाहता हूं, लेकिन कुछ घंटों तक antlr.org साइट पर उदाहरणों की समीक्षा करने के बाद , मैं अभी भी व्याकरण की स्पष्ट समझ जावा प्रक्रिया को प्राप्त नहीं कर सकता।

क्या कुछ सरल उदाहरण है, एएनटीएलआर के साथ कार्यान्वित चार-ऑपरेशन कैलकुलेटर जैसा कुछ है जो पार्सर परिभाषा और जावा स्रोत कोड के सभी रास्ते से गुजर रहा है?


2
उस सटीक उदाहरण का उपयोग एंट्र की साइट पर एक ट्यूटोरियल के रूप में किया जाता है, आखिरी मैंने जाँच की थी।
कोरी पेत्रोस्की

1
@Cory पेटोस्की: क्या आपकी आपूर्ति लिंक कर सकती है?
एली

मैंने अभी ANTLR पर एक वीडियो ट्यूटोरियल के पहले भाग पोस्ट किए हैं। Javadude.com/articles/antlr3xtut देखें आशा है कि आप इसे उपयोगी पाएंगे!
स्कॉट स्टैनफील्ड ने

2
मैं भी आपकी खोज को साझा करता हूं।
पॉल ड्रेपर

1
ANTLR 4 के लिए सर्वश्रेष्ठ उत्तर है Parr की पुस्तक "द डेफिनिटिव ANTLR 4 संदर्भ।"
james.garriss 14

जवाबों:


447

नोट : यह उत्तर ANTLR3 के लिए है ! यदि आप ANTLR4 उदाहरण के लिए देख रहे हैं , तो यह Q & A दर्शाता है कि कैसे एक सरल अभिव्यक्ति पार्सर, और ANTLR4 का उपयोग करके मूल्यांकनकर्ता बनाया जाए


आप पहले एक व्याकरण बनाएँ। नीचे एक छोटा व्याकरण है जिसे आप 4 मूल गणित ऑपरेटरों: +, -, * और / का उपयोग करके बनाए गए भावों का मूल्यांकन करने के लिए उपयोग कर सकते हैं। आप कोष्ठक का उपयोग करके समूह के भाव भी कर सकते हैं।

ध्यान दें कि यह व्याकरण सिर्फ एक बहुत ही बुनियादी है: यह सिर्फ दो कमियों को दूर करने के लिए यूनी ऑपरेटर्स (: -1 + 9 में माइनस) या .99 (जैसे एक प्रमुख संख्या के बिना) को हैंडल नहीं करता है। यह सिर्फ एक उदाहरण है जो आप खुद पर काम कर सकते हैं।

यहां व्याकरण फ़ाइल की सामग्री Exp.g :

grammar Exp;

/* This will be the entry point of our parser. */
eval
    :    additionExp
    ;

/* Addition and subtraction have the lowest precedence. */
additionExp
    :    multiplyExp 
         ( '+' multiplyExp 
         | '-' multiplyExp
         )* 
    ;

/* Multiplication and division have a higher precedence. */
multiplyExp
    :    atomExp
         ( '*' atomExp 
         | '/' atomExp
         )* 
    ;

/* An expression atom is the smallest part of an expression: a number. Or 
   when we encounter parenthesis, we're making a recursive call back to the
   rule 'additionExp'. As you can see, an 'atomExp' has the highest precedence. */
atomExp
    :    Number
    |    '(' additionExp ')'
    ;

/* A number: can be an integer value, or a decimal value */
Number
    :    ('0'..'9')+ ('.' ('0'..'9')+)?
    ;

/* We're going to ignore all white space characters */
WS  
    :   (' ' | '\t' | '\r'| '\n') {$channel=HIDDEN;}
    ;

(पार्सर नियम कम केस लेटर से शुरू होते हैं, और लेसर रूल्स कैपिटल लेटर से शुरू होते हैं)

व्याकरण बनाने के बाद, आप इससे एक पार्सर और लेक्सर उत्पन्न करना चाहेंगे। ANTLR जार डाउनलोड करें और इसे अपनी व्याकरण फ़ाइल के समान निर्देशिका में संग्रहीत करें।

अपने शेल / कमांड प्रॉम्प्ट पर निम्न कमांड निष्पादित करें:

java -cp antlr-3.2.jar org.antlr.Tool Exp.g

यह किसी भी त्रुटि संदेश का उत्पादन नहीं करना चाहिए, और ExpLexer.java , ExpParser.java और Exp.tokens फ़ाइलों को अब उत्पन्न किया जाना चाहिए।

यह देखने के लिए कि क्या यह सब ठीक से काम करता है, यह परीक्षण वर्ग बनाएं:

import org.antlr.runtime.*;

public class ANTLRDemo {
    public static void main(String[] args) throws Exception {
        ANTLRStringStream in = new ANTLRStringStream("12*(5-6)");
        ExpLexer lexer = new ExpLexer(in);
        CommonTokenStream tokens = new CommonTokenStream(lexer);
        ExpParser parser = new ExpParser(tokens);
        parser.eval();
    }
}

और इसे संकलित करें:

// *nix/MacOS
javac -cp .:antlr-3.2.jar ANTLRDemo.java

// Windows
javac -cp .;antlr-3.2.jar ANTLRDemo.java

और फिर इसे चलाएं:

// *nix/MacOS
java -cp .:antlr-3.2.jar ANTLRDemo

// Windows
java -cp .;antlr-3.2.jar ANTLRDemo

अगर सब ठीक हो जाता है, तो कंसोल को कुछ भी नहीं छापा जा रहा है। इसका मतलब है कि पार्सर को कोई त्रुटि नहीं मिली। जब आप को बदलने "12*(5-6)"में "12*(5-6"recompile और फिर और इसे चलाने के लिए, वहाँ निम्नलिखित मुद्रित किया जाना चाहिए:

line 0:-1 mismatched input '<EOF>' expecting ')'

ठीक है, अब हम व्याकरण में थोड़ा जावा कोड जोड़ना चाहते हैं ताकि पार्सर वास्तव में कुछ उपयोगी हो। कोड जोड़ने {और }अपने व्याकरण के अंदर कुछ सादे जावा कोड के साथ रखकर और अंदर किया जा सकता है ।

लेकिन पहले: व्याकरण फ़ाइल में सभी पार्सर नियम एक आदिम दोहरा मूल्य वापस करना चाहिए। आप returns [double value]प्रत्येक नियम को जोड़कर ऐसा कर सकते हैं :

grammar Exp;

eval returns [double value]
    :    additionExp
    ;

additionExp returns [double value]
    :    multiplyExp 
         ( '+' multiplyExp 
         | '-' multiplyExp
         )* 
    ;

// ...

जिसे बहुत कम स्पष्टीकरण की आवश्यकता है: प्रत्येक नियम से दोहरा मूल्य वापस करने की अपेक्षा की जाती है। अब एक कोड ब्लॉक के अंदर से रिटर्न वैल्यू double value(जो एक सादे जावा कोड ब्लॉक के अंदर नहीं है {...}) के साथ "इंटरैक्ट" करने के लिए , आपको सामने एक डॉलर का चिह्न जोड़ना होगा value:

grammar Exp;

/* This will be the entry point of our parser. */
eval returns [double value]                                                  
    :    additionExp { /* plain code block! */ System.out.println("value equals: "+$value); }
    ;

// ...

यहाँ व्याकरण है, लेकिन अब जावा कोड के साथ जोड़ा गया है:

grammar Exp;

eval returns [double value]
    :    exp=additionExp {$value = $exp.value;}
    ;

additionExp returns [double value]
    :    m1=multiplyExp       {$value =  $m1.value;} 
         ( '+' m2=multiplyExp {$value += $m2.value;} 
         | '-' m2=multiplyExp {$value -= $m2.value;}
         )* 
    ;

multiplyExp returns [double value]
    :    a1=atomExp       {$value =  $a1.value;}
         ( '*' a2=atomExp {$value *= $a2.value;} 
         | '/' a2=atomExp {$value /= $a2.value;}
         )* 
    ;

atomExp returns [double value]
    :    n=Number                {$value = Double.parseDouble($n.text);}
    |    '(' exp=additionExp ')' {$value = $exp.value;}
    ;

Number
    :    ('0'..'9')+ ('.' ('0'..'9')+)?
    ;

WS  
    :   (' ' | '\t' | '\r'| '\n') {$channel=HIDDEN;}
    ;

और चूंकि हमारा evalनियम अब दोहरा रिटर्न करता है, इसलिए अपने ANTLRDemo.java को इसमें बदलें:

import org.antlr.runtime.*;

public class ANTLRDemo {
    public static void main(String[] args) throws Exception {
        ANTLRStringStream in = new ANTLRStringStream("12*(5-6)");
        ExpLexer lexer = new ExpLexer(in);
        CommonTokenStream tokens = new CommonTokenStream(lexer);
        ExpParser parser = new ExpParser(tokens);
        System.out.println(parser.eval()); // print the value
    }
}

फिर से (फिर से) अपने व्याकरण (1) से एक नया लेसर और पार्सर उत्पन्न करें, सभी वर्गों (2) को संकलित करें और ANTLRDemo (3) चलाएं:

// *nix/MacOS
java -cp antlr-3.2.jar org.antlr.Tool Exp.g   // 1
javac -cp .:antlr-3.2.jar ANTLRDemo.java      // 2
java -cp .:antlr-3.2.jar ANTLRDemo            // 3

// Windows
java -cp antlr-3.2.jar org.antlr.Tool Exp.g   // 1
javac -cp .;antlr-3.2.jar ANTLRDemo.java      // 2
java -cp .;antlr-3.2.jar ANTLRDemo            // 3

और अब आप 12*(5-6)अपने कंसोल पर मुद्रित अभिव्यक्ति के परिणाम देखेंगे !

फिर से: यह एक बहुत ही संक्षिप्त विवरण है। मैं आपको ANTLR विकी ब्राउज़ करने और कुछ ट्यूटोरियल पढ़ने और / या जो मैंने अभी पोस्ट किया है, उसके साथ थोड़ा खेलने के लिए प्रोत्साहित करता हूं।

सौभाग्य!

संपादित करें:

यह पोस्ट दिखाती है कि ऊपर दिए गए उदाहरण का विस्तार कैसे किया जाए ताकि Map<String, Double>प्रदान की जा सकने वाली अभिव्यक्ति में परिवर्तनशील हो सके।

इस कोड को एंट्र (जून 2014) के वर्तमान संस्करण के साथ काम करने के लिए मुझे कुछ बदलाव करने की आवश्यकता थी। ANTLRStringStreamबनने के लिए की जरूरत ANTLRInputStream, से परिवर्तन करने की जरूरत दिए गए मान parser.eval()के लिए parser.eval().value, और मैं दूर करने के लिए की जरूरत है WSअंत में खंड, क्योंकि विशेषता मान जैसे $channelनहीं रह lexer कार्यों में प्रदर्शित करने की अनुमति है।


1
कहां होता है लागू parser.eval()? यह यहाँ या ANTLR3 विकी पर स्पष्ट नहीं है!

1
@Jarrod, इरेट, सॉरी, मैं वास्तव में आपको नहीं समझता। evalएक पार्सर नियम है जो एक रिटर्न देता है double। तो एक eval()विधि है जिसे आप एक उदाहरण के ExpParserरूप में कह सकते हैं , जैसे मैंने प्रदर्शन किया ANTLRDemo.main(...)। एक lexer / पार्सर उत्पन्न करने के बाद, बस फ़ाइल खोलें ExpParser.javaऔर आप देखेंगे कि वहाँ एक eval()विधि है जो वापस आ रही है double
बार्ट कीर्स

@ बार्ट मैं एक हफ्ते से इस पर शोध कर रहा हूं - यह पहला उदाहरण है जो वास्तव में विस्तृत था और पहली बार काम करने के लिए पर्याप्त था और मुझे लगता है कि मैं समझता हूं। मैंने लगभग हार मान ली थी। धन्यवाद!
विनील शाह

13

गैब्रिएल टोमासेट्टी द्वारा ANTLR मेगा ट्यूटोरियल बहुत मददगार है

इसमें व्याकरण के उदाहरण हैं, विभिन्न भाषाओं में आगंतुकों के उदाहरण (जावा, जावास्क्रिप्ट, सी # और पायथन) और कई अन्य चीजें हैं। अत्यधिक सिफारिशित।

EDIT: अन्य उपयोगी लेख ANTLR पर गेब्रियल टोमासेट्टी द्वारा


महान ट्यूटोरियल!
मनीष पटेल

Antlr में अब लक्ष्य भाषा के रूप में cpp भी है। क्या cpp पर उदाहरण के साथ कोई ट्यूटोरियल हैं?
सिरकेव्स

एक ही पुरुष सी में ANTLR के लिए ++ एक ट्यूटोरियल बनाया tomassetti.me/getting-started-antlr-cpp मैं तुम्हें अनुमान लगा रहा हूँ रहे हैं कि आप यहां या में मेगा ट्यूटोरियल ढूंढ़ रहे हैं, के लिए जा रहा
एकल

7

Antlr 4 के लिए जावा कोड जेनरेशन प्रक्रिया निम्न है: -

java -cp antlr-4.5.3-complete.jar org.antlr.v4.Tool Exp.g

अपने जार नाम को उसके अनुसार कक्षापाठ में अद्यतन करें।


2

पर https://github.com/BITPlan/com.bitplan.antlr आप कुछ उपयोगी सहायक वर्गों और कुछ पूरा उदाहरण के साथ एक ANTLR जावा पुस्तकालय मिल जाएगा। यह मावेन के साथ प्रयोग करने के लिए तैयार है और यदि आपको ग्रहण और मावेन पसंद है।

https://github.com/BITPlan/com.bitplan.antlr/blob/master/src/main/antlr4/com/bitplan/exp/Exp.g4

एक साधारण अभिव्यक्ति की भाषा है जो कई गुना और संचालन जोड़ सकती है। https://github.com/BITPlan/com.bitplan.antlr/blob/master/src/test/java/com/bitplan/antlr/TestExpParser.java ने इसके लिए संबंधित इकाई परीक्षण किए हैं।

https://github.com/BITPlan/com.bitplan.antlr/blob/master/src/main/antlr4/com/bitplan/iri/IRIParser.g4 एक आईआरसी पार्सर है जिसे तीन भागों में विभाजित किया गया है:

  1. पार्सर व्याकरण
  2. व्याकरण का व्याकरण
  3. आयातित लेक्सबैसिक व्याकरण

https://github.com/BITPlan/com.bitplan.antlr/blob/master/src/test/java/com/bitplan/antlr/TestIRIParser.java ने इसके लिए यूनिट टेस्ट किए हैं।

व्यक्तिगत रूप से मैंने इसे सही पाने के लिए सबसे मुश्किल हिस्सा पाया। Http://wiki.bitplan.com/index.php/ANTLR_maven_plugin देखें

https://github.com/BITPlan/com.bitplan.antlr/tree/master/src/main/antlr4/com/bitplan/expr

तीन और उदाहरण शामिल हैं जो पहले के संस्करण में ANTLR4 के प्रदर्शन के लिए बनाए गए हैं। इस बीच इस मुद्दे को टेस्टकेस https://github.com/BITPlan/com.bitplan.antlr/blob/master/src/test/java/com/bitplan/antlr/TestIssue994.java शो के रूप में तय किया गया है ।


2

संस्करण 4.7.1 थोड़ा अलग था: आयात के लिए:

import org.antlr.v4.runtime.*;

मुख्य खंड के लिए - चारस्ट्रीम पर ध्यान दें:

CharStream in = CharStreams.fromString("12*(5-6)");
ExpLexer lexer = new ExpLexer(in);
CommonTokenStream tokens = new CommonTokenStream(lexer);
ExpParser parser = new ExpParser(tokens);
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.