ANTLR:有一个简单的例子吗?
我想开始使用ANTLR,但花了几个小时在antlr.org网站上查看示例之后,我仍然无法清楚地理解Java过程的语法。
有没有一个简单的例子,像ANTLR通过parsing器定义和Java源代码一起实现的一个四操作计算器?
你首先创build一个语法。 下面是一个小语法,可以用来评估使用4个基本的math运算符(+, – ,*和/)构build的expression式。 您也可以使用圆括号对expression式进行分组。
请注意,这个语法只是一个非常基本的语法:它不处理一元运算符(减号:-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;} ; (parsing器规则以小写字母开头,词法规则以大写字母开头)
创build语法之后,您需要从中生成parsing器和词法分析器。 下载ANTLR jar并将其存储在与语法文件相同的目录中。
在您的shell /命令提示符处执行以下命令:
 java -cp antlr-3.2.jar org.antlr.Tool Exp.g 
它不应该产生任何错误信息,现在应该生成文件ExpLexer.java , ExpParser.java和Exp.tokens 。
要看看它是否正常工作,创build这个testing类:
 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 
 如果一切顺利,没有任何东西正在打印到控制台上。 这意味着parsing器没有发现任何错误。 当您将"12*(5-6)"更改为"12*(5-6)" ,然后重新编译并运行时,应该打印下列内容: 
 line 0:-1 mismatched input '<EOF>' expecting ')' 
 好的,现在我们要在语法中添加一些Java代码,这样parsing器实际上会做一些有用的事情。 添加代码可以通过将{和}放置在语法中,并在其中包含一些简单的Java代码。 
 但首先:语法文件中的所有parsing器规则应该返回一个原始的double值。 你可以通过在每个规则之后添加returns [double value] : 
 grammar Exp; eval returns [double value] : additionExp ; additionExp returns [double value] : multiplyExp ( '+' multiplyExp | '-' multiplyExp )* ; // ... 
 这需要很less的解释:每个规则预期会返回一个双重值。 现在,要从代码块中与返回值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规则现在返回一个double,所以把你的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 } } 
再次(重新)从你的语法生成一个新的词法分析器和parsing器(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 
 现在你会看到expression式12*(5-6)打印到你的控制台的结果! 
再次:这是一个非常简短的解释。 我鼓励你浏览ANTLR wiki ,阅读一些教程和/或播放我刚发布的内容。
祝你好运!
编辑:
  本文展示了如何扩展上面的例子,以便提供一个Map<String, Double>来保存提供的expression式中的variables。 
这个问答演示了如何创build一个简单的expression式parsing器,并使用ANTLR4进行评估。
 为了使这个代码与当前版本的Antlr一起工作(2014年6月),我需要做一些改变。  ANTLRStringStream需要成为ANTLRInputStream ,从parser.eval()到parser.eval().value value所需的返回值,我需要在最后删除WS子句,因为像$channel这样的属性值不再被允许出现在词法分析的行动。 
对于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你会发现有一些有用的帮助类和一些完整的例子ANTLR Java库。 它准备与maven一起使用,如果你喜欢eclipse和maven。
https://github.com/BITPlan/com.bitplan.antlr/blob/master/src/main/antlr4/com/bitplan/exp/Exp.g4
是一个简单的expression式语言,可以做乘法和增加操作。 https://github.com/BITPlan/com.bitplan.antlr/blob/master/src/test/java/com/bitplan/antlr/TestExpParser.java有相应的unit testing。
- parsing器语法
- 词法分析器
- 导入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的性能问题创build的示例。 与此同时,这个问题已经被解决,如testing用例https://github.com/BITPlan/com.bitplan.antlr/blob/master/src/test/java/com/bitplan/antlr/TestIssue994.java所示。;
对我来说,这个教程是非常有用的: https : //tomassetti.me/antlr-mega-tutorial
它有语法示例,不同语言(Java,JavaScript,C#和Python)的访问者的例子以及许多其他的东西。 强烈推荐。