简介
通过Antlr4可以定义一种新的语言或者规则。它是跨语言的。
一个简单例子如下:
// Tokens
MUL: '*';
DIV: '/';
ADD: '+';
SUB: '-';
NUMBER: [0-9]+;
WHITESPACE: [ \r\n\t]+ -> skip;
// Rules
start : expression EOF;
expression
: expression op=('*'|'/') expression # MulDiv
| expression op=('+'|'-') expression # AddSub
| NUMBER # Number
;
组成
上面的简单与法例子中,包含两个部分,tokens和rules。Token是语法中最基础(不可分割)元素,传统的lex就是将输入流转换为一个一个tokens。Rules是tokens和其它rules的组合规则,通过定义的优先级,最终将组合成一棵抽象树。抽象树决定的是程序运行的步骤。
对于Antlr4而言,rule和token的另一个区别是rule会有回调函数(listener,后面会提到),通过这些回调函数实现新语法的解析与执行。
获取
wget http://www.antlr.org/download/antlr-4.7-complete.jar
alias antlr='java -jar $PWD/antlr-4.7-complete.jar'
antlr -Dlanguage=Go -o parser Calc.g4
生成文件
calc.tokens
calcLexer.tokens
calc_base_listener.go
calc_base_visitor.go
calc_lexer.go
calc_listener.go
calc_parser.go
calc_visitor.go
主要包含lex, parser, visitor和listener四个部分。Lex的作用是生成tokens,parser利用lex生成的tokens按照rule定义的规则生成抽象树,visitor和listener是两种语法解析的方法,通常使用一种即可
Token
上述的例子,会生成一下的tokens:NUMBER (1), ADD (+), NUMBER (2), MUL (*), NUMBER (3), EOF
Parser
按照语法的优先级进行结合,下图中红色部分是rule,蓝色部分是token
Listener
抽象树生成后,我们可以遍历该树,Antlr4会在进入(enter)和退出(exit)节点是出发回调函数(event driven manner),这样用户程序就可以感知到正在处理的token和rule。整个遍历过程,相当于代码(规则)编译,编译好后就可以直接执行了。
语法规则
grammar 名称和文件名要一致
Parser 规则(即 non-terminal)以小写字母开始
Lexer 规则(即 terminal)以大写字母开始
所有的 Lexer 规则无论写在哪里都会被重排到 Parser 规则之后
所有规则中若有冲突,先出现的规则优先匹配
用 'string' 单引号引出字符串
| 用于分隔两个产生式,(a|b) 括号用于指定子产生式,?+*用法同正则表达式
在产生式后面 # label 可以给某条产生式命名,在生成的代码中即可根据标签分辨不同产生式
不需要指定开始符号
规则以分号终结
/* block comment */ 以及 // line comment
默认的左结合,可以用 <assoc=right> 指定右结合
可以处理直接的左递归,不能处理间接的左递归
如果用 MUL: '*'; 指定了某个字符串的名字,在程序里面就能用这个名字了
用 fragment 可以给 Lexer 规则中的公共部分命名