Fix brainf*ck interpreter memory issue
[bob_language.git] / core.c
blob8591dbe4d117d5940a623d8cc58d8b27a8a32534
1 #include <stdio.h>
2 #include <stdlib.h>
3 #include <string.h>
4 #include "dynstrings.h"
5 #include "tables.h"
6 #include "core.h"
7 #include "numbers.h"
8 #include "assembly.h"
10 #define SUPRESS_WARNING(x) (void)x
12 int c_label = 0;
13 int c_stack = 0;
15 char *c_fnname;
16 char *c_error;
17 char c_pad[256];
18 FILE *c_output;
19 void (*nodefunc[NODE_MAXFUNC]) (TreeNode *node);
20 TreeNode *root;
22 TreeNode *node_new() {
23 TreeNode *result = malloc(sizeof(TreeNode));
24 result->id = NODE_EMPTY;
25 result->code = strdup("");
26 result->next = result;
27 result->previous = result;
28 result->bottom = NULL;
29 return result;
32 void node_free(TreeNode *node) {
33 free(node->code);
34 free(node);
37 void node_set(TreeNode *node, char *code) {
38 free(node->code);
39 node->code = code;
42 void node_next(TreeNode *parent, TreeNode *child) {
43 child->previous->next = parent->next;
44 parent->next->previous = child->previous;
45 parent->next = child;
46 child->previous = parent;
49 void node_bottom(TreeNode *parent, TreeNode *child) {
50 if (parent->bottom == NULL) {
51 parent->bottom = child;
53 else {
54 TreeNode *childprev = child->previous;
55 TreeNode *parentprev = parent->bottom->previous;
56 child->previous = parentprev;
57 parent->bottom->previous = childprev;
58 childprev->next = parent->bottom;
59 parentprev->next = child;
60 parent->bottom = child;
64 void node_traverse(TreeNode *node) {
65 nodefunc[node->id](node);
68 void core_error(char *msg) {
69 c_error = str_cat2(c_error, msg);
72 void core_pad_add(int amount) {
73 int start = strlen(c_pad);
74 int i;
75 for (i = 0; i < amount; i++)
76 c_pad[start + i] = ' ';
77 c_pad[start + amount] = '\0';
80 void core_pad_sub(int amount) {
81 int position = strlen(c_pad) - amount;
82 if (position < 0) position = 0;
83 c_pad[position] = '\0';
86 void core_pad_reset() {
87 c_pad[0] = '\0';
90 char *core_translate_name(char *name) {
91 int length = strlen(name);
92 int i;
93 int translate = 0;
94 for (i = 0; i < length; i++) {
95 if ((name[i] == '8') || (name[i] == '9') || (name[i] == '_'))
96 translate++;
98 char *result = malloc(length + translate + 1);
99 char *output = result;
100 for (i = 0; i < length; i++) {
101 switch (name[i]) {
102 case '8':
103 output[1] = output[0] = '8';
104 output += 2;
105 break;
106 case '9':
107 output[1] = output[0] = '9';
108 output += 2;
109 break;
110 case '_':
111 output[0] = '8';
112 output[1] = '9';
113 output += 2;
114 break;
115 default:
116 output[0] = name[i];
117 output++;
120 output[0] = '\0';
121 return result;
124 char *core_translate_var(char *name) {
125 name = core_translate_name(name);
126 char *result;
127 int local = varLocal(name);
128 if (local < 0) {
129 result = varGlobal(name);
130 if (result == NULL) {
131 addGlobal(name);
132 result = varGlobal(name);
134 return strdup(result);
136 else
137 return str_printf("^%d", local + c_stack);
140 void core_empty(TreeNode *node) {
141 SUPRESS_WARNING(node);
144 void core_function(TreeNode *node) {
145 clearLocals();
146 c_stack = 0;
147 int c_params = 0;
148 TreeNode *iterator = node->next->next;
149 while (iterator != node) {
150 node_traverse(iterator);
151 iterator = iterator->next;
152 node_free(iterator->previous);
153 c_params++;
155 c_fnname = node->next->code;
156 if (varFunction(c_fnname) != -1) {
157 core_error(str_printf("Error: Function %s already exists!\n", c_fnname));
158 return;
160 addFunction(c_fnname, c_params);
161 c_fnname = core_translate_name(c_fnname);
162 node_free(node->next);
163 core_pad_reset();
164 fprintf(c_output, "fn%sStart:\n", c_fnname);
165 core_pad_add(2);
166 fprintf(c_output, "%sebx = 0 - 1\n", c_pad);
167 node_traverse(node->bottom);
168 fputs(node->bottom->code, c_output);
169 node_free(node->bottom);
170 fprintf(c_output, "jump fn%sEnd\n", c_fnname);
171 fprintf(c_output, "fn%sEnd:\n", c_fnname);
172 int i;
173 for (i = 0; i < c_params; i++)
174 fprintf(c_output, " call BDestroy\n");
175 fprintf(c_output, " call BFinalizeResult\n");
176 fprintf(c_output, "return\n\n");
177 free(c_fnname);
178 if (c_stack != 0)
179 core_error(str_printf("Error: Stack inconsistent! (%d)\n", c_stack));
182 void core_func_args(TreeNode *node) {
183 char *name = core_translate_name(node->bottom->code);
184 addLocal(name);
185 free(name);
186 node_free(node->bottom);
189 void core_return(TreeNode *node) {
190 node_traverse(node->bottom);
191 char *result = strdup(node->bottom->code);
192 result = str_cat2(result, str_printf("%stop ebx\n", c_pad));
193 result = str_cat2(result, str_printf("%spop\n", c_pad));
194 result = str_cat2(result, str_printf("jump fn%sEnd\n", c_fnname));
195 node_set(node, result);
196 node_free(node->bottom);
197 c_stack--;
200 void core_if(TreeNode *node) {
201 node_traverse(node->next);
202 c_stack--;
203 core_pad_add(2);
204 node_traverse(node->bottom);
205 core_pad_sub(2);
206 char *label = str_printf("fn%s%d", c_fnname, c_label);
207 char *result = strdup(node->next->code);
208 result = str_cat2(result, str_printf("%scall BBIsZero\n", c_pad));
209 result = str_cat2(result, str_printf("%sifeq eax %s\n", c_pad, label));
210 result = str_cat(result, node->bottom->code);
211 result = str_cat2(result, str_printf("%s%s: eax = eax + 0\n", c_pad, label));
212 node_set(node, result);
213 free(label);
214 node_free(node->next);
215 node_free(node->bottom);
216 c_label++;
219 void core_while(TreeNode *node) {
220 core_pad_add(2);
221 node_traverse(node->next);
222 c_stack--;
223 node_traverse(node->bottom);
224 core_pad_sub(2);
225 char *check = str_printf("%sfn%dCheck", c_fnname, c_label);
226 char *loop = str_printf("%sfn%dLoop", c_fnname, c_label);
227 char *result = str_printf("%sjump %s\n", c_pad, check);
228 result = str_cat2(result, str_printf("%s%s:\n", c_pad, loop));
229 result = str_cat(result, node->bottom->code);
230 result = str_cat2(result, str_printf("%s%s:\n", c_pad, check));
231 result = str_cat(result, node->next->code);
232 result = str_cat2(result, str_printf("%s call BBIsZero\n", c_pad));
233 result = str_cat2(result, str_printf("%sifneq eax %s\n", c_pad, loop));
234 node_set(node, result);
235 free(check);
236 free(loop);
237 node_free(node->next);
238 node_free(node->bottom);
239 c_label++;
242 void core_push_var(TreeNode *node) {
243 char *name = core_translate_var(node->code);
244 char *result = str_printf("%spush %s\n", c_pad, name);
245 free(name);
246 result = str_cat2(result, str_printf("%scall BBCopy\n", c_pad));
247 node_set(node, result);
248 c_stack++;
251 void core_push_bool(TreeNode *node) {
252 node_set(node, str_printf("%scall BB%s\n", c_pad, node->code));
253 c_stack++;
256 void core_push_dec(TreeNode *node) {
257 unsigned char* str;
258 int length;
259 decToBlob(node->code, &str, &length);
260 char *result = str_printf("%spush %d\n", c_pad, length);
261 result = str_cat2(result, str_printf("%scall BBCreate\n", c_pad));
262 int i;
263 for (i = 0; i < length; i++) {
264 result = str_cat2(result, str_printf("%s@eax = %d + 0\n", c_pad, str[i]));
265 if ((i + 1) < length)
266 result = str_cat2(result, str_printf("%seax = eax + 1\n", c_pad));
268 node_set(node, result);
269 free(str);
270 c_stack++;
273 void core_push_hex(TreeNode *node) {
274 unsigned char* str;
275 int length;
276 hexToBlob(node->code, &str, &length);
277 char *result = str_printf("%spush %d\n", c_pad, length);
278 result = str_cat2(result, str_printf("%scall BBCreate\n", c_pad));
279 int i;
280 for (i = 0; i < length; i++) {
281 result = str_cat2(result, str_printf("%s@eax = %d + 0\n", c_pad, str[i]));
282 if ((i + 1) < length)
283 result = str_cat2(result, str_printf("%seax = eax + 1\n", c_pad));
285 node_set(node, result);
286 free(str);
287 c_stack++;
290 void core_push_str(TreeNode *node) {
291 char *str = node->code;
292 char *input = str + 1;
293 char *output = str;
294 int escape = 0;
295 while (input[0] != '"') {
296 if (escape) {
297 switch (input[0]) {
298 case '\\':
299 output[0] = '\\';
300 break;
301 case 'q':
302 output[0] = '"';
303 break;
304 case 'n':
305 output[0] = '\n';
306 break;
307 case 't':
308 output[0] = '\t';
309 break;
310 default:
311 core_error(str_printf("Error: Invalid escape character! (\"%c\")\n", input[0]));
313 escape = 0;
314 output++;
316 else {
317 if (input[0] != '\\') {
318 output[0] = input[0];
319 output++;
321 else
322 escape = 1;
324 input++;
326 if (escape != 0)
327 core_error(strdup("Error: Dangling escape character!\n"));
328 output[0] = '\0';
329 int length = (output - str);
330 char *result = str_printf("%spush %d\n", c_pad, length);
331 result = str_cat2(result, str_printf("%scall BBCreate\n", c_pad));
332 int i;
333 for (i = 0; i < length; i++) {
334 result = str_cat2(result, str_printf("%s@eax = %d + 0\n", c_pad, str[i]));
335 if ((i + 1) < length)
336 result = str_cat2(result, str_printf("%seax = eax + 1\n", c_pad));
338 node_set(node, result);
339 c_stack++;
342 void core_callfn(TreeNode *node) {
343 char *params = strdup("");
344 int c_callargs = 0;
345 TreeNode *iterator = node->bottom->previous;
346 while (iterator != node->bottom) {
347 node_traverse(iterator);
348 params = str_cat(params, iterator->code);
349 c_callargs++;
350 iterator = iterator->previous;
351 node_free(iterator->next);
353 char *name = node->bottom->code;
354 char *result = params;
355 if (strcmp(name, "get_chr") == 0) {
356 if (c_callargs != 0)
357 core_error(str_printf("Error: get_chr should have 0 parameters! (has %d)\n", c_callargs));
358 result = str_cat2(result, str_printf("%scall BBgetchr\n", c_pad));
360 else if (strcmp(name, "get_int") == 0) {
361 if (c_callargs != 0)
362 core_error(str_printf("Error: get_int should have 0 parameters! (has %d)\n", c_callargs));
363 result = str_cat2(result, str_printf("%scall BBgetint\n", c_pad));
365 else if (strcmp(name, "out_str") == 0) {
366 if (c_callargs == 0)
367 core_error(strdup("Error: out_str should have at least 1 parameter!\n"));
368 result = str_cat2(result, str_printf("%scall BBoutstr\n", c_pad));
369 result = str_cat2(result, str_printf("%scall BBFalse\n", c_pad));
371 else {
372 addFunctionCall(name, c_callargs);
373 char *tname = core_translate_name(name);
374 result = str_cat2(result, str_printf("%scall fn%sStart\n", c_pad, tname));
375 free(tname);
377 node_set(node, result);
378 node_free(node->bottom);
379 c_stack -= c_callargs - 1;
382 void core_call_args(TreeNode *node) {
383 node_traverse(node->bottom);
384 node_set(node, strdup(node->bottom->code));
385 node_free(node->bottom);
388 void core_void_return(TreeNode *node) {
389 node_traverse(node->bottom);
390 char *result = strdup(node->bottom->code);
391 result = str_cat2(result, str_printf("%scall BDestroy\n", c_pad));
392 node_set(node, result);
393 node_free(node->bottom);
394 c_stack--;
397 void core_arit_binary(TreeNode *node) {
398 node_traverse(node->bottom);
399 node_traverse(node->bottom->next);
400 char *result = strdup(node->bottom->code);
401 result = str_cat(result, node->bottom->next->code);
402 result = str_cat2(result, str_printf("%scall BB%s\n", c_pad, node->code));
403 node_set(node, result);
404 node_free(node->bottom->next);
405 node_free(node->bottom);
406 c_stack--;
409 void core_arit_unary(TreeNode *node) {
410 node_traverse(node->bottom);
411 char *result = strdup(node->bottom->code);
412 result = str_cat2(result, str_printf("%scall BB%s\n", c_pad, node->code));
413 node_set(node, result);
414 node_free(node->bottom);
417 void core_set_variable(TreeNode *node) {
418 node_traverse(node->bottom);
419 char *blob = core_translate_var(node->bottom->next->code);
420 char *result = strdup(node->bottom->code);
421 result = str_cat2(result, str_printf("%seax = %s + 0\n", c_pad, blob));
422 result = str_cat2(result, str_printf("%scall BDestroyR\n", c_pad));
423 result = str_cat2(result, str_printf("%stop %s\n", c_pad, blob));
424 result = str_cat2(result, str_printf("%spop\n", c_pad));
425 node_set(node, result);
426 free(blob);
427 node_free(node->bottom->next);
428 node_free(node->bottom);
429 c_stack--;
432 void core_get_length(TreeNode *node) {
433 node_traverse(node->bottom);
434 char *result = strdup(node->bottom->code);
435 result = str_cat2(result, str_printf("%scall BBGetLength\n", c_pad));
436 node_set(node, result);
437 node_free(node->bottom);
440 void core_set_length(TreeNode *node) {
441 node_traverse(node->bottom);
442 char *blob = core_translate_var(node->bottom->next->code);
443 char *result = strdup(node->bottom->code);
444 result = str_cat2(result, str_printf("%spush %s\n", c_pad, blob));
445 result = str_cat2(result, str_printf("%scall BBSetLength\n", c_pad));
446 result = str_cat2(result, str_printf("%stop %s\n", c_pad, blob));
447 result = str_cat2(result, str_printf("%spop\n", c_pad));
448 node_set(node, result);
449 free(blob);
450 node_free(node->bottom->next);
451 node_free(node->bottom);
452 c_stack--;
455 void core_get_element(TreeNode *node) {
456 node_traverse(node->bottom);
457 node_traverse(node->bottom->next);
458 char *result = strdup(node->bottom->code);
459 result = str_cat(result, node->bottom->next->code);
460 result = str_cat2(result, str_printf("%scall BBGetElement\n", c_pad));
461 node_set(node, result);
462 node_free(node->bottom->next);
463 node_free(node->bottom);
464 c_stack--;
467 void core_set_element(TreeNode *node) {
468 node_traverse(node->bottom);
469 node_traverse(node->bottom->next);
470 char *blob = core_translate_var(node->bottom->next->next->code);
471 char *result = strdup(node->bottom->code);
472 result = str_cat(result, node->bottom->next->code);
473 result = str_cat2(result, str_printf("%spush %s\n", c_pad, blob));
474 result = str_cat2(result, str_printf("%scall BBSetElement\n", c_pad));
475 result = str_cat2(result, str_printf("%stop %s\n", c_pad, blob));
476 result = str_cat2(result, str_printf("%spop\n", c_pad));
477 node_set(node, result);
478 free(blob);
479 node_free(node->bottom->next->next);
480 node_free(node->bottom->next);
481 node_free(node->bottom);
482 c_stack -= 2;
485 void core_line(TreeNode *node) {
486 node_traverse(node->bottom);
487 node_set(node, strdup(node->bottom->code));
488 node_free(node->bottom);
491 void core_codeblock(TreeNode *node) {
492 TreeNode *iterator = node->bottom;
493 TreeNode *last = iterator->previous;
494 node_traverse(iterator);
495 char *result = strdup(iterator->code);
496 while (iterator != last) {
497 iterator = iterator->next;
498 node_free(iterator->previous);
499 node_traverse(iterator);
500 result = str_cat(result, iterator->code);
502 node_set(node, result);
503 node_free(iterator);
506 void core_initialize() {
507 c_error = strdup("");
508 core_pad_reset();
509 root = node_new();
510 node_bottom(root, node_new());
511 nodefunc[NODE_EMPTY] = core_empty;
512 nodefunc[NODE_ROOT] = NULL;
513 nodefunc[NODE_FUNCTION] = core_function;
514 nodefunc[NODE_FUNC_ARGS] = core_func_args;
515 nodefunc[NODE_RETURN] = core_return;
516 nodefunc[NODE_IF] = core_if;
517 nodefunc[NODE_WHILE] = core_while;
518 nodefunc[NODE_PUSH_VAR] = core_push_var;
519 nodefunc[NODE_PUSH_BOOL] = core_push_bool;
520 nodefunc[NODE_PUSH_DEC] = core_push_dec;
521 nodefunc[NODE_PUSH_HEX] = core_push_hex;
522 nodefunc[NODE_PUSH_STR] = core_push_str;
523 nodefunc[NODE_CALLFN] = core_callfn;
524 nodefunc[NODE_CALL_ARGS] = core_call_args;
525 nodefunc[NODE_VOID_RETURN] = core_void_return;
526 nodefunc[NODE_ARIT_BINARY] = core_arit_binary;
527 nodefunc[NODE_ARIT_UNARY] = core_arit_unary;
528 nodefunc[NODE_SET_VARIABLE] = core_set_variable;
529 nodefunc[NODE_GET_LENGTH] = core_get_length;
530 nodefunc[NODE_SET_LENGTH] = core_set_length;
531 nodefunc[NODE_GET_ELEMENT] = core_get_element;
532 nodefunc[NODE_SET_ELEMENT] = core_set_element;
533 nodefunc[NODE_LINE] = core_line;
534 nodefunc[NODE_CODEBLOCK] = core_codeblock;
535 addFunction("get_chr", 0);
536 addFunction("get_int", 0);
537 addFunction("out_str", 0);
540 void core_finalize() {
541 clearLocals();
542 clearGlobals();
543 clearFunctions();
546 void root_output() {
547 asm_print(c_output);
548 TreeNode *iterator = root;
549 TreeNode *last = root->previous;
550 node_traverse(iterator->bottom);
551 node_free(iterator->bottom);
552 while (iterator != last) {
553 iterator = iterator->next;
554 node_free(iterator->previous);
555 node_traverse(iterator->bottom);
556 node_free(iterator->bottom);
558 node_free(iterator);
559 int bob = varFunction("BoB");
560 if (bob == -1)
561 core_error(strdup("Error: Function BoB() not defined!\n"));
562 if (bob > 0) {
563 char *msg = strdup("Error: BoB() should have 0 parameters!");
564 msg = str_cat2(msg, str_printf(" (has %d)\n", bob));
565 core_error(msg);
567 char **names;
568 int count, i;
569 varInvalidFunctionCalls(&names, &count);
570 for (i = 0; i < count; i++) {
571 core_error(str_printf("Error: Incorrect call to function \"%s\"!\n", names[i]));
573 i = 0;
574 char *global = varGlobalNo(i);
575 fputs("BoBInit:\n", c_output);
576 while (global != NULL) {
577 fputs(" call BBFalse\n", c_output);
578 fprintf(c_output, " top %s\n", global);
579 fputs(" pop\n", c_output);
580 i++;
581 global = varGlobalNo(i);
583 fputs(" call fnBoBStart\n", c_output);
584 fputs(c_error, stderr);
585 free(c_error);