The following is my attempt at writing a Minim compiler in OCaml using the new
Camlp4. The result is remarkably short, IMHO:
open Camlp4.PreCast;;
open Camlp4.PreCast.Syntax;;
let mmstatement = Gram.Entry.mk "mmstatement";;
let mmvalue = Gram.Entry.mk "mmvalue";;
let mmtest = Gram.Entry.mk "mmtest";;
let mmident = Gram.Entry.mk "mmident";;
let rec compile _loc tag e = function
| [] -> <:binding< $lid:tag$ = fun () -> $e$ >>
| `TL e'::`T tag'::t ->
let bs = compile _loc tag' <:expr< () >> t in
<:binding< $lid:tag$ = fun () -> $e$; $e'$ and $bs$ >>
| (`TL e' | `E e')::t -> compile _loc tag <:expr< $e$; $e'$ >> t
| `T tag'::t ->
let bs = compile _loc tag' <:expr< () >> t in
<:binding< $lid:tag$ = fun () -> $e$; $lid:tag'$() and $bs$ >>;;
let compile _loc ss = compile _loc "entry" <:expr< () >> ss;;
EXTEND Gram
str_item: LEVEL "top"
[ [ "MINIM"; "("; ss=LIST1 mmstatement; ")" ->
<:str_item< let rec $compile _loc ss$ >>
] ];
mmstatement:
[ [ "("; x=mmident; "is"; y=mmvalue; ")" -> `E <:expr< $lid:x$ := $y$ >>
| "("; "++"; x=mmident; ")" -> `E <:expr< incr $lid:x$ >>
| "("; "--"; x=mmident; ")" -> `E <:expr< decr $lid:x$ >>
| "("; "if"; p=mmtest; "then"; t=mmstatement; "else";
f=mmstatement; ")" ->
(match t, f with
| `TL t, `TL f -> `TL <:expr< if $p$ then $t$ else $f$ >>
| (`TL t | `E t), (`TL f | `E f) ->
`E <:expr< if $p$ then $t$ else $f$ >>
| _ -> invalid_arg "Tag in 'if' expression")
| "("; "goto"; t=mmident; ")" -> `TL <:expr< $lid:t$() >>
| "("; "print"; s=STRING; ")" ->
let s = String.escaped s in
`E <:expr< print_string $str:s$ >>
| "("; "print"; x=mmvalue; ")" -> `E <:expr< print_int $x$ >>
| "nl" -> `E <:expr< print_newline() >>
| "("; "input"; x=mmident; ")" ->
`E <:expr< $lid:x$ := int_of_string(input_line stdin) >>
| tag=mmident -> `T tag ] ];
mmvalue:
[ [ x=mmident -> <:expr< ! $lid:x$ >>
| n=INT -> <:expr< $int:n$ >> ] ];
mmtest:
[ [ "("; f=mmvalue; "<"; g=mmvalue; ")" -> <:expr< $f$ < $g$ >>
| "("; f=mmvalue; "="; g=mmvalue; ")" -> <:expr< $f$ = $g$ >>
| "("; f=mmvalue; ">"; g=mmvalue; ")" -> <:expr< $f$ > $g$ >>
| "("; f=mmtest; "and"; g=mmtest; ")" -> <:expr< $f$ && $g$ >>
| "("; f=mmtest; "or"; g=mmtest; ")" -> <:expr< $f$ || $g$ >>
| "("; "not"; f=mmtest; ")" -> <:expr< not $f$ >> ] ];
mmident:
[ [ x=LIDENT -> "_"^x
| x=UIDENT -> "_"^x
| "end" -> "_end" ] ];
END;;
Evaluating that in an OCaml top level lets you embed MINIM code in your OCaml:
let _x, _y = ref 0, ref 0;;
MINIM(
(print "Add x and y (what a feat!)")
nl
(print "Input x: ")
(input x)
nl
(print "Input y: ")
(input y)
main
(if (x = 0) then (goto end) else (goto sub1x))
sub1x
(-- x)
(++ y)
(goto main)
end
nl
(print "The total of x and y is ")
(print y)
nl
);;
The MINIM code is translated into OCaml ASTs on-the-fly and evaluated, giving
a high-performance Minim environment.
--
Dr Jon D Harrop, Flying Frog Consultancy Ltd.
OCaml for Scientists
http://www.ffconsultancy.com/products/ocaml_for_scientists/?e
_______________________________________________
Caml-list mailing list. Subscription management:
http://yquem.inria.fr/cgi-bin/mailman/listinfo/caml-list
Archives: http://caml.inria.fr
Beginner's list: http://groups.yahoo.com/group/ocaml_beginners
Bug reports: http://caml.inria.fr/bin/caml-bugs
.......
> The MINIM code is translated into OCaml ASTs on-the-fly and evaluated, giving
> a high-performance Minim environment.
>
This seems to be a pretty well answer to my question:
http://groups.google.com/group/fa.caml/msg/2d4a242c91ff6bd7
So, it seems to be possible to develop robust interpreters and native-
code compilers for Domain Specific Languages in OCaml using a standard
preprocessor and an extended top-level?
Very nice, seems like I could make my query processing system more
interactive,
With best regards,
Victor