/* 再帰的下向き構文解析プログラム (以下の文法に対する構文解析プログラム) Expr -> CON | FID '(' List ')' List -> Expr Rest Rest -> ',' Expr | ε -- 以下は終端記号: 字句解析部で処理 CON -> '0' | '1' | ... | '9' -- 一桁の数のみ FID -> '+' | '-' | '*' | '!' -- 予測型構文解析表 CON FID ( ) , $ Expr CON FID '(' List ')'× × × × List Expr Rest Expr Rest × × × × Rest × × × ε ',' Expr × */ #include #include /* exit() 用 */ #include /* isdigit() 用 */ /* 大域変数の宣言 */ int token; /* 入力の先頭のトークンを表す */ int yylval; /* token の属性 */ int column = 0; /* デバッグ用 */ /* 終端記号に対応するマクロの定義 */ #define CON 256 #define FID 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 CON; } if (c == '+' || c== '-' || c == '*' ||c =='!') { yylval = c; return FID; } if (c == EOF) { /* ファイルの終 */ exit(0); } /* 上のどの条件にも合わなければ、文字をそのまま返す。*/ return c; /* '(', ')', ',', '\n' など */ } /* デバッグ用 */ char* tokenName(int t) { switch (t) { case '\n': return "(End of Line)"; case 256: return "CON"; case 257: return "FID"; 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 Expr(void); void List(void); void Rest(void); /* 再帰的構文解析関数群 文法の各非終端記号に対応する関数 */ void Expr(void) { switch (token) { case CON: eat(CON); break; case FID: eat(FID); eat('('); List(); eat(')'); break; default: errMessage("Expr"); exit(1); break; } } void List(void) { if (token == CON || token == FID ) { Expr(); Rest(); } else { errMessage("List"); exit(1); } } void Rest(void) { switch (token) { case ',': eat(','); Expr(); break; case ')': /* do nothing */ break; default: errMessage("Rest"); exit(1); break; } } /* 各行の処理 */ void processLine(void) { Expr(); 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; }