1.简介:
ANTLR v4是一款功能强大的语法分析器生成器,可以用来读取、处理、执行和转换结构化文本或二进制文件。它被广泛应用于学术界和工业界构建各种语言、工具和框架。
2 关键字:
import, fragment, lexer, parser, grammar, returns,
locals, throws, catch, finally, mode, options, tokens
3注释
多行:/****/
单行:/****/
4.语法结构
41.官网例句
/** Optional javadoc style comment */
grammar Name; ①
options {...}
import ... ;
tokens {...}
channels {...} // lexer only
@actionName {...}
rule1 // parser and lexer rules, possibly intermingled
...
ruleN
4.2规范
1.文件名称必须为 grammar Name 中名字+.g4 示例: Name.g4
注:
在标头上没有前缀定义的语法grammar
是组合语法,可以包含词法规则和解析器规则。要制作只允许解析器规则的解析器语法,请使用以下标头。
parser grammar Name;
...
纯词法分析器语法看起来像这样:
lexer grammar Name;
...
2.options {...} 选项
3.import ... 导入
4.tokens {...} 令牌规范
4.1目的:tokens
是定义没有关联词法规则的文法所需的标记类型
语法:
tokens { Token1, ..., TokenN }
大多数时候,令牌部分用于定义语法中的操作所需的令牌类型,识别关键字
// explicitly define keyword token types to avoid implicit definition warnings
tokens { BEGIN, END, IF, THEN, WHILE }
@lexer::members { // keywords map used in lexer to assign token types
Map<String,Integer> keywords = new HashMap<String,Integer>() {{
put("begin", KeywordsParser.BEGIN);
put("end", KeywordsParser.END);
...
}};
}
该tokens
部分实际上只是定义了一组要添加到整个集合中的标记。
$ cat Tok.g4
grammar Tok;
tokens { A, B, C }
a : X ;
$ antlr4 Tok.g4
warning(125): Tok.g4:3:4: implicit definition of token X in parser
$ cat Tok.tokens
A=1
B=2
C=3
X=4
5.channels{...} 规则通道
注:
只有词法分析器语法可以包含mode
规范。
只有词法分析器语法可以包含自定义通道规范
channels {
WHITESPACE_CHANNEL,
COMMENTS_CHANNEL
}
然后可以在词法分析器规则中像枚举一样使用这些通道
WS : [ \r\t\n]+ -> channel(WHITESPACE_CHANNEL) ;
6.解析器:
ruleName : alternative1 | ... | alternativeN ;
注:
解析器规则名称必须以小写字母开头,词法分析器规则必须以大写字母开头
7.语法
目前只有两个定义的命名操作(针对 Java 目标)在语法规则之外使用:header
和members
. 前者将代码注入到生成的识别器类文件中,在识别器类定义之前,后者将代码注入到识别器类定义中,作为字段和方法。
对于组合语法,ANTLR 将动作注入到解析器和词法分析器中。要将操作限制为生成的解析器或词法分析器,请使用@parser::name
or @lexer::name
。
下面是一个示例,其中语法为生成的代码指定了一个包:
<span style="color:#1f2328"><span style="background-color:#ffffff"><span style="color:var(--color-fg-default)"><span style="background-color:var(--color-canvas-subtle)"><code>grammar Count;
@header {
package foo;
}
@members {
int count = 0;
}
list
@after {System.out.println(count+" ints");}
: INT {count++;} (',' INT {count++;} )*
;
INT : [0-9]+ ;
WS : [ \r\t\n]+ -> skip ;
</code></span></span></span></span>
然后语法本身应该在目录中foo
,以便 ANTLR 在同一foo
目录中生成代码(至少在不使用-o
ANTLR 工具选项时):
<span style="color:#1f2328"><span style="background-color:#ffffff"><span style="color:var(--color-fg-default)"><span style="background-color:var(--color-canvas-subtle)"><code>$ cd foo
$ antlr4 Count.g4 # generates code in the current directory (foo)
$ ls
Count.g4 CountLexer.java CountParser.java
Count.tokens CountLexer.tokens
CountBaseListener.java CountListener.java
$ javac *.java
$ cd ..
$ grun foo.Count list
=> 9, 10, 11
=> EOF
<= 3 ints
</code></span></span></span></span>
Java 编译器期望包中的类foo
位于目录中foo
。
8.
注:导入和令牌规范中的每一个最多可以有一个
除了标题 ① 和至少一个规则之外,所有这些元素都是可选的
5.准备工作:idea安装插件
6.创建一个java项目,并在其中创建一个.g4的文件
注:
1.文件名称需与grammar后名称一致
2.解析器规则名称总是以小写字母开头
3.首字符后可以跟大小写字母、数字和下划线
4.令牌名称始终以大写字母开头
grammar Hello;
r : 'hello' ID ; // 匹配关键字 hello 后跟一个标识符
ID : [a-z]+ ; // 匹配小写标识符
WS : [ \t\r\n]+ -> skip ; // 跳过空格、制表符、换行符
文件上邮件执行:
7.查看生成文件
Hello.interp
Hello.tokens :ANTLR会给每个我们定义的词法符号指定一个数字形式的类型
HelloBaseListener.java :监听器类(实现)【通过监听触发回调方法】
HelloBaseVisitor.java :访问者(Visitor)模式实现【可以修改分词过程中的数据】
HelloLexer.interp
HelloLexer.java :词法解析器类识别我们语法中的文法规则和词法规则
HelloLexer.tokens
HelloListener.java :监听器类(接口)
HelloParser.java :语法解析器类
HelloVisitor.java :访问者(Visitor)模式接口