尊敬に値するために、言語がセルフホスティングコンパイラを使用する、または少なくとも持つことを人々が期待することを、多くの場所で聞いたことがあります。
これがなぜなのか、私は興味があります。コンパイラーは、書くのに非常に重要なソフトウェアのようであり、すべての言語がそれらを作成するのに適しているとは思えません。より良い結果が得られるようなものに取り組む努力をするほうが理にかなっているのではないでしょうか。
より良い結果が得られるようなものに取り組む努力をするほうが理にかなっているのではないでしょうか。
どのような?
コンパイラのいいところは、依存関係が少ないことです。これにより、非常に大規模または多様な標準ライブラリがまだない可能性が高い新しい言語の候補として適しています。
さらに良いことには、彼らは様々なものが必要であると同時に、よく研究されています。多様性は、例が言語のさまざまな部分をテストすることを確認するのに役立ちます。よく研究されているということは、他のコンパイラと比較する必要があることを意味します。
また、コンパイラーは膨大な作業のように見えますが、全体としてはかなり小さいものです。言語実装者が以前に新しい言語で行ったことさえできない場合、彼らはどのように斬新なことをするのでしょうか?標準ライブラリやIDEなどの非常に大きなものをどのように処理するのでしょうか。
コンパイルされる言語でコンパイラを使用するという目標は、多くの場合、「 自分のドッグフードを食べる 」の実践の一部です。それは、サポートするモジュールとツールの言語、コンパイラー、およびエコシステムが「真剣な作業に十分」または「本番稼働可能」であると考えることを世界に示しています。
また、言語、コンパイラー、およびランタイム設計に最も近いものに、彼らが行ったすべての決定の影響、および彼らが選択した開発の優先事項(いぼなど)の影響に直接直面することを強いるという好意的な効果もあります。これはしばしば、理論的に言語環境を理解するだけでなく、難しい実際の単語の状態のるつぼで言語/ツールを使用した広範な実務経験を持つコアグループにつながります。
人々が新しい汎用言語を作成する主な理由は、他のすべての言語について少なくとも1つのことを嫌うためです。これが、多くの言語がうまくいかない理由です。プログラミングライフを向上させる言語については素晴らしいアイデアがありますが、少なくとも1つの点で不快な言語で最初の実装を行う必要があります。セルフホスティングとは、その古い煩わしい言語で作業する必要がなくなることを意味します。そのため、言語の作成者はそのステップに向けて取り組み、それを主要なマイルストーンと見なしています。
多くの言語機能は紙の上では良さそうですが、実際のプロジェクトでそれらを使い始めると、それらの制限がわかり始めます。一例として、多くの言語は最初はまともなユニコードをサポートしていません。大規模なプロジェクトを完了すると、このような多くの状況が発生し、対処されていることを確認できます。セルフホスティングコンパイラは、他のどのプロジェクトよりも優れています。そのため、言語の作成者以外の人々はそれを主要なマイルストーンと見なしています。
のみ注目に値するマイルストーンであるという意味ではありません。データベースの統合、グラフィカルインターフェイス、ネットワークなど、コンパイラーが実行しない機能があります。
Steve Yegge 素晴らしいブログ記事を書いた これは、ある程度間接的に、これに対処します。
ビッグポイント#1:コンパイラは、コンピュータサイエンスのほぼすべての側面を網羅しています。コンピュータサイエンスのカリキュラムで学習する他のすべてのことを知る必要があるため、これらは上位レベルのコースです。データ構造、検索と並べ替え、漸近的なパフォーマンス、グラフの色付け?それはすべてそこにあります。
(単なる)コンパイラの教科書として始まったにもかかわらず、Knuthが数十年にわたって彼の記念碑的な(そして終わりのない)「コンピュータプログラミングの芸術」に取り組んできた理由があります。カールセーガンが言ったのと同じように、「Appleパイを最初から作成する場合は、最初に宇宙を発明する必要があります」、コンパイラを作成する場合は、最初に処理する必要がありますコンピュータサイエンスのほぼすべての側面。
つまり、コンパイラーが自己ホスト型である場合、私が何をしていても、必要なことを確実に実行できます。逆に、あなたの言語でしなかったコンパイラーを書くと、誰かが本当に重要な何かを見落とす可能性が高くなります。言語の実装者が考えることを要求するプログラムを書く必要がなかったからです。それらすべての問題について。
大きなポイント#2:30,000フィートから、驚くほど多くの問題がコンパイラのように見えます。
コンパイラはシンボルのストリームを受け取り、いくつかのドメイン固有の事前定義されたルールに従って構造を把握し、それらを別のシンボルストリームに変換します。かなり一般的に聞こえますね。まあ、そうだろう。
Visual C++チームのメンバーであろうとなかろうと、コンパイラーの一部のように見えることを実行する必要があることがよくあります。文字通り毎日やってます。
他のほとんどの職業とは異なり、プログラマーはツールを使用するだけでなく、独自のツールを構築します。 (スキルの不足、または他のツールを構築するための使用可能なツールの不足により)ツールを作成できないプログラマーは、他の誰かが提供するツールに限定されて、いつまでも障害者になります。
言語がシンボルのストリームを取得し、ルールを適用して別のシンボルストリームに変換できるプログラムを「作成するのにあまり適していない」場合、それはかなり制限された言語のように聞こえ、有用な言語ではありません私に。
(幸いなことに、シンボルの変換に適さないプログラミング言語は多くないと思います。Cはおそらく今日使用されている最悪の言語の1つですが、Cコンパイラは通常セルフホスト型であるため、誰も止めません。)
3番目の理由私は、イェッジが言及していない個人的な経験から終わります(彼が「なぜセルフホストなのか」について書いていないためです) :バグを振り払う。コンパイラを作成しているとき、つまりbuildを実行するたびに(run itを実行するたびにだけではなく)、動作するように、そして正しく動作するように依存しますまともなサイズのコードベース(コンパイラ自体)に対して。
今月、私は比較的新しくて有名な非自己ホスト型コンパイラーを使用しており(おそらくどちらかを推測できます)、segfaultingなしで2日間は進むことができません。デザイナーが実際にどれだけ使わなければならなかったのかしら。
言語Xのコンパイラをセルフホスティングにしたい場合は、まずそれを他の言語(Yなど)で実装して、言語Xの入力を受け取り、アセンブリコードまたは中間コードを出力するか、さらにはコンパイラが実行されているマシンのオブジェクトコード。ある時点でYで記述されたコードをXに変換するため、言語Yをできるだけ言語Xに類似するように選択する必要があります。
ただし、コンパイラーを必要以上に言語Yで記述したくないので、まず、言語のサブセットのみを実装して、冗長な構成を排除します。 'C'タイプの言語の場合、whileが、forまたはdo while。 ifが、caseまたは3次演算がない。構造体、共用体、列挙型はありません。残されたものは、言語Xのパーサーと基本的なコードジェネレーターを書くのに十分な言語です。次に、出力を確認します。再び。
これが機能したら、言語Yで記述されたコンパイラソースを言語Xに書き換え、言語Yで記述されたコンパイラを使用して言語Xソースをコンパイルできます。出力は、新しい言語Xで記述された新しいコンパイラになります。言語Xをコンパイルします。つまり、現在はセルフホスティングです。ただし、言語Yの言語のサブセットのみを実装したため、完全ではありません。
そこで、不足している機能を追加して、正しいコードを生成する機能(または機能のグループ)をそれぞれテストします。つまり、機能がコンパイラに実装されたら、新しい機能を使用してテストプログラムを作成し、コンパイルしてテストできますが、まだコンパイラソースでは使用しないでください。新しい機能が確認されたら、コンパイラソース自体でこれらの新しい機能を使用できます。おそらく、言語サブセットで記述された元のコードの一部を置き換えます。新しい機能のバージョンを使用してコンパイラソースを再コンパイルします。
これで、言語に新しい機能を追加するためのメカニズムが用意されました。また、機能のコード生成が正しいことが確認されたら、それらを次世代のコンパイラー自体で使用できます。
60年ほど前に、コンピューターが最初に登場したとき(そして、その後再びマイクロプロセッサーが登場したとき)、最初のコンパイラーの実装に適した他の言語はありませんでした。したがって、最初のコンパイラはアセンブリコードで作成する必要があり、その後、十分な数のコンパイラが実行されると、アセンブリコードは新しい言語で作成されたバージョンに置き換えられます。アセンブラもありませんか?プロセッサ全体が別のレベルに下がり、最初はアセンブラが machine code で記述されていました。
コンパイラを書くためにうまく設計されていないが、他の目的のためにうまく設計されているプログラミング言語を生成することは可能ですか?
SQLのような言語を見て、答えはイエスだと思います。しかし、その性質の言語は汎用ではありません。
誰が言ったの? ...とにかく、それは単なる意見です。同意する人もいれば、同意しない人もいますが、ここには正しいことも悪いこともありません。一部の言語にはコンパイラー自体が記述されていますが、そうでない言語もあります。なんでも。
それでも、言語が「自己コンパイル」できる場合、それはいいことだと思います。概念が実証されているのは...それがちょうどいいことであり、言語がいくつかの複雑なことを行うのに適していることを証明します.
ニースであるにも関わらず、コンパイラが別の言語で記述される理由はさまざまです。たとえば、ほとんどのJavaScriptエンジンはJavaScriptで記述されていません。これには多くの理由があります。他のソフトウェアとの統合、既存のライブラリ/依存関係へのリンク、優れたツール、パフォーマンス、レガシーコード...場合によっては、言語の自己コンパイルは素晴らしいですが、コアコンパイラを別の。しかし、言語自体は理にかなっています。通常、エコシステム全体を再開発する余裕はありません。
ClangはC++で書かれています。 Objective-CでClang Objective-Cコンパイラを書き換えることはそれほど難しくありませんが、それではまったく役に立たないでしょう。 C++コンパイラの変更は、Objective-Cでやり直す必要があり、その逆も同様です。なぜ?
現在、Clang Swiftコンパイラーがあります。そのコンパイラーはSwiftで書き直すことができます。しかし、それはどのような目的でしょうか?言語がその中にコンパイラーを作成するのに十分強力であることを示すために?コンパイラーはSwiftで作成できますdoユーザーがSwiftでユーザー・インターフェースを作成できるかどうか、そして明らかにそうであるかどうかに注意してください。
さまざまな言語をコンパイルするように簡単に適応できる十分にテストされたコンパイラーがある場合、1つの異なる言語で書き換えてコンパイラーでの作業が容易にならない限り、それをさまざまな言語に書き換えることはまったく無意味です。たとえば、SwiftでClangを書くことが理にかなっている場合、Clang C、C++、およびObjective-CコンパイラはallがSwiftで書き込まれます。
いくつかのプログラミング言語でコンパイラーを作成できることを証明することよりも、すべきことの方が重要です。
これは、その言語が複雑な文字列処理を処理し、別の言語に翻訳/それ自体を解釈できることを示しています。
コンパイラ(最初の大きなプロジェクト)を作成する過程で、前面に出てくる問題が発生します。