web-dev-qa-db-ja.com

コンパイラはエラーと警告をどのように報告する必要がありますか?

近い将来コンパイラを作成する予定はありません。それでも、私はコンパイラー・テクノロジーに非常に興味があり、どのようにしてこれを改善できるかを考えています。

コンパイルされた言語から始めると、ほとんどのコンパイラには2つのエラーレベルがあります。1つ目は警告とエラーで、最初はほとんどの場合修正する必要がある致命的でないもので、もう1つはほとんどの場合マシン(またはバイト)を生成できないことを示すエラーです。入力からのコード。

しかし、これはかなり弱い定義です。 Javaのような一部の言語では、@SuppressWarningディレクティブを使用せずに特定の警告を取り除くことは不可能です。また、Javaは、致命的でない特定の問題をエラーとして扱います(たとえば、Javaの到達不能コードは、知りたい理由でエラーをトリガーします)。 。

C#にも同じ問題はありませんが、いくつか問題があります。コンパイルは複数のパスで発生するようで、パスが失敗すると、以降のパスが実行されなくなります。そのため、ビルドが失敗したときに取得するエラー数は、多くの場合、かなり過小評価されています。 1回の実行で2つのエラーがあると言うかもしれませんが、一度修正すると、26個の新しいエラーが発生する可能性があります。

CとC++を掘り下げると、JavaとC#のコンパイル診断の弱点に悪い組み合わせが示されます(JavaとC#がちょうど行ったと言う方が正確かもしれませんが)いくつかの警告は実際にはエラーになるはずです(たとえば、すべてのコードパスが値を返すわけではない場合)であり、それでも警告です。なぜなら、彼らが標準を書いた当時、コンパイラテクノロジーはこれらの種類のチェックを必須にするのに十分ではありません。同様に、コンパイラーは多くの場合、標準が言うよりも多くをチェックしますが、追加の調査結果には「標準」の警告エラーレベルを使用します。多くの場合、コンパイラーはレポートしません彼らがすぐに見つけることができるすべてのエラー;それらすべてを取り除くためにいくつかのコンパイルが必要かもしれません。不可解なエラーは言うまでもありませんC++コンパイラーは唾を吐きたいので、単一のミスが何十ものエラーメッセージを引き起こす可能性があります。

多くのビルドシステムは、コンパイラが警告を発したときにエラーを報告するように構成可能であることを追加すると、奇妙な組み合わせが発生します。すべての警告に値するわけではありませんが、警告の存在に言及せずに明示的に抑制される警告もあります。そして時にはすべての警告がエラーになります。

コンパイルされていない言語は、まだらくたのエラー報告のシェアを持っています。 Python=のタイプミスは、コードが実際に実行されるまで報告されません。また、スクリプトがエラーに遭遇すると実行が停止するため、一度に複数のエラーをキックすることはできません。

PHPの側には、多かれ少なかれ重要なエラーレベルがたくさんありますand例外。解析エラーは1つずつ報告されます。警告は非常に悪いため、スクリプトを中止する必要があります(ただし、デフォルトではそうではありません)。通知には、重大なロジックの問題が頻繁に表示されます。そう、そしてPHPでいつものように、そこには本当に奇妙なことがいくつかあります(どうして致命的ではない致命的なエラーのエラーレベルが必要なのですか?E_RECOVERABLE_E_ERROR、私はあなたと話しています)。

私が考えることができるコンパイラエラー報告のすべての実装が壊れているように私には思えます。すべての優れたプログラマーがエラーを正しく処理することの重要性を主張しているにもかかわらず、独自のツールでそれを行うことができないため、これは本当の恥です。

コンパイラエラーを報告する正しい方法は何だと思いますか?

11
zneak

あなたの質問は、実際にはhowに関するものではないようです。コンパイラエラーを報告します。むしろ、問題の分類とそれに対する対処法についてです。

