comparisons operations.

main
bog 2024-04-01 23:33:43 +02:00
parent e7e0789cbb
commit 22cf99faa9
14 changed files with 294 additions and 7 deletions

View File

@ -4,7 +4,9 @@ EXPR ::=
| ASSERT | ASSERT
ASSERT ::= assert EXPR eq EXPR ASSERT ::= assert EXPR eq EXPR
OR ::= AND (or AND)* OR ::= AND (or AND)*
AND ::= TERM (and TERM)* AND ::= EQ (and EQ)*
EQ ::= CMP ((equal|not_equal) CMP)?
CMP ::= TERM ((lt|gt|le|ge) TERM)?
TERM ::= FACTOR ((add|sub) FACTOR)* TERM ::= FACTOR ((add|sub) FACTOR)*
FACTOR ::= USUB ((mul|div|mod) USUB)* FACTOR ::= USUB ((mul|div|mod) USUB)*
USUB ::= sub* NOT USUB ::= sub* NOT

17
features/cmp.sk Normal file
View File

@ -0,0 +1,17 @@
assert 4 < 5 eq true
assert 5 < 5 eq false
assert 6 < 5 eq false
assert 4 <= 5 eq true
assert 5 <= 5 eq true
assert 6 <= 5 eq false
assert 3 > 1 eq true
assert 3 > 3 eq false
assert 3.0 > 7.9 eq false
assert 3 >= 1 eq true
assert 3 >= 3 eq true
assert 3 >= 7 eq false
assert 5 == 5 eq true
assert 5 <> 4 eq true
assert "bim" <> "bim" eq false

View File

@ -10,7 +10,9 @@ G(NODE_ADD), G(NODE_SUB), G(NODE_MUL),\
G(NODE_DIV), G(NODE_POW), G(NODE_MOD),\ 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_BOOL), G(NODE_AND), G(NODE_OR), \
G(NODE_NOT), G(NODE_FLOAT), G(NODE_STRING) G(NODE_NOT), G(NODE_FLOAT), G(NODE_STRING), \
G(NODE_LT), G(NODE_LE), G(NODE_GT), G(NODE_GE), \
G(NODE_EQUAL), G(NODE_NOT_EQUAL)
SK_ENUM_H(NodeKind, NODE_KIND); SK_ENUM_H(NodeKind, NODE_KIND);

View File

@ -22,6 +22,8 @@ struct node* parser_try_expr(struct parser* self);
struct node* parser_try_assert(struct parser* self); struct node* parser_try_assert(struct parser* self);
struct node* parser_try_or(struct parser* self); struct node* parser_try_or(struct parser* self);
struct node* parser_try_and(struct parser* self); struct node* parser_try_and(struct parser* self);
struct node* parser_try_eq(struct parser* self);
struct node* parser_try_cmp(struct parser* self);
struct node* parser_try_term(struct parser* self); struct node* parser_try_term(struct parser* self);
struct node* parser_try_factor(struct parser* self); struct node* parser_try_factor(struct parser* self);
struct node* parser_try_usub(struct parser* self); struct node* parser_try_usub(struct parser* self);

View File

@ -11,7 +11,8 @@ G(OP_ADD), G(OP_SUB), G(OP_MUL), \
G(OP_DIV), G(OP_MOD), G(OP_POW), \ 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_NOT), G(OP_AND), G(OP_OR), \
G(OP_BR), G(OP_BRF) G(OP_BR), G(OP_BRF), G(OP_LT), G(OP_GT), \
G(OP_EQUAL)
SK_ENUM_H(Opcode, OPCODE); SK_ENUM_H(Opcode, OPCODE);

View File

@ -71,4 +71,8 @@ SK state_and(struct state* self);
SK state_or(struct state* self); SK state_or(struct state* self);
SK state_not(struct state* self); SK state_not(struct state* self);
SK state_lt(struct state* self);
SK state_gt(struct state* self);
SK state_eq(struct state* self);
#endif #endif

View File

