【问题标题】:Why does the order of ANTLR4 tokens matter?为什么 ANTLR4 代币的顺序很重要?
【发布时间】:2018-02-01 02:41:00
【问题描述】:

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

【问题讨论】:

  • @BartKiers 这个答案只承认了问题:订购代币的具体规则是什么?我不明白为什么什么相当于一个简单的替换(.aka. MODULE ->“模块”)应该服从声明的顺序。如果可能,请在文档中引用参考资料。
  • @BartKiers 首先,感谢您回答新问题的努力!我得到“词法分析器尝试匹配尽可能多的字符”部分。但我不明白为什么“当 2 个(或更多)规则匹配相同数量的字符时,首先定义的规则将获胜。”甚至适用于这种情况...我只有一个 MODULE 令牌定义和一个使用该定义的规则“module_open”。”
  • @BartKiers 我能回答我自己的问题最接近的是“令牌定义必须按照它们在解析树中的使用顺序声明。”或类似的东西......但是如果我在另一个解析规则中以不同的顺序使用它们呢?
  • “首先,感谢您的努力回答......”:没问题。 “......它们在解析树中的使用顺序。”不,这不是它的工作原理。由于您不清楚我的答案,我将重新打开您的问题并删除链接。也许其他人能够解释它。

标签: parsing intellij-idea token antlr4


【解决方案1】:

如果moduleID 之后,它会失败,因为文本“模块”也是有效的“ID”。如果 ID 规则首先出现,则它具有优先权。这时候词法分析器规则的顺序很重要,两个或多个词法分析器规则可以匹配相同的输入。在这种情况下,首先出现的规则胜过随后出现的规则;它有优先权。

您在这里出色的测试用例完美地说明了这种行为在工作中的作用。

在此处的 ANTLR4 文档中曾经有一篇很棒的文章,正是 Sam Harwell 完美地解释了这一点,但我再也找不到了。

【讨论】:

  • 我手边没有这本书,但应该在词汇讨论中。
【解决方案2】:

来自 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 看跌期权 在显式之前隐式生成的字面量词法规则 词法分析器规则,所以那些总是优先的。在这种情况下,'enum' 是 自动优先于 ID。因为 ANTLR 重新排序 词法规则出现在解析器规则之后,以下变体 在 KeywordTest 上会产生相同的解析器和词法分析器:

grammar KeywordTestReordered;
FOR : 'for' ;
ID : [a-zA-Z]+ ; // does NOT match 'enum' or 'for' ...
enumDef : 'enum' '{' ... '}' ;
...

【讨论】:

    猜你喜欢
    • 2013-05-18
    • 1970-01-01
    • 1970-01-01
    • 2013-11-18
    • 1970-01-01
    • 2017-06-27
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多