Add lab9
parent
7d9c4a6d3e
commit
245052f4b9
@ -0,0 +1,365 @@
|
|||||||
|
(* syntax *)
|
||||||
|
|
||||||
|
type ide = string
|
||||||
|
|
||||||
|
type boolean =
|
||||||
|
| True
|
||||||
|
| False
|
||||||
|
|
||||||
|
type exp =
|
||||||
|
| Eint of int
|
||||||
|
| Eplus of (exp * exp)
|
||||||
|
| Eminus of (exp * exp)
|
||||||
|
| Eide of ide
|
||||||
|
| Ebool of boolean
|
||||||
|
| Eeql of (exp * exp)
|
||||||
|
| Eleq of (exp * exp)
|
||||||
|
| Enot of exp
|
||||||
|
| Eand of (exp * exp)
|
||||||
|
| Eor of (exp * exp)
|
||||||
|
| Eifthenelse of (exp * exp * exp)
|
||||||
|
|
||||||
|
type com =
|
||||||
|
| Cassign of ide * exp
|
||||||
|
| Cvar of ide * exp
|
||||||
|
| Cconst of ide * exp
|
||||||
|
| Cifthenelse of exp * pseq * pseq
|
||||||
|
| Cwhile of exp * pseq
|
||||||
|
| CDoNTimes of exp * pseq
|
||||||
|
|
||||||
|
and pseq =
|
||||||
|
| Pseq of com * pseq
|
||||||
|
| Pend
|
||||||
|
|
||||||
|
type prog = Prog of pseq * exp
|
||||||
|
|
||||||
|
let rec exp_to_string (e: exp) =
|
||||||
|
match e with
|
||||||
|
| Eint i -> sprintf "%d" i
|
||||||
|
| Eplus (e1, e2) -> sprintf "(%s + %s)" (exp_to_string e1) (exp_to_string e2)
|
||||||
|
| Eminus (e1, e2) -> sprintf "(%s - %s)" (exp_to_string e1) (exp_to_string e2)
|
||||||
|
| Eide i -> i
|
||||||
|
| Ebool b ->
|
||||||
|
match b with
|
||||||
|
| True -> "true"
|
||||||
|
| False -> "false"
|
||||||
|
| Enot e -> sprintf "(not %s)" (exp_to_string e)
|
||||||
|
| Eand (e1, e2) -> sprintf "(%s and %s)" (exp_to_string e1) (exp_to_string e2)
|
||||||
|
| Eor (e1, e2) -> sprintf "(%s or %s)" (exp_to_string e1) (exp_to_string e2)
|
||||||
|
| Eeql (e1, e2) -> sprintf "(%s == %s)" (exp_to_string e1) (exp_to_string e2)
|
||||||
|
| Eleq (e1, e2) -> sprintf "(%s <= %s)" (exp_to_string e1) (exp_to_string e2)
|
||||||
|
| Eifthenelse (c, e1, e2) ->
|
||||||
|
sprintf "if %s then (%s) else (%s)" (exp_to_string c) (exp_to_string e1) (exp_to_string e2)
|
||||||
|
|
||||||
|
let rec com_to_string (c: com) =
|
||||||
|
match c with
|
||||||
|
| Cassign (i, e) -> sprintf "%s := %s" i (exp_to_string e)
|
||||||
|
| Cvar (v, e) -> sprintf "var %s := %s" v (exp_to_string e)
|
||||||
|
| Cconst (v, e) -> sprintf "const %s = %s" v (exp_to_string e)
|
||||||
|
| Cifthenelse (cond, cthen, celse) ->
|
||||||
|
sprintf "if %s\nthen %s\nelse %s" (exp_to_string cond) (pseq_to_string cthen) (pseq_to_string celse)
|
||||||
|
| Cwhile (cond, body) -> sprintf "while %s\n%s" (exp_to_string cond) (pseq_to_string body)
|
||||||
|
| CDoNTimes (n, body) -> sprintf "do %s times:\n%s" (exp_to_string n) (pseq_to_string body)
|
||||||
|
|
||||||
|
and pseq_to_string (s: pseq) =
|
||||||
|
match s with
|
||||||
|
| Pseq (c, Pend) -> sprintf "%s" (com_to_string c)
|
||||||
|
| Pseq (c, q) -> sprintf "%s;\n%s" (com_to_string c) (pseq_to_string q)
|
||||||
|
| Pend -> ""
|
||||||
|
|
||||||
|
let prog_to_string (p: prog) =
|
||||||
|
match p with
|
||||||
|
| Prog (s, e) -> sprintf "%s;\nreturn %s" (pseq_to_string s) (exp_to_string e)
|
||||||
|
|
||||||
|
(* error handling *)
|
||||||
|
|
||||||
|
let unbound_identifier_error ide =
|
||||||
|
failwith (sprintf "unbound identifier %s" ide)
|
||||||
|
|
||||||
|
let negative_natural_number_error () =
|
||||||
|
failwith "natural numbers must be positive or zero"
|
||||||
|
|
||||||
|
let type_error () = failwith "type error"
|
||||||
|
|
||||||
|
let memory_error () =
|
||||||
|
failwith "access to a location that is not available"
|
||||||
|
|
||||||
|
let not_a_location_error i =
|
||||||
|
failwith (sprintf "not a location: %s" i)
|
||||||
|
|
||||||
|
(* semantic domains *)
|
||||||
|
|
||||||
|
type eval =
|
||||||
|
| Int of int
|
||||||
|
| Bool of bool
|
||||||
|
|
||||||
|
type loc = int
|
||||||
|
|
||||||
|
type mval = eval
|
||||||
|
|
||||||
|
type store = int * (loc -> mval) (* il primo elemento della coppia è la minima locazione non definita *)
|
||||||
|
|
||||||
|
let empty_store = (0, (fun l -> memory_error ()))
|
||||||
|
|
||||||
|
let apply_store st l = (snd st) l
|
||||||
|
|
||||||
|
let allocate: store -> loc * store =
|
||||||
|
fun st ->
|
||||||
|
let l = fst st in
|
||||||
|
let l1 = l + 1 in
|
||||||
|
let st1 = (l1, snd st) in
|
||||||
|
(l, st1)
|
||||||
|
|
||||||
|
let update: store -> loc -> mval -> store =
|
||||||
|
fun st l mv ->
|
||||||
|
match st with
|
||||||
|
| (maxloc, fn) -> let fn1 l1 = if l = l1 then mv else fn l1 in (maxloc, fn1)
|
||||||
|
|
||||||
|
type dval =
|
||||||
|
| E of eval
|
||||||
|
| L of loc
|
||||||
|
|
||||||
|
type env = ide -> dval
|
||||||
|
|
||||||
|
let empty_env = fun v -> unbound_identifier_error v
|
||||||
|
|
||||||
|
let bind e v r = fun v1 -> if v1 = v then r else e v1
|
||||||
|
|
||||||
|
let apply_env e v = e v
|
||||||
|
|
||||||
|
let rec eval_to_string (e: eval) =
|
||||||
|
match e with
|
||||||
|
| Int i -> sprintf "%d" i
|
||||||
|
| Bool b -> if b then "true" else "false"
|
||||||
|
|
||||||
|
(* denotational semantics *)
|
||||||
|
|
||||||
|
let rec esem: exp -> env -> store -> eval =
|
||||||
|
fun e ev st ->
|
||||||
|
match e with
|
||||||
|
| Eint i ->
|
||||||
|
if i < 0 then
|
||||||
|
negative_natural_number_error ()
|
||||||
|
else
|
||||||
|
Int i
|
||||||
|
| Eplus (e1, e2) ->
|
||||||
|
(let s1 = esem e1 ev st in
|
||||||
|
let s2 = esem e2 ev st in
|
||||||
|
|
||||||
|
match (s1, s2) with
|
||||||
|
| (Int i1, Int i2) -> Int(i1 + i2)
|
||||||
|
| _ -> type_error ())
|
||||||
|
| Eminus (e1, e2) ->
|
||||||
|
let s1 = esem e1 ev st in
|
||||||
|
let s2 = esem e2 ev st in
|
||||||
|
|
||||||
|
(match (s1, s2) with
|
||||||
|
| (Int i1, Int i2) ->
|
||||||
|
if i1 >= i2 then
|
||||||
|
Int(i1 - i2)
|
||||||
|
else
|
||||||
|
negative_natural_number_error ()
|
||||||
|
| _ -> type_error ())
|
||||||
|
| Ebool b ->
|
||||||
|
(match b with
|
||||||
|
| True -> Bool true
|
||||||
|
| False -> Bool false)
|
||||||
|
| Eeql (e1, e2) ->
|
||||||
|
let s1 = esem e1 ev st in
|
||||||
|
let s2 = esem e2 ev st in
|
||||||
|
|
||||||
|
(match (s1, s2) with
|
||||||
|
| (Int i1, Int i2) ->
|
||||||
|
if i1 = i2 then
|
||||||
|
Bool true
|
||||||
|
else
|
||||||
|
Bool false
|
||||||
|
| _ -> type_error ())
|
||||||
|
| Eleq (e1, e2) ->
|
||||||
|
let s1 = esem e1 ev st in
|
||||||
|
let s2 = esem e2 ev st in
|
||||||
|
|
||||||
|
(match (s1, s2) with
|
||||||
|
| (Int i1, Int i2) ->
|
||||||
|
if i1 <= i2 then
|
||||||
|
Bool true
|
||||||
|
else
|
||||||
|
Bool false
|
||||||
|
| _ -> type_error ())
|
||||||
|
| Eand (e1, e2) ->
|
||||||
|
let s1 = esem e1 ev st in
|
||||||
|
let s2 = esem e2 ev st in
|
||||||
|
|
||||||
|
(match (s1, s2) with
|
||||||
|
| (Bool b1, Bool b2) -> Bool(b1 && b2)
|
||||||
|
| _ -> type_error ())
|
||||||
|
| Eor (e1, e2) ->
|
||||||
|
let s1 = esem e1 ev st in
|
||||||
|
let s2 = esem e2 ev st in
|
||||||
|
|
||||||
|
(match (s1, s2) with
|
||||||
|
| (Bool b1, Bool b2) -> Bool(b1 || b2)
|
||||||
|
| _ -> type_error ())
|
||||||
|
| Enot e ->
|
||||||
|
let s = esem e ev st in
|
||||||
|
|
||||||
|
(match s with
|
||||||
|
| Bool b -> Bool(not b)
|
||||||
|
| _ -> type_error ())
|
||||||
|
| Eifthenelse (c, e1, e2) ->
|
||||||
|
let sc = esem c ev st in
|
||||||
|
|
||||||
|
(match sc with
|
||||||
|
| Bool b -> esem (if b then e1 else e2) ev st
|
||||||
|
| _ -> type_error ())
|
||||||
|
| Eide i ->
|
||||||
|
let value = apply_env ev i
|
||||||
|
|
||||||
|
match value with
|
||||||
|
| L l -> apply_store st l
|
||||||
|
| E e -> e
|
||||||
|
|
||||||
|
let rec csem: com -> env -> store -> (env * store) =
|
||||||
|
fun c ev st ->
|
||||||
|
match c with
|
||||||
|
| Cassign (i, e) ->
|
||||||
|
let s = esem e ev st
|
||||||
|
|
||||||
|
match apply_env ev i with
|
||||||
|
| L l -> let st1 = update st l s in (ev, st1)
|
||||||
|
| _ -> not_a_location_error i
|
||||||
|
| Cvar (i, e) ->
|
||||||
|
let s = esem e ev st in
|
||||||
|
let (newloc, st1) = allocate st in
|
||||||
|
let st2 = update st1 newloc s in
|
||||||
|
let ev1 = bind ev i (L newloc) in
|
||||||
|
(ev1, st2)
|
||||||
|
| Cconst (i, e) ->
|
||||||
|
let s = esem e ev st in
|
||||||
|
let ev1 = bind ev i (E s) in
|
||||||
|
(ev1, st)
|
||||||
|
| Cifthenelse (cond, cthen, celse) ->
|
||||||
|
let s = esem cond ev st in
|
||||||
|
|
||||||
|
match s with
|
||||||
|
| Bool b ->
|
||||||
|
if b then
|
||||||
|
pssem cthen ev st // ERRORE: questo causa scoping dinamico, vale a dire, le variabili dichiarate nel ramo then possono essere viste dal seguito del programma
|
||||||
|
else
|
||||||
|
pssem celse ev st
|
||||||
|
| _ -> type_error ()
|
||||||
|
| Cwhile (cond, body) ->
|
||||||
|
let s = esem cond ev st in
|
||||||
|
|
||||||
|
match st with
|
||||||
|
| (firstloc,stfn) ->
|
||||||
|
|
||||||
|
match s with
|
||||||
|
| Bool b ->
|
||||||
|
if b then
|
||||||
|
// ERRORE, non va restituito st1 ma st1 con "maxloc" (primo elemento della coppia) resettata
|
||||||
|
(* let (ev1, st1) = pssem body ev st in
|
||||||
|
* csem (Cwhile(cond, body)) ev st1 *)
|
||||||
|
// Invece, resettiamo maxloc a quello vecchio per st1
|
||||||
|
let (ev1, (firstloc',stfn')) = pssem body ev st in
|
||||||
|
csem (Cwhile(cond, body)) ev (firstloc,stfn')
|
||||||
|
(* NOTA CHE L'AMBIENTE VIENE BUTTATO VIA, LO STATO NO, PERCHE'? *)
|
||||||
|
else
|
||||||
|
(ev, st)
|
||||||
|
| _ -> type_error ()
|
||||||
|
| CDoNTimes (n,body) ->
|
||||||
|
let n = esem n ev st
|
||||||
|
|
||||||
|
match n with
|
||||||
|
| Int 0 -> (ev, st)
|
||||||
|
| Int m ->
|
||||||
|
let (ev1, st1) = pssem body ev st
|
||||||
|
csem (CDoNTimes(Eint(m-1),body)) ev st1
|
||||||
|
| _ -> type_error ()
|
||||||
|
|
||||||
|
and pssem: pseq -> env -> store -> (env * store) =
|
||||||
|
fun s ev st ->
|
||||||
|
match s with
|
||||||
|
| Pend -> (ev, st)
|
||||||
|
| Pseq (c, q) ->
|
||||||
|
match csem c ev st with
|
||||||
|
| (ev1, st1) -> pssem q ev1 st1
|
||||||
|
|
||||||
|
let rec psem: prog -> env -> store -> eval =
|
||||||
|
fun p ev st ->
|
||||||
|
match p with
|
||||||
|
| Prog (s, e) ->
|
||||||
|
let (ev1, st1) = pssem s ev st
|
||||||
|
esem e ev1 st1
|
||||||
|
|
||||||
|
(* test *)
|
||||||
|
|
||||||
|
let eval: prog -> unit =
|
||||||
|
fun p ->
|
||||||
|
printf "\n%s \n\n==> " (prog_to_string p)
|
||||||
|
|
||||||
|
try
|
||||||
|
printf "%s\n" (eval_to_string (psem p empty_env empty_store))
|
||||||
|
with
|
||||||
|
| Failure message -> printfn "error: %s\n" message
|
||||||
|
|
||||||
|
let a () = failwith ""
|
||||||
|
|
||||||
|
let l =
|
||||||
|
[ Prog(
|
||||||
|
Pseq(
|
||||||
|
Cvar("x", Eint 98),
|
||||||
|
(Pseq(
|
||||||
|
Cvar("y", Eint 28),
|
||||||
|
(Pseq(
|
||||||
|
Cwhile(
|
||||||
|
Enot(Eeql(Eide "x", Eide "y")),
|
||||||
|
Pseq(
|
||||||
|
Cifthenelse(
|
||||||
|
Eleq(Eide "x", Eide "y"),
|
||||||
|
Pseq(Cassign("y", Eminus(Eide "y", Eide "x")), Pend),
|
||||||
|
Pseq(Cassign("x", Eminus(Eide "x", Eide "y")), Pend)
|
||||||
|
),
|
||||||
|
Pend
|
||||||
|
)
|
||||||
|
),
|
||||||
|
Pend
|
||||||
|
))
|
||||||
|
))
|
||||||
|
),
|
||||||
|
Eide "x"
|
||||||
|
) ]
|
||||||
|
|
||||||
|
let l2 =
|
||||||
|
[ Prog(
|
||||||
|
Pseq(
|
||||||
|
Cvar("x", Eint 1),
|
||||||
|
(Pseq(
|
||||||
|
Cvar("y", Eint 0),
|
||||||
|
Pseq(
|
||||||
|
CDoNTimes(Eint(9),Pseq(Cassign("y", Eplus(Eide "y", Eide "x")),Pend)),
|
||||||
|
Pend
|
||||||
|
)
|
||||||
|
))
|
||||||
|
),
|
||||||
|
Eide "x"
|
||||||
|
) ]
|
||||||
|
|
||||||
|
let main = List.iter eval l
|
||||||
|
let main2 = List.iter eval l2
|
||||||
|
|
||||||
|
(*
|
||||||
|
|
||||||
|
> dotnet run
|
||||||
|
|
||||||
|
var x := 98;
|
||||||
|
var y := 28;
|
||||||
|
while (not (x == y))
|
||||||
|
if (x <= y)
|
||||||
|
then y := (y - x)
|
||||||
|
else x := (x - y);
|
||||||
|
return x
|
||||||
|
|
||||||
|
==> 14
|
||||||
|
|
||||||
|
*)
|
Loading…
Reference in New Issue