コンパイラーとは

自宅でパソコンで仕事をする女性

執筆者

Josh Schneider

Staff Writer

IBM Think

Ian Smalley

Staff Editor

IBM Think

コンパイラーとは

コンパイラーは、あるプログラミング言語(ソース言語)で記述されたコードを、別のプログラミング言語(ターゲット言語)へ変換する種類のコンピューター・プログラムです。

コンパイラーは、プログラムの機能を維持しながら、高水準のソースコードを低水準のターゲットコード(アセンブラー言語、オブジェクト・コード、マシン・コードなど)に変換するために使用されます。

現代の実用的なコンピューター・プログラミングに重要なツールであるコンパイラーがあれば、プログラマーは人間にとって分かりやすい高水準のコードで作業し、そのソースコードをコンピューターが実行可能なターゲット・コードに変換できます。コンパイラーは、ソフトウェア開発者がセキュリティー、安定性、移植性が向上した、効率的な実行可能プログラムを作成する際にも役立ちます。これは、コンパイラーがエラーの特定と対処を支援することで、移植できるコンピューターが実行可能なアプリケーションを作成できるようになるためです。

すべてのコンパイラーは高水準のコードを低水準の実行可能なコードに変換しますが、プログラミング言語やアプリケーションによってさまざまな種類のコンパイラーが使用されます。たとえば、クロスコンパイラーは、実行されているCPUまたはオペレーティング・システムとは異なる種類のCPUまたはオペレーティング・システム用のコードを生成するために使用されます。

理想的なコンパイラーが利用できない、あるいはまだ作られていない場合には、より最適化された恒久的なコンパイラーをビルドするための一時的なブートストラップ・コンパイラーを用います。

関連ソフトウェアの例として、次のようなものがあります。

  • 逆コンパイラーはコンパイラーとは逆の働きをするものであり、低水準のコードを高水準言語に変換します。
  • ソース・トゥ・ソース・コンパイラー(トランスパイラー):高水準コードを別の高水準言語へ変換します。
  • 言語リライター:言語自体は変えずに、形式的なコード表現を異なる形に変換します。
  • コンパイラー・ジェネレーターは、汎用的で再利用可能なコンパイラーまたはコンパイラー・コンポーネントを作成するために使用され、プロジェクトの目的に応じて組み込むことが可能です。

The DX Leaders

AI活用のグローバル・トレンドや日本の市場動向を踏まえたDX、生成AIの最新情報を毎月お届けします。登録の際はIBMプライバシー・ステートメントをご覧ください。

ご登録いただきありがとうございます。

ニュースレターは日本語で配信されます。すべてのニュースレターに登録解除リンクがあります。サブスクリプションの管理や解除はこちらから。詳しくはIBMプライバシー・ステートメントをご覧ください。

コンパイラーの仕組み

実際には、コンパイラーの使用は、Linux(または同等の)システムのコマンド・ラインにコマンドを入力し、コンパイラーの実行可能ファイルとコンパイル対象のソース・ファイルを指定するだけの簡単な作業です。このコマンドは、ソース・コードを処理し、ターゲットとするマシン・コードにコンパイルし、実行可能なプログラムを生成するために必要なオブジェクト・ファイルを生成するようにシステムに指示するものです。

オープンソースのコンパイラーとしては、GNU Compiler Collection(GCC)(CコードをCプログラムにコンパイルする用途で広く用いられる堅牢なCコンパイラー群)や代替のClangなどがあり、GitHubのようなリポジトリーで入手できます。その他のコンパイラーは、多様なディストリビューターから無償でインストールするか、購入することもできます。また、人気の統合開発環境(IDE)に組み込まれている場合もあり、テキスト・エディター、APIドキュメント、デバッグ・ツールなどの各種ユーティリティーをバンドルしています。

使用するコンパイラーの種類にかかわらず、コンパイル処理では、ソースコードが解析、最適化、そして最終的にはコード生成という複数の段階を順次通過します。ソースコードは各分析レイヤーを順に通過し、各段階で検証されます。

コンパイラーが元のソースコードに問題を認識した場合は、エラーメッセージを返し、残りのコードをコンパイルする前に開発者に修正を促すことがあります。一般に、コンパイラーは次の手順で進みます:

  1. 字句解析:コンパイルの最初のステップでは、ソースコードをコンパイラーの字句解析器(lexer)に通します。字句解析器(lexer)は、文字をキーワードや識別子、演算子といった意味のある言語単位に変換するプログラムです。これらの単位は、総称してトークンと呼ばれます。つまりこのステップでは、次のステップに備え、ソースコードにおける意味のある重要な要素をコンパイラーが扱えるトークンに変換するのです。
  2. 構文解析:コンパイル・プロセスの第2段階では、字句解析器(lexer)から渡されたトークンをコンパイラーのパーサーに送り、構文エラーの有無を確認して、ソースコードがソース言語の規則に従っていることを保証します。パース中にエラーが検知されなければ、コード全体の構造を抽象的に表現する抽象構文木(AST)を生成します。
  3. 意味解析:構文の検証後、コンパイラーは解析済みコードに対して意味解析を行い、ソースコードの意図する機能を推論します。この段階では、未宣言変数や演算子の誤用などの論理エラーを検査します。
  4. 最適化:機能するコードの生成には必須ではありませんが、コンパイルされたコードの全体的なパフォーマンスを向上させるために、多くのコンパイラーで最適化のオプションを備えています。最適化を行うことで不要なコードを特定して削除でき、プログラムの高速化、効率化、安定性を高め、最終的なデバッグ・プロセスを短縮することができます。
  5. コード生成:コンパイルの最終ステップであり、コンパイラーは抽象構文木(AST)を機械が読めるコードに変換します。コード生成において最終的に出力されるのは、バイナリ・コードに変換されコンピューター・システムで実行できるアセンブリ言語コードです。
