main
Francesco Minnocci 2 years ago
parent 7d9c4a6d3e
commit 245052f4b9
Signed by: BachoSeven
GPG Key ID: 2BE4AB7FDAD828A4

@ -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…
Cancel
Save