simple variable declarations.

main
bog 2023-12-17 19:10:17 +01:00
parent 5b8748b843
commit bb83d39bb9
26 changed files with 901 additions and 195 deletions

View File

@ -1,8 +1,10 @@
MOD ::= EXPR*
EXPR ::=
| ASSERT
| VARDECL
| OR
ASSERT ::= assert EXPR
VARDECL ::= let ident assign EXPR
OR ::= AND (or AND)*
AND ::= EQNE (and EQNE)*
EQNE ::=
@ -15,4 +17,4 @@ FACTOR ::= POWER ((mul | div | mod) POWER)*
POWER ::= UNARY (pow UNARY)?
UNARY ::= sub? GROUP | not? GROUP
GROUP ::= BUILTIN | opar EXPR cpar
BUILTIN ::= num | bool | str
BUILTIN ::= num | bool | str | ident

View File

@ -1,13 +1,21 @@
#include "compiler.h"
#include "lib/commons.h"
#include "lib/mod.h"
#include "node.h"
void compiler_init(compiler_t* compiler, mod_t* mod, tysy_t* tysy, err_t* err)
void compiler_init(compiler_t* compiler,
mod_t* mod,
sym_t* sym,
tysy_t* tysy,
err_t* err)
{
assert(compiler);
assert(sym);
assert(tysy);
assert(err);
compiler->mod = mod;
compiler->sym = sym;
compiler->tysy = tysy;
compiler->err = err;
}
@ -17,7 +25,7 @@ void compiler_free(compiler_t* compiler)
assert(compiler);
}
void compiler_run(compiler_t* compiler, node_t* node)
int compiler_run(compiler_t* compiler, node_t* node)
{
assert(compiler);
assert(node);
@ -222,10 +230,41 @@ void compiler_run(compiler_t* compiler, node_t* node)
mod_push_instr(compiler->mod, OP_NOT, RZ_NO_PARAM);
} break;
case NODE_VARDECL: {
char* name = ((node_t*) node->children.data[0])->value.data;
sym_entry_t* entry = sym_try_find_by_name(compiler->sym, name);
assert(entry);
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;
sym_entry_t* entry = sym_try_find_by_name(compiler->sym, name);
if (!entry)
{
char msg[RZ_STR_LIMIT];
snprintf(msg, RZ_STR_LIMIT, "%s is undefined.",
name);
err_fatal(compiler->err, msg, node->line);
return -1;
}
else
{
int id = entry->id;
mod_push_instr(compiler->mod, OP_LOAD, id);
}
} break;
default: {
fprintf(stderr, "Cannot compile unknown node '%s'",
NodeTypeStr[node->type]);
abort();
} break;
}
return 0;
}

View File

@ -6,16 +6,23 @@
#include "mod.h"
#include "node.h"
#include "tysy.h"
#include "sym.h"
typedef struct {
mod_t* mod;
sym_t* sym;
tysy_t* tysy;
err_t* err;
} compiler_t;
void compiler_init(compiler_t* compiler, mod_t* mod, tysy_t* tysy, err_t* err);
void compiler_init(compiler_t* compiler,
mod_t* mod,
sym_t* sym,
tysy_t* tysy,
err_t* err);
void compiler_free(compiler_t* compiler);
void compiler_run(compiler_t* compiler, node_t* node);
int compiler_run(compiler_t* compiler, node_t* node);
#endif

View File

@ -6,6 +6,8 @@ void err_init(err_t* err)
{
assert(err);
err->size = 0;
err->total = 0;
err->quiet = 0;
}
void err_free(err_t* err)
@ -31,6 +33,8 @@ void err_of_type(err_t* err, char* what, int line, ErrType type)
err->errors[err->size]->line = line;
err->errors[err->size]->type = type;
err->size++;
err->total++;
}
void err_fatal(err_t* err, char* what, int line)
@ -47,23 +51,35 @@ int err_dump(err_t* err)
{
if (err->errors[i]->type == ERR_WARNING)
{
fprintf(stderr, "\33[33mWARNING\33[0m[:%d] %s\n",
err->errors[i]->line,
err->errors[i]->what);
if (!err->quiet)
{
fprintf(stderr, "\33[33mWARNING\33[0m[:%d] %s\n",
err->errors[i]->line,
err->errors[i]->what);
}
}
else if (err->errors[i]->type == ERR_FATAL)
{
fprintf(stderr, "\33[31mERROR\33[0m[:%d] %s\n",
err->errors[i]->line,
err->errors[i]->what);
if (!err->quiet)
{
fprintf(stderr, "\33[31mERROR\33[0m[:%d] %s\n",
err->errors[i]->line,
err->errors[i]->what);
}
is_fatal = 1;
}
}
int total = err->total;
int quiet = err->quiet;
err_free(err);
err_init(err);
err->total = total;
err->quiet = quiet;
return is_fatal;
}

View File

@ -17,6 +17,8 @@ typedef struct {
} err_msg_t;
typedef struct {
int total;
int quiet;
size_t size;
err_msg_t* errors[RZ_ERROR_STACK_SIZE];
} err_t;

View File

