単純なマーク付けがなされた文字列の解析 #14
前回示したflex用コードと#10や#11の有限状態機械のC実装とは表現の違いに過ぎないと述べたが、
生成されるプログラムの動作は変えないようにflex用コードの規則部を以下のように変更するとさらによく分かると思う。
...snip %% BEGIN(start); <start>[^()] { printf("string [%c", yytext[0]); BEGIN(string); } <start>\( { printf("marked-string ["); BEGIN(head); } <start>\) { yyerror("illegal right parenthesis"); return 1; } <start><<EOF>> { yyerror("unexpected EOF"); return 1; } <restart>[^()] { printf("string [%c", yytext[0]); BEGIN(string); } <restart>\( { printf("marked-string ["); BEGIN(head); } <restart>\) { yyerror("illegal right parenthesis"); return 1; } <restart><<EOF>> return 0; <string>[^()] ECHO; <string>\( { printf("]\nmarked-string ["); BEGIN(head); } <string>\) { yynerror("illegal right parenthesis"); return 1; } <string><<EOF>> { printf("]\n"); return 0; } <head>[^()] { ECHO; BEGIN(body); } <head>\( { yynerror("illegal left parenthesis"); return 1; } <head>\) { yynerror("null string between parentheses"); return 1; } <head><<EOF>> { yynerror("unexpected EOF"); return 1; } <body>[^()] ECHO; <body>\( { yynerror("illegal left parenthesis"); return 1; } <body>\) { printf("]\n"); BEGIN(restart); } <body><<EOF>> { yynerror("unexpected EOF"); return 1; }
これは、複数の開始状態をカンマ区切りでまとめたり、
開始状態のスコープを定義して複数の規則をまとめたりしていた前回のコードを解いて平坦にしたものである。
この形式にすると、まさに#12で図示した状態遷移表そのままであることが分かる。
開始状態と入力文字の組が状態遷移表のstateとcの組であり、
アクション内にBEGINマクロがあればその引数が次に遷移すべき状態を、
return 0;
は受容状態への遷移を、
return 1;
がエラー状態への遷移を、
そして、そのどれもが無ければ現在の状態自身への遷移を表している。
もちろんprintfやyyerror、yynerrorの呼び出しが行うべきactionそのものである。