Flex と Bison を併用する場合には、 Flex のソースファイル(mylexer.l)には次のような #include 文を入れておきます。 インクルードされるファイル(myparser.h)は Bison が生成するファイルで、 NUMBER や EOL などの Flex で使用する終端記号を表すマクロの定義が書かれています。
%{ void yyerror(char*); #define YY_SKIP_YYWRAP int yywrap(void) { return 1; } #include "myparser.h" /* myparser.hは bisonが生成するファイル */ %} %% [ \t]+ { /* ここでは何もしない */ } [0-9]+(\.[0-9]+)?(E[+\-]?[0-9]+)? { /* NUMBERという終端記号の種類を返す。その値(“属性”)は yylvalという大域変数に代入する。 */ sscanf(yytext, "%lf", &yylval); return NUMBER; } [+\-\*\/\(\)] { /* + - * / ( )の場合は、マッチした文字をそのまま返す。*/ /* マッチした文字は一般に yytext[0] 〜 yytext[yyleng-1]。*/ return yytext[0]; } "\n" { return EOL; } . { yyerror("不正な文字です。"); return EOL; } %% /* なにもなし */
動作の中に return 文を入れておくと、 その式の値が Flex の生成する yylex 関数の戻り値になります。 yylex 関数は呼び出されるたびに、次のトークンの情報を返します。
終端記号の “種類”(NUMBER, EOL など)を yylex 関数の値として返し、値(“属性”)を yylval という大域変数に代入していることに注意します。 これが通常の yylex 関数の書き方です。
一般に正規表現にマッチした文字は、 yytext という配列に保持されています。また yyleng という変数にマッチした文字の数が保持されています。 だからマッチした文字は一般に yytext[0] 〜 yytext[yyleng-1] ということになります。(通常のC言語の文字列とは異なり、 最後(yytext[yyleng])にヌル文字 '\0' は入っていないので注意が必要です。)
Bison のソースファイル (myparser.y)の方は、 単独で使う場合とあまり変わりませんが、 yylex 関数は Flex の方で用意するのでプロトタイプ宣言だけしておきます。
%{ #define YYSTYPE double /* トークンの属性の型を宣言 */ #include <stdio.h> #include <stdlib.h> /* exit関数を使うため */ void yyerror(char* s) { printf("%s\n", s); } int yylex(void); /* yylexのプロトタイプ宣言 */ %} %token NUMBER %token EOL %left '+' '-' %left '*' '/' %% input : /* 空 */ | input line {} ; line : EOL { exit (0); } /* 空行だったら終了 */ | expr EOL { printf ("\t%g\n", $1); } ; expr : NUMBER { $$ = $1; } | expr '+' expr { $$ = $1 + $3; } | expr '-' expr { $$ = $1 - $3; } | expr '*' expr { $$ = $1 * $3; } | expr '/' expr { $$ = $1 / $3; } | '(' expr ')' $$ = $2; } ; %% int main(void) { printf("Ctrl-cで終了します。\n"); yyparse(); return 0; }
C ソースファイルはそれぞれ次のコマンドで生成します。
bison -omyparser.c -d myparser.y flex -omylexer.c -I mylexer.l
必ず -d オプションをつけて Bisonを実行します。 このとき -o オプションで、 C ファイル名(この場合 myparser.c)を指定しておきます。 すると、拡張子を除いて同じ名前のヘッダーファイル(この場合 myparser.h)も生成されます。 (-o オプションをつけないと、 myparser.tab.c と myparser.tab.h という名前のファイルが生成されます。)
あとはこの 2つの C ソースファイルをまとめてコンパイルします。
bcc32 -ecalc mylexer.c myparser.c
-e は実行ファイルの名前を指定するオプションです。 これで calc.exe という名前の実行可能ファイルが生成されます。