%{ /* C宣言部 ─ 動作記述の中で用いる関数の定義や宣言 */ #define YYSTYPE double /* トークンの属性の型を宣言 */ #include #include /* exit関数を使うため */ #include /* isdigit関数を使うため */ void yyerror(char* s) { /* エラーがあった時に呼ばれる関数を定義しておく */ printf("%s\n", s); } int yylex(void); %} /* Bison宣言部 */ /* 終端記号(と非終端記号)の宣言 */ /* 終端記号は定数マクロとして定義される */ %token NUMBER %token EOL /* 曖昧な文法に対して演算子の優先順位と結合性を宣言できる */ %left '+' '-' %left '*' '/' /* leftは左結合を表す。ちなみに、右結合は right, 非結合は nonassocとなる。 */ /* 優先順位が高い演算子ほど下に書く。 */ %% /* 文法記述とそれに対する動作(還元時に実行されるプログラム) */ /* 最初に start symbolを書く */ input : /* 空 */ | input line {} ; /* 通常の BNFの → の代わりに : を書く。各BNFは ; で区切る。 */ line : EOL { exit(0); } | expr EOL { printf("%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 == '\n') { return EOL; } else if (c == EOF) { return 0; /* 終了を表す。*/ } /* 上のどの条件にも合わなければ、文字をそのまま返す。*/ return c; } int main(void) { printf("Ctrl-cで終了します。\n"); yyparse(); /* Bisonが生成した関数 */ return 0; } /* この例では、mainを自前で用意しているが、通常は他のファイルに main関数など他の関数を定義する。*/