(* this file can be a "drop-in replacement" for interp.ml from hw1 *) open Ast (* all about _when_ things are computed, though hard to tell b/c everything is functional in the metalanguage In particular, if we float the fun h out, then our denotations are still deconstructing abstract syntax -- basically a large-step semantics -- as we do it here, our denotations make no use of abstract syntax, which is cool! And look at if case -- we actually denote both sides! *) (* See how our language without "functions" is denoted by OCaml functions taking heaps *) let rec denote_exp e = match e with Int i -> (fun h -> i) | Var v -> (fun h -> h v) | Plus(e1,e2) -> let d1 = denote_exp e1 in let d2 = denote_exp e2 in (fun h -> (d1 h) + (d2 h)) | Times(e1,e2) -> let d1 = denote_exp e1 in let d2 = denote_exp e2 in (fun h -> (d1 h) * (d2 h)) let rec denote_stmt s = match s with Skip -> (fun h -> h) | Assign(v,e) -> let d = denote_exp e in (fun h -> let c = d h in fun x -> if x=v then c else h x) | Seq(s1,s2) -> let d1 = denote_stmt s1 in let d2 = denote_stmt s2 in (fun h -> d2 (d1 h)) (* i.e., s2 o s1 *) | If(e,s1,s2) -> let d1 = denote_exp e in let d2 = denote_stmt s1 in let d3 = denote_stmt s2 in (fun h -> if (d1 h)==0 then (d2 h) else (d3 h)) | While(e,s) -> let d1 = denote_exp e in let d2 = denote_stmt s in let rec f h = if (d1 h) > 0 then f (d2 h) else h in f let denote_prog s = let d = denote_stmt s in fun () -> (d (fun x -> 0)) "ans" let get_prog () = let argv = Sys.argv in let _ = if Array.length argv != 2 then (prerr_string ("usage: " ^ argv.(0) ^ " [file-to-interpret]\n"); exit 1) in let ch = open_in argv.(1) in Parse.program Lex.lexer (Lexing.from_channel ch) (* run the translated program *) let _ = let prog = get_prog () in print_string ("ans = " ^ string_of_int ((denote_prog prog) ()) ^ "\n")