Java ANTLR:有简单的例子吗?

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/1931307/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-13 01:32:54  来源:igfitidea点击:

ANTLR: Is there a simple example?

javaantlrantlr4antlr3

提问by Eli

I'd like to get started with ANTLR, but after spending a few hours reviewing the examples at the antlr.orgsite, I still can't get a clear understanding of the grammar to Java process.

我想开始使用 ANTLR,但是在花了几个小时查看antlr.org站点上的示例之后,我仍然无法清楚地了解 Java 过程的语法。

Is there some simple example, something like a four-operations calculator implemented with ANTLR going through the parser definition and all the way to the Java source code?

有没有一些简单的例子,比如用 ANTLR 实现的四运算计算器,通过解析器定义,一直到 Java 源代码?

采纳答案by Bart Kiers

Note: this answer is for ANTLR3! If you're looking for an ANTLR4example, then this Q&Ademonstrates how to create a simple expression parser, and evaluator using ANTLR4.

注意:这个答案是针对ANTLR3 的!如果您正在寻找ANTLR4示例,那么此问答演示了如何使用ANTLR4创建简单的表达式解析器和评估器。



You first create a grammar. Below is a small grammar that you can use to evaluate expressions that are built using the 4 basic math operators: +, -, * and /. You can also group expressions using parenthesis.

您首先创建一个语法。下面是一个小语法,可用于评估使用 4 个基本数学运算符构建的表达式:+、-、* 和 /。您还可以使用括号对表达式进行分组。

Note that this grammar is just a very basic one: it does not handle unary operators (the minus in: -1+9) or decimals like .99 (without a leading number), to name just two shortcomings. This is just an example you can work on yourself.

请注意,这种语法只是一个非常基本的语法:它不处理一元运算符(减号:-1+9)或小数,如 .99(没有前导数字),仅举两个缺点。这只是您可以自己处理的示例。

Here's the contents of the grammar file Exp.g:

下面是语法文件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;}
    ;

(Parser rules start with a lower case letter, and lexer rules start with a capital letter)

(解析器规则以小写字母开头,词法规则以大写字母开头)

After creating the grammar, you'll want to generate a parser and lexer from it. Download the ANTLR jarand store it in the same directory as your grammar file.

创建语法后,您需要从中生成解析器和词法分析器。下载ANTLR jar并将其存储在与您的语法文件相同的目录中。

Execute the following command on your shell/command prompt:

在 shell/命令提示符下执行以下命令:

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

It should not produce any error message, and the files ExpLexer.java, ExpParser.javaand Exp.tokensshould now be generated.

它不应产生任何错误消息,现在应生成文件ExpLexer.javaExpParser.javaExp.tokens

To see if it all works properly, create this test class:

要查看是否一切正常,请创建此测试类:

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();
    }
}

and compile it:

并编译它:

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

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

and then run it:

然后运行它:

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

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

If all goes well, nothing is being printed to the console. This means the parser did not find any error. When you change "12*(5-6)"into "12*(5-6"and then recompile and run it, there should be printed the following:

如果一切顺利,控制台不会打印任何内容。这意味着解析器没有发现任何错误。当你"12*(5-6)"改成"12*(5-6"然后重新编译并运行它时,应该打印以下内容:

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

Okay, now we want to add a bit of Java code to the grammar so that the parser actually does something useful. Adding code can be done by placing {and }inside your grammar with some plain Java code inside it.

好的,现在我们想在语法中添加一些 Java 代码,以便解析器真正做一些有用的事情。添加代码可以通过将完成{,并}与里面的一些普通的Java代码你的语法内。

But first: all parser rules in the grammar file should return a primitive double value. You can do that by adding returns [double value]after each rule:

但首先:语法文件中的所有解析器规则都应该返回一个原始双精度值。您可以通过returns [double value]在每个规则之后添加来做到这一点:

grammar Exp;

eval returns [double value]
    :    additionExp
    ;

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

// ...

which needs little explanation: every rule is expected to return a double value. Now to "interact" with the return value double value(which is NOT inside a plain Java code block {...}) from inside a code block, you'll need to add a dollar sign in front of value:

这几乎不需要解释:每个规则都应该返回一个双精度值。现在要与double value代码块内部的返回值(不在普通 Java 代码块中{...})“交互” ,您需要在 前面添加一个美元符号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); }
    ;

// ...

Here's the grammar but now with the Java code added:

这是语法,但现在添加了 Java 代码:

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;}
    ;

and since our evalrule now returns a double, change your ANTLRDemo.java into this:

由于我们的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
    }
}

Again (re) generate a fresh lexer and parser from your grammar (1), compile all classes (2) and run ANTLRDemo (3):