@ -67,9 +67,11 @@ node_t* lexer_try_new_next(lexer_t* lexer)
RZ_TEXT(">=", NODE_GE, 0);
RZ_TEXT("<", NODE_LT, 0);
RZ_TEXT(">", NODE_GT, 0);
RZ_TEXT("=", NODE_ASSIGN, 0);
// Keywords
// ========
RZ_KEYWORD("let", NODE_LET, 0);
RZ_KEYWORD("and", NODE_AND, 0);
RZ_KEYWORD("or", NODE_OR, 0);
RZ_KEYWORD("not", NODE_NOT, 0);
@ -88,6 +90,17 @@ node_t* lexer_try_new_next(lexer_t* lexer)
}
}
// scan str
{
node_t* node = lexer_try_new_ident(lexer);
if (node)
{
lexer_skip_spaces(lexer); // usefull ???
return node;
}
}
// scan num
{
size_t cursor = lexer->cursor;
@ -147,6 +160,7 @@ node_t* lexer_try_new_next(lexer_t* lexer)
char msg[SZ];
snprintf(msg, SZ, "unexpected symbol '%c'", lexer->source[lexer->cursor]);
err_fatal(lexer->err, msg, lexer->line);
err_dump(lexer->err);
}
return NULL;
@ -327,6 +341,55 @@ node_t* lexer_try_new_str(lexer_t* lexer)
return tok;
}
node_t* lexer_try_new_ident(lexer_t* lexer)
{
assert(lexer);
ssize_t cursor = lexer->cursor;
ssize_t len = strlen(lexer->source);
str_t res_str;
str_init(&res_str);
int first = 1;
while (cursor < len)
{
char c = lexer->source[cursor];
int is_first = isalpha(c) ||
c == '_' ||
c == '?' ||
c == '!';
int is_rest = is_first || isdigit(c);
if ((first && is_first) || (!first && is_rest))
{
str_push(&res_str, c);
first = 0;
}
else
{
break;
}
cursor++;
}
if (res_str.size == 0)
{
str_free(&res_str);
return NULL;
}
node_t* tok = malloc(sizeof(node_t));
node_init(tok, NODE_IDENT, res_str.data, lexer->line);
str_free(&res_str);
lexer->cursor = cursor;
return tok;
}
int lexer_is_sep(lexer_t* lexer, size_t idx)
{
assert(lexer);

View File

@ -25,6 +25,7 @@ node_t* lexer_try_new_keyword(lexer_t* lexer, char* kw,
int is_kw);
node_t* lexer_try_new_str(lexer_t* lexer);
node_t* lexer_try_new_ident(lexer_t* lexer);
int lexer_is_sep(lexer_t* lexer, size_t idx);

View File

@ -6,6 +6,8 @@
#include "prepass.h"
#include "mod.h"
#include "vm.h"
#include "sym.h"
#include "tysolver.h"
void loader_init(loader_t* loader)
{
@ -59,98 +61,138 @@ int loader_ldfile(loader_t* loader, char const* path, int debug)
lexer_t lex;
lexer_init(&lex, source.data, &err);
if (err_dump(&err))
{
lexer_free(&lex);
err_free(&err);
tysy_free(&tysy);
abort();
}
parser_t parser;
parser_init(&parser, &lex, &err);
node_t* node = parser_try_new_tree(&parser);
assert(node);
if (!node)
{
str_free(&source);
err_dump(&err);
parser_free(&parser);
lexer_free(&lex);
err_free(&err);
tysy_free(&tysy);
return -1;
}
if (debug)
{
char msg[RZ_STR_LIMIT];
node_str(node, msg, RZ_STR_LIMIT);
{
char msg[RZ_STR_LIMIT];
node_str(node, msg, RZ_STR_LIMIT);
printf("\n======== AST ========\n");
printf("%s\n", msg);
printf("\n======== AST ========\n");
printf("%s\n", msg);
}
sym_t sym;
sym_init(&sym, &tysy, &err);
mod_t mod;
mod_init(&mod);
tysolver_t tysolver;
tysolver_init(&tysolver, &sym, &tysy);
// prepass
{
prepass_t prepass;
prepass_init(&prepass, &sym, &tysolver, &err);
prepass_run(&prepass, node);
prepass_free(&prepass);
}
if (node)
// compile
{
compiler_t compiler;
compiler_init(&compiler, &mod, &sym, &tysy, &err);
int status = compiler_run(&compiler, node);
if (status != 0)
{
return -1;
}
compiler_free(&compiler);
}
tysolver_free(&tysolver);
node_free(node);
free(node);
// check compilation errors
if (err_dump(&err))
{
mod_t mod;
mod_init(&mod);
// prepass
{
prepass_t prepass;
prepass_init(&prepass, &err);
prepass_run(&prepass, node);
prepass_free(&prepass);
}
// compile
{
compiler_t compiler;
compiler_init(&compiler, &mod, &tysy, &err);
compiler_run(&compiler, node);
compiler_free(&compiler);
}
node_free(node);
free(node);
// check compilation errors
if (err_dump(&err))
{
parser_free(&parser);
lexer_free(&lex);
str_free(&source);
tysy_free(&tysy);
err_free(&err);
abort();
}
if (debug)
{
char msg[RZ_STR_LIMIT];
mod_str(&mod, msg, RZ_STR_LIMIT);
printf("%s", msg);
}
// execute
{
vm_t vm;
vm_init(&vm, &tysy, &err);
int status = vm_exec_mod(&vm, &mod);
if (status != 0)
{
vm_free(&vm);
mod_free(&mod);
parser_free(&parser);
lexer_free(&lex);
str_free(&source);
tysy_free(&tysy);
err_free(&err);
return status;
}
if (debug)
{
char msg[RZ_STR_LIMIT];
vm_stack_str(&vm, msg, RZ_STR_LIMIT);
printf("\n======== STACK ========\n");
printf("%s\n", msg);
}
vm_free(&vm);
}
parser_free(&parser);
lexer_free(&lex);
str_free(&source);
err_free(&err);
mod_free(&mod);
sym_free(&sym);
tysy_free(&tysy);
return -1;
}
// execute
{
vm_t vm;
vm_init(&vm, &sym, &tysy, &err);
int status = vm_exec_mod(&vm, &mod);
if (status != 0)
{
vm_free(&vm);
mod_free(&mod);
sym_free(&sym);
parser_free(&parser);
lexer_free(&lex);
str_free(&source);
tysy_free(&tysy);
err_free(&err);
return status;
}
if (debug)
{
char msg[RZ_STR_LIMIT];
vm_stack_str(&vm, msg, RZ_STR_LIMIT);
printf("\n======== STACK ========\n");
printf("%s\n", msg);
}
vm_free(&vm);
}
if (debug)
{
char msg[RZ_STR_LIMIT];
mod_str(&mod, msg, RZ_STR_LIMIT);
printf("%s", msg);
char msg2[RZ_STR_LIMIT];
sym_str(&sym, msg2, RZ_STR_LIMIT);
printf("\n======== SYM TABLE ========\n");
printf("%s", msg2);
}
mod_free(&mod);
sym_free(&sym);
// free
parser_free(&parser);
lexer_free(&lex);
@ -161,7 +203,7 @@ int loader_ldfile(loader_t* loader, char const* path, int debug)
if (err_dump(&err))
{
err_free(&err);
abort();
return -1;
}
err_free(&err);

View File

@ -11,7 +11,8 @@
G(NODE_LT), G(NODE_LE), G(NODE_GT), G(NODE_GE), \
G(NODE_ADD), G(NODE_SUB), G(NODE_MUL), G(NODE_DIV), \
G(NODE_MODULO), G(NODE_POW), G(NODE_OPAR), G(NODE_CPAR), \
G(NODE_AND), G(NODE_OR), G(NODE_NOT)
G(NODE_AND), G(NODE_OR), G(NODE_NOT), \
G(NODE_LET), G(NODE_IDENT), G(NODE_ASSIGN), G(NODE_VARDECL)
RZ_ENUM_H(NodeType, NODE_TYPE);

View File

@ -10,9 +10,10 @@
G(OP_LT), G(OP_LE), G(OP_GT), G(OP_GE), \
G(OP_ADD), G(OP_SUB), G(OP_MUL), G(OP_DIV), \
G(OP_MODULO), G(OP_POW), G(OP_USUB), \
G(OP_AND), G(OP_OR), G(OP_NOT), \
G(OP_NOT), \
G(OP_BRF), G(OP_BRT), G(OP_BR), \
G(OP_STRCAT), G(OP_STRDUP)
G(OP_STRCAT), G(OP_STRDUP), \
G(OP_LOAD), G(OP_STORE)
RZ_ENUM_H(Opcode, OPCODES);

View File

@ -1,4 +1,5 @@
#include "parser.h"
#include "lib/commons.h"
#include "lib/lexer.h"
#include "lib/node.h"
@ -61,6 +62,11 @@ node_t* parser_try_new_expr(parser_t* parser)
return parser_try_new_assert(parser);
}
if (type == NODE_LET)
{
return parser_try_new_vardecl(parser);
}
return parser_try_new_or(parser);
}
@ -77,6 +83,24 @@ node_t* parser_try_new_assert(parser_t* parser)
return node;
}
node_t* parser_try_new_vardecl(parser_t* parser)
{
assert(parser);
parser_skip(parser, NODE_LET);
node_t* ident = parser_try_new_consume(parser, NODE_IDENT);
parser_skip(parser, NODE_ASSIGN);
node_t* expr = parser_try_new_expr(parser);
node_t* node = malloc(sizeof(node_t));
node_init(node, NODE_VARDECL, "", parser->lexer->line);
node_add_new_child(node, ident);
node_add_new_child(node, expr);
return node;
}
node_t* parser_try_new_or(parser_t* parser)
{
assert(parser);
@ -303,11 +327,30 @@ node_t* parser_try_new_builtin(parser_t* parser)
assert(parser);
NodeType next = lexer_peek(parser->lexer, 1);
if (next == NODE_NUM || next == NODE_BOOL || next == NODE_STR)
if (next == NODE_NUM
|| next == NODE_BOOL
|| next == NODE_STR
|| next == NODE_IDENT)
{
return parser_try_new_consume(parser, next);
}
if (next)
{
node_t* node = lexer_try_new_next(parser->lexer);
char nstr[RZ_STR_LIMIT];
node_str(node, nstr, RZ_STR_LIMIT);
node_free(node);
free(node);
size_t limit = RZ_STR_LIMIT + strlen(nstr);
char msg[limit];
snprintf(msg, limit, "unexpected node '%s'.", nstr);
err_fatal(parser->err, msg, parser->lexer->line);
err_dump(parser->err);
}
return NULL;
}
@ -329,8 +372,37 @@ node_t* parser_try_new_consume(parser_t* parser, NodeType type)
err_fatal(parser->err, err_msg, next->line);
node_free(next);
free(next);
err_dump(parser->err);
return NULL;
}
return next;
}
int parser_skip(parser_t* parser, NodeType type)
{
assert(parser);
node_t* next = lexer_try_new_next(parser->lexer);
assert(next);
if (next->type != type)
{
size_t const SZ = RZ_STR_LIMIT;
char err_msg[SZ];
snprintf(err_msg, SZ, "unexpected node '%s'", NodeTypeStr[next->type]);
err_fatal(parser->err, err_msg, next->line);
node_free(next);
free(next);
err_dump(parser->err);
return 0;
}
else
{
node_free(next);
free(next);
return 1;
}
}

