2

そこで、ANTLR を使用して Java でコンパイラを作成していますが、コンパイラがエラーをどのように処理するかについて少し戸惑っています。

デフォルトの動作は、エラー メッセージを出力してから、トークンの挿入などによって、エラーから回復して解析を続行しようとするようです。原則としてこれが好きです。これは、(最良の場合) ユーザーが複数の構文エラーを犯した場合、エラーごとに 1 つのメッセージを受け取ることを意味しますが、次のエラーを検出するために再コンパイルを強制するのではなく、すべてのエラーについて言及します。私の目的には、デフォルトのエラーメッセージで問題ありません。すべてのトークンの読み取りが完了すると、問題が発生します。

もちろん、ANTLR のツリー コンストラクターを使用して抽象構文ツリーを構築しています。ユーザーがすべてのエラーを確認できるように、構文エラーが発生しても解析を続行するのは良いことですが、解析が完了したら、例外を取得するか、入力が構文的に有効でないことを示す何らかの兆候を取得したいと考えています。そうすれば、コンパイルを停止して、ユーザーに「申し訳ありませんが、構文エラーを修正してから再試行してください」と伝えることができます。私が望んでいないのは、ユーザーが言おうとしていたと思われる内容に基づいて不完全な AST を吐き出し、何か問題が発生したことを示すことなくコンパイルの次のフェーズに進むことです (エラーメッセージ以外)。コンソールに表示され、表示されません)。しかし、デフォルトでは、まさにそれを行います。

The Definitive ANTLR Referencemismatchは、構文エラーが検出されるとすぐに解析を停止する手法を提供します: メソッドとメソッドをオーバーライドしてsrecoverFromMismatchedSetをスローし、同じことを行うアクションをRecognitionException追加します。@rulecatchこれは解析エラーから回復する利点を失っているように見えますが、もっと重要なのは、部分的にしか機能しないことです。必要なトークンが欠落している場合 (たとえば、二項演算子の一方の側にしか式がない場合)、期待どおりに例外がスローされますが、余分なトークンが追加された場合、ANTLR はそこに属すると思われるトークンを挿入します。コンソール メッセージを除いて、構文エラーを示さない AST を生成し、陽気な方法で続行します。(さらに悪いことに、挿入されたトークンはEOFであったため、ファイルの残りの部分は解析されませんでした。)

たとえば、フィールドのようなものをパーサーに追加し、メソッドをオーバーライドしてアクションを追加することで、これを修正できると確信しています。これにより、isValid解析の最後にエラーが発生した場合に例外がスローされます。しかし、より良い方法はありますか?私がやろうとしていることは、ANTLR ユーザーの間では珍しいことだとは想像できません。

4

1 に答える 1

2

...[O]解析が完了したら、例外または入力が構文的に有効でないことを示す何らかの兆候を取得したいと考えています。そうすれば、コンパイルを停止できます...

構文解析後にレクサーとパーサーの両方を呼び出しgetNumberOfSyntaxErrorsて、ANTLR によって密かに対処されたエラーがあったかどうかを判断できます。明らかに、これらのエラーが何であるかはわかりませんが、これらのメソッドは、質問の「解析が完了したら...コンパイルを停止する」部分に対処していると思います。

Definitive ANTLR Reference は、構文エラーが検出されるとすぐに解析を停止する手法を提供します。不一致メソッドとrecoverFromMismatchedSet メソッドをオーバーライドして RecognitionExceptions をスローし、@rulecatch アクションを追加して同じことを行います。

使用しているANTLRのバージョンについては言及していないと思いますが、メソッドのANTLR v3.4コードのドキュメントには、recoverFromMismatchedSet「現在使用されていない」と書かれており、Eclipseの「グローバル使用」スキャンでは呼び出し元が見つかりませんでした。あなたの主な問題にはここにもそこにもありませんが、記録のために言及したかったのです。お使いのバージョンでオーバーライドするのが正しい方法かもしれません。

必要なトークンが欠落している場合...、[オーバーライドされたコード]は予想どおり例外をスローしますが、無関係なトークンが追加された場合、ANTLRはそこに属していると思われるトークンを挿入し、楽しい方法で続行します...

メソッドとrecoverFromMismatchedTokenメソッドに委譲することにより、回復可能な欠落トークンと無関係なトークンをテストします。挿入または削除によって問題が解決すると適切なメソッドが判断した場合は、適切な修正を行います。トークンの不一致の問題を解決する操作がないと判断された場合は、.mismatchIsMissingTokenmismatchIsUnwantedTokenrecoverFromMismatchedTokenrecoverFromMismatchedTokenMismatchedTokenException

回復操作が行わreportErrorれると、 が呼び出さdisplayRecognitionErrorれ、詳細が呼び出されます。

これは、ANTLR v3.4 およびおそらくそれ以前のバージョンに適用されます。

これにより、少なくとも 2 つのオプションが提供されます。

  • recoverFromMismatchedToken細かいレベルでエラーをオーバーライドして処理します。ここから、呼び出しをスーパー実装に委譲したり、独自の回復コードを展開したり、例外で救済したりできます。いずれの場合でも、コードが呼び出されるため、不一致エラーが発生したこと、回復可能であろうとなかろうと認識されます。このオプションはおそらくオーバーライドと同等recoverFromMismatchedSetです。

  • displayRecognitionError大まかなレベルでエラーをオーバーライドして処理します。メソッドreportErrorはいくつかの状態ジャグリングを行うため、オーバーライドする実装がスーパー実装を呼び出さない限り、メソッドをオーバーライドすることはお勧めしません。MethoddisplayRecognitionErrorは、recovered-token 呼び出しチェーンの最後の呼び出しの 1 つと思われるため、続行するかどうかを判断するのに妥当な場所です。そのための合理的な場所であることを示す名前を付けたいと思いますが、まあ。これは、このオプションを示す回答です。

displayRecognitionErrorエラーメッセージテキストを十分に簡単に提供し、トークン回復操作と必要な状態ジャグリングの後にのみ呼び出されることがわかっているため、オーバーライドに部分的です-パーサーが自分で回復する方法を理解する必要はありません。これと相まってgetNumberOfSyntaxErrors、ANTLR の関連バージョンを使用していて、問題を完全に理解していると仮定すると、探しているオプションが得られるように見えます。

于 2012-12-15T07:54:11.123 に答える