* Minim compiler as a camlp4 macro
@ 2007-08-17 9:36 Jon Harrop
0 siblings, 0 replies; only message in thread
From: Jon Harrop @ 2007-08-17 9:36 UTC (permalink / raw)
To: caml-list
Mark Tarver posted an open challenge for people to write programs to evaluate
Minim programs, a simple imperative language.
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
^ permalink raw reply [flat|nested] only message in thread
only message in thread, other threads:[~2007-08-17 9:47 UTC | newest]
Thread overview: (only message) (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2007-08-17 9:36 Minim compiler as a camlp4 macro Jon Harrop
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox