kumaryu日記
2010-07-14
_ 日記
またイベント多すぎで忙しい。9月にやりそうなイベント終わったら次のイベントは今年はキャンセルしようかな…。
_ [Ruby] RubyでGLSLパーサ作り
プリプロセッサのif条件式評価をいまだにやってたりする。
citrusのトークン列を入力にするのは出来て、テストをせっせと書いてたんだけど予想外の場所で失敗してしまった。なんの変哲もない場所でパース失敗する。
「1==2&&3」なんかが失敗するんだよね。「2&&3==1」は成功。優先順位が高い演算子が前だと駄目なのかなーと思ったんだけど、「1*2+3」とかはちゃんと通るんだわ。書き方全く一緒なのに。
これを本当に数日悩んでたんだけど、昨日やっとわかった。分かってしまえばどうということはない、次にマッチする場所を探すのにマッチしたテキストの長さを使う場所が残っていただけだった。
トークン列を入力にしてるのでトークン1つにマッチしたら(たとえトークンが'foobar'とかいう識別子でも)当然長さは1だし、それは間違いなくそういう処理をできるようにしてたんだけど、終端じゃないマッチオブジェクトがやらかしてた。
終端じゃないマッチの長さは部分マッチの長さ合計であるべきなのに、部分マッチのテキストをくっつけてその長さを取るようになってたので、トークン列にマッチしてるはずがいつのまにか文字列の長さを数えてやがった。
途中まで気付かなかったのは1+2*3みたいに演算子も数値も1文字だったのでトークンの長さと変わらなかったせいだ。こわいね。
終端じゃないマッチの長さは部分マッチの長さ合計で計算してあげるようにして解決。
ところでこの問題を調べてる途中で気付いたんだけど、途中のマッチを覚えていない設定にした場合のcitrusの遅さがやばすぎる。
Citrus::Grammar.parseのオプションに:enable_memo => trueを入れてやるとマッチ結果のキャッシュをしてくれるようになる。Treetopはこれが標準なんだけどcitrusはメモリ使用量が増えることを嫌ってか標準ではOFF。
しかし俺が試したところ、「1==2&&3」ぐらいのパースを試すのにキャッシュ有りで0.03秒、キャッシュ無しで1.9秒だった。実行時間60倍とかありえねぇだろ…。事実テストを全部通そうとしたら、どこかで無限ループしたかと本気で思うくらい終わらなかったので中断した。
なんでこれ標準でOFFになってんだろ?メモリ使用量とかいう話でなく全く実用的でないと思うんだけど。