一周前,我开始了以下项目:一种识别Java代码后缀的语法。
我使用Java的官方ANTLR
语法(Java.g4
)作为基线并开始添加一些规则。但是,这些新规则还引入了左递归,我也不得不处理。
经过几天的工作,我得到了following code。当我开始测试时,我注意到一些不寻常的东西,我仍然无法解释。当给出输入{ }
时,解析器告诉我no viable alternative at input '<EOF>'
但是当我在规则s2
的右侧切换终端的顺序时,特别是如果我们改变了右手从v2_1 | v2_2 | v2_3 ...
到v2_36 | v2_1 | v2_2 ...
的一边(终端v2_36
移动到第一个位置),序列{ }
被接受。
我的第一个想法是Antlr
没有回溯,因为我注意到输入{ }
,解析器的第一个版本开始遵循规则v2_3
,并且只报告没有任何内容发现并没有尝试考虑其他选项(这是我的想法,但可能不是真的),如v2_36
,它给出了正确的答案。
但是,经过一些研究,我发现ANTLR
实际上是回溯,但只有在其他一切都失败的情况下。至少对于v3.3(在官方ANTLR
论文中阅读)也是如此,但我想对于v4
也是如此。现在我有点困惑。在这个项目上花了这么多时间后,如果我不能让它工作,我会觉得非常糟糕。有人可以提供某种提示吗?非常感谢,谢谢。
修改
管理将问题隔离到
grammar Java;
@parser::members {String ruleName; }
start : compilationUnitSuf EOF;
compilationUnitSuf
: {ruleName = "typeDeclarationSuf"; } s2
;
s2: '{' '}' v2_81 | '{' '}';
v2_81 : {ruleName.equals("enumBodyDeclarationsSuf")}? t173 | t173 '}';
t173: '}' | '{'*;
LBRACKET: '{';
RBRACKET: '}';
WS : [ \t\r\n\u000C]+ -> skip
;
那么为什么预测算法会建议我关注s2 -> v'{' '}' v2_81 -> ...
而不是s2 -> '{' '}'
?
答案 0 :(得分:1)
我认为你会发现它不会以你期望的方式回溯。原因是它找到{}
,然后期望看到v2_181
,它找不到。因为它没有回溯,它找不到你想要的替代品。另一种方法是只使v2_181
成为可选项,然后您就不需要回溯了。如下所示:
grammar Java;
@parser::members {String ruleName; }
start : compilationUnitSuf EOF;
compilationUnitSuf
: {ruleName = "typeDeclarationSuf"; } s2
;
s2: '{' '}' v2_81?;
v2_81 : {ruleName.equals("enumBodyDeclarationsSuf")}? t173 | t173 '}';
t173: '}' | '{'*;
LBRACKET: '{';
RBRACKET: '}';
WS : [ \t\r\n\u000C]+ -> skip
;