S式パーサ

30分プログラム、その63。
OCamlのStreamでパーサを書いてみる。

# parse_string "1";;
- : s_exp = Num 1
# parse_string "+";;
- : s_exp = Op "+"
# parse_string "(+ 1 3)";;
- : s_exp = List [Op "+"; Num 1; Num 3]
#load "camlp4o.cma";;
open Genlex;;
let ($) f g = f g;;
type s_exp = Num of int | Op of string | List of s_exp list;;

let lexer = Genlex.make_lexer ["+";"-";"*";"/";"(";")"];;
let stream = lexer (Stream.of_string "(1 2 3)");;
let make_stream x = lexer (Stream.of_string x);;
let rec many f s= 
  try 
    let x = f s in
      x::(many f s)
  with _ -> [];;

let rec parse =parser 
  | [<'Kwd"(" ; e = many parse ; 'Kwd")">] -> List e
  | [<'Kwd op when List.mem op ["+";"-";"*";"/"]>] -> Op op
  | [<'Int n>] -> Num n;;

let parse_string s = parse $ lexer (Stream.of_string s);;