comparison operators.

main
bog 2024-03-19 16:25:02 +01:00
parent f0fa844c8a
commit f1b82208ce
12 changed files with 259 additions and 6 deletions

View File

@ -5,7 +5,9 @@ EXPR ::=
ASSERT ::= (assert_eq|assert_ne) tuple
IN ::= OR (in OR)?
OR ::= AND (or AND)*
AND ::= TERM (and TERM)*
AND ::= EQNE (and EQNE)*
EQNE ::= CMP ((eq|ne) CMP)?
CMP ::= TERM ((lt|le|gt|ge) TERM)?
TERM ::= FACTOR ((add|sub) FACTOR)*
FACTOR ::= USUB ((mul|div|mod) USUB)*
USUB ::= sub* NOT

View File

@ -8,7 +8,8 @@ G(OP_PUSH), G(OP_POP), \
G(OP_ADD), G(OP_SUB), G(OP_USUB), G(OP_MUL), \
G(OP_DIV), G(OP_POW), G(OP_MOD), G(OP_MK_TUPLE), \
G(OP_ASSERT_EQ), G(OP_ASSERT_NE), G(OP_BRF), G(OP_BR), \
G(OP_NOT), G(OP_IN), G(OP_INDEX)
G(OP_NOT), G(OP_IN), G(OP_INDEX), G(OP_EQ), G(OP_LT), \
G(OP_GT)
CCM_ENUM_H(Opcode, OPCODES);

View File

@ -84,6 +84,13 @@ CCM ccm_from_value(ccm_t* self, value_t* value)
}
}
value_t* ccm_to_value(ccm_t* self, CCM value)
{
assert(self);
assert(value < self->values.size);
return (value_t*) self->values.data[value];
}
int ccm_is_num(ccm_t* self, CCM value)
{
value_t const* val = self->values.data[value];
@ -386,3 +393,65 @@ void ccm_not(ccm_t* self)
ccm_push(self, ccm_to_boolean(self, !lhs, line));
}
void ccm_eq(ccm_t* self)
{
CCM ccm_rhs = ccm_pop(self);
CCM ccm_lhs = ccm_pop(self);
value_t* lhs = ccm_to_value(self, ccm_lhs);
value_t* rhs = ccm_to_value(self, ccm_rhs);
int line = ((value_t*) self->values.data[ccm_lhs])->line;
int eq = value_equals(lhs, rhs);
ccm_push(self, ccm_to_boolean(self, eq, line));
}
void ccm_ne(ccm_t* self)
{
CCM ccm_rhs = ccm_pop(self);
CCM ccm_lhs = ccm_pop(self);
value_t* lhs = ccm_to_value(self, ccm_lhs);
value_t* rhs = ccm_to_value(self, ccm_rhs);
int line = ((value_t*) self->values.data[ccm_lhs])->line;
int eq = value_equals(lhs, rhs);
ccm_push(self, ccm_to_boolean(self, !eq, line));
}
void ccm_lt(ccm_t* self)
{
CCM ccm_rhs = ccm_pop(self);
CCM ccm_lhs = ccm_pop(self);
double lhs = ccm_from_num(self, ccm_lhs);
double rhs = ccm_from_num(self, ccm_rhs);
int line = ((value_t*) self->values.data[ccm_lhs])->line;
ccm_push(self, ccm_to_boolean(self, lhs < rhs, line));
}
void ccm_le(ccm_t* self)
{
ccm_gt(self);
ccm_not(self);
}
void ccm_gt(ccm_t* self)
{
CCM ccm_rhs = ccm_pop(self);
CCM ccm_lhs = ccm_pop(self);
double lhs = ccm_from_num(self, ccm_lhs);
double rhs = ccm_from_num(self, ccm_rhs);
int line = ((value_t*) self->values.data[ccm_lhs])->line;
ccm_push(self, ccm_to_boolean(self, lhs > rhs, line));
}
void ccm_ge(ccm_t* self)
{
ccm_lt(self);
ccm_not(self);
}

View File

@ -20,6 +20,7 @@ void ccm_free(ccm_t* self);
size_t ccm_str(ccm_t* self, char* buffer, size_t size);
CCM ccm_from_value(ccm_t* self, value_t* value);
value_t* ccm_to_value(ccm_t* self, CCM value);
int ccm_is_num(ccm_t* self, CCM value);
double ccm_from_num(ccm_t* self, CCM value);
@ -51,4 +52,11 @@ void ccm_mod(ccm_t* self);
void ccm_pow(ccm_t* self);
void ccm_not(ccm_t* self);
void ccm_eq(ccm_t* self);
void ccm_ne(ccm_t* self);
void ccm_lt(ccm_t* self);
void ccm_le(ccm_t* self);
void ccm_gt(ccm_t* self);
void ccm_ge(ccm_t* self);
#endif

