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.javaExpParser.javaExp.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 : //tomassetti.me/antlr-mega-tutorial

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