bison & flexメモ その3
C言語でflexを使う方法のメモ その3
スタート状態について
%% 〜 %%間のどのルールを有効にするかを指定する。
%x state_name %s state_name
%sまたは%xに続いて使用する状態名を記述する。
%x(排他的スタート)はその状態名が書かれたルールのみ有効になり、%s(包含的スタート)はその状態名で書かれたルールと状態名が書かれていないルールが有効になる。ルールセクションでの記述は以下のとおり。
%% <state_name> pattern action <state_name> pattern action %%
または
%% <state_name> { pattern action pattern action } %%
デフォルトの状態はINITIALであり、別のスタート状態に移行するにはアクションの中で、BEGIN(state_name);を記述する。
下の例では、C言語タイプのコメント/* 〜 */を除去している。"/*"を検出すると
改行(\n)に適合した場合は、行番号を保存する変数lineを+1するが、全ての状態で使用するので状態名は記述していない。
test_flex.l
%{ #include <stdio.h> /* 字句(トークン)の種類を定義 */ enum {NUMBER = 1, STRING}; int num; /* 数字列を変換した数値の格納用 */ int line = 1; /* ソースの行番号表示 */ /* 読み込みファイルが複数ある場合に使用、今は1を返す様にしておく */ int yywrap(void){return 1; } %} %s COMMENT %% <INITIAL>{ "/*" {BEGIN(COMMENT);}/* COMMENT状態に移行 */ [0-9]+ {sscanf(yytext,"%d",&num); /* パターンに適合すると{ }内のアクションを実行 */ return NUMBER;} /* yylex()の戻り値としてNUMBERを返す */ [a-z]+ {return STRING;} /* yylex()の戻り値としてSTRINGを返す */ " " {} /* スペースは何もしない*/ . {yyerror("Illegal character");}/* その他の文字はエラー処理 */ } <COMMENT>{ "*/" {BEGIN(INITIAL);}/* INITIAL状態に移行 */ " " {} /* スペースは何もしない*/ . {} /* コメント文は無視 */ } "\n" {line++;} /* 改行がきたら行番号を+1する <INITIAL> <COMMENT>双方で使用 */ %% void yyerror(char *msg){ printf("line %d : %s : '%s'\n", line, msg, yytext); } int main(int argc, char ** argv){ int t; if ( argc > 1 ) /* yyinをファイル入力に切り替え */ if((yyin = fopen( argv[1], "r")) == NULL){ fprintf(stderr,"Can't open a input file!\n"); return 1; } while((t = yylex()) != 0){ if(t == NUMBER) printf("line %d : kind = %d, string = '%s' length = %d value = %d\n", line, t, yytext, yyleng, num); else if(t == STRING) printf("line %d : kind = %d, string = '%s' length = %d\n", line, t, yytext, yyleng); else printf("line %d : other TOKEN\n", line); } return 0; }
sample.txt
int i; /* foo */ /* bar */ int j; /* comment line 1 comment line 2 */ i = 123;
実行結果
bash-3.1$ ./test_flex.exe sample.txt line 1 : kind = 2, string = 'int' length = 3 line 1 : kind = 2, string = 'i' length = 1 line 1 : Illegal character : ';' line 2 : kind = 2, string = 'int' length = 3 line 2 : kind = 2, string = 'j' length = 1 line 2 : Illegal character : ';' line 5 : kind = 2, string = 'i' length = 1 line 5 : Illegal character : '=' line 5 : kind = 1, string = '123' length = 3 value = 123 line 5 : Illegal character : ';'