0

请看看我的语法:https ://bitbucket.org/rstoll/tsphp-parser/raw/cdb41531e86ec66416403eb9c29edaf60053e5df/src/main/antlr/TSPHP.g

不知何故,ANTLR 产生了一个无限循环,为以下输入找到无限的 EOF 标记:

class a{public function void a(}

虽然,只有 prog 期望 EOF classBody 也能以某种方式接受它。有人知道我该如何解决这个问题,我必须改变 classBody 分别不接受 EOF 令牌吗?

生成的类中的代码:

// D:\\TSPHP-parser\\src\\main\\antlr\\TSPHP.g:287:129: ( classBody )*
loop17:
do {
    int alt17=2;
    int LA17_0 = input.LA(1);
    if ( (LA17_0==EOF||LA17_0==Abstract||LA17_0==Const||LA17_0==Final||LA17_0==Function||LA17_0==Private||(LA17_0 >= Protected && LA17_0 <= Public)||LA17_0==Static) ) {
        alt17=1;
    }

    switch (alt17) {
    case 1 :
        // D:\\TSPHP-parser\\src\\main\\antlr\\TSPHP.g:287:129: classBody
        {
        pushFollow(FOLLOW_classBody_in_classDeclaration1603);
        classBody38=classBody();
        state._fsp--;
        if (state.failed) return retval;
        if ( state.backtracking==0 ) stream_classBody.add(classBody38.getTree());
        }
        break;

    default :
        break loop17;
    }
} while (true);

问题出现了,当令牌 = EOF 时,循环永远不会退出,因为 EOF 是一个有效的令牌,即使我没有这样指定。

编辑如果我将第 342 行和第 347 行注释掉(分别在规则 accessModifierWithoutPrivateOrPublic、accessModifierOrPublic 中的空例),则不会出现错误

编辑 2我可以解决我的问题。我重写了 methodModifier 规则(将所有可能的修饰符集成到一个规则中)。这样ANTLR不相信EOF是/ empty /in

accessModifierOrPublic
    :   accessModifier 
    |   /* empty */ -> Public["public"]
    ;
4

1 回答 1

1

这种类型的错误可能发生在 ANTLR 3 的错误处理中。在 ANTLR 4 中,该IntStream.consume() 方法已更新为要求引发以下异常以抢占此问题。

抛出: IllegalStateException- 如果尝试消费流的末尾(即,如果在调用消费之前)。LA(1)==EOF

对于 ANTLR 3 语法,您至少可以通过使用自己的TokenStream实现(可能最容易扩展CommonTokenStream)来防止无限循环,如果违反上面列出的条件,则抛出此异常。请注意,您可能需要允许违反此条件一次(原因很复杂),因此IllegalStateException如果代码尝试消耗 EOF 超过 2 或 3 次,请保留计数并抛出。请记住,这只是打破无限循环的努力,因此您在实际检查时可能会有点“模糊”。

于 2013-01-27T18:10:47.663 回答