%% "+" return ADDOP; "-" return SUBOP; "*" return MULOP; "/" return DIVOP; "(" return LP; ")" return RP; [0-9]+ { yylval = atoi(yytext); return NUMBER; } [ \t] ; \n return NL; . return yytext[0]; %%
lexが切り出した文字列はchar* yytext
で参照できる.
yylval
に値をセットするとyacc
から参照できる.
返値はyacc
にどんな種類のトークンが入力されたかを教えるためのものなので,
例えば数字が入力された場合,返値としてはNUMBER
を返しておき,
実際の値はyylval
にセットしてyacc
に伝達するという方法をとる.
lexソースは,パターン アクションの並びで記述するが,アクションは複数行に分かれてもかまわないらしい. たぶん,行頭から始まっているとパターン,行頭以外から始まっている場合はアクションの継続行と解釈されるのだと思う.
%token NL %token NUMBER %token LP %token RP %token ADDOP SUBOP %token MULOP DIVOP %% s : list ; list : /* empty */ | list expr NL { printf("%d\n", $2); } ; expr : expr ADDOP expr { $$ = $1 + $2; } | expr SUBOP expr { $$ = $1 - $2; } | expr MULOP expr { $$ = $1 * $2; } | expr DIVOP expr { $$ = $1 / $2; } | LP expr RP { $$ = $2; } | NUMBER { $$ = $1; } ; %% #include "lex.yy.c"
乗除算は加減算より先に実行する(優先順位が高い)ので,乗除算用の%left
は加減算のものよりあとに指定する.
%left
は,
そのトークンの結合規則が左から右である(同じ優先度のトークンが連続したときに左から右に評価する)ことを指示する.
同じ優先順位のトークンが複数表れた場合,もっとも左に出現したものから順に処理することを示す.
$$
は構文規則の左辺,$n
(n
= 1, 2, ...)は右辺の各トークンをあらわしている.
$ yacc foo.y $ lex foo.l $ cc y.tab.c -ly -ll -o foo
lex
が生成するlex.yy.c
については
yacc
ソースで#include "lex.yy.c"
と指定しているため,
上記のコマンド列には現れていない(明示的に指定する方法でもいいような気がするが,普通このようにするのが慣習のようだ).
[1] | Lex and YACC primer/HOW-TO |
[2] | Lex and YACC HOW-TO |