173 lines
3.9 KiB
OCaml
173 lines
3.9 KiB
OCaml
|
|
(* source language ---------------------------------------------------------- *)
|
||
|
|
|
||
|
|
(* This variant of the language treats variables as mutable.
|
||
|
|
Their interpretation in ML has type "int64 ref"
|
||
|
|
*)
|
||
|
|
|
||
|
|
type var = string
|
||
|
|
module SRC = struct
|
||
|
|
|
||
|
|
(* Abstract syntax of arithmetic expressions *)
|
||
|
|
type exp =
|
||
|
|
| Var of var
|
||
|
|
| Add of exp * exp
|
||
|
|
| Mul of exp * exp
|
||
|
|
| Neg of exp
|
||
|
|
| Const of int64
|
||
|
|
|
||
|
|
(* Abstract syntax of commands *)
|
||
|
|
type cmd =
|
||
|
|
| Skip (* skip *)
|
||
|
|
| Assn of var * exp (* X := e *)
|
||
|
|
| Seq of cmd * cmd (* c1 ; c2 *)
|
||
|
|
|
||
|
|
(* The global context of available variables and their initial values. *)
|
||
|
|
let globals : (var * int64) list =
|
||
|
|
[
|
||
|
|
"X1", 1L
|
||
|
|
; "X2", 2L
|
||
|
|
; "X3", 3L
|
||
|
|
; "X4", 4L
|
||
|
|
; "X5", 5L
|
||
|
|
; "X6", 6L
|
||
|
|
; "X7", 7L
|
||
|
|
; "X8", 8L
|
||
|
|
]
|
||
|
|
|
||
|
|
(*
|
||
|
|
(1 + X4) + (3 + (X1 * 5) )
|
||
|
|
*)
|
||
|
|
let example : exp =
|
||
|
|
Add(Add(Const 1L, Var "X4"),
|
||
|
|
Add(Const 3L, Mul(Var "X1",
|
||
|
|
Const 5L)))
|
||
|
|
|
||
|
|
(*
|
||
|
|
X1 := (1 + X4) + (3 + (X1 * 5) ) ;
|
||
|
|
Skip ;
|
||
|
|
X2 := X1 * X1 ;
|
||
|
|
*)
|
||
|
|
let example_cmd : cmd =
|
||
|
|
Seq(Assn("X1", example),
|
||
|
|
Seq(Skip,
|
||
|
|
Assn("X2", Mul(Var "X1", Var "X1"))))
|
||
|
|
|
||
|
|
end
|
||
|
|
|
||
|
|
|
||
|
|
module IR = struct
|
||
|
|
(* Unique identifiers for temporaries. *)
|
||
|
|
type uid = int
|
||
|
|
|
||
|
|
(* "gensym" -- generate a new unique identifier *)
|
||
|
|
let mk_uid : unit -> uid =
|
||
|
|
let ctr = ref 0 in
|
||
|
|
fun () ->
|
||
|
|
ctr := !ctr + 1;
|
||
|
|
!ctr
|
||
|
|
|
||
|
|
(* operands *)
|
||
|
|
type opn =
|
||
|
|
| Id of uid
|
||
|
|
| Const of int64
|
||
|
|
|
||
|
|
(* binary operations *)
|
||
|
|
type bop =
|
||
|
|
| Add
|
||
|
|
| Mul
|
||
|
|
|
||
|
|
(* instructions *)
|
||
|
|
(* note that there is no nesting of operations! *)
|
||
|
|
type insn =
|
||
|
|
| Let of uid * bop * opn * opn
|
||
|
|
| Load of uid * var
|
||
|
|
| Store of var * opn
|
||
|
|
|
||
|
|
type program = {
|
||
|
|
globals: (var * int64) list;
|
||
|
|
insns: insn list
|
||
|
|
}
|
||
|
|
|
||
|
|
|
||
|
|
(* pretty printing *)
|
||
|
|
let pp_uid u = Printf.sprintf "tmp%d" u
|
||
|
|
let pp_var x = Printf.sprintf "var%s" x
|
||
|
|
let pp_int64 c = (Int64.to_string c)^"L"
|
||
|
|
|
||
|
|
let pp_opn = function
|
||
|
|
| Id u -> pp_uid u
|
||
|
|
| Const c -> pp_int64 c
|
||
|
|
|
||
|
|
let pp_bop = function
|
||
|
|
| Add -> "add"
|
||
|
|
| Mul -> "mul"
|
||
|
|
|
||
|
|
let pp_insn = function
|
||
|
|
| Let (u, bop, op1, op2) ->
|
||
|
|
Printf.sprintf "let %s = %s %s %s"
|
||
|
|
(pp_uid u) (pp_bop bop) (pp_opn op1) (pp_opn op2)
|
||
|
|
| Load (u, x) ->
|
||
|
|
Printf.sprintf "let %s = load %s"
|
||
|
|
(pp_uid u) (pp_var x)
|
||
|
|
| Store (x, op) ->
|
||
|
|
Printf.sprintf "let _ = store %s %s"
|
||
|
|
(pp_opn op) (pp_var x)
|
||
|
|
|
||
|
|
let pp_global = function (x,c) ->
|
||
|
|
Printf.sprintf "let %s = ref %s" (pp_var x) (pp_int64 c)
|
||
|
|
|
||
|
|
let pp_program {globals; insns} =
|
||
|
|
Printf.sprintf "%s\n;;\n%s in\n ()"
|
||
|
|
(String.concat "\n" (List.map pp_global globals))
|
||
|
|
(String.concat " in\n" (List.map pp_insn insns))
|
||
|
|
|
||
|
|
|
||
|
|
|
||
|
|
module MLMeaning = struct
|
||
|
|
let add = Int64.add
|
||
|
|
let mul = Int64.mul
|
||
|
|
let load x = x.contents
|
||
|
|
let store o x = x.contents <- o
|
||
|
|
end
|
||
|
|
|
||
|
|
end
|
||
|
|
|
||
|
|
|
||
|
|
module Compile = struct
|
||
|
|
open SRC
|
||
|
|
|
||
|
|
let rec compile_exp (e:exp) : (IR.insn list) * IR.opn =
|
||
|
|
let compile_bop bop e1 e2 =
|
||
|
|
let ins1, ret1 = compile_exp e1 in
|
||
|
|
let ins2, ret2 = compile_exp e2 in
|
||
|
|
let ret = IR.mk_uid () in
|
||
|
|
ins1 @ ins2 @ IR.[Let (ret, bop, ret1, ret2)], IR.Id ret
|
||
|
|
in
|
||
|
|
begin match e with
|
||
|
|
| Var x ->
|
||
|
|
let ret = IR.mk_uid () in
|
||
|
|
IR.[Load(ret, x)], IR.Id ret
|
||
|
|
| Const c -> [], IR.Const c
|
||
|
|
| Add(e1, e2) -> compile_bop IR.Add e1 e2
|
||
|
|
| Mul(e1, e2) -> compile_bop IR.Mul e1 e2
|
||
|
|
| Neg(e1) -> compile_bop IR.Mul e1 (Const(-1L))
|
||
|
|
end
|
||
|
|
|
||
|
|
let rec compile_cmd (c:cmd) : (IR.insn list) =
|
||
|
|
begin match c with
|
||
|
|
| Skip -> []
|
||
|
|
| Assn(x, e) ->
|
||
|
|
let ins1, ret1 = compile_exp e in
|
||
|
|
ins1 @ IR.[Store(x, ret1)]
|
||
|
|
| Seq(c1, c2) ->
|
||
|
|
(compile_cmd c1) @ (compile_cmd c2)
|
||
|
|
end
|
||
|
|
|
||
|
|
let compile (c:cmd) : IR.program =
|
||
|
|
let globals = SRC.globals in
|
||
|
|
let insns = compile_cmd c in
|
||
|
|
IR.{ globals; insns }
|
||
|
|
|
||
|
|
end
|
||
|
|
|