必要なファイル
interp_main.c AST.c cparser.c clex.c interp.c interp_expr.c AST.h
makefile
"**.c"なファイルは一旦オブジェクトファイルにする。
コンパイルして→"**.o"に。
で、makeする。
cc -o tiny-c-run interp_main.o AST.o cparser.o interp.o interp_expr.o
あとはファイルから入力して実行。
まず、文の処理でも最も簡単なif文の処理から説明をしよう。 if文のASTは、左に条件式、右に条件が成立した時に実行される文(then部)の ASTと条件式が成立しなかった時に実行される式(else部)のリストが入っている。これを、取り出して、if文を実行するexecuteIfを呼び出す。
case IF_STATEMENT: executeIf(p->left,getNth(p->right,0),getNth(p->right,1)); break;
executeIfは以下のようになる。
interp.c
void executeIf(AST *cond, AST *then_part, AST *else_part) { if(executeExpr(cond)) executeStatement(then_part); else executeStatement(else_part); }
まず、executeExprで条件式を実行し、その結果によって、then部かelse部の式をexecuteStatementを呼び出して実行する。
制御文であるwhile文のASTは、左の条件式、右に条件が成立している間実行される文が入っている。これを取り出して、executeWhileを実行する。
case WHILE_STATEMENT: executeWhile(p->left,p->right); break;
executeWhileでは、executeExprで条件式を実行し、これが真、すなわち0でない間、本体の文を実行すればよい。
interp.c
void executeWhile(AST *cond,AST *body) { while(executeExpr(cond)) executeStatement(body); }
このほかにも、for文などの制御構造も、シンタックスを決め、その意味にしたがってどの部分を実行するかを制御すれば実装することができる。 (for文については、わざとぬいてあるので、作ってみること)
通常使っているコンパイラでは、途中で文法エラーを見つけたとしてもなるべく、他の部分もparseして一度に多くの文法エラーを見つけることができるようにしてある。文法エラーを見つけたときに、次にどこから構文解析を再開するかの処理をエラーからの回復処理という。どこから処理を再開するか、どうやって再開するかについてはコンパイラの使いやすさの要素の一つにもなり、結構むずかしい問題である。ここでは、yaccでの簡単なエラー処理だけについて述べておく。
yaccでは、予約の非終端記号として、errorという予約語があり、yyerrorが呼び出されて、これが終了(retrun)すると、errorという記号にreduceされるように処理してある。例えば、
statement: .... | error ';' ;
とすることによって、statementの構文解析で文法エラーが起きた場合には、';' がくるまで読みとばす処理をすることになる。
448New! 名前:初心者 投稿日:2006/01/29(日) 21:13:56 質問です。 Yaccとかで論理式の短絡評価を行う常套手段はどのようなものでしょうか? 例えば、if(a==b||c==d) でa==bが確定するとc==dの評価はスキップ可能ですが、 Yaccとかだと、先にa==bとc==dが認識されてしまうと思うのです。
449New! 名前:デフォルトの名無しさん 投稿日:2006/01/29(日) 21:53:31 >>448 yaccが生成するのは構文解析器。 意味解析は通常は構文解析で構文木を作った後のステップであって、yaccはやってくれません。 [文字列]→字句解析→[トークン列]→構文解析→[構文木]→意味解析→[一時コード]→最適化→[ましなコード]→コード生成→[出力コード] というように道のりは長い。 yaccがやってくれるのは構文解析だけ(でも構文解析は最適化の次に面倒くさい部分なので大助かり)。
Expression->Section->N-Factor->式->項->数値(数字ではない!)
で、
Factor->C_Factor->Ident->文字
さらに、
Factor-> C_Factor|N_Factor
書き換えて
Factor->N-Factor->式->項->数値(数字ではない!)
とすると、今度は
//繰り返し文 Repetition_state : Repetition_head LM Statement Condition_part Connect_par Statement RM Statement | LM Condition_part RM // | Statement CONJ LM Condition_part RM ;
//繰り返し接頭語 Repetition_head : LOOP /*| KURIKAESI */ ;