Advertisement
Guest User

Untitled

a guest
Sep 1st, 2018
103
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
F# 12.36 KB | None | 0 0
  1. (* Programming language concepts for software developers, 2012-02-17 *)
  2.  
  3. (* Evaluation, checking, and compilation of object language expressions *)
  4. (* Stack machines for expression evaluation                             *)
  5.  
  6. (* Object language expressions with variable bindings and nested scope *)
  7.  
  8. module Intcomp1
  9.  
  10. type expr =
  11.   | CstI of int
  12.   | Var of string
  13.   | Let of string * expr * expr
  14.   | Prim of string * expr * expr;;
  15.  
  16. (* Some closed expressions: *)
  17.  
  18. let e1 = Let("z", CstI 17, Prim("+", Var "z", Var "z"));;
  19.  
  20. let e2 = Let("z", CstI 17,
  21.              Prim("+", Let("z", CstI 22, Prim("*", CstI 100, Var "z")),
  22.                        Var "z"));;
  23.  
  24. let e3 = Let("z", Prim("-", CstI 5, CstI 4),
  25.              Prim("*", CstI 100, Var "z"));;
  26.  
  27. let e4 = Prim("+", Prim("+", CstI 20, Let("z", CstI 17,
  28.                                           Prim("+", Var "z", CstI 2))),
  29.                    CstI 30);;
  30.  
  31. let e5 = Prim("*", CstI 2, Let("x", CstI 3, Prim("+", Var "x", CstI 4)));;
  32.  
  33. (* ---------------------------------------------------------------------- *)
  34.  
  35. (* Evaluation of expressions with variables and bindings *)
  36.  
  37. let rec lookup env x =
  38.     match env with
  39.     | []        -> failwith (x + " not found")
  40.     | (y, v)::r -> if x=y then v else lookup r x;;
  41.  
  42. let rec eval e (env : (string * int) list) : int =
  43.     match e with
  44.     | CstI i            -> i
  45.     | Var x             -> lookup env x
  46.     | Let(x, erhs, ebody) ->
  47.       let xval = eval erhs env
  48.       let env1 = (x, xval) :: env
  49.       eval ebody env1
  50.     | Prim("+", e1, e2) -> eval e1 env + eval e2 env
  51.     | Prim("*", e1, e2) -> eval e1 env * eval e2 env
  52.     | Prim("-", e1, e2) -> eval e1 env - eval e2 env
  53.     | Prim _            -> failwith "unknown primitive";;
  54.  
  55. let run e = eval e [];;
  56.  
  57. (* ---------------------------------------------------------------------- *)
  58.  
  59. (* Closedness *)
  60.  
  61. // let mem x vs = List.exists (fun y -> x=y) vs;;
  62.  
  63. let rec mem x vs =
  64.     match vs with
  65.     | []      -> false
  66.     | v :: vr -> x=v || mem x vr;;
  67.  
  68. (* Checking whether an expression is closed.  The vs is
  69.    a list of the bound variables.  *)
  70.  
  71. let rec closedin (e : expr) (vs : string list) : bool =
  72.     match e with
  73.     | CstI i -> true
  74.     | Var x  -> List.exists (fun y -> x=y) vs
  75.     | Let(x, erhs, ebody) ->
  76.       let vs1 = x :: vs
  77.       closedin erhs vs && closedin ebody vs1
  78.     | Prim(ope, e1, e2) -> closedin e1 vs && closedin e2 vs;;
  79.  
  80. (* An expression is closed if it is closed in the empty environment *)
  81.  
  82. let closed1 e = closedin e [];;
  83.  
  84.  
  85. (* ---------------------------------------------------------------------- *)
  86.  
  87. (* Substitution of expressions for variables *)
  88.  
  89. (* This version of lookup returns a Var(x) expression if there is no
  90.    pair (x,e) in the list env --- instead of failing with exception: *)
  91.  
  92. let rec lookOrSelf env x =
  93.     match env with
  94.     | []        -> Var x
  95.     | (y, e)::r -> if x=y then e else lookOrSelf r x;;
  96.  
  97. (* Remove (x, _) from env: *)
  98.  
  99. let rec remove env x =
  100.     match env with
  101.     | []        -> []
  102.     | (y, e)::r -> if x=y then r else (y, e) :: remove r x;;
  103.  
  104. (* Naive substitution, may capture free variables: *)
  105.  
  106. let rec nsubst (e : expr) (env : (string * expr) list) : expr =
  107.     match e with
  108.     | CstI i -> e
  109.     | Var x  -> lookOrSelf env x
  110.     | Let(x, erhs, ebody) ->
  111.       let newenv = remove env x
  112.       Let(x, nsubst erhs env, nsubst ebody newenv)
  113.     | Prim(ope, e1, e2) -> Prim(ope, nsubst e1 env, nsubst e2 env)
  114.  
  115. (* Some expressions with free variables: *)
  116.  
  117. let e6 = Prim("+", Var "y", Var "z");;
  118.  
  119. let e6s1 = nsubst e6 [("z", CstI 17)];;
  120.  
  121. let e6s2 = nsubst e6 [("z", Prim("-", CstI 5, CstI 4))];;
  122.  
  123. let e6s3 = nsubst e6 [("z", Prim("+", Var "z", Var "z"))];;
  124.  
  125. // Shows that only z outside the Let gets substituted:
  126. let e7 = Prim("+", Let("z", CstI 22, Prim("*", CstI 5, Var "z")),
  127.                    Var "z");;
  128.  
  129. let e7s1 = nsubst e7 [("z", CstI 100)];;
  130.  
  131. // Shows that only the z in the Let rhs gets substituted
  132. let e8 = Let("z", Prim("*", CstI 22, Var "z"), Prim("*", CstI 5, Var "z"));;
  133.  
  134. let e8s1 = nsubst e8 [("z", CstI 100)];;
  135.  
  136. // Shows (wrong) capture of free variable z under the let:
  137. let e9 = Let("z", CstI 22, Prim("*", Var "y", Var "z"));;
  138.  
  139. let e9s1 = nsubst e9 [("y", Var "z")];;
  140.  
  141. //
  142. let e9s2 = nsubst e9 [("z", Prim("-", CstI 5, CstI 4))];;
  143.  
  144. let newVar : string -> string =
  145.     let n = ref 0
  146.     let varMaker x = (n := 1 + !n; x + string (!n))
  147.     varMaker;;
  148.  
  149. (* Correct, capture-avoiding substitution *)
  150.  
  151. let rec subst (e : expr) (env : (string * expr) list) : expr =
  152.     match e with
  153.     | CstI i -> e
  154.     | Var x  -> lookOrSelf env x
  155.     | Let(x, erhs, ebody) ->
  156.       let newx = newVar x
  157.       let newenv = (x, Var newx) :: remove env x
  158.       Let(newx, subst erhs env, subst ebody newenv)
  159.     | Prim(ope, e1, e2) -> Prim(ope, subst e1 env, subst e2 env)
  160.  
  161. let e6s1a = subst e6 [("z", CstI 17)];;
  162.  
  163. let e6s2a = subst e6 [("z", Prim("-", CstI 5, CstI 4))];;
  164.  
  165. let e6s3a = subst e6 [("z", Prim("+", Var "z", Var "z"))];;
  166.  
  167.  
  168. // Shows renaming of bound variable z (to z1)
  169. let e7s1a = subst e7 [("z", CstI 100)];;
  170.  
  171. // Shows renaming of bound variable z (to z2)
  172. let e8s1a = subst e8 [("z", CstI 100)];;
  173.  
  174. // Shows renaming of bound variable z (to z3), avoiding capture of free z
  175. let e9s1a = subst e9 [("y", Var "z")];;
  176.  
  177. (* ---------------------------------------------------------------------- *)
  178.  
  179. (* Free variables *)
  180.  
  181. (* Operations on sets, represented as lists.  Simple but inefficient;
  182.    one could use binary trees, hashtables or splaytrees for
  183.    efficiency.  *)
  184.  
  185. (* union(xs, ys) is the set of all elements in xs or ys, without duplicates *)
  186.  
  187. let rec union (xs, ys) =
  188.     match xs with
  189.     | []    -> ys
  190.     | x::xr -> if mem x ys then union(xr, ys)
  191.                else x :: union(xr, ys);;
  192.  
  193. (* minus xs ys  is the set of all elements in xs but not in ys *)
  194.  
  195. let rec minus (xs, ys) =
  196.     match xs with
  197.     | []    -> []
  198.     | x::xr -> if mem x ys then minus(xr, ys)
  199.                else x :: minus (xr, ys);;
  200.  
  201. (* Find all variables that occur free in expression e *)
  202.  
  203. let rec freevars e : string list =
  204.     match e with
  205.     | CstI i -> []
  206.     | Var x  -> [x]
  207.     | Let(x, erhs, ebody) ->
  208.           union (freevars erhs, minus (freevars ebody, [x]))
  209.     | Prim(ope, e1, e2) -> union (freevars e1, freevars e2);;
  210.  
  211. (* Alternative definition of closed *)
  212.  
  213. let closed2 e = (freevars e = []);;
  214.  
  215.  
  216. (* ---------------------------------------------------------------------- *)
  217.  
  218. (* Compilation to target expressions with numerical indexes instead of
  219.    symbolic variable names.  *)
  220.  
  221. type texpr =                            (* target expressions *)
  222.   | TCstI of int
  223.   | TVar of int                         (* index into runtime environment *)
  224.   | TLet of texpr * texpr               (* erhs and ebody                 *)
  225.   | TPrim of string * texpr * texpr;;
  226.  
  227.  
  228. (* Map variable name to variable index at compile-time *)
  229.  
  230. let rec getindex vs x =
  231.     match vs with
  232.     | []    -> failwith "Variable not found"
  233.     | y::yr -> if x=y then 0 else 1 + getindex yr x;;
  234.  
  235. (* Compiling from expr to texpr *)
  236.  
  237. let rec tcomp (e : expr) (cenv : string list) : texpr =
  238.     match e with
  239.     | CstI i -> TCstI i
  240.     | Var x  -> TVar (getindex cenv x)
  241.     | Let(x, erhs, ebody) ->
  242.       let cenv1 = x :: cenv
  243.       TLet(tcomp erhs cenv, tcomp ebody cenv1)
  244.     | Prim(ope, e1, e2) -> TPrim(ope, tcomp e1 cenv, tcomp e2 cenv);;
  245.  
  246. (* Evaluation of target expressions with variable indexes.  The
  247.    run-time environment renv is a list of variable values (ints).  *)
  248.  
  249. let rec teval (e : texpr) (renv : int list) : int =
  250.     match e with
  251.     | TCstI i -> i
  252.     | TVar n  -> List.nth renv n
  253.     | TLet(erhs, ebody) ->
  254.       let xval = teval erhs renv
  255.       let renv1 = xval :: renv
  256.       teval ebody renv1
  257.     | TPrim("+", e1, e2) -> teval e1 renv + teval e2 renv
  258.     | TPrim("*", e1, e2) -> teval e1 renv * teval e2 renv
  259.     | TPrim("-", e1, e2) -> teval e1 renv - teval e2 renv
  260.     | TPrim _            -> failwith "unknown primitive";;
  261.  
  262. (* Correctness: eval e []  equals  teval (tcomp e []) [] *)
  263.  
  264.  
  265. (* ---------------------------------------------------------------------- *)
  266.  
  267. (* Stack machines *)
  268.  
  269. (* Stack machine instructions.  An expressions in postfix or reverse
  270.    Polish form is a list of stack machine instructions. *)
  271.  
  272. type rinstr =
  273.   | RCstI of int
  274.   | RAdd
  275.   | RSub
  276.   | RMul
  277.   | RDup
  278.   | RSwap;;
  279.  
  280. (* A simple stack machine for evaluation of variable-free expressions
  281.    in postfix form *)
  282.  
  283. let rec reval (inss : rinstr list) (stack : int list) : int =
  284.     match (inss, stack) with
  285.     | ([], v :: _) -> v
  286.     | ([], [])     -> failwith "reval: no result on stack!"
  287.     | (RCstI i :: insr,             stk)  -> reval insr (i::stk)
  288.     | (RAdd    :: insr, i2 :: i1 :: stkr) -> reval insr ((i1+i2)::stkr)
  289.     | (RSub    :: insr, i2 :: i1 :: stkr) -> reval insr ((i1-i2)::stkr)
  290.     | (RMul    :: insr, i2 :: i1 :: stkr) -> reval insr ((i1*i2)::stkr)
  291.     | (RDup    :: insr,       i1 :: stkr) -> reval insr (i1 :: i1 :: stkr)
  292.     | (RSwap   :: insr, i2 :: i1 :: stkr) -> reval insr (i1 :: i2 :: stkr)
  293.     | _ -> failwith "reval: too few operands on stack";;
  294.  
  295. let rpn1 = reval [RCstI 10; RCstI 17; RDup; RMul; RAdd] [];;
  296.  
  297.  
  298. (* Compilation of a variable-free expression to a rinstr list *)
  299.  
  300. let rec rcomp (e : expr) : rinstr list =
  301.     match e with
  302.     | CstI i            -> [RCstI i]
  303.     | Var _             -> failwith "rcomp cannot compile Var"
  304.     | Let _             -> failwith "rcomp cannot compile Let"
  305.     | Prim("+", e1, e2) -> rcomp e1 @ rcomp e2 @ [RAdd]
  306.     | Prim("*", e1, e2) -> rcomp e1 @ rcomp e2 @ [RMul]
  307.     | Prim("-", e1, e2) -> rcomp e1 @ rcomp e2 @ [RSub]
  308.     | Prim _            -> failwith "unknown primitive";;
  309.            
  310. (* Correctness: eval e []  equals  reval (rcomp e) [] *)
  311.  
  312.  
  313. (* Storing intermediate results and variable bindings in the same stack *)
  314.  
  315. type sinstr =
  316.   | SCstI of int                        (* push integer           *)
  317.   | SVar of int                         (* push variable from env *)
  318.   | SAdd                                (* pop args, push sum     *)
  319.   | SSub                                (* pop args, push diff.   *)
  320.   | SMul                                (* pop args, push product *)
  321.   | SPop                                (* pop value/unbind var   *)
  322.   | SSwap;;                             (* exchange top and next  *)
  323.  
  324. let rec seval (inss : sinstr list) (stack : int list) =
  325.     match (inss, stack) with
  326.     | ([], v :: _) -> v
  327.     | ([], [])     -> failwith "seval: no result on stack"
  328.     | (SCstI i :: insr,          stk) -> seval insr (i :: stk)
  329.     | (SVar i  :: insr,          stk) -> seval insr (List.nth stk i :: stk)
  330.     | (SAdd    :: insr, i2::i1::stkr) -> seval insr (i1+i2 :: stkr)
  331.     | (SSub    :: insr, i2::i1::stkr) -> seval insr (i1-i2 :: stkr)
  332.     | (SMul    :: insr, i2::i1::stkr) -> seval insr (i1*i2 :: stkr)
  333.     | (SPop    :: insr,    _ :: stkr) -> seval insr stkr
  334.     | (SSwap   :: insr, i2::i1::stkr) -> seval insr (i1::i2::stkr)
  335.     | _ -> failwith "seval: too few operands on stack";;
  336.  
  337.  
  338. (* A compile-time variable environment representing the state of
  339.    the run-time stack. *)
  340.  
  341. type stackvalue =
  342.   | Value                               (* A computed value *)
  343.   | Bound of string;;                   (* A bound variable *)
  344.  
  345. (* Compilation to a list of instructions for a unified-stack machine *)
  346.  
  347. let rec scomp (e : expr) (cenv : stackvalue list) : sinstr list =
  348.     match e with
  349.     | CstI i -> [SCstI i]
  350.     | Var x  -> [SVar (getindex cenv (Bound x))]
  351.     | Let(x, erhs, ebody) ->
  352.           scomp erhs cenv @ scomp ebody (Bound x :: cenv) @ [SSwap; SPop]
  353.     | Prim("+", e1, e2) ->
  354.           scomp e1 cenv @ scomp e2 (Value :: cenv) @ [SAdd]
  355.     | Prim("-", e1, e2) ->
  356.           scomp e1 cenv @ scomp e2 (Value :: cenv) @ [SSub]
  357.     | Prim("*", e1, e2) ->
  358.           scomp e1 cenv @ scomp e2 (Value :: cenv) @ [SMul]
  359.     | Prim _ -> failwith "scomp: unknown operator";;
  360.  
  361. let s1 = scomp e1 [];;
  362. let s2 = scomp e2 [];;
  363. let s3 = scomp e3 [];;
  364. let s5 = scomp e5 [];;
  365.  
  366. (* Output the integers in list inss to the text file called fname: *)
  367.  
  368. let intsToFile (inss : int list) (fname : string) =
  369.     let text = String.concat " " (List.map string inss)
  370.     System.IO.File.WriteAllText(fname, text);;
  371.  
  372. (* -----------------------------------------------------------------  *)
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement