编译原理-Antlr1

583 阅读3分钟

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安装常出错还是先记下宫老师的图,日后再试:

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