不知何故,ANTLR为以下输入产生无限循环,发现无限EOF标记:
class a{public function void a(}
虽然,只有前卫希望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);
出现问题,当token = EOF时,循环永远不会退出,因为EOF是一个有效的令牌,即使我没有这样指定。
编辑如果我将第342行和第347行注释掉(规则accessModifierWithoutPrivateOrPublic中的空案例,分别是accessModifierOrPublic),则不会收到错误
编辑2 我可以解决我的问题。我重写了methodModifier规则(在一个规则中集成了所有可能的修饰符)。这样,在空 / in
之后,ANTLR不相信EOF是有效令牌accessModifierOrPublic
: accessModifier
| /* empty */ -> Public["public"]
;
答案 0 :(得分:1)
在ANTLR 3的错误处理中可能会发生此类错误。在ANTLR 4中,IntStream.consume()
方法已更新为要求抛出以下异常以抢占此问题。
抛出:
IllegalStateException
- 如果尝试使用流的结尾(即LA(1)
==
EOF
,则在调用之前)。
对于ANTLR 3语法,您至少可以通过使用自己的TokenStream
实现(可能最容易扩展CommonTokenStream
)来防止无限循环,并在违反上面列出的条件时抛出此异常。请注意,可能需要允许违反此条件一次(原因很复杂),因此如果代码尝试消耗超过2或3的EOF,请保持计数并抛出IllegalStateException
倍。请记住,这只是为了打破无限循环,以便在实际检查中有点“模糊”。