View File

@ -17,6 +17,7 @@ node_t* parser_try_new_tree(parser_t* parser);
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_or(parser_t* parser);
node_t* parser_try_new_and(parser_t* parser);
node_t* parser_try_new_eqne(parser_t* parser);
@ -29,5 +30,6 @@ node_t* parser_try_new_group(parser_t* parser);
node_t* parser_try_new_builtin(parser_t* parser);
node_t* parser_try_new_consume(parser_t* parser, NodeType type);
int parser_skip(parser_t* parser, NodeType type);
#endif

View File

@ -1,10 +1,18 @@
#include "prepass.h"
#include "node.h"
void prepass_init(prepass_t* prepass, err_t* err)
void prepass_init(prepass_t* prepass,
sym_t* sym,
tysolver_t* tysolver,
err_t* err)
{
assert(prepass);
assert(sym);
assert(tysolver);
assert(err);
prepass->sym = sym;
prepass->tysolver = tysolver;
prepass->err = err;
}
@ -20,39 +28,20 @@ void prepass_run(prepass_t* prepass, node_t* node)
switch (node->type)
{
case NODE_MOD:
case NODE_NUM:
case NODE_STR:
case NODE_BOOL:
case NODE_ASSERT:
case NODE_EQ:
case NODE_NE:
case NODE_LT:
case NODE_LE:
case NODE_GT:
case NODE_GE:
case NODE_VARDECL: {
char* name = ((node_t*) node->children.data[0])->value.data;
prepass_run(prepass, (node_t*) node->children.data[1]);
case NODE_ADD:
case NODE_SUB:
case NODE_MUL:
case NODE_DIV:
case NODE_MODULO:
case NODE_POW:
type_t* type = tysolver_try_solve_node(prepass->tysolver,
(node_t*) node->children.data[1]);
sym_declare(prepass->sym, name, type);
} break;
case NODE_OR:
case NODE_AND:
case NODE_NOT:
{
default: {
for (size_t i=0; i<node->children.size; i++)
{
prepass_run(prepass, (node_t*) node->children.data[i]);
}
} break;
default: {
fprintf(stderr, "Cannot prepass unknown node '%s'.\n",
NodeTypeStr[node->type]);
abort();
} break;
}
}

