自分で構文エラーを修正しようとするコンパイラはありますか?[閉まっている]


15

しばらく前に、コンテキストを分析して意図を推測することで構文エラーを修正しようとするコンパイラーがあったことを聞きました。

そのようなコンパイラは本当に存在しますか?明らかに実用的な価値はほとんどありませんが、遊んだり、学んだりすることは非常に興味深いでしょう。


3
IntelliSenseはこのカテゴリに分類されますか?多くのコンパイラには、[セミコロン]に類似したエラーがあります。
ロバートハーベイ

1
@ロバート:いいえ、しかしそれは良い点です。
ネイサンオスマン

1
私の友人は、Cプリプロセッサでかなりのハッキングを行いました。たとえば、「inlcude-> include」や、オープン条件が閉じられるべき場所を見つけようとする作業です。それは彼の修士論文であり、彼はすぐに簡単なものを捨てました。それでも、非常に興味深い質問です!
ティムポスト

3
AC#コンパイラは非常に有用なエラーメッセージで失敗します。それは、すべてのエラーコードについてオンラインで入手できる優れたドキュメントと組み合わされ、かなりうまく機能します。HTMLインタープリター(ブラウザーなど)は、とにかく頻繁にそれを行いますが、構文を自動修正することは悪い考えです。
ジョブ

1
参照しているコンパイラは、元のPL / Iでした。プログラマーが書いたものは何かを意味しているに違いないと推測し、それが何であるかを推測しようとしました。私の経験では、非常にひどく推測しました!
david.pfx 14年

回答:


28

ある意味では、コンパイルの行為をされ、特定の構文が行うことを意図しているものを推測し、コンパイラはそれを把握することができないときに、したがって、構文エラーがあります。より多くの「推測」を追加して、コンパイラにさらに物事を推測させ、構文をより柔軟にすることができますが、特定のルールセットによって推測する必要があります。そして、それらのルールは言語の一部となり、エラーではなくなりました。

だから、いいえ、そのようなコンパイラはありません、本当に、質問が意味をなさないので。いくつかのルールに従って構文エラーが何を意味するかを推測することは、単に構文の一部になります。

その意味で、これを行うコンパイラーの良い例があります:任意のCコンパイラー。多くの場合、彼らはあるべきではない何かの警告を出力し、それからあなたがXを意味すると仮定して、続けます。これは実際には不明瞭なコードの「推測」であり(ほとんどの場合それ自体は構文ではありませんが)、エラーでコンパイルを停止し、エラーと見なすこともできます。


4
これは正しい答えです。コンパイラがエラーから回復できれば、実際にはエラーではなくなります。Perlは、この "Do What Me Mean"の振る舞いで(で?)有名で、プログラマが曖昧なソースを与えられた場合に最も意味するものを選択します。
ジョンパーディ

Perlは、ソースコードサイズの冗長性を犠牲にします。
ネイサンオスマン

@ジョージ・エジソン:それはトートロジーか矛盾です。
ジョンパーディ

または深い洞察。:)
レナート・レゲブロ

23

本当に危険ですね。コンパイラーが意図を推測しようと試み、間違っていると推測し、コードを修正した後、ユーザーに通知しない(または、皆さんと同じように無視するという警告を表示する)場合、コードを実行しようとしています深刻なダメージを与えます。

このようなコンパイラは、おそらく非常に意図的に作成されていないものです。


5
そんなこと知ってる。このようなコンパイラーはコンパイルには使用できませんが、この概念は非常に興味深いものであり、学習の可能性があります。
ネイサンオスマン

2
ほとんどすべての最新のIDEは構文の提案を提供し、それは本当に役立ちます。一部の残りのためnganjuに同意
Jigarジョシ

私はそのようなコンパイラを使用しません。それは「黒魔術」という見出しの下にあります。
マイケルK

うーん、このスケールでScalaの型推論をどこで評価しますか?試してみると、簡潔なコードへの大きな貢献だと言えます。一方で、リストを扱っていると思っていたが実際にはまだセットを扱っていたために、時々足を踏み入れました。
ティムデイ

OMPにはオートスコープのようなものがあるので、少しだけ実行可能です。もちろん、私が作業しているコードは、私たちが信用していないために自動スコープをオフにしています。「XXXを意味しましたか?」と尋ねる対話型コンパイラがあることを確認できました。それは私が行くことをいとわない限りです。そして、それでもおそらく危険すぎる。
オメガケンタウリ

12

最近のプログラミング言語のIDEには通常、なんらかの方法でバックグラウンドで実行されているコンパイラがあり、構文の色分け、IntelliSense、エラーなどの分析サービスを提供できます。明らかに、そのようなコンパイラーは、深く壊れたコードを理解できる必要があります。ほとんどの場合、編集時にコードは正しくありません。しかし、それを理解する必要があります。

ただし、通常、エラー回復機能は編集中にのみ使用されます。「メインライン」シナリオで実際のコンパイルを許可することはあまり意味がありません。

興味深いことに、この機能をJScript.NETコンパイラに組み込みました。基本的に、IDEがエラーから回復した場合、エラーが発生してもコンパイラを続行できるモードにコンパイラを配置することができます。あなたは入力できVisual Basicのもう一方の端を出て、内のコードをそれにJScript.NETコンパイラを実行し、作業プログラムの合理的なチャンスがあります!

これは面白いデモですが、多くの理由で「メインライン」シナリオにはあまり良い機能ではないことがわかりました。完全な説明は非常に長くなります。簡単な説明は、予期せ偶然に動作するプログラムを作成し、複数のコンパイラーまたは同じコンパイラーの複数のバージョンで同じコードを実行するのを難しくするということです。この機能が追加する大きな費用は、小さな利点では正当化されません。

過去にこの機能をPMしたPeter Torrが、2003年のこのブログ投稿でこの機能について簡単説明しています。

JScript .NETエンジンのAPIをホストしているスクリプトを介してこの機能を公開していますが、これを使用した実際の顧客は知りません。


私は私の雇用主にそのような実験のリソースがあればいいのにと思います。追加する機能や修正するバグが非常に多いため、夜間にユニットテストを実行することさえしません。(
Job

1
これは私が望んでいた種類の答えです...前に述べたように-明らかにそのような機能はほとんど実用的ではありませんが、他のものに適用できるテクニックを学ぶための素晴らしい方法を提供します。(言語解析など)
ネイサンオスマン

1
@ジョブ:一般的な知恵は、ユニットテストを定期的に実行しないと、修正すべきバグがさらに多くなるということです。
エリックリッパー

ここで泣き言を言うのではなく、自分の仕事について何をする必要があるかをすでに知っています。一部のソフトウェア会社では、トップの人々はプロトタイプと完成品の違いを本当に理解していません。結局のところ、多くの場合、ピクセル単位で大きな違いはありません。プロトタイプから始めないのは賢明ではないので、時間は無駄になりません。しかし、恐ろしい反応は「よさそうだ。これを本番環境に移行するのに何日かかるか」。それらは、インフラストラクチャやリファクタリングに時間をかける必要があるとエンジニアが言った場合に疑わしい人と同じです。Spolskyでさえ嫌いだと聞いています。
ジョブ

10

私の頭に浮かぶ最初のものはJavascriptのです 自動セミコロン挿入です。恐ろしく、恐ろしい機能であり、決して言語に組み込まれるべきではありませんでした。

それは、より良い仕事をすることができなかったということではありません。次の行を先読みすると、プログラマーの意図をよりよく推測できる可能性がありますが、結局のところ、構文無効になる可能性のある有効な方法が複数ある場合、実際には代替手段はありませんプログラマーが明示的であること。


1
JavaScriptのセミコロン挿入機能に完全に役に立たないことに心から同意します。
ネイサンオスマン

7

コンパイラーが誤った構文を修正できる場合、その構文は言語で文書化されるべきだと思います。

構文エラーの理由は、パーサーがプログラムから抽象構文ツリーを作成できなかったためです。これは、トークンが適切でない場合に発生します。そのトークンがどこにあるか、それを削除する必要があるか、またはエラーを修正するために他のトークンを追加する必要がある場合、プログラマーの意図を推測できる何らかのコンピューターが必要になります。マシンはどのように推測できますか:

int x = 5 6;

はずだった:

int x = 5 + 6;

これは、同じように簡単に次のいずれかが考えられます565 - 65 & 6。コンパイラが知る方法はありません。

その技術はまだ存在しません。


1
そのような技術は存在できません。心の読み取りは許可されていません。すべての指示は明確にコードからのものでなければなりません。
ジョブ

本当ですが、私が本当に意味したのは、「コンテキストに基づいて推測を行うことによって無効な構文を修正しようとするコンパイラはありますか」です。コンパイラが無効な構文を修正しても、構文は有効になりません。また、このようなツールはコード開発には役に立たないことも理解しています。
ネイサンオスマン

6

まったく同じことではありませんが、これがHTMLが災害に変わった理由です。ブラウザは悪いマークアップを許容し、次に知っていること、ブラウザAはブラウザBと同じようにレンダリングできませんでした(はい、他の理由がありますが、これは10年前のいくつかのルーズネスルールが慣習になる前のトップ数の1つでした) )。

Eric Lippertが推測するように、これらの多くはコンパイラではなくIDEで処理するのが最適です。それは、自動ビットがあなたのために台無しにしようとしているものを見ることができます。

私が現在支配していると思う戦略は、コンパイラを緩めるのではなく、継続的な言語の改良です。それが本当にコンパイラが自動的に理解できるものである場合、その周りに明確に定義された言語構造を導入します。

頭に浮かぶ直接的な例は、C#の自動プロパティです(類似したものがある唯一の言語ではありません):アプリのゲッター/セッターの大部分は実際にはフィールドの単なるラッパーであるため、開発者が意図し、コンパイラに残りを注入させます。

それから私は考えさせられます:ほとんどのCスタイル言語はすでにある程度これをしています。自動的に把握できるものについては、構文を改良してください。

 if (true == x)
 {
    dothis();
 }
 else
 {
    dothat();
 }

に減らすことができます:

if (true == x)
    dothis();
else
    dothat();

結局、私はこれに帰着すると思います:傾向は、コンパイラを「スマート」または「ルーサー」にしないことです。それは、よりスマートまたはルーズに作られた言語です。

さらに、古典的な「if」バグのように、「ヘルプ」が多すぎると危険な場合があります。

if (true == x)
    if (true == y)
       dothis();
else
    dothat();

XHTMLは、HTMLの貧弱な仕様が作成した混乱の解決策を提供したことに注意してください。
ネイサンオスマン

2
if (x && y) dothis(); else dothat();少し良くなります。
ジョブ

1
猫は誰かがtrueまたはに対して比較するたびに死ぬfalse
JensG 14

2

DECとIBMのミニコンピューターとメインフレームシステムで80年代後半と90年代前半にFORTRANとPL / Iをコーディングしていたとき、コンパイラーは定期的に「なんとかエラー。 。 "。当時、これは実行前にコードを送信してから結果を取得するまでに非常に長い間待機していたバッチ処理とパンチカードの(以前よりもずっと前の)日々の遺産でした。そのため、コンパイラーは、最初に遭遇したミスで中止するのではなく、プログラマーを推測し、続行しようとするのは非常に理にかなっています。心に留めておいて、私は「修正」が特に洗練されていることを覚えていません。最終的にインタラクティブなUnixワークステーション(Sun、SGIなど)に移動したとき、


2
これらのコンパイラーは続行しますが、さらにエラーを見つけようとする目的でのみ継続するため、再送信する前に(潜在的に)いくつかの問題を修正できます。最近のPCは十分に高速であるため、「対話型」コンパイラーが最初の構文エラーで停止してエディターにドロップすることは完全に実行可能です。(実際、1980年代初期の最初のTurbo Pascalは、まさにそのように機能しました。それは良かったです。)
ジョンR.ストローム

1
はい、IBM PL / I最適化コンパイラーが欠落しているBEGINおよびENDステートメントを時々提供することを覚えていますが、ISTRは欠落しているセミコロンも提供します。
TMN

1

コンパイラの目標は、希望どおりに動作する実行可能ファイルを生成することです。プログラマーが無効なものを書いた場合、たとえコンパイラーが90%の確率で意図を推測できたとしても、コンパイラーが先に進んで実行可能ファイルを生成するよりも、プログラマーにプログラムを修正して意図を明確にするよう要求する方が一般的には良いでしょうバグを隠す可能性が非常に高くなります。

もちろん、言語は一般に、意図を明確に表現するコードが合法になるように設計されるべきであり、意図を明確に表現しないコードは禁止されるべきですが、そうではありません。次のコードを検討してください[JavaまたはC#]

const double oneTenth = 0.1;
const float  oneTenthF = 0.1f;
...
float f1 = oneTenth;
double d1 = oneTenthF;

f1プログラマがf1含めることができる論理的なものは1つ(float1/10に最も近い値)しかないため、コンパイラに割り当ての暗黙的な型キャストを追加すると便利です。ただし、コンパイラが不適切なプログラムを受け入れるようにするのではなく、特定のコンテキストで暗黙的にdoubleからfloatへの変換を許可する方が仕様のほうが優れています。反対に、割り当てd1はプログラマが本当に意図したものである場合とそうでない場合がありますが、それを禁止する言語規則はありません。

最悪の種類の言語規則は、そうでなければ合法的にコンパイルできなかった場合にコンパイラが推論を行うが、推論が意図されていた場合にプログラムが「偶然に」有効になる可能性がある規則です。暗黙のステートメントの終わりを含む多くの状況は、このカテゴリーに分類されます。2つの別個のステートメントを作成しようとするプログラマーがステートメントターミネーターを省略した場合、コンパイラーは通常ステートメントの境界を推測できますが、1つのステートメントを2つとして処理されるはずの何かと見なすことがあります。


0

構文エラーは特に修正が困難です。権利がない場合)を考えてみましょう。コードを挿入することでコードを修復できますが、通常、コードを挿入して構文的に正しいプログラムを取得できる場所がたくさんあります。

はるかに簡単なポイントは、スペルミスの識別子です(ただし、これは構文エラーではないことに注意してください)。解決できない識別子とスコープ内のすべての識別子の間の編集距離を計算し、解決できない単語をユーザーが最も意味する可能性の高いものに置き換えることにより、多くの場合、正しいプログラムを見つけ出すことができます。ただし、エラーにフラグを付けて、有効な置換をIDEに提案させる方が良いことがわかります。


-1

このようなコンパイラは、単純に、コンパイルする言語のリラックスした非標準の実装になります。


-2

これは複数回試行されましたが、多くの場合、目的の効果が得られませんでした。HAL9000またはGlaDOSを考えてください。


-3

Cでは、配列を値で渡すことはできませんが、コンパイラーでは次のように記述できます。

void foo(int array[10]);

その後、次のように静かに書き換えられます。

void foo(int* array);

それはどれほど愚かですか?この特別な規則により、多くのプログラマーが配列とポインターは基本的に同じものであると信じるようになったため、ここではサイレントリライトではなくハードエラーを好むでしょう。ではない。

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.