Compare commits
2 Commits
a27eda5eda
...
968f7a312d
Author | SHA1 | Date |
---|---|---|
bog | 968f7a312d | |
bog | e786b8f756 |
10
doc/roza.bnf
10
doc/roza.bnf
|
@ -2,12 +2,17 @@ MOD ::= EXPR*
|
|||
EXPR ::=
|
||||
| ASSERT
|
||||
| VARDECL
|
||||
| FUNDECL
|
||||
| RETURN
|
||||
| VARSET
|
||||
| SCOPE
|
||||
| IF
|
||||
| OR
|
||||
ASSERT ::= assert EXPR
|
||||
VARDECL ::= let ident assign EXPR
|
||||
FUNDECL ::= fun ident opar PARAMS cpar BLOCK end
|
||||
PARAMS ::= (ident (comma ident)*)?
|
||||
RETURN ::= return EXPR
|
||||
VARSET ::= ident assign EXPR
|
||||
BLOCK ::= EXPR*
|
||||
SCOPE ::= begin BLOCK end
|
||||
|
@ -23,5 +28,8 @@ TERM ::= FACTOR ((add | sub) FACTOR)*
|
|||
FACTOR ::= POWER ((mul | div | mod) POWER)*
|
||||
POWER ::= UNARY (pow UNARY)?
|
||||
UNARY ::= sub? GROUP | not? GROUP
|
||||
GROUP ::= BUILTIN | opar EXPR cpar
|
||||
GROUP ::= LITERAL | opar EXPR cpar
|
||||
LITERAL ::= BUILTIN | FUNCALL
|
||||
FUNCALL ::= ident opar ARGS cpar
|
||||
ARGS ::= (EXPR (comma EXPR)*)?
|
||||
BUILTIN ::= num | bool | str | ident
|
||||
|
|
244
lib/compiler.c
244
lib/compiler.c
|
@ -1,10 +1,14 @@
|
|||
#include "compiler.h"
|
||||
#include "lib/commons.h"
|
||||
#include "lib/mod.h"
|
||||
#include "lib/prepass.h"
|
||||
#include "lib/program.h"
|
||||
#include "lib/sym.h"
|
||||
#include "lib/tysy.h"
|
||||
#include "node.h"
|
||||
#include "fun.h"
|
||||
|
||||
void compiler_init(compiler_t* compiler,
|
||||
mod_t* mod,
|
||||
sym_t* sym,
|
||||
tysy_t* tysy,
|
||||
err_t* err)
|
||||
|
@ -14,7 +18,6 @@ void compiler_init(compiler_t* compiler,
|
|||
assert(tysy);
|
||||
assert(err);
|
||||
|
||||
compiler->mod = mod;
|
||||
compiler->sym = sym;
|
||||
compiler->tysy = tysy;
|
||||
compiler->err = err;
|
||||
|
@ -27,7 +30,7 @@ void compiler_free(compiler_t* compiler)
|
|||
assert(compiler);
|
||||
}
|
||||
|
||||
int compiler_run(compiler_t* compiler, node_t* node)
|
||||
int compiler_run(compiler_t* compiler, node_t* node, program_t* program)
|
||||
{
|
||||
assert(compiler);
|
||||
assert(node);
|
||||
|
@ -37,7 +40,7 @@ int compiler_run(compiler_t* compiler, node_t* node)
|
|||
case NODE_MOD: {
|
||||
for (size_t i=0; i<node->children.size; i++)
|
||||
{
|
||||
compiler_run(compiler, (node_t*) node->children.data[i]);
|
||||
compiler_run(compiler, (node_t*) node->children.data[i], program);
|
||||
}
|
||||
} break;
|
||||
|
||||
|
@ -45,9 +48,10 @@ int compiler_run(compiler_t* compiler, node_t* node)
|
|||
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);
|
||||
param_t param = (param_t) program_push_new_value(program,
|
||||
(struct value*) val);
|
||||
|
||||
mod_push_instr(compiler->mod, op, param);
|
||||
program_push_instr(program, op, param);
|
||||
|
||||
} break;
|
||||
|
||||
|
@ -55,24 +59,26 @@ int compiler_run(compiler_t* compiler, node_t* node)
|
|||
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);
|
||||
param_t param = (param_t) program_push_new_value(program,
|
||||
(struct value*) val);
|
||||
|
||||
mod_push_instr(compiler->mod, op, param);
|
||||
program_push_instr(program, 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);
|
||||
param_t param = (param_t) program_push_new_value(program,
|
||||
(struct value*) val);
|
||||
|
||||
mod_push_instr(compiler->mod, op, param);
|
||||
program_push_instr(program, 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);
|
||||
compiler_run(compiler, node_child(node, 0), program);
|
||||
program_push_instr(program, OP_ASSERT, RZ_NO_PARAM);
|
||||
} break;
|
||||
|
||||
case NODE_NE:
|
||||
|
@ -81,11 +87,11 @@ int compiler_run(compiler_t* compiler, node_t* node)
|
|||
|
||||
for (size_t i=0; i<node->children.size; i++)
|
||||
{
|
||||
compiler_run(compiler, node_child(node, i));
|
||||
compiler_run(compiler, node_child(node, i), program);
|
||||
}
|
||||
|
||||
mod_push_instr(compiler->mod,
|
||||
node->type == NODE_EQ ? OP_EQ : OP_NE, RZ_NO_PARAM);
|
||||
program_push_instr(program,
|
||||
node->type == NODE_EQ ? OP_EQ : OP_NE, RZ_NO_PARAM);
|
||||
} break;
|
||||
|
||||
case NODE_LT:
|
||||
|
@ -96,7 +102,7 @@ int compiler_run(compiler_t* compiler, node_t* node)
|
|||
|
||||
for (size_t i=0; i<node->children.size; i++)
|
||||
{
|
||||
compiler_run(compiler, node_child(node, i));
|
||||
compiler_run(compiler, node_child(node, i), program);
|
||||
}
|
||||
|
||||
Opcode op;
|
||||
|
@ -109,7 +115,7 @@ int compiler_run(compiler_t* compiler, node_t* node)
|
|||
default: assert(0);
|
||||
}
|
||||
|
||||
mod_push_instr(compiler->mod, op, RZ_NO_PARAM);
|
||||
program_push_instr(program, op, RZ_NO_PARAM);
|
||||
|
||||
} break;
|
||||
|
||||
|
@ -121,7 +127,7 @@ int compiler_run(compiler_t* compiler, node_t* node)
|
|||
case NODE_POW: {
|
||||
for (size_t i=0; i<node->children.size; i++)
|
||||
{
|
||||
compiler_run(compiler, node_child(node, i));
|
||||
compiler_run(compiler, node_child(node, i), program);
|
||||
}
|
||||
|
||||
Opcode op;
|
||||
|
@ -156,7 +162,7 @@ int compiler_run(compiler_t* compiler, node_t* node)
|
|||
}
|
||||
}
|
||||
|
||||
mod_push_instr(compiler->mod, op, RZ_NO_PARAM);
|
||||
program_push_instr(program, op, RZ_NO_PARAM);
|
||||
|
||||
} break;
|
||||
|
||||
|
@ -167,29 +173,29 @@ int compiler_run(compiler_t* compiler, node_t* node)
|
|||
|
||||
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);
|
||||
compiler_run(compiler, node_child(node, i), program);
|
||||
size_t addr = program_push_instr(program, 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);
|
||||
param_t t_param = program_push_new_value(program, (struct value*) t);
|
||||
program_push_instr(program, OP_PUSH, t_param);
|
||||
size_t to_end = program_push_instr(program, OP_BR, RZ_NO_PARAM);
|
||||
|
||||
// False case
|
||||
size_t program_sz = compiler->mod->program.size;
|
||||
size_t program_sz = program->size;
|
||||
for (size_t i=0; i<sz; i++)
|
||||
{
|
||||
compiler->mod->program.params[to_false[i]] = program_sz;
|
||||
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);
|
||||
param_t f_param = program_push_new_value(program, (struct value*) f);
|
||||
program_push_instr(program, OP_PUSH, f_param);
|
||||
|
||||
compiler->mod->program.params[to_end] = compiler->mod->program.size;
|
||||
program->params[to_end] = program->size;
|
||||
|
||||
} break;
|
||||
|
||||
|
@ -200,75 +206,81 @@ int compiler_run(compiler_t* compiler, node_t* node)
|
|||
|
||||
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);
|
||||
compiler_run(compiler, node_child(node, i), program);
|
||||
size_t addr = program_push_instr(program, 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);
|
||||
param_t f_param = program_push_new_value(program, (struct value*) f);
|
||||
program_push_instr(program, OP_PUSH, f_param);
|
||||
size_t to_end = program_push_instr(program, OP_BR, RZ_NO_PARAM);
|
||||
|
||||
// True case
|
||||
size_t program_sz = compiler->mod->program.size;
|
||||
size_t program_sz = program->size;
|
||||
for (size_t i=0; i<sz; i++)
|
||||
{
|
||||
compiler->mod->program.params[to_true[i]] = program_sz;
|
||||
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);
|
||||
param_t t_param = program_push_new_value(program, (struct value*) t);
|
||||
program_push_instr(program, OP_PUSH, t_param);
|
||||
|
||||
compiler->mod->program.params[to_end] = compiler->mod->program.size;
|
||||
program->params[to_end] = 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);
|
||||
compiler_run(compiler, (node_t*) node->children.data[0], program);
|
||||
program_push_instr(program, 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);
|
||||
node);
|
||||
|
||||
if (!entry)
|
||||
{
|
||||
entry = sym_try_find_by_name(compiler->sym, name,
|
||||
compiler->scope,
|
||||
SYM_DECL,
|
||||
block);
|
||||
node);
|
||||
|
||||
}
|
||||
|
||||
if (!entry)
|
||||
{
|
||||
char msg[RZ_STR_LIMIT];
|
||||
snprintf(msg, RZ_STR_LIMIT, "unknown entry %s\n", name);
|
||||
err_fatal(compiler->err, msg, node->line);
|
||||
err_dump(compiler->err);
|
||||
}
|
||||
|
||||
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);
|
||||
compiler_run(compiler, (node_t*) node->children.data[1], program);
|
||||
program_push_instr(program, 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);
|
||||
node);
|
||||
|
||||
if (!entry)
|
||||
{
|
||||
|
@ -281,18 +293,18 @@ int compiler_run(compiler_t* compiler, node_t* node)
|
|||
else
|
||||
{
|
||||
int id = entry->id;
|
||||
compiler_run(compiler, (node_t*) node->children.data[1]);
|
||||
mod_push_instr(compiler->mod, OP_STORE, id);
|
||||
compiler_run(compiler, (node_t*) node->children.data[1], program);
|
||||
program_push_instr(program, 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);
|
||||
node);
|
||||
if (!entry)
|
||||
{
|
||||
char msg[RZ_STR_LIMIT];
|
||||
|
@ -305,19 +317,19 @@ int compiler_run(compiler_t* compiler, node_t* node)
|
|||
else
|
||||
{
|
||||
int id = entry->id;
|
||||
mod_push_instr(compiler->mod, OP_LOAD, id);
|
||||
program_push_instr(program, OP_LOAD, id);
|
||||
}
|
||||
} break;
|
||||
|
||||
case NODE_SCOPE: {
|
||||
compiler_run(compiler, (node_t*) node->children.data[0]);
|
||||
compiler_run(compiler, (node_t*) node->children.data[0], program);
|
||||
} 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_run(compiler, (node_t*) node->children.data[i], program);
|
||||
}
|
||||
|
||||
compiler->scope--;
|
||||
|
@ -329,13 +341,112 @@ int compiler_run(compiler_t* compiler, node_t* node)
|
|||
int end_points[IF_LIMIT];
|
||||
size_t size = 0;
|
||||
|
||||
compiler_run_if(compiler, node, end_points, &size);
|
||||
compiler_run_if(compiler, node, program, 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;
|
||||
program->params[end_points[i]] = program->size;
|
||||
}
|
||||
|
||||
} break;
|
||||
|
||||
case NODE_FUNDECL: {
|
||||
char* fun_name = ((node_t*) node->children.data[0])->value.data;
|
||||
|
||||
fun_t* fun = malloc(sizeof(fun_t));
|
||||
fun_init(fun, (struct tysy*) compiler->tysy, compiler->err);
|
||||
|
||||
value_t* value = tysy_new_fun(compiler->tysy, fun, node->line);
|
||||
|
||||
sym_entry_t* entry = sym_try_find_by_name(compiler->sym,
|
||||
fun_name,
|
||||
compiler->scope,
|
||||
SYM_PRE,
|
||||
node);
|
||||
assert(entry);
|
||||
|
||||
entry->state = SYM_DECL;
|
||||
|
||||
// Compile function
|
||||
{
|
||||
compiler_t comp;
|
||||
compiler_init(&comp, (sym_t*) fun->sym,
|
||||
compiler->tysy, compiler->err);
|
||||
|
||||
tysolver_t tysolver;
|
||||
tysolver_init(&tysolver, (sym_t*) fun->sym, compiler->tysy);
|
||||
|
||||
prepass_t pre;
|
||||
prepass_init(&pre, (sym_t*) fun->sym, compiler->tysy,
|
||||
&tysolver, compiler->err);
|
||||
|
||||
prepass_run(&pre, (node_t*) node->children.data[2]);
|
||||
|
||||
// self
|
||||
sym_declare((sym_t*) fun->sym, fun_name,
|
||||
tysy_try_find_type(comp.tysy, "fun"),
|
||||
comp.scope,
|
||||
SYM_DECL,
|
||||
node);
|
||||
|
||||
compiler_run(&comp, (node_t*) node->children.data[1], &fun->program);
|
||||
compiler_run(&comp, (node_t*) node->children.data[2], &fun->program);
|
||||
program_push_instr(&fun->program, OP_RET, RZ_NO_PARAM);
|
||||
|
||||
prepass_free(&pre);
|
||||
tysolver_free(&tysolver);
|
||||
compiler_free(&comp);
|
||||
}
|
||||
|
||||
// value_t* value = tysy_new_fun(compiler->tysy, fun, node->line);
|
||||
param_t param = program_push_new_value(program, (struct value*) value);
|
||||
program_push_instr(program, OP_PUSH, param);
|
||||
|
||||
program_push_instr(program, OP_STORE, entry->id);
|
||||
} break;
|
||||
|
||||
case NODE_PARAMS: {
|
||||
for (size_t i=0; i<node->children.size; i++)
|
||||
{
|
||||
node_t* child = (node_t*) node->children.data[i];
|
||||
char* name = child->value.data;
|
||||
sym_declare(compiler->sym, name, NULL,
|
||||
compiler->scope, SYM_DECL,
|
||||
child);
|
||||
}
|
||||
} break;
|
||||
|
||||
case NODE_RETURN: {
|
||||
compiler_run(compiler, (node_t*) node->children.data[0], program);
|
||||
program_push_instr(program, OP_RET, RZ_NO_PARAM);
|
||||
} break;
|
||||
|
||||
case NODE_FUNCALL: {
|
||||
char* name = ((node_t*) node->children.data[0])->value.data;
|
||||
node_t* args = (node_t*) node->children.data[1];
|
||||
|
||||
for (size_t i=0; i<args->children.size; i++)
|
||||
{
|
||||
compiler_run(compiler, (node_t*)args->children.data[i], program);
|
||||
}
|
||||
|
||||
sym_entry_t* entry = sym_try_find_by_name(compiler->sym,
|
||||
name,
|
||||
compiler->scope,
|
||||
SYM_DECL,
|
||||
node);
|
||||
if (!entry)
|
||||
{
|
||||
char msg[RZ_STR_LIMIT];
|
||||
snprintf(msg, RZ_STR_LIMIT, "undefined function '%s'", name);
|
||||
err_fatal(compiler->err, msg, node->line);
|
||||
}
|
||||
else
|
||||
{
|
||||
int id = entry->id;
|
||||
program_push_instr(program, OP_LOAD, id);
|
||||
program_push_instr(program, OP_CALL, args->children.size);
|
||||
}
|
||||
|
||||
} break;
|
||||
|
@ -350,26 +461,25 @@ int compiler_run(compiler_t* compiler, node_t* node)
|
|||
return 0;
|
||||
}
|
||||
|
||||
void compiler_run_if(compiler_t* compiler, node_t* node,
|
||||
void compiler_run_if(compiler_t* compiler, node_t* node, program_t* program,
|
||||
int* end_points, size_t* sz)
|
||||
{
|
||||
assert(compiler);
|
||||
assert(node);
|
||||
|
||||
// if
|
||||
compiler_run(compiler, (node_t*) node->children.data[0]);
|
||||
compiler_run(compiler, (node_t*) node->children.data[0], program);
|
||||
// if false goto next
|
||||
int to_next = mod_push_instr(compiler->mod, OP_BRF, RZ_NO_PARAM);
|
||||
int to_next = program_push_instr(program, OP_BRF, RZ_NO_PARAM);
|
||||
|
||||
// then
|
||||
compiler_run(compiler, (node_t*) node->children.data[1]);
|
||||
compiler_run(compiler, (node_t*) node->children.data[1], program);
|
||||
// goto end
|
||||
int to_end = mod_push_instr(compiler->mod, OP_BR, RZ_NO_PARAM);
|
||||
int to_end = program_push_instr(program, OP_BR, RZ_NO_PARAM);
|
||||
end_points[*sz] = to_end;
|
||||
(*sz)++;
|
||||
|
||||
compiler->mod->program.params[to_next]
|
||||
= compiler->mod->program.size;
|
||||
program->params[to_next] = program->size;
|
||||
|
||||
if (node->children.size >= 3)
|
||||
{
|
||||
|
@ -377,11 +487,11 @@ void compiler_run_if(compiler_t* compiler, node_t* node,
|
|||
|
||||
if (next->type == NODE_BLOCK)
|
||||
{
|
||||
compiler_run(compiler, next);
|
||||
compiler_run(compiler, next, program);
|
||||
}
|
||||
else if (next->type == NODE_IF)
|
||||
{
|
||||
compiler_run_if(compiler, next, end_points, sz);
|
||||
compiler_run_if(compiler, next, program, end_points, sz);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -9,7 +9,6 @@
|
|||
#include "sym.h"
|
||||
|
||||
typedef struct {
|
||||
mod_t* mod;
|
||||
sym_t* sym;
|
||||
tysy_t* tysy;
|
||||
err_t* err;
|
||||
|
@ -18,15 +17,14 @@ typedef struct {
|
|||
} compiler_t;
|
||||
|
||||
void compiler_init(compiler_t* compiler,
|
||||
mod_t* mod,
|
||||
sym_t* sym,
|
||||
tysy_t* tysy,
|
||||
err_t* err);
|
||||
|
||||
void compiler_free(compiler_t* compiler);
|
||||
|
||||
int compiler_run(compiler_t* compiler, node_t* node);
|
||||
void compiler_run_if(compiler_t* compiler, node_t* node,
|
||||
int compiler_run(compiler_t* compiler, node_t* node, program_t* program);
|
||||
void compiler_run_if(compiler_t* compiler, node_t* node, program_t* program,
|
||||
int* end_points, size_t* sz);
|
||||
|
||||
#endif
|
||||
|
|
|
@ -0,0 +1,19 @@
|
|||
#include "fun.h"
|
||||
#include "sym.h"
|
||||
|
||||
void fun_init(fun_t* fun, struct tysy* tysy, err_t* err)
|
||||
{
|
||||
assert(fun);
|
||||
program_init(&fun->program);
|
||||
fun->sym = malloc(sizeof(sym_t));
|
||||
sym_init((sym_t*) fun->sym, (tysy_t*) tysy, err);
|
||||
}
|
||||
|
||||
void fun_free(fun_t* fun)
|
||||
{
|
||||
assert(fun);
|
||||
program_free(&fun->program);
|
||||
|
||||
sym_free((sym_t*) fun->sym);
|
||||
free(fun->sym);
|
||||
}
|
|
@ -0,0 +1,20 @@
|
|||
#ifndef RZ_FUN_H
|
||||
#define RZ_FUN_H
|
||||
|
||||
#include "commons.h"
|
||||
#include "program.h"
|
||||
#include "err.h"
|
||||
|
||||
struct sym;
|
||||
|
||||
typedef struct {
|
||||
program_t program;
|
||||
struct sym* sym;
|
||||
struct tysy* tysy;
|
||||
} fun_t;
|
||||
|
||||
void fun_init(fun_t* fun, struct tysy* tysy, err_t* err);
|
||||
void fun_free(fun_t* fun);
|
||||
|
||||
|
||||
#endif
|
|
@ -68,9 +68,12 @@ node_t* lexer_try_new_next(lexer_t* lexer)
|
|||
RZ_TEXT("<", NODE_LT, 0);
|
||||
RZ_TEXT(">", NODE_GT, 0);
|
||||
RZ_TEXT("=", NODE_ASSIGN, 0);
|
||||
RZ_TEXT(",", NODE_COMMA, 0);
|
||||
|
||||
// Keywords
|
||||
// ========
|
||||
RZ_KEYWORD("fun", NODE_FUN, 0);
|
||||
RZ_KEYWORD("return", NODE_RETURN, 0);
|
||||
RZ_KEYWORD("if", NODE_IF, 0);
|
||||
RZ_KEYWORD("then", NODE_THEN, 0);
|
||||
RZ_KEYWORD("else", NODE_ELSE, 0);
|
||||
|
@ -422,5 +425,6 @@ int lexer_is_sep(lexer_t* lexer, size_t idx)
|
|||
|| c == '!'
|
||||
|| c == '('
|
||||
|| c == ')'
|
||||
|| c == ','
|
||||
;
|
||||
}
|
||||
|
|
|
@ -108,7 +108,7 @@ int loader_ldfile(loader_t* loader, char const* path, int debug)
|
|||
// prepass
|
||||
{
|
||||
prepass_t prepass;
|
||||
prepass_init(&prepass, &sym, &tysolver, &err);
|
||||
prepass_init(&prepass, &sym, &tysy, &tysolver, &err);
|
||||
prepass_run(&prepass, node);
|
||||
prepass_free(&prepass);
|
||||
}
|
||||
|
@ -116,8 +116,8 @@ int loader_ldfile(loader_t* loader, char const* path, int debug)
|
|||
// compile
|
||||
{
|
||||
compiler_t compiler;
|
||||
compiler_init(&compiler, &mod, &sym, &tysy, &err);
|
||||
int status = compiler_run(&compiler, node);
|
||||
compiler_init(&compiler, &sym, &tysy, &err);
|
||||
int status = compiler_run(&compiler, node, &mod.program);
|
||||
|
||||
if (status != 0)
|
||||
{
|
||||
|
|
106
lib/mod.c
106
lib/mod.c
|
@ -5,116 +5,16 @@ void mod_init(mod_t* mod)
|
|||
{
|
||||
assert(mod);
|
||||
|
||||
mod->program.size = 0;
|
||||
mod->program.cap = 0;
|
||||
mod->program.ops = NULL;
|
||||
mod->program.params = NULL;
|
||||
|
||||
mod->values.size = 0;
|
||||
mod->values.cap = 0;
|
||||
mod->values.data = NULL;
|
||||
program_init(&mod->program);
|
||||
}
|
||||
|
||||
void mod_free(mod_t* mod)
|
||||
{
|
||||
assert(mod);
|
||||
free(mod->program.ops);
|
||||
free(mod->program.params);
|
||||
mod->program.size = 0;
|
||||
mod->program.cap = 0;
|
||||
|
||||
for (size_t i=0; i<mod->values.size; i++)
|
||||
{
|
||||
value_free(mod->values.data[i]);
|
||||
free(mod->values.data[i]);
|
||||
}
|
||||
|
||||
free(mod->values.data);
|
||||
mod->values.data = NULL;
|
||||
mod->values.size = 0;
|
||||
mod->values.cap = 0;
|
||||
}
|
||||
|
||||
size_t mod_push_instr(mod_t* mod, Opcode op, param_t param)
|
||||
{
|
||||
assert(mod);
|
||||
|
||||
if (mod->program.cap == 0)
|
||||
{
|
||||
mod->program.cap = 2;
|
||||
mod->program.ops = malloc(sizeof(Opcode) * mod->program.cap);
|
||||
mod->program.params = malloc(sizeof(param_t) * mod->program.cap);
|
||||
}
|
||||
|
||||
if (mod->program.size >= mod->program.cap)
|
||||
{
|
||||
mod->program.cap *= 2;
|
||||
mod->program.ops = realloc(mod->program.ops,
|
||||
sizeof(Opcode) * mod->program.cap);
|
||||
mod->program.params = realloc(mod->program.params,
|
||||
sizeof(param_t) * mod->program.cap);
|
||||
}
|
||||
|
||||
mod->program.ops[mod->program.size] = op;
|
||||
mod->program.params[mod->program.size] = param;
|
||||
mod->program.size++;
|
||||
|
||||
return mod->program.size - 1;
|
||||
program_free(&mod->program);
|
||||
}
|
||||
|
||||
size_t mod_str(mod_t* mod, char* buffer, size_t size)
|
||||
{
|
||||
size_t sz = 0;
|
||||
|
||||
sz += snprintf(buffer + sz, size - sz, "======== VALUES ========\n");
|
||||
for (size_t i=0; i<mod->values.size; i++)
|
||||
{
|
||||
sz += snprintf(buffer + sz, size - sz, "%d| ", (int) i);
|
||||
sz += value_str(mod->values.data[i], buffer + sz, size - sz);
|
||||
sz += snprintf(buffer + sz, size - sz, "\n");
|
||||
}
|
||||
|
||||
sz += snprintf(buffer + sz, size - sz, "\n======== PROGRAM ========\n");
|
||||
for (size_t i=0; i<mod->program.size; i++)
|
||||
{
|
||||
if (mod->program.params[i] != RZ_NO_PARAM)
|
||||
{
|
||||
sz += snprintf(buffer + sz, size - sz, "%d| %s %d\n",
|
||||
(int) i,
|
||||
OpcodeStr[mod->program.ops[i]] + strlen("OP_"),
|
||||
mod->program.params[i]);
|
||||
}
|
||||
else
|
||||
{
|
||||
sz += snprintf(buffer + sz, size - sz, "%d| %s\n",
|
||||
(int) i,
|
||||
OpcodeStr[mod->program.ops[i]] + strlen("OP_"));
|
||||
}
|
||||
}
|
||||
|
||||
return sz;
|
||||
}
|
||||
|
||||
size_t mod_push_new_value(mod_t* mod, value_t* value)
|
||||
{
|
||||
assert(mod);
|
||||
assert(value);
|
||||
|
||||
if (mod->values.size == 0)
|
||||
{
|
||||
mod->values.cap = 2;
|
||||
mod->values.data = malloc(sizeof(value_t*) * mod->values.cap);
|
||||
}
|
||||
|
||||
if (mod->values.size >= mod->values.cap)
|
||||
{
|
||||
mod->values.cap *= 2;
|
||||
mod->values.data = realloc(mod->values.data,
|
||||
sizeof(value_t*) * mod->values.cap);
|
||||
}
|
||||
|
||||
mod->values.data[mod->values.size] = value;
|
||||
mod->values.size++;
|
||||
|
||||
return mod->values.size - 1;
|
||||
return program_str(&mod->program, buffer, size);
|
||||
}
|
||||
|
|
17
lib/mod.h
17
lib/mod.h
|
@ -4,28 +4,15 @@
|
|||
#include "commons.h"
|
||||
#include "opcodes.h"
|
||||
#include "value.h"
|
||||
#include "program.h"
|
||||
|
||||
typedef struct {
|
||||
struct {
|
||||
size_t size;
|
||||
size_t cap;
|
||||
Opcode* ops;
|
||||
param_t* params;
|
||||
} program;
|
||||
|
||||
struct {
|
||||
size_t size;
|
||||
size_t cap;
|
||||
value_t** data;
|
||||
} values;
|
||||
program_t program;
|
||||
} mod_t;
|
||||
|
||||
void mod_init(mod_t* mod);
|
||||
void mod_free(mod_t* mod);
|
||||
|
||||
size_t mod_push_instr(mod_t* mod, Opcode op, param_t param);
|
||||
size_t mod_str(mod_t* mod, char* buffer, size_t size);
|
||||
|
||||
size_t mod_push_new_value(mod_t* mod, value_t* value);
|
||||
|
||||
#endif
|
||||
|
|
|
@ -14,7 +14,9 @@
|
|||
G(NODE_AND), G(NODE_OR), G(NODE_NOT), \
|
||||
G(NODE_LET), G(NODE_IDENT), G(NODE_ASSIGN), G(NODE_VARDECL), \
|
||||
G(NODE_VARSET), G(NODE_BEGIN), G(NODE_END), G(NODE_BLOCK), \
|
||||
G(NODE_SCOPE), G(NODE_IF), G(NODE_THEN), G(NODE_ELSE)
|
||||
G(NODE_SCOPE), G(NODE_IF), G(NODE_THEN), G(NODE_ELSE), \
|
||||
G(NODE_FUNDECL), G(NODE_FUN), G(NODE_RETURN), G(NODE_COMMA), \
|
||||
G(NODE_PARAMS), G(NODE_FUNCALL), G(NODE_ARGS)
|
||||
|
||||
RZ_ENUM_H(NodeType, NODE_TYPE);
|
||||
|
||||
|
|
|
@ -13,7 +13,8 @@
|
|||
G(OP_NOT), \
|
||||
G(OP_BRF), G(OP_BRT), G(OP_BR), \
|
||||
G(OP_STRCAT), G(OP_STRDUP), \
|
||||
G(OP_LOAD), G(OP_STORE)
|
||||
G(OP_LOAD), G(OP_STORE), \
|
||||
G(OP_CALL), G(OP_RET)
|
||||
|
||||
|
||||
RZ_ENUM_H(Opcode, OPCODES);
|
||||
|
|
128
lib/parser.c
128
lib/parser.c
|
@ -79,6 +79,16 @@ node_t* parser_try_new_expr(parser_t* parser)
|
|||
return parser_try_new_vardecl(parser);
|
||||
}
|
||||
|
||||
if (type_1 == NODE_FUN)
|
||||
{
|
||||
return parser_try_new_fundecl(parser);
|
||||
}
|
||||
|
||||
if (type_1 == NODE_RETURN)
|
||||
{
|
||||
return parser_try_new_return(parser);
|
||||
}
|
||||
|
||||
if (type_1 == NODE_BEGIN)
|
||||
{
|
||||
return parser_try_new_scope(parser);
|
||||
|
@ -118,6 +128,66 @@ node_t* parser_try_new_vardecl(parser_t* parser)
|
|||
return node;
|
||||
}
|
||||
|
||||
node_t* parser_try_new_fundecl(parser_t* parser)
|
||||
{
|
||||
assert(parser);
|
||||
node_t* node = malloc(sizeof(node_t));
|
||||
node_init(node, NODE_FUNDECL, "", parser->lexer->line);
|
||||
|
||||
parser_skip(parser, NODE_FUN);
|
||||
node_t* ident = parser_try_new_consume(parser, NODE_IDENT);
|
||||
node_add_new_child(node, ident);
|
||||
|
||||
parser_skip(parser, NODE_OPAR);
|
||||
node_add_new_child(node, parser_try_new_params(parser));
|
||||
parser_skip(parser, NODE_CPAR);
|
||||
|
||||
node_add_new_child(node, parser_try_new_block(parser));
|
||||
parser_skip(parser, NODE_END);
|
||||
|
||||
return node;
|
||||
}
|
||||
|
||||
node_t* parser_try_new_params(parser_t* parser)
|
||||
{
|
||||
assert(parser);
|
||||
|
||||
node_t* node = malloc(sizeof(node_t));
|
||||
node_init(node, NODE_PARAMS, "", parser->lexer->line);
|
||||
|
||||
int next = lexer_peek(parser->lexer, 1);
|
||||
|
||||
if (next == NODE_CPAR)
|
||||
{
|
||||
return node;
|
||||
}
|
||||
|
||||
node_add_new_child(node, parser_try_new_consume(parser, NODE_IDENT));
|
||||
|
||||
while (1)
|
||||
{
|
||||
int next_1 = lexer_peek(parser->lexer, 1);
|
||||
|
||||
if (next_1 != NODE_COMMA)
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
parser_skip(parser, NODE_COMMA);
|
||||
node_add_new_child(node, parser_try_new_consume(parser, NODE_IDENT));
|
||||
}
|
||||
|
||||
return node;
|
||||
}
|
||||
|
||||
node_t* parser_try_new_return(parser_t* parser)
|
||||
{
|
||||
assert(parser);
|
||||
node_t* node = parser_try_new_consume(parser, NODE_RETURN);
|
||||
node_add_new_child(node, parser_try_new_expr(parser));
|
||||
return node;
|
||||
}
|
||||
|
||||
node_t* parser_try_new_varset(parser_t* parser)
|
||||
{
|
||||
assert(parser);
|
||||
|
@ -425,11 +495,63 @@ node_t* parser_try_new_group(parser_t* parser)
|
|||
return node;
|
||||
}
|
||||
|
||||
node_t* builtin = parser_try_new_builtin(parser);
|
||||
return parser_try_new_literal(parser);
|
||||
}
|
||||
|
||||
assert(builtin);
|
||||
node_t* parser_try_new_literal(parser_t* parser)
|
||||
{
|
||||
assert(parser);
|
||||
|
||||
return builtin;
|
||||
int type_1 = lexer_peek(parser->lexer, 1);
|
||||
int type_2 = lexer_peek(parser->lexer, 2);
|
||||
|
||||
if (type_1 == NODE_IDENT
|
||||
&& type_2 == NODE_OPAR)
|
||||
{
|
||||
return parser_try_new_funcall(parser);
|
||||
}
|
||||
|
||||
return parser_try_new_builtin(parser);
|
||||
}
|
||||
|
||||
node_t* parser_try_new_funcall(parser_t* parser)
|
||||
{
|
||||
assert(parser);
|
||||
|
||||
node_t* node = malloc(sizeof(node_t));
|
||||
node_init(node, NODE_FUNCALL, "", parser->lexer->line);
|
||||
|
||||
node_add_new_child(node, parser_try_new_consume(parser, NODE_IDENT));
|
||||
parser_skip(parser, NODE_OPAR);
|
||||
node_add_new_child(node, parser_try_new_args(parser));
|
||||
parser_skip(parser, NODE_CPAR);
|
||||
|
||||
return node;
|
||||
}
|
||||
|
||||
node_t* parser_try_new_args(parser_t* parser)
|
||||
{
|
||||
assert(parser);
|
||||
node_t* node = malloc(sizeof(node_t));
|
||||
node_init(node, NODE_ARGS, "", parser->lexer->line);
|
||||
|
||||
int next = lexer_peek(parser->lexer, 1);
|
||||
|
||||
if (next == NODE_CPAR)
|
||||
{
|
||||
return node;
|
||||
}
|
||||
|
||||
node_t* arg = parser_try_new_expr(parser);
|
||||
node_add_new_child(node, arg);
|
||||
|
||||
while ((next = lexer_peek(parser->lexer, 1)) == NODE_COMMA)
|
||||
{
|
||||
parser_skip(parser, NODE_COMMA);
|
||||
node_add_new_child(node, parser_try_new_expr(parser));
|
||||
}
|
||||
|
||||
return node;
|
||||
}
|
||||
|
||||
node_t* parser_try_new_builtin(parser_t* parser)
|
||||
|
|
|
@ -18,6 +18,9 @@ node_t* parser_try_new_mod(parser_t* parser);
|
|||
node_t* parser_try_new_expr(parser_t* parser);
|
||||
node_t* parser_try_new_assert(parser_t* parser);
|
||||
node_t* parser_try_new_vardecl(parser_t* parser);
|
||||
node_t* parser_try_new_fundecl(parser_t* parser);
|
||||
node_t* parser_try_new_params(parser_t* parser);
|
||||
node_t* parser_try_new_return(parser_t* parser);
|
||||
node_t* parser_try_new_varset(parser_t* parser);
|
||||
node_t* parser_try_new_block(parser_t* parser);
|
||||
node_t* parser_try_new_scope(parser_t* parser);
|
||||
|
@ -31,6 +34,9 @@ node_t* parser_try_new_factor(parser_t* parser);
|
|||
node_t* parser_try_new_power(parser_t* parser);
|
||||
node_t* parser_try_new_unary(parser_t* parser);
|
||||
node_t* parser_try_new_group(parser_t* parser);
|
||||
node_t* parser_try_new_literal(parser_t* parser);
|
||||
node_t* parser_try_new_funcall(parser_t* parser);
|
||||
node_t* parser_try_new_args(parser_t* parser);
|
||||
node_t* parser_try_new_builtin(parser_t* parser);
|
||||
|
||||
node_t* parser_try_new_consume(parser_t* parser, NodeType type);
|
||||
|
|
|
@ -1,18 +1,22 @@
|
|||
#include "prepass.h"
|
||||
#include "lib/sym.h"
|
||||
#include "lib/tysy.h"
|
||||
#include "node.h"
|
||||
|
||||
void prepass_init(prepass_t* prepass,
|
||||
sym_t* sym,
|
||||
tysy_t* tysy,
|
||||
tysolver_t* tysolver,
|
||||
err_t* err)
|
||||
{
|
||||
assert(prepass);
|
||||
assert(sym);
|
||||
assert(tysy);
|
||||
assert(tysolver);
|
||||
assert(err);
|
||||
|
||||
prepass->sym = sym;
|
||||
prepass->tysy = tysy;
|
||||
prepass->tysolver = tysolver;
|
||||
prepass->err = err;
|
||||
|
||||
|
@ -45,7 +49,6 @@ void prepass_run(prepass_t* prepass, node_t* node)
|
|||
|
||||
case NODE_VARDECL: {
|
||||
char* name = ((node_t*) node->children.data[0])->value.data;
|
||||
node_t* block = node_try_find_parent(node, NODE_BLOCK);
|
||||
|
||||
prepass_run(prepass, (node_t*) node->children.data[1]);
|
||||
|
||||
|
@ -54,10 +57,20 @@ void prepass_run(prepass_t* prepass, node_t* node)
|
|||
|
||||
sym_declare(prepass->sym, name, type,
|
||||
prepass->scope, SYM_PRE,
|
||||
block);
|
||||
node);
|
||||
|
||||
} break;
|
||||
|
||||
case NODE_FUNDECL: {
|
||||
char* name = ((node_t*) node->children.data[0])->value.data;
|
||||
|
||||
sym_declare(prepass->sym, name,
|
||||
tysy_try_find_type(prepass->tysy, "fun"),
|
||||
prepass->scope,
|
||||
SYM_PRE,
|
||||
node);
|
||||
} break;
|
||||
|
||||
default: {
|
||||
for (size_t i=0; i<node->children.size; i++)
|
||||
{
|
||||
|
|
|
@ -6,9 +6,11 @@
|
|||
#include "node.h"
|
||||
#include "sym.h"
|
||||
#include "tysolver.h"
|
||||
#include "tysy.h"
|
||||
|
||||
typedef struct {
|
||||
sym_t* sym;
|
||||
tysy_t* tysy;
|
||||
tysolver_t* tysolver;
|
||||
err_t* err;
|
||||
|
||||
|
@ -18,6 +20,7 @@ typedef struct {
|
|||
|
||||
void prepass_init(prepass_t* prepass,
|
||||
sym_t* sym,
|
||||
tysy_t* tysy,
|
||||
tysolver_t* tysolver,
|
||||
err_t* err);
|
||||
|
||||
|
|
|
@ -0,0 +1,131 @@
|
|||
#include "program.h"
|
||||
#include "value.h"
|
||||
|
||||
void program_init(program_t* program)
|
||||
{
|
||||
assert(program);
|
||||
|
||||
program->size = 0;
|
||||
program->cap = 0;
|
||||
program->ops = NULL;
|
||||
program->params = NULL;
|
||||
|
||||
program->values.cap = 0;
|
||||
program->values.size = 0;
|
||||
program->values.data = NULL;
|
||||
}
|
||||
|
||||
void program_free(program_t* program)
|
||||
{
|
||||
assert(program);
|
||||
|
||||
for (size_t i=0; i<program->values.size; i++)
|
||||
{
|
||||
value_free((value_t*) program->values.data[i]);
|
||||
free(program->values.data[i]);
|
||||
program->values.data[i] = NULL;
|
||||
}
|
||||
|
||||
free(program->values.data);
|
||||
program->values.data = NULL;
|
||||
program->values.size = 0;
|
||||
program->values.cap = 0;
|
||||
|
||||
free(program->ops);
|
||||
free(program->params);
|
||||
program->size = 0;
|
||||
program->cap = 0;
|
||||
}
|
||||
|
||||
size_t program_push_instr(program_t* program, Opcode op, param_t param)
|
||||
{
|
||||
assert(program);
|
||||
|
||||
if (program->cap == 0)
|
||||
{
|
||||
program->cap = 2;
|
||||
program->ops = malloc(sizeof(Opcode) * program->cap);
|
||||
program->params = malloc(sizeof(param_t) * program->cap);
|
||||
}
|
||||
|
||||
if (program->size >= program->cap)
|
||||
{
|
||||
program->cap *= 2;
|
||||
program->ops = realloc(program->ops,
|
||||
sizeof(Opcode) * program->cap);
|
||||
program->params = realloc(program->params,
|
||||
sizeof(param_t) * program->cap);
|
||||
}
|
||||
|
||||
program->ops[program->size] = op;
|
||||
program->params[program->size] = param;
|
||||
program->size++;
|
||||
|
||||
return program->size - 1;
|
||||
}
|
||||
|
||||
size_t program_push_new_value(program_t* program, struct value* value)
|
||||
{
|
||||
assert(program);
|
||||
assert(value);
|
||||
|
||||
for (size_t i=0; i<program->values.size; i++)
|
||||
{
|
||||
assert(program->values.data[i] != value);
|
||||
}
|
||||
|
||||
if (program->values.size == 0)
|
||||
{
|
||||
program->values.cap = 2;
|
||||
program->values.data = malloc(sizeof(struct value*)
|
||||
* program->values.cap);
|
||||
}
|
||||
|
||||
if (program->values.size >= program->values.cap)
|
||||
{
|
||||
program->values.cap *= 2;
|
||||
program->values.data = realloc(program->values.data,
|
||||
sizeof(struct value*)
|
||||
* program->values.cap);
|
||||
}
|
||||
|
||||
program->values.data[program->values.size] = value;
|
||||
|
||||
program->values.size++;
|
||||
|
||||
return program->values.size - 1;
|
||||
}
|
||||
|
||||
size_t program_str(program_t* program, char* buffer, size_t size)
|
||||
{
|
||||
size_t sz = 0;
|
||||
|
||||
sz += snprintf(buffer + sz, size - sz, "======== VALUES ========\n");
|
||||
for (size_t i=0; i<program->values.size; i++)
|
||||
{
|
||||
sz += snprintf(buffer + sz, size - sz, "%d| ", (int) i);
|
||||
sz += value_str((value_t*) program->values.data[i],
|
||||
buffer + sz, size - sz);
|
||||
sz += snprintf(buffer + sz, size - sz, "\n");
|
||||
}
|
||||
|
||||
sz += snprintf(buffer + sz, size - sz, "\n======== PROGRAM ========\n");
|
||||
for (size_t i=0; i<program->size; i++)
|
||||
{
|
||||
if (program->params[i] != RZ_NO_PARAM)
|
||||
{
|
||||
sz += snprintf(buffer + sz, size - sz, "%d| %s %d\n",
|
||||
(int) i,
|
||||
OpcodeStr[program->ops[i]] + strlen("OP_"),
|
||||
program->params[i]);
|
||||
}
|
||||
else
|
||||
{
|
||||
sz += snprintf(buffer + sz, size - sz, "%d| %s\n",
|
||||
(int) i,
|
||||
OpcodeStr[program->ops[i]] + strlen("OP_"));
|
||||
}
|
||||
}
|
||||
|
||||
return sz;
|
||||
}
|
|
@ -0,0 +1,31 @@
|
|||
#ifndef RZ_PROGRAM_H
|
||||
#define RZ_PROGRAM_H
|
||||
|
||||
#include "commons.h"
|
||||
#include "opcodes.h"
|
||||
|
||||
struct value;
|
||||
|
||||
typedef struct {
|
||||
size_t size;
|
||||
size_t cap;
|
||||
Opcode* ops;
|
||||
param_t* params;
|
||||
|
||||
struct {
|
||||
size_t size;
|
||||
size_t cap;
|
||||
struct value** data;
|
||||
} values;
|
||||
|
||||
} program_t;
|
||||
|
||||
void program_init(program_t* program);
|
||||
void program_free(program_t* program);
|
||||
|
||||
size_t program_push_instr(program_t* program, Opcode op, param_t param);
|
||||
size_t program_push_new_value(program_t* program, struct value* value);
|
||||
|
||||
size_t program_str(program_t* program, char* buffer, size_t size);
|
||||
|
||||
#endif
|
30
lib/sym.c
30
lib/sym.c
|
@ -1,4 +1,5 @@
|
|||
#include "sym.h"
|
||||
#include "lib/node.h"
|
||||
|
||||
void sym_init(sym_t* sym, tysy_t* tysy, err_t* err)
|
||||
{
|
||||
|
@ -30,7 +31,7 @@ void sym_free(sym_t* sym)
|
|||
}
|
||||
|
||||
int sym_declare(sym_t* sym, char* name, type_t* type,
|
||||
int scope, int state_flag, node_t* block)
|
||||
int scope, int state_flag, node_t* node)
|
||||
{
|
||||
assert(sym);
|
||||
assert(name);
|
||||
|
@ -39,8 +40,18 @@ int sym_declare(sym_t* sym, char* name, type_t* type,
|
|||
name,
|
||||
scope,
|
||||
state_flag,
|
||||
block);
|
||||
if (res && res->block == block)
|
||||
node);
|
||||
|
||||
node_t* block = node_try_find_parent(node, NODE_BLOCK);
|
||||
|
||||
node_t* res_block;
|
||||
|
||||
if (res)
|
||||
{
|
||||
res_block = node_try_find_parent(res->node, NODE_BLOCK);
|
||||
}
|
||||
|
||||
if (res && res_block == block)
|
||||
{
|
||||
return res->id;
|
||||
}
|
||||
|
@ -69,7 +80,7 @@ int sym_declare(sym_t* sym, char* name, type_t* type,
|
|||
sym->entries.data[sym->entries.size]->type = type;
|
||||
sym->entries.data[sym->entries.size]->scope = scope;
|
||||
sym->entries.data[sym->entries.size]->state = state_flag;
|
||||
sym->entries.data[sym->entries.size]->block = block;
|
||||
sym->entries.data[sym->entries.size]->node = node;
|
||||
|
||||
sym->entries.size++;
|
||||
|
||||
|
@ -78,7 +89,7 @@ int sym_declare(sym_t* sym, char* name, type_t* type,
|
|||
|
||||
sym_entry_t* sym_try_find_by_name(sym_t* sym, char* name,
|
||||
int scope, int state_flag,
|
||||
node_t* block)
|
||||
node_t* node)
|
||||
{
|
||||
assert(sym);
|
||||
|
||||
|
@ -88,9 +99,10 @@ sym_entry_t* sym_try_find_by_name(sym_t* sym, char* name,
|
|||
{
|
||||
sym_entry_t* entry = sym->entries.data[i];
|
||||
|
||||
node_t* itr = block;
|
||||
node_t* itr = node_try_find_parent(node, NODE_BLOCK);
|
||||
node_t* entry_block = node_try_find_parent(entry->node, NODE_BLOCK);
|
||||
|
||||
while (itr && itr != entry->block)
|
||||
while (itr && itr != entry_block)
|
||||
{
|
||||
itr = (node_t*) itr->parent;
|
||||
}
|
||||
|
@ -98,7 +110,7 @@ sym_entry_t* sym_try_find_by_name(sym_t* sym, char* name,
|
|||
if (strcmp(entry->name, name) == 0
|
||||
&& entry->scope == scope
|
||||
&& (entry->state & state_flag) != 0
|
||||
&& (entry->block == itr))
|
||||
&& (entry_block == itr))
|
||||
{
|
||||
res = entry;
|
||||
return res;
|
||||
|
@ -107,7 +119,7 @@ sym_entry_t* sym_try_find_by_name(sym_t* sym, char* name,
|
|||
|
||||
if (scope > 0)
|
||||
{
|
||||
return sym_try_find_by_name(sym, name, scope - 1, state_flag, block);
|
||||
return sym_try_find_by_name(sym, name, scope - 1, state_flag, node);
|
||||
}
|
||||
|
||||
return NULL;
|
||||
|
|
|
@ -17,7 +17,7 @@ typedef struct {
|
|||
type_t* type;
|
||||
int scope;
|
||||
sym_state_t state;
|
||||
node_t* block;
|
||||
node_t* node;
|
||||
} sym_entry_t;
|
||||
|
||||
typedef struct {
|
||||
|
@ -37,11 +37,11 @@ void sym_free(sym_t* sym);
|
|||
|
||||
int sym_declare(sym_t* sym, char* name, type_t* type,
|
||||
int scope, int state_flag,
|
||||
node_t* block);
|
||||
node_t* node);
|
||||
|
||||
sym_entry_t* sym_try_find_by_name(sym_t* sym, char* name,
|
||||
int scope, int state_flag,
|
||||
node_t* block);
|
||||
node_t* node);
|
||||
|
||||
size_t sym_str(sym_t* sym, char* buffer, size_t size);
|
||||
|
||||
|
|
|
@ -4,7 +4,8 @@
|
|||
#include "commons.h"
|
||||
|
||||
#define TYPE_KIND(G) \
|
||||
G(TYPE_NUM), G(TYPE_BOOL), G(TYPE_STR)
|
||||
G(TYPE_NUM), G(TYPE_BOOL), G(TYPE_STR), \
|
||||
G(TYPE_FUN)
|
||||
|
||||
RZ_ENUM_H(TypeKind, TYPE_KIND);
|
||||
|
||||
|
|
|
@ -49,15 +49,13 @@ type_t* tysolver_try_solve_node(tysolver_t* tysolver, node_t* node)
|
|||
|
||||
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(tysolver->sym,
|
||||
name,
|
||||
tysolver->scope,
|
||||
SYM_PRE | SYM_DECL,
|
||||
block);
|
||||
assert(entry);
|
||||
|
||||
return entry->type;
|
||||
node);
|
||||
return entry ? entry->type : NULL;
|
||||
} break;
|
||||
|
||||
case NODE_SUB:
|
||||
|
@ -121,10 +119,17 @@ type_t* tysolver_try_solve_node(tysolver_t* tysolver, node_t* node)
|
|||
return ty;
|
||||
} break;
|
||||
|
||||
case NODE_IF: {
|
||||
case NODE_IF:
|
||||
case NODE_FUNCALL: {
|
||||
return NULL;
|
||||
} break;
|
||||
|
||||
case NODE_FUNDECL: {
|
||||
type_t* ty = tysy_try_find_type(tysolver->tysy, "fun");
|
||||
assert(ty);
|
||||
return ty;
|
||||
} break;
|
||||
|
||||
default: {
|
||||
tysolver_error(tysolver, node);
|
||||
} break;
|
||||
|
|
18
lib/tysy.c
18
lib/tysy.c
|
@ -25,6 +25,13 @@ void tysy_init(tysy_t* tysy)
|
|||
type_init(ty, TYPE_STR);
|
||||
tysy_register_new_type(tysy, "str", ty);
|
||||
}
|
||||
|
||||
// fun
|
||||
{
|
||||
type_t* ty = malloc(sizeof(type_t));
|
||||
type_init(ty, TYPE_FUN);
|
||||
tysy_register_new_type(tysy, "fun", ty);
|
||||
}
|
||||
}
|
||||
|
||||
void tysy_free(tysy_t* tysy)
|
||||
|
@ -101,3 +108,14 @@ value_t* tysy_new_str(tysy_t* tysy, char* value, int line)
|
|||
|
||||
return val;
|
||||
}
|
||||
|
||||
value_t* tysy_new_fun(tysy_t* tysy, fun_t* fun, int line)
|
||||
{
|
||||
assert(tysy);
|
||||
|
||||
value_t* val = malloc(sizeof(value_t));
|
||||
value_init(val, tysy_try_find_type(tysy, "fun"), line);
|
||||
val->value.fun = fun;
|
||||
|
||||
return val;
|
||||
}
|
||||
|
|
|
@ -19,5 +19,6 @@ type_t* tysy_try_find_type(tysy_t* tysy, char* name);
|
|||
value_t* tysy_new_num(tysy_t* tysy, double value, int line);
|
||||
value_t* tysy_new_bool(tysy_t* tysy, int value, int line);
|
||||
value_t* tysy_new_str(tysy_t* tysy, char* value, int line);
|
||||
value_t* tysy_new_fun(tysy_t* tysy, fun_t* fun, int line);
|
||||
|
||||
#endif
|
||||
|
|
20
lib/value.c
20
lib/value.c
|
@ -1,4 +1,7 @@
|
|||
#include "value.h"
|
||||
#include "lib/commons.h"
|
||||
#include "lib/type.h"
|
||||
#include "program.h"
|
||||
|
||||
void value_init(value_t* value, type_t* type, int line)
|
||||
{
|
||||
|
@ -12,10 +15,19 @@ void value_init(value_t* value, type_t* type, int line)
|
|||
void value_free(value_t* value)
|
||||
{
|
||||
assert(value);
|
||||
assert(value->type);
|
||||
|
||||
if (value->type->kind == TYPE_STR)
|
||||
{
|
||||
free(value->value.str);
|
||||
value->value.str = NULL;
|
||||
}
|
||||
|
||||
if (value->type->kind == TYPE_FUN)
|
||||
{
|
||||
fun_free(value->value.fun);
|
||||
free(value->value.fun);
|
||||
value->value.fun = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -40,6 +52,10 @@ int value_eq(value_t* value, value_t* rhs)
|
|||
return strcmp(value->value.str, rhs->value.str) == 0;
|
||||
} break;
|
||||
|
||||
case TYPE_FUN: {
|
||||
return value->value.fun == rhs->value.fun;
|
||||
} break;
|
||||
|
||||
default: {
|
||||
fprintf(stderr, "Cannot compare value of type '%s'.\n",
|
||||
TypeKindStr[value->type->kind]);
|
||||
|
@ -69,6 +85,10 @@ size_t value_str(value_t* value, char* buffer, size_t size)
|
|||
return snprintf(buffer, size, "\"%s\"", value->value.str);
|
||||
break;
|
||||
|
||||
case TYPE_FUN:
|
||||
return snprintf(buffer, size, "[fun]");
|
||||
break;
|
||||
|
||||
default: {
|
||||
fprintf(stderr, "Cannot stringify unknown value of type '%s'.\n",
|
||||
TypeKindStr[value->type->kind]);
|
||||
|
|
|
@ -2,6 +2,9 @@
|
|||
#define RZ_VALUE_H
|
||||
|
||||
#include "type.h"
|
||||
#include "fun.h"
|
||||
|
||||
struct program;
|
||||
|
||||
typedef struct {
|
||||
type_t* type;
|
||||
|
@ -10,6 +13,7 @@ typedef struct {
|
|||
double num;
|
||||
int bool;
|
||||
char* str;
|
||||
fun_t* fun;
|
||||
} value;
|
||||
|
||||
int line;
|
||||
|
|
271
lib/vm.c
271
lib/vm.c
|
@ -3,6 +3,8 @@
|
|||
#include "lib/mod.h"
|
||||
#include "lib/type.h"
|
||||
#include "lib/tysy.h"
|
||||
#include "program.h"
|
||||
#include "value.h"
|
||||
|
||||
void vm_init(vm_t* vm, sym_t* sym, tysy_t* tysy, err_t* err)
|
||||
{
|
||||
|
@ -11,7 +13,7 @@ void vm_init(vm_t* vm, sym_t* sym, tysy_t* tysy, err_t* err)
|
|||
assert(tysy);
|
||||
|
||||
vm->top_frame = NULL;
|
||||
vm_frame_push(vm);
|
||||
vm_frame_push(vm, NULL);
|
||||
|
||||
vm->tysy = tysy;
|
||||
vm->err = err;
|
||||
|
@ -25,6 +27,12 @@ void vm_free(vm_t* vm)
|
|||
{
|
||||
}
|
||||
|
||||
if (vm->top_frame)
|
||||
{
|
||||
vm_frame_free(vm->top_frame);
|
||||
free(vm->top_frame);
|
||||
}
|
||||
|
||||
vm->top_frame = NULL;
|
||||
}
|
||||
|
||||
|
@ -37,9 +45,14 @@ void vm_frame_init(frame_t* frame)
|
|||
frame->sp = 0;
|
||||
|
||||
frame->prev = NULL;
|
||||
frame->program = NULL;
|
||||
frame->locals.cap = 0;
|
||||
frame->locals.size = 0;
|
||||
frame->locals.data = NULL;
|
||||
|
||||
frame->alloc.cap = 0;
|
||||
frame->alloc.size = 0;
|
||||
frame->alloc.data = NULL;
|
||||
}
|
||||
|
||||
void vm_frame_free(frame_t* frame)
|
||||
|
@ -54,6 +67,8 @@ void vm_frame_free(frame_t* frame)
|
|||
frame->locals.size = 0;
|
||||
frame->locals.cap = 0;
|
||||
|
||||
//vm_clear_alloc(frame);
|
||||
|
||||
if (frame->prev != NULL)
|
||||
{
|
||||
vm_frame_free((frame_t*) frame->prev);
|
||||
|
@ -61,7 +76,7 @@ void vm_frame_free(frame_t* frame)
|
|||
}
|
||||
}
|
||||
|
||||
void vm_frame_push(vm_t* vm)
|
||||
void vm_frame_push(vm_t* vm, program_t* program)
|
||||
{
|
||||
assert(vm);
|
||||
|
||||
|
@ -69,7 +84,7 @@ void vm_frame_push(vm_t* vm)
|
|||
vm_frame_init(frame);
|
||||
|
||||
frame->prev = (struct frame*) vm->top_frame;
|
||||
|
||||
frame->program = program;
|
||||
vm->top_frame = frame;
|
||||
}
|
||||
|
||||
|
@ -79,11 +94,19 @@ int vm_frame_pop(vm_t* vm)
|
|||
|
||||
if (vm->top_frame)
|
||||
{
|
||||
frame_t* frame = vm->top_frame;
|
||||
vm->top_frame = (frame_t*) vm->top_frame->prev;
|
||||
vm_clear_alloc(vm->top_frame);
|
||||
}
|
||||
|
||||
if (vm->top_frame && vm->top_frame->prev)
|
||||
{
|
||||
frame_t* prev = (frame_t*) vm->top_frame->prev;
|
||||
vm->top_frame->prev = NULL;
|
||||
|
||||
vm_frame_free(vm->top_frame);
|
||||
free(vm->top_frame);
|
||||
|
||||
vm->top_frame = prev;
|
||||
|
||||
vm_frame_free(frame);
|
||||
free(frame);
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
@ -141,32 +164,38 @@ void vm_local_store(vm_t* vm, int id, param_t addr)
|
|||
}
|
||||
}
|
||||
|
||||
void vm_push_new_value(vm_t* vm, mod_t* mod, value_t* value)
|
||||
void vm_push_new(vm_t* vm, value_t* value)
|
||||
{
|
||||
assert(vm);
|
||||
assert(value);
|
||||
vm->top_frame->stack[vm->top_frame->sp] = value;
|
||||
|
||||
param_t param = mod_push_new_value(mod, value);
|
||||
vm_push(vm, param);
|
||||
}
|
||||
vm_push_alloc(vm->top_frame, value);
|
||||
|
||||
void vm_push(vm_t* vm, param_t param)
|
||||
{
|
||||
assert(vm);
|
||||
assert(vm->top_frame->sp + 1 < RZ_STACK_LIMIT);
|
||||
|
||||
vm->top_frame->stack[vm->top_frame->sp] = param;
|
||||
vm->top_frame->sp++;
|
||||
}
|
||||
|
||||
param_t vm_pop(vm_t* vm)
|
||||
void vm_push(vm_t* vm, value_t* value)
|
||||
{
|
||||
assert(value);
|
||||
vm->top_frame->stack[vm->top_frame->sp] = value;
|
||||
vm->top_frame->allocated[vm->top_frame->sp] = 0;
|
||||
vm->top_frame->sp++;
|
||||
}
|
||||
|
||||
value_t* vm_pop(vm_t* vm)
|
||||
{
|
||||
assert(vm);
|
||||
assert(vm->top_frame->sp > 0);
|
||||
param_t param = vm->top_frame->stack[vm->top_frame->sp - 1];
|
||||
|
||||
if (vm->top_frame->sp == 0)
|
||||
{
|
||||
assert(0);
|
||||
}
|
||||
|
||||
value_t* val = vm->top_frame->stack[vm->top_frame->sp - 1];
|
||||
|
||||
vm->top_frame->sp--;
|
||||
|
||||
return param;
|
||||
return val;
|
||||
}
|
||||
|
||||
size_t vm_stack_str(vm_t* vm, char* buffer, size_t size)
|
||||
|
@ -184,7 +213,11 @@ size_t vm_stack_str(vm_t* vm, char* buffer, size_t size)
|
|||
|
||||
for (size_t i=0; i<vm->top_frame->sp; i++)
|
||||
{
|
||||
sz += snprintf(buffer + sz, size - sz, "| %d |\n", vm->top_frame->stack[vm->top_frame->sp - 1 - i]);
|
||||
value_t* val = vm->top_frame->stack[vm->top_frame->sp - 1 - i];
|
||||
|
||||
sz += snprintf(buffer + sz, size - sz, "| ");
|
||||
value_str(val, buffer + sz, size - sz);
|
||||
sz += snprintf(buffer + sz, size - sz, " |");
|
||||
}
|
||||
|
||||
return sz;
|
||||
|
@ -194,13 +227,15 @@ int vm_exec_mod(vm_t* vm, mod_t* mod)
|
|||
{
|
||||
assert(vm);
|
||||
vm->top_frame->pc = 0;
|
||||
vm->top_frame->program = &mod->program;
|
||||
|
||||
while (vm->top_frame->pc < mod->program.size)
|
||||
while (vm->top_frame->pc < vm->top_frame->program->size)
|
||||
{
|
||||
program_t* program = vm->top_frame->program;
|
||||
|
||||
int status = vm_exec_instr(vm,
|
||||
mod,
|
||||
mod->program.ops[vm->top_frame->pc],
|
||||
mod->program.params[vm->top_frame->pc]);
|
||||
program->ops[vm->top_frame->pc],
|
||||
program->params[vm->top_frame->pc]);
|
||||
|
||||
if (status != 0)
|
||||
{
|
||||
|
@ -211,7 +246,7 @@ int vm_exec_mod(vm_t* vm, mod_t* mod)
|
|||
return 0;
|
||||
}
|
||||
|
||||
int vm_exec_instr(vm_t* vm, mod_t* mod, Opcode op, param_t param)
|
||||
int vm_exec_instr(vm_t* vm, Opcode op, param_t param)
|
||||
{
|
||||
assert(vm);
|
||||
|
||||
|
@ -224,14 +259,13 @@ int vm_exec_instr(vm_t* vm, mod_t* mod, Opcode op, param_t param)
|
|||
abort();
|
||||
}
|
||||
|
||||
vm->top_frame->stack[vm->top_frame->sp] = param;
|
||||
vm->top_frame->sp++;
|
||||
value_t* val = (value_t*) vm->top_frame->program->values.data[param];
|
||||
vm_push(vm, val);
|
||||
vm->top_frame->pc++;
|
||||
} break;
|
||||
|
||||
case OP_ASSERT: {
|
||||
param_t top = vm_pop(vm);
|
||||
value_t* value = mod->values.data[top];
|
||||
value_t* value = vm_pop(vm);
|
||||
|
||||
if (value->type->kind != TYPE_BOOL)
|
||||
{
|
||||
|
@ -248,20 +282,15 @@ int vm_exec_instr(vm_t* vm, mod_t* mod, Opcode op, param_t param)
|
|||
return -1;
|
||||
}
|
||||
|
||||
vm_push(vm, top);
|
||||
vm_push(vm, value);
|
||||
vm->top_frame->pc++;
|
||||
|
||||
} break;
|
||||
|
||||
case OP_NE:
|
||||
case OP_EQ: {
|
||||
int l = vm_pop(vm);
|
||||
int r = vm_pop(vm);
|
||||
assert(l != -1);
|
||||
assert(r != -1);
|
||||
|
||||
value_t* rhs = mod->values.data[l];
|
||||
value_t* lhs = mod->values.data[r];
|
||||
value_t* rhs = vm_pop(vm);
|
||||
value_t* lhs = vm_pop(vm);
|
||||
|
||||
int same_type = lhs->type->kind == rhs->type->kind;
|
||||
int eq = value_eq(lhs, rhs);
|
||||
|
@ -272,20 +301,17 @@ int vm_exec_instr(vm_t* vm, mod_t* mod, Opcode op, param_t param)
|
|||
: (!same_type || !eq)),
|
||||
rhs->line);
|
||||
|
||||
vm_push_new_value(vm, mod, res);
|
||||
vm_push_new(vm, res);
|
||||
|
||||
vm->top_frame->pc++;
|
||||
} break;
|
||||
|
||||
case OP_LT:
|
||||
case OP_LT:
|
||||
case OP_LE:
|
||||
case OP_GT:
|
||||
case OP_GE: {
|
||||
int r = vm_pop(vm);
|
||||
int l = vm_pop(vm);
|
||||
|
||||
value_t* lhs = mod->values.data[l];
|
||||
value_t* rhs = mod->values.data[r];
|
||||
value_t* rhs = vm_pop(vm);
|
||||
value_t* lhs = vm_pop(vm);
|
||||
|
||||
vm_ensure_type(vm, lhs, TYPE_NUM);
|
||||
vm_ensure_type(vm, rhs, TYPE_NUM);
|
||||
|
@ -302,7 +328,7 @@ int vm_exec_instr(vm_t* vm, mod_t* mod, Opcode op, param_t param)
|
|||
}
|
||||
|
||||
value_t* res = tysy_new_bool(vm->tysy, val, lhs->line);
|
||||
vm_push_new_value(vm, mod, res);
|
||||
vm_push_new(vm, res);
|
||||
|
||||
vm->top_frame->pc++;
|
||||
} break;
|
||||
|
@ -313,11 +339,8 @@ int vm_exec_instr(vm_t* vm, mod_t* mod, Opcode op, param_t param)
|
|||
case OP_DIV:
|
||||
case OP_MODULO:
|
||||
case OP_POW: {
|
||||
int r = vm_pop(vm);
|
||||
int l = vm_pop(vm);
|
||||
|
||||
value_t* lhs = mod->values.data[l];
|
||||
value_t* rhs = mod->values.data[r];
|
||||
value_t* rhs = vm_pop(vm);
|
||||
value_t* lhs = vm_pop(vm);
|
||||
|
||||
vm_ensure_type(vm, lhs, TYPE_NUM);
|
||||
vm_ensure_type(vm, rhs, TYPE_NUM);
|
||||
|
@ -336,17 +359,14 @@ int vm_exec_instr(vm_t* vm, mod_t* mod, Opcode op, param_t param)
|
|||
}
|
||||
|
||||
value_t* res = tysy_new_num(vm->tysy, val, lhs->line);
|
||||
vm_push_new_value(vm, mod, res);
|
||||
vm_push_new(vm, res);
|
||||
|
||||
vm->top_frame->pc++;
|
||||
} break;
|
||||
|
||||
case OP_STRCAT: {
|
||||
int r = vm_pop(vm);
|
||||
int l = vm_pop(vm);
|
||||
|
||||
value_t* lhs = mod->values.data[l];
|
||||
value_t* rhs = mod->values.data[r];
|
||||
value_t* rhs = vm_pop(vm);
|
||||
value_t* lhs = vm_pop(vm);
|
||||
|
||||
vm_ensure_type(vm, lhs, TYPE_STR);
|
||||
vm_ensure_type(vm, rhs, TYPE_STR);
|
||||
|
@ -359,17 +379,14 @@ int vm_exec_instr(vm_t* vm, mod_t* mod, Opcode op, param_t param)
|
|||
value_t* value = tysy_new_str(vm->tysy, res.data, lhs->line);
|
||||
str_free(&res);
|
||||
|
||||
vm_push_new_value(vm, mod, value);
|
||||
vm_push_new(vm, value);
|
||||
|
||||
vm->top_frame->pc++;
|
||||
} break;
|
||||
|
||||
case OP_STRDUP: {
|
||||
int r = vm_pop(vm);
|
||||
int l = vm_pop(vm);
|
||||
|
||||
value_t* lhs = mod->values.data[l];
|
||||
value_t* rhs = mod->values.data[r];
|
||||
value_t* rhs = vm_pop(vm);
|
||||
value_t* lhs = vm_pop(vm);
|
||||
|
||||
if (lhs->type->kind != TYPE_NUM)
|
||||
{
|
||||
|
@ -392,43 +409,40 @@ int vm_exec_instr(vm_t* vm, mod_t* mod, Opcode op, param_t param)
|
|||
value_t* value = tysy_new_str(vm->tysy, res.data, lhs->line);
|
||||
str_free(&res);
|
||||
|
||||
vm_push_new_value(vm, mod, value);
|
||||
vm_push_new(vm, value);
|
||||
|
||||
vm->top_frame->pc++;
|
||||
} break;
|
||||
|
||||
case OP_USUB: {
|
||||
int l = vm_pop(vm);
|
||||
|
||||
value_t* lhs = mod->values.data[l];
|
||||
value_t* lhs = vm_pop(vm);
|
||||
|
||||
vm_ensure_type(vm, lhs, TYPE_NUM);
|
||||
|
||||
double val = -lhs->value.num;
|
||||
|
||||
value_t* res = tysy_new_num(vm->tysy, val, lhs->line);
|
||||
vm_push_new_value(vm, mod, res);
|
||||
vm_push_new(vm, res);
|
||||
|
||||
vm->top_frame->pc++;
|
||||
} break;
|
||||
|
||||
case OP_NOT: {
|
||||
int l = vm_pop(vm);
|
||||
value_t* lhs = mod->values.data[l];
|
||||
value_t* lhs = vm_pop(vm);
|
||||
vm_ensure_type(vm, lhs, TYPE_BOOL);
|
||||
|
||||
int val = !lhs->value.bool;
|
||||
|
||||
value_t* res = tysy_new_bool(vm->tysy, val, lhs->line);
|
||||
vm_push_new_value(vm, mod, res);
|
||||
vm_push_new(vm, res);
|
||||
|
||||
vm->top_frame->pc++;
|
||||
} break;
|
||||
|
||||
case OP_BRT:
|
||||
case OP_BRF: {
|
||||
param_t p = vm_pop(vm);
|
||||
value_t* value = mod->values.data[p];
|
||||
value_t* value = vm_pop(vm);
|
||||
|
||||
vm_ensure_type(vm, value, TYPE_BOOL);
|
||||
|
||||
if (op == OP_BRT && value->value.bool)
|
||||
|
@ -460,11 +474,21 @@ int vm_exec_instr(vm_t* vm, mod_t* mod, Opcode op, param_t param)
|
|||
snprintf(msg, RZ_STR_LIMIT, "Cannot load local variable '%d'.",
|
||||
param);
|
||||
|
||||
param_t p = vm->top_frame->stack[vm->top_frame->sp - 1];
|
||||
int line = mod->values.data[p]->line;
|
||||
if (vm->top_frame->sp == 0)
|
||||
{
|
||||
err_fatal(vm->err, msg, -1);
|
||||
err_dump(vm->err);
|
||||
abort();
|
||||
}
|
||||
else
|
||||
{
|
||||
value_t* val = vm->top_frame->stack[vm->top_frame->sp - 1];
|
||||
int line = val->line;
|
||||
|
||||
err_fatal(vm->err, msg, line);
|
||||
err_dump(vm->err);
|
||||
err_fatal(vm->err, msg, line);
|
||||
err_dump(vm->err);
|
||||
abort();
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
|
@ -480,6 +504,54 @@ int vm_exec_instr(vm_t* vm, mod_t* mod, Opcode op, param_t param)
|
|||
vm->top_frame->pc++;
|
||||
} break;
|
||||
|
||||
case OP_CALL: {
|
||||
size_t const ARG_SZ = param + 1;
|
||||
value_t* args[ARG_SZ];
|
||||
|
||||
for (size_t i=0; i<ARG_SZ; i++)
|
||||
{
|
||||
value_t* val = vm_pop(vm);
|
||||
args[ARG_SZ - 1 - i] = val;
|
||||
}
|
||||
|
||||
value_t* fun_val = args[ARG_SZ - 1];
|
||||
assert(fun_val->type->kind == TYPE_FUN);
|
||||
fun_t* fun = fun_val->value.fun;
|
||||
|
||||
vm->top_frame->pc++;
|
||||
vm_frame_push(vm, &fun->program);
|
||||
|
||||
for (size_t i=0; i<ARG_SZ; i++)
|
||||
{
|
||||
value_t* arg = args[i];
|
||||
|
||||
vm_push(vm, arg);
|
||||
vm_local_store(vm, ARG_SZ - 1 - i, vm->top_frame->sp - 1);
|
||||
}
|
||||
|
||||
} break;
|
||||
|
||||
case OP_RET: {
|
||||
|
||||
frame_t* frame = (frame_t*) vm->top_frame;
|
||||
frame_t* prev = (frame_t*) vm->top_frame->prev;
|
||||
|
||||
value_t* ret = frame->stack[frame->sp - 1];
|
||||
prev->stack[prev->sp] = ret;
|
||||
prev->sp++;
|
||||
|
||||
for (size_t i=0; i<frame->alloc.size; i++)
|
||||
{
|
||||
if (frame->alloc.data[i] == ret)
|
||||
{
|
||||
frame->alloc.data[i] = NULL;
|
||||
vm_push_alloc(prev, ret);
|
||||
}
|
||||
}
|
||||
|
||||
vm_frame_pop(vm);
|
||||
} break;
|
||||
|
||||
default: {
|
||||
fprintf(stderr, "Cannot execute unknown opcode '%s'.\n",
|
||||
OpcodeStr[op]);
|
||||
|
@ -494,6 +566,7 @@ void vm_ensure_type(vm_t* vm, value_t* value, TypeKind want)
|
|||
{
|
||||
assert(vm);
|
||||
assert(value);
|
||||
|
||||
TypeKind got = value->type->kind;
|
||||
int line = value->line;
|
||||
|
||||
|
@ -509,3 +582,43 @@ void vm_ensure_type(vm_t* vm, value_t* value, TypeKind want)
|
|||
err_dump(vm->err);
|
||||
}
|
||||
}
|
||||
|
||||
void vm_push_alloc(frame_t* frame, value_t* value)
|
||||
{
|
||||
assert(frame);
|
||||
assert(value);
|
||||
|
||||
if (frame->alloc.cap == 0)
|
||||
{
|
||||
frame->alloc.cap = 2;
|
||||
frame->alloc.data = malloc(sizeof(value_t*) * frame->alloc.cap);
|
||||
}
|
||||
|
||||
if (frame->alloc.size >= frame->alloc.cap)
|
||||
{
|
||||
frame->alloc.cap *= 2;
|
||||
frame->alloc.data = realloc(frame->alloc.data,
|
||||
sizeof(value_t*) * frame->alloc.cap);
|
||||
}
|
||||
|
||||
frame->alloc.data[frame->alloc.size] = value;
|
||||
frame->alloc.size++;
|
||||
}
|
||||
|
||||
void vm_clear_alloc(frame_t* frame)
|
||||
{
|
||||
assert(frame);
|
||||
for (size_t i=0; i<frame->alloc.size; i++)
|
||||
{
|
||||
value_t* val = frame->alloc.data[i];
|
||||
|
||||
if (val)
|
||||
{
|
||||
value_free(val);
|
||||
free(val);
|
||||
}
|
||||
}
|
||||
|
||||
free(frame->alloc.data);
|
||||
frame->alloc.data = NULL;
|
||||
}
|
||||
|
|
26
lib/vm.h
26
lib/vm.h
|
@ -7,6 +7,7 @@
|
|||
#include "err.h"
|
||||
#include "tysy.h"
|
||||
#include "sym.h"
|
||||
#include "program.h"
|
||||
|
||||
typedef struct {
|
||||
int id;
|
||||
|
@ -15,8 +16,9 @@ typedef struct {
|
|||
|
||||
typedef struct stack_frame{
|
||||
struct frame* prev;
|
||||
|
||||
param_t stack[RZ_STACK_LIMIT];
|
||||
program_t* program;
|
||||
value_t* stack[RZ_STACK_LIMIT];
|
||||
int allocated[RZ_STACK_LIMIT];
|
||||
size_t pc;
|
||||
size_t bp;
|
||||
size_t sp;
|
||||
|
@ -26,6 +28,13 @@ typedef struct stack_frame{
|
|||
size_t cap;
|
||||
local_t** data;
|
||||
} locals;
|
||||
|
||||
struct {
|
||||
size_t size;
|
||||
size_t cap;
|
||||
value_t** data;
|
||||
} alloc;
|
||||
|
||||
} frame_t;
|
||||
|
||||
typedef struct {
|
||||
|
@ -41,20 +50,23 @@ void vm_free(vm_t* vm);
|
|||
void vm_frame_init(frame_t* frame);
|
||||
void vm_frame_free(frame_t* frame);
|
||||
|
||||
void vm_frame_push(vm_t* vm);
|
||||
void vm_frame_push(vm_t* vm, program_t* program);
|
||||
int vm_frame_pop(vm_t* vm);
|
||||
|
||||
local_t* vm_try_local_load(vm_t* vm, int id);
|
||||
void vm_local_store(vm_t* vm, int id, param_t addr);
|
||||
|
||||
void vm_push_new_value(vm_t* vm, mod_t* mod, value_t* value);
|
||||
void vm_push(vm_t* vm, param_t param);
|
||||
param_t vm_pop(vm_t* vm);
|
||||
void vm_push_new(vm_t* vm, value_t* value);
|
||||
void vm_push(vm_t* vm, value_t* value);
|
||||
value_t* vm_pop(vm_t* vm);
|
||||
|
||||
size_t vm_stack_str(vm_t* vm, char* buffer, size_t size);
|
||||
|
||||
int vm_exec_mod(vm_t* vm, mod_t* mod);
|
||||
int vm_exec_instr(vm_t* vm, mod_t* mod, Opcode op, param_t param);
|
||||
int vm_exec_instr(vm_t* vm, Opcode op, param_t param);
|
||||
void vm_ensure_type(vm_t* vm, value_t* value, TypeKind want);
|
||||
|
||||
void vm_push_alloc(frame_t* frame, value_t* value);
|
||||
void vm_clear_alloc(frame_t* frame);
|
||||
|
||||
#endif
|
||||
|
|
|
@ -36,8 +36,12 @@ roza_lib = static_library(
|
|||
'lib/tysy.c',
|
||||
'lib/tysolver.c',
|
||||
|
||||
# types
|
||||
'lib/fun.c',
|
||||
|
||||
# comp
|
||||
'lib/opcodes.c',
|
||||
'lib/program.c',
|
||||
'lib/mod.c',
|
||||
'lib/prepass.c',
|
||||
'lib/compiler.c',
|
||||
|
|
|
@ -0,0 +1,60 @@
|
|||
# FUNCTIONS
|
||||
# =========
|
||||
|
||||
fun double(n)
|
||||
n * 2
|
||||
end
|
||||
|
||||
assert double(4) == 8
|
||||
assert 8 == double(4)
|
||||
|
||||
assert double(4) != 10
|
||||
assert 9 != double(4)
|
||||
|
||||
assert double(double(double(3))) == 24
|
||||
|
||||
fun a()
|
||||
return 45
|
||||
end
|
||||
|
||||
assert a() == 45
|
||||
|
||||
fun b()
|
||||
return 27
|
||||
return 32
|
||||
end
|
||||
|
||||
assert b() == 27
|
||||
|
||||
fun max(m, n)
|
||||
if m > n then
|
||||
return m
|
||||
end
|
||||
return n
|
||||
end
|
||||
|
||||
assert max(7, 3) == 7
|
||||
assert max(7, 9) == 9
|
||||
|
||||
# RECURSIVITY
|
||||
# ===========
|
||||
|
||||
fun fac(n)
|
||||
if n == 0 then
|
||||
return 1
|
||||
end
|
||||
|
||||
return n * fac(n - 1)
|
||||
end
|
||||
|
||||
assert fac(5) == 120
|
||||
|
||||
fun fib(n)
|
||||
if n == 0 or n == 1 then
|
||||
return 1
|
||||
end
|
||||
|
||||
return fib(n - 2) + fib(n - 1)
|
||||
end
|
||||
|
||||
assert fib(6) == 13
|
|
@ -163,3 +163,10 @@ Test(lexer, blocks) {
|
|||
"THEN",
|
||||
"ELSE");
|
||||
}
|
||||
|
||||
Test(lexer, fun) {
|
||||
test_lexer("fun return,", 3,
|
||||
"FUN",
|
||||
"RETURN",
|
||||
"COMMA");
|
||||
}
|
||||
|
|
|
@ -139,3 +139,32 @@ Test(parser, if_then_else) {
|
|||
"IF(IDENT[z],BLOCK(IDENT[u]),BLOCK(IDENT[v]))))",
|
||||
"if x then y else if z then u else v end");
|
||||
}
|
||||
|
||||
Test(parser, fun_decl) {
|
||||
test_parser_ok("MOD(FUNDECL(IDENT[f],"
|
||||
"PARAMS(IDENT[x]),"
|
||||
"BLOCK(RETURN(IDENT[x]))))",
|
||||
"fun f(x) return x end");
|
||||
|
||||
test_parser_ok("MOD(FUNDECL(IDENT[f],"
|
||||
"PARAMS(IDENT[x],IDENT[y]),"
|
||||
"BLOCK(RETURN(IDENT[x]))))",
|
||||
"fun f(x, y) return x end");
|
||||
}
|
||||
|
||||
Test(parser, fun_call) {
|
||||
test_parser_ok("MOD(FUNCALL(IDENT[hello],ARGS("
|
||||
"NUM[1],BOOL[true],BOOL[false]"
|
||||
")))",
|
||||
"hello(1, true, false)");
|
||||
|
||||
test_parser_ok("MOD(FUNCALL(IDENT[hello],ARGS(NUM[1])))",
|
||||
"hello(1)");
|
||||
|
||||
test_parser_ok("MOD(FUNCALL(IDENT[hello],ARGS))",
|
||||
"hello()");
|
||||
|
||||
test_parser_ok("MOD(ASSERT(EQ(FUNCALL(IDENT[hello],ARGS),NUM[1])))",
|
||||
"assert hello() == 1");
|
||||
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue