Compare commits
2 Commits
f4eb33c76c
...
d3f90a5ed1
Author | SHA1 | Date |
---|---|---|
bog | d3f90a5ed1 | |
bog | 9c74cce2a4 |
|
@ -1,3 +1,6 @@
|
|||
MOD ::= EXPR*
|
||||
EXPR ::= BUILTIN
|
||||
EXPR ::=
|
||||
| ASSERT
|
||||
| BUILTIN
|
||||
ASSERT ::= assert EXPR
|
||||
BUILTIN ::= num | bool | str
|
||||
|
|
|
@ -32,7 +32,7 @@ void compiler_run(compiler_t* compiler, node_t* node)
|
|||
|
||||
case NODE_NUM: {
|
||||
double value = atof(node->value.data);
|
||||
value_t* val = tysy_new_num(compiler->tysy, value);
|
||||
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);
|
||||
|
||||
|
@ -42,7 +42,7 @@ void compiler_run(compiler_t* compiler, node_t* node)
|
|||
|
||||
case NODE_BOOL: {
|
||||
int value = strcmp(node->value.data, "true") == 0;
|
||||
value_t* val = tysy_new_bool(compiler->tysy, value);
|
||||
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);
|
||||
|
||||
|
@ -51,18 +51,24 @@ void compiler_run(compiler_t* compiler, node_t* node)
|
|||
|
||||
case NODE_STR: {
|
||||
char* value = node->value.data;
|
||||
value_t* val = tysy_new_str(compiler->tysy, value);
|
||||
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);
|
||||
|
||||
mod_push_instr(compiler->mod, 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);
|
||||
|
||||
} break;
|
||||
|
||||
default: {
|
||||
char msg[RZ_STR_LIMIT];
|
||||
snprintf(msg, RZ_STR_LIMIT, "Unknown node '%s'",
|
||||
NodeTypeStr[node->type]);
|
||||
err_error(compiler->err, msg, node->line);
|
||||
fprintf(stderr, "Cannot compile unknown node '%s'",
|
||||
NodeTypeStr[node->type]);
|
||||
abort();
|
||||
} break;
|
||||
}
|
||||
}
|
||||
|
|
34
lib/err.c
34
lib/err.c
|
@ -1,5 +1,7 @@
|
|||
#include "err.h"
|
||||
|
||||
RZ_ENUM_C(ErrType, ERR_TYPES);
|
||||
|
||||
void err_init(err_t* err)
|
||||
{
|
||||
assert(err);
|
||||
|
@ -19,7 +21,7 @@ void err_free(err_t* err)
|
|||
err->size = 0;
|
||||
}
|
||||
|
||||
void err_error(err_t* err, char* what, int line)
|
||||
void err_of_type(err_t* err, char* what, int line, ErrType type)
|
||||
{
|
||||
assert(err);
|
||||
assert(err->size + 1 < RZ_ERROR_STACK_SIZE);
|
||||
|
@ -27,21 +29,41 @@ void err_error(err_t* err, char* what, int line)
|
|||
err->errors[err->size] = malloc(sizeof(err_msg_t));
|
||||
err->errors[err->size]->what = strdup(what);
|
||||
err->errors[err->size]->line = line;
|
||||
err->errors[err->size]->type = type;
|
||||
err->size++;
|
||||
}
|
||||
|
||||
void err_abort(err_t* err)
|
||||
void err_fatal(err_t* err, char* what, int line)
|
||||
{
|
||||
err_of_type(err, what, line, ERR_FATAL);
|
||||
}
|
||||
|
||||
int err_dump(err_t* err)
|
||||
{
|
||||
assert(err);
|
||||
int is_fatal = 0;
|
||||
|
||||
for (size_t i=0; i<err->size; i++)
|
||||
{
|
||||
fprintf(stderr, "ERR(%d) %s\n",
|
||||
err->errors[i]->line,
|
||||
err->errors[i]->what);
|
||||
if (err->errors[i]->type == ERR_WARNING)
|
||||
{
|
||||
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);
|
||||
|
||||
is_fatal = 1;
|
||||
}
|
||||
}
|
||||
|
||||
err_free(err);
|
||||
err_init(err);
|
||||
|
||||
abort();
|
||||
return is_fatal;
|
||||
}
|
||||
|
|
12
lib/err.h
12
lib/err.h
|
@ -5,7 +5,13 @@
|
|||
|
||||
#include "commons.h"
|
||||
|
||||
#define ERR_TYPES(G) \
|
||||
G(ERR_WARNING), G(ERR_FATAL)
|
||||
|
||||
RZ_ENUM_H(ErrType, ERR_TYPES);
|
||||
|
||||
typedef struct {
|
||||
ErrType type;
|
||||
char* what;
|
||||
int line;
|
||||
} err_msg_t;
|
||||
|
@ -18,7 +24,9 @@ typedef struct {
|
|||
void err_init(err_t* err);
|
||||
void err_free(err_t* err);
|
||||
|
||||
void err_error(err_t* err, char* what, int line);
|
||||
void err_abort(err_t* err);
|
||||
void err_of_type(err_t* err, char* what, int line, ErrType type);
|
||||
void err_fatal(err_t* err, char* what, int line);
|
||||
|
||||
int err_dump(err_t* err);
|
||||
|
||||
#endif
|
||||
|
|
107
lib/lexer.c
107
lib/lexer.c
|
@ -1,6 +1,12 @@
|
|||
#include "lexer.h"
|
||||
#include "lib/commons.h"
|
||||
|
||||
#define RZ_KEYWORD(KW, NODE, VAL) \
|
||||
{ \
|
||||
node_t* kw = lexer_try_new_keyword(lexer, KW, NODE, VAL); \
|
||||
if (kw) { lexer_skip_spaces(lexer); return kw; } \
|
||||
}
|
||||
|
||||
void lexer_init(lexer_t* lexer, char const* source, err_t* err)
|
||||
{
|
||||
assert(lexer);
|
||||
|
@ -22,35 +28,23 @@ node_t* lexer_try_new_next(lexer_t* lexer)
|
|||
assert(lexer);
|
||||
size_t len = strlen(lexer->source);
|
||||
|
||||
// skip spaces
|
||||
{
|
||||
while (lexer->cursor < len
|
||||
&& isspace(lexer->source[lexer->cursor]))
|
||||
{
|
||||
if (lexer->source[lexer->cursor] == '\n')
|
||||
{
|
||||
lexer->line++;
|
||||
}
|
||||
|
||||
lexer->cursor++;
|
||||
}
|
||||
}
|
||||
lexer_skip_spaces(lexer);
|
||||
|
||||
// Keywords
|
||||
// ========
|
||||
{
|
||||
node_t* kw = lexer_try_new_keyword(lexer, "true", NODE_BOOL, 1);
|
||||
if (kw) { return kw; }
|
||||
}
|
||||
{
|
||||
node_t* kw = lexer_try_new_keyword(lexer, "false", NODE_BOOL, 1);
|
||||
if (kw) { return kw; }
|
||||
}
|
||||
RZ_KEYWORD("true", NODE_BOOL, 1);
|
||||
RZ_KEYWORD("false", NODE_BOOL, 1);
|
||||
RZ_KEYWORD("assert", NODE_ASSERT, 0);
|
||||
|
||||
// scan str
|
||||
{
|
||||
node_t* node = lexer_try_new_str(lexer);
|
||||
if (node) { return node; }
|
||||
|
||||
if (node)
|
||||
{
|
||||
lexer_skip_spaces(lexer);
|
||||
return node;
|
||||
}
|
||||
}
|
||||
|
||||
// scan num
|
||||
|
@ -94,6 +88,8 @@ node_t* lexer_try_new_next(lexer_t* lexer)
|
|||
str_free(&res_str);
|
||||
|
||||
lexer->cursor = cursor;
|
||||
|
||||
lexer_skip_spaces(lexer);
|
||||
return tok;
|
||||
}
|
||||
|
||||
|
@ -105,7 +101,7 @@ node_t* lexer_try_new_next(lexer_t* lexer)
|
|||
size_t const SZ = RZ_STR_LIMIT;
|
||||
char msg[SZ];
|
||||
snprintf(msg, SZ, "unexpected symbol '%c'", lexer->source[lexer->cursor]);
|
||||
err_error(lexer->err, msg, lexer->line);
|
||||
err_fatal(lexer->err, msg, lexer->line);
|
||||
}
|
||||
|
||||
return NULL;
|
||||
|
@ -117,7 +113,7 @@ NodeType lexer_peek(lexer_t* lexer, int lookahead)
|
|||
size_t cursor = lexer->cursor;
|
||||
int line = lexer->line;
|
||||
|
||||
NodeType type = 0;
|
||||
NodeType type = -1;
|
||||
|
||||
for (int i=0; i<lookahead; i++)
|
||||
{
|
||||
|
@ -129,6 +125,10 @@ NodeType lexer_peek(lexer_t* lexer, int lookahead)
|
|||
node_free(node);
|
||||
free(node);
|
||||
}
|
||||
else
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
lexer->cursor = cursor;
|
||||
|
@ -137,6 +137,24 @@ NodeType lexer_peek(lexer_t* lexer, int lookahead)
|
|||
return type;
|
||||
}
|
||||
|
||||
void lexer_skip_spaces(lexer_t* lexer)
|
||||
{
|
||||
assert(lexer);
|
||||
size_t len = strlen(lexer->source);
|
||||
|
||||
while (lexer->cursor < len
|
||||
&& isspace(lexer->source[lexer->cursor]))
|
||||
{
|
||||
if (lexer->source[lexer->cursor] == '\n')
|
||||
{
|
||||
lexer->line++;
|
||||
}
|
||||
|
||||
lexer->cursor++;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
node_t* lexer_try_new_keyword(lexer_t* lexer, char* kw,
|
||||
NodeType type, int has_value)
|
||||
{
|
||||
|
@ -184,8 +202,8 @@ node_t* lexer_try_new_str(lexer_t* lexer)
|
|||
{
|
||||
assert(lexer);
|
||||
|
||||
size_t cursor = lexer->cursor;
|
||||
size_t len = strlen(lexer->source);
|
||||
ssize_t cursor = lexer->cursor;
|
||||
ssize_t len = strlen(lexer->source);
|
||||
|
||||
str_t res_str;
|
||||
str_init(&res_str);
|
||||
|
@ -201,8 +219,41 @@ node_t* lexer_try_new_str(lexer_t* lexer)
|
|||
while (cursor < len
|
||||
&& lexer->source[cursor] != '"')
|
||||
{
|
||||
str_push(&res_str, lexer->source[cursor]);
|
||||
cursor++;
|
||||
if (lexer->source[cursor] == '\\')
|
||||
{
|
||||
if (cursor + 1 < len)
|
||||
{
|
||||
switch (lexer->source[cursor + 1])
|
||||
{
|
||||
case '"': {
|
||||
str_push(&res_str, '"');
|
||||
cursor += 2;
|
||||
} break;
|
||||
|
||||
case 'n': {
|
||||
str_push(&res_str, '\n');
|
||||
cursor += 2;
|
||||
} break;
|
||||
|
||||
case 't': {
|
||||
str_push(&res_str, '\t');
|
||||
cursor += 2;
|
||||
} break;
|
||||
|
||||
case 'r': {
|
||||
str_push(&res_str, '\r');
|
||||
cursor += 2;
|
||||
} break;
|
||||
|
||||
default: cursor++; break;
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
str_push(&res_str, lexer->source[cursor]);
|
||||
cursor++;
|
||||
}
|
||||
}
|
||||
|
||||
if (cursor >= len || lexer->source[cursor] != '"')
|
||||
|
|
|
@ -17,6 +17,7 @@ void lexer_free(lexer_t* lexer);
|
|||
|
||||
node_t* lexer_try_new_next(lexer_t* lexer);
|
||||
NodeType lexer_peek(lexer_t* lexer, int lookahead);
|
||||
void lexer_skip_spaces(lexer_t* lexer);
|
||||
|
||||
node_t* lexer_try_new_keyword(lexer_t* lexer, char* kw,
|
||||
NodeType type, int has_value);
|
||||
|
|
39
lib/loader.c
39
lib/loader.c
|
@ -2,6 +2,7 @@
|
|||
#include "parser.h"
|
||||
#include "loader.h"
|
||||
#include "compiler.h"
|
||||
#include "prepass.h"
|
||||
#include "mod.h"
|
||||
#include "vm.h"
|
||||
|
||||
|
@ -67,20 +68,41 @@ void loader_ldfile(loader_t* loader, char const* path, int debug)
|
|||
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);
|
||||
}
|
||||
|
||||
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();
|
||||
}
|
||||
|
||||
// execute
|
||||
{
|
||||
vm_t vm;
|
||||
vm_init(&vm);
|
||||
vm_init(&vm, &err);
|
||||
|
||||
vm_exec_mod(&vm, &mod);
|
||||
|
||||
|
@ -110,15 +132,14 @@ void loader_ldfile(loader_t* loader, char const* path, int debug)
|
|||
parser_free(&parser);
|
||||
lexer_free(&lex);
|
||||
str_free(&source);
|
||||
tysy_free(&tysy);
|
||||
|
||||
if (err.size > 0)
|
||||
{
|
||||
err_abort(&err);
|
||||
}
|
||||
else
|
||||
// check execution errors
|
||||
if (err_dump(&err))
|
||||
{
|
||||
err_free(&err);
|
||||
abort();
|
||||
}
|
||||
|
||||
tysy_free(&tysy);
|
||||
err_free(&err);
|
||||
}
|
||||
|
|
18
lib/mod.c
18
lib/mod.c
|
@ -1,4 +1,5 @@
|
|||
#include "mod.h"
|
||||
#include "lib/commons.h"
|
||||
|
||||
void mod_init(mod_t* mod)
|
||||
{
|
||||
|
@ -74,10 +75,19 @@ size_t mod_str(mod_t* mod, char* buffer, size_t size)
|
|||
sz += snprintf(buffer + sz, size - sz, "\n======== PROGRAM ========\n");
|
||||
for (size_t i=0; i<mod->program.size; i++)
|
||||
{
|
||||
sz += snprintf(buffer + sz, size - sz, "%d| %s %d\n",
|
||||
(int) i,
|
||||
OpcodeStr[mod->program.ops[i]] + strlen("OP_"),
|
||||
mod->program.params[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;
|
||||
|
|
10
lib/node.c
10
lib/node.c
|
@ -34,7 +34,7 @@ void node_free(node_t* node)
|
|||
node->children.cap = 0;
|
||||
}
|
||||
|
||||
void node_add_child(node_t* node, node_t* child)
|
||||
void node_add_new_child(node_t* node, node_t* child)
|
||||
{
|
||||
assert(node);
|
||||
assert(child);
|
||||
|
@ -57,6 +57,14 @@ void node_add_child(node_t* node, node_t* child)
|
|||
node->children.size++;
|
||||
}
|
||||
|
||||
node_t* node_child(node_t* node, size_t index)
|
||||
{
|
||||
assert(node);
|
||||
assert(index < node->children.size);
|
||||
|
||||
return (node_t*) node->children.data[index];
|
||||
}
|
||||
|
||||
size_t node_str(node_t* node, char* buffer, size_t size)
|
||||
{
|
||||
assert(node);
|
||||
|
|
|
@ -5,9 +5,8 @@
|
|||
|
||||
#define NODE_TYPE(G) \
|
||||
G(NODE_MOD), \
|
||||
G(NODE_NUM), \
|
||||
G(NODE_BOOL), \
|
||||
G(NODE_STR)
|
||||
G(NODE_NUM), G(NODE_BOOL), G(NODE_STR), \
|
||||
G(NODE_ASSERT)
|
||||
|
||||
RZ_ENUM_H(NodeType, NODE_TYPE);
|
||||
|
||||
|
@ -26,7 +25,8 @@ typedef struct {
|
|||
void node_init(node_t* node, NodeType type, char* value, int line);
|
||||
void node_free(node_t* node);
|
||||
|
||||
void node_add_child(node_t* node, node_t* child);
|
||||
void node_add_new_child(node_t* node, node_t* child);
|
||||
node_t* node_child(node_t* node, size_t index);
|
||||
|
||||
size_t node_str(node_t* node, char* buffer, size_t size);
|
||||
|
||||
|
|
|
@ -4,7 +4,7 @@
|
|||
#include "commons.h"
|
||||
|
||||
#define OPCODES(G) \
|
||||
G(OP_HALT), \
|
||||
G(OP_ASSERT), \
|
||||
G(OP_PUSH), G(OP_POP)
|
||||
|
||||
RZ_ENUM_H(Opcode, OPCODES);
|
||||
|
|
29
lib/parser.c
29
lib/parser.c
|
@ -33,7 +33,7 @@ node_t* parser_try_new_mod(parser_t* parser)
|
|||
|
||||
if (expr)
|
||||
{
|
||||
node_add_child(mod, expr);
|
||||
node_add_new_child(mod, expr);
|
||||
}
|
||||
else
|
||||
{
|
||||
|
@ -49,9 +49,34 @@ node_t* parser_try_new_mod(parser_t* parser)
|
|||
node_t* parser_try_new_expr(parser_t* parser)
|
||||
{
|
||||
assert(parser);
|
||||
NodeType type = lexer_peek(parser->lexer, 1);
|
||||
|
||||
if (type == -1)
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (type == NODE_ASSERT)
|
||||
{
|
||||
return parser_try_new_assert(parser);
|
||||
}
|
||||
|
||||
return parser_try_new_builtin(parser);
|
||||
}
|
||||
|
||||
node_t* parser_try_new_assert(parser_t* parser)
|
||||
{
|
||||
assert(parser);
|
||||
node_t* node = parser_try_new_consume(parser, NODE_ASSERT);
|
||||
assert(node);
|
||||
|
||||
node_t* expr = parser_try_new_expr(parser);
|
||||
assert(expr);
|
||||
node_add_new_child(node, expr);
|
||||
|
||||
return node;
|
||||
}
|
||||
|
||||
node_t* parser_try_new_builtin(parser_t* parser)
|
||||
{
|
||||
assert(parser);
|
||||
|
@ -80,7 +105,7 @@ node_t* parser_try_new_consume(parser_t* parser, NodeType type)
|
|||
size_t const SZ = RZ_STR_LIMIT;
|
||||
char err_msg[SZ];
|
||||
snprintf(err_msg, SZ, "unexpected node '%s'", NodeTypeStr[next->type]);
|
||||
err_error(parser->err, err_msg, next->line);
|
||||
err_fatal(parser->err, err_msg, next->line);
|
||||
node_free(next);
|
||||
free(next);
|
||||
return NULL;
|
||||
|
|
|
@ -16,6 +16,7 @@ void parser_free(parser_t* parser);
|
|||
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_builtin(parser_t* parser);
|
||||
|
||||
node_t* parser_try_new_consume(parser_t* parser, NodeType type);
|
||||
|
|
|
@ -0,0 +1,40 @@
|
|||
#include "prepass.h"
|
||||
|
||||
void prepass_init(prepass_t* prepass, err_t* err)
|
||||
{
|
||||
assert(prepass);
|
||||
assert(err);
|
||||
|
||||
prepass->err = err;
|
||||
}
|
||||
|
||||
void prepass_free(prepass_t* prepass)
|
||||
{
|
||||
assert(prepass);
|
||||
}
|
||||
|
||||
void prepass_run(prepass_t* prepass, node_t* node)
|
||||
{
|
||||
assert(prepass);
|
||||
assert(node);
|
||||
|
||||
switch (node->type)
|
||||
{
|
||||
case NODE_MOD:
|
||||
case NODE_NUM:
|
||||
case NODE_STR:
|
||||
case NODE_BOOL:
|
||||
case NODE_ASSERT:{
|
||||
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;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,17 @@
|
|||
#ifndef RZ_PREPASS_H
|
||||
#define RZ_PREPASS_H
|
||||
|
||||
#include "commons.h"
|
||||
#include "err.h"
|
||||
#include "node.h"
|
||||
|
||||
typedef struct {
|
||||
err_t* err;
|
||||
} prepass_t;
|
||||
|
||||
void prepass_init(prepass_t* prepass, err_t* err);
|
||||
void prepass_free(prepass_t* prepass);
|
||||
|
||||
void prepass_run(prepass_t* prepass, node_t* node);
|
||||
|
||||
#endif
|
12
lib/tysy.c
12
lib/tysy.c
|
@ -69,34 +69,34 @@ type_t* tysy_try_find_type(tysy_t* tysy, char* name)
|
|||
return NULL;
|
||||
}
|
||||
|
||||
value_t* tysy_new_num(tysy_t* tysy, double value)
|
||||
value_t* tysy_new_num(tysy_t* tysy, double value, int line)
|
||||
{
|
||||
assert(tysy);
|
||||
|
||||
value_t* val = malloc(sizeof(value_t));
|
||||
value_init(val, tysy_try_find_type(tysy, "num"));
|
||||
value_init(val, tysy_try_find_type(tysy, "num"), line);
|
||||
val->value.num = value;
|
||||
|
||||
return val;
|
||||
}
|
||||
|
||||
value_t* tysy_new_bool(tysy_t* tysy, int value)
|
||||
value_t* tysy_new_bool(tysy_t* tysy, int value, int line)
|
||||
{
|
||||
assert(tysy);
|
||||
|
||||
value_t* val = malloc(sizeof(value_t));
|
||||
value_init(val, tysy_try_find_type(tysy, "bool"));
|
||||
value_init(val, tysy_try_find_type(tysy, "bool"), line);
|
||||
val->value.bool = value;
|
||||
|
||||
return val;
|
||||
}
|
||||
|
||||
value_t* tysy_new_str(tysy_t* tysy, char* value)
|
||||
value_t* tysy_new_str(tysy_t* tysy, char* value, int line)
|
||||
{
|
||||
assert(tysy);
|
||||
|
||||
value_t* val = malloc(sizeof(value_t));
|
||||
value_init(val, tysy_try_find_type(tysy, "str"));
|
||||
value_init(val, tysy_try_find_type(tysy, "str"), line);
|
||||
val->value.str = strdup(value);
|
||||
|
||||
return val;
|
||||
|
|
|
@ -16,8 +16,8 @@ void tysy_free(tysy_t* tysy);
|
|||
void tysy_register_new_type(tysy_t* tysy, char* name, type_t* type);
|
||||
type_t* tysy_try_find_type(tysy_t* tysy, char* name);
|
||||
|
||||
value_t* tysy_new_num(tysy_t* tysy, double value);
|
||||
value_t* tysy_new_bool(tysy_t* tysy, int value);
|
||||
value_t* tysy_new_str(tysy_t* tysy, char* value);
|
||||
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);
|
||||
|
||||
#endif
|
||||
|
|
|
@ -1,11 +1,12 @@
|
|||
#include "value.h"
|
||||
|
||||
void value_init(value_t* value, type_t* type)
|
||||
void value_init(value_t* value, type_t* type, int line)
|
||||
{
|
||||
assert(value);
|
||||
assert(type);
|
||||
|
||||
value->type = type;
|
||||
value->line = line;
|
||||
}
|
||||
|
||||
void value_free(value_t* value)
|
||||
|
|
|
@ -12,9 +12,10 @@ typedef struct {
|
|||
char* str;
|
||||
} value;
|
||||
|
||||
int line;
|
||||
} value_t;
|
||||
|
||||
void value_init(value_t* value, type_t* type);
|
||||
void value_init(value_t* value, type_t* type, int line);
|
||||
void value_free(value_t* value);
|
||||
|
||||
int value_eq(value_t* value, value_t* rhs);
|
||||
|
|
58
lib/vm.c
58
lib/vm.c
|
@ -1,13 +1,16 @@
|
|||
#include "vm.h"
|
||||
#include "lib/commons.h"
|
||||
#include "lib/type.h"
|
||||
|
||||
void vm_init(vm_t* vm)
|
||||
void vm_init(vm_t* vm, err_t* err)
|
||||
{
|
||||
assert(vm);
|
||||
|
||||
vm->pc = 0;
|
||||
vm->bp = 0;
|
||||
vm->sp = 0;
|
||||
|
||||
vm->err = err;
|
||||
}
|
||||
|
||||
void vm_free(vm_t* vm)
|
||||
|
@ -15,6 +18,16 @@ void vm_free(vm_t* vm)
|
|||
assert(vm);
|
||||
}
|
||||
|
||||
param_t vm_pop(vm_t* vm)
|
||||
{
|
||||
assert(vm);
|
||||
assert(vm->sp > 0);
|
||||
param_t param = vm->stack[vm->sp - 1];
|
||||
vm->sp--;
|
||||
|
||||
return param;
|
||||
}
|
||||
|
||||
size_t vm_stack_str(vm_t* vm, char* buffer, size_t size)
|
||||
{
|
||||
assert(vm);
|
||||
|
@ -37,12 +50,19 @@ void vm_exec_mod(vm_t* vm, mod_t* mod)
|
|||
|
||||
while (vm->pc < mod->program.size)
|
||||
{
|
||||
vm_exec_instr(vm, mod->program.ops[vm->pc],
|
||||
mod->program.params[vm->pc]);
|
||||
int status = vm_exec_instr(vm,
|
||||
mod,
|
||||
mod->program.ops[vm->pc],
|
||||
mod->program.params[vm->pc]);
|
||||
|
||||
if (!status)
|
||||
{
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void vm_exec_instr(vm_t* vm, Opcode op, param_t param)
|
||||
int vm_exec_instr(vm_t* vm, mod_t* mod, Opcode op, param_t param)
|
||||
{
|
||||
assert(vm);
|
||||
|
||||
|
@ -61,10 +81,40 @@ void vm_exec_instr(vm_t* vm, Opcode op, param_t param)
|
|||
vm->pc++;
|
||||
} break;
|
||||
|
||||
case OP_ASSERT: {
|
||||
param_t top = vm_pop(vm);
|
||||
value_t* value = mod->values.data[top];
|
||||
|
||||
if (value->type->kind != TYPE_BOOL)
|
||||
{
|
||||
char msg[RZ_STR_LIMIT];
|
||||
snprintf(msg, RZ_STR_LIMIT,
|
||||
"type mismatch: BOOL expected, got %s.",
|
||||
TypeKindStr[value->type->kind] + strlen("TYPE_"));
|
||||
|
||||
err_fatal(vm->err, msg, value->line);
|
||||
|
||||
vm->pc++;
|
||||
break;
|
||||
}
|
||||
|
||||
if (!value->value.bool)
|
||||
{
|
||||
fprintf(stderr, "\33[31mASSERT\33[0m[:%d] assertion failed\n",
|
||||
value->line);
|
||||
return 0;
|
||||
}
|
||||
|
||||
vm->pc++;
|
||||
|
||||
} break;
|
||||
|
||||
default: {
|
||||
fprintf(stderr, "Cannot execute unknown opcode '%s'.\n",
|
||||
OpcodeStr[op]);
|
||||
abort();
|
||||
};
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
|
9
lib/vm.h
9
lib/vm.h
|
@ -4,20 +4,25 @@
|
|||
#include "commons.h"
|
||||
#include "opcodes.h"
|
||||
#include "mod.h"
|
||||
#include "err.h"
|
||||
|
||||
typedef struct {
|
||||
param_t stack[RZ_STACK_LIMIT];
|
||||
size_t pc;
|
||||
size_t bp;
|
||||
size_t sp;
|
||||
|
||||
err_t* err;
|
||||
} vm_t;
|
||||
|
||||
void vm_init(vm_t* vm);
|
||||
void vm_init(vm_t* vm, err_t* err);
|
||||
void vm_free(vm_t* vm);
|
||||
|
||||
param_t vm_pop(vm_t* vm);
|
||||
|
||||
size_t vm_stack_str(vm_t* vm, char* buffer, size_t size);
|
||||
|
||||
void vm_exec_mod(vm_t* vm, mod_t* mod);
|
||||
void vm_exec_instr(vm_t* vm, Opcode op, param_t param);
|
||||
int vm_exec_instr(vm_t* vm, mod_t* mod, Opcode op, param_t param);
|
||||
|
||||
#endif
|
||||
|
|
|
@ -34,6 +34,7 @@ roza_lib = static_library(
|
|||
# comp
|
||||
'lib/opcodes.c',
|
||||
'lib/mod.c',
|
||||
'lib/prepass.c',
|
||||
'lib/compiler.c',
|
||||
|
||||
# exec
|
||||
|
|
|
@ -55,7 +55,7 @@ static void test_lexer(char const* source, size_t n, ...)
|
|||
node_str(tok, tok_str, SZ);
|
||||
|
||||
char* oracle = va_arg(lst, char*);
|
||||
cr_assert_str_eq(oracle, tok_str);
|
||||
cr_assert_str_eq(tok_str, oracle);
|
||||
|
||||
node_free(tok);
|
||||
}
|
||||
|
@ -101,4 +101,11 @@ Test(lexer, str) {
|
|||
test_lexer(" \"bonjour\" \" monde \"", 2,
|
||||
"STR[bonjour]",
|
||||
"STR[ monde ]");
|
||||
|
||||
test_lexer("\"the \\\"cat\\\"\"", 1, "STR[the \"cat\"]");
|
||||
test_lexer("\"hello\\n\\tworld\"", 1, "STR[hello\n\tworld]");
|
||||
}
|
||||
|
||||
Test(lexer, assert) {
|
||||
test_lexer("assert", 1, "ASSERT");
|
||||
}
|
||||
|
|
|
@ -66,3 +66,8 @@ Test(parser, bool) {
|
|||
Test(parser, str) {
|
||||
test_parser_ok("MOD(STR[bim bam bum])", " \"bim bam bum\"");
|
||||
}
|
||||
|
||||
Test(parser, assert) {
|
||||
test_parser_ok("MOD(ASSERT(BOOL[false]))", " assert false ");
|
||||
test_parser_ok("MOD(ASSERT(BOOL[true]))", " assert true ");
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue