Add code for lecture 1 (simple.ml)
Signed-off-by: jmug <u.g.a.mariano@gmail.com>
This commit is contained in:
parent
cfe502c598
commit
8437a82fbf
11 changed files with 392 additions and 0 deletions
111
lec01/simple/bin/simple.ml
Normal file
111
lec01/simple/bin/simple.ml
Normal file
|
|
@ -0,0 +1,111 @@
|
|||
(* simple.ml
|
||||
|
||||
Interpeter for a Simple IMperative Programming LanguagE.
|
||||
*)
|
||||
|
||||
(*
|
||||
*
|
||||
* Recall the BNF grammar for this SIMPLE language:
|
||||
*
|
||||
* <exp> ::=
|
||||
* | <X> // variables
|
||||
* | <exp> + <exp> // addition
|
||||
* | <exp> * <exp> // multiplication
|
||||
* | <exp> < <exp> // less-than
|
||||
* | <integer constant> // literal
|
||||
* | (<exp>)
|
||||
*
|
||||
* <cmd> ::=
|
||||
* | skip
|
||||
* | <X> = <exp>
|
||||
* | ifNZ <exp> { <cmd> } else { <cmd> }
|
||||
* | whileNZ <exp> { <cmd> }
|
||||
* | <cmd>; <cmd>
|
||||
*
|
||||
*)
|
||||
|
||||
|
||||
(*
|
||||
* OCaml datatypes that we use to represent SIMPLE abstract syntax.
|
||||
*
|
||||
* This is called _abstract syntax_ because it uses the labeled
|
||||
* tree structure rather than concrete keywords, punctuation marks, etc.,
|
||||
* to represent the program.
|
||||
*
|
||||
* For example, the concrete syntax for the following program:
|
||||
* (3 + X) * 2
|
||||
* is the tree:
|
||||
* Mul(Add(Lit 3, Var "X"), Lit 2)
|
||||
*)
|
||||
|
||||
|
||||
(* AST for the concrete syntax:
|
||||
|
||||
X = 6;
|
||||
ANS = 1;
|
||||
whileNZ (x) {
|
||||
ANS = ANS * X;
|
||||
X = X + -1;
|
||||
}
|
||||
*)
|
||||
|
||||
(*
|
||||
let factorial : cmd =
|
||||
Seq(Assn("X", Lit 6),
|
||||
Seq(Assn("ANS", Lit 1),
|
||||
WhileNZ(Var "X",
|
||||
Seq(Assn("ANS", Mul(Var "ANS", Var "X")),
|
||||
Assn("X", Add(Var "X", Lit (-1)))
|
||||
))
|
||||
))
|
||||
*)
|
||||
|
||||
(* interpreters and state --------------------------------------------------- *)
|
||||
|
||||
(* We can "interpret" a SIMPLE program by giving it a meaning in terms of
|
||||
* OCaml operations. One key question is how to represent the _state_ of
|
||||
* the SIMPLE program. Out intuition tells us that it should be a map
|
||||
* that sends variables to their (current) values. There are many ways that
|
||||
* we could represent such a state. Here, we use OCaml's functions.
|
||||
*)
|
||||
|
||||
(* The initial state maps every variable to 0 *)
|
||||
|
||||
|
||||
(* We can update an old state [s] to one that maps `x` to `v` but is otherwise
|
||||
* unchanged by building a new function like this: *)
|
||||
|
||||
|
||||
(* Looking up the value of a variable in a state is easy: *)
|
||||
|
||||
|
||||
(* To interpret an expression in a given state, we recursively compute the
|
||||
* values of subexpressions and then combine them according to the operation.
|
||||
*
|
||||
* One wrinkle: we have chosen to use only `int` as the domain of values,
|
||||
* so the result of a less-than comparison encodes "true" as 1 and "false" as 0.
|
||||
*)
|
||||
|
||||
|
||||
(* To interpret a command, we write an OCaml program that manipulates that
|
||||
* state as appropriate. The result of running a command is a final state.
|
||||
*
|
||||
* Note that `WhileNZ` "unfolds" the loop into a conditional that either
|
||||
* runs the loop body once and the coninues as another `WhileNZ`, or just
|
||||
* Skip.
|
||||
*
|
||||
* Note that the SIMPLE sequence of two commands is interpreted by the
|
||||
* sequencing of OCaml's `let` binding construct.
|
||||
*)
|
||||
|
||||
|
||||
(* We can write a program that runs the SIMPLE factorial program like this: *)
|
||||
|
||||
(*
|
||||
let main () =
|
||||
let s_ans : state = interpret_cmd init_state factorial in
|
||||
let ans : var = "ANS" in
|
||||
Printf.printf "ANS = %d\n" (lookup s_ans ans)
|
||||
|
||||
;; main ()
|
||||
*)
|
||||
Loading…
Add table
Add a link
Reference in a new issue