AI Academy

ハイブリッドクラウドでAI対応を実現

IBMのエキスパートが主催するこのカリキュラムは、ビジネス・リーダーが成長を促進するAI投資に優先順位を付けるために必要な知識を習得できます。

3段階のコンパイラー構造

上記の構造に厳密に準拠していないコンパイラーもあります。コンパイラーによってはステップが多いことも少ないこともありますが、コンパイルのすべてのフェーズは、フロントエンド、ミドルエンド、バックエンドの3つの段階のいずれかに分類できます。

この三段構成により、コンパイラーはモジュール型のアプローチを採用できます。これにより、言語ごとの複数のフロントエンドとCPUごとのバックエンドを組み合わせつつ、適用可能な各種ミドルエンドの最適化機能を共有できます。

コンパイラーの3つの段階は、次のように構成されます。

  1. フロントエンド:コンパイラーのフロントエンドには、字句解析、構文解析、意味解析が含まれます。この段階では、ソース言語の規則に従って構文と意味を検証し、ソースコード中のエラーを特定して位置を示すことができます。エラーが見つからなければ、フロントエンドはソースコードを中間表現(IR)—ソースコードを一時的に低レベルに変換した表現—に変換し、ミドルエンドに渡します。
  2. ミドルエンド:コンパイラーのミドルエンド段階では、コンパイル全体で対象としているCPUアーキテクチャーに依存せず、IRに対して各種コード最適化を行います。ターゲットのマシンコードから独立してソースコードに最適化を施すことで、複数のバージョンにまたがってコード性能を向上させる汎用的な最適化を適用できます。これらの改良は、対応する特定のプログラミング言語やハードウェア・アーキテクチャーに関係なく実施できます。
  3. バックエンド:バックエンドはミドルエンドの出力を受け取り、CPU固有の最適化や変換をさらに行う場合があります。コンパイル・プロセスの最終段階として、レジスター割り当てや命令スケジューリングを含め、ターゲットに依存するアセンブリー・コードを出力します。通常、バックエンドの結果は、対象となるOSやハードウェアに最適化された機械語となります。

コンパイラーを使用するメリット

コンパイラーは、動作するコードの生成に必ずしも不可欠というわけではありませんが、プログラミング言語やマシン環境の多様性と複雑さを踏まえると、実行可能なソフトウェアを作成するための実務上の必需品といえます。ソフトウェア・コンパイラーを使用する主な利点は次の4点です。

高水準言語でのコーディングを促進

高水準言語は人間の言語に近い構文やキーワードを用いるため、開発者が扱いやすくなります。コンパイラーは、この人が読みやすいコードを、最適化されたソフトウェアを実行するために必要な、より複雑な機械語へ変換します。

高水準言語の例として、次のような言語があります:

  • Python(Web開発、データサイエンスなどに使用)
  • Java™(Android開発、エンタープライズ・アプリケーションなどに使用)
  • C++(ゲーム開発やオペレーティングシステムなどに使用)
  • JavaScript(動的かつインタラクティブなWeb開発に使用)
  • PHP(Web開発のサーバーサイドスクリプトに使用)
  • C#(Windowsアプリケーション、Unityエンジンゲーム開発に使用)
反復の削減

コンパイラーは、高水準コードを実行可能な機械語に変換することで効率を高めます。コンパイラーの出力は.exeというファイル拡張子で保存され、コンピューターによって直接実行されます。コンパイラーを用いることで、実行可能プログラムの作成は基本的に一度の作業で済みます。

コンパイルが完了すると、コンパイルされたコードは必要に応じて何度でも実行できます。このプロセスを行うことで、特定のアプリケーションまたはアプリケーションの一部をランタイム・ソフトウェアのタスクとは別に実行できるようになるため、プログラムは一般的により高速かつ効率的に実行できるようになります。

移植性の向上

すべてのシステムがあらゆる種類のプログラミング・コードを実行できるわけではありません。コンパイラーは、開発者が好むコードの形式を、システムの動作に必要なコードの形式へと変換します。このように、コンパイラーは、さまざまなOSやハードウェア・アーキテクチャーで容易に保存・転送・実行できる互換性の高い形式へソフトウェアを変換し、プログラムの移植性を高めます。

全体最適化の推進

