roza/lib/compiler.c

388 lines
10 KiB
C
Raw Normal View History

2023-12-09 17:24:41 +00:00
#include "compiler.h"
#include "lib/commons.h"
2023-12-16 18:12:20 +00:00
#include "lib/mod.h"
#include "node.h"
2023-12-09 17:24:41 +00:00
void compiler_init(compiler_t* compiler,
mod_t* mod,
sym_t* sym,
tysy_t* tysy,
err_t* err)
2023-12-09 17:24:41 +00:00
{
assert(compiler);
assert(sym);
assert(tysy);
2023-12-09 17:24:41 +00:00
assert(err);
compiler->mod = mod;
compiler->sym = sym;
2023-12-09 17:24:41 +00:00
compiler->tysy = tysy;
compiler->err = err;
compiler->scope = 0;
2023-12-09 17:24:41 +00:00
}
void compiler_free(compiler_t* compiler)
{
assert(compiler);
}
int compiler_run(compiler_t* compiler, node_t* node)
2023-12-09 17:24:41 +00:00
{
assert(compiler);
assert(node);
switch (node->type)
{
case NODE_MOD: {
for (size_t i=0; i<node->children.size; i++)
{
compiler_run(compiler, (node_t*) node->children.data[i]);
}
} break;
case NODE_NUM: {
double value = atof(node->value.data);
2023-12-11 17:01:22 +00:00
value_t* val = tysy_new_num(compiler->tysy, value, node->line);
2023-12-09 17:24:41 +00:00
Opcode op = OP_PUSH;
param_t param = (param_t) mod_push_new_value(compiler->mod, val);
mod_push_instr(compiler->mod, op, param);
} break;
2023-12-09 21:59:24 +00:00
case NODE_BOOL: {
int value = strcmp(node->value.data, "true") == 0;
2023-12-11 17:01:22 +00:00
value_t* val = tysy_new_bool(compiler->tysy, value, node->line);
2023-12-09 21:59:24 +00:00
Opcode op = OP_PUSH;
param_t param = (param_t) mod_push_new_value(compiler->mod, val);
mod_push_instr(compiler->mod, op, param);
} break;
2023-12-10 03:49:28 +00:00
case NODE_STR: {
char* value = node->value.data;
2023-12-11 17:01:22 +00:00
value_t* val = tysy_new_str(compiler->tysy, value, node->line);
2023-12-10 03:49:28 +00:00
Opcode op = OP_PUSH;
param_t param = (param_t) mod_push_new_value(compiler->mod, val);
mod_push_instr(compiler->mod, op, param);
} break;
2023-12-11 17:01:22 +00:00
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; i<node->children.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;
2023-12-15 20:32:17 +00:00
case NODE_LT:
case NODE_LE:
case NODE_GT:
2023-12-15 21:31:01 +00:00
case NODE_GE: {
2023-12-15 20:32:17 +00:00
assert(node->children.size == 2);
for (size_t i=0; i<node->children.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;
2023-12-15 21:31:01 +00:00
case NODE_ADD:
case NODE_SUB:
case NODE_MUL:
case NODE_DIV:
case NODE_MODULO:
case NODE_POW: {
for (size_t i=0; i<node->children.size; i++)
{
compiler_run(compiler, node_child(node, i));
}
Opcode op;
if (node->type == NODE_SUB
&& node->children.size == 1)
{
op = OP_USUB;
}
2023-12-16 18:42:26 +00:00
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;
}
2023-12-15 21:31:01 +00:00
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;
2023-12-16 18:12:20 +00:00
case NODE_AND: {
size_t const SZ = 512;
size_t to_false[SZ];
size_t sz = 0;
for (size_t i=0; i<node->children.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; i<sz; i++)
{
compiler->mod->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; i<node->children.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; i<sz; i++)
{
compiler->mod->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;
node_t* block = node_try_find_parent(node, NODE_BLOCK);
sym_entry_t* entry = NULL;
entry = sym_try_find_by_name(compiler->sym, name,
compiler->scope,
SYM_PRE,
block);
if (!entry)
{
entry = sym_try_find_by_name(compiler->sym, name,
compiler->scope,
SYM_DECL,
block);
}
assert(entry);
entry->state = SYM_DECL;
int id = entry->id;
compiler_run(compiler, (node_t*) node->children.data[1]);
mod_push_instr(compiler->mod, OP_STORE, id);
} break;
case NODE_VARSET: {
char* name = ((node_t*) node->children.data[0])->value.data;
node_t* block = node_try_find_parent(node, NODE_BLOCK);
sym_entry_t* entry = sym_try_find_by_name(compiler->sym, name,
compiler->scope,
SYM_DECL,
block);
if (!entry)
{
char msg[RZ_STR_LIMIT];
snprintf(msg, RZ_STR_LIMIT,
"cannot assign value"
" to undefined variable '%s'.", name);
err_fatal(compiler->err, msg, node->line);
}
else
{
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;
node_t* block = node_try_find_parent(node, NODE_BLOCK);
sym_entry_t* entry = sym_try_find_by_name(compiler->sym, name,
compiler->scope,
SYM_DECL,
block);
if (!entry)
{
char msg[RZ_STR_LIMIT];
snprintf(msg, RZ_STR_LIMIT, "undefined variable '%s'.",
name);
err_fatal(compiler->err, msg, node->line);
return -1;
}
else
{
int id = entry->id;
mod_push_instr(compiler->mod, OP_LOAD, id);
}
} break;
2023-12-18 18:34:31 +00:00
case NODE_SCOPE: {
compiler_run(compiler, (node_t*) node->children.data[0]);
} break;
case NODE_BLOCK: {
compiler->scope++;
for (size_t i=0; i<node->children.size; i++)
{
compiler_run(compiler, (node_t*) node->children.data[i]);
}
compiler->scope--;
} break;
2023-12-18 18:34:31 +00:00
case NODE_IF: {
size_t const IF_LIMIT = 1024;
int end_points[IF_LIMIT];
size_t size = 0;
compiler_run_if(compiler, node, end_points, &size);
assert(size < IF_LIMIT);
for (size_t i=0; i<size; i++)
{
compiler->mod->program.params[end_points[i]]
= compiler->mod->program.size;
}
} break;
2023-12-09 17:24:41 +00:00
default: {
2023-12-11 17:01:22 +00:00
fprintf(stderr, "Cannot compile unknown node '%s'",
NodeTypeStr[node->type]);
abort();
2023-12-09 17:24:41 +00:00
} break;
}
return 0;
2023-12-09 17:24:41 +00:00
}
2023-12-18 18:34:31 +00:00
void compiler_run_if(compiler_t* compiler, node_t* node,
int* end_points, size_t* sz)
{
assert(compiler);
assert(node);
// if
compiler_run(compiler, (node_t*) node->children.data[0]);
// if false goto next
int to_next = mod_push_instr(compiler->mod, OP_BRF, RZ_NO_PARAM);
// then
compiler_run(compiler, (node_t*) node->children.data[1]);
// goto end
int to_end = mod_push_instr(compiler->mod, OP_BR, RZ_NO_PARAM);
end_points[*sz] = to_end;
(*sz)++;
compiler->mod->program.params[to_next]
= compiler->mod->program.size;
if (node->children.size >= 3)
{
node_t* next = (node_t*) node->children.data[2];
if (next->type == NODE_BLOCK)
{
compiler_run(compiler, next);
}
else if (next->type == NODE_IF)
{
compiler_run_if(compiler, next, end_points, sz);
}
}
}