diff options
author | Bad Diode <bd@badd10de.dev> | 2021-11-09 16:32:57 +0100 |
---|---|---|
committer | Bad Diode <bd@badd10de.dev> | 2021-11-09 16:32:57 +0100 |
commit | 795707881285fd171c552516b11e5f7aca65f064 (patch) | |
tree | b01b6a27b5e72abba140708c1f88bd99629846d6 | |
parent | 701369bfb490596a7336415d01142fdee52d5415 (diff) | |
download | bdl-795707881285fd171c552516b11e5f7aca65f064.tar.gz bdl-795707881285fd171c552516b11e5f7aca65f064.zip |
Add compilation context
This prepares the compiler for the compilation of lambdas/procedures.
-rw-r--r-- | src/compiler.h | 342 | ||||
-rw-r--r-- | src/x86_64/prelude.asm | 11 |
2 files changed, 204 insertions, 149 deletions
diff --git a/src/compiler.h b/src/compiler.h index 3227eba..64e6df9 100644 --- a/src/compiler.h +++ b/src/compiler.h | |||
@@ -13,6 +13,16 @@ typedef struct Constant { | |||
13 | 13 | ||
14 | static Constant *constants = NULL; | 14 | static Constant *constants = NULL; |
15 | static char **labels = NULL; | 15 | static char **labels = NULL; |
16 | static char **procedures = NULL; | ||
17 | |||
18 | static char* current_context = NULL; | ||
19 | #define context_printf(fmt, ...) \ | ||
20 | do { \ | ||
21 | char buf[KB(4)]; \ | ||
22 | int n_chars = sprintf(buf, fmt, ##__VA_ARGS__); \ | ||
23 | array_insert(current_context, buf, n_chars); \ | ||
24 | } while(false); | ||
25 | |||
16 | 26 | ||
17 | // TODO: Separate c/h files | 27 | // TODO: Separate c/h files |
18 | // TODO: Create a "driver.c" file with the (display) function for external | 28 | // TODO: Create a "driver.c" file with the (display) function for external |
@@ -70,27 +80,27 @@ emit_file(char *file_name) { | |||
70 | 80 | ||
71 | void | 81 | void |
72 | compile_fixnum(Object *obj) { | 82 | compile_fixnum(Object *obj) { |
73 | printf(" ;; --> compile_fixnum\n"); | 83 | context_printf(" ;; --> compile_fixnum\n"); |
74 | printf(" mov rax, %zu\n", (obj->fixnum << FIXNUM_SHIFT) | FIXNUM_TAG); | 84 | context_printf(" mov rax, %zu\n", (obj->fixnum << FIXNUM_SHIFT) | FIXNUM_TAG); |
75 | printf(" push rax\n"); | 85 | context_printf(" push rax\n"); |
76 | printf(" ;; <-- compile_fixnum\n"); | 86 | context_printf(" ;; <-- compile_fixnum\n"); |
77 | } | 87 | } |
78 | 88 | ||
79 | void | 89 | void |
80 | compile_boolean(Object *obj) { | 90 | compile_boolean(Object *obj) { |
81 | printf(" ;; --> compile_boolean\n"); | 91 | context_printf(" ;; --> compile_boolean\n"); |
82 | int is_true = obj->type == OBJ_TYPE_TRUE; | 92 | int is_true = obj->type == OBJ_TYPE_TRUE; |
83 | printf(" mov rax, %zu\n", (is_true << BOOL_SHIFT) | BOOL_TAG); | 93 | context_printf(" mov rax, %zu\n", (is_true << BOOL_SHIFT) | BOOL_TAG); |
84 | printf(" push rax\n"); | 94 | context_printf(" push rax\n"); |
85 | printf(" ;; <-- compile_boolean\n"); | 95 | context_printf(" ;; <-- compile_boolean\n"); |
86 | } | 96 | } |
87 | 97 | ||
88 | void | 98 | void |
89 | compile_nil(void) { | 99 | compile_nil(void) { |
90 | printf(" ;; --> compile_nil\n"); | 100 | context_printf(" ;; --> compile_nil\n"); |
91 | printf(" mov rax, NIL_VAL\n"); | 101 | context_printf(" mov rax, NIL_VAL\n"); |
92 | printf(" push rax\n"); | 102 | context_printf(" push rax\n"); |
93 | printf(" ;; <-- compile_nil\n"); | 103 | context_printf(" ;; <-- compile_nil\n"); |
94 | } | 104 | } |
95 | 105 | ||
96 | typedef enum OpType { | 106 | typedef enum OpType { |
@@ -115,95 +125,95 @@ typedef enum OpType { | |||
115 | 125 | ||
116 | void | 126 | void |
117 | compile_type_predicate(OpType op, Object* args) { | 127 | compile_type_predicate(OpType op, Object* args) { |
118 | printf(" ;; --> compile_type_predicate\n"); | 128 | context_printf(" ;; --> compile_type_predicate\n"); |
119 | compile_object(args->head); | 129 | compile_object(args->head); |
120 | printf(" pop rax\n"); | 130 | context_printf(" pop rax\n"); |
121 | switch (op) { | 131 | switch (op) { |
122 | case OP_IS_NIL: { | 132 | case OP_IS_NIL: { |
123 | printf(" cmp rax, NIL_VAL\n"); | 133 | context_printf(" cmp rax, NIL_VAL\n"); |
124 | } break; | 134 | } break; |
125 | case OP_IS_ZERO: { | 135 | case OP_IS_ZERO: { |
126 | printf(" cmp rax, 0\n"); | 136 | context_printf(" cmp rax, 0\n"); |
127 | } break; | 137 | } break; |
128 | case OP_IS_BOOL: { | 138 | case OP_IS_BOOL: { |
129 | printf(" and rax, BOOL_MASK\n"); | 139 | context_printf(" and rax, BOOL_MASK\n"); |
130 | printf(" cmp rax, BOOL_TAG\n"); | 140 | context_printf(" cmp rax, BOOL_TAG\n"); |
131 | } break; | 141 | } break; |
132 | case OP_IS_FIXNUM: { | 142 | case OP_IS_FIXNUM: { |
133 | printf(" and rax, FIXNUM_MASK\n"); | 143 | context_printf(" and rax, FIXNUM_MASK\n"); |
134 | printf(" cmp rax, FIXNUM_TAG\n"); | 144 | context_printf(" cmp rax, FIXNUM_TAG\n"); |
135 | } break; | 145 | } break; |
136 | default: break; | 146 | default: break; |
137 | } | 147 | } |
138 | printf(" mov rax, 0\n"); | 148 | context_printf(" mov rax, 0\n"); |
139 | printf(" sete al\n"); | 149 | context_printf(" sete al\n"); |
140 | printf(" shl rax, BOOL_SHIFT\n"); | 150 | context_printf(" shl rax, BOOL_SHIFT\n"); |
141 | printf(" or rax, BOOL_TAG\n"); | 151 | context_printf(" or rax, BOOL_TAG\n"); |
142 | printf(" push rax\n"); | 152 | context_printf(" push rax\n"); |
143 | printf(" ;; <-- compile_type_predicate\n"); | 153 | context_printf(" ;; <-- compile_type_predicate\n"); |
144 | } | 154 | } |
145 | 155 | ||
146 | void | 156 | void |
147 | compile_not(Object* args) { | 157 | compile_not(Object* args) { |
148 | printf(" ;; --> compile_not\n"); | 158 | context_printf(" ;; --> compile_not\n"); |
149 | compile_object(args->head); | 159 | compile_object(args->head); |
150 | printf(" pop rax\n"); | 160 | context_printf(" pop rax\n"); |
151 | printf(" cmp rax, FALSE_VAL\n"); | 161 | context_printf(" cmp rax, FALSE_VAL\n"); |
152 | printf(" mov rax, 0\n"); | 162 | context_printf(" mov rax, 0\n"); |
153 | printf(" sete al\n"); | 163 | context_printf(" sete al\n"); |
154 | printf(" shl rax, BOOL_SHIFT\n"); | 164 | context_printf(" shl rax, BOOL_SHIFT\n"); |
155 | printf(" or rax, BOOL_TAG\n"); | 165 | context_printf(" or rax, BOOL_TAG\n"); |
156 | printf(" push rax\n"); | 166 | context_printf(" push rax\n"); |
157 | printf(" ;; <-- compile_not\n"); | 167 | context_printf(" ;; <-- compile_not\n"); |
158 | } | 168 | } |
159 | 169 | ||
160 | void | 170 | void |
161 | compile_and(Object *args) { | 171 | compile_and(Object *args) { |
162 | printf(" ;; --> compile_and\n"); | 172 | context_printf(" ;; --> compile_and\n"); |
163 | char *lab_false = generate_label("BDLL"); | 173 | char *lab_false = generate_label("BDLL"); |
164 | char *lab_exit = generate_label("BDLL"); | 174 | char *lab_exit = generate_label("BDLL"); |
165 | while (args != NULL) { | 175 | while (args != NULL) { |
166 | compile_object(args->head); | 176 | compile_object(args->head); |
167 | args = args->tail; | 177 | args = args->tail; |
168 | printf(" pop rax\n"); | 178 | context_printf(" pop rax\n"); |
169 | printf(" cmp rax, FALSE_VAL\n"); | 179 | context_printf(" cmp rax, FALSE_VAL\n"); |
170 | printf(" je %s\n", lab_false); | 180 | context_printf(" je %s\n", lab_false); |
171 | } | 181 | } |
172 | printf(" mov rax, TRUE_VAL\n"); | 182 | context_printf(" mov rax, TRUE_VAL\n"); |
173 | printf(" push rax\n"); | 183 | context_printf(" push rax\n"); |
174 | printf(" jmp %s\n", lab_exit); | 184 | context_printf(" jmp %s\n", lab_exit); |
175 | printf("%s:\n", lab_false); | 185 | context_printf("%s:\n", lab_false); |
176 | printf(" mov rax, FALSE_VAL\n"); | 186 | context_printf(" mov rax, FALSE_VAL\n"); |
177 | printf(" push rax\n"); | 187 | context_printf(" push rax\n"); |
178 | printf("%s:\n", lab_exit); | 188 | context_printf("%s:\n", lab_exit); |
179 | printf(" ;; <-- compile_and\n"); | 189 | context_printf(" ;; <-- compile_and\n"); |
180 | } | 190 | } |
181 | 191 | ||
182 | void | 192 | void |
183 | compile_or(Object *args) { | 193 | compile_or(Object *args) { |
184 | printf(" ;; --> compile_or\n"); | 194 | context_printf(" ;; --> compile_or\n"); |
185 | char *lab_true = generate_label("BDLL"); | 195 | char *lab_true = generate_label("BDLL"); |
186 | char *lab_exit = generate_label("BDLL"); | 196 | char *lab_exit = generate_label("BDLL"); |
187 | while (args != NULL) { | 197 | while (args != NULL) { |
188 | compile_object(args->head); | 198 | compile_object(args->head); |
189 | args = args->tail; | 199 | args = args->tail; |
190 | printf(" pop rax\n"); | 200 | context_printf(" pop rax\n"); |
191 | printf(" cmp rax, FALSE_VAL\n"); | 201 | context_printf(" cmp rax, FALSE_VAL\n"); |
192 | printf(" jne %s\n", lab_true); | 202 | context_printf(" jne %s\n", lab_true); |
193 | } | 203 | } |
194 | printf(" mov rax, FALSE_VAL\n"); | 204 | context_printf(" mov rax, FALSE_VAL\n"); |
195 | printf(" push rax\n"); | 205 | context_printf(" push rax\n"); |
196 | printf(" jmp %s\n", lab_exit); | 206 | context_printf(" jmp %s\n", lab_exit); |
197 | printf("%s:\n", lab_true); | 207 | context_printf("%s:\n", lab_true); |
198 | printf(" mov rax, TRUE_VAL\n"); | 208 | context_printf(" mov rax, TRUE_VAL\n"); |
199 | printf(" push rax\n"); | 209 | context_printf(" push rax\n"); |
200 | printf("%s:\n", lab_exit); | 210 | context_printf("%s:\n", lab_exit); |
201 | printf(" ;; <-- compile_or\n"); | 211 | context_printf(" ;; <-- compile_or\n"); |
202 | } | 212 | } |
203 | 213 | ||
204 | void | 214 | void |
205 | compile_cmp_list(OpType op, Object* args) { | 215 | compile_cmp_list(OpType op, Object* args) { |
206 | printf(" ;; --> compile_cmp_list\n"); | 216 | context_printf(" ;; --> compile_cmp_list\n"); |
207 | compile_object(args->head); | 217 | compile_object(args->head); |
208 | char *lab_false = generate_label("BDLL"); | 218 | char *lab_false = generate_label("BDLL"); |
209 | char *lab_exit = generate_label("BDLL"); | 219 | char *lab_exit = generate_label("BDLL"); |
@@ -213,116 +223,116 @@ compile_cmp_list(OpType op, Object* args) { | |||
213 | args = args->tail; | 223 | args = args->tail; |
214 | 224 | ||
215 | // Current value. | 225 | // Current value. |
216 | printf(" pop rcx\n"); | 226 | context_printf(" pop rcx\n"); |
217 | 227 | ||
218 | // Previous value. | 228 | // Previous value. |
219 | printf(" pop rax\n"); | 229 | context_printf(" pop rax\n"); |
220 | 230 | ||
221 | // Comparison. | 231 | // Comparison. |
222 | printf(" cmp rax, rcx\n"); | 232 | context_printf(" cmp rax, rcx\n"); |
223 | switch (op) { | 233 | switch (op) { |
224 | case OP_EQUAL: { printf(" jne %s\n", lab_false); } break; | 234 | case OP_EQUAL: { context_printf(" jne %s\n", lab_false); } break; |
225 | case OP_GREATER: { printf(" jle %s\n", lab_false); } break; | 235 | case OP_GREATER: { context_printf(" jle %s\n", lab_false); } break; |
226 | case OP_LESS: { printf(" jge %s\n", lab_false); } break; | 236 | case OP_LESS: { context_printf(" jge %s\n", lab_false); } break; |
227 | case OP_GREATER_EQ: { printf(" jl %s\n", lab_false); } break; | 237 | case OP_GREATER_EQ: { context_printf(" jl %s\n", lab_false); } break; |
228 | case OP_LESS_EQ: { printf(" jg %s\n", lab_false); } break; | 238 | case OP_LESS_EQ: { context_printf(" jg %s\n", lab_false); } break; |
229 | default: break; | 239 | default: break; |
230 | } | 240 | } |
231 | printf(" push rcx\n"); | 241 | context_printf(" push rcx\n"); |
232 | } | 242 | } |
233 | printf(" pop rcx\n"); | 243 | context_printf(" pop rcx\n"); |
234 | printf(" mov rax, TRUE_VAL\n"); | 244 | context_printf(" mov rax, TRUE_VAL\n"); |
235 | printf(" push rax\n"); | 245 | context_printf(" push rax\n"); |
236 | printf(" jmp %s\n", lab_exit); | 246 | context_printf(" jmp %s\n", lab_exit); |
237 | printf("%s:\n", lab_false); | 247 | context_printf("%s:\n", lab_false); |
238 | printf(" mov rax, FALSE_VAL\n"); | 248 | context_printf(" mov rax, FALSE_VAL\n"); |
239 | printf(" push rax\n"); | 249 | context_printf(" push rax\n"); |
240 | printf("%s:\n", lab_exit); | 250 | context_printf("%s:\n", lab_exit); |
241 | printf(" ;; <-- compile_cmp_list\n"); | 251 | context_printf(" ;; <-- compile_cmp_list\n"); |
242 | } | 252 | } |
243 | 253 | ||
244 | void | 254 | void |
245 | compile_arithmetic_list(OpType op, Object* args) { | 255 | compile_arithmetic_list(OpType op, Object* args) { |
246 | printf(" ;; --> compile_arithmetic\n"); | 256 | context_printf(" ;; --> compile_arithmetic\n"); |
247 | compile_object(args->head); | 257 | compile_object(args->head); |
248 | args = args->tail; | 258 | args = args->tail; |
249 | while (args != NULL) { | 259 | while (args != NULL) { |
250 | compile_object(args->head); | 260 | compile_object(args->head); |
251 | args = args->tail; | 261 | args = args->tail; |
252 | printf(" pop rcx\n"); | 262 | context_printf(" pop rcx\n"); |
253 | printf(" pop rax\n"); | 263 | context_printf(" pop rax\n"); |
254 | switch (op) { | 264 | switch (op) { |
255 | case OP_ADD: { printf(" add rax, rcx\n"); } break; | 265 | case OP_ADD: { context_printf(" add rax, rcx\n"); } break; |
256 | case OP_SUB: { printf(" sub rax, rcx\n"); } break; | 266 | case OP_SUB: { context_printf(" sub rax, rcx\n"); } break; |
257 | case OP_MUL: { | 267 | case OP_MUL: { |
258 | printf(" sar rax, FIXNUM_SHIFT\n"); | 268 | context_printf(" sar rax, FIXNUM_SHIFT\n"); |
259 | printf(" sar rcx, FIXNUM_SHIFT\n"); | 269 | context_printf(" sar rcx, FIXNUM_SHIFT\n"); |
260 | printf(" mul rcx\n"); | 270 | context_printf(" mul rcx\n"); |
261 | printf(" shl rax, FIXNUM_SHIFT\n"); | 271 | context_printf(" shl rax, FIXNUM_SHIFT\n"); |
262 | } break; | 272 | } break; |
263 | case OP_DIV: { | 273 | case OP_DIV: { |
264 | printf(" sar rax, FIXNUM_SHIFT\n"); | 274 | context_printf(" sar rax, FIXNUM_SHIFT\n"); |
265 | printf(" sar rcx, FIXNUM_SHIFT\n"); | 275 | context_printf(" sar rcx, FIXNUM_SHIFT\n"); |
266 | printf(" mov rdx, 0\n"); | 276 | context_printf(" mov rdx, 0\n"); |
267 | printf(" div rcx\n"); | 277 | context_printf(" div rcx\n"); |
268 | printf(" shl rax, FIXNUM_SHIFT\n"); | 278 | context_printf(" shl rax, FIXNUM_SHIFT\n"); |
269 | } break; | 279 | } break; |
270 | case OP_MOD: { | 280 | case OP_MOD: { |
271 | printf(" sar rax, FIXNUM_SHIFT\n"); | 281 | context_printf(" sar rax, FIXNUM_SHIFT\n"); |
272 | printf(" sar rcx, FIXNUM_SHIFT\n"); | 282 | context_printf(" sar rcx, FIXNUM_SHIFT\n"); |
273 | printf(" mov rdx, 0\n"); | 283 | context_printf(" mov rdx, 0\n"); |
274 | printf(" div rcx\n"); | 284 | context_printf(" div rcx\n"); |
275 | printf(" mov rax, rdx\n"); | 285 | context_printf(" mov rax, rdx\n"); |
276 | printf(" shl rax, FIXNUM_SHIFT\n"); | 286 | context_printf(" shl rax, FIXNUM_SHIFT\n"); |
277 | } break; | 287 | } break; |
278 | default: break; | 288 | default: break; |
279 | } | 289 | } |
280 | printf(" push rax\n"); | 290 | context_printf(" push rax\n"); |
281 | } | 291 | } |
282 | printf(" ;; <-- compile_arithmetic\n"); | 292 | context_printf(" ;; <-- compile_arithmetic\n"); |
283 | } | 293 | } |
284 | 294 | ||
285 | void | 295 | void |
286 | compile_cons(Object *obj) { | 296 | compile_cons(Object *obj) { |
287 | printf(" ;; --> compile_cons\n"); | 297 | context_printf(" ;; --> compile_cons\n"); |
288 | // Store objects into the car and cdr. | 298 | // Store objects into the car and cdr. |
289 | compile_object(obj->head); | 299 | compile_object(obj->head); |
290 | compile_object(obj->tail->head); | 300 | compile_object(obj->tail->head); |
291 | printf(" pop rdx\n"); | 301 | context_printf(" pop rdx\n"); |
292 | printf(" pop rax\n"); | 302 | context_printf(" pop rax\n"); |
293 | printf(" mov [r15], rax\n"); | 303 | context_printf(" mov [r15], rax\n"); |
294 | printf(" mov [r15 + 8], rdx\n"); | 304 | context_printf(" mov [r15 + 8], rdx\n"); |
295 | 305 | ||
296 | // Push memory address of cons cell. | 306 | // Push memory address of cons cell. |
297 | printf(" mov rax, r15\n"); | 307 | context_printf(" mov rax, r15\n"); |
298 | printf(" or rax, %zu\n", PAIR_TAG); | 308 | context_printf(" or rax, %zu\n", PAIR_TAG); |
299 | printf(" push rax\n"); | 309 | context_printf(" push rax\n"); |
300 | 310 | ||
301 | // Bump allocation register. | 311 | // Bump allocation register. |
302 | printf(" add r15, 16\n"); | 312 | context_printf(" add r15, 16\n"); |
303 | printf(" ;; <-- compile_cons\n"); | 313 | context_printf(" ;; <-- compile_cons\n"); |
304 | } | 314 | } |
305 | 315 | ||
306 | void | 316 | void |
307 | compile_car(Object *obj) { | 317 | compile_car(Object *obj) { |
308 | printf(" ;; --> compile_car\n"); | 318 | context_printf(" ;; --> compile_car\n"); |
309 | compile_object(obj->head); | 319 | compile_object(obj->head); |
310 | printf(" pop rax\n"); | 320 | context_printf(" pop rax\n"); |
311 | printf(" and rax, %zu\n", ~PAIR_MASK); | 321 | context_printf(" and rax, %zu\n", ~PAIR_MASK); |
312 | printf(" mov rdx, [rax]\n"); | 322 | context_printf(" mov rdx, [rax]\n"); |
313 | printf(" push rdx\n"); | 323 | context_printf(" push rdx\n"); |
314 | printf(" ;; <-- compile_car\n"); | 324 | context_printf(" ;; <-- compile_car\n"); |
315 | } | 325 | } |
316 | 326 | ||
317 | void | 327 | void |
318 | compile_cdr(Object *obj) { | 328 | compile_cdr(Object *obj) { |
319 | printf(" ;; --> compile_cdr\n"); | 329 | context_printf(" ;; --> compile_cdr\n"); |
320 | compile_object(obj->head); | 330 | compile_object(obj->head); |
321 | printf(" pop rax\n"); | 331 | context_printf(" pop rax\n"); |
322 | printf(" and rax, %zu\n", ~PAIR_MASK); | 332 | context_printf(" and rax, %zu\n", ~PAIR_MASK); |
323 | printf(" mov rdx, [rax + 8]\n"); | 333 | context_printf(" mov rdx, [rax + 8]\n"); |
324 | printf(" push rdx\n"); | 334 | context_printf(" push rdx\n"); |
325 | printf(" ;; <-- compile_cdr\n"); | 335 | context_printf(" ;; <-- compile_cdr\n"); |
326 | } | 336 | } |
327 | 337 | ||
328 | void | 338 | void |
@@ -349,8 +359,8 @@ compile_proc_call(Object *obj) { | |||
349 | compile_type_predicate(OP_IS_BOOL, obj->tail); | 359 | compile_type_predicate(OP_IS_BOOL, obj->tail); |
350 | } else if (sv_equal(&obj->head->text, &STRING("display"))) { | 360 | } else if (sv_equal(&obj->head->text, &STRING("display"))) { |
351 | compile_object(obj->tail->head); | 361 | compile_object(obj->tail->head); |
352 | printf(" pop rdi\n"); | 362 | context_printf(" pop rdi\n"); |
353 | printf(" call display\n"); | 363 | context_printf(" call display\n"); |
354 | } else if (sv_equal(&obj->head->text, &STRING("not"))) { | 364 | } else if (sv_equal(&obj->head->text, &STRING("not"))) { |
355 | compile_not(obj->tail); | 365 | compile_not(obj->tail); |
356 | } else if (sv_equal(&obj->head->text, &STRING("and"))) { | 366 | } else if (sv_equal(&obj->head->text, &STRING("and"))) { |
@@ -383,24 +393,24 @@ void | |||
383 | compile_if(Object *obj) { | 393 | compile_if(Object *obj) { |
384 | char *lab_false = generate_label("BDLL"); | 394 | char *lab_false = generate_label("BDLL"); |
385 | compile_object(obj->condition); | 395 | compile_object(obj->condition); |
386 | printf(" pop rax\n"); | 396 | context_printf(" pop rax\n"); |
387 | printf(" cmp rax, FALSE_VAL\n"); | 397 | context_printf(" cmp rax, FALSE_VAL\n"); |
388 | printf(" je %s\n", lab_false); | 398 | context_printf(" je %s\n", lab_false); |
389 | compile_object(obj->expr_true); | 399 | compile_object(obj->expr_true); |
390 | if (obj->expr_false != NULL) { | 400 | if (obj->expr_false != NULL) { |
391 | char *lab_exit = generate_label("BDLL"); | 401 | char *lab_exit = generate_label("BDLL"); |
392 | printf(" jmp %s\n", lab_exit); | 402 | context_printf(" jmp %s\n", lab_exit); |
393 | printf("%s:\n", lab_false); | 403 | context_printf("%s:\n", lab_false); |
394 | compile_object(obj->expr_false); | 404 | compile_object(obj->expr_false); |
395 | printf("%s:\n", lab_exit); | 405 | context_printf("%s:\n", lab_exit); |
396 | } else { | 406 | } else { |
397 | printf("%s:\n", lab_false); | 407 | context_printf("%s:\n", lab_false); |
398 | } | 408 | } |
399 | } | 409 | } |
400 | 410 | ||
401 | void | 411 | void |
402 | compile_string(Object *obj) { | 412 | compile_string(Object *obj) { |
403 | printf(" ;; --> compile_string\n"); | 413 | context_printf(" ;; --> compile_string\n"); |
404 | Constant c; | 414 | Constant c; |
405 | 415 | ||
406 | // Check if the string is already stored as a constant. | 416 | // Check if the string is already stored as a constant. |
@@ -422,10 +432,33 @@ compile_string(Object *obj) { | |||
422 | } | 432 | } |
423 | 433 | ||
424 | // Create a tagged pointer to the label. | 434 | // Create a tagged pointer to the label. |
425 | printf(" mov rax, %s\n", c.label); | 435 | context_printf(" mov rax, %s\n", c.label); |
426 | printf(" or rax, STRING_TAG\n"); | 436 | context_printf(" or rax, STRING_TAG\n"); |
427 | printf(" push rax\n"); | 437 | context_printf(" push rax\n"); |
428 | printf(" ;; <-- compile_string\n"); | 438 | context_printf(" ;; <-- compile_string\n"); |
439 | } | ||
440 | |||
441 | void | ||
442 | compile_lambda(Object *obj) { | ||
443 | // Create a new compilation context. | ||
444 | char *prev_context = current_context; | ||
445 | current_context = NULL; | ||
446 | array_init(current_context, 0); | ||
447 | |||
448 | char *name = generate_label("BDLP"); | ||
449 | context_printf("%s:\n", name); | ||
450 | for (size_t i = 0; i < array_size(obj->body); i++) { | ||
451 | compile_object(obj->body[i]); | ||
452 | } | ||
453 | context_printf(" ret\n"); | ||
454 | context_printf("\n"); | ||
455 | |||
456 | // Restore previous compilation context. | ||
457 | array_push(procedures, current_context); | ||
458 | current_context = prev_context; | ||
459 | |||
460 | // TODO: Create tagged pointer with this lambda procedure. | ||
461 | // TODO: Push compiled object to the stack. | ||
429 | } | 462 | } |
430 | 463 | ||
431 | void | 464 | void |
@@ -438,6 +471,7 @@ compile_object(Object *obj) { | |||
438 | case OBJ_TYPE_PAIR: { compile_proc_call(obj); } break; | 471 | case OBJ_TYPE_PAIR: { compile_proc_call(obj); } break; |
439 | case OBJ_TYPE_STRING: { compile_string(obj); } break; | 472 | case OBJ_TYPE_STRING: { compile_string(obj); } break; |
440 | case OBJ_TYPE_IF: { compile_if(obj); } break; | 473 | case OBJ_TYPE_IF: { compile_if(obj); } break; |
474 | case OBJ_TYPE_LAMBDA: { compile_lambda(obj); } break; | ||
441 | default: break; | 475 | default: break; |
442 | } | 476 | } |
443 | } | 477 | } |
@@ -478,8 +512,16 @@ compile(Root *roots) { | |||
478 | // Prepare compilation variables. | 512 | // Prepare compilation variables. |
479 | array_init(constants, 0); | 513 | array_init(constants, 0); |
480 | array_init(labels, 0); | 514 | array_init(labels, 0); |
515 | array_init(procedures, 0); | ||
516 | array_init(current_context, 0); | ||
481 | 517 | ||
482 | // Prelude. | 518 | // Compile program. |
519 | for (size_t i = 0; i < array_size(roots); i++) { | ||
520 | Object *root = roots[i]; | ||
521 | compile_object(root); | ||
522 | } | ||
523 | |||
524 | // Base defines. | ||
483 | printf("%%define NIL_VAL %zu\n", NIL_VAL); | 525 | printf("%%define NIL_VAL %zu\n", NIL_VAL); |
484 | printf("%%define TRUE_VAL %zu\n", TRUE_VAL); | 526 | printf("%%define TRUE_VAL %zu\n", TRUE_VAL); |
485 | printf("%%define FALSE_VAL %zu\n", FALSE_VAL); | 527 | printf("%%define FALSE_VAL %zu\n", FALSE_VAL); |
@@ -496,12 +538,26 @@ compile(Root *roots) { | |||
496 | printf("%%define STRING_TAG %zu\n", STRING_TAG); | 538 | printf("%%define STRING_TAG %zu\n", STRING_TAG); |
497 | printf("%%define HEAP_SIZE %zu\n", HEAP_SIZE); | 539 | printf("%%define HEAP_SIZE %zu\n", HEAP_SIZE); |
498 | printf("\n"); | 540 | printf("\n"); |
541 | |||
542 | // Prelude. | ||
499 | emit_file(PRELUDE_FILE); | 543 | emit_file(PRELUDE_FILE); |
544 | printf("\n"); | ||
500 | 545 | ||
501 | // Compile program. | 546 | // Function definitions. |
502 | for (size_t i = 0; i < array_size(roots); i++) { | 547 | for (size_t i = 0; i < array_size(procedures); i++) { |
503 | Object *root = roots[i]; | 548 | char *ctx = procedures[i]; |
504 | compile_object(root); | 549 | for (size_t i = 0; i < array_size(ctx); i++) { |
550 | putchar(ctx[i]); | ||
551 | } | ||
552 | } | ||
553 | |||
554 | // Main context. | ||
555 | printf("global _start\n"); | ||
556 | printf("_start:\n"); | ||
557 | printf(" mov r15, bdl_heap\n"); | ||
558 | printf(" push NIL_VAL\n"); | ||
559 | for (size_t i = 0; i < array_size(current_context); i++) { | ||
560 | putchar(current_context[i]); | ||
505 | } | 561 | } |
506 | 562 | ||
507 | // Postlude. | 563 | // Postlude. |
@@ -515,6 +571,10 @@ compile(Root *roots) { | |||
515 | free(labels[i]); | 571 | free(labels[i]); |
516 | } | 572 | } |
517 | array_free(labels); | 573 | array_free(labels); |
574 | for (size_t i = 0; i < array_size(procedures); i++) { | ||
575 | array_free(procedures[i]); | ||
576 | } | ||
577 | array_free(procedures); | ||
518 | } | 578 | } |
519 | 579 | ||
520 | #endif // BDL_COMPILER_H | 580 | #endif // BDL_COMPILER_H |
diff --git a/src/x86_64/prelude.asm b/src/x86_64/prelude.asm index c9ef823..05762b9 100644 --- a/src/x86_64/prelude.asm +++ b/src/x86_64/prelude.asm | |||
@@ -108,14 +108,9 @@ not_string: | |||
108 | 108 | ||
109 | ;; is fixnum? | 109 | ;; is fixnum? |
110 | mov rax, rdi | 110 | mov rax, rdi |
111 | and rax, FIXNUM_MASK | ||
112 | cmp rax, FIXNUM_TAG | ||
113 | jne display_end | ||
111 | call printdln | 114 | call printdln |
112 | display_end: | 115 | display_end: |
113 | ret | 116 | ret |
114 | |||
115 | global _start | ||
116 | _start: | ||
117 | ;; point `rdi` to the start of the heap. | ||
118 | mov r15, bdl_heap | ||
119 | |||
120 | ;; make sure the last element in the stack is the nil value. | ||
121 | push NIL_VAL | ||