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 は有効なトークンであるため、そのように指定していないにもかかわらず、ループが終了しないという問題が発生します。

EDIT行 342 と 347 をコメントアウトしてもエラーは発生しません (ルール accessModifierWithoutPrivateOrPublic、accessModifierOrPublic の空のケース)

EDIT 2私は私の問題を解決することができました. methodModifier ルールを書き直しました (すべての可能な修飾子を 1 つのルールに統合しました)。このように、ANTLR は EOF が after / empty / inの有効なトークンであるとは信じていません

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

1 に答える 1

1

このタイプのバグは、ANTLR 3 のエラー処理で発生する可能性があります。ANTLR 4 では、IntStream.consume() この問題を回避するために次の例外をスローする必要があるようにメソッドが更新されました。

スロー: IllegalStateException- ストリームの最後を消費しようとした場合 (つまり、消費を呼び出す前の場合)。LA(1)==EOF

TokenStreamANTLR 3 文法の場合、独自の実装 (おそらく最も簡単に拡張できるCommonTokenStream) を使用し、上記の条件に違反した場合にこの例外をスローすることで、少なくとも無限ループを防ぐことができます。この条件に 1 回違反することを許可する必要がある場合があることに注意してください(理由は複雑です)。そのため、カウントを保持しIllegalStateException、コードが EOF を 2 回または 3 回以上消費しようとするとスローします。これは無限ループを断ち切るための努力に過ぎないことを覚えておいてください。

于 2013-01-27T18:10:47.663 に答える