%%
"+" 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 |