コンパイラとはソースコードがマシンコードになる仕組み

コンパイラは、ある形式から別の形式に変換するコンピュータ プログラムであり、多くの場合、高水準のコンピュータ言語からバイト コードおよびマシン コードに変換します。 コンパイラにはさまざまなバリエーションがあり、この記事で詳しく説明します。

コンパイラ、トランスパイラ、インタプリタ、および JIT コンパイラ

コンパイラは、多くの場合、C++ などの高級言語のソース コードを、Intel x64 などの現在のコンピューター アーキテクチャのオブジェクト コードに変換します。 複数の高級言語ファイルから生成されたオブジェクト モジュールは、 リンクされた実行可能 列。

コンパイラーを実行するアーキテクチャーとは異なるアーキテクチャー用のオブジェクト・コードを生成することを目的としたコンパイラーが呼び出されます。 クロスコンパイラ. 組み込みシステム用の実行可能ファイルを生成するために、デスクトップ (またはそれより大きい) コンピューターで実行されるクロスコンパイラーを使用するのが一般的です。 TypeScript から JavaScript や C++ から C など、ある高級言語から別の高級言語に変換するコンパイラは、 トランスパイラー. コンパイルしている言語で書かれたコンパイラは呼び出されます ブートストラップ コンパイラ.

Java、Python、C# など、マシンに依存しないことを意図した言語のコンパイラは、ソース コードを仮想マシンのバイト コードに変換し、現在のアーキテクチャのインタープリターで実行します。 インタープリターは、実行時に一部のバイト コードをネイティブ コード命令に変換する Just-In-Time (JIT) コンパイラーによって強化される場合があります。 JIT コンパイラでは、実行時の起動遅延が発生することがありますが、通常は、特に CPU を集中的に使用するコードの場合、実行後の速度の向上がそれを上回ります。 JIT でコンパイルされた実行可能ファイルの起動の遅延を減らす 1 つの方法は、実行可能イメージをビルドするときに事前 (AOT) コンパイラを使用することです。

歴史的に、初期のパーソナル コンピュータに付属していた BASIC インタプリタなど、バイト コードを使用しないインタプリタがありました。 コンパクトなバイト コードを実行するインタープリターよりも実行時に遅くなる傾向があり、コンパイルされたネイティブ コードよりも実行時にはるかに遅くなる傾向がありました。 ただし、プログラマーはコードのコーディング、テスト、デバッグ、変更、および再実行を迅速に行うことができるため、ソフトウェア開発ライフサイクル全体で非常に生産的であることがよくありました。

最も有名な高水準言語コンパイラーのいくつかの特徴を掘り下げてみましょう。

フォートラン

FORTRAN (Formula Translator、1977 年以降は Fortran と綴られる) は、科学および工学のアプリケーションを対象とした最初の成功した高レベル言語です。 FORTRAN I コンパイラは、1954 年から 1957 年にかけて、IBM 704 自体の共同設計者でもあった John W. Backus が率いるオールスター チームによって、IBM 704 用に開発されました。 それはアセンブリ言語で書かれた最適化コンパイラで、23K 命令にもなりました。 FORTRAN I コンパイラは大幅な最適化を行いました。算術式の解析と演算子の優先順位の適用に取り組み、コピーの伝播とデッドコードの削除を実行し、共通部分式を引き上げて冗長な計算を排除し、最適化しました。 do... ループと添字の計算、および最適化されたインデックス レジスタの割り当て。

現在、10 を超える FORTRAN コンパイラがあり、そのうちの 4 つはオープン ソースであり、その多くは商用提供されていますが無料です。

舌足らずの発音

John McCarthy は MIT で LISP (List Processor) を設計し、1960 年に仕様を公開しました。 それは、人工知能 (AI) コミュニティと密接に関連していました。 仕様が公開された直後、Steve Russell は LISP が 評価 関数はマシン コードで実装でき、IBM 704 では実装できました (McCarthy が驚いたことに)。 これが最初の LISP インタープリターになりました。 MIT の Tim Hart と Mike Levin は、1962 年に LISP で最初の LISP コンパイラを作成しました。 コンパイラ自体は、Russell の LISP インタープリタをコンパイラ ソース コードで実行することによってコンパイルされました。 コンパイルされた LISP は、IBM 704 で解釈された LISP よりも 40 倍速く実行されました。これは、最も初期のブートストラップ コンパイラでした。 また、コンパイルされたコードと解釈されたコードを混在させるインクリメンタル コンパイルも導入されました。

