Update hw4 to a newer version.
Signed-off-by: jmug <u.g.a.mariano@gmail.com>
This commit is contained in:
parent
07d34c0cd8
commit
b24a264f7e
221 changed files with 846 additions and 746 deletions
2
hw4/.ocamlformat
Normal file
2
hw4/.ocamlformat
Normal file
|
|
@ -0,0 +1,2 @@
|
||||||
|
profile = janestreet
|
||||||
|
version = 0.26.1
|
||||||
|
|
@ -1,9 +1 @@
|
||||||
#use "topfind";;
|
#use_output "dune top";;
|
||||||
|
|
||||||
#directory "_build"
|
|
||||||
#directory "_build/util"
|
|
||||||
#directory "_build/x86"
|
|
||||||
#directory "_build/grading"
|
|
||||||
|
|
||||||
#load_rec "x86.cmo"
|
|
||||||
#use "llinterp.ml"
|
|
||||||
|
|
|
||||||
31
hw4/Makefile
31
hw4/Makefile
|
|
@ -1,24 +1,27 @@
|
||||||
INCLUDES= util,x86,grading,ll
|
SUBMIT := $(shell cat submit_zip_contents.txt)
|
||||||
LIBS = unix,str
|
HWNAME := hw4
|
||||||
SUBMIT := lexer.mll parser.mly frontend.ml team.txt
|
TIMESTAMP := $(shell /bin/date "+%Y-%m-%d-%H:%M:%S")
|
||||||
|
ZIPNAME := $(HWNAME)-submit-$(TIMESTAMP).zip
|
||||||
|
|
||||||
HWNAME := hw04
|
.PHONY: all oatc test clean zip
|
||||||
ZIPNAME := $(HWNAME)-submit.zip
|
|
||||||
|
|
||||||
|
all: oatc
|
||||||
|
|
||||||
all: main.native
|
oatc:
|
||||||
|
dune build
|
||||||
|
@cp bin/main.exe oatc
|
||||||
|
|
||||||
.PHONY: test
|
test: oatc
|
||||||
test: main.native
|
./oatc --test
|
||||||
./main.native --test
|
|
||||||
|
|
||||||
main.native: $(SUBMIT) ast.ml astlib.ml backend.ml driver.ml main.ml progasts.ml runtime.c
|
utop:
|
||||||
ocamlbuild -Is $(INCLUDES) -libs $(LIBS) -pkg num main.native -use-menhir -yaccflag --explain
|
dune utop
|
||||||
|
|
||||||
zip: $(SUBMIT)
|
zip: $(SUBMIT)
|
||||||
zip '$(ZIPNAME)' $(SUBMIT)
|
zip '$(ZIPNAME)' $(SUBMIT)
|
||||||
|
|
||||||
.PHONY: clean
|
|
||||||
clean:
|
clean:
|
||||||
ocamlbuild -clean
|
dune clean
|
||||||
rm -rf output a.out
|
rm -rf oatc ocamlbin bin/main.exe
|
||||||
|
|
||||||
|
#
|
||||||
|
|
|
||||||
76
hw4/README
76
hw4/README
|
|
@ -1,76 +0,0 @@
|
||||||
Using main.native:
|
|
||||||
|
|
||||||
main.native acts like the clang compiler. Given several .ll, .c, and .o files,
|
|
||||||
it will compile the .ll files to .s files (using the Compiler Design backend)
|
|
||||||
and then combine the results with the .c and .o files to produce an executable
|
|
||||||
named a.out. You can also compile the .ll files using clang instead of the
|
|
||||||
Compiler Design backend, which can be useful for testing purposes.
|
|
||||||
|
|
||||||
|
|
||||||
* To run the automated test harness do:
|
|
||||||
./main.native --test
|
|
||||||
|
|
||||||
* To compile ll files using the Compiler Design backend:
|
|
||||||
./main.native path/to/foo.ll
|
|
||||||
|
|
||||||
- creates output/foo.s backend assembly code
|
|
||||||
- creates output/foo.o assembled object file
|
|
||||||
- creates a.out linked executable
|
|
||||||
|
|
||||||
NOTE: by default the .s and .o files are created in
|
|
||||||
a directory called output, and the filenames are
|
|
||||||
chosen so that multiple runs of the compiler will
|
|
||||||
not overwrite previous outputs. foo.ll will be
|
|
||||||
compiled first to foo.s then foo_1.s, foo_2.s, etc.
|
|
||||||
|
|
||||||
|
|
||||||
* To compile ll files using the clang backend:
|
|
||||||
./main.native --clang path/to/foo.ll
|
|
||||||
|
|
||||||
* Useful flags:
|
|
||||||
--print-oat
|
|
||||||
pretty prints the Oat abstract syntax to the terminal
|
|
||||||
|
|
||||||
--print-ll
|
|
||||||
echoes the ll program to the terminal
|
|
||||||
|
|
||||||
--print-x86
|
|
||||||
echoes the resulting .s file to the terminal
|
|
||||||
|
|
||||||
--interpret-ll
|
|
||||||
runs the ll file through the reference interpreter
|
|
||||||
and outputs the results to the console
|
|
||||||
|
|
||||||
--execute-x86
|
|
||||||
runs the resulting a.out file natively
|
|
||||||
(applies to either the Compiler Design backend or clang-compiled code)
|
|
||||||
|
|
||||||
--clang compiles to assembly using clang, not the Compiler Design backend
|
|
||||||
|
|
||||||
-v
|
|
||||||
generates verbose output, showing which commands are used
|
|
||||||
for linking, etc.
|
|
||||||
|
|
||||||
-op <dirname>
|
|
||||||
change the output path [DEFAULT=output]
|
|
||||||
|
|
||||||
-o
|
|
||||||
change the generated executable's name [DEFAULT=a.out]
|
|
||||||
|
|
||||||
-S
|
|
||||||
stop after generating .s files
|
|
||||||
|
|
||||||
-c
|
|
||||||
stop after generating .o files
|
|
||||||
|
|
||||||
-h or --help
|
|
||||||
display the list of options
|
|
||||||
|
|
||||||
* Example uses:
|
|
||||||
|
|
||||||
Run the test case /programs/factrect.ll using the Compiler Design backend:
|
|
||||||
|
|
||||||
|
|
||||||
./main.native --execute-x86 programs/factrect.ll
|
|
||||||
--------------------------------------------------------------- Executing: a.out
|
|
||||||
* a.out returned 120
|
|
||||||
72
hw4/README.md
Normal file
72
hw4/README.md
Normal file
|
|
@ -0,0 +1,72 @@
|
||||||
|
# HW4: Oat v.1
|
||||||
|
|
||||||
|
Quick Start:
|
||||||
|
|
||||||
|
1. open the folder in VSCode
|
||||||
|
2. start an OCaml sandbox terminal
|
||||||
|
3. run `make test` from the command line
|
||||||
|
4. open `bin/frontend.ml`
|
||||||
|
|
||||||
|
See the general toolchain and project instructions on the course web site. The
|
||||||
|
course web pages have a link to the html version of the homework instructions.
|
||||||
|
|
||||||
|
|
||||||
|
Using ``oatc``
|
||||||
|
--------------
|
||||||
|
|
||||||
|
``oatc`` acts like the clang compiler. Given several .oat, .ll, .c, and .o
|
||||||
|
files, it will compile the .oat and .ll files to .s files (using the CIS 341
|
||||||
|
frontend and backend) and then combine the results with the .c and .o files to
|
||||||
|
produce an executable named a.out. You can also compile the .ll files using
|
||||||
|
clang instead of the CS131 backend, which can be useful for testing purposes.
|
||||||
|
|
||||||
|
|
||||||
|
* To run the automated test harness do:
|
||||||
|
|
||||||
|
./oatc --test
|
||||||
|
|
||||||
|
* To compile oat files using the 341 backend:
|
||||||
|
|
||||||
|
./oatc path/to/foo.oat
|
||||||
|
|
||||||
|
- creates output/foo.ll frontend ll code
|
||||||
|
- creates output/foo.s backend assembly code
|
||||||
|
- creates output/foo.o assembled object file
|
||||||
|
- creates a.out linked executable
|
||||||
|
|
||||||
|
NOTE: by default the .s and .o files are created in
|
||||||
|
a directory called output, and the filenames are
|
||||||
|
chosen so that multiple runs of the compiler will
|
||||||
|
not overwrite previous outputs. foo.ll will be
|
||||||
|
compiled first to foo.s then foo_1.s, foo_2.s, etc.
|
||||||
|
|
||||||
|
|
||||||
|
* To compile oat files using the clang backend:
|
||||||
|
|
||||||
|
./oatc --clang path/to/foo.oat
|
||||||
|
|
||||||
|
* Useful flags:
|
||||||
|
|
||||||
|
| Flag | Description |
|
||||||
|
|-------------------|---------------------------------------------------------------------------------------------------|
|
||||||
|
| --print-oat | pretty prints the Oat abstract syntax to the terminal |
|
||||||
|
| --print-ll | echoes the ll program to the terminal |
|
||||||
|
| --print-x86 | echoes the resulting .s file to the terminal |
|
||||||
|
| --interpret-ll | runs the ll file through the reference interpreter and outputs the results to the console |
|
||||||
|
| --execute-x86 | runs the resulting a.out file natively (applies to either the 341 backend or clang-compiled code) |
|
||||||
|
| --clang | compiles to assembly using clang, not the 341 backend |
|
||||||
|
| -v | generates verbose output, showing which commands are used for linking, etc. |
|
||||||
|
| -op ``<dirname>`` | change the output path [DEFAULT=output] |
|
||||||
|
| -o | change the generated executable's name [DEFAULT=a.out] |
|
||||||
|
| -S | stop after generating .s files |
|
||||||
|
| -c | stop after generating .o files |
|
||||||
|
| -h or --help | display the list of options |
|
||||||
|
|
||||||
|
|
||||||
|
* Example uses:
|
||||||
|
|
||||||
|
Run the test case hw4programs/fact.oat using the 341 backend:
|
||||||
|
|
||||||
|
/oatc --execute-x86 hw4programs/fact.oat bin/runtime.c
|
||||||
|
120--------------------------------------------------------------- Executing: a.out
|
||||||
|
* a.out returned 0
|
||||||
|
|
@ -1,13 +1,27 @@
|
||||||
|
(* The type declarations in this file correspond to productions in the Oat
|
||||||
|
* grammar provided in the Oat v.1 Language Specification. *)
|
||||||
|
|
||||||
|
module Range = Util.Range
|
||||||
|
|
||||||
|
(* The `node` type represents a node in an abstract syntax tree.
|
||||||
|
* The `elt` is the AST element, the `loc` contains the line number
|
||||||
|
* info of the corresponding concrete syntax element. The parser uses
|
||||||
|
* the `loc` to give line numbers with error messages, and you can do
|
||||||
|
* so too in the compiler if you like!
|
||||||
|
*)
|
||||||
type 'a node = { elt : 'a; loc : Range.t }
|
type 'a node = { elt : 'a; loc : Range.t }
|
||||||
|
|
||||||
(** val no_loc : 'a1 -> 'a1 node **)
|
(** val no_loc : 'a1 -> 'a1 node **)
|
||||||
|
|
||||||
|
(* This function might be useful if some of your helper functions
|
||||||
|
* have to return a `node` type.
|
||||||
|
*)
|
||||||
let no_loc x =
|
let no_loc x =
|
||||||
{ elt = x; loc = Range.norange }
|
{ elt = x; loc = Range.norange }
|
||||||
|
|
||||||
type id = string
|
type id = string
|
||||||
|
|
||||||
|
(* Oat types *)
|
||||||
type ty =
|
type ty =
|
||||||
| TBool
|
| TBool
|
||||||
| TInt
|
| TInt
|
||||||
|
|
@ -43,6 +57,7 @@ type binop =
|
||||||
| Shr
|
| Shr
|
||||||
| Sar
|
| Sar
|
||||||
|
|
||||||
|
(* Oat expressions *)
|
||||||
type exp =
|
type exp =
|
||||||
| CNull of rty
|
| CNull of rty
|
||||||
| CBool of bool
|
| CBool of bool
|
||||||
|
|
@ -3,11 +3,13 @@
|
||||||
open Ll
|
open Ll
|
||||||
open X86
|
open X86
|
||||||
|
|
||||||
|
module Platform = Util.Platform
|
||||||
|
|
||||||
(* Overview ----------------------------------------------------------------- *)
|
(* Overview ----------------------------------------------------------------- *)
|
||||||
|
|
||||||
(* We suggest that you spend some time understinging this entire file and
|
(* We suggest that you spend some time understanding this entire file and
|
||||||
how it fits with the compiler pipeline before making changes. The suggested
|
how it fits with the compiler pipeline before making changes. The suggested
|
||||||
plan for implementing the compiler is provided on the project web page.
|
plan for implementing the compiler is provided on the project web page.
|
||||||
*)
|
*)
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -52,7 +54,7 @@ let rbp_offset (offset:int) : X86.operand =
|
||||||
'stack layout'. A stack layout maps a uid to an X86 operand for
|
'stack layout'. A stack layout maps a uid to an X86 operand for
|
||||||
accessing its contents. For this compilation strategy, the operand
|
accessing its contents. For this compilation strategy, the operand
|
||||||
is always an offset from %rbp (in bytes) that represents a storage slot in
|
is always an offset from %rbp (in bytes) that represents a storage slot in
|
||||||
the stack.
|
the stack.
|
||||||
*)
|
*)
|
||||||
|
|
||||||
type layout = (uid * X86.operand) list
|
type layout = (uid * X86.operand) list
|
||||||
|
|
@ -77,7 +79,7 @@ let lookup m x = List.assoc x m
|
||||||
|
|
||||||
NOTE: two important facts about global identifiers:
|
NOTE: two important facts about global identifiers:
|
||||||
|
|
||||||
(1) You should use (Platform.mangle gid) to obtain a string
|
(1) You should use (Platform.mangle gid) to obtain a string
|
||||||
suitable for naming a global label on your platform (OS X expects
|
suitable for naming a global label on your platform (OS X expects
|
||||||
"_main" while linux expects "main").
|
"_main" while linux expects "main").
|
||||||
|
|
||||||
|
|
@ -85,14 +87,14 @@ let lookup m x = List.assoc x m
|
||||||
That is, the X86 code: movq _gid %rax which looks like it should
|
That is, the X86 code: movq _gid %rax which looks like it should
|
||||||
put the address denoted by _gid into %rax is not allowed.
|
put the address denoted by _gid into %rax is not allowed.
|
||||||
Instead, you need to compute an %rip-relative address using the
|
Instead, you need to compute an %rip-relative address using the
|
||||||
leaq instruction: leaq _gid(%rip).
|
leaq instruction: leaq _gid(%rip) %rax.
|
||||||
|
|
||||||
One strategy for compiling instruction operands is to use a
|
One strategy for compiling instruction operands is to use a
|
||||||
designated register (or registers) for holding the values being
|
designated register (or registers) for holding the values being
|
||||||
manipulated by the LLVM IR instruction. You might find it useful to
|
manipulated by the LLVM IR instruction. You might find it useful to
|
||||||
implement the following helper function, whose job is to generate
|
implement the following helper function, whose job is to generate
|
||||||
the X86 instruction that moves an LLVM operand into a designated
|
the X86 instruction that moves an LLVM operand into a designated
|
||||||
destination (usually a register).
|
destination (usually a register).
|
||||||
*)
|
*)
|
||||||
let compile_operand ctxt dest : Ll.operand -> ins =
|
let compile_operand ctxt dest : Ll.operand -> ins =
|
||||||
function
|
function
|
||||||
|
|
@ -104,7 +106,7 @@ let compile_operand ctxt dest : Ll.operand -> ins =
|
||||||
|
|
||||||
(* compiling call ---------------------------------------------------------- *)
|
(* compiling call ---------------------------------------------------------- *)
|
||||||
|
|
||||||
(* You will probably find it helpful to implement a helper function that
|
(* You will probably find it helpful to implement a helper function that
|
||||||
generates code for the LLVM IR call instruction.
|
generates code for the LLVM IR call instruction.
|
||||||
|
|
||||||
The code you generate should follow the x64 System V AMD64 ABI
|
The code you generate should follow the x64 System V AMD64 ABI
|
||||||
|
|
@ -120,6 +122,9 @@ let compile_operand ctxt dest : Ll.operand -> ins =
|
||||||
|
|
||||||
[ NOTE: Don't forget to preserve caller-save registers (only if
|
[ NOTE: Don't forget to preserve caller-save registers (only if
|
||||||
needed). ]
|
needed). ]
|
||||||
|
|
||||||
|
[ NOTE: Remember, call can use labels as immediates! You shouldn't
|
||||||
|
need to perform any RIP-relative addressing for this one. ]
|
||||||
*)
|
*)
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -164,11 +169,11 @@ let compile_call ctxt fop args =
|
||||||
address based on the size of the data, which is dictated by the
|
address based on the size of the data, which is dictated by the
|
||||||
data's type.
|
data's type.
|
||||||
|
|
||||||
To compile getelmentptr, you must generate x86 code that performs
|
To compile getelementptr, you must generate x86 code that performs
|
||||||
the appropriate arithemetic calculations.
|
the appropriate arithmetic calculations.
|
||||||
*)
|
*)
|
||||||
|
|
||||||
(* [size_ty] maps an LLVMlite type to a size in bytes.
|
(* [size_ty] maps an LLVMlite type to a size in bytes.
|
||||||
(needed for getelementptr)
|
(needed for getelementptr)
|
||||||
|
|
||||||
- the size of a struct is the sum of the sizes of each component
|
- the size of a struct is the sum of the sizes of each component
|
||||||
|
|
@ -185,7 +190,7 @@ let rec size_ty (tdecls:(tid * ty) list) (t:Ll.ty) : int =
|
||||||
| I1 | I64 | Ptr _ -> 8 (* Target 64-bit only subset of X86 *)
|
| I1 | I64 | Ptr _ -> 8 (* Target 64-bit only subset of X86 *)
|
||||||
| Struct ts -> List.fold_left (fun acc t -> acc + (size_ty tdecls t)) 0 ts
|
| Struct ts -> List.fold_left (fun acc t -> acc + (size_ty tdecls t)) 0 ts
|
||||||
| Array (n, t) -> n * (size_ty tdecls t)
|
| Array (n, t) -> n * (size_ty tdecls t)
|
||||||
| Namedt id -> size_ty tdecls (List.assoc id tdecls)
|
| Namedt id -> size_ty tdecls (lookup tdecls id)
|
||||||
end
|
end
|
||||||
|
|
||||||
(* Compute the size of the offset (in bytes) of the nth element of a region
|
(* Compute the size of the offset (in bytes) of the nth element of a region
|
||||||
|
|
@ -200,7 +205,7 @@ let index_into tdecls (ts:ty list) (n:int) : int * ty =
|
||||||
in loop ts n 0
|
in loop ts n 0
|
||||||
|
|
||||||
|
|
||||||
(* Generates code that computes a pointer value.
|
(* Generates code that computes a pointer value.
|
||||||
|
|
||||||
1. op must be of pointer type: t*
|
1. op must be of pointer type: t*
|
||||||
|
|
||||||
|
|
@ -211,14 +216,14 @@ let index_into tdecls (ts:ty list) (n:int) : int * ty =
|
||||||
|
|
||||||
4. subsequent indices are interpreted according to the type t:
|
4. subsequent indices are interpreted according to the type t:
|
||||||
|
|
||||||
- if t is a struct, the index must be a constant n and it
|
- if t is a struct, the index must be a constant n and it
|
||||||
picks out the n'th element of the struct. [ NOTE: the offset
|
picks out the n'th element of the struct. [ NOTE: the offset
|
||||||
within the struct of the n'th element is determined by the
|
within the struct of the n'th element is determined by the
|
||||||
sizes of the types of the previous elements ]
|
sizes of the types of the previous elements ]
|
||||||
|
|
||||||
- if t is an array, the index can be any operand, and its
|
- if t is an array, the index can be any operand, and its
|
||||||
value determines the offset within the array.
|
value determines the offset within the array.
|
||||||
|
|
||||||
- if t is any other type, the path is invalid
|
- if t is any other type, the path is invalid
|
||||||
|
|
||||||
5. if the index is valid, the remainder of the path is computed as
|
5. if the index is valid, the remainder of the path is computed as
|
||||||
|
|
@ -227,6 +232,10 @@ let index_into tdecls (ts:ty list) (n:int) : int * ty =
|
||||||
*)
|
*)
|
||||||
let compile_gep (ctxt:ctxt) (op : Ll.ty * Ll.operand) (path: Ll.operand list) : ins list =
|
let compile_gep (ctxt:ctxt) (op : Ll.ty * Ll.operand) (path: Ll.operand list) : ins list =
|
||||||
let op_to_rax = compile_operand ctxt (Reg Rax) in
|
let op_to_rax = compile_operand ctxt (Reg Rax) in
|
||||||
|
let rec effective_type = function
|
||||||
|
| Namedt id -> effective_type @@ lookup ctxt.tdecls id
|
||||||
|
| t -> t
|
||||||
|
in
|
||||||
let rec loop ty path code =
|
let rec loop ty path code =
|
||||||
match (ty, path) with
|
match (ty, path) with
|
||||||
| (_, []) -> List.rev code
|
| (_, []) -> List.rev code
|
||||||
|
|
@ -248,11 +257,11 @@ let compile_gep (ctxt:ctxt) (op : Ll.ty * Ll.operand) (path: Ll.operand list) :
|
||||||
Asm.(Movq, [~%Rax; ~%Rcx])
|
Asm.(Movq, [~%Rax; ~%Rcx])
|
||||||
:: code
|
:: code
|
||||||
|
|
||||||
| (Namedt t, p) -> loop (List.assoc t ctxt.tdecls) p code
|
| (Namedt t, p) -> loop (lookup ctxt.tdecls t) p code
|
||||||
|
|
||||||
| _ -> failwith "compile_gep encountered unsupported getelementptr data" in
|
| _ -> failwith "compile_gep encountered unsupported getelementptr data" in
|
||||||
|
|
||||||
match op with
|
match (effective_type @@ fst op, snd op) with
|
||||||
| (Ptr t, op) -> loop (Array(0, t)) path [op_to_rax op]
|
| (Ptr t, op) -> loop (Array(0, t)) path [op_to_rax op]
|
||||||
| _ -> failwith "compile_gep got incorrect parameters"
|
| _ -> failwith "compile_gep got incorrect parameters"
|
||||||
|
|
||||||
|
|
@ -281,15 +290,15 @@ let compile_gep (ctxt:ctxt) (op : Ll.ty * Ll.operand) (path: Ll.operand list) :
|
||||||
- Bitcast: does nothing interesting at the assembly level
|
- Bitcast: does nothing interesting at the assembly level
|
||||||
*)
|
*)
|
||||||
let compile_insn (ctxt:ctxt) ((uid:uid), (i:Ll.insn)) : X86.ins list =
|
let compile_insn (ctxt:ctxt) ((uid:uid), (i:Ll.insn)) : X86.ins list =
|
||||||
let op_to = compile_operand ctxt in
|
let op_to = compile_operand ctxt in
|
||||||
let op_to_rax = op_to (Reg Rax) in (* Move the value of op into rax *)
|
let op_to_rax = op_to (Reg Rax) in (* Move the value of op into rax *)
|
||||||
let op_to_rcx = op_to (Reg Rcx) in (* Move the value of op into rax *)
|
let op_to_rcx = op_to (Reg Rcx) in (* Move the value of op into rax *)
|
||||||
let dst = lookup ctxt.layout uid in
|
let dst = lookup ctxt.layout uid in
|
||||||
match i with
|
match i with
|
||||||
| Binop (bop, t, op1, op2) ->
|
| Binop (bop, _t, op1, op2) ->
|
||||||
let bin op =
|
let bin op =
|
||||||
(op_to_rax op1) ::
|
(op_to_rax op1) ::
|
||||||
(op_to_rcx op2) ::
|
(op_to_rcx op2) ::
|
||||||
Asm.([ op, [~%Rcx; ~%Rax]
|
Asm.([ op, [~%Rcx; ~%Rax]
|
||||||
; Movq, [~%Rax; dst] ])
|
; Movq, [~%Rax; dst] ])
|
||||||
in
|
in
|
||||||
|
|
@ -305,26 +314,26 @@ let compile_insn (ctxt:ctxt) ((uid:uid), (i:Ll.insn)) : X86.ins list =
|
||||||
| Ll.Xor -> bin Xorq
|
| Ll.Xor -> bin Xorq
|
||||||
end
|
end
|
||||||
|
|
||||||
(* Alloca instructions allocate an fresh stack slot and
|
(* Alloca instructions allocate an fresh stack slot and
|
||||||
move the address of the newly allocated storage into the
|
move the address of the newly allocated storage into the
|
||||||
destination uid. *)
|
destination uid. *)
|
||||||
| Alloca (_t) -> Asm.([ Pushq, [~$0]
|
| Alloca (_t) -> Asm.([ Pushq, [~$0]
|
||||||
; Movq, [~%Rsp; dst] ])
|
; Movq, [~%Rsp; dst] ])
|
||||||
|
|
||||||
(* Load dereferences the pointer value stored in a local.
|
(* Load dereferences the pointer value stored in a local.
|
||||||
Global and constant pointers don't need indirection. *)
|
Global and constant pointers don't need indirection. *)
|
||||||
| Load (t, op) -> (op_to_rax op) :: Asm.([ Movq, [Ind2 Rax; ~%Rcx]
|
| Load (_t, op) -> (op_to_rax op) :: Asm.([ Movq, [Ind2 Rax; ~%Rcx]
|
||||||
; Movq, [~%Rcx; dst] ])
|
; Movq, [~%Rcx; dst] ])
|
||||||
|
|
||||||
(* Store also needs to dereference the destination pointer if it's a global *)
|
(* Store also needs to dereference the destination pointer if it's a global *)
|
||||||
| Store (_, src, (Id uid as dest)) ->
|
| Store (_, src, (Id _ as dest)) ->
|
||||||
(op_to_rcx src) ::
|
(op_to_rcx src) ::
|
||||||
(op_to_rax dest) :: Asm.([Movq, [~%Rcx; Ind2 Rax]])
|
(op_to_rax dest) :: Asm.([Movq, [~%Rcx; Ind2 Rax]])
|
||||||
| Store (_, src, Gid gid) ->
|
| Store (_, src, Gid gid) ->
|
||||||
(op_to_rax src) :: Asm.([Movq, [~%Rax; Ind3 (Lbl (Platform.mangle gid), Rip)]])
|
(op_to_rax src) :: Asm.([Movq, [~%Rax; Ind3 (Lbl (Platform.mangle gid), Rip)]])
|
||||||
| Store (_, _, _) -> failwith "store destination was not a local or global id"
|
| Store (_, _, _) -> failwith "store destination was not a local or global id"
|
||||||
|
|
||||||
(* Treat LL i1 values as words, so zero-out the rest of the bits *)
|
(* Treat LL i1 values as quadwords, so zero-out the rest of the bits *)
|
||||||
| Icmp (cnd, _, op1, op2) -> (op_to_rax op1) ::
|
| Icmp (cnd, _, op1, op2) -> (op_to_rax op1) ::
|
||||||
(op_to_rcx op2) ::
|
(op_to_rcx op2) ::
|
||||||
Asm.([ Cmpq, [~%Rcx; ~%Rax]
|
Asm.([ Cmpq, [~%Rcx; ~%Rax]
|
||||||
|
|
@ -362,6 +371,8 @@ let mk_lbl (fn:string) (l:string) = fn ^ "." ^ l
|
||||||
- Br should jump
|
- Br should jump
|
||||||
|
|
||||||
- Cbr branch should treat its operand as a boolean conditional
|
- Cbr branch should treat its operand as a boolean conditional
|
||||||
|
|
||||||
|
[fn] - the name of the function containing this terminator
|
||||||
*)
|
*)
|
||||||
let compile_terminator (fn:string) (ctxt:ctxt) (t:Ll.terminator) : ins list =
|
let compile_terminator (fn:string) (ctxt:ctxt) (t:Ll.terminator) : ins list =
|
||||||
let epilogue = Asm.([ Movq, [~%Rbp; ~%Rsp]
|
let epilogue = Asm.([ Movq, [~%Rbp; ~%Rsp]
|
||||||
|
|
@ -405,13 +416,13 @@ let arg_loc (n : int) : operand =
|
||||||
| None -> rbp_offset (n-4)
|
| None -> rbp_offset (n-4)
|
||||||
end
|
end
|
||||||
|
|
||||||
(* We suggest that you create a helper function that computes the
|
(* We suggest that you create a helper function that computes the
|
||||||
stack layout for a given function declaration.
|
stack layout for a given function declaration.
|
||||||
|
|
||||||
- each function argument should be copied into a stack slot
|
- each function argument should be copied into a stack slot
|
||||||
- in this (inefficient) compilation strategy, each local id
|
- in this (inefficient) compilation strategy, each local id
|
||||||
is also stored as a stack slot.
|
is also stored as a stack slot.
|
||||||
- see the discussion about locals
|
- see the discussion about locals
|
||||||
|
|
||||||
*)
|
*)
|
||||||
let stack_layout (args : uid list) ((block, lbled_blocks):cfg) : layout =
|
let stack_layout (args : uid list) ((block, lbled_blocks):cfg) : layout =
|
||||||
|
|
@ -467,7 +478,7 @@ let rec compile_ginit : ginit -> X86.data list = function
|
||||||
| GInt c -> [Quad (Lit c)]
|
| GInt c -> [Quad (Lit c)]
|
||||||
| GString s -> [Asciz s]
|
| GString s -> [Asciz s]
|
||||||
| GArray gs | GStruct gs -> List.map compile_gdecl gs |> List.flatten
|
| GArray gs | GStruct gs -> List.map compile_gdecl gs |> List.flatten
|
||||||
| GBitcast (t1,g,t2) -> compile_ginit g
|
| GBitcast (_t1,g,_t2) -> compile_ginit g
|
||||||
|
|
||||||
and compile_gdecl (_, g) = compile_ginit g
|
and compile_gdecl (_, g) = compile_ginit g
|
||||||
|
|
||||||
|
|
@ -1,4 +1,6 @@
|
||||||
open Printf
|
open Printf
|
||||||
|
module Platform = Util.Platform
|
||||||
|
module Range = Util.Range
|
||||||
open Platform
|
open Platform
|
||||||
|
|
||||||
(* configuration flags ------------------------------------------------------ *)
|
(* configuration flags ------------------------------------------------------ *)
|
||||||
|
|
@ -76,7 +78,7 @@ let run_program (args:string) (executable:string) (tmp_out:string) : string =
|
||||||
read_file tmp_out
|
read_file tmp_out
|
||||||
|
|
||||||
let run_program_error (args:string) (executable:string) (tmp_out:string) : string =
|
let run_program_error (args:string) (executable:string) (tmp_out:string) : string =
|
||||||
let cmd = sprintf "timeout 60 %s%s %s > %s 2>&1" dot_path executable args tmp_out in
|
let cmd = sprintf "%s%s %s > %s 2>&1" dot_path executable args tmp_out in
|
||||||
let result = sh cmd (fun _ i -> i)
|
let result = sh cmd (fun _ i -> i)
|
||||||
in
|
in
|
||||||
(read_file tmp_out) ^ (string_of_int result)
|
(read_file tmp_out) ^ (string_of_int result)
|
||||||
|
|
@ -107,7 +109,7 @@ let string_of_ll_ast path ll_ast =
|
||||||
let process_ll_ast path file ll_ast =
|
let process_ll_ast path file ll_ast =
|
||||||
let _ = if !print_ll_flag then print_ll file ll_ast in
|
let _ = if !print_ll_flag then print_ll file ll_ast in
|
||||||
|
|
||||||
(* Optionally interpret it using the reference interpreter. *)
|
(* Optionally interpret it using the cis341 reference interperter. *)
|
||||||
let _ = if !interpret_ll then
|
let _ = if !interpret_ll then
|
||||||
let result = interpret ll_ast [] in
|
let result = interpret ll_ast [] in
|
||||||
Printf.printf "Interpreter Result: %s\n" result
|
Printf.printf "Interpreter Result: %s\n" result
|
||||||
|
|
@ -126,7 +128,7 @@ let process_ll_ast path file ll_ast =
|
||||||
Platform.sh (Printf.sprintf "cat %s" dot_s_file) Platform.raise_error
|
Platform.sh (Printf.sprintf "cat %s" dot_s_file) Platform.raise_error
|
||||||
end
|
end
|
||||||
end else begin
|
end else begin
|
||||||
Platform.verb "* compiling with Compiler Design backend";
|
Platform.verb "* compiling with cis341 backend";
|
||||||
let asm_ast = Backend.compile_prog ll_ast in
|
let asm_ast = Backend.compile_prog ll_ast in
|
||||||
let asm_str = X86.string_of_prog asm_ast in
|
let asm_str = X86.string_of_prog asm_ast in
|
||||||
let _ = if !print_x86_flag then print_x86 dot_s_file asm_str in
|
let _ = if !print_x86_flag then print_x86 dot_s_file asm_str in
|
||||||
|
|
@ -198,7 +200,7 @@ let process_files files =
|
||||||
List.iter process_file files;
|
List.iter process_file files;
|
||||||
|
|
||||||
( if !assemble && !link then
|
( if !assemble && !link then
|
||||||
Platform.link (List.rev !link_files@["runtime.c"]) !executable_filename );
|
Platform.link (List.rev !link_files) !executable_filename );
|
||||||
|
|
||||||
( if !assemble && !link && !execute_x86 then
|
( if !assemble && !link && !execute_x86 then
|
||||||
let ret = run_executable "" !executable_filename in
|
let ret = run_executable "" !executable_filename in
|
||||||
31
hw4/bin/dune
Normal file
31
hw4/bin/dune
Normal file
|
|
@ -0,0 +1,31 @@
|
||||||
|
(library
|
||||||
|
(name oat)
|
||||||
|
(modules driver backend frontend lexer parser ast astlib)
|
||||||
|
(libraries str num util x86 ll))
|
||||||
|
|
||||||
|
(ocamllex lexer)
|
||||||
|
(menhir (modules parser))
|
||||||
|
|
||||||
|
(env
|
||||||
|
(dev
|
||||||
|
(flags
|
||||||
|
(:standard -g -w "+a-4-7-9-26-27-29-30-32..42-44-45-48-50-60-66..70")
|
||||||
|
)))
|
||||||
|
|
||||||
|
(executable
|
||||||
|
(public_name main)
|
||||||
|
(name main)
|
||||||
|
(modules main)
|
||||||
|
(promote (until-clean))
|
||||||
|
(libraries
|
||||||
|
; OCaml standard libraries
|
||||||
|
; project libraries
|
||||||
|
str
|
||||||
|
num
|
||||||
|
util
|
||||||
|
x86
|
||||||
|
ll
|
||||||
|
studenttests
|
||||||
|
gradedtests
|
||||||
|
; sp24_hw4_tests
|
||||||
|
))
|
||||||
|
|
@ -2,11 +2,17 @@ open Ll
|
||||||
open Llutil
|
open Llutil
|
||||||
open Ast
|
open Ast
|
||||||
|
|
||||||
|
(* This file is where much of the work of the project will be carried out.
|
||||||
|
Follow the instructions on the project web site, but first skim through
|
||||||
|
this file to see what it contains.
|
||||||
|
*)
|
||||||
|
|
||||||
|
|
||||||
(* instruction streams ------------------------------------------------------ *)
|
(* instruction streams ------------------------------------------------------ *)
|
||||||
|
|
||||||
(* As in the last project, we'll be working with a flattened representation
|
(* As in the last project, we'll be working with a flattened representation
|
||||||
of LLVMlite programs to make emitting code easier. This version
|
of LLVMlite programs to make emitting code easier. This version
|
||||||
additionally makes it possible to emit elements will be gathered up and
|
additionally makes it possible to emit elements that will be gathered up and
|
||||||
"hoisted" to specific parts of the constructed CFG
|
"hoisted" to specific parts of the constructed CFG
|
||||||
- G of gid * Ll.gdecl: allows you to output global definitions in the middle
|
- G of gid * Ll.gdecl: allows you to output global definitions in the middle
|
||||||
of the instruction stream. You will find this useful for compiling string
|
of the instruction stream. You will find this useful for compiling string
|
||||||
|
|
@ -23,6 +29,16 @@ type elt =
|
||||||
| G of gid * Ll.gdecl (* hoisted globals (usually strings) *)
|
| G of gid * Ll.gdecl (* hoisted globals (usually strings) *)
|
||||||
| E of uid * Ll.insn (* hoisted entry block instructions *)
|
| E of uid * Ll.insn (* hoisted entry block instructions *)
|
||||||
|
|
||||||
|
(* The type of streams of LLVMLite instructions. Note that to improve performance,
|
||||||
|
* we will emit the instructions in reverse order. That is, the LLVMLite code:
|
||||||
|
* %1 = mul i64 2, 2
|
||||||
|
* %2 = add i64 1, %1
|
||||||
|
* br label %l1
|
||||||
|
* would be constructed as a stream as follows:
|
||||||
|
* I ("1", Binop (Mul, I64, Const 2L, Const 2L))
|
||||||
|
* >:: I ("2", Binop (Add, I64, Const 1L, Id "1"))
|
||||||
|
* >:: T (Br "l1")
|
||||||
|
*)
|
||||||
type stream = elt list
|
type stream = elt list
|
||||||
let ( >@ ) x y = y @ x
|
let ( >@ ) x y = y @ x
|
||||||
let ( >:: ) x y = y :: x
|
let ( >:: ) x y = y :: x
|
||||||
|
|
@ -160,10 +176,10 @@ let typ_of_unop : Ast.unop -> Ast.ty * Ast.ty = function
|
||||||
the array), we can simply compile e1[e2] as a left-hand-side and then do the
|
the array), we can simply compile e1[e2] as a left-hand-side and then do the
|
||||||
load. So cmp_exp and cmp_lhs are mutually recursive. [[Actually, as I am
|
load. So cmp_exp and cmp_lhs are mutually recursive. [[Actually, as I am
|
||||||
writing this, I think it could make sense to factor the Oat grammar in this
|
writing this, I think it could make sense to factor the Oat grammar in this
|
||||||
way, which would make things clearer, I may do that for next time around.]]
|
way, which would make things clearerhw, I may do that for next time around.]]
|
||||||
|
|
||||||
|
|
||||||
Consider globals7.oat
|
Consider globals7.oat (in hw4programs)
|
||||||
|
|
||||||
/--------------- globals7.oat ------------------
|
/--------------- globals7.oat ------------------
|
||||||
global arr = int[] null;
|
global arr = int[] null;
|
||||||
|
|
@ -247,7 +263,7 @@ let typ_of_unop : Ast.unop -> Ast.ty * Ast.ty = function
|
||||||
|
|
||||||
(* Global initialized arrays:
|
(* Global initialized arrays:
|
||||||
|
|
||||||
There is another wrinkle: To compile global initialized arrays like in the
|
There is another wrinkle: to compile global initialized arrays like in the
|
||||||
globals4.oat, it is helpful to do a bitcast once at the global scope to
|
globals4.oat, it is helpful to do a bitcast once at the global scope to
|
||||||
convert the "precise type" required by the LLVM initializer to the actual
|
convert the "precise type" required by the LLVM initializer to the actual
|
||||||
translation type (which sets the array length to 0). So for globals4.oat,
|
translation type (which sets the array length to 0). So for globals4.oat,
|
||||||
|
|
@ -287,6 +303,9 @@ let oat_alloc_array (t:Ast.ty) (size:Ll.operand) : Ll.ty * operand * stream =
|
||||||
[ arr_id, Call(arr_ty, Gid "oat_alloc_array", [I64, size])
|
[ arr_id, Call(arr_ty, Gid "oat_alloc_array", [I64, size])
|
||||||
; ans_id, Bitcast(arr_ty, Id arr_id, ans_ty) ]
|
; ans_id, Bitcast(arr_ty, Id arr_id, ans_ty) ]
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
(* Compiles an expression exp in context c, outputting the Ll operand that will
|
(* Compiles an expression exp in context c, outputting the Ll operand that will
|
||||||
recieve the value of the expression, and the stream of instructions
|
recieve the value of the expression, and the stream of instructions
|
||||||
implementing the expression.
|
implementing the expression.
|
||||||
|
|
@ -303,9 +322,9 @@ let oat_alloc_array (t:Ast.ty) (size:Ll.operand) : Ll.ty * operand * stream =
|
||||||
(CArr) and the (NewArr) expressions
|
(CArr) and the (NewArr) expressions
|
||||||
|
|
||||||
*)
|
*)
|
||||||
|
|
||||||
let rec cmp_exp (c:Ctxt.t) (exp:Ast.exp node) : Ll.ty * Ll.operand * stream =
|
let rec cmp_exp (c:Ctxt.t) (exp:Ast.exp node) : Ll.ty * Ll.operand * stream =
|
||||||
failwith "cmp_exp not implemented"
|
failwith "cmp_exp unimplemented"
|
||||||
|
|
||||||
|
|
||||||
(* Compile a statement in context c with return typ rt. Return a new context,
|
(* Compile a statement in context c with return typ rt. Return a new context,
|
||||||
possibly extended with new local bindings, and the instruction stream
|
possibly extended with new local bindings, and the instruction stream
|
||||||
|
|
@ -333,10 +352,10 @@ let rec cmp_exp (c:Ctxt.t) (exp:Ast.exp node) : Ll.ty * Ll.operand * stream =
|
||||||
pointer, you just need to store to it!
|
pointer, you just need to store to it!
|
||||||
|
|
||||||
*)
|
*)
|
||||||
|
|
||||||
let rec cmp_stmt (c:Ctxt.t) (rt:Ll.ty) (stmt:Ast.stmt node) : Ctxt.t * stream =
|
let rec cmp_stmt (c:Ctxt.t) (rt:Ll.ty) (stmt:Ast.stmt node) : Ctxt.t * stream =
|
||||||
failwith "cmp_stmt not implemented"
|
failwith "cmp_stmt not implemented"
|
||||||
|
|
||||||
|
|
||||||
(* Compile a series of statements *)
|
(* Compile a series of statements *)
|
||||||
and cmp_block (c:Ctxt.t) (rt:Ll.ty) (stmts:Ast.block) : Ctxt.t * stream =
|
and cmp_block (c:Ctxt.t) (rt:Ll.ty) (stmts:Ast.block) : Ctxt.t * stream =
|
||||||
List.fold_left (fun (c, code) s ->
|
List.fold_left (fun (c, code) s ->
|
||||||
|
|
@ -366,7 +385,7 @@ let cmp_function_ctxt (c:Ctxt.t) (p:Ast.prog) : Ctxt.t =
|
||||||
in well-formed programs. (The constructors starting with C).
|
in well-formed programs. (The constructors starting with C).
|
||||||
*)
|
*)
|
||||||
let cmp_global_ctxt (c:Ctxt.t) (p:Ast.prog) : Ctxt.t =
|
let cmp_global_ctxt (c:Ctxt.t) (p:Ast.prog) : Ctxt.t =
|
||||||
failwith "cmp_global_ctxt not implemented"
|
failwith "cmp_global_ctxt unimplemented"
|
||||||
|
|
||||||
(* Compile a function declaration in global context c. Return the LLVMlite cfg
|
(* Compile a function declaration in global context c. Return the LLVMlite cfg
|
||||||
and a list of global declarations containing the string literals appearing
|
and a list of global declarations containing the string literals appearing
|
||||||
|
|
@ -379,10 +398,10 @@ let cmp_global_ctxt (c:Ctxt.t) (p:Ast.prog) : Ctxt.t =
|
||||||
4. Compile the body of the function using cmp_block
|
4. Compile the body of the function using cmp_block
|
||||||
5. Use cfg_of_stream to produce a LLVMlite cfg from
|
5. Use cfg_of_stream to produce a LLVMlite cfg from
|
||||||
*)
|
*)
|
||||||
|
|
||||||
let cmp_fdecl (c:Ctxt.t) (f:Ast.fdecl node) : Ll.fdecl * (Ll.gid * Ll.gdecl) list =
|
let cmp_fdecl (c:Ctxt.t) (f:Ast.fdecl node) : Ll.fdecl * (Ll.gid * Ll.gdecl) list =
|
||||||
failwith "cmp_fdecl not implemented"
|
failwith "cmp_fdecl not implemented"
|
||||||
|
|
||||||
|
|
||||||
(* Compile a global initializer, returning the resulting LLVMlite global
|
(* Compile a global initializer, returning the resulting LLVMlite global
|
||||||
declaration, and a list of additional global declarations.
|
declaration, and a list of additional global declarations.
|
||||||
|
|
||||||
|
|
@ -394,9 +413,9 @@ let cmp_fdecl (c:Ctxt.t) (f:Ast.fdecl node) : Ll.fdecl * (Ll.gid * Ll.gdecl) lis
|
||||||
- OAT arrays are always handled via pointers. A global array of arrays will
|
- OAT arrays are always handled via pointers. A global array of arrays will
|
||||||
be an array of pointers to arrays emitted as additional global declarations.
|
be an array of pointers to arrays emitted as additional global declarations.
|
||||||
*)
|
*)
|
||||||
|
|
||||||
let rec cmp_gexp c (e:Ast.exp node) : Ll.gdecl * (Ll.gid * Ll.gdecl) list =
|
let rec cmp_gexp c (e:Ast.exp node) : Ll.gdecl * (Ll.gid * Ll.gdecl) list =
|
||||||
failwith "cmp_gexp not implemented"
|
failwith "cmp_init not implemented"
|
||||||
|
|
||||||
|
|
||||||
(* Oat internals function context ------------------------------------------- *)
|
(* Oat internals function context ------------------------------------------- *)
|
||||||
let internals = [
|
let internals = [
|
||||||
|
|
@ -1,6 +1,7 @@
|
||||||
{
|
{
|
||||||
open Lexing
|
open Lexing
|
||||||
open Parser
|
open Parser
|
||||||
|
module Range = Util.Range
|
||||||
open Range
|
open Range
|
||||||
|
|
||||||
exception Lexer_error of Range.t * string
|
exception Lexer_error of Range.t * string
|
||||||
|
|
@ -53,6 +54,7 @@
|
||||||
( ")", RPAREN);
|
( ")", RPAREN);
|
||||||
( "[", LBRACKET);
|
( "[", LBRACKET);
|
||||||
( "]", RBRACKET);
|
( "]", RBRACKET);
|
||||||
|
|
||||||
]
|
]
|
||||||
|
|
||||||
let (symbol_table : (string, Parser.token) Hashtbl.t) = Hashtbl.create 1024
|
let (symbol_table : (string, Parser.token) Hashtbl.t) = Hashtbl.create 1024
|
||||||
|
|
@ -1,7 +1,7 @@
|
||||||
open Ll
|
open Ll
|
||||||
open Arg
|
open Arg
|
||||||
open Assert
|
open Util.Assert
|
||||||
open Driver
|
open Oat.Driver
|
||||||
|
|
||||||
(* testing harness ---------------------------------------------------------- *)
|
(* testing harness ---------------------------------------------------------- *)
|
||||||
exception Ran_tests
|
exception Ran_tests
|
||||||
|
|
@ -23,12 +23,12 @@ let args =
|
||||||
; ("--interpret-ll", Set interpret_ll, "runs each LL program through the LL interpreter")
|
; ("--interpret-ll", Set interpret_ll, "runs each LL program through the LL interpreter")
|
||||||
; ("--print-ll", Set print_ll_flag, "prints the program LL code")
|
; ("--print-ll", Set print_ll_flag, "prints the program LL code")
|
||||||
; ("--print-x86", Set print_x86_flag, "prints the program's assembly code")
|
; ("--print-x86", Set print_x86_flag, "prints the program's assembly code")
|
||||||
; ("--clang", Set clang, "compiles to assembly using clang, not the Compiler Design backend")
|
; ("--clang", Set clang, "compiles to assembly using clang, not the 341 backend")
|
||||||
; ("--execute-x86", Set execute_x86, "run the resulting executable file")
|
; ("--execute-x86", Set execute_x86, "run the resulting executable file")
|
||||||
; ("--print-ast", Set print_ast_flag , "print the program's AST as ML code")
|
; ("--print-ast", Set print_ast_flag , "print the program's AST as ML code")
|
||||||
; ("--print-oat", Set print_oat_flag , "print the program's OAT code")
|
; ("--print-oat", Set print_oat_flag , "print the program's OAT code")
|
||||||
; ("-v", Unit Platform.enable_verbose, "enables more verbose compilation output")
|
; ("-v", Unit Platform.enable_verbose, "enables more verbose compilation output")
|
||||||
]
|
]
|
||||||
|
|
||||||
|
|
||||||
(* Files found on the command line *)
|
(* Files found on the command line *)
|
||||||
|
|
@ -39,12 +39,13 @@ let main () =
|
||||||
Platform.create_output_dir ();
|
Platform.create_output_dir ();
|
||||||
try
|
try
|
||||||
Arg.parse args (fun filename -> files := filename :: !files)
|
Arg.parse args (fun filename -> files := filename :: !files)
|
||||||
"Compiler Design main test harness\n\
|
"CS 131 main test harness\n\
|
||||||
USAGE: ./main.native [options] <files>\n\
|
USAGE: ./main.native [options] <files>\n\
|
||||||
see README for details about using the compiler";
|
see README for details about using the compiler";
|
||||||
|
|
||||||
process_files !files
|
process_files !files
|
||||||
|
|
||||||
with Ran_tests -> ()
|
with Ran_tests ->
|
||||||
|
()
|
||||||
|
|
||||||
;; main ()
|
;; main ()
|
||||||
|
|
@ -1,5 +1,6 @@
|
||||||
%{
|
%{
|
||||||
open Ast
|
open Ast
|
||||||
|
open Lexing
|
||||||
|
|
||||||
let loc (startpos:Lexing.position) (endpos:Lexing.position) (elt:'a) : 'a node =
|
let loc (startpos:Lexing.position) (endpos:Lexing.position) (elt:'a) : 'a node =
|
||||||
{ elt ; loc=Range.mk_lex_range startpos endpos }
|
{ elt ; loc=Range.mk_lex_range startpos endpos }
|
||||||
|
|
@ -38,6 +39,8 @@ let loc (startpos:Lexing.position) (endpos:Lexing.position) (elt:'a) : 'a node =
|
||||||
%token BANG /* ! */
|
%token BANG /* ! */
|
||||||
%token GLOBAL /* global */
|
%token GLOBAL /* global */
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
%left PLUS DASH
|
%left PLUS DASH
|
||||||
%left STAR
|
%left STAR
|
||||||
%nonassoc BANG
|
%nonassoc BANG
|
||||||
|
|
@ -82,6 +85,7 @@ ty:
|
||||||
| TINT { TInt }
|
| TINT { TInt }
|
||||||
| r=rtyp { TRef r }
|
| r=rtyp { TRef r }
|
||||||
|
|
||||||
|
|
||||||
%inline ret_ty:
|
%inline ret_ty:
|
||||||
| TVOID { RetVoid }
|
| TVOID { RetVoid }
|
||||||
| t=ty { RetVal t }
|
| t=ty { RetVal t }
|
||||||
|
|
@ -94,7 +98,7 @@ ty:
|
||||||
| PLUS { Add }
|
| PLUS { Add }
|
||||||
| DASH { Sub }
|
| DASH { Sub }
|
||||||
| STAR { Mul }
|
| STAR { Mul }
|
||||||
| EQEQ { Eq }
|
| EQEQ { Eq }
|
||||||
|
|
||||||
%inline uop:
|
%inline uop:
|
||||||
| DASH { Neg }
|
| DASH { Neg }
|
||||||
|
|
@ -103,7 +107,7 @@ ty:
|
||||||
|
|
||||||
gexp:
|
gexp:
|
||||||
| t=rtyp NULL { loc $startpos $endpos @@ CNull t }
|
| t=rtyp NULL { loc $startpos $endpos @@ CNull t }
|
||||||
| i=INT { loc $startpos $endpos @@ CInt i }
|
| i=INT { loc $startpos $endpos @@ CInt i }
|
||||||
|
|
||||||
lhs:
|
lhs:
|
||||||
| id=IDENT { loc $startpos $endpos @@ Id id }
|
| id=IDENT { loc $startpos $endpos @@ Id id }
|
||||||
3
hw4/dune-project
Normal file
3
hw4/dune-project
Normal file
|
|
@ -0,0 +1,3 @@
|
||||||
|
(lang dune 2.9)
|
||||||
|
(name hw4)
|
||||||
|
(using menhir 2.1)
|
||||||
0
hw4/hw4.opam
Normal file
0
hw4/hw4.opam
Normal file
8
hw4/hw4programs/argassign.oat
Normal file
8
hw4/hw4programs/argassign.oat
Normal file
|
|
@ -0,0 +1,8 @@
|
||||||
|
int foo(int x) {
|
||||||
|
x = x + 1;
|
||||||
|
return x;
|
||||||
|
}
|
||||||
|
|
||||||
|
int program (int argc, string[] argv) {
|
||||||
|
return foo(17);
|
||||||
|
}
|
||||||
|
|
@ -16,7 +16,7 @@ void proc2 ( ) {
|
||||||
}
|
}
|
||||||
|
|
||||||
bool foo ( int x, int[] y ) {
|
bool foo ( int x, int[] y ) {
|
||||||
var s = bar (x, "compilerdesign");
|
var s = bar (x, "cis341");
|
||||||
proc1 ();
|
proc1 ();
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
int program (int argc, string[] argv) {
|
int program (int argc, string[] argv) {
|
||||||
if(6 != 5) {
|
if(6 != 5) {
|
||||||
return ~(5 << 17 >> 2 >>> 10) * 2 - 100 + 6;
|
return ~(5 >> --6 << 9 >>> 10) * 2 - 100 + 6;
|
||||||
} else {
|
} else {
|
||||||
return 2;
|
return 2;
|
||||||
}
|
}
|
||||||
|
|
@ -1,52 +1,52 @@
|
||||||
global float_len = 2;
|
global float_len = 2;
|
||||||
int[] determine_shift(int[] float)
|
int[] determine_shift(int[] float)
|
||||||
{
|
{
|
||||||
var dec = float[1];
|
var dec = float[1];
|
||||||
var count = 0;
|
var count = 0;
|
||||||
while(dec > 0)
|
while(dec > 0)
|
||||||
{
|
{
|
||||||
var temp = float[0];
|
var temp = float[0];
|
||||||
float[0] = temp << 1;
|
float[0] = temp << 1;
|
||||||
dec = dec >>> 1;
|
dec = dec >>> 1;
|
||||||
count = count + 1;
|
count = count + 1;
|
||||||
}
|
}
|
||||||
var list = new int[2];
|
var list = new int[2];
|
||||||
list[0] = float[0] + float[1];
|
list[0] = float[0] + float[1];
|
||||||
list[1] = count;
|
list[1] = count;
|
||||||
return list;
|
return list;
|
||||||
}
|
}
|
||||||
|
|
||||||
int[] multiply_floats(int[] f1, int[] f2)
|
int[] multiply_floats(int[] f1, int[] f2)
|
||||||
{
|
{
|
||||||
var f1_shifted = determine_shift(f1);
|
var f1_shifted = determine_shift(f1);
|
||||||
var f2_shifted = determine_shift(f2);
|
var f2_shifted = determine_shift(f2);
|
||||||
var product = f1_shifted[0] * f2_shifted[0];
|
var product = f1_shifted[0] * f2_shifted[0];
|
||||||
var num_left_shifts = f1_shifted[1] + f2_shifted[1];
|
var num_left_shifts = f1_shifted[1] + f2_shifted[1];
|
||||||
var remainder = 0;
|
var remainder = 0;
|
||||||
for(var i = 0; i < num_left_shifts; i=i+1;)
|
for(var i = 0; i < num_left_shifts; i=i+1;)
|
||||||
{
|
{
|
||||||
var lsb = product [&] 1;
|
var lsb = product [&] 1;
|
||||||
var shifted_lsb = lsb << i;
|
var shifted_lsb = lsb << i;
|
||||||
product = product >>> 1;
|
product = product >>> 1;
|
||||||
remainder = remainder + shifted_lsb;
|
remainder = remainder + shifted_lsb;
|
||||||
}
|
}
|
||||||
var ans = new int[2];
|
var ans = new int[2];
|
||||||
ans[0] = product;
|
ans[0] = product;
|
||||||
ans[1] = remainder;
|
ans[1] = remainder;
|
||||||
return ans;
|
return ans;
|
||||||
}
|
}
|
||||||
|
|
||||||
int program(int argc, string[] argv)
|
int program(int argc, string[] argv)
|
||||||
{
|
{
|
||||||
var pi = new int[2];
|
var pi = new int[2];
|
||||||
pi[0] = 3;
|
pi[0] = 3;
|
||||||
pi[1] = 14159;
|
pi[1] = 14159;
|
||||||
var diameter = new int[2];
|
var diameter = new int[2];
|
||||||
diameter[0] = 20;
|
diameter[0] = 20;
|
||||||
diameter[1] = 17;
|
diameter[1] = 17;
|
||||||
var prod = multiply_floats(pi, diameter);
|
var prod = multiply_floats(pi, diameter);
|
||||||
print_int(prod[0]);
|
print_int(prod[0]);
|
||||||
print_string(".");
|
print_string(".");
|
||||||
print_int(prod[1]);
|
print_int(prod[1]);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
@ -1,3 +1,8 @@
|
||||||
|
/*
|
||||||
|
* CIS 341 Homework 4
|
||||||
|
* Thomas Delacour & Max McCarthy
|
||||||
|
*/
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Computes longest common subsequence of two strings a and b.
|
* Computes longest common subsequence of two strings a and b.
|
||||||
*/
|
*/
|
||||||
|
|
@ -1,39 +1,39 @@
|
||||||
int mod (int a, int b) {
|
int mod (int a, int b) {
|
||||||
var t = a;
|
var t = a;
|
||||||
while (t - b >= 0) {
|
while (t - b >= 0) {
|
||||||
t = t - b;
|
t = t - b;
|
||||||
}
|
}
|
||||||
return t;
|
return t;
|
||||||
}
|
}
|
||||||
|
|
||||||
int div (int a, int b) {
|
int div (int a, int b) {
|
||||||
var result = 0;
|
var result = 0;
|
||||||
var num = a;
|
var num = a;
|
||||||
var denom = b;
|
var denom = b;
|
||||||
while (num > 0) {
|
while (num > 0) {
|
||||||
num = num - denom;
|
num = num - denom;
|
||||||
result = result + 1;
|
result = result + 1;
|
||||||
}
|
}
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
int no_of_factors(int n) {
|
int no_of_factors(int n) {
|
||||||
var num_fact = 1;
|
var num_fact = 1;
|
||||||
var input = n;
|
var input = n;
|
||||||
for (var i = 2; i * i < input + 1; i=i+1;) {
|
for (var i = 2; i * i < input + 1; i=i+1;) {
|
||||||
var power = 0;
|
var power = 0;
|
||||||
while (mod(n, i) == 0) {
|
while (mod(n, i) == 0) {
|
||||||
n = div(n, i);
|
n = div(n, i);
|
||||||
power = power + 1;
|
power = power + 1;
|
||||||
}
|
}
|
||||||
num_fact = num_fact * (power + 1);
|
num_fact = num_fact * (power + 1);
|
||||||
}
|
}
|
||||||
if (n > 1) {
|
if (n > 1) {
|
||||||
num_fact = num_fact * 2;
|
num_fact = num_fact * 2;
|
||||||
}
|
}
|
||||||
return num_fact;
|
return num_fact;
|
||||||
}
|
}
|
||||||
|
|
||||||
int program (int argc, string[] argv) {
|
int program (int argc, string[] argv) {
|
||||||
return no_of_factors(6400);
|
return no_of_factors(6400);
|
||||||
}
|
}
|
||||||
Some files were not shown because too many files have changed in this diff Show more
Loading…
Add table
Add a link
Reference in a new issue