Vim スクリプトでパーサコンビネータするライブラリを試しに書いてみた。とりあえずものすごく簡単な奴は動くようになったので公開してみる。
http://github.com/thinca/vim-vparsec
- 絶賛実験バージョン。
- インターフェースとかも完全に暫定版。
- 全然最適化してない。
- エラーメッセージも適当。
- 多分中身の構成もいろいろおかしい。
- そもそもこれで正しいのか作った本人もよくわかってない。
- 大量に関数呼び出すので解析対象によっては 'maxfuncdepth' を大きめに設定する必要がある。
以下のように書ける。*1
" This is a sample for vparsec.vim function! s:build_calculator() let p = vparsec#parsers() let conv = {} function! conv.expr(res) " res = [firstToken, [op, rhs]*] let [left, rest] = a:res for [op, right] in rest execute printf('let left = left %s right', op) endfor return left endfunction function! conv.term(res) return str2float(a:res) endfunction let number = p.regex('\v[+-]?\d+%(\.\d+%(e[+-]?\d+)?)?').named('number') let expr = p.lazy().named('expr') let term = p.or(number.map(conv.term), p.seq('(', expr, ')').at(1)).named('term') let mul = term.next(p.seq(p.or('*', '/'), term).many()).map(conv.expr).named('mul') let add = mul.next(p.seq(p.or('+', '-'), mul).many()).map(conv.expr).named('add') call expr.set(add) return expr.phrase() endfunction function! s:run_sample(calculator, input) let result = a:calculator.parse(a:input) if !result.successful return result.toString() endif return result.result endfunction echo s:run_sample(s:build_calculator(), '(2+4.2)*8+1.3-2*3+(3.1e2/2)')
結果。
199.9
おおおおお!動きましたね!
これはちょっと感動。あとはもう少し使いやすくなるようにあちこち弄っていきたいところ。全体的にイケてない箇所が多すぎる。
…実用性?何それおいしいの?
*1:コードは開発中のものです。