✨ comparisons operations.
parent
e7e0789cbb
commit
22cf99faa9
|
@ -4,7 +4,9 @@ EXPR ::=
|
|||
| ASSERT
|
||||
ASSERT ::= assert EXPR eq EXPR
|
||||
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)*
|
||||
FACTOR ::= USUB ((mul|div|mod) USUB)*
|
||||
USUB ::= sub* NOT
|
||||
|
|
|
@ -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
|
|
@ -10,7 +10,9 @@ 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_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);
|
||||
|
||||
|
|
|
@ -22,6 +22,8 @@ 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_eq(struct parser* self);
|
||||
struct node* parser_try_cmp(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);
|
||||
|
|
|
@ -11,7 +11,8 @@ 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_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);
|
||||
|
||||
|
|
|
@ -71,4 +71,8 @@ SK state_and(struct state* self);
|
|||
SK state_or(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
|
||||
|
|
|
@ -11,7 +11,9 @@ 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_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);
|
||||
|
||||
|
|
|
@ -76,6 +76,39 @@ void compiler_compile(struct compiler* self,
|
|||
val);
|
||||
} 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: {
|
||||
compiler_compile_children(self, node, prog);
|
||||
prog_add_instr(prog, OP_ADD, SK_NO_PARAM);
|
||||
|
|
|
@ -112,6 +112,21 @@ void exec_execute(struct exec* self,
|
|||
self->pc++;
|
||||
} 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: {
|
||||
state_sub(state);
|
||||
self->pc++;
|
||||
|
|
|
@ -86,7 +86,10 @@ bool lexer_is_sep(struct lexer* self, size_t index)
|
|||
|| c == '*'
|
||||
|| c == '/'
|
||||
|| c == '%'
|
||||
|| c == '^';
|
||||
|| c == '^'
|
||||
|| c == '<'
|
||||
|| c == '>'
|
||||
|| c == '=';
|
||||
}
|
||||
|
||||
bool lexer_next_is(struct lexer* self, TokenKind kind)
|
||||
|
@ -147,6 +150,10 @@ struct token* lexer_try_new_next(struct lexer* self)
|
|||
{
|
||||
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_SUB);
|
||||
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_OPAR);
|
||||
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("eq", TOKEN_ASSERT_EQ, NULL);
|
||||
SK_SCAN_KEYWORD("true", TOKEN_BOOL, "true");
|
||||
|
|
132
lib/src/parser.c
132
lib/src/parser.c
|
@ -176,7 +176,7 @@ struct node* parser_try_or(struct parser* self)
|
|||
struct node* parser_try_and(struct parser* self)
|
||||
{
|
||||
assert(self);
|
||||
struct node* lhs = SK_TRY(parser_try_term);
|
||||
struct node* lhs = SK_TRY(parser_try_eq);
|
||||
if (!lhs) { return NULL; }
|
||||
|
||||
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);
|
||||
struct node* rhs = SK_TRY(parser_try_term);
|
||||
struct node* rhs = SK_TRY(parser_try_eq);
|
||||
|
||||
if (!rhs)
|
||||
{
|
||||
|
@ -203,6 +203,134 @@ struct node* parser_try_and(struct parser* self)
|
|||
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)
|
||||
{
|
||||
assert(self);
|
||||
|
|
|
@ -517,3 +517,44 @@ SK state_not(struct state* self)
|
|||
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)
|
||||
);
|
||||
}
|
||||
|
|
|
@ -96,6 +96,19 @@ static void test_lexer_string()
|
|||
"STRING[\n\r\t\e]"
|
||||
);
|
||||
}
|
||||
|
||||
static void test_lexer_cmp()
|
||||
{
|
||||
test_lexer("< <= > >= == <>", 6,
|
||||
"LT",
|
||||
"LE",
|
||||
"GT",
|
||||
"GE",
|
||||
"EQUAL",
|
||||
"NOT_EQUAL"
|
||||
);
|
||||
}
|
||||
|
||||
void register_lexer()
|
||||
{
|
||||
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, "Floats", test_lexer_float);
|
||||
CU_add_test(suite, "Strings", test_lexer_string);
|
||||
CU_add_test(suite, "Comparisons", test_lexer_cmp);
|
||||
}
|
||||
|
||||
#endif
|
||||
|
|
|
@ -71,6 +71,22 @@ static void test_parser_string()
|
|||
"\"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()
|
||||
{
|
||||
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, "Booleans", test_parser_bool);
|
||||
CU_add_test(suite, "Strings", test_parser_string);
|
||||
CU_add_test(suite, "Comparisons", test_parser_cmp);
|
||||
}
|
||||
|
||||
#endif
|
||||
|
|
Loading…
Reference in New Issue