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 15:25:02 +00:00
|
|
|
case NODE_LT: {
|
|
|
|
compiler_compile(self, node->children.data[0], prog);
|
|
|
|
compiler_compile(self, node->children.data[1], prog);
|
|
|
|
prog_add_instr(prog, OP_LT, CCM_NO_PARAM);
|
|
|
|
} break;
|
|
|
|
|
|
|
|
case NODE_LE: {
|
|
|
|
compiler_compile(self, node->children.data[0], prog);
|
|
|
|
compiler_compile(self, node->children.data[1], prog);
|
|
|
|
prog_add_instr(prog, OP_GT, CCM_NO_PARAM);
|
|
|
|
prog_add_instr(prog, OP_NOT, CCM_NO_PARAM);
|
|
|
|
} break;
|
|
|
|
|
|
|
|
case NODE_GT: {
|
|
|
|
compiler_compile(self, node->children.data[0], prog);
|
|
|
|
compiler_compile(self, node->children.data[1], prog);
|
|
|
|
prog_add_instr(prog, OP_GT, CCM_NO_PARAM);
|
|
|
|
} break;
|
|
|
|
|
|
|
|
case NODE_GE: {
|
|
|
|
compiler_compile(self, node->children.data[0], prog);
|
|
|
|
compiler_compile(self, node->children.data[1], prog);
|
|
|
|
prog_add_instr(prog, OP_LT, CCM_NO_PARAM);
|
|
|
|
prog_add_instr(prog, OP_NOT, CCM_NO_PARAM);
|
|
|
|
} break;
|
|
|
|
|
|
|
|
case NODE_EQ: {
|
|
|
|
compiler_compile(self, node->children.data[0], prog);
|
|
|
|
compiler_compile(self, node->children.data[1], prog);
|
|
|
|
prog_add_instr(prog, OP_EQ, CCM_NO_PARAM);
|
|
|
|
} break;
|
|
|
|
|
|
|
|
case NODE_NE: {
|
|
|
|
compiler_compile(self, node->children.data[0], prog);
|
|
|
|
compiler_compile(self, node->children.data[1], prog);
|
|
|
|
prog_add_instr(prog, OP_EQ, CCM_NO_PARAM);
|
|
|
|
prog_add_instr(prog, OP_NOT, CCM_NO_PARAM);
|
|
|
|
} break;
|
|
|
|
|
2024-03-19 07:56:41 +00:00
|
|
|
case NODE_INDEX: {
|
|
|
|
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_INDEX, node->children.size - 1);
|
|
|
|
} break;
|
|
|
|
|
|
|
|
case NODE_IN: {
|
|
|
|
compiler_compile(self, node->children.data[0], prog);
|
|
|
|
compiler_compile(self, node->children.data[1], prog);
|
|
|
|
|
|
|
|
prog_add_instr(prog, OP_IN, CCM_NO_PARAM);
|
|
|
|
} break;
|
|
|
|
|
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;
|
|
|
|
|
2024-03-19 13:23:11 +00:00
|
|
|
case NODE_STR: {
|
|
|
|
size_t id = prog_add_new_constant(
|
|
|
|
prog,
|
|
|
|
ccm_to_str(&self->module->ccm,
|
|
|
|
node->value,
|
|
|
|
node->line)
|
|
|
|
);
|
|
|
|
|
|
|
|
prog_add_instr(prog, OP_PUSH, id);
|
|
|
|
} break;
|
|
|
|
|
2024-03-18 17:20:40 +00:00
|
|
|
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(
|
2024-03-19 07:56:41 +00:00
|
|
|
prog,
|
|
|
|
OP_PUSH,
|
2024-03-19 06:11:28 +00:00
|
|
|
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);
|
|
|
|
}
|