ccm/lib/compiler.c

225 lines
5.9 KiB
C
Raw Normal View History

2024-03-18 17:20:40 +00:00
#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;
}
2024-03-19 06:11:28 +00:00
ccm_t* ccm = &self->module->ccm;
2024-03-18 17:20:40 +00:00
switch (node->kind)
{
2024-03-19 06:11:28 +00:00
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;
2024-03-18 17:20:40 +00:00
case NODE_ASSERT_EQ: {
compiler_compile(self, node->children.data[0], prog);
prog_add_instr(prog, OP_ASSERT_EQ, CCM_NO_PARAM);
} break;
2024-03-19 06:11:28 +00:00
2024-03-18 17:20:40 +00:00
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; i<node->children.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; i<node->children.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;
2024-03-19 06:11:28 +00:00
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;
2024-03-18 17:20:40 +00:00
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();
}
}
}
2024-03-19 06:11:28 +00:00
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; i<node->children.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; i<to_true.size; i++)
{
size_t k = ((size_t) to_true.data[i]);
((instr_t*) prog->instrs.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; i<node->children.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; i<to_false.size; i++)
{
size_t k = ((size_t) to_false.data[i]);
((instr_t*) prog->instrs.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);
}