View File

@ -4,12 +4,20 @@
#include "commons.h"
#include "err.h"
#include "node.h"
#include "sym.h"
#include "tysolver.h"
typedef struct {
sym_t* sym;
tysolver_t* tysolver;
err_t* err;
} prepass_t;
void prepass_init(prepass_t* prepass, err_t* err);
void prepass_init(prepass_t* prepass,
sym_t* sym,
tysolver_t* tysolver,
err_t* err);
void prepass_free(prepass_t* prepass);
void prepass_run(prepass_t* prepass, node_t* node);

99
lib/sym.c Normal file
View File

@ -0,0 +1,99 @@
#include "sym.h"
void sym_init(sym_t* sym, tysy_t* tysy, err_t* err)
{
assert(sym);
sym->tysy = tysy;
sym->err = err;
sym->entries.id_counter = 0;
sym->entries.size = 0;
sym->entries.cap = 0;
sym->entries.data = NULL;
}
void sym_free(sym_t* sym)
{
assert(sym);
for (size_t i=0; i<sym->entries.size; i++)
{
sym_entry_t* entry = sym->entries.data[i];
free(entry->name);
free(entry);
}
free(sym->entries.data);
sym->entries.size = 0;
sym->entries.cap = 0;
}
int sym_declare(sym_t* sym, char* name, type_t* type)
{
assert(sym);
assert(name);
assert(type);
if (sym->entries.data == NULL)
{
sym->entries.cap = 2;
sym->entries.data = malloc(sizeof(sym_entry_t*)
* sym->entries.cap);
}
if (sym->entries.size >= sym->entries.cap)
{
sym->entries.cap *= 2;
sym->entries.data = realloc(sym->entries.data,
sizeof(sym_entry_t*) * sym->entries.cap);
}
sym->entries.data[sym->entries.size] = malloc(sizeof(sym_entry_t));
int id = sym->entries.id_counter;
sym->entries.id_counter++;
sym->entries.data[sym->entries.size]->name = strdup(name);
sym->entries.data[sym->entries.size]->id = id;
sym->entries.data[sym->entries.size]->type = type;
sym->entries.size++;
return id;
}
sym_entry_t* sym_try_find_by_name(sym_t* sym, char* name)
{
assert(sym);
for (size_t i=0; i<sym->entries.size; i++)
{
if (strcmp(sym->entries.data[i]->name, name) == 0)
{
return sym->entries.data[i];
}
}
return NULL;
}
size_t sym_str(sym_t* sym, char* buffer, size_t size)
{
assert(sym);
assert(buffer);
size_t sz = 0;
for (size_t i=0; i<sym->entries.size; i++)
{
sym_entry_t* entry = sym->entries.data[i];
sz += snprintf(buffer + sz, size - sz, "(%d %s ",
entry->id, entry->name);
sz += type_str(entry->type, buffer + sz, size - sz);
sz += snprintf(buffer + sz, size - sz, ")\n");
}
return sz;
}

