最初のコンパイラはGrace Hopperによって1952年に作成され、LISPインタプリタは1958年にJohn McCarthyの学生であるSteve Russellによって作成されました。コンパイラーの作成は、インタープリターよりもはるかに難しい問題のようです。もしそうなら、なぜ最初のコンパイラが最初のインタプリタの6年前に書かれたのですか?
コンパイラーの作成は、インタープリターよりもはるかに難しい問題のようです。
今日はそうかもしれませんが、約60年前はそうではなかったと私は主張します。いくつかの理由:
基本的なポイントは、1950年代のコンピューティングハードウェア環境は、当時のコンピューターのバッチ指向の処理を考えるとコンパイラーのみが実行可能であったようにしたことです。
当時、より優れたユーザーインターフェイスは主にパンチカードと テレタイププリンター に限定されていました。 1961年に SAGEシステム がコンピューターで最初の Cathode-Ray Tube(CRT)ディスプレイ になりました。そのため、インタプリタのインタラクティブな性質は、ずっと後になってからは望ましくも自然でもありませんでした。
1950年代の多くのコンピュータは、フロントパネルスイッチを使用して命令をロードし、出力は単にランプ/ LEDの列であり、愛好家は1970年代までフロントパネルスイッチとLEDを使用していました。多分あなたは悪名高い Altair 88 に精通しているでしょう。
その他のハードウェア制限により、インタプリタも実行不可能になりました。 1950年代のコンピューターでは、プライマリメモリ(RAMなど)の利用が極端に制限されていました。 (1958年まで登場しなかった)半導体集積回路以前は、メモリは 磁気コアメモリ または 遅延ラインメモリ に制限されていましたビットまたはワード、接頭辞なし。セカンダリストレージメモリ(ディスクやテープなど)の低速性と組み合わせると、インタープリターが使用するメモリの大部分をインタープリターに使用することが不可能ではないにしても、解釈されるプログラムがロードされる前であっても、無駄になると考えられます。
IBMのJohn Backusが率いるチームが1954年から57年にかけてFORTRANコンパイラを作成したとき、メモリの制限は依然として大きな要因でした。この革新的なコンパイラは 最適化コンパイラ であるという理由だけで成功しました。
1950年代のほとんどのコンピュータには、anyオペレーティングシステムがほとんどありませんでした。ダイナミックリンクや仮想メモリ管理などの最新の機能はもちろん、インタプリタのアイデアも当時は過激すぎて非現実的でした。
補遺
1950年代の言語は原始的でした。それらには、small少数の操作のみが含まれ、多くの場合、基盤となるハードウェアの命令またはそれらの対象となる使用の問題定義の影響を受けました。
当時、コンピュータは、今日私たちが考えるコンピュータの意味では、めったに汎用コンピュータではありませんでした。再構築せずに再プログラム可能であることは革命的な概念と考えられていました-以前は人々が計算するために電気機械マシン(通常は電卓)を使用するか、答えを計算していました(アプリケーションの大部分1950年代は本質的に数値でした)。
コンピュータサイエンスの観点から見ると、コンパイラとインタプリタはどちらもtranslatorsであり、実装する複雑さはほぼ同じです。
最初のプログラミング言語は非常に単純で(たとえば、再帰なし)、それ自体が単純なマシンアーキテクチャに近いものでした。 変換は単純なプロセスでした。
コンパイラーは、プログラムとして実行するためのデータとソースコードを解釈するためのテーブルの両方を保持する必要があるインタープリターよりも、プログラムとして単純です。そして、インタプリタは、それ自体のために、プログラムのソースコードとシンボリックテーブルのためにより多くのスペースを必要とします。
メモリが非常に少ないため(コストとアーキテクチャ上の理由から)、コンパイラはオペレーティングシステムを上書きするスタンドアロンプログラムになる可能性があります(私はこれらの1つを使用しました)。コンパイルされたプログラムを実行するには、コンパイル後にOSをリロードする必要がありました。 ...実際の作業のためにインタプリタを実行することは単にオプションではなかったことを明確にします。
確かに、コンパイラーに要求される単純さは、コンパイラーがあまり良くないほどだった(コードの最適化はまだ検討されていたが、まだ初期段階でした)。手書きのマシンコードは、少なくとも一部の場所では60年代後半まで、コンパイラーが生成したコードよりもはるかに効率的であるという評判がありました。 コード拡張比率という概念さえあり、それはコンパイルされたコードのサイズを非常に優れたプログラマの仕事と比較しました。ほとんどの(すべての?)コンパイラーは通常、1を超えていたため、プログラムが遅くなり、さらに重要なことに、より多くのメモリーを必要とする大規模なプログラムが必要でした。これはまだ60年代の問題でした。
コンパイラーの関心は、特にさまざまな分野の科学者など、コンピューティングの専門家ではないユーザーにとって、プログラミングの容易さにありました。この関心はコードのパフォーマンスではありませんでした。しかし、それでもプログラマの時間は安価なリソースと見なされていました。コストは、1975年から1980年までハードウェアからソフトウェアにコストが切り替わるまでのコンピューター時間でした。つまり、コンパイラさえも一部の専門家によって真剣に受け取られなかったことを意味します。
コンピュータ時間の非常に高いコストは、通訳を失格にするもう1つの理由でした。この考えはほとんどの人にとって笑えるものでした。
LISPの場合は非常に特殊です。なぜなら、それはそれを実現可能にした非常に単純な言語だったからです(そして、コンピュータは58で少し大きくなりました)。さらに重要なことに、LISPインタプリタは、LISP( meta-circularity )の自己定義可能性に関する概念の証明であり、独立して使いやすさの問題。
LISPが成功したのは、この自己定義性により、プログラミング構造を研究し、新しい言語を設計するための優れたテストベッドになった(そして、シンボリック計算の利便性も向上した)ためです。
質問の前提に同意しません。
Adm。Hopperの最初のコンパイラ(A-0)は、リンカやマクロ言語に似ていました。彼女はサブルーチンをテープに保存し(それぞれに番号を割り当てました)、彼女のプログラムはサブルーチンと引数のリストとして作成されます。コンパイラーは、要求されたサブルーチンをテープからコピーして、完全なプログラムに並べ替えます。
彼女は、詩のアンソロジーを編集するのと同じ意味で「コンパイル」という言葉を使用しました。さまざまなアイテムを1つのボリュームにまとめます。
その最初のコンパイラーには、私の知る限り、字句解析器またはパーサーがありませんでした。そのため、現代のコンパイラーの遠い祖先になっています。彼女は後に別のコンパイラー(B-0、別名FLOW-MATIC)を作成して、より英語に似た構文を目指しましたが、それは1958年または1959年まで、LISPインタープリターとほぼ同時期に完成しました。
したがって、質問自体は少し間違っていると思います。当時、多くの科学者が同じ線に沿って考えていたはずのアイデアを共有したため、コンパイラとインタプリタはほぼ正確に同時に進化したようです。
ここで引用のより良い答え: https://stackoverflow.com/a/7719098/12276 。
方程式の他の部分は、コンパイラーがアセンブラーより上のステップの抽象化であったということです。最初に、ハードコードされたマシンコードがありました。 「私たち」はアセンブラーでした。すべてのジャンプやオフセットなどは、16進数(または8進数)に手動で計算され、紙テープまたはカードにパンチされました。したがって、現場にアセンブラが登場したとき、それは非常に時間の節約になりました。次のステップは、マクロアセンブラーでした。これにより、一連の機械語命令に展開するマクロを作成することができました。したがって、FortranとCobolは大きな前進でした。リソース(ストレージ、メモリ、CPUサイクル)の不足は、汎用の通訳者がテクノロジーの成長を待たなければならないことを意味しました。初期のインタープリターのほとんどはバイトコードエンジンでした(Javaまたは今日のCLRのようですが、機能ははるかに少ないです)。UCSDPascalは非常に人気のある(そして高速な)言語です。MSBasicはバイトつまり、「コンパイル」は実際に、ランタイムによって実際に実行されるバイトコードストリームを生成することでした。
命令のオーバーヘッドに関しては、実行されているプロセッサに完全に依存していました。業界はしばらくの間、RISCとCISCの大きな混乱を経験しました。私は個人的に、IBM、Data General、Motorola、Intel(登場したとき)、TI、その他いくつかのアセンブラーを書いた。命令セット、レジスタなどには、pコードを「解釈」するために必要なことに影響を与えるかなりの違いがありました。
時間の参考として、1972年頃に電話会社でプログラミングを始めました。
すべてをメモリに保持していない場合は、コンパイルされたコードの方がはるかに高速です。これらの時代には、関数はコンパイルされたコードに結合されていたことを忘れないでください。コンパイルしないと、必要な関数がわかりません。それで、あなたは関数を呼び出しています...ああ、まだディスクからではなく、私たちは50代前半ですが、カードからです!ランタイムで!
もちろん、回避策を見つけることは可能ですが、それらはまだ見つかりませんでした。言語が非常に単純で、マシンコードからそれほど遠くないからです。そして、コンパイルは簡単で十分でした。
最初のコンパイラーが作成される前に、人々はアセンブラー・コードを作成しました。これは、プレーン・バイナリー・コードと比較して大きな進歩でした。当時、コンパイラーによってコンパイルされたコードはアセンブラーコードよりも効率が悪いという強い主張がありました。当時、(コンピューターのコスト)と(プログラマーのコスト)の関係は、今日とはかなり異なっていました。したがって、その観点からはコンパイラーに対する強い抵抗がありました。
しかし、コンパイラーはインタープリターよりもはるかに効率的です。その時点で通訳を書くことを提案していたら、人々はあなたが狂っていると思っただろう。 100万ドルのコンピューターを購入し、その力の90%をコードの解釈に費やすことを想像できますか?
ループプログラムを解釈する前に、繰り返し読み取ることができるメディアに保存する必要があります。ほとんどの場合、適切なメディアはRAMだけです。コードは通常、人間が読める言語の場合はほとんど空であるパンチカードに入力されるため、RAMに格納する前に、コードに対して何らかの処理を実行する必要があります。多くの場合、パンチカードのテキストをプロセッサで直接実行するのに適した形式に処理することは、インタプリタを介して効率的に処理できる形式に処理することと同じくらい難しいことではありません。
初期のコンパイラの目標は、ディスク上にアセンブリ言語またはオブジェクトコードファイルを作成することではなく、コードを最終的にRAMで実行する準備ができていることです。これは実際には邪魔になるオペレーティングシステムがない場合は驚くほど簡単です。コンパイラは、メモリの一方の端から始まるコードを生成し、変数と分岐先を他方の端から割り当てることができます。ステートメントがラベル「1234」でマークされている場合、コンパイラは「1234」と呼ばれる変数で、現在のコード生成アドレスにジャンプし、存在しない場合はその変数を作成する命令。「goto 1234」というステートメントは、存在しない場合に変数「1234」を作成してからジャンプする[変数がそのステートメントが実行される前に、適切に格納されている場所にジャンプすることを期待します]。コンパイラがコードにgoto
のラベルを許可するために特別なことを行う必要はありません。 goto
がどこにジャンプするかを知っているので、まだ定義されていません-vaに傷つきやすい。これはコードを生成する最も効率的な方法ではないかもしれませんが、コンピューターが処理すると予想されるプログラムのサイズには十分です。
インタープリターが機能するにはコンパイラーが必要なため
上記の説明は実際には当てはまりません。厳密に言えば、コンパイラーを使用したり、コンパイラーとやり取りしたりせずに、インタープリターを作成することができます。しかし、これを実行した結果は、私がそれらの用語で意味していると私が思うようにはあまり見えません。
厳密に言えば、コンパイラとインタプリタはまったく異なることを行います。コンパイラーは、あるソースからテキストを読み取り、それを他の形式(アセンブリー言語、マシンコード、別の高水準言語、データ構造など)に変換します。一方、インタプリタは、ある種のデータ構造を取り込み、それに基づいて命令を実行します。
最近「コンパイラ」と考える傾向があるのは、実際にはコードジェネレータとペアになっているコンパイラです:あるソースからデータを受け取り、その内容に基づいてコードをある形式で出力するプログラム。これはコンパイラーのかなり直感的な使用法であり、コンパイラーが最初に作成されたものの1つでした。しかし、別の見方をすると、これはインタプリタが行うことと非常によく似ています。より一般的な操作を実行する代わりに常にコードを出力しますが、原理は同じです。
反対側から見た場合、インタプリタはどこかからデータを取得する必要があります。これは単なるデータなので、他の種類のデータを構築するのと同じ方法で構築できます。私たちは解釈について話しているので、テキストファイルの指示に基づいてデータを構築できるのは当然のようです。しかし、それを行うには、テキストを読み取ってデータ構造を作成する必要があります。それはコンパイラです。コードジェネレーターではなくインタープリターに接続されていますが、コンパイラーと同じです。
それがコンパイラが最初に書かれた理由です。 コンパイラーが考案されたときでもデータ構造を解釈するという考えは新しいものではありませんでしたが、コンパイラーはプログラマーがテキストからそれらの構造体を構築できるようにする「ミッシングリンク」でした。