コンパイラについて
コンパイラとは
ソースコードを機械が解釈できる形式(バイナリ)に変換するソフトウェア 具体例としてCコンパイラのgccやclangなどがある
コンパイラが行うこと
コンパイラが行うことには大きく分けて次の5つがある。
入力の受け取り
入力のトークナイズ
トークン列のパース
機械語の生成
コード最適化
入力の受け取り
ファイルを開いて中のソースコードをプログラム中で扱える形にする。
入力のトークナイズ
入力されたソースコードをトークンに分ける。
トークンとはプログラム中で意味を持つ文字列の最小単位のことである。
例えば、int a = func(x) + 12;というコードが与えられるた場合これをトークンに切り分けると
{ "int", "a", "func", "(", "x", ")", "+", "12", ";" }ような文字列の配列を返すことになる。
トークン列のパース
与えられたコードがどのような意味を持つのかを判定するために、トークン列の並びから抽象構文木(AST)を生成する。ASTはコードの意味だけを取り出し木構造で表現されたデータ構造で、計算の順序や意味が明白に示されている。
例えば、プログラミング言語Lispはコードが全て前置記法で書かれる言語であるが、その特徴のために抽象構文木をそのまま書き下ろす言語であると言われることもある。
code:一般的な算術演算コードとそれをLisp形式のASTであらわした例
//一般的な算術演算式
3 * 4 + 8 / 2
//上と等価なLisp形式の抽象構文木
(+ (* 3 4) (/ 8 2))
プログラムコードをこのような形式にすることで、オペランドを計算するコードを生成した後それらの結果に対してオペコードを適用するコードを生成する、といったプログラムを書けばどのようなプログラムも再帰的にコード生成を行えるという利点がある。
機械語の生成
ASTから機械語を生成する。
上で述べたように一つの式に対してその引数を計算するコードをそれぞれ生成した後、その式のオペコードを適用するコードを生成することでプログラム全体のコードを生成できる。
コンパイラ自作について
コンパイラ自作の本などでは上の役割を行うためのプログラムがそれぞれ各章で詳細に解説され、その章末問題などで製作していくことで最終的にコンパイラが完成するようになっているようなものがあるが、この形式は本を一冊読まないと動くものが完成しなかったり、致命的な間違いに気づくのが遅れたりその箇所を探すのに苦労してしまう
おすすめの方法として一旦電卓レベルの簡単なコンパイラを完成させ、それを拡張する形で開発をしていく方法がある。こうすることでモチベを保ちつつ、開発中のどの時点においてもその時点で動作するレベルのコンパイラにおいて必要な知識をまんべんなく定着させられる。(コンパイラの本を読むと最初の方の章の内容にだけ異常に詳しくなったりしそうなので…)