%{
/* 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ソースファイルを普通にコンパイルすると、 実行可能ファイルができます。