関数呼び出しに対応するの大変でした。
正しいかわかりませんが、生成規則を以下のように定義しました。
(試行錯誤のすえ以下のようになったのですが...)
```
`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 件のコメント :
コメントを投稿