再次(重新)从您的语法(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

and you'll now see the outcome of the expression 12*(5-6)printed to your console!

您现在将看到12*(5-6)打印到控制台的表达式的结果!

Again: this is a very brief explanation. I encourage you to browse the ANTLR wikiand read some tutorials and/or play a bit with what I just posted.

再次:这是一个非常简短的解释。我鼓励您浏览ANTLR wiki并阅读一些教程和/或使用我刚刚发布的内容。

Good luck!

祝你好运!

EDIT:

编辑:

This postshows how to extend the example above so that a Map<String, Double>can be provided that holds variables in the provided expression.

这篇文章展示了如何扩展上面的例子,以便Map<String, Double>可以提供一个在所提供的表达式中保存变量的变量。

To get this code working with a current version of Antlr (June 2014) I needed to make a few changes. ANTLRStringStreamneeded to become ANTLRInputStream, the returned value needed to change from parser.eval()to parser.eval().value, and I needed to remove the WSclause at the end, because attribute values such as $channelare no longer allowed to appear in lexer actions.

为了使此代码与当前版本的 Antlr(2014 年 6 月)一起使用,我需要进行一些更改。ANTLRStringStream需要变成ANTLRInputStream,返回值需要从parser.eval()变为parser.eval().value,我需要删除最后的WS子句,因为诸如此类的属性值$channel不再允许出现在词法分析器动作中。

回答by Abhishek K

For Antlr 4 the java code generation process is below:-

对于 Antlr 4,java 代码生成过程如下:-

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

Update your jar name in classpath accordingly.

相应地更新类路径中的 jar 名称。

回答by Wolfgang Fahl

At https://github.com/BITPlan/com.bitplan.antlryou'll find an ANTLR java library with some useful helper classes and a few complete examples. It's ready to be used with maven and if you like eclipse and maven.

https://github.com/BITPlan/com.bitplan.antlr你会发现一个 ANTLR java 库,里面有一些有用的帮助类和一些完整的例子。如果您喜欢 eclipse 和 maven,它已准备好与 maven 一起使用。

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/main/antlr4/com/bitplan/exp/Exp.g4

is a simple Expression language that can do multiply and add operations. https://github.com/BITPlan/com.bitplan.antlr/blob/master/src/test/java/com/bitplan/antlr/TestExpParser.javahas the corresponding unit tests for it.

是一种简单的表达式语言,可以进行乘法和加法运算。 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.g4is an IRI parser that has been split into the three parts:

https://github.com/BITPlan/com.bitplan.antlr/blob/master/src/main/antlr4/com/bitplan/iri/IRIParser.g4是一个 IRI 解析器,分为三个部分:

  1. parser grammar
  2. lexer grammar
  3. imported LexBasic grammar
  1. 语法分析器
  2. 词法语法
  3. 导入的 LexBasic 语法

https://github.com/BITPlan/com.bitplan.antlr/blob/master/src/test/java/com/bitplan/antlr/TestIRIParser.javahas the unit tests for it.

https://github.com/BITPlan/com.bitplan.antlr/blob/master/src/test/java/com/bitplan/antlr/TestIRIParser.java有单元测试。

Personally I found this the most tricky part to get right. See http://wiki.bitplan.com/index.php/ANTLR_maven_plugin

我个人发现这是最棘手的部分。见http://wiki.bitplan.com/index.php/ANTLR_maven_plugin

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

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

contains three more examples that have been created for a performance issue of ANTLR4 in an earlier version. In the meantime this issues has been fixed as the testcase https://github.com/BITPlan/com.bitplan.antlr/blob/master/src/test/java/com/bitplan/antlr/TestIssue994.javashows.

包含另外三个示例,这些示例是针对早期版本中 ANTLR4 的性能问题创建的。同时,此问题已在测试用例https://github.com/BITPlan/com.bitplan.antlr/blob/master/src/test/java/com/bitplan/antlr/TestIssue994.java显示时得到修复。

回答by solo

ANTLR mega tutorialby Gabriele Tomassetti is very helpful

Gabriele Tomassetti 的ANTLR 大型教程非常有帮助

It has grammar examples, examples of visitors in different languages (Java, JavaScript, C# and Python) and many other things. Highly recommended.

它有语法示例、不同语言(Java、JavaScript、C# 和 Python)的访问者示例以及许多其他内容。强烈推荐。

EDIT: other useful articles by Gabriele Tomassetti on ANTLR

编辑:Gabriele Tomassetti 关于 ANTLR 的其他有用文章

回答by user1562431

version 4.7.1 was slightly different : for import:

版本 4.7.1 略有不同:对于导入:

import org.antlr.v4.runtime.*;

for the main segment - note the CharStreams:

对于主要部分 - 请注意 CharStreams:

CharStream in = CharStreams.fromString("12*(5-6)");
ExpLexer lexer = new ExpLexer(in);
CommonTokenStream tokens = new CommonTokenStream(lexer);
ExpParser parser = new ExpParser(tokens);