コンパイルの過程で、コンパイラーはソフトウェアのエラーや欠陥を検出・対処でき、より安定し最適化されたプログラムの実現に寄与します。また、バッファー・オーバーフローなどのメモリー関連エラーを防止し、潜在的なメモリー問題を検出した場合に警告を生成することで、ソフトウェアのセキュリティー向上にも役立ちます。

コンパイラーとインタープリターの比較

コンパイラーはソース・コードを機械で実行可能なマシン・コードに変換するために使用されますが、インタープリターは異なる仕組みで同様の機能を提供する別のタイプのプログラムです。

インタープリターはソースコードを変換するのではなく、ソースコードを直接実行するか、バイトコードと呼ばれる中間コード(ソースコードを低レベルかつプラットフォーム非依存で表現したもの)を用います。バイトコードは、人間に読みやすいソースコードと機械語の間を取り持つ役割を果たし、コンピューターのハードウェア上で直接実行するのではなく、仮想マシン(VM)によって実行されるよう設計されています。

理論上、あらゆるプログラミング言語は、コンパイラーでもインタープリターでも実行できます。ただし、言語によってはコンパイルに適したもの、解釈実行に適したものがあるのが一般的です。

実際には、いわゆるコンパイラー言語とインタープリター言語の区別は曖昧になることがあります。—コンパイラーとインタープリター自体の区別と同様で、両者の機能が重なり合う場合があるためです。一般的にコンパイルされる言語もあれば、解釈実行される言語もありますが、通常インタープリターで実行される言語に対してコンパイラーを実装することも、その逆も可能です。

高水準言語は通常、コンパイラーまたはインタープリターのいずれかで変換することを念頭に置いて作成されますが、どちらしかないというわけではなく、選ぶことができます。たとえば、BASICはインタープリター型言語、Cはコンパイル型言語とよく呼ばれますが、Cにインタープリターが存在するように、BASICにもコンパイラーが存在します。

インタープリターとコンパイラーの主な違いは、変換のタイミングと最適化にあります。どちらのタイプのプログラムもソース・コードをまずは動作し、そして最適化されたターゲット・コードに変換することを試みます。

動作環境によっては、ハードウェア性能、メモリ、ストレージ容量を考慮した場合、コンパイラーを通したコードまたはインタープリターを通したコードの方が効率的に実行できる場合があります。プログラム上、アプリケーション上、ハードウェア上の制約次第では、コンパイラーを通す、インタープリターを通す、あるいは両方を組み合わせることが最良の結果につながります。

厳密に言うとインタープリターはコンパイラーを完全に代替することはできませんが、段階的に変換することでコンパイラーと同様の機能を果たすことが出来ます。コンパイラーは、実行可能ファイルを作成する前にソースコードをターゲットコードに完全に変換する、事前処理(AOT)変換方式を採用しています。

一方インタープリターは、アプリケーションの要求に応じてコードを直接実行するか、仲介としてバイトコードを用いて、仮想マシンで実行可能な形式のコードを生成します。この方式により、インタープリターは一定の高速化や柔軟性を提供する場合がありますが、実行スタックの最終段階では、最終的に直接実行される機械命令列が必要になります。

動作の軽さが優先される場合、実行時(JIT)変換ができる特殊なインタープリターの方がコンパイラーよりも適していることがあります。実行時(JIT)変換は、即座に実行できるよう、ソースコードの一部をターゲットコードにコンパイルしてメモリバッファに格納する方式です。実行時(JIT)インタープリターは、従来のコンパイラーが一度のコンパイルで済む効率性と、コードを繰り返し実行する柔軟性を組み合わせ、必要に応じてコードをコンパイルします。そのため一般的なバイトコード・インタープリターよりも高速に処理されることもあります。

しかしJITコンパイルの傾向が高まり、状況に応じたバイトコードの解釈実行が増加する中で、多くのコンパイラーはコンパイラー機能とインタープリター機能の双方を備えるようになっています。このような機能面での重複が、両者の区別をさらに曖昧にしているのです。

関連ソリューション
IBM Cloud Infrastructure Center 

IBM Cloud Infrastructure Centerは、IBM zSystemsおよびIBM LinuxONE上のプライベートクラウドのインフラストラクチャーを管理するためのOpenStack互換ソフトウェア・プラットフォームです。

Cloud Infrastructure Centerの詳細はこちら
ITインフラストラクチャー・ソリューション

企業のハイブリッドクラウドとAI戦略のために設計された、サーバー、ストレージ、ソフトウェアを紹介します。

ITインフラストラクチャー・ソリューションはこちら
クラウド・ソリューション

安全性と柔軟性を備えたクラウドで、ビジネスの成長に合わせてリソースを無理なく拡張できます。

クラウド・ソリューション
詳細情報はこちら

IBMのハイブリッドクラウドとAI対応ソリューションで、企業インフラを変革しましょう。ビジネスを保護、拡張、モダナイズするために設計されたサーバー、ストレージ、ソフトウェアを発見したり、専門家のインサイトにアクセスして生成AIストラテジーを強化したりできます。

ITインフラストラクチャー・ソリューションはこちら 電子書籍を読む