ANTLR v4 中文文档1:语法词典Grammar Lexicon部分
文档地址:ANTLR v4 中文文档
一个更好的文档地址:入门 · ANTLR 4简明教程
学习ANTLR v4
第一部分:
ANTLR实际上有两件事:一种将语法转换为Java(或其他目标语言)的解析器/词法分析器的工具,以及生成的解析器/词法分析器所需的运行时。即使您使用ANTLR Intellij插件或ANTLRWorks来运行ANTLR工具,生成的代码仍将需要运行时库。
您应该做的第一件事可能是下载并安装开发工具插件。即使仅使用此类工具进行编辑,它们也很棒。
从这里学到了一个开发工具:IntelliJ IDEA 是一款由 JetBrains 开发的集成开发环境(IDE),专为提升开发者生产力而设计,尤其以支持 Java、Kotlin 等 JVM 语言开发而闻名。
到网站一看,IntelliJ IDEA个人版也是收费的,学校师生可以免费。有点怀念当前的VS全家桶了。
安装
看这个手册,晕头转向的。我的安装方法是直接pip安装:
pip install antlr4-tools
然后测试
A First Example
在一个临时目录中,将以下语法放入文件Hello.g4中: 你好.g4
//Define a grammar called Hello
grammar Hello;
r : 'hello' ID ; //match keyword hello followed by an identifier
ID : [a-z]+ ; //match lower-case identifiers
WS : [ \t\r\n]+ -> skip ; //skip spaces, tabs, newlines
然后在其上运行ANTLR工具:
$ cd /tmp
$ antlr4 Hello.g4
$ javac Hello*.java
现在测试一下:
$ grun Hello r -tree
(Now enter something like the string below)
hello parrt
(now,do:)
^D
(The output:)
(r hello parrt)
(That ^D means EOF on unix; it's ^Z in Windows.) The -tree option prints the parse tree in LISP notation.
It's nicer to look at parse trees visually.
$ grun Hello r -gui
hello parrt
^D
语法词典Grammar Lexicon
注释
有单行,多行和Javadoc样式的注释,如
/** C 2011 grammar built from the C11 Spec */
// $antlr-format alignTrailingComments true, columnLimit 150, minEmptyLines 1, maxEmptyLinesToKeep 1, reflowComments false, useTab false
// $antlr-format allowShortRulesOnASingleLine false, allowShortBlocksOnASingleLine true, alignSemicolons hanging, alignColons hanging
标识符Identifiers
ANTLR4 的标志符规范主要参考 Java 或 C 的标志符命名规范,具体规则如下:
1. Lexer 部分的 Token 名
- 命名规范:采用全大写字母的形式。
- 示例:
INT
、FLOAT
、STRING
等。
2. Parser Rule 命名
- 命名规范:推荐首字母小写的驼峰命名。
- 示例:
expr
、stat
、functionCall
等。
3. 字符与字符串
- ANTLR4 不区分字符和字符串,都是用单引号引起来的。
- 示例:
'a'
、'123'
、'\n'
等。
4. Unicode 支持
- ANTLR4 支持 Unicode 编码,即支持中文编码等。但为了保持代码的可读性和一致性,建议尽量使用英文。
5. 其他注意事项
- 关键字避免:虽然 ANTLR4 支持一些关键字(如
import
、fragment
、lexer
、parser
等),但应避免将这些关键字作为规则或备选分支名,以免造成冲突。
token 是语法分析过程中的一个核心概念,表示源代码中的最小语义单元。它是词法分析器(Lexer)的输出,也是语法分析器(Parser)的输入。token都要大写。比如INT ID WS等。
rule
(规则) 是语法定义的核心组成部分,用于描述语言的语法结构。规则分为 Lexer 规则 和 Parser 规则,分别用于词法分析和语法分析。
ID, LPAREN, RIGHT_CURLY //token names/rules
expr, simpleDeclarator, d2, header_file //rule names
直接常量Literals
ANTLR不能像大多数语言一样区分字符和字符串文字。所有长度为一个或多个字符的文字字符串都用单引号引起来,例如’;’
,’if’
,’>=’
和’\’
(指的是包含单引号字符)。文字绝不包含正则表达式。
ANTLR还理解通常的特殊转义序列:’\n’
(换行符),’\r’
(回车符),’\t’
(制表符),’\b’
(退格键)和’\f’
(换页)。您可以直接在文字中使用Unicode代码点,也可以使用Unicode转义序列:
grammar Foreign;
a : '外' ;
动作
动作是用目标语言编写的代码块。您可以在语法中的多个位置使用动作,但是语法始终相同:用花括号括起来的任意文本。如果字符串或注释中的结束卷曲字符为"}"
或/*}*/
,则无需转义。如果小括号是配对的,那么您也不需要转义}:{...}
。否则,请使用反斜杠转出多余的括号:\{
或\}
。操作文本应符合语言选项所指定的目标语言。
嵌入式代码可以出现在:@header
和@members
命名动作,解析器和词法分析器规则,异常捕获规范,解析器规则的属性部分(返回值,参数和局部变量)以及一些规则元素选项(当前谓词)。
ANTLR在内部动作中所做的唯一解释与语法属性有关。请参阅令牌属性和第10章属性和操作。嵌入在词法分析器规则中的动作无需任何解释或转换为生成的词法分析器。
关键字Keywords
这是ANTLR语法中保留字的列表:
import, fragment, lexer, parser, grammar, returns,
locals, throws, catch, finally, mode, options, tokens
另外,尽管它不是关键字,但请勿将单词rule
用作规则名称。此外,请勿将目标语言的任何关键字用作标记,标签或规则名称。例如,规则if
将产生一个名为if
的函数。那显然不会编译。
语法词汇表
ANTLR的词汇表对大多数程序员来说都很熟悉,因为它遵循C及其衍生语言的语法,并增加了一些用于语法描述的扩展。
注释
有单行、多行和Javadoc风格的注释:
语法词典
/** 这个语法是一个例子,展示了三种 * 注释类型。 */ grammar T; /* 多行 注释 */ /** 这个规则匹配我语言中的一个声明符 */ decl : ID ; // 匹配一个变量名
Javadoc注释对解析器是隐藏的,目前会被忽略。它们仅用于语法和任何规则的开头。
标识符
标记名称总是以大写字母开头,词法规则也是如此,这由Java的Character.isUpperCase
方法定义。解析器规则名称总是以小写字母开头(那些不符合Character.isUpperCase
的)。初始字符后面可以跟大写和小写字母、数字和下划线。以下是一些示例名称:
antlrCopy Code
ID, LPAREN, RIGHT_CURLY // 标记名称/词法规则 expr, simpleDeclarator, d2, header_file // 解析器规则名称
像Java一样,ANTLR接受Unicode字符作为名称:
为了支持Unicode解析器和词法规则名称,ANTLR使用以下规则:
antlrCopy Code
ID : a=NameStartChar NameChar* { if ( Character.isUpperCase(getText().charAt(0)) ) setType(TOKEN_REF); else setType(RULE_REF); } ;
规则NameChar
识别有效的标识符字符:
antlrCopy Code
fragment NameChar : NameStartChar | '0'..'9' | '_' | '\u00B7' | '\u0300'..'\u036F' | '\u203F'..'\u2040' ; fragment NameStartChar : 'A'..'Z' | 'a'..'z' | '\u00C0'..'\u00D6' | '\u00D8'..'\u00F6' | '\u00F8'..'\u02FF' | '\u0370'..'\u037D' | '\u037F'..'\u1FFF' | '\u200C'..'\u200D' | '\u2070'..'\u218F' | '\u2C00'..'\u2FEF' | '\u3001'..'\uD7FF' | '\uF900'..'\uFDCF' | '\uFDF0'..'\uFFFD' ;
规则NameStartChar
是可以开始标识符(规则、标记或标签名称)的字符列表:这些或多或少对应于Java的Character
类中的isJavaIdentifierPart
和isJavaIdentifierStart
。如果你的语法文件不是UTF-8格式,请确保在ANTLR工具上使用-encoding
选项,以便ANTLR正确读取字符。
字面量
ANTLR不像大多数语言那样区分字符字面量和字符串字面量。所有长度为一个或多个字符的字面量字符串都用单引号括起来,例如';'
、'if'
、'>='
和'\''
(指的是包含一个单引号字符的一字符字符串)。字面量从不包含正则表达式。
字面量可以包含形式为'\uXXXX'
(对于最多U+FFFF
的Unicode代码点)或'\u{XXXXXX}'
(对于所有Unicode代码点)的Unicode转义序列,其中XXXX
是十六进制Unicode代码点值。
例如,'\u00E8'
是带重音符号的法语字母:'è'
,而'\u{1F4A9}'
是著名的表情符号:'💩'
。
ANTLR还理解常见的特殊转义序列:'\n'
(换行)、'\r'
(回车)、'\t'
(制表符)、'\b'
(退格)和'\f'
(换页)。你可以在字面量中直接使用Unicode代码点或使用Unicode转义序列:
antlrCopy Code
grammar Foreign; a : '外' ;
ANTLR生成的识别器假设字符词汇表包含所有Unicode字符。运行时库假设的输入文件编码取决于目标语言。对于Java目标,运行时库假设文件是UTF-8。使用CharStreams
中的工厂方法,你可以指定不同的编码。
动作
动作是用目标语言编写的代码块。你可以在语法中的多个位置使用动作,但语法总是相同的:用花括号括起来的任意文本。如果右花括号在字符串或注释中,则不需要转义:"}"
或/*}*/
。如果花括号是平衡的,你同样不需要转义}
:{...}
。否则,用反斜杠转义多余的花括号:\{
或\}
。动作文本应符合用language
选项指定的目标语言。
嵌入代码可以出现在:@header
和@members
命名动作、解析器和词法规则、异常捕获规范、解析器规则的属性部分(返回值、参数和局部变量)以及一些规则元素选项(当前是谓词)中。
ANTLR在动作内部进行的唯一解释与语法属性有关;见第10章“属性和动作”中的“标记属性”。嵌入在词法规则中的动作在生成的词法器中没有任何解释或翻译地发出。
关键字
以下是ANTLR语法中的保留字列表:
textCopy Code
import, fragment, lexer, parser, grammar, returns, locals, throws, catch, finally, mode, options, tokens
此外,虽然不是关键字,但不要用rule
作为规则名称。此外,不要将目标语言的任何关键字用作标记、标签或规则名称。例如,规则if
会...