View File

@ -30,6 +30,45 @@ void compiler_compile(compiler_t* self,
switch (node->kind)
{
case NODE_LT: {
compiler_compile(self, node->children.data[0], prog);
compiler_compile(self, node->children.data[1], prog);
prog_add_instr(prog, OP_LT, CCM_NO_PARAM);
} break;
case NODE_LE: {
compiler_compile(self, node->children.data[0], prog);
compiler_compile(self, node->children.data[1], prog);
prog_add_instr(prog, OP_GT, CCM_NO_PARAM);
prog_add_instr(prog, OP_NOT, CCM_NO_PARAM);
} break;
case NODE_GT: {
compiler_compile(self, node->children.data[0], prog);
compiler_compile(self, node->children.data[1], prog);
prog_add_instr(prog, OP_GT, CCM_NO_PARAM);
} break;
case NODE_GE: {
compiler_compile(self, node->children.data[0], prog);
compiler_compile(self, node->children.data[1], prog);
prog_add_instr(prog, OP_LT, CCM_NO_PARAM);
prog_add_instr(prog, OP_NOT, CCM_NO_PARAM);
} break;
case NODE_EQ: {
compiler_compile(self, node->children.data[0], prog);
compiler_compile(self, node->children.data[1], prog);
prog_add_instr(prog, OP_EQ, CCM_NO_PARAM);
} break;
case NODE_NE: {
compiler_compile(self, node->children.data[0], prog);
compiler_compile(self, node->children.data[1], prog);
prog_add_instr(prog, OP_EQ, CCM_NO_PARAM);
prog_add_instr(prog, OP_NOT, CCM_NO_PARAM);
} break;
case NODE_INDEX: {
for (size_t i=0; i<node->children.size; i++)
{

View File

@ -44,6 +44,21 @@ void exec_instr(exec_t* self,
switch (op)
{
case OP_EQ: {
ccm_eq(ccm);
self->pc++;
} break;
case OP_LT: {
ccm_lt(ccm);
self->pc++;
} break;
case OP_GT: {
ccm_gt(ccm);
self->pc++;
} break;
case OP_INDEX: {
CCM ccm_target = ccm_pop(ccm);

View File

@ -15,6 +15,12 @@ void lexer_init(lexer_t* self)
str_init(&self->separators);
vec_init(&self->texts);
lexer_add_text(self, "<>", NODE_NE);
lexer_add_text(self, "==", NODE_EQ);
lexer_add_text(self, "<=", NODE_LE);
lexer_add_text(self, ">=", NODE_GE);
lexer_add_text(self, "<", NODE_LT);
lexer_add_text(self, ">", NODE_GT);
lexer_add_text(self, ",", NODE_COMMA);
lexer_add_text(self, "(", NODE_OPAR);
lexer_add_text(self, ")", NODE_CPAR);

View File

@ -12,7 +12,8 @@ G(NODE_DIV), G(NODE_MOD), G(NODE_COMMA), G(NODE_TUPLE), \
G(NODE_ASSERT_EQ), G(NODE_ASSERT_NE), G(NODE_BOOL), \
G(NODE_AND), G(NODE_OR), G(NODE_NOT), G(NODE_IN), \
G(NODE_OSQUARE), G(NODE_CSQUARE), G(NODE_INDEX), \
G(NODE_STR)
G(NODE_STR), G(NODE_LT), G(NODE_LE), G(NODE_GT), \
G(NODE_GE), G(NODE_EQ), G(NODE_NE)
CCM_ENUM_H(NodeKind, NODE_KIND);
@ -23,7 +24,7 @@ typedef struct {
int line;
} node_t;
void node_init(node_t* self, NodeKind kind,
void node_init(node_t* self, NodeKind kind,
char const* value, int line);
void node_free(node_t* self);

View File

@ -229,7 +229,7 @@ node_t* parser_try_new_or(parser_t* self)
node_t* parser_try_new_and(parser_t* self)
{
assert(self);
node_t* lhs = CCM_TRY(parser_try_new_term);
node_t* lhs = CCM_TRY(parser_try_new_eqne);
if (!lhs) { return NULL; }
while (lexer_peek_kind(self->lexer, NODE_AND, 0))
@ -239,7 +239,7 @@ node_t* parser_try_new_and(parser_t* self)
node_init(node, NODE_AND, "", lhs->line);
node_push_new_child(node, lhs);
node_t* rhs = CCM_TRY(parser_try_new_term);
node_t* rhs = CCM_TRY(parser_try_new_eqne);
if (!rhs)
{
@ -256,6 +256,64 @@ node_t* parser_try_new_and(parser_t* self)
return lhs;
}
node_t* parser_try_new_eqne(parser_t* self)
{
assert(self);
node_t* lhs = CCM_TRY(parser_try_new_cmp);
if (!lhs) { return NULL; }
if (lexer_peek_kind(self->lexer, NODE_EQ, 0)
|| lexer_peek_kind(self->lexer, NODE_NE, 0))
{
node_t* node = lexer_try_new_next(self->lexer);
node_t* rhs = CCM_TRY(parser_try_new_cmp);
if (!rhs)
{
node_free(node); free(node);
node_free(lhs); free(lhs);
return NULL;
}
node_push_new_child(node, lhs);
node_push_new_child(node, rhs);
lhs = node;
}
return lhs;
}
node_t* parser_try_new_cmp(parser_t* self)
{
assert(self);
node_t* lhs = CCM_TRY(parser_try_new_term);
if (!lhs) { return NULL; }
if (lexer_peek_kind(self->lexer, NODE_LT, 0)
|| lexer_peek_kind(self->lexer, NODE_LE, 0)
|| lexer_peek_kind(self->lexer, NODE_GT, 0)
|| lexer_peek_kind(self->lexer, NODE_GE, 0))
{
node_t* node = lexer_try_new_next(self->lexer);
node_t* rhs = CCM_TRY(parser_try_new_term);
if (!rhs)
{
node_free(node); free(node);
node_free(lhs); free(lhs);
return NULL;
}
node_push_new_child(node, lhs);
node_push_new_child(node, rhs);
lhs = node;
}
return lhs;
}
node_t* parser_try_new_term(parser_t* self)
{
assert(self);

View File

@ -29,6 +29,8 @@ node_t* parser_try_new_assert(parser_t* self);
node_t* parser_try_new_in(parser_t* self);
node_t* parser_try_new_or(parser_t* self);
node_t* parser_try_new_and(parser_t* self);
node_t* parser_try_new_eqne(parser_t* self);
node_t* parser_try_new_cmp(parser_t* self);
node_t* parser_try_new_term(parser_t* self);
node_t* parser_try_new_factor(parser_t* self);
node_t* parser_try_new_usub(parser_t* self);

23
tests/cmp.ccm Normal file
View File

@ -0,0 +1,23 @@
assert_eq (true, 3 == 3)
assert_eq (false, "3" == 3)
assert_eq (false, 5 == 3)
assert_eq (false, 3 <> 3)
assert_eq (true, "3" <> 3)
assert_eq (true, 5 <> 3)
assert_eq (true, 5 < 7)
assert_eq (false, 5 < 5)
assert_eq (false, 9 < 4)
assert_eq (true, 5 <= 7)
assert_eq (true, 5 <= 5)
assert_eq (false, 9 <= 4)
assert_eq (true, 12 > 1)
assert_eq (false, -2 > -2)
assert_eq (false, 0 > 8)
assert_eq (true, 12 >= 1)
assert_eq (true, -2 >= -2)
assert_eq (false, 0 >= 8)

29
tests/str.ccm Normal file
View File

@ -0,0 +1,29 @@
assert_eq ("hello", "hello")
assert_ne ("hello", "world")
# INDEX
# =====
assert_eq ("hello"[0], "h")
assert_eq ("hello"[1], "e")
assert_eq ("hello"[2], "l")
assert_eq ("hello"[3], "l")
assert_eq ("hello"[4], "o")
assert_eq ("hello"[-5], "h")
assert_eq ("hello"[-4], "e")
assert_eq ("hello"[-3], "l")
assert_eq ("hello"[-2], "l")
assert_eq ("hello"[-1], "o")
# BINOPS
# ======
assert_eq (
"hello world", "hello "
+ "world"
)
assert_eq ("www", "w" * 3)
assert_eq ("wwww", 4 * "w")
assert_eq ("abab", ("a" + "b") * 2)
assert_eq ("abab", 2 * ("a" + "b"))