Parsing ANTLR语法中的非决定论

Parsing ANTLR语法中的非决定论,parsing,antlr,Parsing,Antlr,如果我有如下ANTLR语法: grammar Test; options { language = Java; } rule : (foo | bar); foo : FOO ',' FOO; bar : BAR; FOO: ('0'..'9')+; BAR: ('a'..'z' | 'A'..'Z' | '0'..'9' | ' ')+; WHITESPACE: (' ' | '\t')+ { $channel=HIDDEN; }; 我使用一个测试字符串: 12abc3

如果我有如下ANTLR语法:

grammar Test;
options {
  language = Java;
}

rule : (foo | bar);


foo : FOO ',' FOO;   
bar : BAR; 

FOO: ('0'..'9')+;
BAR: ('a'..'z' | 'A'..'Z' | '0'..'9' | ' ')+;
WHITESPACE: (' ' | '\t')+ { $channel=HIDDEN; };
我使用一个测试字符串:


12abc3

这(我相信)是一个
BAR
标记,它满足
BAR
规则,并且被解析为这样。好极了

但是,如果我有以下字符串:

12
我收到
行1:2不匹配的输入“'expecting',”


这似乎是不确定的,尽管我肯定不是。我知道我已经有麻烦了,因为我有两个令牌:
FOO
和接受数字的
BAR
。但是,如果解析器要成功或失败,那么它应该一致地成功或失败。换句话说,在第一种情况下,第一个字符是1,并且显然是作为
BAR
标记的成员进行计算的,因此解析器沿着一条成功的路径前进。在第二种情况下,相同的第一个字符被评估为
FOO
标记,因此,尽管字符串可能是成功的
bar
解析,路径注定会失败。为什么不一致?还是我缺少了一些关于ANTLR和/或解析的更基本的东西?

ANTLR在看到下一个标记(或EOF)的第一个字符之前不会确定标记类型。ANTLR还将尝试最长的匹配,这就是为什么您将“12abc3”视为BAR而不是FOO BAR。在第二种情况下,ANTLR将对“12”使用FOO,因为它在语法中列在第一位


除了Adam answer,您还必须意识到,lexer和parser虽然定义在同一语法中,但在不同的时间构造。首先,输入源被标记化,当这种情况发生时,解析器才对这些标记进行操作。当解析器遍历源代码(字符流)以支持完全匹配时(即,将
“12”
标记化为
),不会创建标记。
“12”
被标记为
FOO
的事实是因为
FOO
位于
BAR
规则之前,因此在相同的长匹配情况下具有更高的优先级

简而言之:ANTLR语法不是的