Common Lisp、Emacs Lisp、Scheme、Clojure など、LISP とその子孫の新しいバージョンには、多数のコンパイラとインタプリタが存在します。

コボル

COBOL (Common Business-Oriented Language) は、1959 年に米国国防総省の要請により、CODASYL という委員会によって設計され、FLOW-MATIC (Grace Hopper によって設計された)、AIMACO (FLOW -MATIC 派生)、および COMTRAN (IBM の Bob Bemer による)。 COBOL の当初の目標は、一般的なデータ処理用の移植可能な高水準言語になることでした。 最初の COBOL プログラムは 1960 年に実行されました。

1962 年に行われた海軍の調査によると、COBOL は 1 回あたり 3 ~ 11 のステートメントをコンパイルしていたことがわかりました。 . これは、言語仕様とコンパイラが更新されるにつれて、長年にわたって改善されました。 1970 年までに、COBOL は世界で最も広く使用されているプログラミング言語になりました。

現在、存続している 4 つの主要な COBOL コンパイラがあります。 GnuCOBOL は、コンパイルおよびリンクできる C コードにコンパイルされます。 IBM COBOL は、初期の COBOL コンパイラーと同様に、IBM メインフレームおよびミッドレンジ コンピューター用のオブジェクト コードにコンパイルし、コードをリンクします。 Micro Focus COBOL は、.NET または JVM (Java 仮想マシン) バイト コードにコンパイルします。

アルゴール

Edsger Dijkstra 博士と Jaap Zonneveld 博士は、アムステルダムの数学センターで、1959 年から 1960 年までの 9 か月にわたって、X1 アセンブリ言語で最初の ALGOL 60 コンパイラを作成しました。 社内で設計された X1 は、新しいオランダのコンピューター工場 Electrologica によって製造されました。 ALGOL (Algorithmic Language) 自体は、FORTRAN を超える理工系コンピューター言語の大きな進歩であり、CPL、Simula、BCPL、B、Pascal、C などの命令型言語の開発に影響を与えました。

コンパイラ自体は約 2,000 命令の長さで、ランタイム ライブラリ (MJH Römgens と SJ Christen によって作成された) はさらに 2,000 命令の長さでした。 プログラムのソースコードとライブラリと同様に、コンパイラは紙テープから読み込まれました。 コンパイラは、コードを 2 回通過しました。 1 回目 (プレスキャン) は識別子とブロックを収集し、2 回目 (メイン スキャン) は別の紙テープにオブジェクト コードを生成します。 その後、紙テープの代わりに「ストア」(おそらく磁気ドラム)を使用することで、プロセスが高速化されました。 最終的に、ALGOL 60 とその方言の約 70 の実装がありました。

ALGOL 68 は ALGOL 60 を置き換えることを目的としており、非常に影響力がありましたが、非常に複雑だったため、実装も採用もほとんどありませんでした。 ALGOL 68 の影響を受ける言語には、C、C++、Bourne shell、KornShell、Bash、Steelman、Ada、および Python が含まれます。

折り畳み

PL/I (Programming Language One) は、1960 年代半ばに IBM と SHARE (IBM Scientific Users Group) によって、科学ユーザーとビジネス ユーザーの両方のための統一言語として設計されました。 最初の実装である PL/IF は、IBM S/360 用であり、System/360 アセンブリ言語で完全に記述され、1966 年に出荷されました。F コンパイラは、制御フェーズと多数のコンパイラ フェーズ (100 に近づく) で構成されていました。 その後、IBM で PL/I がいくつか実装され、Multics (システム言語として) と DEC VAX も実装されました。

パスカル

チューリッヒの ETH の Niklaus Wirth は、ALGOL 60 の後継に取り組んでいる標準化委員会のメンバーであり、より小さな言語である ALGOL W を提出しましたが、これは却下されました。 Wirt は委員会を辞任し、ALGOL W の作業を続け、1970 年に Pascal として簡略化された形式でリリースしました。 Wirt は当初、FORTRAN 66 で Pascal コンパイラを実装しようとしましたが、できませんでした。 その後、彼は C に似た言語 Scallop で Pascal コンパイラを作成し、それをブートストラップ用に同僚が Pascal に翻訳しました。

Wirth Pascal の 2 つの注目すべき派生製品は、Pascal P-system と Turbo Pascal です。 チューリッヒの P システム コンパイラは、仮想スタック マシン用の「p コード」を生成し、それを解釈しました。 それが IBM PC の UCSD Pascal と Apple Pascal につながりました。 Anders Hejlsberg は、Nascom-2 用に Blue Label Pascal を作成し、IBM PC 用に 8088 アセンブリ言語で再実装しました。 Borland はそれを購入し、Turbo Pascal として再リリースしました。 その後、Hejlsberg は Turbo Pascal を Macintosh に移植し、Apple の Object Pascal 拡張機能を追加して、新しい言語を PC に移植し、最終的に Microsoft Windows 用の Delphi に進化しました。

VS

C はもともと、1972 年から 1973 年にかけて、ベル研究所でデニス リッチーが Unix 上で動作するユーティリティを構築するために開発しました。 元の C コンパイラは、当時の Unix と同様に、PDP-7 アセンブリ言語で書かれていました。 PDP-11 への移植もアセンブリ言語でした。 その後、C を使用して Unix カーネルを書き直し、移植可能にしました。

C++

C++ は、1979 年に Bell Laboratories の Bjarne Stroustrup によって開発されました。C++ は C にオブジェクト指向の機能 (およびその他の改善) を追加する試みであるため、Stroustrup は当初、それを「C with Objects」と呼びました。Stroustrup は 1983 年に言語を C++ に改名しました。最初の商用 C++ コンパイラである Cfront がその時点でリリースされました. Cfront は C++ を C に変換し、それをコンパイルして直接リンカにリンクすることができました.

ジャワ

Java は、Pascal P システムと同様に、JVM 用のバイト コードにコンパイルされてから解釈される移植可能な言語 (「一度書けば、どこでも実行可能」というマーケティング スローガンを使用) として 1995 年にリリースされました。 Java コンパイラはもともと C で書かれており、いくつかの C++ ライブラリを使用していました。 その後の JVM リリースでは、インタープリターを高速化するために JIT コンパイラーが追加されました。 現在の Java コンパイラは Java で書かれていますが、Java ランタイムはまだ C で書かれています。

Java およびその他の言語の GraalVM 実装では、ビルド時に AOT コンパイラが実行され、バイトコードが最適化され、起動時間が短縮されます。

VS#

C# は、1999 年に Borland を離れて Microsoft に移籍した Anders Hejlsberg によって設計され、2000 年に Mads Torgersen によって CLR 用の C および C++ で実装されました。C# は CLR バイト コード (中間言語、または IL) にコンパイルされ、解釈され、JIT -実行時にコンパイルされます。 C# コンパイラ、CLR、およびライブラリは C# で記述され、コンパイラはあるバージョンから別のバージョンにブートストラップされます。

タイミングに基づくと、C# を開発する原動力の一部は、Microsoft が Sun から Java のライセンスを取得できなかったことである可能性がありますが、Microsoft はこれを否定しています。 Hejlsberg は、C# は Java と同じくらい C++ の影響を受けていると述べています。 いずれにせよ、Java 言語と C# 言語は長年にわたって大幅に分岐しています。

結論

これまで見てきたように、言語コンパイラは、多くの場合、最初に既存の下位レベルの言語で実装され、後でコンパイルしている言語で再実装され、ブートストラップによる移植性とアップグレードが可能になります。 一方、高水準言語は、仮想マシン用のバイトコードにコンパイルされ、その後解釈され、JIT コンパイルされることが増えています。 ただし、より高速な実行速度が必要な場合、ライブラリ ルーチンは C またはアセンブリ言語で記述されることがよくあります。

著作権 © 2023 IDG Communications, Inc.

Leave a Comment

Your email address will not be published. Required fields are marked *