第十九回スパルタンプログラミング
何がしたいか?何が問題か?を意識して変なとこでぐだぐだ考えないこと! 30分悩んで分からなかったら、早めにヘルプを出す。
やりたいこと
lex & yacc 再訪。pthreadのなんちゃって実装をしたので、サーバのパーサ部分へいったん戻る。ちゃんと使えるようになりたい。
パーサができればクライアントへの応答ができて、「webサーバ作った!」が得られるはず!
やったこと
14.09.01
- 1.2節まで復習
14.09.02
- 1.3.3節まで復習。
- ch1-05.yのyyinはstdinを代入して上げないと動作しない!前回は待ってた場所の理由が分かったので、すっきり。
- y.tab.cのコンパイルで「warning: implicit declaration of function 'yylex' is invalid in C99 [-Wimplicit-function-declaration]」となるときは、.yファイルの定義部にextern int yylex(void);でOK. yylex()そのものはlex.yy.cで定義されている。
- 分割コンパイル覚えた。
14.09.03
- 理解の整理。
- 端末のカノニカルモード:getcharが標準入力を改行押下するまでブロックする理由が分からなかったため調べた。
整理
目的
HTTPヘッダを解釈し、レスポンスを返す。
方法
1.lexと2.yaccを使う
1.と2.はそれぞれ何ができるの?
正規表現を使ってトークンに分割。トークン発見時にアクションを実行できる。
トークンの並びを構文に分け、目的の構文に合致したらアクションを実行できる。
メモ1
1.yylexと2.yyparseの関係は?
yylexは規則部をreturnが実行ないかぎり、繰り返し実行。
yyparseはyylexを呼び出し、トークンコードと規則部の合致をしらべ、合致する最上位規則のアクションを実行。
関係1:yyparseでyylexを呼び出したら、returnはトークンコードをyyparseへ返す。
メモ2
- ch1-05.yではまったやつ↓。下記ままだとsegmentation fault
//ch1-05.y抜粋 int main(void){ while(!feof(yyin)){// yyin==0x0でsegmetasion fault, yyparse();//yyparseでyylexを一度でも実行すると、yyin==0x0ならyyin==stdinとなる。see lex.yy.c } }
14.09.04
- ch1-05.yが2回目の入力でsyntax errorを吐くことの調査。
yaccのトレースの仕方
- .yファイルの定義部に下記を書くと、yyparse()実行時にトレースをstderrに吐いてくれる。
- トレース内のstateはy.output内のstateと一致するので追える。
#define YYDEBUG 1 int yydebug 1
トレースの読み方
- Starting parseがyyparse()の開始
- Reading a token:がyylex()の開始
14.09.05
マニュアル
覚え書き
lex
- yyin, yyoutを定義しないとデフォルトはそれぞれstdin, stdoutとなる。
- -lオプションでAT&T の lex の実装に対して最大限の互換性を持たせる。
- YY_STDINITは.lファイルのdefinition sectionに書くことでyylex_destroy()のyyinをstdinにする。書かない場合yyinは0x0。 また、yylex()自身も初回実行時にyyinが0x0ならyyinにstdinを代入する。
gcc
- -gオプションでデバッグ情報の生成。
yacc
- -dオプションでトークン定義をすべて含んだy.tab.hを生成
- -vオプションで生成されたパーザの詳細を人間に読める形式でファイルy.outputに出力
- -DYY_STDINITオプションまたは#define YY_STDINITでyyinのデフォルトがstdinになる。
- -DYYDEBUGオプションまたは#define YYDEBUGでパーサーのデバッグ内容が吐かれるようになる。
- -DYYERROR_VERBOSEオプションまたはむにゃむにゃ
- オプション
yyparseはYYLEXマクロでyylex()を呼ぶが、そのyyparse内ではyylex_destroyは呼ばれない。 よって、YY_STDINITはyyparseには無効。
言葉
- コルーチン:コルーチンはいったん処理を中断した後、続きから処理を再開できる。