(* -------------------------------------------- *)
(* denotational semantics definitions: in SML *)
(* = ds_imp.ml *)
(* -------------------------------------------- *)
(* -------------------------------------------- *)
(* Skeleton for Lab; *)
(* fill in all missing sections. *)
(* -------------------------------------------- *)
(* -------------------------------------------- *)
(* Imp: expressions language (Watt, Ex. 3.6) *)
(* with commands (store).. *)
(* and definitions (evnironment).. *)
(* -- *)
(* (A nicer version of Ex. 4.7 from text) *)
(* -------------------------------------------- *)
(* -------------------------------------------- *)
(* ---------- Abstract Syntax ----------------- *)
(* terminal nodes of the syntax *)
type Numeral = int;
type Ident = string;
(* parsed phrases of the abstract syntax *)
datatype
Command =
skip
| assign of Ident * Expression
| letin of Declaration * Command
| cmdcmd of Command * Command
| ifthen of Expression * Command * Command
| whiledo of Expression * Command
and
Expression =
num of Numeral
| False
| True
| id of Ident
| sumof of Expression * Expression
| subof of Expression * Expression
| prodof of Expression * Expression
| less of Expression * Expression
(* | leten of Declaration * Expression *)
| notexp of Expression
and
Declaration =
constdef of Ident * Expression
| vardef of Ident * TypeDef
and
TypeDef =
Bool | Int
;
(* -------------------------------------------- *)
(* ---------- Semantic Domains ---------------- *)
type Integer = int;
type Boolean = bool;
type Location= int;
datatype Value = integer of int
| truth_value of bool;
type Storable = Value;
datatype Bindable = value of Value | variable of Location;
datatype Denotable = unbound | bound of Bindable ;
exception fail;
(* -------------------------------------------- *)
(* ---------- Semantic Functions -------------- *)
(* These declarations are automatically inferred
* from the defining equations below...
type Environ = Ident -> Denotable;
(..old..)
type Store = Location -> (Storable + undef + unused);
type execute = Command -> Environ -> Store -> Store;
type evaluate = Expression -> Environ -> Store -> Value;
type elaborate = Definition -> Environ -> Store -> (Environ * Store);
*)
(* -------------------------------------------- *)
(* ---------- Auxiliary Semantic Functions ---- *)
fun sum (x, y) = x + y:int;
fun diff (x, y) = x - y:int;
fun prod (x, y) = x * y:int;
fun lessthan (x, y) = x < (y:int);
(* ---------- Storage ---------- *)
(*
fun deallocate sto loc:Location = sto; (* ... later *)
*)
datatype Sval = stored of Storable | undef | unused;
(* --bot--- --top--- ----data--------- *)
datatype Store = store of Location * Location * (Location -> Sval);
val sto_init = fn loc:Location => unused;
val sto_null = store( 1, 0, sto_init);
fun update (store(bot,top,data), loc, v) =
let fun new adr = if adr=loc
then stored v else (data adr);
in store( bot, top, new)
end;
(* fetch from store, and convert into Storable (=Value) *)
fun fetch (store(bot,top,data), loc:Location) =
let fun stored_value(stored stble) = stble
| stored_value(unused) = raise fail
| stored_value(undef) = raise fail
in stored_value( data loc)
end;
(* create a new "undefined" location in a store *)
fun allocate ( store(bot,top,data) ) =
let val newtop = top+1
fun new adr = if adr=newtop
then undef else (data adr);
in (store( bot, newtop, new), newtop)
end;
(* ---------- Envirionment ---------- *)
type Environ = Ident -> Denotable;
val env_null = fn i:Ident => unbound;
fun bind (name, vl) = fn idn => if idn=(name:Ident)
then bound(vl) else unbound;
fun find (env:Environ, idn) =
let fun getbv(bound bdbl) = bdbl
| getbv(unbound) = raise fail
in getbv( env idn)
end;
fun overlay (env', env:Environ) =
fn idn => let val val' = env' idn
in if val'<>unbound then val'
else env idn
end;
(* ---------- Etc.... ---------- *)
(* coerce a Bindable into a Value.. *)
fun coerc (sto, value v) = v
| coerc (sto, variable loc) = fetch(sto,loc);
(* ---------- Initialize system ---------- *)
(* -------------------------------------------- *)
(* ---------- Semantic Equations -------------- *)
(* from integer to Value *)
fun valuation ( n ) = integer(n)
and
execute ( skip ) env sto = sto
| execute ( assign(name,exp) ) env sto =
let val rhs = evaluate exp env sto
val variable loc = find( env,name)
in update( sto, loc, rhs)
end
| execute ( letin(def,c) ) env sto =
...
| execute ( cmdcmd(c1,c2) ) env sto =
...
| execute ( ifthen(e,c1,c2) ) env sto =
...
| execute ( whiledo(e,c) ) en st =
...
and
(* simple, just build a Value *)
evaluate ( num(n) ) env sto = integer n
| evaluate ( True ) env sto = truth_value true
| evaluate ( False ) env sto = truth_value false
(* lookup id, and coerce as needed *)
| evaluate ( id(n) ) env sto = coerc( sto, find(env,n) )
(* get values, and compute result *)
| evaluate ( sumof (e1,e2) ) env sto =
let val integer(i1) = evaluate e1 env sto
val integer(i2) = evaluate e2 env sto
in integer( sum(i1,i2) )
end
| evaluate ( subof (e1,e2) ) env sto =
...
| evaluate ( prodof(e1,e2) ) env sto =
...
| evaluate ( less(e1,e2) ) env sto =
...
| evaluate ( notexp(e) ) env sto =
...
(* ------- * Later...
(* layer enviroinment, and compute result *)
| evaluate ( leten(def,e) ) env sto =
let val (env', sto') = elaborate def env sto
in evaluate e (overlay (env', env)) sto'
end
* ------- *)
and
elaborate ( constdef(name,e) ) env sto =
let val v = evaluate e env sto
in ( bind(name, value v), sto )
end
| elaborate ( vardef(name,tdef) ) env sto =
...
;
(* ============================================ *)
(* ---------- Test it..! ---------------------- *)
val e1 = num(2);
val e2 = sumof(num(1),num(2));
evaluate e1 env_null sto_null; (* = 2 *)
evaluate e2 env_null sto_null; (* = 3 *)
evaluate (sumof(num(1), prodof(num(2),num(3)))) env_null sto_null; (* = 7 *)
val dx = constdef("x",num(2)); (* a declaration *)
elaborate dx env_null sto_null;
(*
evaluate ( letin( dx, sumof( num(1), id("x") )) ) env_null sto_null; (* = 3 *)
*)
(* ----------------------------------------------- *)
(* let const x ~ 2
* in let var y : int
* in y:= 3
* if x