KDOC 27: Cコンパイラを書く

この文書のステータス

  • 作成
  • レビュー

コード追加中。

概要

compilerを作成する。自作言語だとだるくなるので、C languageの言語仕様でコンパイラを作る。

  • 8ccを参考にする。アセンブラの部分が参考になる
  • いきなりGoを書いているけど、いったん理解してからがいい感じがする…
  • パーサーとかレキサーを他から持ってきているので、乖離していく
  • ちょっとずつ進めること、動作テストコードを書く。各コミットでテストがあるので、追いつくことはできる
  • まだ1文しか考えなくてよい

導入

背景。

Tasks

TODO 8ccを読む

まず全体像を把握する。

TODO 終端のチェックをやる

セミコロンをチェックする。

TODO 変数宣言まわりで式の評価順が間違っているのを直す

なぜか違う値になる。

echo 'int a = 1;a+2' | go run ./main.go > gogo.s
.text
        .global mymain
mymain:
        mov $1, %eax
        mov %eax, -4(%rbp)
        mov $2, %eax
        push %rax
        mov %eax, -4(%rbp)
        pop %rbx
        add %ebx, %eax
        ret

TODO identの許容文字を明示する

小文字、大文字、アンダースコアのみにする。

Archives

DONE 関数呼び出しを実装する

関数定義は後でやる。

DONE charを実装する

文字列と同じ感じでいけそう。

DONE 文字列のテスト落ちを直す

テスト用のCの関数がintを返すようになっているから、文字列は返せないんだな。8ccではASTで文字列を返すようになっているので、同じ感じにする。

DONE identを直す

envが初期状態のままになっているようだ。分岐の箇所を間違っていた。

DONE stringを直す

データラベルが必要。

DONE 文字列テストを書き直す

printf関数を使って文字列テストをやる。

CLOSE DeclStatementは中置演算子で書けないか

いや、今のコミット時点の8ccと同じように合わせておくのが安全そう。いきなり大変になるし。

宣言文は int a = 1 みたいな文。

別枠にしているが、中置演算子で共用するときれいにかけるのではないか。型名がなければ代入文で完全に中置にできる。

int a “=” 2

今はidentが特定の名前だったらトークン認識するが、これは最初の判定にイコールを使ったほうがよさそうだ。代入しなおすときに型名はないから。イコールを使えば中置演算子とできそう。

  • 宣言文と代入文は使う関数を変えたほうがいいのだろうか
  • 各ast構造体に型を追加する
    • プリミティブ型だけで必要。それぞれintのときは…とかで分岐するから、共通でなくていい

DONE astのidentをvarにする

astの時点でidentの中の、varと確定できるので。lexerの時点ではidentのまま。

DONE ctypeを追加する

  • それぞれのASTにctypeを追加する
    • 不定なものと、確定しているものがある
  • identをCTYPEに変換する関数を追加する
  • 型演算の結果を出す関数を追加する

DONE ast読み込みの時点で変数を確定する

今は変数の確認をasmでやっていて確定するが、それをparserでやる。うーん、変数の確認をするにはobjectを持ってくる必要があるが、面倒だな。

monkeyではevaluatorでやってる。インタプリタではそうするのが自然に思える。とにかく、コンパイルするので事前にそれぞれの型を確定して、チェックする必要がある。

とりあえずparserにobjectsを保存するようにして、取り出して確定できるようにする。

  • 関数呼び出しを、変数と解釈してしまっている。
  • f(1) で、 f が見つからないエラー。
  • f() がidentになっているのが問題
  • token.identは共用のもので、ast.callとast.varに分岐させたい