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
ANTLR: Is there a simple example?
提问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.java、ExpParser.java和Exp.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 eval
rule 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. ANTLRStringStream
needed to become ANTLRInputStream
, the returned value needed to change from parser.eval()
to parser.eval().value
, and I needed to remove the WS
clause at the end, because attribute values such as $channel
are 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 解析器,分为三个部分:
- parser grammar
- lexer grammar
- imported LexBasic grammar
- 语法分析器
- 词法语法
- 导入的 LexBasic 语法
https://github.com/BITPlan/com.bitplan.antlr/blob/master/src/test/java/com/bitplan/antlr/TestIRIParser.javahas the unit tests for it.
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);