私はいくつかの論文、記事、およびコンパイラー:原則、手法、およびツール(第2版)(別名「ドラゴン・ブック」)のセクション4.1.4、第4章を読み、すべて構文コンパイラーのエラー回復のトピックについて説明しています。ただし、いくつかの最新のコンパイラーで実験した後、構文エラーだけでなく、セマンティックエラーからも回復することがわかりました。
構文的に関連するエラーから回復するコンパイラーの背後にあるアルゴリズムと手法はかなりよく理解していますが、コンパイラーがセマンティックエラーから回復する方法を正確には理解していません。
現在、ビジターパターンのわずかなバリエーションを使用して、抽象構文ツリーからコードを生成しています。コンパイラが次の式をコンパイルすることを検討してください。
1 / (2 * (3 + "4"))
コンパイラーは、次の抽象構文ツリーを生成します。
op(/)
|
-------
/ \
int(1) op(*)
|
-------
/ \
int(2) op(+)
|
-------
/ \
int(3) str(4)
コード生成フェーズでは、ビジターパターンを使用して、抽象構文ツリーを再帰的に走査し、型チェックを実行します。コンパイラが式の最も内側の部分に到達するまで、抽象構文ツリーをたどります。(3 + "4")
。次に、コンパイラーは式の両側をチェックし、それらが意味的に同等ではないことを確認します。コンパイラは型エラーを発生させます。ここに問題があります。今コンパイラは何をすべきですか?
コンパイラは、このエラーから回復し、式の外側の部分を型チェックを継続するためには、返却しなければならないいくつかのタイプ(int
またはstr
に、表現の最も内側の部分を評価するから)を、次式の最も内側の部分。ただし、単に返すタイプがありません。型エラーが発生したため、型は推定されませんでした。
私が仮定した1つの可能な解決策は、型エラーが発生した場合、エラーが発生し、型エラーが発生したことを示す特別な値が以前の抽象構文ツリートラバーサル呼び出しに返されることです。以前のトラバーサル呼び出しでこの値が検出された場合、抽象構文ツリーのより深いところで型エラーが発生したことがわかっているため、型を推測することは避けてください。この方法は機能するように見えますが、非常に非効率的です。式の最も内側の部分が抽象構文ツリーの奥にある場合、コンパイラーは多くの再帰呼び出しを行って、実際の作業が実行できないことを認識し、それぞれから単に戻る必要があります。
上記の方法を使用していますか(疑わしい)。もしそうなら、それは効率的ではありませんか?そうでない場合、コンパイラがセマンティックエラーから回復するときに使用される方法は正確には何ですか?