%{ /* C 宣言部 ─ 動作記述の中で用いる関数の定義や宣言 */ #define YYSTYPE double /* トークンの属性の型を宣言 */ #include #include /* exit 関数を使うため */ #include /* isdigit 関数を使うため */ void yyerror(char* s) { /* エラーがあった時に呼ばれる関数を定義しておく */ printf("%s\n", s); } int yylex(void); %} /* Bison 宣言部 */ /* 終端記号(トークン)(と非終端記号)の宣言 */ /* トークンは定数マクロとして定義される */ /* トークンとして使えるのは文字コードかここで定義したマクロ */ %token NUMBER /* 曖昧な文法に対して演算子の優先順位と結合性を宣言できる */ %left '+' '-' %left '*' '/' /* left は左結合を表す。ちなみに、右結合は right, 非結合は nonassoc となる。 */ /* 優先順位が高い演算子ほど下に書く。 */ %% /* 文法記述とそれに対する動作(還元時に実行されるプログラム) */ /* 最初に start symbol を書く */ input : /* 空 */ | input line {} ; /* 通常の BNF の → の代わりに : を書く。各 BNF は ; で区切る。 */ line : '\n' { exit(0); } | expr '\n' { printf("\t%g\n", $1); } ; /* $$ は左辺の属性値、$n は右辺の n 番目の文法要素の属性値を表す。 */ expr : NUMBER { $$ = $1; } | expr '+' expr { $$ = $1 + $3; } | expr '-' expr { $$ = $1 - $3; } | expr '*' expr { $$ = $1 * $3; } | expr '/' expr { $$ = $1 / $3; } | '(' expr ')' { $$ = $2; } ; %% /* 追加の C プログラム */ /* yylex(字句解析)関数を flex を使わず定義している。yylex の戻り値は、トークン。*/ int yylex() { int c; do { c = getchar (); } while (c == ' ' || c == '\t'); if (isdigit (c) || c == '.') { ungetc(c, stdin); scanf("%lf", &yylval); /* トークンの属性値は yylval という 大域変数に代入して返す。*/ return NUMBER; /* NUMBER というトークンを返す。*/ } else if (c == EOF) { return 0; /* 終了を表す。*/ } /* 上のどの条件にも合わなければ、文字をそのまま返す。*/ return c; } int main(void) { printf("Ctrl-c で終了します。\n"); yyparse(); /* Bison が生成した関数 */ return 0; } /* この例では、main を自前で用意しているが、通常は他のファイルに main 関数など他の関数を定義する。*/