#include "compiler.h" #include "lib/commons.h" #include "lib/mod.h" #include "node.h" void compiler_init(compiler_t* compiler, mod_t* mod, sym_t* sym, tysy_t* tysy, err_t* err) { assert(compiler); assert(sym); assert(tysy); assert(err); compiler->mod = mod; compiler->sym = sym; compiler->tysy = tysy; compiler->err = err; } void compiler_free(compiler_t* compiler) { assert(compiler); } int compiler_run(compiler_t* compiler, node_t* node) { assert(compiler); assert(node); switch (node->type) { case NODE_MOD: { for (size_t i=0; ichildren.size; i++) { compiler_run(compiler, (node_t*) node->children.data[i]); } } break; case NODE_NUM: { double value = atof(node->value.data); value_t* val = tysy_new_num(compiler->tysy, value, node->line); Opcode op = OP_PUSH; param_t param = (param_t) mod_push_new_value(compiler->mod, val); mod_push_instr(compiler->mod, op, param); } break; case NODE_BOOL: { int value = strcmp(node->value.data, "true") == 0; value_t* val = tysy_new_bool(compiler->tysy, value, node->line); Opcode op = OP_PUSH; param_t param = (param_t) mod_push_new_value(compiler->mod, val); mod_push_instr(compiler->mod, op, param); } break; case NODE_STR: { char* value = node->value.data; value_t* val = tysy_new_str(compiler->tysy, value, node->line); Opcode op = OP_PUSH; param_t param = (param_t) mod_push_new_value(compiler->mod, val); mod_push_instr(compiler->mod, op, param); } break; case NODE_ASSERT: { assert(node->children.size == 1); compiler_run(compiler, node_child(node, 0)); mod_push_instr(compiler->mod, OP_ASSERT, RZ_NO_PARAM); } break; case NODE_NE: case NODE_EQ: { assert(node->children.size == 2); for (size_t i=0; ichildren.size; i++) { compiler_run(compiler, node_child(node, i)); } mod_push_instr(compiler->mod, node->type == NODE_EQ ? OP_EQ : OP_NE, RZ_NO_PARAM); } break; case NODE_LT: case NODE_LE: case NODE_GT: case NODE_GE: { assert(node->children.size == 2); for (size_t i=0; ichildren.size; i++) { compiler_run(compiler, node_child(node, i)); } Opcode op; switch (node->type) { case NODE_LT: op = OP_LT; break; case NODE_LE: op = OP_LE; break; case NODE_GT: op = OP_GT; break; case NODE_GE: op = OP_GE; break; default: assert(0); } mod_push_instr(compiler->mod, op, RZ_NO_PARAM); } break; case NODE_ADD: case NODE_SUB: case NODE_MUL: case NODE_DIV: case NODE_MODULO: case NODE_POW: { for (size_t i=0; ichildren.size; i++) { compiler_run(compiler, node_child(node, i)); } Opcode op; if (node->type == NODE_SUB && node->children.size == 1) { op = OP_USUB; } else if (node->type == NODE_ADD && node_find_first(node, NODE_STR)) { op = OP_STRCAT; } else if (node->type == NODE_MUL && node_find_first(node, NODE_STR) && node_find_first(node, NODE_NUM)) { op = OP_STRDUP; } else { switch (node->type) { case NODE_ADD: op = OP_ADD; break; case NODE_SUB: op = OP_SUB; break; case NODE_MUL: op = OP_MUL; break; case NODE_DIV: op = OP_DIV; break; case NODE_MODULO: op = OP_MODULO; break; case NODE_POW: op = OP_POW; break; default: assert(0); } } mod_push_instr(compiler->mod, op, RZ_NO_PARAM); } break; case NODE_AND: { size_t const SZ = 512; size_t to_false[SZ]; size_t sz = 0; for (size_t i=0; ichildren.size; i++) { compiler_run(compiler, node_child(node, i)); size_t addr = mod_push_instr(compiler->mod, OP_BRF, RZ_NO_PARAM); to_false[sz++] = addr; } // True case value_t* t = tysy_new_bool(compiler->tysy, 1, node->line); param_t t_param = mod_push_new_value(compiler->mod, t); mod_push_instr(compiler->mod, OP_PUSH, t_param); size_t to_end = mod_push_instr(compiler->mod, OP_BR, RZ_NO_PARAM); // False case size_t program_sz = compiler->mod->program.size; for (size_t i=0; imod->program.params[to_false[i]] = program_sz; } value_t* f = tysy_new_bool(compiler->tysy, 0, node->line); param_t f_param = mod_push_new_value(compiler->mod, f); mod_push_instr(compiler->mod, OP_PUSH, f_param); compiler->mod->program.params[to_end] = compiler->mod->program.size; } break; case NODE_OR: { size_t const SZ = 512; size_t to_true[SZ]; size_t sz = 0; for (size_t i=0; ichildren.size; i++) { compiler_run(compiler, node_child(node, i)); size_t addr = mod_push_instr(compiler->mod, OP_BRT, RZ_NO_PARAM); to_true[sz++] = addr; } // False case value_t* f = tysy_new_bool(compiler->tysy, 0, node->line); param_t f_param = mod_push_new_value(compiler->mod, f); mod_push_instr(compiler->mod, OP_PUSH, f_param); size_t to_end = mod_push_instr(compiler->mod, OP_BR, RZ_NO_PARAM); // True case size_t program_sz = compiler->mod->program.size; for (size_t i=0; imod->program.params[to_true[i]] = program_sz; } value_t* t = tysy_new_bool(compiler->tysy, 1, node->line); param_t t_param = mod_push_new_value(compiler->mod, t); mod_push_instr(compiler->mod, OP_PUSH, t_param); compiler->mod->program.params[to_end] = compiler->mod->program.size; } break; case NODE_NOT: { assert(node->children.size > 0); compiler_run(compiler, (node_t*) node->children.data[0]); mod_push_instr(compiler->mod, OP_NOT, RZ_NO_PARAM); } break; case NODE_VARDECL: { char* name = ((node_t*) node->children.data[0])->value.data; sym_entry_t* entry = sym_try_find_by_name(compiler->sym, name); assert(entry); int id = entry->id; compiler_run(compiler, (node_t*) node->children.data[1]); mod_push_instr(compiler->mod, OP_STORE, id); } break; case NODE_IDENT: { char* name = node->value.data; sym_entry_t* entry = sym_try_find_by_name(compiler->sym, name); if (!entry) { char msg[RZ_STR_LIMIT]; snprintf(msg, RZ_STR_LIMIT, "%s is undefined.", name); err_fatal(compiler->err, msg, node->line); return -1; } else { int id = entry->id; mod_push_instr(compiler->mod, OP_LOAD, id); } } break; default: { fprintf(stderr, "Cannot compile unknown node '%s'", NodeTypeStr[node->type]); abort(); } break; } return 0; }