java - एएनटीएलआर: क्या कोई साधारण उदाहरण है?




antlr antlr4 (3)

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

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


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

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

तदनुसार क्लासपाथ में अपना जार नाम अपडेट करें।


आप पहले व्याकरण बनाते हैं। नीचे एक छोटा व्याकरण है जिसका उपयोग आप 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;}
    ;

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

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

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

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" में बदलते हैं और फिर पुन: संकलित करते हैं और इसे चलाते हैं, तो निम्न को मुद्रित किया जाना चाहिए:

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) और एएनटीएलआरडीमो (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) के परिणाम देखेंगे!

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

सौभाग्य!

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

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

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

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


https://github.com/BITPlan/com.bitplan.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

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







antlr3