bool arithmetic.

main
bog 2024-04-01 14:00:06 +02:00
parent e8b10498cf
commit 7a10a7f330
17 changed files with 432 additions and 21 deletions

View File

@ -1,14 +1,18 @@
ROOT ::= EXPR*
EXPR ::=
| TERM
| OR
| ASSERT
ASSERT ::= assert EXPR eq EXPR
OR ::= AND (or AND)*
AND ::= TERM (and TERM)*
TERM ::= FACTOR ((add|sub) FACTOR)*
FACTOR ::= USUB ((mul|div|mod) USUB)*
USUB ::= sub* POW
USUB ::= sub* NOT
NOT ::= not* POW
POW ::= LITERAL (pow LITERAL)?
LITERAL ::=
| BUILTIN
| opar EXPR cpar
BUILTIN ::=
| int
| bool

15
features/bool.sk Normal file
View File

@ -0,0 +1,15 @@
assert true eq true
assert false eq false
assert not true eq false
assert not false eq true
assert true and true eq true
assert true and false eq false
assert false and true eq false
assert false and false eq false
assert true or true eq true
assert true or false eq true
assert false or true eq true
assert false or false eq false

View File

@ -18,5 +18,19 @@ void compiler_compile(struct compiler* self,
void compiler_compile_children(struct compiler* self,
struct node* node,
struct prog* prog);
void compiler_compile_value(struct compiler* self,
struct node* node,
struct prog* prog,
TypeKind type,
union val val);
void compiler_compile_and(struct compiler* self,
struct node* node,
struct prog* prog);
void compiler_compile_or(struct compiler* self,
struct node* node,
struct prog* prog);
#endif

View File

@ -8,7 +8,9 @@ G(NODE_ROOT), \
G(NODE_INT), \
G(NODE_ADD), G(NODE_SUB), G(NODE_MUL),\
G(NODE_DIV), G(NODE_POW), G(NODE_MOD),\
G(NODE_USUB), G(NODE_ASSERT_EQ)
G(NODE_USUB), G(NODE_ASSERT_EQ), \
G(NODE_BOOL), G(NODE_AND), G(NODE_OR), \
G(NODE_NOT)
SK_ENUM_H(NodeKind, NODE_KIND);

View File

@ -20,9 +20,12 @@ struct node* parser_try_parse(struct parser* self);
struct node* parser_try_root(struct parser* self);
struct node* parser_try_expr(struct parser* self);
struct node* parser_try_assert(struct parser* self);
struct node* parser_try_or(struct parser* self);
struct node* parser_try_and(struct parser* self);
struct node* parser_try_term(struct parser* self);
struct node* parser_try_factor(struct parser* self);
struct node* parser_try_usub(struct parser* self);
struct node* parser_try_not(struct parser* self);
struct node* parser_try_pow(struct parser* self);
struct node* parser_try_literal(struct parser* self);
struct node* parser_try_builtin(struct parser* self);

View File

@ -9,7 +9,9 @@
G(OP_PUSH), \
G(OP_ADD), G(OP_SUB), G(OP_MUL), \
G(OP_DIV), G(OP_MOD), G(OP_POW), \
G(OP_USUB), G(OP_ASSERT_EQ)
G(OP_USUB), G(OP_ASSERT_EQ), \
G(OP_NOT), G(OP_AND), G(OP_OR), \
G(OP_BR), G(OP_BRF)
SK_ENUM_H(Opcode, OPCODE);

View File

@ -44,7 +44,13 @@ struct value* state_try_get_value(struct state* self, SK value);
SK state_pop(struct state* self);
SK state_push(struct state* self,
TypeKind type,
union val val,
int line);
SK state_push_int(struct state* self, int integer, int line);
SK state_push_bool(struct state* self, bool boolean, int line);
SK state_add(struct state* self);
SK state_sub(struct state* self);
@ -54,4 +60,8 @@ SK state_div(struct state* self);
SK state_mod(struct state* self);
SK state_pow(struct state* self);
SK state_and(struct state* self);
SK state_or(struct state* self);
SK state_not(struct state* self);
#endif

View File

@ -9,7 +9,9 @@ G(TOKEN_INT), \
G(TOKEN_ADD), G(TOKEN_SUB), \
G(TOKEN_MUL), G(TOKEN_DIV), G(TOKEN_MOD), \
G(TOKEN_POW), G(TOKEN_OPAR), G(TOKEN_CPAR), \
G(TOKEN_ASSERT), G(TOKEN_ASSERT_EQ)
G(TOKEN_ASSERT), G(TOKEN_ASSERT_EQ), \
G(TOKEN_BOOL), G(TOKEN_AND), G(TOKEN_OR), \
G(TOKEN_NOT)
SK_ENUM_H(TokenKind, TOKEN_KIND);

View File

@ -5,13 +5,14 @@
#include "node.h"
#define TYPE_KIND(G) \
G(TYPE_INT)
G(TYPE_INT), G(TYPE_BOOL)
SK_ENUM_H(TypeKind, TYPE_KIND);
union val
{
int integer;
bool boolean;
};
struct value

View File

@ -29,19 +29,37 @@ void compiler_compile(struct compiler* self,
}
} break;
case NODE_NOT: {
compiler_compile_children(self, node, prog);
prog_add_instr(prog, OP_NOT, SK_NO_PARAM);
} break;
case NODE_AND: {
compiler_compile_and(self, node, prog);
} break;
case NODE_OR: {
compiler_compile_or(self, node, prog);
} break;
case NODE_ASSERT_EQ: {
compiler_compile_children(self, node, prog);
prog_add_instr(prog, OP_ASSERT_EQ, SK_NO_PARAM);
} break;
case NODE_BOOL: {
union val val;
val.boolean =
strcmp(node->token->value, "true") == 0;
compiler_compile_value(self, node, prog, TYPE_BOOL,
val);
} break;
case NODE_INT: {
struct value* value = malloc(sizeof(struct value));
union val val;
val.integer = atoi(node->token->value);
value_init(value, TYPE_INT, val, node->token->line);
size_t idx = prog_add_constant(prog, value);
prog_add_instr(prog, OP_PUSH, idx);
compiler_compile_value(self, node, prog, TYPE_INT,
val);
} break;
case NODE_ADD: {
@ -101,3 +119,101 @@ void compiler_compile_children(struct compiler* self,
compiler_compile(self, child, prog);
}
}
void compiler_compile_value(struct compiler* self,
struct node* node,
struct prog* prog,
TypeKind type,
union val val)
{
(void) self;
struct value* value = malloc(sizeof(struct value));
value_init(value, type, val, node->token->line);
size_t idx = prog_add_constant(prog, value);
prog_add_instr(prog, OP_PUSH, idx);
}
void compiler_compile_and(struct compiler* self,
struct node* node,
struct prog* prog)
{
assert(self);
assert(node);
assert(prog);
struct vec to_false;
vec_init(&to_false);
for (size_t i =0; i<node->children.size; i++)
{
struct node* child = node->children.data[i];
compiler_compile(self, child, prog);
size_t brf = prog_add_instr(prog, OP_BRF, 0); // to false
vec_push(&to_false, (void*) brf);
}
union val tval;
tval.boolean = true;
compiler_compile_value(self, node, prog, TYPE_BOOL, tval);
size_t to_end = prog_add_instr(prog, OP_BR, 0);
union val fval;
fval.boolean = false;
size_t false_point = prog->opcodes.size;
compiler_compile_value(self, node, prog, TYPE_BOOL, fval);
size_t end_point = prog->opcodes.size;
((size_t*)prog->params.data)[to_end] = end_point;
for (size_t i=0; i<to_false.size; i++)
{
((size_t*)prog->params.data)[(size_t)
to_false.data[i]] = false_point;
}
vec_free(&to_false);
}
void compiler_compile_or(struct compiler* self,
struct node* node,
struct prog* prog)
{
assert(self);
assert(node);
assert(prog);
struct vec to_true;
vec_init(&to_true);
for (size_t i =0; i<node->children.size; i++)
{
struct node* child = node->children.data[i];
compiler_compile(self, child, prog);
prog_add_instr(prog, OP_NOT, 0);
size_t brf = prog_add_instr(prog, OP_BRF, 0); // to true
vec_push(&to_true, (void*) brf);
}
union val fval;
fval.boolean = false;
compiler_compile_value(self, node, prog, TYPE_BOOL, fval);
size_t to_end = prog_add_instr(prog, OP_BR, 0);
union val tval;
tval.boolean = true;
size_t true_point = prog->opcodes.size;
compiler_compile_value(self, node, prog, TYPE_BOOL, tval);
size_t end_point = prog->opcodes.size;
((size_t*)prog->params.data)[to_end] = end_point;
for (size_t i=0; i<to_true.size; i++)
{
((size_t*)prog->params.data)[(size_t)
to_true.data[i]] = true_point;
}
vec_free(&to_true);
}

View File

@ -49,7 +49,7 @@ void exec_execute(struct exec* self,
str_init(&rstr);
value_str(right, &rstr);
errors_push(left->line,
errors_push(left->line,
"assertion failed"
"\n\texpected: %s"
"\n\tgot: %s",
@ -73,6 +73,15 @@ void exec_execute(struct exec* self,
constant->line
);
} break;
case TYPE_BOOL: {
state_push_bool(
state,
constant->val.boolean,
constant->line
);
} break;
default: {
fprintf(stderr, "cannot push value '%s'\n",
TypeKindStr[constant->type]);
@ -117,6 +126,41 @@ void exec_execute(struct exec* self,
self->pc++;
} break;
case OP_NOT: {
state_not(state);
self->pc++;
} break;
case OP_AND: {
state_and(state);
self->pc++;
} break;
case OP_OR: {
state_or(state);
self->pc++;
} break;
case OP_BR: {
self->pc = param;
} break;
case OP_BRF: {
SK addr = state_pop(state);
bool val =
state_try_get_value(state, addr)->val.boolean;
if (!val)
{
self->pc = param;
}
else
{
self->pc++;
}
} break;
default: {
fprintf(stderr, "cannot execute opcode '%s'\n",
OpcodeStr[opcode]);

View File

@ -122,6 +122,11 @@ struct token* lexer_try_new_next(struct lexer* self)
SK_SCAN_TEXT(")", TOKEN_CPAR);
SK_SCAN_KEYWORD("assert", TOKEN_ASSERT, NULL);
SK_SCAN_KEYWORD("eq", TOKEN_ASSERT_EQ, NULL);
SK_SCAN_KEYWORD("true", TOKEN_BOOL, "true");
SK_SCAN_KEYWORD("false", TOKEN_BOOL, "false");
SK_SCAN_KEYWORD("and", TOKEN_AND, NULL);
SK_SCAN_KEYWORD("or", TOKEN_OR, NULL);
SK_SCAN_KEYWORD("not", TOKEN_NOT, NULL);
if (self->context.cursor < self->len)
{

View File

@ -73,7 +73,7 @@ struct node* parser_try_expr(struct parser* self)
return SK_TRY(parser_try_assert);
}
return SK_TRY(parser_try_term);
return SK_TRY(parser_try_or);
}
struct node* parser_try_assert(struct parser* self)
@ -99,11 +99,11 @@ struct node* parser_try_assert(struct parser* self)
lexer_consume_next(&self->lexer);
struct node* rhs = SK_TRY(parser_try_expr);
if (!rhs)
if (!rhs)
{
token_free(tok);
free(tok);
return NULL;
return NULL;
}
struct node* node = malloc(sizeof(struct node));
@ -113,6 +113,66 @@ struct node* parser_try_assert(struct parser* self)
return node;
}
struct node* parser_try_or(struct parser* self)
{
assert(self);
struct node* lhs = SK_TRY(parser_try_and);
if (!lhs) { return NULL; }
while (lexer_next_is(&self->lexer, TOKEN_OR))
{
struct node* node = malloc(sizeof(struct node));
node_init(node, NODE_OR, lexer_try_new_next(
&self->lexer
));
node_push_new_child(node, lhs);
struct node* rhs = SK_TRY(parser_try_and);
if (!rhs)
{
node_free(node);
free(node);
return NULL;
}
node_push_new_child(node, rhs);
lhs = node;
}
return lhs;
}
struct node* parser_try_and(struct parser* self)
{
assert(self);
struct node* lhs = SK_TRY(parser_try_term);
if (!lhs) { return NULL; }
while (lexer_next_is(&self->lexer, TOKEN_AND))
{
struct node* node = malloc(sizeof(struct node));
node_init(node, NODE_AND, lexer_try_new_next(
&self->lexer
));
node_push_new_child(node, lhs);
struct node* rhs = SK_TRY(parser_try_term);
if (!rhs)
{
node_free(node);
free(node);
return NULL;
}
node_push_new_child(node, rhs);
lhs = node;
}
return lhs;
}
struct node* parser_try_term(struct parser* self)
{
assert(self);
@ -225,6 +285,33 @@ struct node* parser_try_usub(struct parser* self)
return node;
}
return SK_TRY(parser_try_not);
}
struct node* parser_try_not(struct parser* self)
{
assert(self);
if (lexer_next_is(&self->lexer, TOKEN_NOT))
{
struct node* node = malloc(sizeof(struct node));
node_init(node, NODE_NOT, lexer_try_new_next(
&self->lexer
));
struct node* child = SK_TRY(parser_try_not);
if (!child)
{
node_free(node);
free(node);
return NULL;
}
node_push_new_child(node, child);
return node;
}
return SK_TRY(parser_try_pow);
}
@ -290,6 +377,17 @@ struct node* parser_try_literal(struct parser* self)
struct node* parser_try_builtin(struct parser* self)
{
if (lexer_next_is(&self->lexer, TOKEN_BOOL))
{
struct node* node = malloc(sizeof(struct node));
node_init(node,
NODE_BOOL,
lexer_try_new_next(&self->lexer));
return node;
}
if (lexer_next_is(&self->lexer, TOKEN_INT))
{
struct node* node = malloc(sizeof(struct node));

View File

@ -107,14 +107,15 @@ SK state_pop(struct state* self)
return value;
}
SK state_push_int(struct state* self, int integer, int line)
SK state_push(struct state* self,
TypeKind type,
union val val,
int line)
{
assert(self);
struct value* value = malloc(sizeof(struct value));
union val val;
val.integer = integer;
value_init(value, TYPE_INT, val, line);
value_init(value, type, val, line);
struct frame* frame = state_frame(self);
struct local* local = malloc(sizeof(struct local));
@ -125,8 +126,26 @@ SK state_push_int(struct state* self, int integer, int line)
self->addr++;
return self->addr - 1;
}
SK state_push_int(struct state* self, int integer, int line)
{
assert(self);
union val val;
val.integer = integer;
return state_push(self, TYPE_INT, val, line);
}
SK state_push_bool(struct state* self, bool boolean, int line)
{
assert(self);
union val val;
val.boolean = boolean;
return state_push(self, TYPE_BOOL, val, line);
}
SK state_add(struct state* self)
{
SK rhs = state_pop(self);
@ -229,3 +248,46 @@ SK state_pow(struct state* self)
left->line
);
}
SK state_and(struct state* self)
{
SK rhs = state_pop(self);
SK lhs = state_pop(self);
struct value* left = state_try_get_value(self, lhs);
struct value* right = state_try_get_value(self, rhs);
return state_push_bool(
self,
left->val.boolean && right->val.boolean,
left->line
);
}
SK state_or(struct state* self)
{
SK rhs = state_pop(self);
SK lhs = state_pop(self);
struct value* left = state_try_get_value(self, lhs);
struct value* right = state_try_get_value(self, rhs);
return state_push_bool(
self,
left->val.boolean || right->val.boolean,
left->line
);
}
SK state_not(struct state* self)
{
SK lhs = state_pop(self);
struct value* left = state_try_get_value(self, lhs);
return state_push_bool(
self,
!left->val.boolean,
left->line
);
}

View File

@ -46,6 +46,11 @@ void value_str(struct value* self, struct str* dest)
case TYPE_INT: {
str_format(dest, "%d", self->val.integer);
} break;
case TYPE_BOOL: {
str_format(dest, "%s",
self->val.boolean ? "true" : "false");
} break;
default: {
fprintf(stderr, "cannot get value string of '%s'\n",
TypeKindStr[self->type]);

View File

@ -26,7 +26,7 @@ static void test_lexer(char const* source, int count, ...)
fprintf(stderr, "%s != %s\n", oracle, tok_str.value);
}
CU_ASSERT_STRING_EQUAL(tok_str.value, oracle);
CU_ASSERT_STRING_EQUAL_FATAL(tok_str.value, oracle);
str_free(&tok_str);
token_free(tok);
free(tok);
@ -60,11 +60,22 @@ static void test_lexer_assert()
);
}
static void test_lexer_bool()
{
test_lexer("true false and or not", 5,
"BOOL[true]",
"BOOL[false]",
"AND",
"OR",
"NOT"
);
}
void register_lexer()
{
CU_pSuite suite = CU_add_suite("Lexer", 0, 0);
CU_add_test(suite, "Integers", test_lexer_int);
CU_add_test(suite, "Assertions", test_lexer_assert);
CU_add_test(suite, "Booleans", test_lexer_bool);
}
#endif

View File

@ -44,15 +44,32 @@ static void test_parser_int()
static void test_parser_assert()
{
test_parser("ROOT(ASSERT_EQ(INT[32],INT[12]))",
test_parser("ROOT(ASSERT_EQ(INT[32],INT[12]))",
" assert 32 eq 12 ");
}
static void test_parser_bool()
{
test_parser("ROOT(BOOL[true])",
"true");
test_parser("ROOT(NOT(BOOL[false]))",
"not false");
test_parser("ROOT(OR(AND(NOT(BOOL[false]),BOOL[true]),"
"BOOL[false]))",
"not false and true or false");
test_parser("ROOT(AND(NOT(BOOL[false]),OR(BOOL[true],"
"BOOL[false])))",
"not false and (true or false)");
}
void register_parser()
{
CU_pSuite suite = CU_add_suite("Parser", 0, 0);
CU_add_test(suite, "Integers", test_parser_int);
CU_add_test(suite, "Assertions", test_parser_assert);
CU_add_test(suite, "Booleans", test_parser_bool);
}
#endif