今までの知識を使って C 言語を勝手に拡張してみよう。 foreach ステートメントを導入する。以下のようなコードをコンパイルできるようにしたいわけだ。
/* foreach.c */ int main() { int i; char msg[] = "hello\n"; foreach (i; msg) { printf("%c", msg[i]); } }
もちろん、まだ意味解析を調べていないため、本格的に作成することはできない。しかし、先程既に for_stmt を調べているため、 foreach を見つけたら for の木を作ってやることによって実現することは可能なのではないか。
さて c-parse.in に foreach を教えてやる。該当個所はすぐにわかると思う。
%token SIZEOF ENUM STRUCT UNION IF ELSE WHILE DO FOR FOREACH SWITCH CASE DEFAULT
{ "for", RID_FOR, 0 }, { "foreach", RID_FOREACH, 0 },
/* RID_FOR */ FOR, /* RID_FOREACH */ FOREACH,
| FOREACH /* empty */ { printf("foreach comes!\n"); } | SWITCH '(' expr ')'
これで foreach.c をコンパイルすると、確かに foreach comes! と表示される。字句解析の拡張は成功したようだ。では構文解析部も作ってしまおう。四苦八苦した後、
| FOREACH '(' primary ';' primary ')' { tree init, cond, expr; init = build_stmt( EXPR_STMT, build_modify_expr($3, NOP_EXPR, integer_zero_node)); cond = parser_build_binary_op(LT_EXPR, $3, c_sizeof(TREE_TYPE($5))); expr = build_unary_op(POSTINCREMENT_EXPR, $3, 0); $$ = build_stmt (FOR_STMT, init, cond, expr, NULL_TREE); add_stmt($<ttype>$); stmt_count++; c_in_iteration_stmt++; } c99_block_lineno_labeled_stmt { RECHAIN_STMTS ($<ttype>7, FOR_BODY ($<ttype>7)); c_in_iteration_stmt--; }
とすると動いた!これはうれしい。すなおにうれしい。つまらんデバッグを除けば、生まれて始めて gcc の hack に成功したわけだ。ああうれしい。ほんとにうれしい。
冷静に書こう。最初に述べた通り、これは foreach を for に歪めているだけに過ぎない。常識的に考えて FOREACH_STMT を作成して、意味解析でコード生成を行うべきだし、エラー処理も全くしていない。上記のコードは説明を書いていない部分が多いが、ただ for の構成要素を作るコードを呼び出しているだけだし、別に面白くもないので説明しない。
構文解析はこんなもんで終わりだろうか。たぶん次は意味解析、 RTL生成。ここまでは難しくなかったが wo さんをしてさえ RTL 生成は難しいらしい のでまあゆっくり読もう。