为什么ANTLR4令牌的顺序很重要?

时间:2017-08-23 13:17:46

标签: parsing intellij-idea token antlr4

我有一个简单的语法,最终会解析杨源。当我发现似乎是任意改变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

2 个答案:

答案 0 :(得分:2)

如果moduleID之后,则会失败,因为文字'模块&#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也可以 匹配enumfor之类的关键字,这意味着 一个可以匹配相同字符串的规则。为了更清楚一点 考虑一下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' '{' ... '}' ;
...
相关问题