はじめに
FORTRAN、C、Java、Pascalなどのコンパイル言語で必要となるコンパイルによる機械語への変換処理。普段何気なく使っているコンパイルが何をしているのか、今回はC言語のコンパイルの処理過程について紹介する。
コンパイルとは
コンパイルとは、人間が読み書きできる状態のSource codeを、コンピューターの実行可能なBinary(Object) codeに変換すること。Binary codeを10進数の世界で生きている人間が理解し記述するのは難しいので、一度人間でも扱える文字で書き、それを変換プログラムで機械後に変換し、CPUで直接処理可能な状態にする。
具体的な処理
一般的なC言語のコンパイルは以下の処理が順に行われている。
- プリプロセッサ
- コンパイル
- リンク
1. プリプロセッサ cpp
プロプロセッサはコンパイルの最初の処理で、ソースコードに記述したヘッダーファイル(.h)やマクロを挿入して、ソースファイルに展開する。またコメントなどを削除してソースファイルを簡潔にする。
例として下記のように記述されたヘッダーファイルを集めてソースコードに展開する。
# include <stdio.h>
# include <stdlib.h>
# include <string.h>
# include <wchar.h>
# include <cmath>
# include <ctime>
# include <math.h>
# include <iostream>
# include <fstream>
# include <sstream>
# include <algorithm>
# include <cstdio>
2. コンパイル
コンパイルは実際にソースコードを機械語に変換する処理。
-
字句解析(Lexical Analyzer)
識別子、定数、演算子、カンマや括弧などの区切り記号等をトークンと呼ばれるものに分ける。
for(i==0,i<10,I++){
=>for
、(
、i
、==
、0
、,
、i
、<
、10
、,
、I
、++
、)
、{
-
構文解析(Syntax Analyzer)
字句解析で識別したトークンを、まとまりのある構文に分ける。
for
┣==i
,0
┣<i
,10
┣++i
-
中間コード生成(Intermediate Code Generation)
複数の構文で一連の単純な命令を作る。 -
最適化(Optimization)
処理速度をあげるため、プログラムのコードサイズを小さくして効率化する。
※最適化によりコードが飛ばされ予期せぬ動きをすることがあるため、最適化オプションを無効化したりする。 -
コード生成(Code Generation)
構造ごとに使用する命令や実行順序、またレジスタの割り当てなどを確定して機械語に変換する。
それぞれのフェーズでは並行してテーブルマネージメントとエラーハンドリングが行われている。
-
テーブルマネージメント
トークンや構文の情報を保持する。 -
エラーハンドリング
各フェーズで字句誤りや構文の間違いをチェックする。
3. リンク
既にコンパイルされたオブジェクトファイル(.o)を結合して実行形式ファイルを生成する処理。
C言語でいうところの静的リンクライブラリ(.a)や動的リンクライブラリ(.dll/.so)。
まとめ
コンパイルの処理過程を簡単にまとめた。もし間違いなどあれば、編集リクエストを出して頂くと嬉しいです。