Antlr是编译器前端工具,可以用于生成词法、语法分析器,使用Antlr代替手写是可以提高效率的
选择Antlr是因为它能支持很多目标语言(Java、C#、JavaScript、Python、Go、C++、Swift),并且Antlr语法简单
Antlr
Antlr 是一个开源的工具,支持根据规则文件生成词法分析器和语法分析器,它自身是用 Java 实现的。
Antlr生成词法分析器
使用Antlr定义Token意义和类型名就是生成词法分析器,还是粘贴宫老师的例子,方便以后查看:
lexer grammar Hello; //lexer关键字意味着这是一个词法规则文件,名称是Hello,要与文件名相同
//关键字
If : 'if';
Int : 'int';
//字面量
IntLiteral: [0-9]+;StringLiteral: '"' .*? '"' ;
//字符串字面量
//操作符
AssignmentOP: '=' ;
RelationalOP: '>'|'>='|'<' |'<=' ;
Star: '*';
Plus: '+';
Sharp: '#';
SemiColon: ';';
Dot: '.';
Comm: ',';
LeftBracket : '[';
RightBracket: ']';
LeftBrace: '{';
RightBrace: '}';
LeftParen: '(';RightParen: ')';
//标识符
Id : [a-zA-Z_] ([a-zA-Z_] | [0-9])*;
//空白字符,抛弃
Whitespace: [ \t]+ -> skip;
Newline: ( '\r' '\n'?|'\n')-> skip;
可以看到,我们定义了很多Token的意义还有识别他们的规则,即词法,给文件命名Hello.g4,在终端中使用antlr Hello.g4。编译这个规则文件生成Hello.java和其他两个辅助文件,再使用 javac *.java编译Hello.g4。结果会生成 Hello.class 文件,这就是我们生成的词法分析器。
可以自己写一个Token流存在一个文件里(这里存在hello.play)使用grun Hello tokens -tokens hello.play 查看词法分析结果:(这里还是使用宫老师的图)

从结果中看到,我们的词法分析器把每个 Token 都识别了,还记录了它们在代码中的位置、文本值、类别。上面这些都是 Token 的属性。以第二行[@1, 4:6=‘age’,< Id >,1:4]为例,其中 @1 是 Token 的流水编号,表明这是 1 号 Token;4:6 是 Token 在字符流中的开始和结束位置;age 是文本值,Id 是其 Token 类别;最后的 1:4 表示这个 Token 在源代码中位于第 1 行、第 4 列。
成熟的词法规则文件
上面是自己写的词法规则,与成熟的词法规则文件还有差距,这里举例字符串识别:
自己的:
StringLiteral: '"' .*? '"' ;
成熟的:
STRING_LITERAL: '"' (~["\\\r\n] | EscapeSequence)* '"';
fragment EscapeSequence
: '\\' [btnfr"'\\]
| '\\' ([0-3]? [0-7])? [0-7]
| '\\' 'u'+ HexDigit HexDigit HexDigit HexDigit
;
fragment HexDigit
: [0-9a-fA-F]
;
很明显转义字符被考虑进去了。fragment 指的是一个语法片段,是为了让规则定义更清晰。它本身并不生成 Token,只有 StringLiteral 规则才会生成 Token。
Antlr 生成语法分析器
一样编写 .g4文件,直接粘贴:
grammar PlayScript;
import CommonLexer; //导入词法定义
/*下面的内容加到所生成的Java源文件的头部,如包名称,import语句等。*/
@header {package antlrtest;}
expression
: assignmentExpression
| expression ',' assignmentExpression
;
assignmentExpression
: additiveExpression
| Identifier assignmentOperator additiveExpression
;
assignmentOperator
: '='
| '*='
| '/='
| '%='
| '+='
| '-='
;
additiveExpression
: multiplicativeExpression
| additiveExpression '+' multiplicativeExpression
| additiveExpression '-' multiplicativeExpression
;
multiplicativeExpression
: primaryExpression
| multiplicativeExpression '*' primaryExpression
| multiplicativeExpression '/' primaryExpression
| multiplicativeExpression '%' primaryExpression
;
这里左递归antlr会自动处理。import CommonLexer; 中CommonLexer是一个成熟的此法定义包,这里再语法定义文件中导入即可。
antlr PlayScript.g4
javac antlrtest/*.java
grun antlrtest.PlayScript expression -gui
测试 PlayScript 这个类的 expression 方法,也就是解析表达式的方法,结果用图形化界面显示。也就是接下来终端中输入一段Token流,按下ctrl+D会自动生成AST并显示出来,这里由于win安装常出错还是先记下宫老师的图,日后再试:


可以看到左结合没有问题。