num literals.

main
bog 2023-12-09 18:24:41 +01:00
parent e434d5c4ae
commit 46dc8b8c2d
34 changed files with 1439 additions and 13 deletions

View File

@ -7,13 +7,16 @@ build:
tests: build
build/roza-tests
install: build
install: tests
meson install -C build
check:
@cppcheck --language=c --enable=all lib src -q \
--suppress=missingIncludeSystem
--suppress=missingIncludeSystem \
--suppress=missingInclude \
--suppress=unmatchedSuppression
@cppcheck --language=c --enable=all tests/units -q \
--suppress=missingIncludeSystem \
--suppress=unusedFunction
--suppress=unusedFunction \
--suppress=unmatchedSuppression

View File

@ -0,0 +1,2 @@
MOD ::= EXPR*
EXPR ::= num

30
lib/commons.h Normal file
View File

@ -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

50
lib/compiler.c Normal file
View File

@ -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;
}
}

21
lib/compiler.h Normal file
View File

@ -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

47
lib/err.c Normal file
View File

@ -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();
}

24
lib/err.h Normal file
View File

@ -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

95
lib/lexer.c Normal file
View File

@ -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;
}

20
lib/lexer.h Normal file
View File

@ -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

124
lib/loader.c Normal file
View File

@ -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);
}

15
lib/loader.h Normal file
View File

@ -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

118
lib/mod.c Normal file
View File

@ -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;
}

31
lib/mod.h Normal file
View File

@ -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

91
lib/node.c Normal file
View File

@ -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;
}

31
lib/node.h Normal file
View File

@ -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

3
lib/opcodes.c Normal file
View File

@ -0,0 +1,3 @@
#include "opcodes.h"
RZ_ENUM_C(Opcode, OPCODES);

12
lib/opcodes.h Normal file
View File

@ -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

83
lib/parser.c Normal file
View File

@ -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;
}

23
lib/parser.h Normal file
View File

@ -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

67
lib/str.c Normal file
View File

@ -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;
}

22
lib/str.h Normal file
View File

@ -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

22
lib/type.c Normal file
View File

@ -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;
}

20
lib/type.h Normal file
View File

@ -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

67
lib/tysy.c Normal file
View File

@ -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;
}

21
lib/tysy.h Normal file
View File

@ -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

52
lib/value.c Normal file
View File

@ -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;
}
}

22
lib/value.h Normal file
View File

@ -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

70
lib/vm.c Normal file
View File

@ -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();
};
}
}

23
lib/vm.h Normal file
View File

@ -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

View File

@ -16,6 +16,28 @@ configure_file(
roza_lib = static_library(
'roza',
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',
sources: [
'tests/units/trivial.c'
'tests/units/lexer.c',
'tests/units/parser.c',
],
dependencies: [
roza_dep,

View File

@ -1,8 +1,64 @@
#include <stdio.h>
#include <conf.h>
#include <getopt.h>
#include <commons.h>
#include <loader.h>
int main()
int main(int argc, char** argv)
{
printf("Roza v%s\n", ROZA_VERSION);
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("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;
}

83
tests/units/lexer.c Normal file
View File

@ -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..");
}

60
tests/units/parser.c Normal file
View File

@ -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(" § ");
}

View File

@ -1,5 +0,0 @@
#include <criterion/criterion.h>
Test(trivial, trivial) {
cr_assert(1 + 1 == 2);
}