/* 再帰的下向き構文解析プログラム (以下の文法に対する構文解析プログラム) E -> C | F ( L ) L -> E R R -> , E | ε -- 以下は終端記号: 字句解析部で処理 C -> 0 | 1 | ... | 9 -- 一桁の数のみ F -> + | - | * | ! -- 予測型構文解析表 C F ( ) , $ E C F ( L ) × × × × L E R E R × × × × R × × × ε  , E × */ #include #include /* exit() 用 */ #include /* isdigit() 用 */ /* 大域変数の宣言 */ int token; /* 入力の先頭のトークンを表す */ int yylval; /* token の属性 */ int column = 0; /* デバッグ用 */ /* 終端記号に対応するマクロの定義 */ #define C 256 #define F 257 /* 簡易字句解析ルーチン */ int yylex(void) { int c; if (token == '\n') { /* 前のトークンが改行だったら */ column = 0; } do { c = getchar(); column++; } while (c == ' ' || c == '\t'); if (isdigit(c)) { yylval = c - '0'; /* 数字から数へ変換 */ return C; } if (c == '+' || c== '-' || c == '*' ||c =='!') { yylval = c; return F; } if (c == EOF) { /* ファイルの終 */ exit(0); } /* 上のどの条件にも合わなければ、文字をそのまま返す。*/ return c; /* '(', ')', ',', '\n' など */ } /* デバッグ用 */ char* tokenName(int t) { switch (t) { case '\n': return "(End of Line)"; case 256: return "C"; case 257: return "F"; default: return "(Unknown)"; } } /* token(終端記号)を消費して、次の token を読む */ void eat(int t) { if (token == t) { token = yylex(); return; } else { if (isprint(t)) { printf("eat: Character '%c' is expected at column %d ", t, column); } else { printf("eat: Token %s is expected at column %d ", tokenName(t), column); } if (isprint(token)) { printf("instead of '%c'.\n", token); } else { printf("instead of %s (code %d).\n", tokenName(token), token); } exit(1); } } /* エラーメッセージの出力 */ void errMessage(char* place) { if (isprint(token)) { printf("%s: Unexpected token: '%c' at column %d.\n", place, token, column); } else { printf("%s: Unexpected token: %s (code %d) at column %d.\n", place, tokenName(token), token, column); } } /* 関数プロトタイプ宣言 */ void E(void); void L(void); void R(void); /* 再帰的構文解析関数群 文法の各非終端記号に対応する関数 */ void E(void) { switch (token) { case C: eat(C); break; case F: eat(F); eat('('); L(); eat(')'); break; default: errMessage("E"); exit(1); break; } } void L(void) { if (token == C || token == F ) { E(); R(); } else { errMessage("L"); exit(1); } } void R(void) { switch (token) { case ',': eat(','); E(); break; case ')': /* do nothing */ break; default: errMessage("R"); exit(1); break; } } /* 各行の処理 */ void processLine(void) { E(); if (token == '\n') { /* 入力がブロックしないように改行は特別扱い */ printf("Correct!\n"); /* eat('\n') の前に出力しておく */ } eat('\n'); } /* main関数 */ int main(void) { printf("Ctrl-c で終了します。\n"); token = yylex(); /* 最初のトークンを読む */ while (1 /* 無限ループ */) { processLine(); /* 各行を処理する */ } return 0; }