单空格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声明为片段,则可以在词法规则中使用它,但它不会被视为自己的词法规则,因此在决定应用哪个词法规则时不会考虑它
当解析器请求令牌时,这种情况会缓慢发生,但这对于本答案来说并不重要。非常好,感谢您提供了一个清晰而全面的答案!