%{ /* C宣言部 ─ 動作記述の中で用いる関数の定義や宣言 */ #define YYSTYPE double /* トークンの属性の型を宣言 */ #include <stdio.h> #include <stdlib.h> /* exit関数を使うため */ #include <ctype.h> /* isdigit関数を使うため */ void yyerror(char* s) { /* エラーがあった時に呼ばれる関数を定義しておく */ printf("%s\n", s); } %} /* Bison宣言部 */ /* 終端記号と非終端記号の宣言 */ %token NUMBER %token EOL /* 演算子の優先順位と結合性の宣言 */ %left '+' '-' %left '*' '/' /* leftは左結合を表す、ちなみに右結合は right、非結合は nonassocとなる。 */ /* 下の演算子ほど優先順位が高い。 */ %% /* 文法記述とそれに対する動作 */ /* 最初に start symbolを書く。 */ 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; } ; %% /* 追加の Cプログラム */ /* yylex(字句解析)関数を flexを使わず自分で定義している。*/ int yylex(void) { int c; do { c = getchar (); } while (c == ' ' || c == '\t'); if (isdigit (c) || c == '.') { ungetc(c, stdin); scanf("%lf", &yylval); /* トークンの属性値は yylvalという 大域変数に代入して返す。*/ return NUMBER; /* NUMBERというトークンを返す。*/ } if (c == '\n') { return EOL; } if (c == EOF) { return 0; /* 終了を表す。*/ } /* 上のどの条件にも合わなければ、文字をそのまま返す。*/ return c; } int main(void) { printf("Ctrl-cで終了します。\n"); 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ソースファイルを普通にコンパイルすると、 (警告(Waring)がいくつか出ますが) 実行可能ファイルができます。