Brainfuck インタプリタ

寝る前に OCaml でなんか書いてみるか、と思って書いてみた。

exception Unexpected_char
let interpret str =
  (* バッファ *)
  let buf = Array.create 3000 0 in
  (* 対応する右括弧(])を探しに行く *)
  let rec rp idx n = match String.get str idx with
    | '[' -> rp (idx+1) (n+1)
    | ']' -> if n=0 then idx else rp (idx+1) (n-1)
    | _ -> rp (idx+1) n
  (* 対応する左括弧([)を探しに行く *)
  and lp idx n = match String.get str idx with
    | '[' -> if n=0 then idx else lp (idx-1) (n-1)
    | ']' -> lp (idx-1) (n+1)
    | _ -> lp (idx-1) n
  (* 1文字ずつ読み込んで処理 *)
  and loop idx p = match String.get str idx with
    | '>' -> loop (idx+1) (p+1)
    | '<' -> loop (idx+1) (p-1)
    | '+' -> buf.(p) <- buf.(p)+1; loop (idx+1) p
    | '-' -> buf.(p) <- buf.(p)-1; loop (idx+1) p
    | '.' -> print_char(char_of_int(buf.(p))); loop (idx+1) p
    | ',' -> buf.(p) <- int_of_char (input_char stdin); loop (idx+1) p
    | '[' -> loop (if buf.(p)=0 then (rp (idx+1) 0)+1 else idx+1) p
    | ']' -> loop (if buf.(p)<>0 then (lp (idx-1) 0)+1 else idx+1) p
    | '\n' -> ()
    | _   -> raise Unexpected_char
  in loop 0 0
let _ = interpret (read_line()^"\n")
$ ocaml bf.ml
+++++++++[>++++++++>+++++++++++>+++++<<<-]>.>++.+++++++..+++.>-.------------.<++++++++.--------.+++.------.--------.>+.
Hello, world!$ 

ゴルフを経験した後だと、 loop を ($) にすれば括弧が消せる!とか、if 式を消したい!とか、while 使った方がいいかも!とか、例外は無視してよくね!とか思ってしまう。