34
lib/sym.h Normal file
View File

@ -0,0 +1,34 @@
#ifndef RZ_SYM_H
#define RZ_SYM_H
#include "commons.h"
#include "tysy.h"
#include "err.h"
typedef struct {
int id;
char* name;
type_t* type;
} sym_entry_t;
typedef struct {
tysy_t* tysy;
err_t* err;
struct {
int id_counter;
size_t size;
size_t cap;
sym_entry_t** data;
} entries;
} sym_t;
void sym_init(sym_t* sym, tysy_t* tysy, err_t* err);
void sym_free(sym_t* sym);
int sym_declare(sym_t* sym, char* name, type_t* type);
sym_entry_t* sym_try_find_by_name(sym_t* sym, char* name);
size_t sym_str(sym_t* sym, char* buffer, size_t size);
#endif

View File

@ -20,3 +20,12 @@ int type_eq(type_t* type, type_t* rhs)
return type->kind == rhs->kind;
}
size_t type_str(type_t* type, char* buffer, size_t size)
{
assert(type);
assert(buffer);
return snprintf(buffer, size, "%s",
TypeKindStr[type->kind] + strlen("TYPE_"));
}

View File

@ -16,5 +16,6 @@ void type_init(type_t* type, TypeKind kind);
void type_free(type_t* type);
int type_eq(type_t* type, type_t* rhs);
size_t type_str(type_t* type, char* buffer, size_t size);
#endif

118
lib/tysolver.c Normal file
View File

@ -0,0 +1,118 @@
#include "tysolver.h"
#include "lib/tysy.h"
void tysolver_init(tysolver_t* tysolver, sym_t* sym, tysy_t* tysy)
{
assert(tysolver);
assert(sym);
assert(tysy);
tysolver->sym = sym;
tysolver->tysy = tysy;
}
void tysolver_free(tysolver_t* tysolver)
{
assert(tysolver);
}
/*
#define NODE_TYPE(G) \
G(NODE_MOD), \
G(NODE_LET), G(NODE_IDENT), G(NODE_ASSIGN), G(NODE_VARDECL)
*/
type_t* tysolver_try_solve_node(tysolver_t* tysolver, node_t* node)
{
assert(tysolver);
assert(node);
switch (node->type)
{
case NODE_VARDECL: {
return tysolver_try_solve_node(tysolver,
(node_t*) node->children.data[1]);
} break;
case NODE_IDENT: {
char* name = node->value.data;
sym_entry_t* entry = sym_try_find_by_name(tysolver->sym, name);
assert(entry);
return entry->type;
} break;
case NODE_SUB:
case NODE_DIV:
case NODE_MODULO:
case NODE_POW:
case NODE_NUM: {
type_t* ty = tysy_try_find_type(tysolver->tysy, "num");
assert(ty);
return ty;
} break;
case NODE_ADD: {
return tysolver_try_solve_node(tysolver,
(node_t*) node->children.data[0]);
} break;
case NODE_MUL: {
type_t* lhs = tysolver_try_solve_node(tysolver,
(node_t*) node->children.data[0]);
type_t* rhs = tysolver_try_solve_node(tysolver,
(node_t*) node->children.data[1]);
if (type_eq(lhs, rhs) && lhs->kind == TYPE_NUM)
{
return tysolver_try_solve_node(tysolver,
(node_t*) node->children.data[0]);
}
else if ((lhs->kind == TYPE_NUM && rhs->kind == TYPE_STR)
|| (rhs->kind == TYPE_NUM && lhs->kind == TYPE_STR))
{
return tysy_try_find_type(tysolver->tysy, "str");
}
else
{
tysolver_error(tysolver, node);
}
} break;
case NODE_ASSERT:
case NODE_EQ:
case NODE_NE:
case NODE_LT:
case NODE_LE:
case NODE_GT:
case NODE_GE:
case NODE_AND:
case NODE_OR:
case NODE_NOT:
case NODE_BOOL: {
type_t* ty = tysy_try_find_type(tysolver->tysy, "bool");
assert(ty);
return ty;
} break;
case NODE_STR: {
type_t* ty = tysy_try_find_type(tysolver->tysy, "str");
assert(ty);
return ty;
} break;
default: {
tysolver_error(tysolver, node);
} break;
}
return NULL;
}
void tysolver_error(tysolver_t* tysolver, node_t* node)
{
fprintf(stderr, "Cannot solve type of '%s'.\n",
NodeTypeStr[node->type]);
abort();
}