@ -11,7 +11,9 @@ G(TOKEN_MUL), G(TOKEN_DIV), G(TOKEN_MOD), \
G(TOKEN_POW), G(TOKEN_OPAR), G(TOKEN_CPAR), \ 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_BOOL), G(TOKEN_AND), G(TOKEN_OR), \
G(TOKEN_NOT), G(TOKEN_FLOAT), G(TOKEN_STRING) G(TOKEN_NOT), G(TOKEN_FLOAT), G(TOKEN_STRING), \
G(TOKEN_LT), G(TOKEN_LE), G(TOKEN_GT), G(TOKEN_GE), \
G(TOKEN_EQUAL), G(TOKEN_NOT_EQUAL)
SK_ENUM_H(TokenKind, TOKEN_KIND); SK_ENUM_H(TokenKind, TOKEN_KIND);

View File

@ -76,6 +76,39 @@ void compiler_compile(struct compiler* self,
val); val);
} break; } break;
case NODE_LT: {
compiler_compile_children(self, node, prog);
prog_add_instr(prog, OP_LT, SK_NO_PARAM);
} break;
case NODE_LE: {
compiler_compile_children(self, node, prog);
prog_add_instr(prog, OP_GT, SK_NO_PARAM);
prog_add_instr(prog, OP_NOT, SK_NO_PARAM);
} break;
case NODE_GT: {
compiler_compile_children(self, node, prog);
prog_add_instr(prog, OP_GT, SK_NO_PARAM);
} break;
case NODE_GE: {
compiler_compile_children(self, node, prog);
prog_add_instr(prog, OP_LT, SK_NO_PARAM);
prog_add_instr(prog, OP_NOT, SK_NO_PARAM);
} break;
case NODE_EQUAL: {
compiler_compile_children(self, node, prog);
prog_add_instr(prog, OP_EQUAL, SK_NO_PARAM);
} break;
case NODE_NOT_EQUAL: {
compiler_compile_children(self, node, prog);
prog_add_instr(prog, OP_EQUAL, SK_NO_PARAM);
prog_add_instr(prog, OP_NOT, SK_NO_PARAM);
} break;
case NODE_ADD: { case NODE_ADD: {
compiler_compile_children(self, node, prog); compiler_compile_children(self, node, prog);
prog_add_instr(prog, OP_ADD, SK_NO_PARAM); prog_add_instr(prog, OP_ADD, SK_NO_PARAM);

View File

@ -112,6 +112,21 @@ void exec_execute(struct exec* self,
self->pc++; self->pc++;
} break; } break;
case OP_LT: {
state_lt(state);
self->pc++;
} break;
case OP_GT: {
state_gt(state);
self->pc++;
} break;
case OP_EQUAL: {
state_eq(state);
self->pc++;
} break;
case OP_SUB: { case OP_SUB: {
state_sub(state); state_sub(state);
self->pc++; self->pc++;

View File

@ -86,7 +86,10 @@ bool lexer_is_sep(struct lexer* self, size_t index)
|| c == '*' || c == '*'
|| c == '/' || c == '/'
|| c == '%' || c == '%'
|| c == '^'; || c == '^'
|| c == '<'
|| c == '>'
|| c == '=';
} }
bool lexer_next_is(struct lexer* self, TokenKind kind) bool lexer_next_is(struct lexer* self, TokenKind kind)
@ -147,6 +150,10 @@ struct token* lexer_try_new_next(struct lexer* self)
{ {
return tok; return tok;
} }
SK_SCAN_TEXT("<=", TOKEN_LE);
SK_SCAN_TEXT(">=", TOKEN_GE);
SK_SCAN_TEXT("==", TOKEN_EQUAL);
SK_SCAN_TEXT("<>", TOKEN_NOT_EQUAL);
SK_SCAN_TEXT("+", TOKEN_ADD); SK_SCAN_TEXT("+", TOKEN_ADD);
SK_SCAN_TEXT("-", TOKEN_SUB); SK_SCAN_TEXT("-", TOKEN_SUB);
SK_SCAN_TEXT("*", TOKEN_MUL); SK_SCAN_TEXT("*", TOKEN_MUL);
@ -155,6 +162,8 @@ struct token* lexer_try_new_next(struct lexer* self)
SK_SCAN_TEXT("%", TOKEN_MOD); SK_SCAN_TEXT("%", TOKEN_MOD);
SK_SCAN_TEXT("(", TOKEN_OPAR); SK_SCAN_TEXT("(", TOKEN_OPAR);
SK_SCAN_TEXT(")", TOKEN_CPAR); SK_SCAN_TEXT(")", TOKEN_CPAR);
SK_SCAN_TEXT(">", TOKEN_GT);
SK_SCAN_TEXT("<", TOKEN_LT);
SK_SCAN_KEYWORD("assert", TOKEN_ASSERT, NULL); SK_SCAN_KEYWORD("assert", TOKEN_ASSERT, NULL);
SK_SCAN_KEYWORD("eq", TOKEN_ASSERT_EQ, NULL); SK_SCAN_KEYWORD("eq", TOKEN_ASSERT_EQ, NULL);
SK_SCAN_KEYWORD("true", TOKEN_BOOL, "true"); SK_SCAN_KEYWORD("true", TOKEN_BOOL, "true");

View File

@ -176,7 +176,7 @@ struct node* parser_try_or(struct parser* self)
struct node* parser_try_and(struct parser* self) struct node* parser_try_and(struct parser* self)
{ {
assert(self); assert(self);
struct node* lhs = SK_TRY(parser_try_term); struct node* lhs = SK_TRY(parser_try_eq);
if (!lhs) { return NULL; } if (!lhs) { return NULL; }
while (lexer_next_is(&self->lexer, TOKEN_AND)) while (lexer_next_is(&self->lexer, TOKEN_AND))
@ -187,7 +187,7 @@ struct node* parser_try_and(struct parser* self)
)); ));
node_push_new_child(node, lhs); node_push_new_child(node, lhs);
struct node* rhs = SK_TRY(parser_try_term); struct node* rhs = SK_TRY(parser_try_eq);
if (!rhs) if (!rhs)
{ {
@ -203,6 +203,134 @@ struct node* parser_try_and(struct parser* self)
return lhs; return lhs;
} }
struct node* parser_try_eq(struct parser* self)
{
assert(self);
struct node* lhs = SK_TRY(parser_try_cmp);
if (!lhs) { return NULL; }
if (lexer_next_is(&self->lexer, TOKEN_EQUAL))
{
struct token* tok = lexer_try_new_next(&self->lexer);
struct node* rhs = SK_TRY(parser_try_cmp);
if (!rhs)
{
node_free(lhs); free(lhs);
return NULL;
}
struct node* node = malloc(sizeof(struct node));
node_init(node, NODE_EQUAL, tok);
node_push_new_child(node, lhs);
node_push_new_child(node, rhs);
lhs = node;
}
else if (lexer_next_is(&self->lexer, TOKEN_NOT_EQUAL))
{
struct token* tok = lexer_try_new_next(&self->lexer);
struct node* rhs = SK_TRY(parser_try_cmp);
if (!rhs)
{
node_free(lhs); free(lhs);
return NULL;
}
struct node* node = malloc(sizeof(struct node));
node_init(node, NODE_NOT_EQUAL, tok);
node_push_new_child(node, lhs);
node_push_new_child(node, rhs);
lhs = node;
}
return lhs;
}
struct node* parser_try_cmp(struct parser* self)
{
assert(self);
struct node* lhs = SK_TRY(parser_try_term);
if (!lhs) { return NULL; }
if (lexer_next_is(&self->lexer, TOKEN_LT))
{
struct token* tok = lexer_try_new_next(&self->lexer);
struct node* rhs = SK_TRY(parser_try_term);
if (!rhs)
{
node_free(lhs); free(lhs);
return NULL;
}
struct node* node = malloc(sizeof(struct node));
node_init(node, NODE_LT, tok);
node_push_new_child(node, lhs);
node_push_new_child(node, rhs);
lhs = node;
}
else if (lexer_next_is(&self->lexer, TOKEN_LE))
{
struct token* tok = lexer_try_new_next(&self->lexer);
struct node* rhs = SK_TRY(parser_try_term);
if (!rhs)
{
node_free(lhs); free(lhs);
return NULL;
}
struct node* node = malloc(sizeof(struct node));
node_init(node, NODE_LE, tok);
node_push_new_child(node, lhs);
node_push_new_child(node, rhs);
lhs = node;
}
else if (lexer_next_is(&self->lexer, TOKEN_GT))
{
struct token* tok = lexer_try_new_next(&self->lexer);
struct node* rhs = SK_TRY(parser_try_term);
if (!rhs)
{
node_free(lhs); free(lhs);
return NULL;
}
struct node* node = malloc(sizeof(struct node));
node_init(node, NODE_GT, tok);
node_push_new_child(node, lhs);
node_push_new_child(node, rhs);
lhs = node;
}
else if (lexer_next_is(&self->lexer, TOKEN_GE))
{
struct token* tok = lexer_try_new_next(&self->lexer);
struct node* rhs = SK_TRY(parser_try_term);
if (!rhs)
{
node_free(lhs); free(lhs);
return NULL;
}
struct node* node = malloc(sizeof(struct node));
node_init(node, NODE_GE, tok);
node_push_new_child(node, lhs);
node_push_new_child(node, rhs);
lhs = node;
}
return lhs;
}
struct node* parser_try_term(struct parser* self) struct node* parser_try_term(struct parser* self)
{ {
assert(self); assert(self);

View File

@ -517,3 +517,44 @@ SK state_not(struct state* self)
left->line left->line
); );
} }
SK state_lt(struct state* self)
{
assert(self);
SK rhs = state_pop(self);
SK lhs = state_pop(self);
return state_push_bool(
self,
state_as_real(self, lhs) < state_as_real(self, rhs),
state_line(self, lhs)
);
}
SK state_gt(struct state* self)
{
assert(self);
SK rhs = state_pop(self);
SK lhs = state_pop(self);
return state_push_bool(
self,
state_as_real(self, lhs) > state_as_real(self, rhs),
state_line(self, lhs)
);
}
SK state_eq(struct state* self)
{
assert(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,
value_equals(left, right),
state_line(self, lhs)
);
}

