题
我想开始使用这些代码,但是在花费几个小时审查实例 antlr.org 网站,我仍然不能得到清楚理解的语法Java进程。
有一些简单的例子,像四个操作计算实施与这些代码打算通过分析程序的定义和所有方式的Java源代码?
解决方案
注意:这个答案是对的 ANTLR3 !如果你正在寻找一个 ANTLR4 示例,那么这个的 Q&A 演示了如何使用创建一个简单的表达式分析器,以及评估器的 ANTLR4 强>
您首先创建一个语法。下面是一个小的语法,你可以用它来评估正在使用的4个基本数学运算符建表达式:+, - ,*,/和。也可以使用括号组表达式。
请注意,这个语法只是一个很基本的一个:它不处理一元运算符(在零下:1 + 9)或小数像1.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"
然后重新编译并运行它,有应该打印以下内容:
line 0:-1 mismatched input '<EOF>' expecting ')'
好了,现在我们要一点点的Java代码添加到语法,这样分析器实际上做一些有用的东西。添加代码可以通过一些普通的Java代码放置{
和}
你的语法里面里面来完成。
但是首先:在语法文件中的所有的语法规则应该返回一个原语双精度值。您可以通过每个规则之后加入returns [double value]
做到这一点:
grammar Exp;
eval returns [double value]
: additionExp
;
additionExp returns [double value]
: multiplyExp
( '+' multiplyExp
| '-' multiplyExp
)*
;
// ...
这需要一点解释:每一个规则有望回归的双重价值。现在到“互动”与一个代码块中的返回值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); }
;
// ...
这里的语法,但现在具有添加的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;}
;
和,因为我们的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>
保持在所提供的表达式中的变量。
要获得此代码ANTLR的当前版本的工作(2014年6月),我需要做出一些改变。 ANTLRStringStream
需要成为ANTLRInputStream
,该换货政...需要rned值从parser.eval()
改变parser.eval().value
,我需要在端部除去WS
子句,因为属性值如$channel
不再允许出现在词法分析器的操作。
其他提示
这些代码的巨型教程 由加布里埃尔Tomassetti是非常有帮助的
它具有法例,例的访客在不同的语言(Java,JavaScript,C#和Python)和许多其他的事情。强烈建议。
编辑:其他有用的文章由加布里埃尔Tomassetti在这些代码
有关的Antlr 4中的Java代码生成过程低于: -
java -cp antlr-4.5.3-complete.jar org.antlr.v4.Tool Exp.g
相应地更新在classpath中你的JAR的名字。
在 https://github.com/BITPlan/com.bitplan.antlr 你会找到这些代码java图书馆与一些有用辅助类和一些完整的例子。它准备用于与家,如果你喜欢蚀和家.
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 是IRI的分析器已被拆分为三个部分:
- 语法分析器
- 语法分析程序的语法
- 进口LexBasic语法
就个人而言,我发现这一最棘手的部分获得的权利。看看 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 示。
版本4.7.1略有不同: 进口:
import org.antlr.v4.runtime.*;
对于主段 - 注意CharStreams:
CharStream in = CharStreams.fromString("12*(5-6)");
ExpLexer lexer = new ExpLexer(in);
CommonTokenStream tokens = new CommonTokenStream(lexer);
ExpParser parser = new ExpParser(tokens);