Cコンパイラを作り始めた

タイトルの通り、コンパイラを作り始めました。
先日、 転職のお知らせ にも書いたのですが、低レイヤーを勉強していきたいとここ最近考えていました。
正直、僕が考えていた低レイヤーというのは、AWS上でインフラを構築できるようになることやRDBのチューニングでした(前職ではアプリケーションのコードを書くこと以外、あまり気にしなくてよかったのでこのへんをやりたかった)。
しかし、会社の同僚の方たちと飲んでいるときに、エモい低レイヤーの話を聞き、ちょっとやってみるか!という気持ちになったのでコンパイラを作り始めてみました。

作っているもの

9ccというCコンパイラを作っています。
Cを書いた経験はなく、けっこう苦しいところもあります...

github.com

Cコンパイラとは、C言語で書かれたプログラムをアセンブリ言語に変換するものです。
例えば 5+20-4 の場合、以下のようなアセンブリを出力します(僕の現時点のコードでは)

.intel_syntax noprefix
.global main
main:
  push 5
  push 20
  pop rdi
  pop rax
  add rax, rdi
  push rax
  push 4
  pop rdi
  pop rax
  sub rax, rdi
  push rax
  pop rax
  ret

9ccという名前を聞いて、ピンと来る方もいるかもしれませんが、8cc9cc 作者の Rui Ueyama さんが書かれている 低レイヤを知りたい人のためのCコンパイラ作成入門 を参考にしながら(現時点ではほぼ写経しながら)作っています。

実装が完了しているもの

  • 足し算、引き算
  • 空白を含む足し算、引き算
  • 加減乗算、優先順位のカッコを含む計算
  • 単項プラス、単項マイナス

と、書いてもよくわからないと思うので、テストコードを見てもらうのがわかりやすいです。

tryという関数に期待値と入力値を渡し、実際の結果が期待値と一致するかをチェックしています。
try {期待値} {入力値}

# 整数1個だけコンパイルできる
try 0 0
try 42 42

# 足し算、引き算対応
try 21 '5+20-4'

# 空白対応
try 41 ' 12 + 34 - 5 '

# 加減乗算と優先順位のカッコからなる式に対応
try 47 '5+6*7'
try 15 '5*(9-6)'
try 4 '(3+5)/2'

# 単項プラスと単項マイナス
try 5 '-10+15'
try 15 '14+-(-7)-(+6)'

地道にやっていく感じですね。 できることが増えてくると面白いです。

実装中の箇所

  • 比較演算子 (== != <= >=)
    • ちょっとハマっている...

これから実装すること

  • ファイルを分けて分割コンパイルできるようにする
  • 変数、関数に対応

基本、 低レイヤを知りたい人のためのCコンパイラ作成入門 に沿って実装していく予定です。
挫折しなければ😂

最後に

APIなどのアプリケーションのコード書くのとは全然違いますが、ちょっと楽しいので地道に続けていきたいです。
そして、いつかGoでGoのコンパイラ作ってみたいです

参考文献

www.sigbus.info

nor-isio.hateblo.jp