我有一个简单的语法,最终会解析杨源。当我发现似乎是任意改变MODULE令牌的位置时,IntelliJ ANTLR4插件可以/不能解析我的输入。
要解析的输入字符串:
module x { }
这是没有任何错误的语法:
grammar Yang ;
yang: module_open module_close;
module_open : MODULE ID BRACKET_OPEN ;
module_close: BRACKET_CLOSE ;
MODULE: 'module' ;
ID: ([A-Za-z][A-Za-z0-9_-]*) ;
BRACKET_OPEN: '{' ;
BRACKET_CLOSE: '}' ;
WS: [ \t\r\n]+ -> skip ;
这是失败的语法:
grammar Yang ;
yang: module_open module_close;
module_open : MODULE ID BRACKET_OPEN ;
module_close: BRACKET_CLOSE ;
ID: ([A-Za-z][A-Za-z0-9_-]*) ;
MODULE: 'module' ;
BRACKET_OPEN: '{' ;
BRACKET_CLOSE: '}' ;
WS: [ \t\r\n]+ -> skip ;
我正在做的就是在ID令牌之前/之后剪切粘贴MODULE令牌定义,如果MODULE定义在ID定义之后,它总是会失败。
我错过了什么?我在文档中看不到关于令牌顺序的讨论!
编辑:@BartKiers相关帖子...... ANTLR4 lexer rules don't work as expected
答案 0 :(得分:2)
如果module
在ID
之后,则会失败,因为文字'模块&#39}也是一个有效的ID'。如果ID规则首先出现,则它具有优先权。当词法分析器规则的顺序重要时,当两个或多个词法分析器规则可以匹配相同的输入时。在这种情况下,出现的那个首先胜过那些跟随;它有优先权。
这里出色的测试案例是这种行为的完美典范。
在ANTLR4文档中曾经有一篇很棒的文章,除了Sam Harwell之外,完全解释了这一点,但我再也找不到了。
答案 1 :(得分:1)
摘自《 Antlr》(第5.5节):
匹配标识符
在语法伪代码中,基本标识符是的非空序列 大写和小写字母。使用我们的新技能,我们知道 使用符号
(...)+
表示序列模式。因为 序列的元素可以是大写或小写字母, 我们也知道我们会在子规则中有一个选择运算符。
ID : ('a'..'z'|'A'..'Z')+ ; //
匹配1个或多个大写或小写字母 字母这里唯一的新ANTLR表示法是范围运算符:
'a'..'z'
表示从a到z的任何字符。那实际上是ASCII码 范围从97到122。要使用Unicode代码点,我们需要使用'\uXXXX'
文字,其中XXXX
是十六进制值 Unicode字符代码点值。作为字符集的简写,ANTLR支持更熟悉的字符集 正则表达式集符号。
ID : [a-zA-Z]+ ; //
匹配1个或多个大写或小写字母诸如ID之类的规则有时会与其他词汇规则或 语法中引用的文字,例如
'enum'
。
grammar KeywordTest;
enumDef : 'enum' '{' ... '}' ;
...
FOR : 'for' ;
...
ID : [a-zA-Z]+ ; // does NOT match 'enum' or 'for'
规则ID也可以 匹配
enum
和for
之类的关键字,这意味着 一个可以匹配相同字符串的规则。为了更清楚一点 考虑一下ANTLR如何处理组合词法分析器语法,例如 这个。 ANTLR收集并分离所有字符串文字和 语法分析器规则中的词法分析器规则。诸如“枚举”之类的文字变成 词汇规则,并在解析器规则之后但在 明确的词汇规则。ANTLR词法分析器通过支持词法规则来解决词法规则之间的歧义 首先指定规则。这意味着您的ID规则应在 您所有的关键字规则,例如与FOR相关的规则。 ANTLR放置 显式词义之前隐式生成的词法规则 lexer规则,因此这些规则始终具有优先权。在这种情况下,
'enum'
是 自动优先于ID。由于ANTLR重新排序 词法规则出现在解析器规则之后,以下变化 KeywordTest上的结果在相同的解析器和词法分析器中:
grammar KeywordTestReordered;
FOR : 'for' ;
ID : [a-zA-Z]+ ; // does NOT match 'enum' or 'for' ...
enumDef : 'enum' '{' ... '}' ;
...