下面这个非常简单的语法示例并不像我所期望的那样(一点也不)。
Declaration : 'VAR';
Letter: ('A'..'Z');
message : Declaration Letter+;因此,我所期望的是,任何字母序列都会将lex作为单个字母,而序列“VAR”将被作为单个标记进行词汇处理。
当我查看ANTLRWorks interperter时,我看到以下结果:
VARA将解析为message -> "VAR", "A" (预期)VARVA不解析(MismatchedTokenException(-1 != 5)。雷克萨斯击中了第二个VA,并试图对Declaration进行令牌化。预期:message -> "VAR", "V", "A"VARVPP将解析为message -> "VAR", "V", "P", "P" (预期)VARVALL将其解析为message -> "VAR", "VALL"。我想要一些帮助理解这种行为,并建议我如何解决这个问题。
具体地说:
VA开头的字符串后面跟着一个字母,那么它为什么要尝试把所有字符串都托起呢?V开头的所有字符串来完成此操作?发布于 2012-12-03 12:42:15
让我们来看看你的四个例子:
1 "VARA“

一切都好。
2 "VARVA“
"VAR" (很明显)被标记为VAR,但是lexer“看到”"VA"并期望得到一个不存在的"R"。它发出以下错误:
line 1:5 mismatched character '<EOF>' expecting 'R'
line 1:5 required (...)+ loop did not match anything at input '<EOF>'并丢弃导致创建单个令牌的"VA",正如您在运行ANTLRWorks调试器时所看到的(忽略解析中的异常,它们实际上并不存在:):

你必须意识到的是,雷克萨斯永远不会放弃它已经匹配的东西。因此,如果lexer看到了"VA"并且不能在它之后匹配一个"R",那么它将查看其他可以与"VA"匹配的词汇规则。但是Letter与此不匹配(它只匹配单个字母!)如果您将Letter更改为与多个字符匹配,则ANTLR将能够返回该规则。但是当它匹配一个字母时就不行了: lexer不会为了让"A"规则匹配而放弃来自"VA"的Letter。无可奈何:这就是ANTLR的lexer的工作方式。
这通常不是一个问题,因为当关键字不能匹配时,通常会有某种类型的IDENTIFIER规则使词法器返回。
3 "VARVPP“

好的:"VAR"变成了一个VAR,然后莱克星试图在"V"之后匹配一个"A",但是这没有发生,所以莱克星回到了单一"V"的Letter规则上。在此之后,"PP"都被标记为Letter。
4 "VARVALL“
"VAR"又变成了VAR。然后,"L"中的"VAL"将导致lexer产生以下错误消息:
line 1:5 mismatched character 'L' expecting 'R'最后一个"L"变成了一个Letter

我想(或希望)前三个问题现在已经回答了,这就留给了你最后的答案:
我应该如何改变这个语法来解析我所期望的方式?
如果前面确实有"VAR",则强制lexer首先查看字符流,如果没有,只需匹配一个"V"并将匹配的令牌类型更改为Letter,如下所示:
Declaration
: ('VAR')=> 'VAR'
| 'V' {$type=Letter;}
;正如我在回答之前提到的,请参阅以下相关的问答:ANTLR lexer can't lookahead at all
发布于 2012-12-03 12:14:14
lexer并不真正执行展望,只有解析器执行;您可以在ANTLR lexer can't lookahead at all中了解更多有关它的信息。所以这里的问题是,一旦VAR不匹配,它就会试图匹配到目前为止得到的结果-- VA --并且没有匹配的标记,因为字母不能匹配两个字符,只有一个字符。
至于解决方案,一个简单的解决方案就是将其更改为单个令牌:
Message : 'VAR' ('A'..'Z')+;
message : Message;但是,它不会为每封信给你一个不同的标记。
https://stackoverflow.com/questions/13679674
复制相似问题