1 词法规则
词法由词法规则组成,分为多个词法模式。
词法解析只能返回当前模式匹配规则的记号。
词法解析定义与语法解析定义相似,不同的是不能有入参、返回值和本地变量,词法名称必须大写字母开头。
如:
1 | /** Optional document comment */ |
可以定义用于辅助识别记号的规则,如:
1 | fragment |
1 | # DIGIT是辅助识别数值的规则 |
2 词法模式
模式用于分组规则。
词法解析器只能返回当前模式匹配规则的记号。
在没有指定模式时,规则属于默认模式。
定义如下:
1 | rules in default mode |
示例详见Tokenizing XML
3 词法规则元素
有两种结构,且在语法解析器中不可用。..
范围操作符和[characters]
字符集。
注意不要混淆字符集和语法解析器中的参数。
所有元素如下:
Syntax | Description | |
---|---|---|
T | 记号 | |
’literal’ | 字面量 | |
[char set] | 字符。支持范围、特殊字符、转义、Unicode和长短Unicode属性(不区分大小写) | |
’x’..’y’ | 范围 | |
T | 词法规则。支持递归,但不是左侧递归。 | |
. | 任意字符 | |
{«action»} | 词法动作。4.2版本中可以在任意位置。对所有选项执行的动作可以使用圆括号包含所有选项,随后附带动作,如`END : (‘endif’ | ‘end’) {System.out.println(“found an end”);} ; `。动作代码逐字符拷贝到目标语言,不会像语法解析器一样解释如\$x.y。注意只有在最外侧规则以内的动作才会被执行。 |
{«p»}? | 评估语义谓词predicate。false时周围的规则不可见。谓词需要在词法动作之前,因此最好放在规则最后。 | |
~x | 排除字符 |
和语法规则一样,词法规则允许子规则和EBNF操作符:?、*、+等,以及非贪婪模式符号?
4 递归词法规则
允许递归,如用于匹配嵌套记号:
1 | lexer grammar Recur; |
5 冗余字符串
注意不要为同一字符串定义多个记号,否则导致词法错误。
1 | lexer grammar L; |
1 | parser grammar P; |
1 | $ antlr4 L.g4 # yields L.tokens file needed by tokenVocab option in P.g4 |
6 词法规则动作
词法规则动作用于设置记号对象的状态。
每个对记号的请求都从Lexer.nextToken
开始,一旦被识别就调用emit
方法。emit收集信息以构建记号对象,如_type、_text、_channel、_tokenStartCharIndex、_tokenStartLine和_tokenStartCharPositionInLine
。可以在动作中设置字段,如:
1 | ENUM : 'enum' {if (!enumIsKeyword) setType(Identifier);} ; |
注意版本4不会在词法解析器中翻译$x
属性。
每个词法规则最多有一个动作。
7 词法命令
为了避免与特定语言绑定,词法解析器支持词法命令。
与内嵌动作不同,命令遵循特殊的语法,且限定了种类。
词法命令出现在规则后面、最外面。
与其他动作相似,一个记号规则只能有一个。
命令使用如下,可以带有参数:
1 | TokenName : «alternative» -> command-name |
一个选项可以有多个逗号分隔的命令。
常见命令如下:
(1) skip
抛弃当前文本,继续下一个记号。
1 | WS : [ \t]+ -> skip ; // toss out whitespace |
(2) mode(), pushMode(), popMode, and more
mode命令改变模式栈。在栈底弹出将抛出异常。
more命令继续下一个记号,但不抛弃当前文本。多个more等效于一个,且顺序无关。
以下为模式定义:
1 | // Default "mode": Everything OUTSIDE of a tag |
以下为命令使用:
1 | lexer grammar Strings; |
(3) type()
多个type时,只有最右侧的生效。
1 | lexer grammar SetType; |
(4) channel()
1 | BLOCK_COMMENT |
可以在词法规则前,像枚举值一样定义:
1 | channels { WSCHANNEL, MYHIDDEN } |