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