ANTLR:如何解释识别Java代码后缀的语法行为?

时间:2013-08-28 19:39:18

标签: java antlr grammar

一周前,我开始了以下项目:一种识别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 -> '{' '}'

1 个答案:

答案 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
    ;