Cの自作コンパイラにおいてdo-while文を実装したいのですが、syntax errorになってしまいます。以下のコードのdo-while文においてどのように修正すればよいか教えていただきたいです。以下に関連ファイルを載せておきます。
yacc
1%token NUM; 2%token IDENT; 3%token READ; 4%token PRINT; 5%token WHILE; 6%token IF; 7%token DO; 8%left '+' '-'; 9%left '*' '/'; 10%% 11 12prog : IDENT '{' stlist'}' { dotree($3); return 0; } 13; 14stlist : { $$ = 0; } 15| stlist stat { $$ = node(T_STLIST, $1, $2); } 16; 17stat :var '=' expr ';' { $$ = node(T_ASSIGN, $1, $3); } 18| READ var ';' { $$ = node(T_READ, $2, 0); } 19| PRINT expr ';' { $$ = node(T_PRINT, $2, 0); } 20| WHILE '(' cond ')' stat { $$ = node(T_WHILE, $3, $5); } 21| IF '(' cond ')' stat { $$ = node(T_IF, $3, $5); } 22| DO '{' expr '}' stat { $$ = node(T_DO, $3, $5); } // do-whileを表現する構文規則 23| '{' stlist '}' { $$ = $2; } 24; 25cond : expr '<' expr { $$ = node(T_LT, $1, $3); } 26| expr '>' expr { $$ = node(T_GT, $1, $3); } 27; 28expr : term { $$ = $1; } 29| expr '+' term { $$ = node(T_ADD, $1, $3); } 30| expr '-' term { $$ = node(T_SUB, $1, $3); } 31; 32term: prim{ $$ = $1; } 33| term '*' prim { $$ = node(T_MUL, $1, $3); } 34| term '/' prim { $$ = node(T_DIV, $1, $3); } 35| term '%' prim { $$ = node(T_REM, $1, $3); } 36; 37prim : NUM { $$ = node(T_NUM, atoi(yytext), 0); } 38| var { $$ = node(T_VAR, $1, 0); } 39| '(' expr ')' { $$ = $2; } 40; 41var : IDENT { $$ = lookup(yytext); } 42;
test.uec
1main { 2 read x; 3 i = 0; 4 do{ // ここのdo-whileを実装したいです。 5 i = i + x; 6 x = x - 1; 7 }while(x > 0); 8 print i;
lex
1alpha [a-zA-Z] 2digit [0-9] 3white [\n\t ] 4%% 5while { return WHILE; } 6if { return IF; } 7do { return DO; } // ここも正しいか不明 8read { return READ; } 9print { return PRINT; } 10{alpha}({alpha}|{digit})* { return IDENT; } 11{digit}+ { return NUM; } 12[-+()=;{}<>*/%] { return yytext[0]; } 13{white} { ; }
試せる環境がないので、間違っていたらすみません。
| DO stat WHILE '(' cond ')' ';' { $$ = node(T_DO, $5, $2); } // do-whileを表現する構文規則
actorbugさんの通りにするとyaccのコンパイルエラーが解消されました!
しかし、まだdo-whileを実行できません。おそらく以下のCコードに問題があるのですが、どこが問題かわかりますでしょうか??
ちなみにwhileは正常に動きますので、whileと一緒に掲載します。
---------------------------------------
case T_WHILE: l = labelno++; //ラベル更新
printf(".L%d:\n", l); // ラベル l を生成
emittree(ntab[i].left); // 条件文の判定
printf(".L%d\n", l+1); // 条件を満たさなかったら l+1 のラベルに移動
emittree(ntab[i].right); // while文の中身を実行
printf("jmp .L%d\n", l); // ラベル l に移動
printf(".L%d:\n", l+1); // ラベル l+1 を生成
break;
case T_DO: l = labelno++; // ラベルを更新
printf(".L%d:\n", l); // ラベル l を生成
emittree(ntab[i].right); // doの部分を実行
emittree(ntab[i].left); // whileの条件文を実行
break; // 条件を満たさなかったら終了
printf("jmp .L%d\n", l); // ラベル l に移動
}
-----------------------------------
長文失礼しました。問題点がわかりそうでしたら指摘をお願いいたします。
正直コード生成系はさっぱりですが、emittree(ntab[i].left);直後にbreakしたら駄目なのは分かります。
現在実行中のコードと生成中のコードの区別がついていないのではないでしょうか。
yaccの記述も、どういう理屈で解釈されるか「理解」できていれば簡単に書けたはずです。
case T_DO:についても、case T_WHILE:の動作原理を「理解」できていれば簡単に書けます。
他人に頼っていたら、いつまでたっても自力で書けるようにはなりません。
まずはT_WHILEを本当の意味で「理解」できるよう努力することをお勧めします。
T_WHILEは上記のコメントで動作を正しく説明できていると考えています。T_WHILEの本当の意味はコメントの内容とは違うのでしょうか?
