汎用言語をできるだけ早く(Lexで)解析しているときにエラーをキャッチする必要がありますか、それともより便利な場所で(Yaccで)より多くの情報を提供する必要がありますか?さまざまな言語がこの問題をどのように解決しますか?
2 に答える
一般に、エラーが複雑になるほど、エラーをアサートするためのコードは複雑になります。レクサーとパーサーは(実際には)かなり単純であるため、単純なエラーをキャッチします。
- レクサーは、トークンを構成するはずの無効な文字シーケンスをキャッチします
- Bison / Yaccなどの構文解析ツールは、構文とステートメントを構成するトークンの無効なシーケンスをキャッチします。
複雑なエラーは通常、実行時に他の場所で、またはコンパイル時にさまざまな変換で発生します。例としては、存在しない関数/メソッドの参照が含まれる場合があります。クロージャスコープ/バインディング、オブジェクトと参照識別子、引数の有効性、オーバーロード、およびその他の言語に依存するもののトン。
その非常に狭いトークン/構文範囲外のものはすべて、AST分析または中間コード生成のツールの外にあります(または処理する必要があります)。
検討:
a.b();
ab();
両方とも、両方のステートメントが有効なオブジェクト指向言語のレクサー/パーサーを通過する必要があります。エラーはありますか?
言語がかなり静的であり、識別子がコンパイル時に解決できる場合、 コンパイラはコンパイル時にこれをアサートする可能性があります。
両方のステートメントをID解決コードに置き換えて、実行時に実行し、コンパイラエラーではなく実行時エラーを生成することができます。
実行時とコンパイル時の解決とセマンティクスの違いは微妙で、言語ごとに大きく異なる可能性があります。
エラーは通常、エラーであることがわかっていて、最も多くの情報を持っている場合にキャッチされます。これは言語と実装によって異なります。
エラー処理は、字句解析と構文解析の両方で実行する必要があります。無効な文字などのトークンエラーは、スキャナー自体ができるだけ早くキャッチする必要があります。ただし、構文エラーなどのエラーはスキャナーでキャッチできないため、パーサーで処理されます。