高速 Brainf*ck VM
Brainf*ck は移植性が高いのは良いのですが、実行が遅いという難点があったのでした。ということで実行前にバイトコードに変換して実行してやれば速くなるだろう、ということで安易にそういうものを作りました。
http://shinh.skr.jp/koneta/bfopt.ml
諸事情 (Cで書くとコードを短くしたくなる、遅い言語だと高速化してもCに負けそう) により OCaml で書きました。
> ocamlopt bfopt.ml > ./a.out echo.bf
などとして実行できます。第二引数を指定するとそのファイルにバイトコードに変換した結果を吐きます。
このバイトコードでは、通常の命令は全て使える上に、拡張された命令をいくつか使用することができます。
- 0b11xxxxxx
- + 命令を x+2 回繰り返して実行します。
- 0b10xxxxxx
- - 命令を x+2 回繰り返して実行します。
- 0b000xxxxx
- > 命令を x+2 回繰り返して実行します。
- 0b011xxxxx
- < 命令を x+2 回繰り返して実行します。
- 0b01011111
- [-] 命令を実行します。
まぁ要するに複数回実行は RLE でまとめてしまうのと、頻出する [-] を単なる 0 の代入にしてしまう、という話です。これら以外を無視する仕様は変わらないため、 magic としてくっつけてある BFC は無視されてくれます。
昨日の SBF が吐いた BF コードは 2倍くらい速くなったようです。ちなみにバイトコンパイルを実装する前から、 C 版よりちょっと速度速いくらいでした。
ああ OCaml は手続き脳でも素直に書けて良いのうと思いました。問題は let の後に rec を忘れるくらいですよ。
でもいつも疑問に思うんだけど、 OCaml で void な式を挟む場合は
let _ = void_function() in
とか書き加えてるんですが、本当にこれでいいのか…まぁださいし、 printf デバッグしにくい。
コメントで教えていただきましたが ; 使えとのこと。ていうか、3年前の段階で既に then begin ...; ... end とか書いているのにも関わらずいったいお前の脳は退化しすぎじゃないかとか。
7.1 9:30 頃追記。パターンマッチの時に when なんてあったのねー とか思ったので、いろいろ書き換えてみました。もとのがひどかったんだけど、それなりにすっきりしました。