Cコンパイラを作る-その3
以下のサイトを参考にCコンパイラを書いていきます.エラーが出たところとかをメモがわりに残していきながらやっていきます. www.sigbus.info
僕の現状の実装 github.com
STEP12
if else while for
などの予約語が増えててきたので以下のように配列を用意してそこから一致するものがあれば予約語,なければ変数になるようにしました.
char *reserve_word[] = { "==", "!=", "<=", ">=", "if", "else", "while", "for" }; int get_reserved_len(char *p) { for (int i = 0; i < 8; i++) { if (memcmp(p, reserve_word[i], strlen(reserve_word[i])) == 0) { return strlen(reserve_word[i]); } } return 0; }
int len = get_reserved_len(p); if (len != 0) { cur = new_token(TK_RESERVED, cur, p, len); p += len; continue; }
パース部分に関しては正直ごちゃごちゃになってしまいましたが,一応動作はするような形になりました.構文木等を気にせずとりあえず動作すればいい精神で書いてしまった部分があるので後々リファクタリングしたいです.
STEP13
ブロックに関しては,ブロックが終了するまでステートメントノードをつなげるような形にしました.コード生成時に最初まで遡ってから順に出力していくことで順番が担保できると思ってます.ブロックに含まれる式のベクタとかが正直よくわからなかったのですが,現状それっぽく動いてるのでよしとします.
Node *block() { Node *node = stmt(); if (check("}")){ consume("}"); return node; } return new_node(ND_BLOCK, node, block()); }
Cコンパイラを作る-その2
以下のサイトを参考にCコンパイラを書いていきます.エラーが出たところとかをメモがわりに残していきながらやっていきます. www.sigbus.info
僕の現状の実装 github.com
STEP9
比較演算子の部分を考慮しながらサイトを参考に書いていきました.
サイトではconsume_ident()
を作成して変数を読み進めるような形式を取っていましたが,僕は数値に寄せる形でnew_node_ident()
を作成して変数を読み進めるような形を取りました.
「;」をつけないと今までのテストが動かないので注意です.
STEP10
localsの初期化はprogram()
内で,offsetが0のLVarを作成して行いました.
tokenize部分では以下のように複数文字受け入れるように変数取得部分を変更しました.
if('a' <= *p && *p <= 'z') { cur = new_token(TK_IDENT, cur, p++, 1); int i = 0; while ('a' <= *p && *p <= 'z') { i++; p++; } p -= i; cur = new_token(TK_IDENT, cur, p, i); p += i; continue; }
STEP11
consume(TokenKind)
を実装しないで,数値や変数と同じように処理する場合にはnode->lhs=expr()
する前にtoken = token->next
をしないとトークンがTK_RETURNのまま進んでしまうので注意です.
https://github.com/arato-make/9cc/commit/893c5fbdb01a3a0cb1e8d5298c9d7b03bdef5567
Cコンパイラを作る-その1
下記のサイトを参考にしながらCコンパイラを作っています. エラーが出たところとかをメモがわりに残していきながらやりたいと思います.
https://www.sigbus.info/compilerbook
僕の現状の実装経過
STEP4
error_at(token->str, "数ではありません")
にコードをアップデートするとあるが,tokenizeの中ではtokenに値が代入されていないため,token->strではなく以下のようにpを渡すようにする.そうしないとトークナイズできなかった際にSegmentation faultが起こってしまう.
error_at(p, "トークナイズできません");
user_inputを初期化し忘れると無限ループするので注意.
STEP6
リファレンス実装とサイト実装で単項を複数受け入れるかどうかで実装差が存在していた.リファレンス実装のほうのテストコードを参考にしてテストしようとすると通らないので注意.
リファレンス実装では単項を複数受け入れるような実装にしているため「- - 1」などが解釈できるようになっているが,サイト実装では解釈できない.
STEP7
token->strには該当トークン部分の文字列だけしか入っていないと思ってしまっており,new_tokenする際に二文字だけ渡すようなコードを書こうとしてしまった.token->strは該当トークン文字列が始まるポインタが入っているので,そこから何文字を解釈するかを表すlenだけで特に他の変更は必要なかった.
STEP8
今まで作成したtest.cとか残ってるとmainが複数あるよってエラー出る.