170 likes | 359 Views
lex,yacc について. 2001 年 9 月 20 日 上牧瀬 誠. 宣言部. %%. ルール部. %%. プログラム部. lex. 字句解析プログラムを生成するプログラムジェネレータ lex.yy.c が生成. ルール部. 字句解析を行う パターンとアクションからなる パターンとアクションは同じ行に書く 入力がパターンにマッチしたときアクションが実行される. パターン. 入力文字の並び パターンは正規表現で書かれる 例 abc { アクション 1} de { アクション 2} 入力“ abcde” が与えられると,
E N D
lex,yaccについて 2001年9月20日 上牧瀬 誠
宣言部 %% ルール部 %% プログラム部 lex • 字句解析プログラムを生成するプログラムジェネレータ • lex.yy.cが生成
ルール部 • 字句解析を行う • パターンとアクションからなる • パターンとアクションは同じ行に書く • 入力がパターンにマッチしたときアクションが実行される
パターン • 入力文字の並び • パターンは正規表現で書かれる • 例 abc {アクション1} de {アクション2} 入力“abcde”が与えられると, • “abc”を読みアクション1が実行 • “de”を読みアクション2が実行
正規表現で使われる記号 . 改行を除く任意の1文字にマッチ * 直前の正規表現の0回以上の繰り返しにマッチ + 直前の正規表現の1回以上の繰り返しにマッチ ? 直前の正規表現の0回か1回にマッチ | 直前の正規表現もしくは直後の正規表現にマッチ [] 角括弧で囲まれた文字のどれか1文字にマッチ ^ 正規表現の先頭にある場合は,行の先頭にマッチ 角括弧の中では否定の意味 $ 正規表現の最後にある場合は,行末にマッチ \ メタ文字をエスケープするために使用(\n:改行,\t:タブ,など) {} カッコ内に1つあるいは2つの数字を記述し,直前のパタンの繰り返し が何回現れるとマッチするか示す {3,} 3回以上 {,5} 5回以下 {3,5} 3回以上5回以下 “” 引用符の中の文字列そのものにマッチ / 「/」の直後の正規表現にマッチするような文字列の前にある場合のみ, 「/」の直前のパタンにマッチ () 正規表現の並びをグループ化
lexで使われる主な変数 • yytext • パターンとマッチした文字列が格納されている変数 • yyleng • パターンとマッチした文字列の長さが格納されている変数 • yylval • 構文解析ルーチン(yaccプログラム)にトークンを返すときの付加情報を格納する変数
字句解析の例 abc ECHO; • パターンにマッチした文字列をそのまま出力 [0-9]+ printf(“number = %d\n”,atoi(yytext)); • マッチした文字列を数値に変換して,数値として出力 -?[0-9]+ {yylval = atoi(yytext); return (NUMBER);} • NUMBERの付加情報としてマッチした文字列を数値に変換 [a-zA-Z] retrun (CHAR); • アルファベット1文字にマッチしたらCHARを返す
ECHO • fprintf(yyout,”%s”,yytext); と同値 yyoutは標準出力のファイルポインタ • NUMBER,CHAR • 構文解析ルーチン(yaccプログラム)で宣言されたトークン
宣言部 • 「%{」と「%}」で囲んで記述したCのコードを,lexは字句解析ルーチンにそのまま複写 ファイル読み込み,定数定義,変数宣言 • word [^ \n\t]+ • ルール部のパターンで{word}で参照できる {word} {yylval = yyleng; return (WORD);}
プログラム部 • Cのプログラムを書く • 省略すると,デフォルトで次のmain()関数が書かれる int main() { yylex(); return 0; }
宣言部 %% ルール部 %% プログラム部 yacc • 構文解析プログラムを生成するプログラムジェネレータ • y.tab.cが生成
宣言部 • 「%{」と「%}」で囲んで記述したCのコードを,yaccは構文解析ルーチンにそのまま複写 • %tokenでトークン(終端記号)を宣言 %token NUMBER CHAR • %left,%right,%nonassocで優先順位の設定 下に書いてあるものほど優先順位が高い %left ‘+’ ‘-’ %left ‘*’ ‘/’ • %startでスタート規則を宣言,省略するとルール部の最初の規則がスタート規則
ルール部 • 構文解析を行う • 規則とアクションからなる • 規則はLALR(1)文法で書かれる • アクションはCのプログラム S : A ‘+’ B {$$ = $1 + $3;} | C {printf(“%d\n”,$1);} ; S : A ‘+’ B $$ $1 $2 $3 $$,$1,...はそれぞれの 付加情報(yylaval)に対応
lexプログラム例 %{ /******************************/ /* Simple Calculator (lex program) */ /******************************/ #include <stdio.h> %} %% “+” 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]); %%
yaccプログラム例 %{ /*******************************/ /* Simple Calculator (yacc program) */ /*******************************/ #include <stdio.h> %} %token NL NUMBER LP RP %left ADDOP SUBOP %left MULOP DIVOP %%
yaccプログラム例(続き) s : list ; list : /* empty */ | list expr NL {printf("%d\n",$2);} ; expr : expr ADDOP expr {$$ = $1 + $3;} | expr SUBOP expr {$$ = $1 - $3;} | expr MULOP expr {$$ = $1 * $3;} | expr DIVOP expr {$$ = $1 / $3;} | LP expr RP {$$ = $2;} | NUMBER {$$ = $1;} ; %% #include "lex.yy.c"
実行例 % lex smpint.l yy.lex.cが生成 % yacc smpint.y y.tab.cが生成 % gcc y.tab.c –ly –ll –o scalc コンパイル % ./scalc 実行 (1+2)*3 入力 9 出力 ^D 終了 %