参考元:低レイヤを知りたい人のためのCコンパイラ作成入門
ソースコード:C compiler written in V
Twitterモーメント:VCC開発日記まとめ V言語HP:The V Programming Language

Cコンパイラを作ろうとした話

をとこもすなるCコンパイラ作成といふものを、杏もしてみむとてするなり。

昨年(2018年)のセキュリティ・キャンプでruiu氏講師のC言語コンパイラ作成講座が開かれた。
当時私はTLでhsjoihs氏がやってるのを見てて楽しそうだなーと思う反面分からんという気持ちが多く、それを横目にCPUをガリガリ書いてた。

時は変わって今年(2019年)の6月あたり、V言語というモダンでシンプルかつ安全な言語を謳ったプログラミング言語がオープンソースになってリリースされた。
6月時点では(さすがに個人開発だったため)実装が甘く散々に批判されていたが、最近はだいぶバグも減って喧伝されていた機能も追加されてきている。

そんな中、ゲテモノを食うのが好きだった私はそのコミュニティの観察が趣味になっていた。
貢献してみたい気持ちも山々だけども、私が何かできるとしたら周辺の標準ライブラリ関連だけで、中心のコンパイラに関しては何の理解もしていなかった。
なので、何かコンパイラを勉強できるものはないか探していた。

Googleで一番最初に出てきたのが参考元のruiu氏の「低レイヤを知りたい人のためのコンパイラ作成入門」だった。(SEO強すぎでは)
この文書は、セキュリティ・キャンプでの講義の内容が元になっているらしく、先人たちの 知見が多いため参考になろう。

そして手元にあったV言語で私はC言語のコンパイラを書き始めたのだった…

ビルド・実行方法

V言語のインストール

まず、私の環境はWindows上のWSLで、ディストリビューションはUbuntu16.04で動かしている。基本的にV言語はUnix系OSやWindowsのMingwなどがサポートされているので、適当な環境を作成すれば動く。

まずはgitをインストールする。パッケージコマンドは環境依存なので、適宜(yumやらbrewやら)に置き換えて読んでほしい。

$ sudo apt update
$ sudo apt install git

gitをインストールしたら、V言語のソースコードをGitHubからダウンロードしてビルドする。

$ git clone https://github.com/vlang/v
$ cd v
$ make

ビルドが終わったら、vコマンドを使えるようにするために、リンクを作成する。

$ sudo ./v symlink

これでvコマンドが使えるようになる。また、これからもしV言語をアップデートしたくなれば、v upと打つだけでアップデートが開始する。

VCCのビルド

次に、VCCのビルドをしていく。

まずはVCCのソースコードをGitHubからダウンロードする。

$ git clone https://github.com/lemoncmd/vcc

終わったら、VCCのディレクトリに移り、ビルドする。

$ cd vcc
$ make

これで、vccという実行ファイルが作成される。

コンパイル方法

以下のコマンドで、アセンブリコードが出力される。

$ ./vcc hoge.c > hoge.s

そして、GCCでアセンブリコードをコンパイルする。

$ gcc -o hoge hoge.s

これでhogeという実行ファイルが作成される。
なお、今のところVCCはプリプロセッサを搭載していないため、プリプロセスしたい場合はGCCに任せる。

$ gcc -E -U__GNUC__ -o hoge2.c hoge.c

V言語での開発設計について

参考元のCコンパイラはC言語で書かれているため、いくつか設計上の差異が存在した。
その内容を以下にいくつか示す。

オブジェクト指向

まず、V言語にはグローバル変数が存在しない。
そこで、設計構造を移植する際には構造体のメンバを利用する。

// グローバル変数 global_var
int global_var;

// global_varを引数aの値に書き換える関数 hoge
void hoge(int a) {
  global_var = a;
}

C言語ではこのように書かれるものは、V言語では以下のように書かれる。

// 構造体 Something
struct Something {
// mut(書き換え可能)なSomethingのメンバ global_var
mut:
  global_var int
}

// Somethingのmut(構造体を書き換え可能)なメソッド hoge
fn (s mut Something) hoge(int a) {
  s.global_var = a
}

上のように、グローバル変数がメンバ、関数がメソッドになっている。
実際にC言語でグローバル変数が使われるケースではこのようなオブジェクト指向で事足りることが多いので、他のオブジェクト指向言語よろしくどんどん活用する。 なお、V言語では安全性のためにデフォルトで変数やメンバは宣言時以降は書き換えられないので、書き換えたいものはmutを付けて宣言する。

エラー構造

執筆中

「低レイヤ」以降の実装

ruiu氏の文書に書かれている機能は実装完了したので、それ以降の機能についていくつか知見を記す(未実装もあり)。

型(unsigned, void, float等)

初期化

do文

switch文

引数

構造体

プリプロセッサ

V言語コンパイラを改善する

現在の進捗

おわりに

いかがでしたか?

よく分かりませんでしたが、V言語でCコンパイラは作れるようです。
今後も分かり次第情報を追加する予定です。