20
lib/tysolver.h Normal file
View File

@ -0,0 +1,20 @@
#ifndef RZ_TYSOLVER_H
#define RZ_TYSOLVER_H
#include "commons.h"
#include "tysy.h"
#include "node.h"
#include "sym.h"
typedef struct {
sym_t* sym;
tysy_t* tysy;
} tysolver_t;
void tysolver_init(tysolver_t* tysolver, sym_t* sym, tysy_t* tysy);
void tysolver_free(tysolver_t* tysolver);
type_t* tysolver_try_solve_node(tysolver_t* tysolver, node_t* node);
void tysolver_error(tysolver_t* tysolver, node_t* node);
#endif

250
lib/vm.c
View File

@ -4,13 +4,14 @@
#include "lib/type.h"
#include "lib/tysy.h"
void vm_init(vm_t* vm, tysy_t* tysy, err_t* err)
void vm_init(vm_t* vm, sym_t* sym, tysy_t* tysy, err_t* err)
{
assert(vm);
assert(sym);
assert(tysy);
vm->pc = 0;
vm->bp = 0;
vm->sp = 0;
vm->top_frame = NULL;
vm_frame_push(vm);
vm->tysy = tysy;
vm->err = err;
@ -19,6 +20,125 @@ void vm_init(vm_t* vm, tysy_t* tysy, err_t* err)
void vm_free(vm_t* vm)
{
assert(vm);
while (vm_frame_pop(vm))
{
}
vm->top_frame = NULL;
}
void vm_frame_init(frame_t* frame)
{
assert(frame);
frame->pc = 0;
frame->bp = 0;
frame->sp = 0;
frame->prev = NULL;
frame->locals.cap = 0;
frame->locals.size = 0;
frame->locals.data = NULL;
}
void vm_frame_free(frame_t* frame)
{
for (size_t i=0; i<frame->locals.size; i++)
{
free(frame->locals.data[i]);
}
free(frame->locals.data);
frame->locals.data = NULL;
frame->locals.size = 0;
frame->locals.cap = 0;
if (frame->prev != NULL)
{
vm_frame_free((frame_t*) frame->prev);
frame->prev = NULL;
}
}
void vm_frame_push(vm_t* vm)
{
assert(vm);
frame_t* frame = malloc(sizeof(frame_t));
vm_frame_init(frame);
frame->prev = (struct frame*) vm->top_frame;
vm->top_frame = frame;
}
int vm_frame_pop(vm_t* vm)
{
assert(vm);
if (vm->top_frame)
{
frame_t* frame = vm->top_frame;
vm->top_frame = (frame_t*) vm->top_frame->prev;
vm_frame_free(frame);
free(frame);
return 1;
}
return 0;
}
local_t* vm_try_local_load(vm_t* vm, int id)
{
assert(vm);
for (size_t i=0; i<vm->top_frame->locals.size; i++)
{
if (vm->top_frame->locals.data[i]->id == id)
{
return vm->top_frame->locals.data[i];
}
}
return NULL;
}
void vm_local_store(vm_t* vm, int id, param_t addr)
{
assert(vm);
local_t* loc = vm_try_local_load(vm, id);
if (!loc)
{
if (vm->top_frame->locals.data == NULL)
{
vm->top_frame->locals.cap = 2;
vm->top_frame->locals.data = malloc(sizeof(local_t*)
* vm->top_frame->locals.cap);
}
if (vm->top_frame->locals.size >= vm->top_frame->locals.cap)
{
vm->top_frame->locals.cap *= 2;
vm->top_frame->locals.data = realloc(vm->top_frame->locals.data,
sizeof(local_t*)
* vm->top_frame->locals.cap);
}
vm->top_frame->locals.data[vm->top_frame->locals.size]
= malloc(sizeof(local_t));
vm->top_frame->locals.data[vm->top_frame->locals.size]->id = id;
vm->top_frame->locals.data[vm->top_frame->locals.size]->addr = addr;
vm->top_frame->locals.size++;
}
else
{
loc->id = id;
loc->addr = addr;
}
}
void vm_push_new_value(vm_t* vm, mod_t* mod, value_t* value)
@ -33,18 +153,18 @@ void vm_push_new_value(vm_t* vm, mod_t* mod, value_t* value)
void vm_push(vm_t* vm, param_t param)
{
assert(vm);
assert(vm->sp + 1 < RZ_STACK_LIMIT);
assert(vm->top_frame->sp + 1 < RZ_STACK_LIMIT);
vm->stack[vm->sp] = param;
vm->sp++;
vm->top_frame->stack[vm->top_frame->sp] = param;
vm->top_frame->sp++;
}
param_t vm_pop(vm_t* vm)
{
assert(vm);
assert(vm->sp > 0);
param_t param = vm->stack[vm->sp - 1];
vm->sp--;
assert(vm->top_frame->sp > 0);
param_t param = vm->top_frame->stack[vm->top_frame->sp - 1];
vm->top_frame->sp--;
return param;
}
@ -56,9 +176,15 @@ size_t vm_stack_str(vm_t* vm, char* buffer, size_t size)
size_t sz = 0;
for (size_t i=0; i<vm->sp; i++)
if (vm->top_frame->sp == 0)
{
sz += snprintf(buffer + sz, size - sz, "| %d |\n", vm->stack[vm->sp - 1 - i]);
sz += snprintf(buffer + sz, size - sz, "** empty **\n");
return sz;
}
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]);
}
return sz;
@ -67,14 +193,14 @@ size_t vm_stack_str(vm_t* vm, char* buffer, size_t size)
int vm_exec_mod(vm_t* vm, mod_t* mod)
{
assert(vm);
vm->pc = 0;
vm->top_frame->pc = 0;
while (vm->pc < mod->program.size)
while (vm->top_frame->pc < mod->program.size)
{
int status = vm_exec_instr(vm,
mod,
mod->program.ops[vm->pc],
mod->program.params[vm->pc]);
mod->program.ops[vm->top_frame->pc],
mod->program.params[vm->top_frame->pc]);
if (status != 0)
{
@ -91,17 +217,16 @@ int vm_exec_instr(vm_t* vm, mod_t* mod, Opcode op, param_t param)
switch (op)
{
case OP_PUSH: {
if (vm->sp + 1 >= RZ_STACK_LIMIT)
if (vm->top_frame->sp + 1 >= RZ_STACK_LIMIT)
{
fprintf(stderr, "Stack overflow\n");
abort();
}
vm->stack[vm->sp] = param;
vm->sp++;
vm->pc++;
vm->top_frame->stack[vm->top_frame->sp] = param;
vm->top_frame->sp++;
vm->top_frame->pc++;
} break;
case OP_ASSERT: {
@ -112,7 +237,7 @@ int vm_exec_instr(vm_t* vm, mod_t* mod, Opcode op, param_t param)
{
vm_ensure_type(vm, value, TYPE_BOOL);
vm->pc++;
vm->top_frame->pc++;
break;
}
@ -123,7 +248,8 @@ int vm_exec_instr(vm_t* vm, mod_t* mod, Opcode op, param_t param)
return -1;
}
vm->pc++;
vm_push(vm, top);
vm->top_frame->pc++;
} break;
@ -148,7 +274,7 @@ int vm_exec_instr(vm_t* vm, mod_t* mod, Opcode op, param_t param)
vm_push_new_value(vm, mod, res);
vm->pc++;
vm->top_frame->pc++;
} break;
case OP_LT:
@ -178,7 +304,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->pc++;
vm->top_frame->pc++;
} break;
case OP_ADD:
@ -212,7 +338,7 @@ 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->pc++;
vm->top_frame->pc++;
} break;
case OP_STRCAT: {
@ -235,7 +361,7 @@ int vm_exec_instr(vm_t* vm, mod_t* mod, Opcode op, param_t param)
vm_push_new_value(vm, mod, value);
vm->pc++;
vm->top_frame->pc++;
} break;
case OP_STRDUP: {
@ -268,33 +394,7 @@ int vm_exec_instr(vm_t* vm, mod_t* mod, Opcode op, param_t param)
vm_push_new_value(vm, mod, value);
vm->pc++;
} break;
case OP_AND:
case OP_OR: {
int r = vm_pop(vm);
int l = vm_pop(vm);
value_t* lhs = mod->values.data[l];
value_t* rhs = mod->values.data[r];
vm_ensure_type(vm, lhs, TYPE_BOOL);
vm_ensure_type(vm, rhs, TYPE_BOOL);
int val = 0;
switch (op)
{
case OP_AND: val = lhs->value.bool && rhs->value.bool; break;
case OP_OR: val = lhs->value.bool || rhs->value.bool; break;
default: assert(0); break;
}
value_t* res = tysy_new_bool(vm->tysy, val, lhs->line);
vm_push_new_value(vm, mod, res);
vm->pc++;
vm->top_frame->pc++;
} break;
case OP_USUB: {
@ -309,7 +409,7 @@ 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->pc++;
vm->top_frame->pc++;
} break;
case OP_NOT: {
@ -322,7 +422,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->pc++;
vm->top_frame->pc++;
} break;
case OP_BRT:
@ -333,21 +433,51 @@ int vm_exec_instr(vm_t* vm, mod_t* mod, Opcode op, param_t param)
if (op == OP_BRT && value->value.bool)
{
vm->pc = param;
vm->top_frame->pc = param;
}
else if (op == OP_BRF && !value->value.bool)
{
vm->pc = param;
vm->top_frame->pc = param;
}
else
{
vm->pc++;
vm->top_frame->pc++;
}
} break;
case OP_BR: {
vm->pc = param;
vm->top_frame->pc = param;
} break;
case OP_LOAD: {
local_t* local = vm_try_local_load(vm, param);
if (!local)
{
char msg[RZ_STR_LIMIT];
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;
err_fatal(vm->err, msg, line);
err_dump(vm->err);
}
else
{
vm_push(vm, vm->top_frame->stack[local->addr]);
}
vm->top_frame->pc++;
} break;
case OP_STORE: {
assert(vm->top_frame->sp > 0);
vm_local_store(vm, param, vm->top_frame->sp - 1);
vm->top_frame->pc++;
} break;
default: {

View File

@ -6,20 +6,47 @@
#include "mod.h"
#include "err.h"
#include "tysy.h"
#include "sym.h"
typedef struct {
tysy_t* tysy;
int id;
param_t addr;
} local_t;
typedef struct stack_frame{
struct frame* prev;
param_t stack[RZ_STACK_LIMIT];
size_t pc;
size_t bp;
size_t sp;
struct {
size_t size;
size_t cap;
local_t** data;
} locals;
} frame_t;
typedef struct {
sym_t* sym;
tysy_t* tysy;
err_t* err;
frame_t* top_frame;
} vm_t;
void vm_init(vm_t* vm, tysy_t* tysy, err_t* err);
void vm_init(vm_t* vm, sym_t* sym, tysy_t* tysy, err_t* err);
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);
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);

