bison & flexメモ その1
環境は、Windows XP上のMinGWで、flexのバージョンは2.5.35、bisonのバージョンは2.4.2
いきなり両者を使うとよく理解できないので、まずはC言語でflexを使う方法のメモ。
基本的なフォーマットは以下
%{ 初期Cコード %} %% パターン アクション %% 他のCコード
初期Cコード部分にヘッダファイルや定義等を記述して、他のCコード部分にはmain()等の関数を記述。パターンには適合させたい文字列を正規表現で、アクションには適合するパターンが見つかった場合に実行させたい内容を記述する。
main()からyylex()が呼ばれると、入力文字列を頭からスキャンしていき、適合するパターンが見つかるとそのパターンに応じたアクションを実行する。アクションの中でreturn int値を記述すると、それがyylex()の戻り値になる。全てのスキャンが終了した場合には、0を返す。
下のサンプルでは、数字列と英小字列を見つけると、それぞれNUMBER(=1)とSTRING(=2)を返す。この時に変数yytextには適合した文字列(の先頭アドレス)が、yylengには文字数が入っている。これらの変数の値は次回yylex()が呼ばれるまで保持されている(と思う)
数字列に適合した場合は、アクションの中で用意されているnumという変数に対応する数値を代入している。空白や改行の場合はアクションで何もしない。その他の文字の場合はエラーとしてyyerror()が呼ばれる。
test_flex.l
%{ #include <stdio.h> /* 字句(トークン)の種類を定義 */ enum {NUMBER = 1, STRING}; int num; /* 数字列を変換した数値の格納用 */ /* 読み込みファイルが複数ある場合に使用、今は1を返す様にしておく */ int yywrap(void){return 1; } %} %% [0-9]+ {sscanf(yytext,"%d",&num); /* パターンに適合すると{ }内のアクションを実行 */ return NUMBER;} /* yylex()の戻り値としてNUMBERを返す */ [a-z]+ {return STRING;} /* yylex()の戻り値としてSTRINGを返す */ " "|"\n" {} /* スペース・改行は何もしない */ . {yyerror("Illegal character");}/* その他の文字はエラー処理 */ %% void yyerror(char *msg){ printf("%s : '%s'\n", msg, yytext); } int main(void){ int t; while((t = yylex()) != 0){ if(t == NUMBER) printf("kind = %d, string = '%s' length = %d value = %d\n", t, yytext, yyleng, num); else if(t == STRING) printf("kind = %d, string = '%s' length = %d\n", t, yytext, yyleng); else printf("other TOKEN\n"); } }
Makefile
TARGET = test_flex LEX_SRC = $(TARGET).l LEX_C = lex.yy.c C_FILES = $(LEX_C) all : $(TARGET) $(TARGET) : $(LEX_C) gcc -o $(TARGET) $(C_FILES) $(LEX_C) : $(LEX_SRC) flex $(LEX_SRC) clean : rm -f *.exe rm -f *.c
コンパイル時にyyerror()について以下の警告がでるけど、関数yyerror()をコメントアウトするとエラーになるので無視
test_flex.l:25:6: warning: conflicting types for 'yyerror' test_flex.l:21:2: note: previous implicit declaration of 'yyerror' was here
実行結果
bash-3.1$ ./test_flex.exe 123 ←入力文字 kind = 1, string = '123' length = 3 value = 123 abc 456 ←入力文字 kind = 2, string = 'abc' length = 3 kind = 1, string = '456' length = 3 value = 456 ABC ←入力文字 Illegal character : 'A' Illegal character : 'B' Illegal character : 'C'