2017-07-31 8 views
1

私はANTLR4のパーサーの特定のエラーメッセージを取得したいと思います。 そして、私はエラーを処理する2つの方法があることを発見しました:errorListenerとerrorHandler。ANTLR4のerrorListenerとerrorHandlerの違いは何ですか?

// set error handler 
parser.removeErrorListeners(); 
parser.addErrorListener(new QueryErrorListener()); 

parser.setErrorHandler(new BailErrorStrategy()); 

しかし、私はそれらの違いについて混乱しています。

私は、errorListenerは特定のエラーメッセージを受け取ることができますが、それを印刷することもログを記録することもできますが、例外をスローすることはできません。ベローとして

は、ErrorListenerのimplemention:

public class QueryErrorListener extends BaseErrorListener { 

    private static final Logger LOGGER = LoggerFactory.getLogger(QueryDispatcher.class); 


    @Override 
    public void syntaxError(Recognizer<?, ?> recognizer, Object offendingSymbol, 
          int line, int charPositionInLine, String msg, 
          RecognitionException e) 
    { 
     List<String> stack = ((Parser)recognizer).getRuleInvocationStack(); Collections.reverse(stack); 
     String errorMessage = "line "+line+":"+charPositionInLine+" at "+ 
       offendingSymbol+": "+msg; 
     LOGGER.error("rule stack: "+stack); 
     LOGGER.error(errorMessage); 
     QueryParseErrorStrategy queryParseErrorStrategy = new QueryParseErrorStrategy(); 

    } 
} 

同時に、のErrorHandlerは、任意の特定のメッセージなし例外ParseCancellationExceptionを投げることができます。

public class BailErrorStrategy extends DefaultErrorStrategy { 
    /** Instead of recovering from exception {@code e}, re-throw it wrapped 
    * in a {@link ParseCancellationException} so it is not caught by the 
    * rule function catches. Use {@link Exception#getCause()} to get the 
    * original {@link RecognitionException}. 
    */ 
    @Override 
    public void recover(Parser recognizer, RecognitionException e) { 
     for (ParserRuleContext context = recognizer.getContext(); context != null; context = context.getParent()) { 
      context.exception = e; 
     } 

     throw new ParseCancellationException(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 
    { 
     InputMismatchException e = new InputMismatchException(recognizer); 
     for (ParserRuleContext context = recognizer.getContext(); context != null; context = context.getParent()) { 
      context.exception = e; 
     } 

     throw new ParseCancellationException(e); 
    } 

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

私は怒鳴るよう、ParseCancellationExceptionから詳細メッセージを取得するには、転送方法を追加し、解決策を見つけることを試みるました。

私はRecognitionExceptionのTokenオブジェクトから何らかのメッセージを受け取ることができますが、行/ charPositionInLine/offendingSymbolメッセージしか見つけることができません。「xxxがない」などの詳細メッセージがどこにあるのかわかりません。 「yyy」を期待する」

public class ANTLRExceptionTransfer { 

    public static SemanticException transfer(RecognitionException re) { 
     String errorMsg = ""; 
     Recognizer<?, ?> recognizer = re.getRecognizer(); 
     Token offendingSymbol = re.getOffendingToken(); 
     int line = offendingSymbol.getLine(); 
     int charPositionInLine = offendingSymbol.getCharPositionInLine(); 
     // ???????? 
     String msg = ""; 

     List<String> stack = ((Parser)recognizer).getRuleInvocationStack(); 
     Collections.reverse(stack); 

     String errorMessage = "rule stack: "+stack; 
     errorMessage = "\nline "+line+":"+charPositionInLine+" at "+ 
       offendingSymbol+": "+msg; 
     return new SemanticException(errorMessage); 


    } 
} 

errorHandlerを使用するのは正しい方法ですか? 特定のエラーメッセージで例外を取得するにはどうすればよいですか?

+0

私は今RecognitionExceptionから基本情報を得ることができますが、errorListenerのような読み取り可能なメッセージを作成する方法はまだ分かりません[行1:4632 [@ 1289,4632:4632 = '}'、<46>、1:4632 ]:無関係な入力 '}'期待する '、']。 ANTLR4が提供する利用可能な方法はありますか? – lulijun

答えて

2

setErrorHandlerという名前はちょっと混乱しています。それはあなたがそこで設定できるものと一貫していなければなりません。それはエラー戦略を設定するためのものです(これはもちろん、何らかの種類の処理です...)。

エラーリスナーとエラーストラテジの両方は、アプリケーションが解析エラーを処理する手段です。エラーリスナーは、発生したエラーごとに呼び出され、アプリケーションがそれらを収集することを可能にする(例えばGUIで表示する)。あらかじめ生成されたエラーメッセージが表示されるか、渡されたパラメータから独自のエラーメッセージを作成できます。

エラー戦略は、エラーが検出された後も継続する方法を決定するクラスです。デフォルトの状態は、入力ストリームとの同期を試み、解析を続行することです。ただし、パーサーがすぐに停止し、エラーが検出された後に長時間の操作を避けたい場合もあります。このいわゆる救済戦略はANTLR4の別のクラスで、通常SLL解析に使用されます。その使用方法については、one of my projectsを参照してください。

ベールアウトエラー戦略にParseCancellationExceptionが投げられた場合、追加情報なしの例外です。これはエラー処理(アプリケーション/ユーザへの送信という意味ではエラーハンドラがあります)ではなく、通常のパーサ例外ではない例外をスローして、すべてのエラー捕捉をバイパスします実行中の解析実行から可能な限り迅速に抜け出す方法を見つけることができます。あなたは自分のコードでこの例外をキャッチする必要があります。そうしないと、アプリケーションのルートコンテキストにバブルしてしまいます(ターゲット言語によってはアプリケーションが終了する可能性があります)。

+0

ParseCancellationExceptionから特定の診断情報を取得できますか?または、errorHandlerにerrorlistenerのエラーメッセージを送信することは可能ですか?私は、エラーハンドラとerrorListenerを同時に設定すると、errorListenerがうまく動作しないことがあることが判明しましたが、ときどき動作します。いくつかの競合がありますか? – lulijun

+0

まあ、エラー戦略はいつでもパーズ実行を取り消すことができるので(例えば、ベールアウト戦略)、エラーリスナーを介してすべてのエラーが報告されるわけではありません。 'ParseCancellationException'は情報を持たず、私の答えで説明したもの(現在の解析実行を取り消す)だけを1つの目標にしています。 –

+0

RecognitionExceptionには、errorListenerが取得できるすべての情報が含まれています。 RecognitionExceptionはメンバ 'recognizer'を持っていて、それからエラースタックを得ることができ、別のメンバ 'offendingToken'、行(エラー行)とcharPositionInLine(エラー位置)&それ自身(エラーmsg)を得ることができます。しかし、エラーメッセージは '[@ 1,1:12 =' "selectmust" '、<72>、1:1]のようにエラーメッセージを転送する必要があるようですが、わかりやすい形式に変換する必要があります。私の質問にお答えいただきありがとうございます〜 – lulijun

関連する問題