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
24
lec01/Makefile
Normal file
24
lec01/Makefile
Normal file
|
|
@ -0,0 +1,24 @@
|
||||||
|
CFLAGS := -mmacosx-version-min=10.12 -fno-vectorize -fno-slp-vectorize
|
||||||
|
|
||||||
|
parameters := O0 O1 O2 O3
|
||||||
|
|
||||||
|
.PHONY: all
|
||||||
|
all: factorialO0 factorialO1 factorialO2 factorialO3
|
||||||
|
|
||||||
|
LIBPATH := /Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX.sdk/usr/lib
|
||||||
|
|
||||||
|
|
||||||
|
define COMPILE_WITH_OPT
|
||||||
|
$(info DEFINING $1)
|
||||||
|
factorial$(1): factorial64.c
|
||||||
|
gcc $$(CFLAGS) -$(1) -emit-llvm -S -o factorial-$(1).ll factorial.c
|
||||||
|
gcc $$(CFLAGS) -$(1) -S -o factorial-$(1).s factorial-$(1).ll
|
||||||
|
as -o factorial-$(1).o factorial-$(1).s
|
||||||
|
ld -macosx_version_min 12.0 -L $(LIBPATH) -lSystem -o factorial-$(1) factorial-$(1).o
|
||||||
|
endef
|
||||||
|
|
||||||
|
$(foreach P, $(parameters), $(eval $(call COMPILE_WITH_OPT,$(P))))
|
||||||
|
|
||||||
|
|
||||||
|
clean:
|
||||||
|
rm -rf a.out factorial*.s factorial*.ll factorial*.o factorial-O?
|
||||||
12
lec01/factorial-rec.c
Normal file
12
lec01/factorial-rec.c
Normal file
|
|
@ -0,0 +1,12 @@
|
||||||
|
#include <stdio.h>
|
||||||
|
|
||||||
|
int factorial(int n) {
|
||||||
|
if (n == 0) {
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
return n * (factorial(n-1));
|
||||||
|
}
|
||||||
|
|
||||||
|
int main(int argc, char *argv[]) {
|
||||||
|
printf("factorial(6) = %d\n", factorial(6));
|
||||||
|
}
|
||||||
14
lec01/factorial.c
Normal file
14
lec01/factorial.c
Normal file
|
|
@ -0,0 +1,14 @@
|
||||||
|
#include <stdio.h>
|
||||||
|
|
||||||
|
int factorial(int n) {
|
||||||
|
int acc = 1;
|
||||||
|
while (n > 0) {
|
||||||
|
acc = acc * n;
|
||||||
|
n = n - 1;
|
||||||
|
}
|
||||||
|
return acc;
|
||||||
|
}
|
||||||
|
|
||||||
|
int main(int argc, char *argv[]) {
|
||||||
|
printf("factorial(6) = %d\n", factorial(6));
|
||||||
|
}
|
||||||
14
lec01/factorial64.c
Normal file
14
lec01/factorial64.c
Normal file
|
|
@ -0,0 +1,14 @@
|
||||||
|
#include <stdio.h>
|
||||||
|
|
||||||
|
long long int factorial(long long int n) {
|
||||||
|
long long int acc = 1;
|
||||||
|
while (n > 0) {
|
||||||
|
acc = acc * n;
|
||||||
|
n = n - 1;
|
||||||
|
}
|
||||||
|
return acc;
|
||||||
|
}
|
||||||
|
|
||||||
|
int main(int argc, char *argv[]) {
|
||||||
|
printf("factorial(6) = %llu\n", factorial(6));
|
||||||
|
}
|
||||||
2
lec01/simple/.ocamlformat
Normal file
2
lec01/simple/.ocamlformat
Normal file
|
|
@ -0,0 +1,2 @@
|
||||||
|
profile = janestreet
|
||||||
|
version = 0.26.1
|
||||||
23
lec01/simple/Makefile
Normal file
23
lec01/simple/Makefile
Normal file
|
|
@ -0,0 +1,23 @@
|
||||||
|
.PHONY: all oatc test clean zip
|
||||||
|
|
||||||
|
all: oatc
|
||||||
|
|
||||||
|
dev:
|
||||||
|
dune build --watch --terminal-persistence=clear-on-rebuild
|
||||||
|
|
||||||
|
oatc:
|
||||||
|
dune build
|
||||||
|
@cp bin/simple.exe oatc
|
||||||
|
|
||||||
|
test: oatc
|
||||||
|
./oatc --test
|
||||||
|
|
||||||
|
utop:
|
||||||
|
dune utop
|
||||||
|
|
||||||
|
zip: $(SUBMIT)
|
||||||
|
zip '$(ZIPNAME)' $(SUBMIT)
|
||||||
|
|
||||||
|
clean:
|
||||||
|
dune clean
|
||||||
|
rm -rf oatc bin/main.exe
|
||||||
10
lec01/simple/bin/dune
Normal file
10
lec01/simple/bin/dune
Normal file
|
|
@ -0,0 +1,10 @@
|
||||||
|
(env
|
||||||
|
(dev
|
||||||
|
(flags (:standard -warn-error -A))))
|
||||||
|
|
||||||
|
(executable
|
||||||
|
(public_name simple)
|
||||||
|
(name simple)
|
||||||
|
(modules simple)
|
||||||
|
(promote (until-clean)))
|
||||||
|
|
||||||
180
lec01/simple/bin/simple-soln.ml
Normal file
180
lec01/simple/bin/simple-soln.ml
Normal file
|
|
@ -0,0 +1,180 @@
|
||||||
|
(* 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)
|
||||||
|
*)
|
||||||
|
|
||||||
|
|
||||||
|
type var = string
|
||||||
|
|
||||||
|
type exp =
|
||||||
|
| Var of var
|
||||||
|
| Add of exp * exp
|
||||||
|
| Mul of exp * exp
|
||||||
|
| Lt of exp * exp
|
||||||
|
| Lit of int
|
||||||
|
|
||||||
|
type cmd =
|
||||||
|
| Skip
|
||||||
|
| Assn of var * exp
|
||||||
|
| IfNZ of exp * cmd * cmd
|
||||||
|
| WhileNZ of exp * cmd
|
||||||
|
| Seq of cmd * cmd
|
||||||
|
|
||||||
|
|
||||||
|
(* AST for the concrete syntax:
|
||||||
|
* (3 + X) * 2
|
||||||
|
*)
|
||||||
|
let example = 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 =
|
||||||
|
let x = "X" in
|
||||||
|
let ans = "ANS" in
|
||||||
|
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.
|
||||||
|
*)
|
||||||
|
type state = var -> int
|
||||||
|
|
||||||
|
(* The initial state maps every variable to 0 *)
|
||||||
|
let init_state : state =
|
||||||
|
fun x -> 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: *)
|
||||||
|
let update (s:state) (x:var) (v:int) : state =
|
||||||
|
fun (y:var) ->
|
||||||
|
if x = y then v else s y
|
||||||
|
|
||||||
|
|
||||||
|
(* Looking up the value of a variable in a state is easy: *)
|
||||||
|
let lookup (s:state) (x:var) : int = s x
|
||||||
|
|
||||||
|
|
||||||
|
(* 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.
|
||||||
|
*)
|
||||||
|
let rec interpret_exp (s:state) (e:exp) : int =
|
||||||
|
begin match e with
|
||||||
|
| Var x -> lookup s x
|
||||||
|
| Add(e1, e2) -> (interpret_exp s e1) + (interpret_exp s e2)
|
||||||
|
| Mul(e1, e2) -> (interpret_exp s e1) * (interpret_exp s e2)
|
||||||
|
| Lt(e1, e2) -> if (interpret_exp s e1) < (interpret_exp s e2) then 1 else 0
|
||||||
|
| Lit i -> i
|
||||||
|
end
|
||||||
|
|
||||||
|
(* 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.
|
||||||
|
*)
|
||||||
|
let rec interpret_cmd (s:state) (c:cmd) : state =
|
||||||
|
begin match c with
|
||||||
|
| Skip -> s
|
||||||
|
| Assn(x, e) -> update s x (interpret_exp s e)
|
||||||
|
| IfNZ(e, c1, c2) ->
|
||||||
|
if (interpret_exp s e) <> 0 then interpret_cmd s c1 else interpret_cmd s c2
|
||||||
|
| WhileNZ(e, c) ->
|
||||||
|
interpret_cmd s (IfNZ(e, Seq(c, WhileNZ(e, c)), Skip))
|
||||||
|
| Seq(c1, c2) ->
|
||||||
|
let s1 = interpret_cmd s c1 in
|
||||||
|
interpret_cmd s1 c2
|
||||||
|
end
|
||||||
|
|
||||||
|
(* optimizations ------------------------------------------------------------ *)
|
||||||
|
|
||||||
|
let rec loop : cmd =
|
||||||
|
WhileNZ (Lit 1, Skip)
|
||||||
|
|
||||||
|
|
||||||
|
let rec optimize_cmd (c:cmd) : cmd =
|
||||||
|
match c with
|
||||||
|
| Assn(x, Var y) -> if x = y then Skip else c
|
||||||
|
| Assn(_, _) -> c
|
||||||
|
| WhileNZ (Lit 0, c) -> Skip
|
||||||
|
| WhileNZ(Lit _, c) -> loop
|
||||||
|
| WhileNZ(e, c) -> WhileNZ(e, optimize_cmd c)
|
||||||
|
| Skip -> Skip
|
||||||
|
| IfNZ(Lit 0, c1, c2) -> optimize_cmd c2
|
||||||
|
| IfNZ(Lit _, c1, c2) -> optimize_cmd c1
|
||||||
|
| IfNZ(e, c1, c2) -> IfNZ(e, optimize_cmd c1, optimize_cmd c2)
|
||||||
|
| Seq(c1, c2) ->
|
||||||
|
begin match (optimize_cmd c1, optimize_cmd c2) with
|
||||||
|
| (Skip, c2') -> c2'
|
||||||
|
| (c1', Skip) -> c1'
|
||||||
|
| (c1', c2') -> Seq(c1', c2')
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
(* We can write a program that runs the SIMPLE factorial program like this: *)
|
||||||
|
let main () =
|
||||||
|
let s_ans = interpret_cmd init_state factorial in
|
||||||
|
Printf.printf "ANS = %d\n" (lookup s_ans "ANS")
|
||||||
|
|
||||||
|
;; main ()
|
||||||
|
|
||||||
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 ()
|
||||||
|
*)
|
||||||
2
lec01/simple/dune-project
Normal file
2
lec01/simple/dune-project
Normal file
|
|
@ -0,0 +1,2 @@
|
||||||
|
(lang dune 2.9)
|
||||||
|
(name simple)
|
||||||
0
lec01/simple/simple.opam
Normal file
0
lec01/simple/simple.opam
Normal file
Loading…
Add table
Add a link
Reference in a new issue