✨ num literals.
parent
e434d5c4ae
commit
46dc8b8c2d
9
Makefile
9
Makefile
|
@ -7,13 +7,16 @@ build:
|
||||||
tests: build
|
tests: build
|
||||||
build/roza-tests
|
build/roza-tests
|
||||||
|
|
||||||
install: build
|
install: tests
|
||||||
meson install -C build
|
meson install -C build
|
||||||
|
|
||||||
check:
|
check:
|
||||||
@cppcheck --language=c --enable=all lib src -q \
|
@cppcheck --language=c --enable=all lib src -q \
|
||||||
--suppress=missingIncludeSystem
|
--suppress=missingIncludeSystem \
|
||||||
|
--suppress=missingInclude \
|
||||||
|
--suppress=unmatchedSuppression
|
||||||
|
|
||||||
@cppcheck --language=c --enable=all tests/units -q \
|
@cppcheck --language=c --enable=all tests/units -q \
|
||||||
--suppress=missingIncludeSystem \
|
--suppress=missingIncludeSystem \
|
||||||
--suppress=unusedFunction
|
--suppress=unusedFunction \
|
||||||
|
--suppress=unmatchedSuppression
|
||||||
|
|
|
@ -0,0 +1,2 @@
|
||||||
|
MOD ::= EXPR*
|
||||||
|
EXPR ::= num
|
|
@ -0,0 +1,30 @@
|
||||||
|
#ifndef RZ_COMMONS_H
|
||||||
|
#define RZ_COMMONS_H
|
||||||
|
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <assert.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <ctype.h>
|
||||||
|
|
||||||
|
#include <conf.h>
|
||||||
|
#include "str.h"
|
||||||
|
|
||||||
|
#define RZ_STR_LIMIT 256
|
||||||
|
#define RZ_STACK_LIMIT 1024
|
||||||
|
#define RZ_MAX_TYPES 256
|
||||||
|
|
||||||
|
#define RZ_NO_PARAM (-1)
|
||||||
|
typedef int param_t;
|
||||||
|
|
||||||
|
#define RZ_ENUM_ID(X) X
|
||||||
|
#define RZ_ENUM_STR(X) #X
|
||||||
|
|
||||||
|
#define RZ_ENUM_H(PREFIX, NAME) \
|
||||||
|
typedef enum PREFIX { NAME(RZ_ENUM_ID) } PREFIX; \
|
||||||
|
extern char const* PREFIX ## Str []
|
||||||
|
|
||||||
|
#define RZ_ENUM_C(PREFIX, NAME) \
|
||||||
|
char const* PREFIX ## Str [] = { NAME(RZ_ENUM_STR) }
|
||||||
|
|
||||||
|
#endif
|
|
@ -0,0 +1,50 @@
|
||||||
|
#include "compiler.h"
|
||||||
|
#include "lib/commons.h"
|
||||||
|
|
||||||
|
void compiler_init(compiler_t* compiler, mod_t* mod, tysy_t* tysy, err_t* err)
|
||||||
|
{
|
||||||
|
assert(compiler);
|
||||||
|
assert(err);
|
||||||
|
|
||||||
|
compiler->mod = mod;
|
||||||
|
compiler->tysy = tysy;
|
||||||
|
compiler->err = err;
|
||||||
|
}
|
||||||
|
|
||||||
|
void compiler_free(compiler_t* compiler)
|
||||||
|
{
|
||||||
|
assert(compiler);
|
||||||
|
}
|
||||||
|
|
||||||
|
void compiler_run(compiler_t* compiler, node_t* node)
|
||||||
|
{
|
||||||
|
assert(compiler);
|
||||||
|
assert(node);
|
||||||
|
|
||||||
|
switch (node->type)
|
||||||
|
{
|
||||||
|
case NODE_MOD: {
|
||||||
|
for (size_t i=0; i<node->children.size; i++)
|
||||||
|
{
|
||||||
|
compiler_run(compiler, (node_t*) node->children.data[i]);
|
||||||
|
}
|
||||||
|
} break;
|
||||||
|
|
||||||
|
case NODE_NUM: {
|
||||||
|
double value = atof(node->value.data);
|
||||||
|
value_t* val = tysy_new_num(compiler->tysy, value);
|
||||||
|
Opcode op = OP_PUSH;
|
||||||
|
param_t param = (param_t) mod_push_new_value(compiler->mod, val);
|
||||||
|
|
||||||
|
mod_push_instr(compiler->mod, op, 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);
|
||||||
|
} break;
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,21 @@
|
||||||
|
#ifndef RZ_COMPILER_H
|
||||||
|
#define RZ_COMPILER_H
|
||||||
|
|
||||||
|
#include "commons.h"
|
||||||
|
#include "err.h"
|
||||||
|
#include "mod.h"
|
||||||
|
#include "node.h"
|
||||||
|
#include "tysy.h"
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
mod_t* mod;
|
||||||
|
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_free(compiler_t* compiler);
|
||||||
|
|
||||||
|
void compiler_run(compiler_t* compiler, node_t* node);
|
||||||
|
|
||||||
|
#endif
|
|
@ -0,0 +1,47 @@
|
||||||
|
#include "err.h"
|
||||||
|
|
||||||
|
void err_init(err_t* err)
|
||||||
|
{
|
||||||
|
assert(err);
|
||||||
|
err->size = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
void err_free(err_t* err)
|
||||||
|
{
|
||||||
|
assert(err);
|
||||||
|
|
||||||
|
for (size_t i=0; i<err->size; i++)
|
||||||
|
{
|
||||||
|
free(err->errors[i]->what);
|
||||||
|
free(err->errors[i]);
|
||||||
|
}
|
||||||
|
|
||||||
|
err->size = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
void err_error(err_t* err, char* what, int line)
|
||||||
|
{
|
||||||
|
assert(err);
|
||||||
|
assert(err->size + 1 < RZ_ERROR_STACK_SIZE);
|
||||||
|
|
||||||
|
err->errors[err->size] = malloc(sizeof(err_msg_t));
|
||||||
|
err->errors[err->size]->what = strdup(what);
|
||||||
|
err->errors[err->size]->line = line;
|
||||||
|
err->size++;
|
||||||
|
}
|
||||||
|
|
||||||
|
void err_abort(err_t* err)
|
||||||
|
{
|
||||||
|
assert(err);
|
||||||
|
|
||||||
|
for (size_t i=0; i<err->size; i++)
|
||||||
|
{
|
||||||
|
fprintf(stderr, "ERR(%d) %s\n",
|
||||||
|
err->errors[i]->line,
|
||||||
|
err->errors[i]->what);
|
||||||
|
}
|
||||||
|
|
||||||
|
err_free(err);
|
||||||
|
|
||||||
|
abort();
|
||||||
|
}
|
|
@ -0,0 +1,24 @@
|
||||||
|
#ifndef RZ_ERR_H
|
||||||
|
#define RZ_ERR_H
|
||||||
|
|
||||||
|
#define RZ_ERROR_STACK_SIZE 256
|
||||||
|
|
||||||
|
#include "commons.h"
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
char* what;
|
||||||
|
int line;
|
||||||
|
} err_msg_t;
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
size_t size;
|
||||||
|
err_msg_t* errors[RZ_ERROR_STACK_SIZE];
|
||||||
|
} err_t;
|
||||||
|
|
||||||
|
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);
|
||||||
|
|
||||||
|
#endif
|
|
@ -0,0 +1,95 @@
|
||||||
|
#include "lexer.h"
|
||||||
|
#include "lib/commons.h"
|
||||||
|
|
||||||
|
void lexer_init(lexer_t* lexer, char const* source, err_t* err)
|
||||||
|
{
|
||||||
|
assert(lexer);
|
||||||
|
lexer->source = strdup(source);
|
||||||
|
lexer->cursor = 0;
|
||||||
|
lexer->err = err;
|
||||||
|
lexer->line = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
void lexer_free(lexer_t* lexer)
|
||||||
|
{
|
||||||
|
assert(lexer);
|
||||||
|
free(lexer->source);
|
||||||
|
lexer->source = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
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++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// scan num
|
||||||
|
{
|
||||||
|
size_t cursor = lexer->cursor;
|
||||||
|
|
||||||
|
str_t res_str;
|
||||||
|
str_init(&res_str);
|
||||||
|
|
||||||
|
if (cursor < len && lexer->source[cursor] == '-')
|
||||||
|
{
|
||||||
|
str_push(&res_str, lexer->source[cursor]);
|
||||||
|
cursor++;
|
||||||
|
}
|
||||||
|
|
||||||
|
while (cursor < len
|
||||||
|
&& isdigit(lexer->source[cursor]))
|
||||||
|
{
|
||||||
|
str_push(&res_str, lexer->source[cursor]);
|
||||||
|
cursor += 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (cursor < len && lexer->source[cursor] == '.')
|
||||||
|
{
|
||||||
|
str_push(&res_str, lexer->source[cursor]);
|
||||||
|
cursor++;
|
||||||
|
|
||||||
|
while (cursor < len
|
||||||
|
&& isdigit(lexer->source[cursor]))
|
||||||
|
{
|
||||||
|
str_push(&res_str, lexer->source[cursor]);
|
||||||
|
cursor += 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (res_str.size > 0
|
||||||
|
&& (cursor >= len || isspace(lexer->source[cursor])))
|
||||||
|
{
|
||||||
|
node_t* tok = malloc(sizeof(node_t));
|
||||||
|
node_init(tok, NODE_NUM, res_str.data, lexer->line);
|
||||||
|
str_free(&res_str);
|
||||||
|
|
||||||
|
lexer->cursor = cursor;
|
||||||
|
return tok;
|
||||||
|
}
|
||||||
|
|
||||||
|
str_free(&res_str);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (lexer->cursor < len && lexer->err)
|
||||||
|
{
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
|
||||||
|
return NULL;
|
||||||
|
}
|
|
@ -0,0 +1,20 @@
|
||||||
|
#ifndef RZ_LEXER_H
|
||||||
|
#define RZ_LEXER_H
|
||||||
|
|
||||||
|
#include "commons.h"
|
||||||
|
#include "node.h"
|
||||||
|
#include "err.h"
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
err_t* err;
|
||||||
|
char* source;
|
||||||
|
size_t cursor;
|
||||||
|
int line;
|
||||||
|
} lexer_t;
|
||||||
|
|
||||||
|
void lexer_init(lexer_t* lexer, char const* source, err_t* err);
|
||||||
|
void lexer_free(lexer_t* lexer);
|
||||||
|
|
||||||
|
node_t* lexer_try_new_next(lexer_t* lexer);
|
||||||
|
|
||||||
|
#endif
|
|
@ -0,0 +1,124 @@
|
||||||
|
#include "lexer.h"
|
||||||
|
#include "parser.h"
|
||||||
|
#include "loader.h"
|
||||||
|
#include "compiler.h"
|
||||||
|
#include "mod.h"
|
||||||
|
#include "vm.h"
|
||||||
|
|
||||||
|
void loader_init(loader_t* loader)
|
||||||
|
{
|
||||||
|
assert(loader);
|
||||||
|
}
|
||||||
|
|
||||||
|
void loader_free(loader_t* loader)
|
||||||
|
{
|
||||||
|
assert(loader);
|
||||||
|
}
|
||||||
|
|
||||||
|
void loader_ldfile(loader_t* loader, char const* path, int debug)
|
||||||
|
{
|
||||||
|
assert(loader);
|
||||||
|
str_t source;
|
||||||
|
str_init(&source);
|
||||||
|
|
||||||
|
// read sources
|
||||||
|
{
|
||||||
|
FILE* file = fopen(path, "r");
|
||||||
|
|
||||||
|
if (!file)
|
||||||
|
{
|
||||||
|
fprintf(stderr, "Cannot open file '%s'.\n", path);
|
||||||
|
abort();
|
||||||
|
}
|
||||||
|
|
||||||
|
char buf;
|
||||||
|
size_t sz;
|
||||||
|
|
||||||
|
while ( (sz = fread(&buf, sizeof(char), 1, file)) )
|
||||||
|
{
|
||||||
|
str_push(&source, buf);
|
||||||
|
}
|
||||||
|
|
||||||
|
fclose(file);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (str_empty(&source))
|
||||||
|
{
|
||||||
|
str_free(&source);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
tysy_t tysy;
|
||||||
|
tysy_init(&tysy);
|
||||||
|
|
||||||
|
err_t err;
|
||||||
|
err_init(&err);
|
||||||
|
|
||||||
|
lexer_t lex;
|
||||||
|
lexer_init(&lex, source.data, &err);
|
||||||
|
|
||||||
|
parser_t parser;
|
||||||
|
parser_init(&parser, &lex, &err);
|
||||||
|
|
||||||
|
node_t* node = parser_try_new_tree(&parser);
|
||||||
|
|
||||||
|
if (node)
|
||||||
|
{
|
||||||
|
mod_t mod;
|
||||||
|
mod_init(&mod);
|
||||||
|
|
||||||
|
// compile
|
||||||
|
{
|
||||||
|
compiler_t compiler;
|
||||||
|
compiler_init(&compiler, &mod, &tysy, &err);
|
||||||
|
compiler_run(&compiler, node);
|
||||||
|
compiler_free(&compiler);
|
||||||
|
node_free(node);
|
||||||
|
free(node);
|
||||||
|
}
|
||||||
|
|
||||||
|
// execute
|
||||||
|
{
|
||||||
|
vm_t vm;
|
||||||
|
vm_init(&vm);
|
||||||
|
|
||||||
|
vm_exec_mod(&vm, &mod);
|
||||||
|
|
||||||
|
if (debug)
|
||||||
|
{
|
||||||
|
{
|
||||||
|
char msg[RZ_STR_LIMIT];
|
||||||
|
mod_str(&mod, msg, RZ_STR_LIMIT);
|
||||||
|
printf("%s", msg);
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
char msg[RZ_STR_LIMIT];
|
||||||
|
vm_stack_str(&vm, msg, RZ_STR_LIMIT);
|
||||||
|
printf("\n======== STACK ========\n");
|
||||||
|
printf("%s\n", msg);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
vm_free(&vm);
|
||||||
|
}
|
||||||
|
|
||||||
|
mod_free(&mod);
|
||||||
|
}
|
||||||
|
|
||||||
|
// free
|
||||||
|
parser_free(&parser);
|
||||||
|
lexer_free(&lex);
|
||||||
|
str_free(&source);
|
||||||
|
|
||||||
|
if (err.size > 0)
|
||||||
|
{
|
||||||
|
err_abort(&err);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
err_free(&err);
|
||||||
|
}
|
||||||
|
|
||||||
|
tysy_free(&tysy);
|
||||||
|
}
|
|
@ -0,0 +1,15 @@
|
||||||
|
#ifndef RZ_LOADER_H
|
||||||
|
#define RZ_LOADER_H
|
||||||
|
|
||||||
|
#include "commons.h"
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
|
||||||
|
} loader_t;
|
||||||
|
|
||||||
|
void loader_init(loader_t* loader);
|
||||||
|
void loader_free(loader_t* loader);
|
||||||
|
|
||||||
|
void loader_ldfile(loader_t* loader, char const* path, int debug);
|
||||||
|
|
||||||
|
#endif
|
|
@ -0,0 +1,118 @@
|
||||||
|
#include "mod.h"
|
||||||
|
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
|
||||||
|
void 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++;
|
||||||
|
}
|
||||||
|
|
||||||
|
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++)
|
||||||
|
{
|
||||||
|
sz += snprintf(buffer + sz, size - sz, "%d| %s %d\n",
|
||||||
|
(int) i,
|
||||||
|
OpcodeStr[mod->program.ops[i]] + strlen("OP_"),
|
||||||
|
mod->program.params[i]);
|
||||||
|
}
|
||||||
|
|
||||||
|
return sz;
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t mod_push_new_value(mod_t* mod, value_t* value)
|
||||||
|
{
|
||||||
|
assert(mod);
|
||||||
|
assert(value);
|
||||||
|
|
||||||
|
for (size_t i=0; i<mod->values.size; i++)
|
||||||
|
{
|
||||||
|
if (value_eq(value, mod->values.data[i]))
|
||||||
|
{
|
||||||
|
value_free(value);
|
||||||
|
free(value);
|
||||||
|
return i;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
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;
|
||||||
|
}
|
|
@ -0,0 +1,31 @@
|
||||||
|
#ifndef RZ_MOD_H
|
||||||
|
#define RZ_MOD_H
|
||||||
|
|
||||||
|
#include "commons.h"
|
||||||
|
#include "opcodes.h"
|
||||||
|
#include "value.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;
|
||||||
|
} mod_t;
|
||||||
|
|
||||||
|
void mod_init(mod_t* mod);
|
||||||
|
void mod_free(mod_t* mod);
|
||||||
|
|
||||||
|
void 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
|
|
@ -0,0 +1,91 @@
|
||||||
|
#include "node.h"
|
||||||
|
|
||||||
|
RZ_ENUM_C(NodeType, NODE_TYPE);
|
||||||
|
|
||||||
|
void node_init(node_t* node, NodeType type, char* value, int line)
|
||||||
|
{
|
||||||
|
assert(node);
|
||||||
|
assert(value);
|
||||||
|
|
||||||
|
node->type = type;
|
||||||
|
str_init(&node->value);
|
||||||
|
str_append(&node->value, value);
|
||||||
|
|
||||||
|
node->line = line;
|
||||||
|
|
||||||
|
node->children.size = 0;
|
||||||
|
node->children.cap = 0;
|
||||||
|
node->children.data = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
void node_free(node_t* node)
|
||||||
|
{
|
||||||
|
assert(node);
|
||||||
|
str_free(&node->value);
|
||||||
|
|
||||||
|
for (size_t i=0; i<node->children.size; i++)
|
||||||
|
{
|
||||||
|
node_free((node_t*) node->children.data[i]);
|
||||||
|
free(node->children.data[i]);
|
||||||
|
}
|
||||||
|
|
||||||
|
free(node->children.data);
|
||||||
|
node->children.size = 0;
|
||||||
|
node->children.cap = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
void node_add_child(node_t* node, node_t* child)
|
||||||
|
{
|
||||||
|
assert(node);
|
||||||
|
assert(child);
|
||||||
|
|
||||||
|
if (node->children.cap == 0)
|
||||||
|
{
|
||||||
|
node->children.cap = 2;
|
||||||
|
node->children.data = malloc(sizeof(node_t) * node->children.cap);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (node->children.size >= node->children.cap)
|
||||||
|
{
|
||||||
|
node->children.cap *= 2;
|
||||||
|
node->children.data = realloc(node->children.data,
|
||||||
|
sizeof(node_t) * node->children.cap);
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t sz = node->children.size;
|
||||||
|
node->children.data[sz] = (struct node_t*) child;
|
||||||
|
node->children.size++;
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t node_str(node_t* node, char* buffer, size_t size)
|
||||||
|
{
|
||||||
|
assert(node);
|
||||||
|
size_t sz = 0;
|
||||||
|
|
||||||
|
sz += snprintf(buffer + sz, size - sz, "%s",
|
||||||
|
NodeTypeStr[node->type] + strlen("NODE_"));
|
||||||
|
|
||||||
|
if (!str_empty(&node->value))
|
||||||
|
{
|
||||||
|
sz += snprintf(buffer + sz, size - sz, "[%s]", node->value.data);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (node->children.size > 0)
|
||||||
|
{
|
||||||
|
sz += snprintf(buffer +sz, size - sz, "(");
|
||||||
|
|
||||||
|
for (size_t i=0; i<node->children.size; i++)
|
||||||
|
{
|
||||||
|
if (i > 0)
|
||||||
|
{
|
||||||
|
sz += snprintf(buffer +sz, size - sz, ",");
|
||||||
|
}
|
||||||
|
|
||||||
|
sz += node_str((node_t*) node->children.data[i], buffer + sz, size - sz);
|
||||||
|
}
|
||||||
|
|
||||||
|
sz += snprintf(buffer +sz, size - sz, ")");
|
||||||
|
}
|
||||||
|
|
||||||
|
return sz;
|
||||||
|
}
|
|
@ -0,0 +1,31 @@
|
||||||
|
#ifndef RZ_NODE_H
|
||||||
|
#define RZ_NODE_H
|
||||||
|
|
||||||
|
#include "commons.h"
|
||||||
|
|
||||||
|
#define NODE_TYPE(G) \
|
||||||
|
G(NODE_MOD), \
|
||||||
|
G(NODE_NUM)
|
||||||
|
|
||||||
|
RZ_ENUM_H(NodeType, NODE_TYPE);
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
NodeType type;
|
||||||
|
str_t value;
|
||||||
|
int line;
|
||||||
|
|
||||||
|
struct {
|
||||||
|
struct node_t** data;
|
||||||
|
size_t size;
|
||||||
|
size_t cap;
|
||||||
|
} children;
|
||||||
|
} node_t;
|
||||||
|
|
||||||
|
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);
|
||||||
|
|
||||||
|
size_t node_str(node_t* node, char* buffer, size_t size);
|
||||||
|
|
||||||
|
#endif
|
|
@ -0,0 +1,3 @@
|
||||||
|
#include "opcodes.h"
|
||||||
|
|
||||||
|
RZ_ENUM_C(Opcode, OPCODES);
|
|
@ -0,0 +1,12 @@
|
||||||
|
#ifndef RZ_OPCODES_H
|
||||||
|
#define RZ_OPCODES_H
|
||||||
|
|
||||||
|
#include "commons.h"
|
||||||
|
|
||||||
|
#define OPCODES(G) \
|
||||||
|
G(OP_HALT), \
|
||||||
|
G(OP_PUSH), G(OP_POP)
|
||||||
|
|
||||||
|
RZ_ENUM_H(Opcode, OPCODES);
|
||||||
|
|
||||||
|
#endif
|
|
@ -0,0 +1,83 @@
|
||||||
|
#include "parser.h"
|
||||||
|
#include "lib/lexer.h"
|
||||||
|
#include "lib/node.h"
|
||||||
|
|
||||||
|
void parser_init(parser_t* parser, lexer_t* lexer, err_t* err)
|
||||||
|
{
|
||||||
|
assert(parser);
|
||||||
|
parser->lexer = lexer;
|
||||||
|
parser->err = err;
|
||||||
|
}
|
||||||
|
|
||||||
|
void parser_free(parser_t* parser)
|
||||||
|
{
|
||||||
|
assert(parser);
|
||||||
|
}
|
||||||
|
|
||||||
|
node_t* parser_try_new_tree(parser_t* parser)
|
||||||
|
{
|
||||||
|
assert(parser);
|
||||||
|
return parser_try_new_mod(parser);
|
||||||
|
}
|
||||||
|
|
||||||
|
node_t* parser_try_new_mod(parser_t* parser)
|
||||||
|
{
|
||||||
|
assert(parser);
|
||||||
|
node_t* mod = malloc(sizeof(node_t));
|
||||||
|
node_init(mod, NODE_MOD, "", parser->lexer->line);
|
||||||
|
size_t len = strlen(parser->lexer->source);
|
||||||
|
|
||||||
|
while (parser->lexer->cursor < len)
|
||||||
|
{
|
||||||
|
node_t* expr = parser_try_new_expr(parser);
|
||||||
|
|
||||||
|
if (expr)
|
||||||
|
{
|
||||||
|
node_add_child(mod, expr);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
node_free(mod);
|
||||||
|
free(mod);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return mod;
|
||||||
|
}
|
||||||
|
|
||||||
|
node_t* parser_try_new_expr(parser_t* parser)
|
||||||
|
{
|
||||||
|
assert(parser);
|
||||||
|
return parser_try_new_num(parser);
|
||||||
|
}
|
||||||
|
|
||||||
|
node_t* parser_try_new_num(parser_t* parser)
|
||||||
|
{
|
||||||
|
assert(parser);
|
||||||
|
return parser_try_new_consume(parser, NODE_NUM);
|
||||||
|
}
|
||||||
|
|
||||||
|
node_t* parser_try_new_consume(parser_t* parser, NodeType type)
|
||||||
|
{
|
||||||
|
assert(parser);
|
||||||
|
node_t* next = lexer_try_new_next(parser->lexer);
|
||||||
|
|
||||||
|
if (!next)
|
||||||
|
{
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
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_error(parser->err, err_msg, next->line);
|
||||||
|
node_free(next);
|
||||||
|
free(next);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
return next;
|
||||||
|
}
|
|
@ -0,0 +1,23 @@
|
||||||
|
#ifndef RZ_PARSER_H
|
||||||
|
#define RZ_PARSER_H
|
||||||
|
|
||||||
|
#include "commons.h"
|
||||||
|
#include "err.h"
|
||||||
|
#include "lexer.h"
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
lexer_t* lexer;
|
||||||
|
err_t* err;
|
||||||
|
} parser_t;
|
||||||
|
|
||||||
|
void parser_init(parser_t* parser, lexer_t* lexer, err_t* err);
|
||||||
|
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_num(parser_t* parser);
|
||||||
|
|
||||||
|
node_t* parser_try_new_consume(parser_t* parser, NodeType type);
|
||||||
|
|
||||||
|
#endif
|
|
@ -0,0 +1,67 @@
|
||||||
|
#include "str.h"
|
||||||
|
|
||||||
|
void str_init(str_t* str)
|
||||||
|
{
|
||||||
|
assert(str);
|
||||||
|
str->data = NULL;
|
||||||
|
str->size = 0;
|
||||||
|
str->cap = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
void str_free(str_t* str)
|
||||||
|
{
|
||||||
|
assert(str);
|
||||||
|
|
||||||
|
free(str->data);
|
||||||
|
str->data = NULL;
|
||||||
|
str->size = 0;
|
||||||
|
str->cap = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
void str_resize(str_t* str)
|
||||||
|
{
|
||||||
|
assert(str);
|
||||||
|
|
||||||
|
if (str->data == NULL)
|
||||||
|
{
|
||||||
|
str->cap = 2;
|
||||||
|
str->data = calloc(str->cap + 1, sizeof(char));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (str->size >= str->cap)
|
||||||
|
{
|
||||||
|
str->cap *= 2;
|
||||||
|
str->data = realloc(str->data, sizeof(char) * (str->cap + 1));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void str_push(str_t* str, char c)
|
||||||
|
{
|
||||||
|
assert(str);
|
||||||
|
|
||||||
|
str_resize(str);
|
||||||
|
str->data[str->size] = c;
|
||||||
|
|
||||||
|
str_resize(str);
|
||||||
|
str->data[str->size + 1] = '\0';
|
||||||
|
str->size++;
|
||||||
|
}
|
||||||
|
|
||||||
|
void str_append(str_t* str, char const* src)
|
||||||
|
{
|
||||||
|
assert(str);
|
||||||
|
assert(src);
|
||||||
|
|
||||||
|
size_t len = strlen(src);
|
||||||
|
|
||||||
|
for (size_t i=0; i<len; i++)
|
||||||
|
{
|
||||||
|
str_push(str, src[i]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
int str_empty(str_t* str)
|
||||||
|
{
|
||||||
|
assert(str);
|
||||||
|
return str->size == 0;
|
||||||
|
}
|
|
@ -0,0 +1,22 @@
|
||||||
|
#ifndef RZ_STR_H
|
||||||
|
#define RZ_STR_H
|
||||||
|
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <assert.h>
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
char* data;
|
||||||
|
size_t size;
|
||||||
|
size_t cap;
|
||||||
|
} str_t;
|
||||||
|
|
||||||
|
void str_init(str_t* str);
|
||||||
|
void str_free(str_t* str);
|
||||||
|
|
||||||
|
void str_resize(str_t* str);
|
||||||
|
void str_push(str_t* str, char c);
|
||||||
|
void str_append(str_t* str, char const* src);
|
||||||
|
int str_empty(str_t* str);
|
||||||
|
|
||||||
|
#endif
|
|
@ -0,0 +1,22 @@
|
||||||
|
#include "type.h"
|
||||||
|
|
||||||
|
RZ_ENUM_C(TypeKind, TYPE_KIND);
|
||||||
|
|
||||||
|
void type_init(type_t* type, TypeKind kind)
|
||||||
|
{
|
||||||
|
assert(type);
|
||||||
|
type->kind = kind;
|
||||||
|
}
|
||||||
|
|
||||||
|
void type_free(type_t* type)
|
||||||
|
{
|
||||||
|
assert(type);
|
||||||
|
}
|
||||||
|
|
||||||
|
int type_eq(type_t* type, type_t* rhs)
|
||||||
|
{
|
||||||
|
assert(type);
|
||||||
|
assert(rhs);
|
||||||
|
|
||||||
|
return type->kind == rhs->kind;
|
||||||
|
}
|
|
@ -0,0 +1,20 @@
|
||||||
|
#ifndef RZ_TYPE_H
|
||||||
|
#define RZ_TYPE_H
|
||||||
|
|
||||||
|
#include "commons.h"
|
||||||
|
|
||||||
|
#define TYPE_KIND(G) \
|
||||||
|
G(TYPE_NUM)
|
||||||
|
|
||||||
|
RZ_ENUM_H(TypeKind, TYPE_KIND);
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
TypeKind kind;
|
||||||
|
} type_t;
|
||||||
|
|
||||||
|
void type_init(type_t* type, TypeKind kind);
|
||||||
|
void type_free(type_t* type);
|
||||||
|
|
||||||
|
int type_eq(type_t* type, type_t* rhs);
|
||||||
|
|
||||||
|
#endif
|
|
@ -0,0 +1,67 @@
|
||||||
|
#include "tysy.h"
|
||||||
|
|
||||||
|
void tysy_init(tysy_t* tysy)
|
||||||
|
{
|
||||||
|
assert(tysy);
|
||||||
|
tysy->size = 0;
|
||||||
|
|
||||||
|
// num
|
||||||
|
{
|
||||||
|
type_t* num = malloc(sizeof(type_t));
|
||||||
|
type_init(num, TYPE_NUM);
|
||||||
|
tysy_register_new_type(tysy, "num", num);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void tysy_free(tysy_t* tysy)
|
||||||
|
{
|
||||||
|
assert(tysy);
|
||||||
|
|
||||||
|
for (size_t i=0; i<tysy->size; i++)
|
||||||
|
{
|
||||||
|
type_free(tysy->types[i]);
|
||||||
|
free(tysy->types[i]);
|
||||||
|
free(tysy->names[i]);
|
||||||
|
}
|
||||||
|
|
||||||
|
tysy->size = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
void tysy_register_new_type(tysy_t* tysy, char* name, type_t* type)
|
||||||
|
{
|
||||||
|
assert(tysy);
|
||||||
|
assert(name);
|
||||||
|
assert(type);
|
||||||
|
assert(tysy->size + 1 < RZ_MAX_TYPES);
|
||||||
|
|
||||||
|
tysy->types[tysy->size] = type;
|
||||||
|
tysy->names[tysy->size] = strdup(name);
|
||||||
|
tysy->size++;
|
||||||
|
}
|
||||||
|
|
||||||
|
type_t* tysy_try_find_type(tysy_t* tysy, char* name)
|
||||||
|
{
|
||||||
|
assert(tysy);
|
||||||
|
assert(name);
|
||||||
|
|
||||||
|
for (size_t i=0; i<tysy->size; i++)
|
||||||
|
{
|
||||||
|
if (strcmp(name, tysy->names[i]) == 0)
|
||||||
|
{
|
||||||
|
return tysy->types[i];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
value_t* tysy_new_num(tysy_t* tysy, double value)
|
||||||
|
{
|
||||||
|
assert(tysy);
|
||||||
|
|
||||||
|
value_t* val = malloc(sizeof(value_t));
|
||||||
|
value_init(val, tysy_try_find_type(tysy, "num"));
|
||||||
|
val->value.num = value;
|
||||||
|
|
||||||
|
return val;
|
||||||
|
}
|
|
@ -0,0 +1,21 @@
|
||||||
|
#ifndef RZ_TYSY_H
|
||||||
|
#define RZ_TYSY_H
|
||||||
|
|
||||||
|
#include "commons.h"
|
||||||
|
#include "value.h"
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
type_t* types[RZ_MAX_TYPES];
|
||||||
|
char* names[RZ_MAX_TYPES];
|
||||||
|
size_t size;
|
||||||
|
} tysy_t;
|
||||||
|
|
||||||
|
void tysy_init(tysy_t* tysy);
|
||||||
|
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);
|
||||||
|
|
||||||
|
#endif
|
|
@ -0,0 +1,52 @@
|
||||||
|
#include "value.h"
|
||||||
|
|
||||||
|
void value_init(value_t* value, type_t* type)
|
||||||
|
{
|
||||||
|
assert(value);
|
||||||
|
assert(type);
|
||||||
|
|
||||||
|
value->type = type;
|
||||||
|
}
|
||||||
|
|
||||||
|
void value_free(value_t* value)
|
||||||
|
{
|
||||||
|
assert(value);
|
||||||
|
}
|
||||||
|
|
||||||
|
int value_eq(value_t* value, value_t* rhs)
|
||||||
|
{
|
||||||
|
if (!type_eq(value->type, rhs->type))
|
||||||
|
{
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
switch (value->type->kind)
|
||||||
|
{
|
||||||
|
case TYPE_NUM: {
|
||||||
|
return value->value.num == rhs->value.num;
|
||||||
|
} break;
|
||||||
|
|
||||||
|
default: {
|
||||||
|
fprintf(stderr, "Cannot compare value of type '%s'.\n",
|
||||||
|
TypeKindStr[value->type->kind]);
|
||||||
|
abort();
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t value_str(value_t* value, char* buffer, size_t size)
|
||||||
|
{
|
||||||
|
assert(value);
|
||||||
|
assert(buffer);
|
||||||
|
|
||||||
|
switch (value->type->kind)
|
||||||
|
{
|
||||||
|
case TYPE_NUM:
|
||||||
|
return snprintf(buffer, size, "%lf", value->value.num);
|
||||||
|
break;
|
||||||
|
|
||||||
|
default: return 0;
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,22 @@
|
||||||
|
#ifndef RZ_VALUE_H
|
||||||
|
#define RZ_VALUE_H
|
||||||
|
|
||||||
|
#include "type.h"
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
type_t* type;
|
||||||
|
|
||||||
|
union {
|
||||||
|
double num;
|
||||||
|
} value;
|
||||||
|
|
||||||
|
} value_t;
|
||||||
|
|
||||||
|
void value_init(value_t* value, type_t* type);
|
||||||
|
void value_free(value_t* value);
|
||||||
|
|
||||||
|
int value_eq(value_t* value, value_t* rhs);
|
||||||
|
|
||||||
|
size_t value_str(value_t* value, char* buffer, size_t size);
|
||||||
|
|
||||||
|
#endif
|
|
@ -0,0 +1,70 @@
|
||||||
|
#include "vm.h"
|
||||||
|
#include "lib/commons.h"
|
||||||
|
|
||||||
|
void vm_init(vm_t* vm)
|
||||||
|
{
|
||||||
|
assert(vm);
|
||||||
|
|
||||||
|
vm->pc = 0;
|
||||||
|
vm->bp = 0;
|
||||||
|
vm->sp = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
void vm_free(vm_t* vm)
|
||||||
|
{
|
||||||
|
assert(vm);
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t vm_stack_str(vm_t* vm, char* buffer, size_t size)
|
||||||
|
{
|
||||||
|
assert(vm);
|
||||||
|
assert(buffer);
|
||||||
|
|
||||||
|
size_t sz = 0;
|
||||||
|
|
||||||
|
for (size_t i=0; i<vm->sp; i++)
|
||||||
|
{
|
||||||
|
sz += snprintf(buffer + sz, size - sz, "| %d |\n", vm->stack[vm->sp - 1 - i]);
|
||||||
|
}
|
||||||
|
|
||||||
|
return sz;
|
||||||
|
}
|
||||||
|
|
||||||
|
void vm_exec_mod(vm_t* vm, mod_t* mod)
|
||||||
|
{
|
||||||
|
assert(vm);
|
||||||
|
vm->pc = 0;
|
||||||
|
|
||||||
|
while (vm->pc < mod->program.size)
|
||||||
|
{
|
||||||
|
vm_exec_instr(vm, mod->program.ops[vm->pc],
|
||||||
|
mod->program.params[vm->pc]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void vm_exec_instr(vm_t* vm, Opcode op, param_t param)
|
||||||
|
{
|
||||||
|
assert(vm);
|
||||||
|
|
||||||
|
switch (op)
|
||||||
|
{
|
||||||
|
|
||||||
|
case OP_PUSH: {
|
||||||
|
if (vm->sp + 1 >= RZ_STACK_LIMIT)
|
||||||
|
{
|
||||||
|
fprintf(stderr, "Stack overflow\n");
|
||||||
|
abort();
|
||||||
|
}
|
||||||
|
|
||||||
|
vm->stack[vm->sp] = param;
|
||||||
|
vm->sp++;
|
||||||
|
vm->pc++;
|
||||||
|
} break;
|
||||||
|
|
||||||
|
default: {
|
||||||
|
fprintf(stderr, "Cannot execute unknown opcode '%s'.\n",
|
||||||
|
OpcodeStr[op]);
|
||||||
|
abort();
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,23 @@
|
||||||
|
#ifndef RZ_VM_H
|
||||||
|
#define RZ_VM_H
|
||||||
|
|
||||||
|
#include "commons.h"
|
||||||
|
#include "opcodes.h"
|
||||||
|
#include "mod.h"
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
param_t stack[RZ_STACK_LIMIT];
|
||||||
|
size_t pc;
|
||||||
|
size_t bp;
|
||||||
|
size_t sp;
|
||||||
|
} vm_t;
|
||||||
|
|
||||||
|
void vm_init(vm_t* vm);
|
||||||
|
void vm_free(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);
|
||||||
|
|
||||||
|
#endif
|
25
meson.build
25
meson.build
|
@ -16,6 +16,28 @@ configure_file(
|
||||||
roza_lib = static_library(
|
roza_lib = static_library(
|
||||||
'roza',
|
'roza',
|
||||||
sources: [
|
sources: [
|
||||||
|
# utils
|
||||||
|
'lib/str.c',
|
||||||
|
|
||||||
|
# core
|
||||||
|
'lib/err.c',
|
||||||
|
'lib/loader.c',
|
||||||
|
|
||||||
|
# lang
|
||||||
|
'lib/node.c',
|
||||||
|
'lib/lexer.c',
|
||||||
|
'lib/parser.c',
|
||||||
|
'lib/type.c',
|
||||||
|
'lib/value.c',
|
||||||
|
'lib/tysy.c',
|
||||||
|
|
||||||
|
# comp
|
||||||
|
'lib/opcodes.c',
|
||||||
|
'lib/mod.c',
|
||||||
|
'lib/compiler.c',
|
||||||
|
|
||||||
|
# exec
|
||||||
|
'lib/vm.c',
|
||||||
]
|
]
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -35,7 +57,8 @@ executable('roza',
|
||||||
|
|
||||||
executable('roza-tests',
|
executable('roza-tests',
|
||||||
sources: [
|
sources: [
|
||||||
'tests/units/trivial.c'
|
'tests/units/lexer.c',
|
||||||
|
'tests/units/parser.c',
|
||||||
],
|
],
|
||||||
dependencies: [
|
dependencies: [
|
||||||
roza_dep,
|
roza_dep,
|
||||||
|
|
62
src/main.c
62
src/main.c
|
@ -1,8 +1,64 @@
|
||||||
#include <stdio.h>
|
#include <getopt.h>
|
||||||
#include <conf.h>
|
#include <commons.h>
|
||||||
|
#include <loader.h>
|
||||||
|
|
||||||
int main()
|
int main(int argc, char** argv)
|
||||||
{
|
{
|
||||||
|
int index = 0;
|
||||||
|
int debug = 0;
|
||||||
|
|
||||||
|
while (1)
|
||||||
|
{
|
||||||
|
static struct option opts[] = {
|
||||||
|
{"help", no_argument, 0, 'h'},
|
||||||
|
{"version", no_argument, 0, 'v'},
|
||||||
|
{"debug", no_argument, 0, 'd'},
|
||||||
|
{0, 0, 0, 0}
|
||||||
|
};
|
||||||
|
|
||||||
|
char c = getopt_long(argc, argv, "hvd", opts, &index);
|
||||||
|
|
||||||
|
if (c == -1) { break; }
|
||||||
|
|
||||||
|
switch (c)
|
||||||
|
{
|
||||||
|
case 'h': {
|
||||||
|
printf("Usage: roza [OPTIONS] [SOURCE]\n");
|
||||||
|
printf("OPTIONS:\n");
|
||||||
|
printf("\t-d, --debug\tshow roza debug messages\n");
|
||||||
|
printf("\t-h, --help\tshow this message\n");
|
||||||
|
printf("\t-v, --version\tshow roza version\n");
|
||||||
|
exit(0);
|
||||||
|
} break;
|
||||||
|
|
||||||
|
case 'v': {
|
||||||
printf("Roza v%s\n", ROZA_VERSION);
|
printf("Roza v%s\n", ROZA_VERSION);
|
||||||
|
printf("License GPLv3+\n");
|
||||||
|
exit(0);
|
||||||
|
} break;
|
||||||
|
|
||||||
|
case 'd': {
|
||||||
|
printf("Roza v%s: Debug mode enabled\n", ROZA_VERSION);
|
||||||
|
debug = 1;
|
||||||
|
} break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (optind < argc)
|
||||||
|
{
|
||||||
|
loader_t loader;
|
||||||
|
loader_init(&loader);
|
||||||
|
|
||||||
|
while (optind < argc)
|
||||||
|
{
|
||||||
|
loader_ldfile(&loader, argv[optind++], debug);
|
||||||
|
}
|
||||||
|
|
||||||
|
loader_free(&loader);
|
||||||
|
}
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,83 @@
|
||||||
|
#include <stdarg.h>
|
||||||
|
#include <criterion/criterion.h>
|
||||||
|
#include <lexer.h>
|
||||||
|
|
||||||
|
static void test_lexer_ok(char const* oracle, char const* source)
|
||||||
|
{
|
||||||
|
lexer_t lex;
|
||||||
|
lexer_init(&lex, source, NULL);
|
||||||
|
|
||||||
|
node_t* tok = lexer_try_new_next(&lex);
|
||||||
|
cr_assert(tok != NULL);
|
||||||
|
|
||||||
|
size_t const SZ = 512;
|
||||||
|
char str[SZ];
|
||||||
|
node_str(tok, str, SZ);
|
||||||
|
|
||||||
|
cr_assert_str_eq(str, oracle);
|
||||||
|
|
||||||
|
node_free(tok);
|
||||||
|
lexer_free(&lex);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void test_lexer_ko(char const* source)
|
||||||
|
{
|
||||||
|
lexer_t lex;
|
||||||
|
err_t err;
|
||||||
|
err_init(&err);
|
||||||
|
|
||||||
|
lexer_init(&lex, source, &err);
|
||||||
|
|
||||||
|
node_t* tok = lexer_try_new_next(&lex);
|
||||||
|
|
||||||
|
cr_assert(tok == NULL);
|
||||||
|
cr_assert(err.size > 0);
|
||||||
|
|
||||||
|
err_free(&err);
|
||||||
|
lexer_free(&lex);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void test_lexer(char const* source, size_t n, ...)
|
||||||
|
{
|
||||||
|
va_list lst;
|
||||||
|
va_start(lst, n);
|
||||||
|
|
||||||
|
lexer_t lexer;
|
||||||
|
lexer_init(&lexer, source, NULL);
|
||||||
|
|
||||||
|
for (size_t i=0; i<n; i++)
|
||||||
|
{
|
||||||
|
node_t* tok = lexer_try_new_next(&lexer);
|
||||||
|
cr_assert(NULL != tok);
|
||||||
|
|
||||||
|
size_t const SZ = 256;
|
||||||
|
char tok_str[SZ];
|
||||||
|
node_str(tok, tok_str, SZ);
|
||||||
|
|
||||||
|
char* oracle = va_arg(lst, char*);
|
||||||
|
cr_assert_str_eq(oracle, tok_str);
|
||||||
|
|
||||||
|
node_free(tok);
|
||||||
|
}
|
||||||
|
|
||||||
|
lexer_free(&lexer);
|
||||||
|
va_end(lst);
|
||||||
|
}
|
||||||
|
|
||||||
|
Test(lexer, num) {
|
||||||
|
test_lexer_ok("NUM[35]", " 35 ");
|
||||||
|
test_lexer_ok("NUM[-270]", " -270 ");
|
||||||
|
test_lexer_ok("NUM[0.7]", "0.7");
|
||||||
|
test_lexer_ok("NUM[3.]", "3.");
|
||||||
|
test_lexer_ok("NUM[.4]", ".4");
|
||||||
|
test_lexer_ok("NUM[-3.14]", "-3.14");
|
||||||
|
|
||||||
|
test_lexer("-2 4.1 6", 3,
|
||||||
|
"NUM[-2]",
|
||||||
|
"NUM[4.1]",
|
||||||
|
"NUM[6]");
|
||||||
|
|
||||||
|
test_lexer_ko("-3..14");
|
||||||
|
test_lexer_ko("..2");
|
||||||
|
test_lexer_ko("2..");
|
||||||
|
}
|
|
@ -0,0 +1,60 @@
|
||||||
|
#include <criterion/criterion.h>
|
||||||
|
#include <lexer.h>
|
||||||
|
#include <parser.h>
|
||||||
|
|
||||||
|
static void test_parser_ok(char const* oracle, char const* source)
|
||||||
|
{
|
||||||
|
err_t err;
|
||||||
|
err_init(&err);
|
||||||
|
|
||||||
|
lexer_t lex;
|
||||||
|
lexer_init(&lex, source, &err);
|
||||||
|
|
||||||
|
parser_t parser;
|
||||||
|
parser_init(&parser, &lex, &err);
|
||||||
|
|
||||||
|
node_t* node = parser_try_new_tree(&parser);
|
||||||
|
|
||||||
|
cr_assert(NULL != node);
|
||||||
|
|
||||||
|
size_t const SZ = 256;
|
||||||
|
char msg[SZ];
|
||||||
|
node_str(node, msg, SZ);
|
||||||
|
|
||||||
|
cr_assert_str_eq(msg, oracle);
|
||||||
|
|
||||||
|
node_free(node);
|
||||||
|
free(node);
|
||||||
|
|
||||||
|
parser_free(&parser);
|
||||||
|
lexer_free(&lex);
|
||||||
|
err_free(&err);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void test_parser_ko(char const* source)
|
||||||
|
{
|
||||||
|
err_t err;
|
||||||
|
err_init(&err);
|
||||||
|
|
||||||
|
lexer_t lex;
|
||||||
|
lexer_init(&lex, source, &err);
|
||||||
|
|
||||||
|
parser_t parser;
|
||||||
|
parser_init(&parser, &lex, &err);
|
||||||
|
|
||||||
|
node_t* node = parser_try_new_tree(&parser);
|
||||||
|
|
||||||
|
cr_assert(NULL == node);
|
||||||
|
cr_assert_gt(err.size, 0);
|
||||||
|
|
||||||
|
parser_free(&parser);
|
||||||
|
lexer_free(&lex);
|
||||||
|
err_free(&err);
|
||||||
|
}
|
||||||
|
|
||||||
|
Test(parser, num) {
|
||||||
|
test_parser_ok("MOD", "");
|
||||||
|
test_parser_ok("MOD(NUM[37],NUM[29])", "37 29");
|
||||||
|
|
||||||
|
test_parser_ko(" § ");
|
||||||
|
}
|
|
@ -1,5 +0,0 @@
|
||||||
#include <criterion/criterion.h>
|
|
||||||
|
|
||||||
Test(trivial, trivial) {
|
|
||||||
cr_assert(1 + 1 == 2);
|
|
||||||
}
|
|
Loading…
Reference in New Issue