# 低レイヤを知りたい人のためのCコンパイラ作成入門 ## 動機 低レイヤーに興味があり、C/C++ユーザーとして一度はコンパイラを自作すべきだと思っていた。 ## 目標 1. 完走すること。 2. (1ができたら)セルフホストを目指す 3. (2ができたら)自作OSのCソースを自作コンパイラでコンパイルする(i386-elf-gccでコンパイルしているコードは標準ライブラリを使用していないので、ヘッダーファイル読み込みといくつかのgccビルトイン関数を実装できればできそう) ## 実行環境 Mac(M1) ## 環境構築 Dockerイメージを作成する。 ``` $ docker build -t compilerbook https://www.sigbus.info/compilerbook/Dockerfile ``` :::danger M1Macだとアセンブリがうまくいかないので、Dockerfileを書き換えてビルドし直す必要がある。 ```diff - FROM ubuntu:latest + FROM amd64/ubuntu:latest ``` ::: コンテナを立ち上げコマンドを実行するには、引数にイメージ名とコマンドを与える。 ``` $ docker run --rm compilerbook <command> ``` ```--rm```オプションを与えることで、コマンドが終了し次第コンテナも終了する。 コンテナ内でローカルのコードを実行したい場合は、以下のようにする。 ``` $ docker run --rm -v <source>:<dest> -w <working-dir> compilerbook <command> ``` コンテナ内でシェルを起動したい場合は、 ``` $ docker run --rm -it -v <source>:<dest> compilerbook ``` ## 機械語とアセンブラ(2023/10/15) 自作OSで、NASMで関数を実装したことがあったので簡単に読み進めることができた。 NASMだと関数ポインタが```ESP```に入って引数が```ESP+4```以降、戻り値は```EAX```に格納する、という決まりだった気がするので、そこは少し混乱した。 :::info レジスタ名の接頭辞: 無印(16bit)、E(32bit)、R(64bit)らしい ::: :::info 便利サイト:[Compiler Explorer](https://godbolt.org/)(通称godbolt) 左半分にコードを書くと右半分にアセンブリが出力される。 ::: ## 電卓レベルの言語の作成(2023/10/15) 「再帰下降構文解析法」(recursive descent parsing)を使う。 ``` $ docker run --rm -it -v $HOME/build_own_compiler:/home/user/compiler compilerbook ``` ### ステップ1:整数1個をコンパイルする言語の作成 電卓プログラム自体は何度か書いたことがあるので、それと同じ要領だろうか ### ステップ2:加減算のできるコンパイラの作成 ふむふむ ### ステップ3:トークナイザを導入 スペース読み飛ばしではなく、最初に部品に分割する方針。 ```consume```や```expect```といった関数は新鮮。 ```ctype.h```という便利そうな標準ライブラリを初めて知った。 ### ステップ4:エラーメッセージを改良 goto failバグの話 ### 文法の記述方法と再帰下降構文解析 「抽象構文木」(abstract syntax tree、AST) BNF(Backus–Naur form)、EBNF(Extended BNF) 「具象構文木」(concrete syntax tree) 作ったことのある数式解析アルゴリズムをちゃんと説明した感じ ### スタックマシン 木の葉から順に、スタックに格納→二項演算、を繰り返していく ``` cpo // RAXに入っている64ビットの値を128ビットに拡張 idiv rdi // RDX:RAX/RDI の商をRAXへ剰余をRDXへ格納 ``` > *「早すぎる最適化は全ての悪の元凶」(Donald Knuth)* ### ステップ5:四則演算のできる言語の作成 メモリ管理であえてfreeをしないという話。 ### ステップ6:単項プラスと単項マイナス ### ステップ7: 比較演算子 フラグレジスタとハードウェアの話。 ### ステップ8: ファイル分割とMakefileの変更