diff --git a/doc/grammar.bnf b/doc/grammar.bnf index f8abd01..12db630 100644 --- a/doc/grammar.bnf +++ b/doc/grammar.bnf @@ -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 diff --git a/features/bool.sk b/features/bool.sk new file mode 100644 index 0000000..533b169 --- /dev/null +++ b/features/bool.sk @@ -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 diff --git a/lib/include/compiler.h b/lib/include/compiler.h index 5f4c0c6..7db4ae3 100644 --- a/lib/include/compiler.h +++ b/lib/include/compiler.h @@ -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 diff --git a/lib/include/node.h b/lib/include/node.h index 0857517..c01263c 100644 --- a/lib/include/node.h +++ b/lib/include/node.h @@ -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); diff --git a/lib/include/parser.h b/lib/include/parser.h index ec79eb2..7d09a7d 100644 --- a/lib/include/parser.h +++ b/lib/include/parser.h @@ -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); diff --git a/lib/include/prog.h b/lib/include/prog.h index fe14679..d230327 100644 --- a/lib/include/prog.h +++ b/lib/include/prog.h @@ -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); diff --git a/lib/include/state.h b/lib/include/state.h index f185d3a..0dfa780 100644 --- a/lib/include/state.h +++ b/lib/include/state.h @@ -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 diff --git a/lib/include/token.h b/lib/include/token.h index ae26819..ca50d2e 100644 --- a/lib/include/token.h +++ b/lib/include/token.h @@ -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); diff --git a/lib/include/value.h b/lib/include/value.h index 414638c..150d3ce 100644 --- a/lib/include/value.h +++ b/lib/include/value.h @@ -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 diff --git a/lib/src/compiler.c b/lib/src/compiler.c index e98a6d4..851e270 100644 --- a/lib/src/compiler.c +++ b/lib/src/compiler.c @@ -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; ichildren.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; iparams.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; ichildren.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; iparams.data)[(size_t) + to_true.data[i]] = true_point; + } + + vec_free(&to_true); +} diff --git a/lib/src/exec.c b/lib/src/exec.c index 7af42db..fd676b2 100644 --- a/lib/src/exec.c +++ b/lib/src/exec.c @@ -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]); diff --git a/lib/src/lexer.c b/lib/src/lexer.c index d2d951b..8c6e2a9 100644 --- a/lib/src/lexer.c +++ b/lib/src/lexer.c @@ -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) { diff --git a/lib/src/parser.c b/lib/src/parser.c index ffa4b55..0a6b6b1 100644 --- a/lib/src/parser.c +++ b/lib/src/parser.c @@ -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)); diff --git a/lib/src/state.c b/lib/src/state.c index 1985d47..e911ab5 100644 --- a/lib/src/state.c +++ b/lib/src/state.c @@ -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 + ); +} diff --git a/lib/src/value.c b/lib/src/value.c index e3d29b0..bc4406b 100644 --- a/lib/src/value.c +++ b/lib/src/value.c @@ -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]); diff --git a/tests/lexer.h b/tests/lexer.h index 58228fb..a6c42b0 100644 --- a/tests/lexer.h +++ b/tests/lexer.h @@ -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 diff --git a/tests/parser.h b/tests/parser.h index 4fc313a..3340ce8 100644 --- a/tests/parser.h +++ b/tests/parser.h @@ -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