我在语法中遇到空格问题。
这是一个最小的语法,仍然存在问题:
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
。如果我在标识符之间添加空格:
aaa: bbb
它解析没有问题。如果删除~
中的DoubleQuotedStringCharacter
可以使用,但是我不确定为什么,没有它语法就无效。
答案 0 :(得分:1)
TL; DR:将DoubleQuotedStringCharacter
声明为fragment
。
词法分析器通过仔细研究词法规则并查看与当前输入匹配的项来工作。在那些匹配的规则中,然后选择产生最长匹配的规则-如果出现平局,则选择语法中最先出现的规则。一旦选择了一条规则,它就会生成给定类型的令牌供解析器使用,然后对其余输入¹应用相同的逻辑。
请牢记这一点,这是您的词法分析器处理输入"aaa: bbb"
的方式:
当前输入"aaa: bbb"
。
适用规则:标识符(匹配"aaa"
),DoubleQuotedStringCharacter(匹配"a"
?)
选择:标识符,因为它是更长的匹配项
当前输入": bbb"
。
适用规则:“:”(匹配":"
),DoubleQuotedStringCharacter(也匹配":"
)
选择:':',因为两个匹配项相同,并且字符串文字的优先级高于命名规则
当前输入" bbb"
。
适用规则:WS(匹配" "
),DoubleQuotedStringCharacter(也匹配" "
)
选择:DoubleQuotedStringCharacter,因为两个匹配项都相同,并且DoubleQuotedStringCharacter在语法上排在第一位
现在对于输入"aaa: bbb"
,除了步骤3现在变为:
当前输入" bbb"
。
适用规则:WS(匹配" "
),DoubleQuotedStringCharacter(匹配" "
)
选择:WS,因为它是更长的比赛
所以这次WS由于最长匹配规则而获胜。
您可以通过将DoubleQuotedStringCharacter
移至语法末尾来使WS在这两种情况下都胜出,以便所有其他规则都优先于WS,但这不是适当的解决方案。
要意识到的重要一点是,您根本不需要生成DoubleQuotedStringCharacter
令牌。您想将DoubleQuotedStringCharacter
用作其他定义(即StringLiteral
)的一部分,而不要单独使用。那就是片段的用途。如果您将DoubleQuotedStringCharacter
声明为片段(使用fragment
关键字),则可以在词法规则中使用它,但是它不会被视为自身的词法规则,因此在决定要应用哪个词汇规则时将不会被考虑。
¹当解析器请求令牌时,这种情况很懒惰,但这对于此答案的目的并不重要。