oelementがこれから問題にしようとしている要素だ。elementは終端記号Aで始まりBで終わるリストである。ifで言うならifで始まりendで終わる。変数参照やリテラルである。この文法に基くパーサで次のような入力をパースしてみよう。次のように考えればわりと簡単である。AとBがoだけを狭んで現れるので、それを消してoに変える。結論は図4のようになる。conflictsと出た。入力は、先程のものから単純にBを抜くと次のようになってしまう。oどうにもよくわからない。スしてみよう(図5)。Aで始まるリストのリストをパースとりあえずパースできた。途中でリストを切ることができなくなってしまった。実はRubyの括弧省略メソッドはこれと似たような状態にある。メソッド名と第一引数が合わせてAだ。ないので、新しいリストの始まりだと認識できるからである。他に「現実的な」HTMLもこのパターンを含む。いうわけでyaccは普通のHTMLにはまるで通用しない。スキャナパーサ概形スキャナに移る前にパーサの概形について説明しておこう。rb_compile_file()の三つである。ト、RubyのIOオブジェクトからプログラムを読み込んでコンパイルする。yyparse()に完全に制御を移す。yyparse()を中心に把握してやるとよい。明確に分類することができる。スキャナの最も低レベルな部分には入力バッファがある。次のレベルはトークンバッファである。読んだらトークンが一つ完成するまでここにまとめてとっておく。従ってyylex全体の構造は図7のように図示できる。入力バッファまず入力バッファから見ていこう。nextc()、pushback()、peek()の三つだけだ。しつこいようだがまずデータ構造を調べるのだった。入力バッファの使う変数はこうだ。*lex_pend;(parse.y)バッファの先頭と現在位置、終端。文字列バッファらしい(図8)。入力バッファnextc()ではこれを使っているところを見てみる。思われるnextc()から。}(parse.y)最初のifで入力バッファの最後まで行ったかどうかテストしているようだ。終わりをテストしているのだと想像できる。lex_inputが0になる。lex_getline()なので行に間違いない。まとめるとこういうことだ。c行を補給する関数lex_getline()も見てみよう。この関数で使う変数も一緒に並べておく。}(parse.y)最初の行以外はどうでもよい。lex_getsが一行読み込み関数へのポインタ、lex_inputが本当の入力だろう。lex_getsをセットしているところを検索してみると、こう出た。file;(parse.y)rb_io_gets()はパーサ専用というわけではなく、rubyの汎用ライブラリだ。IOオブジェクトから一行読み込む関数である。一方のlex_get_str()は次のように定義されている。}(parse.y)この関数はいいだろう。lex_gets_ptrが既に読み込んだところを記憶している。それを次の\nまで移動し、同時にそこを切り取って返す。ここでnextcに戻ろう。分を共通化しているわけだ。st_tableにも似たような手法があった。pushback()バッファの物理構造とnextc()がわかればあとは簡単だ。一文字書き戻すpushback()。Cで言えばungetc()である。*lex_p)(parse.y)トークンバッファトークンバッファは次のレベルのバッファである。トークンが一つ切り出せるまで文字列を保管しておく。インターフェイスは以下の五つである。バッファリングしている文字列の最後のバイトではまずデータ構造から見ていく。クスらしい)、toksizがバッファ長だろう。絵にすると図9のようになる。化されていない可能性がある。