单空格Antlr4语法无关输入

单空格Antlr4语法无关输入,antlr4,Antlr4,我对语法中的空格有意见 下面是一个仍然存在问题的最小语法: sourceUnit : ( foo ) EOF ; foo : (Identifier ':' Identifier) ; StringLiteral : '"' DoubleQuotedStringCharacter* '"' ; DoubleQuotedStringCharacter : ~["\r\n\\] | ('\\') ; // The problem is in here somewher

我对语法中的空格有意见

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

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
我获得了与“”无关的输入,需要标识符。如果在标识符之间添加空格:

aaa:  bbb
它解析起来没有问题。如果我删除DoubleQuotedStringCharacter中的~in,它会起作用,但我不知道为什么,没有它语法就无效

TL;DR:将DoubleQuotedStringCharacter声明为片段

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

考虑到这一点,以下是您的lexer如何处理输入aaa:bbb:

当前输入aaa:bbb

适用规则:标识符匹配aaa,DoubleQuotedStringCharacter匹配a

拾取:标识符,因为它是较长的匹配项

电流输入:bbb

适用规则:':'匹配:,DoubleQuotedStringCharacter也匹配:

拾取:“:”因为两个匹配项相同,并且字符串文字的优先级高于命名规则

电流输入bbb

适用规则:WS匹配,DoubleQuotedStringCharacter也匹配

Pick:DoubleQuotedStringCharacter,因为两个匹配项相同,并且DoubleQuotedStringCharacter在语法中位于第一位

与1相同 EOF 现在对于输入aaa:bbb,除了步骤3现在变成:

电流输入bbb

适用规则:WS-matches、DoubleQuotedStringCharacter匹配

选择:WS,因为这是一场较长的比赛

所以这次WS赢是因为最长的比赛规则

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

需要了解的重要一点是,您根本不希望生成DoubleQuotedStringCharacter标记。您希望使用DoubleQuotedStringCharacter作为其他定义的一部分,即StringLiteral,而不是单独使用。这就是碎片的用途。如果使用fragment关键字将DoubleQuotedStringCharacter声明为片段,则可以在词法规则中使用它,但它不会被视为自己的词法规则,因此在决定应用哪个词法规则时不会考虑它


当解析器请求令牌时,这种情况会缓慢发生,但这对于本答案来说并不重要。

非常好,感谢您提供了一个清晰而全面的答案!