Compare commits
2 Commits
4f6f3253c2
...
5b8748b843
Author | SHA1 | Date |
---|---|---|
bog | 5b8748b843 | |
bog | caf6b3b47c |
|
@ -1,8 +1,10 @@
|
||||||
MOD ::= EXPR*
|
MOD ::= EXPR*
|
||||||
EXPR ::=
|
EXPR ::=
|
||||||
| ASSERT
|
| ASSERT
|
||||||
| EQNE
|
| OR
|
||||||
ASSERT ::= assert EXPR
|
ASSERT ::= assert EXPR
|
||||||
|
OR ::= AND (or AND)*
|
||||||
|
AND ::= EQNE (and EQNE)*
|
||||||
EQNE ::=
|
EQNE ::=
|
||||||
| CMP
|
| CMP
|
||||||
| CMP eq CMP
|
| CMP eq CMP
|
||||||
|
@ -11,6 +13,6 @@ CMP ::= TERM ((lt | le | ge | gt) TERM)?
|
||||||
TERM ::= FACTOR ((add | sub) FACTOR)*
|
TERM ::= FACTOR ((add | sub) FACTOR)*
|
||||||
FACTOR ::= POWER ((mul | div | mod) POWER)*
|
FACTOR ::= POWER ((mul | div | mod) POWER)*
|
||||||
POWER ::= UNARY (pow UNARY)?
|
POWER ::= UNARY (pow UNARY)?
|
||||||
UNARY ::= sub? GROUP
|
UNARY ::= sub? GROUP | not? GROUP
|
||||||
GROUP ::= BUILTIN | opar EXPR cpar
|
GROUP ::= BUILTIN | opar EXPR cpar
|
||||||
BUILTIN ::= num | bool | str
|
BUILTIN ::= num | bool | str
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
#include "compiler.h"
|
#include "compiler.h"
|
||||||
#include "lib/commons.h"
|
#include "lib/commons.h"
|
||||||
|
#include "lib/mod.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, tysy_t* tysy, err_t* err)
|
||||||
{
|
{
|
||||||
|
@ -120,6 +121,17 @@ void compiler_run(compiler_t* compiler, node_t* node)
|
||||||
{
|
{
|
||||||
op = OP_USUB;
|
op = OP_USUB;
|
||||||
}
|
}
|
||||||
|
else if (node->type == NODE_ADD
|
||||||
|
&& node_find_first(node, NODE_STR))
|
||||||
|
{
|
||||||
|
op = OP_STRCAT;
|
||||||
|
}
|
||||||
|
else if (node->type == NODE_MUL
|
||||||
|
&& node_find_first(node, NODE_STR)
|
||||||
|
&& node_find_first(node, NODE_NUM))
|
||||||
|
{
|
||||||
|
op = OP_STRDUP;
|
||||||
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
switch (node->type)
|
switch (node->type)
|
||||||
|
@ -138,6 +150,78 @@ void compiler_run(compiler_t* compiler, node_t* node)
|
||||||
|
|
||||||
} break;
|
} break;
|
||||||
|
|
||||||
|
case NODE_AND: {
|
||||||
|
size_t const SZ = 512;
|
||||||
|
size_t to_false[SZ];
|
||||||
|
size_t sz = 0;
|
||||||
|
|
||||||
|
for (size_t i=0; i<node->children.size; i++)
|
||||||
|
{
|
||||||
|
compiler_run(compiler, node_child(node, i));
|
||||||
|
size_t addr = mod_push_instr(compiler->mod, OP_BRF, RZ_NO_PARAM);
|
||||||
|
to_false[sz++] = addr;
|
||||||
|
}
|
||||||
|
|
||||||
|
// True case
|
||||||
|
value_t* t = tysy_new_bool(compiler->tysy, 1, node->line);
|
||||||
|
param_t t_param = mod_push_new_value(compiler->mod, t);
|
||||||
|
mod_push_instr(compiler->mod, OP_PUSH, t_param);
|
||||||
|
size_t to_end = mod_push_instr(compiler->mod, OP_BR, RZ_NO_PARAM);
|
||||||
|
|
||||||
|
// False case
|
||||||
|
size_t program_sz = compiler->mod->program.size;
|
||||||
|
for (size_t i=0; i<sz; i++)
|
||||||
|
{
|
||||||
|
compiler->mod->program.params[to_false[i]] = program_sz;
|
||||||
|
}
|
||||||
|
|
||||||
|
value_t* f = tysy_new_bool(compiler->tysy, 0, node->line);
|
||||||
|
param_t f_param = mod_push_new_value(compiler->mod, f);
|
||||||
|
mod_push_instr(compiler->mod, OP_PUSH, f_param);
|
||||||
|
|
||||||
|
compiler->mod->program.params[to_end] = compiler->mod->program.size;
|
||||||
|
|
||||||
|
} break;
|
||||||
|
|
||||||
|
case NODE_OR: {
|
||||||
|
size_t const SZ = 512;
|
||||||
|
size_t to_true[SZ];
|
||||||
|
size_t sz = 0;
|
||||||
|
|
||||||
|
for (size_t i=0; i<node->children.size; i++)
|
||||||
|
{
|
||||||
|
compiler_run(compiler, node_child(node, i));
|
||||||
|
size_t addr = mod_push_instr(compiler->mod, OP_BRT, RZ_NO_PARAM);
|
||||||
|
to_true[sz++] = addr;
|
||||||
|
}
|
||||||
|
|
||||||
|
// False case
|
||||||
|
value_t* f = tysy_new_bool(compiler->tysy, 0, node->line);
|
||||||
|
param_t f_param = mod_push_new_value(compiler->mod, f);
|
||||||
|
mod_push_instr(compiler->mod, OP_PUSH, f_param);
|
||||||
|
size_t to_end = mod_push_instr(compiler->mod, OP_BR, RZ_NO_PARAM);
|
||||||
|
|
||||||
|
// True case
|
||||||
|
size_t program_sz = compiler->mod->program.size;
|
||||||
|
for (size_t i=0; i<sz; i++)
|
||||||
|
{
|
||||||
|
compiler->mod->program.params[to_true[i]] = program_sz;
|
||||||
|
}
|
||||||
|
|
||||||
|
value_t* t = tysy_new_bool(compiler->tysy, 1, node->line);
|
||||||
|
param_t t_param = mod_push_new_value(compiler->mod, t);
|
||||||
|
mod_push_instr(compiler->mod, OP_PUSH, t_param);
|
||||||
|
|
||||||
|
compiler->mod->program.params[to_end] = compiler->mod->program.size;
|
||||||
|
|
||||||
|
} break;
|
||||||
|
|
||||||
|
case NODE_NOT: {
|
||||||
|
assert(node->children.size > 0);
|
||||||
|
compiler_run(compiler, (node_t*) node->children.data[0]);
|
||||||
|
mod_push_instr(compiler->mod, OP_NOT, RZ_NO_PARAM);
|
||||||
|
} break;
|
||||||
|
|
||||||
default: {
|
default: {
|
||||||
fprintf(stderr, "Cannot compile unknown node '%s'",
|
fprintf(stderr, "Cannot compile unknown node '%s'",
|
||||||
NodeTypeStr[node->type]);
|
NodeTypeStr[node->type]);
|
||||||
|
|
|
@ -70,6 +70,9 @@ node_t* lexer_try_new_next(lexer_t* lexer)
|
||||||
|
|
||||||
// Keywords
|
// Keywords
|
||||||
// ========
|
// ========
|
||||||
|
RZ_KEYWORD("and", NODE_AND, 0);
|
||||||
|
RZ_KEYWORD("or", NODE_OR, 0);
|
||||||
|
RZ_KEYWORD("not", NODE_NOT, 0);
|
||||||
RZ_KEYWORD("true", NODE_BOOL, 1);
|
RZ_KEYWORD("true", NODE_BOOL, 1);
|
||||||
RZ_KEYWORD("false", NODE_BOOL, 1);
|
RZ_KEYWORD("false", NODE_BOOL, 1);
|
||||||
RZ_KEYWORD("assert", NODE_ASSERT, 0);
|
RZ_KEYWORD("assert", NODE_ASSERT, 0);
|
||||||
|
@ -348,5 +351,8 @@ int lexer_is_sep(lexer_t* lexer, size_t idx)
|
||||||
|| c == '/'
|
|| c == '/'
|
||||||
|| c == '%'
|
|| c == '%'
|
||||||
|| c == '^'
|
|| c == '^'
|
||||||
|| c == '!';
|
|| c == '!'
|
||||||
|
|| c == '('
|
||||||
|
|| c == ')'
|
||||||
|
;
|
||||||
}
|
}
|
||||||
|
|
16
lib/loader.c
16
lib/loader.c
|
@ -63,6 +63,7 @@ int loader_ldfile(loader_t* loader, char const* path, int debug)
|
||||||
parser_init(&parser, &lex, &err);
|
parser_init(&parser, &lex, &err);
|
||||||
|
|
||||||
node_t* node = parser_try_new_tree(&parser);
|
node_t* node = parser_try_new_tree(&parser);
|
||||||
|
assert(node);
|
||||||
|
|
||||||
if (debug)
|
if (debug)
|
||||||
{
|
{
|
||||||
|
@ -109,6 +110,13 @@ int loader_ldfile(loader_t* loader, char const* path, int debug)
|
||||||
abort();
|
abort();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (debug)
|
||||||
|
{
|
||||||
|
char msg[RZ_STR_LIMIT];
|
||||||
|
mod_str(&mod, msg, RZ_STR_LIMIT);
|
||||||
|
printf("%s", msg);
|
||||||
|
}
|
||||||
|
|
||||||
// execute
|
// execute
|
||||||
{
|
{
|
||||||
vm_t vm;
|
vm_t vm;
|
||||||
|
@ -130,20 +138,12 @@ int loader_ldfile(loader_t* loader, char const* path, int debug)
|
||||||
}
|
}
|
||||||
|
|
||||||
if (debug)
|
if (debug)
|
||||||
{
|
|
||||||
{
|
|
||||||
char msg[RZ_STR_LIMIT];
|
|
||||||
mod_str(&mod, msg, RZ_STR_LIMIT);
|
|
||||||
printf("%s", msg);
|
|
||||||
}
|
|
||||||
|
|
||||||
{
|
{
|
||||||
char msg[RZ_STR_LIMIT];
|
char msg[RZ_STR_LIMIT];
|
||||||
vm_stack_str(&vm, msg, RZ_STR_LIMIT);
|
vm_stack_str(&vm, msg, RZ_STR_LIMIT);
|
||||||
printf("\n======== STACK ========\n");
|
printf("\n======== STACK ========\n");
|
||||||
printf("%s\n", msg);
|
printf("%s\n", msg);
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
vm_free(&vm);
|
vm_free(&vm);
|
||||||
}
|
}
|
||||||
|
|
|
@ -35,7 +35,7 @@ void mod_free(mod_t* mod)
|
||||||
mod->values.cap = 0;
|
mod->values.cap = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
void mod_push_instr(mod_t* mod, Opcode op, param_t param)
|
size_t mod_push_instr(mod_t* mod, Opcode op, param_t param)
|
||||||
{
|
{
|
||||||
assert(mod);
|
assert(mod);
|
||||||
|
|
||||||
|
@ -58,6 +58,8 @@ void mod_push_instr(mod_t* mod, Opcode op, param_t param)
|
||||||
mod->program.ops[mod->program.size] = op;
|
mod->program.ops[mod->program.size] = op;
|
||||||
mod->program.params[mod->program.size] = param;
|
mod->program.params[mod->program.size] = param;
|
||||||
mod->program.size++;
|
mod->program.size++;
|
||||||
|
|
||||||
|
return mod->program.size - 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
size_t mod_str(mod_t* mod, char* buffer, size_t size)
|
size_t mod_str(mod_t* mod, char* buffer, size_t size)
|
||||||
|
|
|
@ -23,7 +23,7 @@ typedef struct {
|
||||||
void mod_init(mod_t* mod);
|
void mod_init(mod_t* mod);
|
||||||
void mod_free(mod_t* mod);
|
void mod_free(mod_t* mod);
|
||||||
|
|
||||||
void mod_push_instr(mod_t* mod, Opcode op, param_t param);
|
size_t mod_push_instr(mod_t* mod, Opcode op, param_t param);
|
||||||
size_t mod_str(mod_t* mod, char* buffer, size_t size);
|
size_t mod_str(mod_t* mod, char* buffer, size_t size);
|
||||||
|
|
||||||
size_t mod_push_new_value(mod_t* mod, value_t* value);
|
size_t mod_push_new_value(mod_t* mod, value_t* value);
|
||||||
|
|
22
lib/node.c
22
lib/node.c
|
@ -97,3 +97,25 @@ size_t node_str(node_t* node, char* buffer, size_t size)
|
||||||
|
|
||||||
return sz;
|
return sz;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
node_t* node_find_first(node_t* node, NodeType type)
|
||||||
|
{
|
||||||
|
assert(node);
|
||||||
|
|
||||||
|
if (node->type == type)
|
||||||
|
{
|
||||||
|
return node;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (size_t i=0; i<node->children.size; i++)
|
||||||
|
{
|
||||||
|
node_t* child = node_find_first((node_t*) node->children.data[i], type);
|
||||||
|
|
||||||
|
if (child)
|
||||||
|
{
|
||||||
|
return child;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
|
@ -10,7 +10,8 @@
|
||||||
G(NODE_EQ), G(NODE_NE), \
|
G(NODE_EQ), G(NODE_NE), \
|
||||||
G(NODE_LT), G(NODE_LE), G(NODE_GT), G(NODE_GE), \
|
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_ADD), G(NODE_SUB), G(NODE_MUL), G(NODE_DIV), \
|
||||||
G(NODE_MODULO), G(NODE_POW), G(NODE_OPAR), G(NODE_CPAR)
|
G(NODE_MODULO), G(NODE_POW), G(NODE_OPAR), G(NODE_CPAR), \
|
||||||
|
G(NODE_AND), G(NODE_OR), G(NODE_NOT)
|
||||||
|
|
||||||
RZ_ENUM_H(NodeType, NODE_TYPE);
|
RZ_ENUM_H(NodeType, NODE_TYPE);
|
||||||
|
|
||||||
|
@ -33,5 +34,6 @@ void node_add_new_child(node_t* node, node_t* child);
|
||||||
node_t* node_child(node_t* node, size_t index);
|
node_t* node_child(node_t* node, size_t index);
|
||||||
|
|
||||||
size_t node_str(node_t* node, char* buffer, size_t size);
|
size_t node_str(node_t* node, char* buffer, size_t size);
|
||||||
|
node_t* node_find_first(node_t* node, NodeType type);
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -9,7 +9,11 @@
|
||||||
G(OP_EQ), G(OP_NE), \
|
G(OP_EQ), G(OP_NE), \
|
||||||
G(OP_LT), G(OP_LE), G(OP_GT), G(OP_GE), \
|
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_ADD), G(OP_SUB), G(OP_MUL), G(OP_DIV), \
|
||||||
G(OP_MODULO), G(OP_POW), G(OP_USUB)
|
G(OP_MODULO), G(OP_POW), G(OP_USUB), \
|
||||||
|
G(OP_AND), G(OP_OR), G(OP_NOT), \
|
||||||
|
G(OP_BRF), G(OP_BRT), G(OP_BR), \
|
||||||
|
G(OP_STRCAT), G(OP_STRDUP)
|
||||||
|
|
||||||
|
|
||||||
RZ_ENUM_H(Opcode, OPCODES);
|
RZ_ENUM_H(Opcode, OPCODES);
|
||||||
|
|
||||||
|
|
74
lib/parser.c
74
lib/parser.c
|
@ -61,7 +61,7 @@ node_t* parser_try_new_expr(parser_t* parser)
|
||||||
return parser_try_new_assert(parser);
|
return parser_try_new_assert(parser);
|
||||||
}
|
}
|
||||||
|
|
||||||
return parser_try_new_eqne(parser);
|
return parser_try_new_or(parser);
|
||||||
}
|
}
|
||||||
|
|
||||||
node_t* parser_try_new_assert(parser_t* parser)
|
node_t* parser_try_new_assert(parser_t* parser)
|
||||||
|
@ -77,10 +77,52 @@ node_t* parser_try_new_assert(parser_t* parser)
|
||||||
return node;
|
return node;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
node_t* parser_try_new_or(parser_t* parser)
|
||||||
|
{
|
||||||
|
assert(parser);
|
||||||
|
node_t* lhs = parser_try_new_and(parser);
|
||||||
|
|
||||||
|
while (1)
|
||||||
|
{
|
||||||
|
int next = lexer_peek(parser->lexer, 1);
|
||||||
|
if (next != NODE_OR) { break; }
|
||||||
|
|
||||||
|
node_t* node = parser_try_new_consume(parser, next);
|
||||||
|
node_add_new_child(node, lhs);
|
||||||
|
node_add_new_child(node, parser_try_new_and(parser));
|
||||||
|
lhs = node;
|
||||||
|
}
|
||||||
|
|
||||||
|
return lhs;
|
||||||
|
}
|
||||||
|
|
||||||
|
node_t* parser_try_new_and(parser_t* parser)
|
||||||
|
{
|
||||||
|
assert(parser);
|
||||||
|
node_t* lhs = parser_try_new_eqne(parser);
|
||||||
|
|
||||||
|
while (1)
|
||||||
|
{
|
||||||
|
int next = lexer_peek(parser->lexer, 1);
|
||||||
|
if (next != NODE_AND) { break; }
|
||||||
|
|
||||||
|
node_t* node = parser_try_new_consume(parser, next);
|
||||||
|
assert(node);
|
||||||
|
node_add_new_child(node, lhs);
|
||||||
|
node_t* eqne = parser_try_new_eqne(parser);
|
||||||
|
assert(eqne);
|
||||||
|
node_add_new_child(node, eqne);
|
||||||
|
lhs = node;
|
||||||
|
}
|
||||||
|
|
||||||
|
return lhs;
|
||||||
|
}
|
||||||
|
|
||||||
node_t* parser_try_new_eqne(parser_t* parser)
|
node_t* parser_try_new_eqne(parser_t* parser)
|
||||||
{
|
{
|
||||||
assert(parser);
|
assert(parser);
|
||||||
node_t* lhs = parser_try_new_cmp(parser);
|
node_t* lhs = parser_try_new_cmp(parser);
|
||||||
|
assert(lhs);
|
||||||
|
|
||||||
while (1)
|
while (1)
|
||||||
{
|
{
|
||||||
|
@ -108,6 +150,7 @@ node_t* parser_try_new_cmp(parser_t* parser)
|
||||||
{
|
{
|
||||||
assert(parser);
|
assert(parser);
|
||||||
node_t* lhs = parser_try_new_term(parser);
|
node_t* lhs = parser_try_new_term(parser);
|
||||||
|
assert(lhs);
|
||||||
|
|
||||||
int next = lexer_peek(parser->lexer, 1);
|
int next = lexer_peek(parser->lexer, 1);
|
||||||
|
|
||||||
|
@ -130,6 +173,7 @@ node_t* parser_try_new_term(parser_t* parser)
|
||||||
{
|
{
|
||||||
assert(parser);
|
assert(parser);
|
||||||
node_t* lhs = parser_try_new_factor(parser);
|
node_t* lhs = parser_try_new_factor(parser);
|
||||||
|
assert(lhs);
|
||||||
|
|
||||||
while (1)
|
while (1)
|
||||||
{
|
{
|
||||||
|
@ -157,6 +201,7 @@ node_t* parser_try_new_factor(parser_t* parser)
|
||||||
{
|
{
|
||||||
assert(parser);
|
assert(parser);
|
||||||
node_t* lhs = parser_try_new_power(parser);
|
node_t* lhs = parser_try_new_power(parser);
|
||||||
|
assert(lhs);
|
||||||
|
|
||||||
while (1)
|
while (1)
|
||||||
{
|
{
|
||||||
|
@ -185,6 +230,7 @@ node_t* parser_try_new_power(parser_t* parser)
|
||||||
{
|
{
|
||||||
assert(parser);
|
assert(parser);
|
||||||
node_t* lhs = parser_try_new_unary(parser);
|
node_t* lhs = parser_try_new_unary(parser);
|
||||||
|
assert(lhs);
|
||||||
|
|
||||||
NodeType next = lexer_peek(parser->lexer, 1);
|
NodeType next = lexer_peek(parser->lexer, 1);
|
||||||
|
|
||||||
|
@ -207,11 +253,27 @@ node_t* parser_try_new_unary(parser_t* parser)
|
||||||
if (next == NODE_SUB)
|
if (next == NODE_SUB)
|
||||||
{
|
{
|
||||||
node_t* node = parser_try_new_consume(parser, next);
|
node_t* node = parser_try_new_consume(parser, next);
|
||||||
|
assert(node);
|
||||||
|
|
||||||
node_add_new_child(node, parser_try_new_group(parser));
|
node_add_new_child(node, parser_try_new_group(parser));
|
||||||
|
assert(node);
|
||||||
|
|
||||||
return node;
|
return node;
|
||||||
}
|
}
|
||||||
|
|
||||||
return parser_try_new_group(parser);
|
if (next == NODE_NOT)
|
||||||
|
{
|
||||||
|
node_t* node = parser_try_new_consume(parser, next);
|
||||||
|
assert(node);
|
||||||
|
node_add_new_child(node, parser_try_new_unary(parser));
|
||||||
|
|
||||||
|
return node;
|
||||||
|
}
|
||||||
|
|
||||||
|
node_t* group = parser_try_new_group(parser);
|
||||||
|
assert(group);
|
||||||
|
|
||||||
|
return group;
|
||||||
}
|
}
|
||||||
|
|
||||||
node_t* parser_try_new_group(parser_t* parser)
|
node_t* parser_try_new_group(parser_t* parser)
|
||||||
|
@ -223,11 +285,17 @@ node_t* parser_try_new_group(parser_t* parser)
|
||||||
{
|
{
|
||||||
lexer_skip_next(parser->lexer);
|
lexer_skip_next(parser->lexer);
|
||||||
node_t* node = parser_try_new_expr(parser);
|
node_t* node = parser_try_new_expr(parser);
|
||||||
|
assert(node);
|
||||||
|
assert(lexer_peek(parser->lexer, 1) == NODE_CPAR);
|
||||||
lexer_skip_next(parser->lexer);
|
lexer_skip_next(parser->lexer);
|
||||||
return node;
|
return node;
|
||||||
}
|
}
|
||||||
|
|
||||||
return parser_try_new_builtin(parser);
|
node_t* builtin = parser_try_new_builtin(parser);
|
||||||
|
|
||||||
|
assert(builtin);
|
||||||
|
|
||||||
|
return builtin;
|
||||||
}
|
}
|
||||||
|
|
||||||
node_t* parser_try_new_builtin(parser_t* parser)
|
node_t* parser_try_new_builtin(parser_t* parser)
|
||||||
|
|
|
@ -17,6 +17,8 @@ node_t* parser_try_new_tree(parser_t* parser);
|
||||||
node_t* parser_try_new_mod(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_expr(parser_t* parser);
|
||||||
node_t* parser_try_new_assert(parser_t* parser);
|
node_t* parser_try_new_assert(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);
|
node_t* parser_try_new_eqne(parser_t* parser);
|
||||||
node_t* parser_try_new_cmp(parser_t* parser);
|
node_t* parser_try_new_cmp(parser_t* parser);
|
||||||
node_t* parser_try_new_term(parser_t* parser);
|
node_t* parser_try_new_term(parser_t* parser);
|
||||||
|
|
|
@ -37,7 +37,12 @@ void prepass_run(prepass_t* prepass, node_t* node)
|
||||||
case NODE_MUL:
|
case NODE_MUL:
|
||||||
case NODE_DIV:
|
case NODE_DIV:
|
||||||
case NODE_MODULO:
|
case NODE_MODULO:
|
||||||
case NODE_POW:{
|
case NODE_POW:
|
||||||
|
|
||||||
|
case NODE_OR:
|
||||||
|
case NODE_AND:
|
||||||
|
case NODE_NOT:
|
||||||
|
{
|
||||||
for (size_t i=0; i<node->children.size; i++)
|
for (size_t i=0; i<node->children.size; i++)
|
||||||
{
|
{
|
||||||
prepass_run(prepass, (node_t*) node->children.data[i]);
|
prepass_run(prepass, (node_t*) node->children.data[i]);
|
||||||
|
|
131
lib/vm.c
131
lib/vm.c
|
@ -21,7 +21,7 @@ void vm_free(vm_t* vm)
|
||||||
assert(vm);
|
assert(vm);
|
||||||
}
|
}
|
||||||
|
|
||||||
void vm_push_value(vm_t* vm, mod_t* mod, value_t* value)
|
void vm_push_new_value(vm_t* vm, mod_t* mod, value_t* value)
|
||||||
{
|
{
|
||||||
assert(vm);
|
assert(vm);
|
||||||
assert(value);
|
assert(value);
|
||||||
|
@ -146,7 +146,7 @@ int vm_exec_instr(vm_t* vm, mod_t* mod, Opcode op, param_t param)
|
||||||
: (!same_type || !eq)),
|
: (!same_type || !eq)),
|
||||||
rhs->line);
|
rhs->line);
|
||||||
|
|
||||||
vm_push_value(vm, mod, res);
|
vm_push_new_value(vm, mod, res);
|
||||||
|
|
||||||
vm->pc++;
|
vm->pc++;
|
||||||
} break;
|
} break;
|
||||||
|
@ -176,7 +176,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);
|
value_t* res = tysy_new_bool(vm->tysy, val, lhs->line);
|
||||||
vm_push_value(vm, mod, res);
|
vm_push_new_value(vm, mod, res);
|
||||||
|
|
||||||
vm->pc++;
|
vm->pc++;
|
||||||
} break;
|
} break;
|
||||||
|
@ -210,7 +210,89 @@ 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);
|
value_t* res = tysy_new_num(vm->tysy, val, lhs->line);
|
||||||
vm_push_value(vm, mod, res);
|
vm_push_new_value(vm, mod, res);
|
||||||
|
|
||||||
|
vm->pc++;
|
||||||
|
} break;
|
||||||
|
|
||||||
|
case OP_STRCAT: {
|
||||||
|
int r = vm_pop(vm);
|
||||||
|
int l = vm_pop(vm);
|
||||||
|
|
||||||
|
value_t* lhs = mod->values.data[l];
|
||||||
|
value_t* rhs = mod->values.data[r];
|
||||||
|
|
||||||
|
vm_ensure_type(vm, lhs, TYPE_STR);
|
||||||
|
vm_ensure_type(vm, rhs, TYPE_STR);
|
||||||
|
|
||||||
|
str_t res;
|
||||||
|
str_init(&res);
|
||||||
|
str_append(&res, lhs->value.str);
|
||||||
|
str_append(&res, rhs->value.str);
|
||||||
|
|
||||||
|
value_t* value = tysy_new_str(vm->tysy, res.data, lhs->line);
|
||||||
|
str_free(&res);
|
||||||
|
|
||||||
|
vm_push_new_value(vm, mod, value);
|
||||||
|
|
||||||
|
vm->pc++;
|
||||||
|
} break;
|
||||||
|
|
||||||
|
case OP_STRDUP: {
|
||||||
|
int r = vm_pop(vm);
|
||||||
|
int l = vm_pop(vm);
|
||||||
|
|
||||||
|
value_t* lhs = mod->values.data[l];
|
||||||
|
value_t* rhs = mod->values.data[r];
|
||||||
|
|
||||||
|
if (lhs->type->kind != TYPE_NUM)
|
||||||
|
{
|
||||||
|
value_t* tmp = lhs;
|
||||||
|
lhs = rhs;
|
||||||
|
rhs = tmp;
|
||||||
|
}
|
||||||
|
|
||||||
|
vm_ensure_type(vm, lhs, TYPE_NUM);
|
||||||
|
vm_ensure_type(vm, rhs, TYPE_STR);
|
||||||
|
|
||||||
|
str_t res;
|
||||||
|
str_init(&res);
|
||||||
|
|
||||||
|
for (int i=0; i<(int) lhs->value.num; i++)
|
||||||
|
{
|
||||||
|
str_append(&res, rhs->value.str);
|
||||||
|
}
|
||||||
|
|
||||||
|
value_t* value = tysy_new_str(vm->tysy, res.data, lhs->line);
|
||||||
|
str_free(&res);
|
||||||
|
|
||||||
|
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->pc++;
|
||||||
} break;
|
} break;
|
||||||
|
@ -225,11 +307,49 @@ int vm_exec_instr(vm_t* vm, mod_t* mod, Opcode op, param_t param)
|
||||||
double val = -lhs->value.num;
|
double val = -lhs->value.num;
|
||||||
|
|
||||||
value_t* res = tysy_new_num(vm->tysy, val, lhs->line);
|
value_t* res = tysy_new_num(vm->tysy, val, lhs->line);
|
||||||
vm_push_value(vm, mod, res);
|
vm_push_new_value(vm, mod, res);
|
||||||
|
|
||||||
vm->pc++;
|
vm->pc++;
|
||||||
} break;
|
} break;
|
||||||
|
|
||||||
|
case OP_NOT: {
|
||||||
|
int l = vm_pop(vm);
|
||||||
|
value_t* lhs = mod->values.data[l];
|
||||||
|
vm_ensure_type(vm, lhs, TYPE_BOOL);
|
||||||
|
|
||||||
|
int val = !lhs->value.bool;
|
||||||
|
|
||||||
|
value_t* res = tysy_new_bool(vm->tysy, val, lhs->line);
|
||||||
|
vm_push_new_value(vm, mod, res);
|
||||||
|
|
||||||
|
vm->pc++;
|
||||||
|
} break;
|
||||||
|
|
||||||
|
case OP_BRT:
|
||||||
|
case OP_BRF: {
|
||||||
|
param_t p = vm_pop(vm);
|
||||||
|
value_t* value = mod->values.data[p];
|
||||||
|
vm_ensure_type(vm, value, TYPE_BOOL);
|
||||||
|
|
||||||
|
if (op == OP_BRT && value->value.bool)
|
||||||
|
{
|
||||||
|
vm->pc = param;
|
||||||
|
}
|
||||||
|
else if (op == OP_BRF && !value->value.bool)
|
||||||
|
{
|
||||||
|
vm->pc = param;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
vm->pc++;
|
||||||
|
}
|
||||||
|
|
||||||
|
} break;
|
||||||
|
|
||||||
|
case OP_BR: {
|
||||||
|
vm->pc = param;
|
||||||
|
} break;
|
||||||
|
|
||||||
default: {
|
default: {
|
||||||
fprintf(stderr, "Cannot execute unknown opcode '%s'.\n",
|
fprintf(stderr, "Cannot execute unknown opcode '%s'.\n",
|
||||||
OpcodeStr[op]);
|
OpcodeStr[op]);
|
||||||
|
@ -256,5 +376,6 @@ void vm_ensure_type(vm_t* vm, value_t* value, TypeKind want)
|
||||||
TypeKindStr[got] + strlen("TYPE_"));
|
TypeKindStr[got] + strlen("TYPE_"));
|
||||||
|
|
||||||
err_fatal(vm->err, msg, line);
|
err_fatal(vm->err, msg, line);
|
||||||
|
err_dump(vm->err);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
2
lib/vm.h
2
lib/vm.h
|
@ -20,7 +20,7 @@ typedef struct {
|
||||||
void vm_init(vm_t* vm, tysy_t* tysy, err_t* err);
|
void vm_init(vm_t* vm, tysy_t* tysy, err_t* err);
|
||||||
void vm_free(vm_t* vm);
|
void vm_free(vm_t* vm);
|
||||||
|
|
||||||
void vm_push_value(vm_t* vm, mod_t* mod, value_t* value);
|
void vm_push_new_value(vm_t* vm, mod_t* mod, value_t* value);
|
||||||
void vm_push(vm_t* vm, param_t param);
|
void vm_push(vm_t* vm, param_t param);
|
||||||
param_t vm_pop(vm_t* vm);
|
param_t vm_pop(vm_t* vm);
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,16 @@
|
||||||
|
# BOOL ARITHMETIC
|
||||||
|
# ===============
|
||||||
|
assert not true == false
|
||||||
|
assert not false == true
|
||||||
|
assert false == not true
|
||||||
|
assert not not true == true
|
||||||
|
assert not not not false == true
|
||||||
|
assert (true and true) == true
|
||||||
|
assert (true and false) == false
|
||||||
|
assert (false and true) == false
|
||||||
|
assert (false and false) == false
|
||||||
|
|
||||||
|
assert (true or true) == true
|
||||||
|
assert (true or false) == true
|
||||||
|
assert (false or true) == true
|
||||||
|
assert (false or false) == false
|
|
@ -1,4 +1,4 @@
|
||||||
# Num Arithmetic
|
# NUM ARITHMETIC
|
||||||
# ==============
|
# ==============
|
||||||
assert 5 + 2 == 7
|
assert 5 + 2 == 7
|
||||||
assert 5 - 2 == 3
|
assert 5 - 2 == 3
|
||||||
|
@ -9,7 +9,7 @@ assert 12 / 4 == 3
|
||||||
assert 5 / 2 == 2.5
|
assert 5 / 2 == 2.5
|
||||||
assert 35 % 8 == 3
|
assert 35 % 8 == 3
|
||||||
assert 2^6 == 64
|
assert 2^6 == 64
|
||||||
|
assert -2^3 == -8
|
||||||
assert 1 + 2 * 3 == 7
|
assert 1 + 2 * 3 == 7
|
||||||
assert (1 + 2) * 3 == 9
|
assert (1 + 2) * 3 == 9
|
||||||
assert 5 == (3 + 2)
|
assert 5 == (3 + 2)
|
|
@ -0,0 +1,14 @@
|
||||||
|
# STRING OPERATIONS
|
||||||
|
# =================
|
||||||
|
|
||||||
|
# concatenation with +
|
||||||
|
assert "hel" + "lo" == "hello"
|
||||||
|
assert "hello" + " " + "world" == "hello world"
|
||||||
|
|
||||||
|
# duplication with *
|
||||||
|
assert "a" * 3 == "aaa"
|
||||||
|
assert 4 * "!" == "!!!!"
|
||||||
|
|
||||||
|
# bonus
|
||||||
|
assert ("a" * 2) + "b" == "aab"
|
||||||
|
assert 4 * ("a" + "b") == "abababab"
|
|
@ -146,3 +146,10 @@ Test(lexer, num_arith) {
|
||||||
"MODULO");
|
"MODULO");
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Test(lexer, bool_arith) {
|
||||||
|
test_lexer("and or not", 3,
|
||||||
|
"AND",
|
||||||
|
"OR",
|
||||||
|
"NOT");
|
||||||
|
}
|
||||||
|
|
|
@ -91,3 +91,11 @@ Test(parser, num_arith) {
|
||||||
test_parser_ok("MOD(DIV(SUB(NUM[1],NUM[2]),NUM[3]))", " (1 - 2) / 3 ");
|
test_parser_ok("MOD(DIV(SUB(NUM[1],NUM[2]),NUM[3]))", " (1 - 2) / 3 ");
|
||||||
test_parser_ok("MOD(POW(NUM[2],ADD(NUM[1],NUM[2])))", " 2^(1+2) ");
|
test_parser_ok("MOD(POW(NUM[2],ADD(NUM[1],NUM[2])))", " 2^(1+2) ");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Test(parser, bool_arith) {
|
||||||
|
test_parser_ok("MOD(OR(AND(BOOL[true],BOOL[false]),NOT(BOOL[true])))",
|
||||||
|
" true and false or not true ");
|
||||||
|
|
||||||
|
test_parser_ok("MOD(ASSERT(AND(BOOL[true],BOOL[false])))",
|
||||||
|
" assert (true and false) ");
|
||||||
|
}
|
||||||
|
|
Loading…
Reference in New Issue