codepad
[
create a new paste
]
login
|
about
Language:
C
C++
D
Haskell
Lua
OCaml
PHP
Perl
Plain Text
Python
Ruby
Scheme
Tcl
/******************************************************** * 再帰的下降型構文解析の例 * E: expressionを加減算の結果とする * T: term を乗除算の結果 * F: factor 項(被演算子)とする * n: numeric 値(簡単のため1文字) * * 構文規則(BNF) * <L>::= <E> '\n' * <E>::= <T> { {+|-} T} * <T>::= <F> { {*|/} <F> } * <F>::= n | ( <E> ) * 応用練習問題 1)Pーマシン言語に翻訳する 2)一桁の数字からなる式の計算する電卓プログラムに改造する。 (2+8)/(7-4) * 5 15 ********************************************************/ #include <stdio.h> void scan(); void error(); typedef int val_type; /* 浮動小数点演算なら double へ */ void print_val(val_type val) { printf("-> %d\n", val); /* 浮動小数点演算なら %lf に */ } val_type E(); /* 非終端記号Eを解析する関数 戻りは計算値 */ val_type T(); /* 非終端記号Fを解析する関数 戻りは計算値 */ val_type F(); /* 非終端記号Tを解析する関数 戻りは計算値 */ char next; /*次のトークン*/ /******************************************* * <L>::= <E> 改行文字 * lineは開始記号なので * プログラムを短くするためmainにしてしまう ******************************************/ int main (int argc, char* argv[]) { val_type v; scan(); printf("L--->E\n"); v = E(); if (next != '\n') error(); print_val(v); exit(0); } /***************************************************** * トークン(非終端記号)を読みこむ関数 * 空白(タブはないものとして)を読み飛ばす * 字句解析はしばしばスキャナーと呼ばれるので、ここではscan()とする。 ****************************************************/ void scan() { while ( (next = getchar()) == ' '); } /****************************************************** * 簡単のためエラー回復なし、で構文解析終了とする *****************************************************/ void error() { printf("*********error**********\n"); exit(1); } /***************************************** * <E>::= <T> { {+|-} T } * * 解析プログラム E( ): * 最初のトークンは既に読まれている * T(); * while(トークン == 加算演算子) { * 次のトークンを読む(); * T(); * } * 戻るときは次のトークンまで読んでいる *****************************************/ val_type E() { val_type v1, v2; printf("E--->T <E-rest> \n"); v1 = T(); if (next !='+' && next !='-') printf("<E-rest>--->empty\n"); while (next == '+' || next == '-') { int c = next; /* 後ろの処理で next が変わるので保持 */ printf("<E-rest> ---> %c T\n", next); scan(); v2 = T(); /* ADDまたはSUBの演算 */ if (c == '+') { v1 += v2; } else if (c == '-') { v1 -= v2; } } return v1; } /*************************** * <T>::=<F> { {*|/} <F> } * *解析プログラムT(): * 最初のトークンは既に読まれている * F(); * while(トークン == 乗除演算子) { * 次のトークンを読む(); * F(); * } * 戻るときは次のトークンまで読んでいる ****************************/ val_type T() { val_type v1, v2; printf("T--->F <F-rest>\n"); v1 = F(); if (next !='*' && next !='/') printf("<F-rest>--->empty\n"); while (next=='*' || next=='/') { int c = next; /* 後ろの処理で next が変わるので保持 */ printf("<F-rest>---> %c F\n", next); scan(); v2 = F(); /* MULまたはDIVの演算 */ if (c=='*') { v1 *= v2; } else if (c=='/') { v1 /= v2; } } return v1; } /******************************************** * <F>::= <0-9の1文字> * | ( <E> ) * *解析プログラムF() * if (トークン == 値) { * 次のトークンを読む(); * } * else if (トークン == 括弧開き) { * 次のトークンを読む(); * T(); * 括弧閉じを確定 * 次のトークンを読む(); * } * 戻るときは次のトークンまで読んでいる ********************************************/ val_type F() { val_type v; if (next >='0' && next <= '9') { printf("F--->id(%c)\n", next); /* LOAD */ v = (val_type)(next - '0'); scan(); } else if (next == '('){ printf("F --->( E )\n"); scan(); v = E(); if (next == ')') { scan(); } else error(); } return v; }
Private
[
?
]
Run code
Submit