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
Bisonの生成するヘッダーファイルが Flexに必要なので、 必ず -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という名前の実行可能ファイルが生成されます。