5

私は Antlr4 を使用しています。これが私が書いた簡略化された文法です。

grammar BooleanExpression;

/*******************************
 *      Parser Rules
 *******************************/
booleanTerm
    : booleanLiteral (KW_OR booleanLiteral)+
    | booleanLiteral
    ;

id
    : IDENTIFIER
    ;

booleanLiteral
    : KW_TRUE
    | KW_FALSE
    ;

/*******************************
 *         Lexer Rules
 *******************************/
KW_TRUE
    : 'true'
    ;

KW_FALSE
    : 'false'
    ;

KW_OR
    : 'or'
    ;   

IDENTIFIER
    : (SIMPLE_LATIN)+
    ;

fragment 
SIMPLE_LATIN
    : 'A' .. 'Z'
    | 'a' .. 'z'
    ;

WHITESPACE
    : [ \t\n\r]+ -> skip
    ;

以下のように BailErrorStategy と BailLexer を使用しました。

public class BailErrorStrategy extends DefaultErrorStrategy {
    /**
     * Instead of recovering from exception e, rethrow it wrapped in a generic
     * IllegalArgumentException so it is not caught by the rule function catches.
     * Exception e is the "cause" of the IllegalArgumentException.
     */

    @Override
    public void recover(Parser recognizer, RecognitionException e) {
        throw new IllegalArgumentException(e);
    }

    /**
     * Make sure we don't attempt to recover inline; if the parser successfully
     * recovers, it won't throw an exception.
     */
    @Override
    public Token recoverInline(Parser recognizer) throws RecognitionException {
        throw new IllegalArgumentException(new InputMismatchException(recognizer));
    }

    /** Make sure we don't attempt to recover from problems in subrules. */
    @Override
    public void sync(Parser recognizer) {
    }

    @Override
    protected Token getMissingSymbol(Parser recognizer) {
        throw new IllegalArgumentException(new InputMismatchException(recognizer));
    }
}



 public class BailLexer extends BooleanExpressionLexer {
    public BailLexer(CharStream input) {
        super(input);
        //removeErrorListeners();
        //addErrorListener(new ConsoleErrorListener());
    }

    @Override
    public void recover(LexerNoViableAltException e) {
        throw new IllegalArgumentException(e); // Bail out
    }

    @Override
    public void recover(RecognitionException re) {
        throw new IllegalArgumentException(re); // Bail out
    }
}

1 つのケースを除いて、すべて正常に動作します。次の表現を試しました。

true OR false

「or」トークンは大文字ではなく小文字にする必要があるため、この式は拒否され、IllegalArgumentException がスローされると予想されます。しかし、Antlr4 はこの式を拒否せず、式は "KW_TRUE IDENTIFIER KW_FALSE" にトークン化されていることが判明しました (これは予想されます。大文字の 'OR' は IDENTIFIER と見なされます)。このトークン ストリームを処理し、「true」のみを含むツリーに解析し、残りの「IDENTIFIER KW_FALSE」トークンを破棄しました。さまざまな予測モードを試しましたが、すべて上記のように機能しました。なぜこのように動作し、デバッグを行ったのかわかりませんが、最終的に Antlr の次のコードにつながりました。

ATNConfigSet reach = computeReachSet(previous, t, false);

if ( reach==null ) {
    // if any configs in previous dipped into outer context, that
    // means that input up to t actually finished entry rule
    // at least for SLL decision. Full LL doesn't dip into outer
    // so don't need special case.
    // We will get an error no matter what so delay until after
    // decision; better error message. Also, no reachable target
    // ATN states in SLL implies LL will also get nowhere.
    // If conflict in states that dip out, choose min since we
    // will get error no matter what.
    int alt = getAltThatFinishedDecisionEntryRule(previousD.configs);
    if ( alt!=ATN.INVALID_ALT_NUMBER ) {
        // return w/o altering DFA
        return alt;
    }
    throw noViableAlt(input, outerContext, previous, startIndex);
}  

コード「int alt = getAltThatFinishedDecisionEntryRule(previousD.configs);」booleanTerm で 2 番目の選択肢を返しました (「true」は 2 番目の選択肢「booleanLiteral」と一致するため) が、ATN.INVALID_ALT_NUMBER と等しくないため、noViableAlt はすぐにはスローされません。そこにある Java のコメントによると、「どうしてもエラーが発生するので、決定後まで遅らせてください」とありますが、最終的にエラーはスローされなかったようです。

この場合、Antlrがエラーを報告する方法が本当にわかりません。これについて誰かが私に光を当てることができますか? どんな助けでも大歓迎です、ありがとう。

4

1 に答える 1

8

トップレベルのルールが明示的な で終わらEOFない場合、ANTLR は入力シーケンスの最後まで解析する必要はありません。例外をスローするのではなく、指定したシーケンスの有効な部分を単純に解析しました。

次のstartルールは、入力シーケンス全体を単一の として解析することを強制しますbooleanTerm

start : booleanTerm EOF;

また、BailErrorStrategyANTLR 4 ランタイムによって提供されParseCancellationException、例に示されているものよりも有益なものをスローします。

于 2013-02-28T14:24:22.127 に答える