#include "compiler.h" void compiler_init(compiler_t* self, module_t* module) { assert(self); err_init(&self->err); self->module = module; } void compiler_free(compiler_t* self) { assert(self); err_free(&self->err); } void compiler_compile(compiler_t* self, node_t* node, prog_t* prog) { assert(self); assert(node); assert(prog); if (!err_is_ok(&self->err)) { return; } ccm_t* ccm = &self->module->ccm; switch (node->kind) { case NODE_AND: { compiler_compile_and(self, node, prog); } break; case NODE_OR: { compiler_compile_or(self, node, prog); } break; case NODE_NOT: { compiler_compile(self, node->children.data[0], prog); prog_add_instr(prog, OP_NOT, CCM_NO_PARAM); } break; case NODE_ASSERT_EQ: { compiler_compile(self, node->children.data[0], prog); prog_add_instr(prog, OP_ASSERT_EQ, CCM_NO_PARAM); } break; case NODE_ASSERT_NE: { compiler_compile(self, node->children.data[0], prog); prog_add_instr(prog, OP_ASSERT_NE, CCM_NO_PARAM); } break; case NODE_MODULE: { for (size_t i=0; ichildren.size; i++) { compiler_compile(self, node->children.data[i], prog); } } break; case NODE_NUM: { size_t id = prog_add_new_constant( prog, ccm_to_num(&self->module->ccm, atof(node->value), node->line) ); prog_add_instr(prog, OP_PUSH, id); } break; case NODE_TUPLE: { for (size_t i=0; ichildren.size; i++) { size_t k = node->children.size - 1 - i; compiler_compile(self, node->children.data[k], prog); } prog_add_instr(prog, OP_MK_TUPLE, node->children.size); } break; case NODE_BOOL: { int val = strcmp(node->value, "true") == 0; CCM value = ccm_to_boolean(ccm, val, node->line); size_t id = prog_add_new_constant(prog, value); prog_add_instr(prog, OP_PUSH, id); } break; case NODE_SUB: { compiler_compile(self, node->children.data[0], prog); if (node->children.size == 2) { compiler_compile(self, node->children.data[1], prog); prog_add_instr(prog, OP_SUB, CCM_NO_PARAM); } else { prog_add_instr(prog, OP_USUB, CCM_NO_PARAM); } } break; case NODE_ADD: case NODE_MUL: case NODE_DIV: case NODE_MOD: case NODE_POW: { compiler_compile(self, node->children.data[0], prog); compiler_compile(self, node->children.data[1], prog); Opcode op; switch (node->kind) { case NODE_ADD: op = OP_ADD; break; case NODE_MUL: op = OP_MUL; break; case NODE_DIV: op = OP_DIV; break; case NODE_MOD: op = OP_MOD; break; case NODE_POW: op = OP_POW; break; default: abort(); } prog_add_instr(prog, op, CCM_NO_PARAM); } break; default: { fprintf(stderr, "cannot compile node %s\n", NodeKindStr[node->kind]); abort(); } } } void compiler_compile_or(compiler_t* self, node_t* node, prog_t* prog) { ccm_t* ccm = &self->module->ccm; vec_t to_true; vec_init(&to_true); for (size_t i=0; ichildren.size; i++) { compiler_compile(self, node->children.data[i], prog); prog_add_instr(prog, OP_NOT, 0); size_t addr = prog_add_instr(prog, OP_BRF, 0); vec_push(&to_true, (void*) addr); } // FALSE prog_add_instr(prog, OP_PUSH, prog_add_new_constant( prog, ccm_to_boolean(ccm, 0, node->line) )); size_t to_end = prog_add_instr(prog, OP_BR, 0); // TRUE size_t true_point = prog->instrs.size; prog_add_instr(prog, OP_PUSH, prog_add_new_constant( prog, ccm_to_boolean(ccm, 1, node->line) )); for (size_t i=0; iinstrs.data[k])->param = true_point; } size_t end_point = prog->instrs.size; ((instr_t*) prog->instrs.data[to_end])->param = end_point; vec_free(&to_true); } void compiler_compile_and(compiler_t* self, node_t* node, prog_t* prog) { ccm_t* ccm = &self->module->ccm; vec_t to_false; vec_init(&to_false); for (size_t i=0; ichildren.size; i++) { compiler_compile(self, node->children.data[i], prog); size_t addr = prog_add_instr(prog, OP_BRF, 0); vec_push(&to_false, (void*) addr); } // TRUE prog_add_instr(prog, OP_PUSH, prog_add_new_constant( prog, ccm_to_boolean(ccm, 1, node->line) )); size_t to_end = prog_add_instr(prog, OP_BR, 0); // FALSE size_t false_point = prog_add_instr( prog, OP_PUSH, prog_add_new_constant( prog, ccm_to_boolean(ccm, 0, node->line) ) ); for (size_t i=0; iinstrs.data[k])->param = false_point; } size_t end_point = prog->instrs.size; ((instr_t*) prog->instrs.data[to_end])->param = end_point; vec_free(&to_false); }