bool arithmetic operators.

main
bog 2023-12-16 19:12:20 +01:00
parent 4f6f3253c2
commit caf6b3b47c
16 changed files with 283 additions and 25 deletions

View File

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

View File

@ -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)
{ {
@ -138,6 +139,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]);

View File

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

View File

@ -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;
@ -131,18 +139,10 @@ int loader_ldfile(loader_t* loader, char const* path, int debug)
if (debug) if (debug)
{ {
{ char msg[RZ_STR_LIMIT];
char msg[RZ_STR_LIMIT]; vm_stack_str(&vm, msg, RZ_STR_LIMIT);
mod_str(&mod, msg, RZ_STR_LIMIT); printf("\n======== STACK ========\n");
printf("%s", msg); printf("%s\n", 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); vm_free(&vm);

View File

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

View File

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

View File

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

View File

@ -9,7 +9,10 @@
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)
RZ_ENUM_H(Opcode, OPCODES); RZ_ENUM_H(Opcode, OPCODES);

View File

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

View File

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

View File

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

View File

@ -215,6 +215,32 @@ int vm_exec_instr(vm_t* vm, mod_t* mod, Opcode op, param_t param)
vm->pc++; vm->pc++;
} break; } 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_value(vm, mod, res);
vm->pc++;
} break;
case OP_USUB: { case OP_USUB: {
int l = vm_pop(vm); int l = vm_pop(vm);
@ -230,6 +256,44 @@ int vm_exec_instr(vm_t* vm, mod_t* mod, Opcode op, param_t param)
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_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]);

View File

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

View File

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

View File

@ -146,3 +146,11 @@ Test(lexer, num_arith) {
"MODULO"); "MODULO");
} }
Test(lexer, bool_arith) {
test_lexer("and or not", 3,
"AND",
"OR",
"NOT");
}

View File

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