[C] コンパイラ作成 (関数呼び出しに対応する)

関数呼び出しに対応するの大変でした。 正しいかわかりませんが、生成規則を以下のように定義しました。 (試行錯誤のすえ以下のようになったのですが...) ``` `gutter:true; program: stmt program program: ε stmt: assign ";" assign: equality assign: equality "=" assign equality: add equality: add "==" equality equality: add "!=" equality add: mul add: add "+" mul add: add "-" mul mul: func mul: mul "*" func mul: mul "/" func func: ident "(" argument ")" func: term argument: equality argument: equality "," equality argument: ε term: num term: ident term: "(" assign ")" digit: "0" | "1" | "2" | "3" | "4" | "5 | "6" | "7" | "8" | "9" ident: "a" - "z" ``` funcの定義をmulより下に持ってきてさらに引数用のargumentを定義しました。 新しくfuncとargumentを導入したので、コード生成の部分にもそれぞれのパターンを定義してパースしたらうまく動きました。 一旦最大の引数は6個までを制限にしています。 ```c void gen(Node *node) { : if (node->ty == ND_FUNCTION) { // 引数がある場合は引数を評価 if (node->rhs != NULL) { gen(node->rhs); } // 引数をレジスタにセット gen_arguments(node->name, node->val); // 関数名を指定して実行 printf(" call %s\n", node->name); // 結果をスタックに入れる printf(" push rax\n"); return; } if (node->ty == ND_ARGUMENT) { // 引数を評価 gen(node->lhs); gen(node->rhs); return; } : ``` あと、RSPを16の倍数にするとの事ですが、変数領域を確保するところで16の倍数にするようにしたのですがよかったのでしょうか。 ```c `gutter:true; : // プロローグ // 変数の数分の領域を確保する // 関数呼び出しをする際にはRSPが16の倍数になっている必要があるとのこと // ココで調整しているけど、正しい? int size_of_variables = variables->keys->len * SIZE_OF_ADDRESS; int rsp_offset = size_of_variables % 16; size_of_variables += rsp_offset; printf(" push rbp\n"); printf(" mov rbp, rsp\n"); printf(" sub rsp, %d\n", size_of_variables); : ``` 実装したものが動作するかどうかはテスト用の関数が入ったソースを用意して 実際に動作させて確認します。 ```bash `gutter:false; $ ./9cc "a = hoge(1, 2) * 3;" > tmp.s $ gcc -o tmp tmp.s test.o $ ./tmp $ echo $? # 結果の値になるはず ``` ひとまず動作したのでよしとします。 ## 参考URL * [低レイヤを知りたい人のためのCコンパイラ作成入門](https://www.sigbus.info/compilerbook) * 進捗は[ここ](https://github.com/k28/9cc)

0 件のコメント :

コメントを投稿