Antlr4 语法无关输入单个 space

Antlr4 grammar extraneous input with single space

我的语法中有白色space的问题。

这是一个仍然存在问题的最小语法:

sourceUnit
  : ( foo ) EOF ;

foo
  : (Identifier ':' Identifier)
  ;

StringLiteral
  : '"' DoubleQuotedStringCharacter* '"'
  ;

DoubleQuotedStringCharacter
  : ~["\r\n\] | ('\') ;  // The problem is in here somewhere

Identifier
  : [a-zA-Z$_][a-zA-Z0-9$_]* ;

WS
  : [ \t\r\n]+
    -> skip;

如果我使用以下输入测试此语法:

aaa: bbb

我得到 extraneous input ' ' expecting Identifier。如果我在标识符之间添加 space:

aaa:  bbb

解析没有问题。如果我删除 DoubleQuotedStringCharacter 中的 ~ 它会起作用,但我不确定为什么,没有它语法就无效。

TL;DR:将 DoubleQuotedStringCharacter 声明为 fragment

词法分析器的工作原理是检查您的词法规则并查看哪一个与当前输入匹配。在匹配的规则中,它会选择产生最长匹配的规则——如果出现平局,它会选择语法中排在第一位的规则。一旦它选择了一个规则,它就会生成一个给定类型的标记以供解析器使用,然后对剩余的输入应用相同的逻辑。

考虑到这一点,下面是您的词法分析器处理输入的方式 "aaa: bbb":

    • 当前输入"aaa: bbb".

    • 适用规则:Identifier(匹配"aaa"),DoubleQuotedStringCharacter(匹配"a"?)

    • 选择:标识符,因为它是较长的匹配项

    • 当前输入": bbb".

    • 适用规则:':'(匹配":"),DoubleQuotedStringCharacter(也匹配":"

    • 选择:':' 因为两个匹配项相同并且字符串文字的优先级高于命名规则

    • 当前输入" bbb".

    • 适用规则:WS(匹配" "),DoubleQuotedStringCharacter(也匹配" "

    • 选择:DoubleQuotedStringCharacter 因为两个匹配项相同并且 DoubleQuotedStringCharacter 在语法中排在第一位

  1. 同 1
  2. EOF

现在输入 "aaa: bbb" 除了第 3 步现在变成:

看起来几乎一样
  • 当前输入" bbb".

  • 适用规则:WS(匹配" ")、DoubleQuotedStringCharacter(匹配" "

  • 选择:WS 因为它是更长的比赛

所以这次WS因为最长匹配规则获胜

您可以通过将 DoubleQuotedStringCharacter 移动到语法末尾来使 WS 在两种情况下都胜出,这样所有其他规则都将优先于它,但这不是正确的解决方案。

要认识到的重要一点是,您根本不想生成 DoubleQuotedStringCharacter 令牌。您希望将 DoubleQuotedStringCharacter 用作其他定义(即 StringLiteral)的一部分,而不是单独使用。这就是片段的用途。如果你将 DoubleQuotedStringCharacter 声明为一个片段(使用 fragment 关键字),你将能够在词法规则中使用它,但它不会被视为它自己的词法规则,所以它在决定应用哪个词法规则时不会考虑。


¹ 这是延迟发生的,因为解析器请求令牌,但这对于这个答案的目的并不重要。