%{ /* C宣言部 ─ 動作記述の中で用いる関数の定義や宣言 */ #include <stdio.h> #include <ctype.h> /* isdigitのため */ void yyerror(char* s) { /* エラーがあった時に呼ばれる関数を定義しておく */ printf("%s\n", s); } %} /* Bison宣言部 */ %union { /* 各文法記号の``値''となりうる型を C言語の unionで表す。 この例の場合 NUMBERという終端記号と exprという非終端記号は、 double型の``値''を持っているので、double dval;は必要。 また、この例題の場合 int ival;は不要だが、例として示しておく。 */ int ival; double dval; } /* 終端記号と非終端記号の宣言 */ /* <dval>はその文法要素が double型を持つことを宣言する (上の union宣言参照) */ %token <dval> NUMBER %token EOL %type <dval> expr /* 演算子の優先順位と結合性の宣言 */ %left '+' '-' %left '*' '/' /* leftは左結合を表す、下の演算子ほど優先順位が高い */ %right UMINUS /* UMINUSは優先順位の指定だけに使われる文法記号 */ %% /* 文法記述とそれに対する動作 */ input : /* 空 */ | input line {} ; 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; } | '-' expr %prec UMINUS { $$ = - $2; /* %prec以下は優先順位を表す。*/} ; %% /* yylex関数を flexを使わず自分で定義している。*/ int yylex() { int c; do { c = getchar (); } while (c == ' ' || c == '\t'); if (isdigit (c) || c == '.') { ungetc(c, stdin); scanf("%lf", &yylval.dval); /* ``値''は yylvalという 大域変数に代入して返す。*/ return NUMBER; /* NUMBERというトークンを返す。*/ } if (c == '\n') { return EOL; } if (c == EOF) { return 0; /* 終了を表す。*/ } /* 上のどの条件にも合わなければ、文字をそのまま返す。*/ return c; } int main() { yyparse(); /* Bisonが生成した関数 */ return 0; } /* この例では、mainを自前で用意しているが、通常は他のファイルに main関数など他の関数を定義する。 */
bison parser.yというコマンドを実行します。 これで parser_tab.cという名前 (.yファイルの名前の後ろに _tabがつく)の Cソースファイルができます。 また、-oというオプションで、 Cのファイル名を指定することができます。例えば、
bison -ofoo.c parser.yで foo.cという名前の Cソースファイルができます。
この例の場合は、この Cソースファイルを普通にコンパイルすると、 実行可能ファイルができます。