1. 注释、命名规范、保留字
- 注释:支持单行、多行、Javadoc风格的注释。Javadoc风格注释只能出现在语法和任意规则的开头。
- 标识符:词法符号和词法规则名以大写字母开头,语法规则以小写字母开头。后面的字符可以是大小写字符、数字、下划线。
- 文件命名:文件第一行命名语法名字X,包含语法X的文件必须被命名为X.g4
- 文本常量:ANTLR不区分字符常量和字符串常量,所有文本常量都是由单引号括起来的字符串。文本常量不支持正则表达式,可以包含\uXXXX形式的Unicode转义序列。
- 保留字:import 、fragment、lexer、parser、grammar、returns、locals、throws、catch、finally、mode、options、tokens,rule不是关键字但也需要避免。另外不使用目标语言中的关键字作为标识符。
2. 文件结构
-
语法声明:不带前缀的语法声明时混合语法,可同时包含词法规则和文法规则,如
grammar Name;
;只允许文法规则出现使用parser grammar Name;
;值允许词法规则出现则使用lexer grammar Name;
-
options、import、tokens:这些声明可以以任何次序出现,可有可无,最多出现一次。
- options
可以理解为一些特定的参数设定。可通过ANTLR语法在文件中提前设定。
语法形式:options { name1=value1; ......nameN=valueN;}
superClass: 设定生成的语法分析器或词法分析器的父类。混合语法设定的是语法分析器的父类
language: 可行则生成指定语言的代码。否则报错
tokenVocab: ANTLR会为每个语法生成一个".tokens"文件,这个选项可以指定其他语法生成的tokens文件,最后会也会生成进当前语法的tokens文件中。
TokenLabelType: ???? - tokens
定义了一份语法所需,但没有在本语法中列出对应规则的词法符号。
基本的语法:tokens {<<Token1>>, ... , <<TokenN>>}
- import
导入其他的词法或者语法文件,例如
import SelectClauseParser, FromClauseParser, IdentifiersParser;
- options
-
动作:动作是使用目标语言编写的代码块,可在语法中很多位置使用,格式是由花括号包围的任意文本。内嵌代码可以出现在以@header、@members命名的动作、词法和语法规则、指定异常捕获区、语法规则的属性区域(返回值、参数以及局部变量)以及一些规则元素的选项。
-
语法、词法规则
3. 通用规则
- 语法导入: 一个语法会从其导入的语法中继承所有的规则、词法符号声明和具名的动作。位于主语法中的规则将会覆盖其导入的语法中的规则,词法符号和具名动作如@members会被合并;被导入语法中的所有选项 options会被忽略;
并非每种类型的语法都能导入其他类型语法:词法语法能导入词法语法、句法语法能导入句法语法、混合语法能导入词法语法或者句法语法 - 动作相关规则:对于JAVA目标语言而言只有 headers 和 members两种动作。
headers用于将代码注入生成的识别类中的类声明之前(例如package xxx.xxxx.xxx或者import java类)
members用于将代码注入为识别类的字段和方法
对于混合语法,ANTLR会同时将这些代码注入到词法分析器和语法分析器中,如果只需出现在特定分析器中,使用@parser::name
或者@lexer::name
4. 文法规则
文法名 : 备选分支1 # Return // #后面的是备选分支的标签,为了获得更加精确的语法分析器监听器事件。
| 备选分支2
;
注意事项:
- 对于一个规则的备选分支,要么全都带上标签,要么全都不带。标签无须位于行尾,#后面的空格不必须, ANTLR为每个标签生成一个规则上下文类
- ANTLR为每个规则引用生成上下文对象的访问方法。
对于只包含一条规则引用的规则,例如:inc : e '++';
, ANTLR生成无参方法。
对于包含多条规则引用的规则,例如:field : e '.' e;
,ANTLR生成单参数方法,其参数是访问第i个规则时的索引值。另外还生成一个返回该规则对应的所有上下文对象列表的方法。 - 可以使用 = 符号给规则元素增加标签,以此为规则上限文对象增加字段。
例如:stat : 'return' value=e ';'
value就是规则e的返回值 - 当需要匹配除了一个/一组词法符号之外的任何东西时,使用 ~ "非"运算符。例如
~INT
~','
~(INT|ID)
匹配除INT或ID以外的任何词法符号。 - 4种子规则,子规则被包括在圆括号内
(x|y|z)
: 匹配该子规则内的任意备选分支一次
(x|y|z)?
:匹配子规则内的备选分支或者不匹配任何东西
(x|y|z)*
:匹配该子规则内的备选分支零次或多次
(x|y|z)+
:匹配该子规则内的备选分支一次或多次
可以在 ? * + 后面加上?表示非贪婪运算符 - 想要修改单条规则的异常处理机制,可以在规则定义后指定一个异常,如果有即使异常发生也需要执行的动作代码放入finally语句中
例如:
r : ...
;
catch[RecognitionException e] { throw e;}
finally { System.out.println(); }
5. 词法规则
6. 嵌入动作、属性等
- 嵌入动作
动作:使用目标语言编写的、放置在{…}中的任意代码块。
一些语言类应用程序需要在语法分析的过程中执行自身的逻辑代码,为了达到这个目的需要将代码片段注入到ANTLR生成的代码中。
例1:
@parser::members {
Map<String, Integer> memory = new HashMap<String, Integer>();
}
stat : e NEWLINE {System.out.println($e.v);}
| ID '=' e NEWLINE {memory.put($ID.text, $e.v);}
| NEWLINE
;
动作出现在备选分支的末尾,因此它们会在语法分析器匹配到整个语句之后被执行。
动作代码中的 $x.y
是指元素x的y属性,x可以是词法符号引用或者规则引用。$e.v指的是调用规则e的返回值,$ID.text指的是ID词法符号匹配到的文本。