-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathcode_generator.ml
More file actions
309 lines (274 loc) · 10.2 KB
/
code_generator.ml
File metadata and controls
309 lines (274 loc) · 10.2 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
open String
open Types
open Char
open Codefragments
open List
open Pretty_printer_files
open Typechecker_types
open Typechecker_print
open Char_func
let list_gen (gen:'a->string) (alist:'a list): string = fold_right (^) (map gen alist) ("");;
(* besluiten *)
(* "var id = exp" betekent niks anders dan dat je geen zin had om de type van id te specificeren *)
(* lists zijn single linkedlists, oftewel tuples van (waarde, pointer naar volgende plek) *)
(* Als een pointer is 0, dan wijst hij naar een lege lijst *)
(* exp_infix voorbeeld *)
(* 2 + 3 *)
(*LDC 2
LDC 3
ADD *)
let get_vartype id (vars : env_var list) =
try
(List.find (fun (x : env_var) -> x.id = id) vars).t
with
| Not_found -> Void;;
let get_fun id (funs : env_fun list) =
try
(List.find (fun (x : env_fun) -> x.id=id) funs)
with
| Not_found -> empty_fun;;
let get_idstruct id (idstructs : idstruct list) =
try
List.find (fun (x : idstruct) -> x.id=id) idstructs
with
| Not_found -> empty_idstruct;;
let rec get_typenr c i = function
| [] -> raise(Failure "Not Found")
| hd::tl -> if (hd=c) then i else get_typenr c (i+1) tl
let rec expfield_gen vars = function
| Nofield id -> let idstruct = get_idstruct id vars in code_get idstruct
| Field (exp,Hd)
| Field (exp,Fst) -> (expfield_gen vars exp) ^ lda (-1)
| Field (exp,Tl)
| Field (exp,Snd) -> (expfield_gen vars exp) ^ lda 0;;
let rec exp_gen vars types exp =
match exp with
| Exp_int x -> ldc x
| Exp_char x -> ldc (Char.code x)
| Exp_bool true -> ldc truenr
| Exp_bool false -> ldc 0
| Exp_field (expfield) -> expfield_gen vars expfield
| Exp_infix (exp1,op,exp2) -> (exp_gen vars types exp1) ^ (exp_gen vars types exp2) ^ (op2code op)
| Exp_prefix (op,exp) -> (exp_gen vars types exp) ^ (op1code op)
| Exp_function_call (id,explist) -> (list_gen (exp_gen vars types) (explist)) ^ (some_funcallcode id (length explist))
| Exp_emptylist -> ldc 0
| Exp_tuple (exp1,exp2) -> (exp_gen vars types exp1) ^ (exp_gen vars types exp2) ^ create_tuplecode
| Exp_constructor c -> ldc (get_typenr c 0 types) ;;
(* sta: *)
(* Store via Address. *)
(* Pops 2 values from the stack and *)
(* stores the second popped value in the location pointed to by the first. *)
(* The pointer value is offset by a constant offset. *)
(* Wat moet er gebeuren met een vardecl (met een nieuw id)? *)
(* Zoek de var in de vars list en onthoud index i *)
(* '(var met index i) = x': *)
(* ldc x \n *)
(* ldr r5 \n *)
(* sta i \n *)
let branchindex = ref 0;;
let choose_label labeloption label2 =
match labeloption with
| Some label1 -> label1
| None -> label2
let rec if_gen vars types fid = function
| (exp,stmts) -> branchindex := !branchindex + 1;
let (ifbody,labeloption) = stmtlist_gen vars types fid None stmts in
let endiflabel = choose_label labeloption (endiflabel fid !branchindex) in
let code =
exp_gen vars types exp^
brf endiflabel^
ifbody^
(if labeloption = None then pointlabel endiflabel else "") in
(code, Some endiflabel)
and
if_else_gen vars types fid = function
| (exp,stmtsif,stmtselse) -> branchindex := !branchindex + 1;
let endiflabel = endiflabel fid !branchindex in
let (elsebody, labeloption) = stmtlist_gen vars types fid (Some endiflabel) stmtselse in
let endelselabel = choose_label labeloption (endelselabel fid !branchindex) in
let code =
exp_gen vars types exp^
brf endiflabel^
fst (stmtlist_gen vars types fid None stmtsif)^
bra endelselabel^
pointlabel endiflabel^
elsebody^
(if labeloption = None then pointlabel endelselabel else "") in
(code,Some endelselabel)
and
while_gen vars types fid startlabeloption = function
| (exp,stmts) -> branchindex := !branchindex + 1;
let startwhilelabel = choose_label startlabeloption (startwhilelabel fid !branchindex) in
let endwhilelabel = endwhilelabel fid !branchindex in
let code =
(if startlabeloption = None then pointlabel startwhilelabel else "") ^
exp_gen vars types exp^
brf endwhilelabel^
fst (stmtlist_gen vars types fid None stmts)^
bra startwhilelabel^
pointlabel endwhilelabel in
(code,Some endwhilelabel)
and
define_gen vars types = function
| (Nofield id, exp) ->
let idstruct = get_idstruct id vars in
let code =
exp_gen vars types exp^
code_set idstruct in
(code,None)
| (Field (fieldexp,Fst),exp)
| (Field (fieldexp,Hd),exp) ->
let code =
exp_gen vars types exp^
expfield_gen vars fieldexp ^
sta (-1) in
(code,None)
| (Field (fieldexp,Snd),exp)
| (Field (fieldexp,Tl),exp) ->
let code =
exp_gen vars types exp^
expfield_gen vars fieldexp ^
sta 0 in
(code, None)
and
function_call_gen vars types = function
| (id,explist) ->
let code =
list_gen (exp_gen vars types) explist^
none_funcallcode id (length explist) in
(code,None)
and
return_gen vars types = function
| (Some exp) ->
let code =
exp_gen vars types exp^
return_some_code in
(code,None)
| None ->
let code =
return_none_code in
(code,None)
and
stmt_gen vars types fid startlabeloption = function
| Stmt_if (a,b) -> if_gen vars types fid (a,b)
| Stmt_if_else (a,b,c) -> if_else_gen vars types fid (a,b,c)
| Stmt_while (a,b) -> while_gen vars types fid startlabeloption (a,b)
| Stmt_define (a,b) -> define_gen vars types (a,b)
| Stmt_function_call (a,b) -> function_call_gen vars types (a,b)
| Stmt_return a -> return_gen vars types a
and
stmtlist_gen vars types fid startlabeloption = function
| stmt::stmtlist ->
let (stmtcode,startlabeloption) = stmt_gen vars types fid startlabeloption stmt in
let (stmtlistcode,startlabeloption) = stmtlist_gen vars types fid startlabeloption stmtlist in
(stmtcode^stmtlistcode,startlabeloption)
| [] -> ("",startlabeloption)
exception Should_end_with_return_statement of string;;
let rec last_if_else_gen vars types fid = function
| (exp,stmtsif,stmtselse) -> branchindex := !branchindex + 1;
let endiflabel = endiflabel fid !branchindex in
let code =
exp_gen vars types exp^
brf endiflabel^
fst (topstmtlist_gen vars types fid None stmtsif)^
pointlabel endiflabel^
fst (topstmtlist_gen vars types fid (Some endiflabel) stmtselse) in
(code,None)
and
last_stmt_gen vars types fid startlabeloption = function
| Stmt_if_else (a,b,c) -> last_if_else_gen vars types fid (a,b,c)
| Stmt_return (a) -> return_gen vars types (a)
| stmt -> raise (Should_end_with_return_statement fid)
and
topstmtlist_gen vars types fid startlabeloption = function
| stmt::[] -> last_stmt_gen vars types fid startlabeloption stmt
| stmt::stmtlist ->
let (stmtcode,startlabeloption) = stmt_gen vars types fid startlabeloption stmt in
let (stmtlistcode,startlabeloption) = topstmtlist_gen vars types fid startlabeloption stmtlist in
(stmtcode^stmtlistcode,startlabeloption)
let rec fargs_to_idstructs i fargtypes = function
| id::fargs -> {global=false;vartype=hd fargtypes; id=id; index=i}::(fargs_to_idstructs (i+1) (tl fargtypes) fargs)
| [] -> []
let rec vardecl_gen vars types = function
|(t,id,exp)::vardecllist ->
let id= get_idstruct id vars in
(exp_gen vars types exp) ^ (code_set id)^(vardecl_gen vars types vardecllist)
| [] -> ""
(* append_unique l1 l2: append el l2 als hij niet voorkomt in l1 *)
let rec append_unique (l1: idstruct list) (l2: idstruct list) = match l2 with
| el2::l2 ->
if List.exists (fun (x: idstruct) -> x.id = el2.id) l1
then
append_unique l1 l2
else
append_unique (el2::l1) l2
| [] -> l1
(* Als een var in fargs voorkomt bindt die sterker dan als in gvars *)
(* Als een var in lvars voorkomt en ook in fargs hoeft er geen ruimte voor gereserveerd te worden *)
let localknown fargs lvars gvars = append_unique (append lvars fargs) gvars
let rec vartypes_to_idstructs global index = function
| (x : env_var)::vartypes -> {id=x.id;vartype=x.t;global=global;index=index}::vartypes_to_idstructs global (index+1) vartypes
| [] -> []
let rec print_vars (vars:idstruct list)= match vars with
| var::vars -> var.id ^ " " ^ (print_vars vars)
| [] -> " # "
let rec ftype_to_fargtypes=function
| Imp (t,ftype) -> t::ftype_to_fargtypes ftype
| _ -> []
(* in order: *)
(* set branchname*)
(* reserve space for the local vars *)
(* parse the local vars *)
(* parse de stmts. This includes return *)
let rec functions_gen (gvars:'a list) funtypes types = function
| (fid,fargs,_,vardecllist,stmtlist)::decllist ->
let func = get_fun fid funtypes in
let fargtypes = ftype_to_fargtypes func.t in
let fargs = fargs_to_idstructs (-1-(length fargs)) fargtypes fargs in
let locals = Env_var.fold (fun x list ->
if (List.exists (fun (y: idstruct) -> y.id = x.id) fargs)
then list
else x::list) func.locals [] in
let lvars = vartypes_to_idstructs false 1 locals in
let localknown = localknown fargs lvars gvars in
(* print_vars gvars^"\n"^ *)
(* print_vars localknown^ *)
(* print_list (map string_of_type (map (fun x -> x.vartype) localknown))^ *)
pointlabel fid^
reservelocalcode (length lvars)^
vardecl_gen localknown types vardecllist^
fst (topstmtlist_gen localknown types fid None stmtlist)^
functions_gen gvars funtypes types decllist
| [] -> ""
let rec get_vardecls = function
| (Vardecl vardecl)::spl -> vardecl::(get_vardecls spl)
| (Fundecl fundecl)::spl -> get_vardecls spl
| [] -> []
let rec get_fundecls = function
| (Fundecl fundecl)::spl -> fundecl::(get_fundecls spl)
| (Vardecl vardecl)::spl -> get_fundecls spl
| [] -> []
(*help function for printing: makes a simple string of vardecls*)
let rec print_vardecls = function
| (_,id,_)::list -> id ^" "^(print_vardecls list)
| [] -> " # "
(* in order: *)
(* make the startcode: define emptylist and branch to main *)
(* reserve space for all global vars *)
(* define all functions *)
(* generate main: only look at vardecls *)
let code_gen env (spl:decl list) =
let vartypes = Env_var.elements env.vars in
let funtypes = Env_fun.elements env.funs in
let types = filter (fun x -> is_uppercase (String.get x 0)) (map (fun (x : env_type) -> x.id) (Env_type.elements env.types)) in
let mainlabel = "main" in
let gvars = vartypes_to_idstructs true 0 vartypes in
(* print_vars gvars^ *)
reservecode (length gvars)^
vardecl_gen gvars types (get_vardecls spl)^
"bsr "^ mainlabel^" \n"^
end_code^
functions_gen gvars funtypes types (get_fundecls spl)^
isempty_code^
read_code^
write_code