View File

@ -25,6 +25,7 @@ roza_lib = static_library(
# core
'lib/err.c',
'lib/loader.c',
'lib/sym.c',
# lang
'lib/node.c',
@ -33,6 +34,7 @@ roza_lib = static_library(
'lib/type.c',
'lib/value.c',
'lib/tysy.c',
'lib/tysolver.c',
# comp
'lib/opcodes.c',

View File

@ -0,0 +1,8 @@
# VARIABLE DECLARATIONS
# =====================
# simple
let x = 35
assert x == 35
let y = x + 2
assert y == 37

View File

@ -25,13 +25,14 @@ static void test_lexer_ko(char const* source)
lexer_t lex;
err_t err;
err_init(&err);
err.quiet = 1;
lexer_init(&lex, source, &err);
node_t* tok = lexer_try_new_next(&lex);
cr_assert(tok == NULL, "error -> %s", source);
cr_assert(err.size > 0);
cr_assert_gt(err.total, 0);
err_free(&err);
lexer_free(&lex);
@ -48,7 +49,7 @@ static void test_lexer(char const* source, size_t n, ...)
for (size_t i=0; i<n; i++)
{
node_t* tok = lexer_try_new_next(&lexer);
cr_assert(NULL != tok, "error -> %s", source);
cr_assert(NULL != tok, "error token %ld: %s", i, source);
size_t const SZ = 256;
char tok_str[SZ];
@ -83,10 +84,7 @@ Test(lexer, num) {
}
Test(lexer, bool) {
test_lexer_ko("true3");
test_lexer_ko("1true");
test_lexer_ko("afalse");
test_lexer_ko("falset");
test_lexer("true 3 false", 3,
"BOOL[true]",
@ -95,9 +93,6 @@ Test(lexer, bool) {
}
Test(lexer, str) {
test_lexer_ko("\"hello");
test_lexer_ko("hello\"");
test_lexer(" \"bonjour\" \" monde \"", 2,
"STR[bonjour]",
"STR[ monde ]");
@ -153,3 +148,11 @@ Test(lexer, bool_arith) {
"OR",
"NOT");
}
Test(lexer, let_var) {
test_lexer("let x = 3", 4,
"LET",
"IDENT[x]",
"ASSIGN",
"NUM[3]");
}

View File

@ -6,6 +6,7 @@ static void test_parser_ok(char const* oracle, char const* source)
{
err_t err;
err_init(&err);
err.quiet = 1;
lexer_t lex;
lexer_init(&lex, source, &err);
@ -35,6 +36,7 @@ static void test_parser_ko(char const* source)
{
err_t err;
err_init(&err);
err.quiet = 1;
lexer_t lex;
lexer_init(&lex, source, &err);
@ -45,7 +47,7 @@ static void test_parser_ko(char const* source)
node_t* node = parser_try_new_tree(&parser);
cr_assert(NULL == node);
cr_assert_gt(err.size, 0);
cr_assert_gt(err.total, 0);
parser_free(&parser);
lexer_free(&lex);
@ -99,3 +101,11 @@ Test(parser, bool_arith) {
test_parser_ok("MOD(ASSERT(AND(BOOL[true],BOOL[false])))",
" assert (true and false) ");
}
Test(parser, var_decl) {
test_parser_ok("MOD(VARDECL(IDENT[x],NUM[33]))",
" let x = 33 ");
test_parser_ok("MOD(VARDECL(IDENT[bim],MUL(NUM[3],NUM[6])))",
" let bim = 3 * 6 ");
}