View File

@ -96,6 +96,19 @@ static void test_lexer_string()
"STRING[\n\r\t\e]" "STRING[\n\r\t\e]"
); );
} }
static void test_lexer_cmp()
{
test_lexer("< <= > >= == <>", 6,
"LT",
"LE",
"GT",
"GE",
"EQUAL",
"NOT_EQUAL"
);
}
void register_lexer() void register_lexer()
{ {
CU_pSuite suite = CU_add_suite("Lexer", 0, 0); CU_pSuite suite = CU_add_suite("Lexer", 0, 0);
@ -104,6 +117,7 @@ void register_lexer()
CU_add_test(suite, "Booleans", test_lexer_bool); CU_add_test(suite, "Booleans", test_lexer_bool);
CU_add_test(suite, "Floats", test_lexer_float); CU_add_test(suite, "Floats", test_lexer_float);
CU_add_test(suite, "Strings", test_lexer_string); CU_add_test(suite, "Strings", test_lexer_string);
CU_add_test(suite, "Comparisons", test_lexer_cmp);
} }
#endif #endif

View File

@ -71,6 +71,22 @@ static void test_parser_string()
"\"ok pizza NOW\""); "\"ok pizza NOW\"");
} }
static void test_parser_cmp()
{
test_parser("ROOT(LT(INT[5],INT[3]))",
"5<3");
test_parser("ROOT(LE(INT[5],INT[3]))",
"5<=3");
test_parser("ROOT(GT(INT[5],INT[3]))",
"5>3");
test_parser("ROOT(GE(INT[5],INT[3]))",
"5>=3");
test_parser("ROOT(EQUAL(INT[5],INT[3]))",
"5==3");
test_parser("ROOT(NOT_EQUAL(INT[5],INT[3]))",
"5<>3");
}
void register_parser() void register_parser()
{ {
CU_pSuite suite = CU_add_suite("Parser", 0, 0); CU_pSuite suite = CU_add_suite("Parser", 0, 0);
@ -78,6 +94,7 @@ void register_parser()
CU_add_test(suite, "Assertions", test_parser_assert); CU_add_test(suite, "Assertions", test_parser_assert);
CU_add_test(suite, "Booleans", test_parser_bool); CU_add_test(suite, "Booleans", test_parser_bool);
CU_add_test(suite, "Strings", test_parser_string); CU_add_test(suite, "Strings", test_parser_string);
CU_add_test(suite, "Comparisons", test_parser_cmp);
} }
#endif #endif