とりあえず、警告/エラーの二分法が正しいと仮定することから始める場合、その上にどれだけうまく構築できるか見てみましょう。いくつかのアイデア:

  1. 警告のさまざまな「レベル」。多くのコンパイラはこれを実装しています(たとえば、GCCには警告する内容を正確に設定するためのスイッチがたくさんあります)。ただし、たとえば、報告された警告の重大​​度を報告したり、「警告」を設定したりする機能が必要です指定された重大度を超える警告のみのエラーです。

  2. エラーと警告の正しい分類。エラーが報告されるのは、コードが仕様を満たしていないため、コンパイルできない場合のみです。到達不能なステートメントはおそらくコーディングエラーですが、エラーではなくwarningである必要があります。コードはまだ「有効」であり、到達不能なコードでコンパイルする正当なインスタンスがあります(クイックたとえば、デバッグのための変更)。

今、私はあなたに同意しません:

  1. すべての問題を報告するために余分な努力をします。エラーがあると、ビルドが失敗します。ビルドが壊れています。エラーが修正されるまで、ビルドは機能しません。したがって、コードで「間違った」他のすべてを試みて特定するために、「続行」するよりも、そのエラーをすぐに報告する方が良いです。特に、それらの多くがおそらくいずれにしても初期エラーによって引き起こされている場合はなおさらです。

  2. エラーであるべき警告の具体的な例。はい、それはおそらくプログラマの間違いです。いいえ、ビルドが壊れることはありません。関数への入力が常に値を返すようなものであることがわかっている場合は、ビルドを実行して、追加のチェックを追加しなくてもテストを実行できるはずです。はい、警告です。そして、それはひどい重大度のものです。しかし、warnings-are-errorsでコンパイルしない限り、それ自体でビルドを壊すべきではありません。

考え?

6
Anon.

あなたが提起した1つの問題は、エラーの不完全な報告でした。たとえば、2つのエラーを報告し、それらを修正すると、さらに多くのエラーが発生します。

これは、(大部分)コンパイラライターの妥協点です。発生したエラーによっては、コンパイラーがあなたの誤解を始めがちであるdoは、現実とはほとんど関係のないエラーを報告し始めるほどにひどいものです。たとえば、itn x;ではなくint x;のような単純なタイプミスがあるとします。 itnが何かを意味するような他のことを行っていない限り、これはエラーとして報告されます。それはそれで十分ですが、次に何が起こるかを考えます-コンパイラは変数としてsexを試みる多くのコードを調べます。それはA)停止して修正するか、またはB)error: "x": undeclared identifierまたはそのオーダーに関する何かについて2000エラーを発生させる必要がありますか?別の可能性を検討してください:

int main()[

これはかなり明白なタイプミスの1つです。明らかに{ではなく[である必要があります。コンパイラはその部分を簡単に教えてくれますが、x=1;のようなものに対してerror: statement only allowed inside a functionのようなことを言ってエラーを報告しますか?

これらはかなり些細な問題であることに注意してください-さらに悪い問題は簡単に見つけることができます(特に、私たちの多くが知っているように、C++テンプレートに入ると)。要するに、コンパイラの作成者は通常、誤ったエラーの報告(つまり、問題はないものの、エラーとして報告する)と実際のエラーの報告との間で妥協しようとすることに悩まされています。ほとんどの場合、どちらの方向にも極端に失敗しないようにするための経験則がありますが、それらのどれも完全に近いものはほとんどありません。

あなたが言及したもう1つの問題は、Java and @SupressWarningです。これは上記とはかなり異なります。修正するのはかなり簡単です。修正されない唯一の理由は、そうすることです。 Java-の基本的な「文字」に適合しません。つまり、「バグではなく、機能です」という意見ですが、通常は冗談ですが、この場合は関係する人々は非常に誤解されているので、彼らは本当にそれが真実であると信じています。

CおよびC++で、値を返さないコードパスを使用して言及した問題は、プリミティブコンパイラを許可するためのものではありません。それは何十年もの既存のcodeを可能にするためのものです。それは古くて醜​​いですが、それは機能し、そしてそれが機能し続けること以外には何も望んでいません。良くも悪くも、言語委員会はその下位互換性を維持することにかなりこだわっているので、彼らはnobodyが本当に好きなものを許可し続けます-しかし、一部の人々(少なくとも彼らはそう思う)が必要です。

7
Jerry Coffin