From 299c095af4cb1322d848ccd78cb1152da46e4795 Mon Sep 17 00:00:00 2001 From: bog Date: Fri, 25 Aug 2023 11:22:29 +0200 Subject: [PATCH] ADD/ comparisons operators for integers and floats. --- src/compiler.c | 88 ++++++++++++++++++++++++ src/cstatic.c | 35 ++++++++++ src/lex.l | 2 + src/node.h | 3 +- src/opcodes.h | 10 ++- src/parser.y | 76 +++++++++++++++++++-- src/vm.c | 162 +++++++++++++++++++++++++++++++++++++++++++++ src/vm.h | 10 +++ tests/err_cmp.wuz | 24 +++++++ tests/test_cmp.wuz | 33 +++++++++ 10 files changed, 434 insertions(+), 9 deletions(-) create mode 100644 tests/err_cmp.wuz create mode 100644 tests/test_cmp.wuz diff --git a/src/compiler.c b/src/compiler.c index 7ce0307..d30d944 100644 --- a/src/compiler.c +++ b/src/compiler.c @@ -158,6 +158,94 @@ void compile_node(compiler* self, node* root, program* prog) compile_children(self, root, prog); program_add_instr(prog, OP_ASSERT, NO_PARAM); } + else if (root->type == NODE_LT) + { + compile_children(self, root, prog); + cstatic cs; + cstatic_init(&cs); + int base_type = cstatic_resolve_base_type(&cs, + root->children.data[0]); + cstatic_free(&cs); + + if (base_type == TY_INTEGER) + { + program_add_instr(prog, OP_ILT, NO_PARAM); + } + else if (base_type == TY_FLOAT) + { + program_add_instr(prog, OP_FLT, NO_PARAM); + } + else + { + assert(0); + } + } + else if (root->type == NODE_LE) + { + compile_children(self, root, prog); + cstatic cs; + cstatic_init(&cs); + int base_type = cstatic_resolve_base_type(&cs, + root->children.data[0]); + cstatic_free(&cs); + + if (base_type == TY_INTEGER) + { + program_add_instr(prog, OP_ILE, NO_PARAM); + } + else if (base_type == TY_FLOAT) + { + program_add_instr(prog, OP_FLE, NO_PARAM); + } + else + { + assert(0); + } + } + else if (root->type == NODE_GT) + { + compile_children(self, root, prog); + cstatic cs; + cstatic_init(&cs); + int base_type = cstatic_resolve_base_type(&cs, + root->children.data[0]); + cstatic_free(&cs); + + if (base_type == TY_INTEGER) + { + program_add_instr(prog, OP_IGT, NO_PARAM); + } + else if (base_type == TY_FLOAT) + { + program_add_instr(prog, OP_FGT, NO_PARAM); + } + else + { + assert(0); + } + } + else if (root->type == NODE_GE) + { + compile_children(self, root, prog); + cstatic cs; + cstatic_init(&cs); + int base_type = cstatic_resolve_base_type(&cs, + root->children.data[0]); + cstatic_free(&cs); + + if (base_type == TY_INTEGER) + { + program_add_instr(prog, OP_IGE, NO_PARAM); + } + else if (base_type == TY_FLOAT) + { + program_add_instr(prog, OP_FGE, NO_PARAM); + } + else + { + assert(0); + } + } else if (root->type == NODE_UADD) { compile_number(self, root, prog, OP_IUADD, OP_FUADD); diff --git a/src/cstatic.c b/src/cstatic.c index 81b8aee..5ba0804 100644 --- a/src/cstatic.c +++ b/src/cstatic.c @@ -145,8 +145,13 @@ type* cstatic_resolve_new(cstatic* self, node* ast) } else if (ast->type == NODE_BOOLEAN + || ast->type == NODE_LT + || ast->type == NODE_LE + || ast->type == NODE_GT + || ast->type == NODE_GE || ast->type == NODE_EQ || ast->type == NODE_NE) + { return cstatic_new_type(self, TY_BOOLEAN); } @@ -458,6 +463,36 @@ int cstatic_check(cstatic* self, node* ast, char* msg, size_t size) return status; } } + // Comparisons + else if (ast->type == NODE_LT + || ast->type == NODE_LE + || ast->type == NODE_GT + || ast->type == NODE_GE + ) + { + int status = cstatic_check_same_type(self, + ast->children.data[0], + ast->children.data[1], + msg, + size); + + if (!status) + { + return status; + } + + status = cstatic_check_type_base(self, + ast->children.data[0], + msg, + size, + TY_INTEGER, + TY_FLOAT, + TYPE_END); + if (!status) + { + return status; + } + } return 1; } diff --git a/src/lex.l b/src/lex.l index 9e50740..6b422b8 100644 --- a/src/lex.l +++ b/src/lex.l @@ -26,6 +26,8 @@ TYPE (int|float|bool|str|array) } "assert" { return ASSERT; } +"<=" { return LE; } +">=" { return GE; } "<" { return LT; } ">" { return GT; } "," { return COMMA; } diff --git a/src/node.h b/src/node.h index 51bc777..9d0d8f5 100644 --- a/src/node.h +++ b/src/node.h @@ -10,7 +10,8 @@ G(NODE_ASSERT), \ G(NODE_UADD), G(NODE_USUB), G(NODE_ADD), G(NODE_SUB), \ G(NODE_MUL), G(NODE_DIV), G(NODE_MOD), G(NODE_POW), \ - G(NODE_ARRAY), G(NODE_INDEX) + G(NODE_ARRAY), G(NODE_INDEX), G(NODE_LT), G(NODE_LE), \ + G(NODE_GT), G(NODE_GE) #include "mutils.h" diff --git a/src/opcodes.h b/src/opcodes.h index c6c2aa1..10d2d20 100644 --- a/src/opcodes.h +++ b/src/opcodes.h @@ -33,7 +33,15 @@ G(OP_ACAT), \ G(OP_AMUL), \ G(OP_TMUL), \ - G(OP_TADD) + G(OP_TADD), \ + G(OP_ILT), \ + G(OP_ILE), \ + G(OP_IGT), \ + G(OP_IGE), \ + G(OP_FLT), \ + G(OP_FLE), \ + G(OP_FGT), \ + G(OP_FGE) \ enum Opcodes { OPCODES(GEN_ENUM) diff --git a/src/parser.y b/src/parser.y index d34a21d..e2187eb 100644 --- a/src/parser.y +++ b/src/parser.y @@ -22,15 +22,14 @@ }; %left ASSERT -%token LT GT %token TYPE BOOLEAN INTEGER FLOAT STRING %type expr exprs prog array builtins %type expr_list type type_list %left EQ NE +%left LT GT LE GE %left AND %left OR -%left ADD -%left SUB +%left ADD SUB %left MUL DIV MOD %left POW %left NOT @@ -118,9 +117,49 @@ expr: } - | expr_unop {} - | expr ADD expr{ + | expr LT expr { + node *n = malloc(sizeof(node)); + node_init(n, NODE_LT, "", line); + node* rhs = stack_pop(); + node* lhs = stack_pop(); + node_add_child(n, lhs); + node_add_child(n, rhs); + stack_push(n); + $$ = 1; + } + | expr LE expr { + node *n = malloc(sizeof(node)); + node_init(n, NODE_LE, "", line); + node* rhs = stack_pop(); + node* lhs = stack_pop(); + node_add_child(n, lhs); + node_add_child(n, rhs); + stack_push(n); + $$ = 1; + } + | expr GT expr { + node *n = malloc(sizeof(node)); + node_init(n, NODE_GT, "", line); + node* rhs = stack_pop(); + node* lhs = stack_pop(); + node_add_child(n, lhs); + node_add_child(n, rhs); + stack_push(n); + $$ = 1; + } + | expr GE expr { + node *n = malloc(sizeof(node)); + node_init(n, NODE_GE, "", line); + node* rhs = stack_pop(); + node* lhs = stack_pop(); + node_add_child(n, lhs); + node_add_child(n, rhs); + stack_push(n); + $$ = 1; + } + + | expr ADD expr { node *n = malloc(sizeof(node)); node_init(n, NODE_ADD, "", line); node* rhs = stack_pop(); @@ -243,6 +282,7 @@ expr: $$ = $2; } + | expr_unop {} ; @@ -265,8 +305,8 @@ expr_unop: ; type_list: - expr { $$ = $1; } - | type_list COMMA expr { $$ = $1 + $3; } + type { $$ = $1; } + | type_list COMMA type { $$ = $1 + $3; } ; @@ -299,6 +339,28 @@ type: stack_push(n); $$ = 1; } + + | type ADD type { + node *n = malloc(sizeof(node)); + node_init(n, NODE_ADD, "", line); + node* rhs = stack_pop(); + node* lhs = stack_pop(); + node_add_child(n, lhs); + node_add_child(n, rhs); + stack_push(n); + $$ = 1; + } + + | type MUL type { + node *n = malloc(sizeof(node)); + node_init(n, NODE_MUL, "", line); + node* rhs = stack_pop(); + node* lhs = stack_pop(); + node_add_child(n, lhs); + node_add_child(n, rhs); + stack_push(n); + $$ = 1; + } ; builtins: diff --git a/src/vm.c b/src/vm.c index 3a7b1bd..e8ee8e5 100644 --- a/src/vm.c +++ b/src/vm.c @@ -76,6 +76,16 @@ void vm_exec(vm* self, program* prog) case OP_TMUL: vm_tmul(self); break; case OP_TADD: vm_tadd(self); break; + case OP_ILT: vm_ilt(self); break; + case OP_ILE: vm_ile(self); break; + case OP_IGT: vm_igt(self); break; + case OP_IGE: vm_ige(self); break; + + case OP_FLT: vm_flt(self); break; + case OP_FLE: vm_fle(self); break; + case OP_FGT: vm_fgt(self); break; + case OP_FGE: vm_fge(self); break; + default: { fprintf(stderr, "unknown opcode %s\n", OpcodesStr[opcode]); @@ -740,3 +750,155 @@ void vm_tadd(vm* self) self->pc++; } + +void vm_flt(vm* self) +{ + assert(self); + + value* rhs = vm_pop_value(self); + value* lhs = vm_pop_value(self); + + value* val = malloc(sizeof(value)); + value_init_boolean(val, lhs->val.real_float < rhs->val.real_float, lhs->lineno); + vm_push_value(self, val); + + value_free(rhs); + free(rhs); + value_free(lhs); + free(lhs); + + self->pc++; +} + +void vm_fle(vm* self) +{ + assert(self); + + value* rhs = vm_pop_value(self); + value* lhs = vm_pop_value(self); + + value* val = malloc(sizeof(value)); + value_init_boolean(val, lhs->val.real_float <= rhs->val.real_float, lhs->lineno); + vm_push_value(self, val); + + value_free(rhs); + free(rhs); + value_free(lhs); + free(lhs); + + self->pc++; +} + +void vm_fgt(vm* self) +{ + assert(self); + + value* rhs = vm_pop_value(self); + value* lhs = vm_pop_value(self); + + value* val = malloc(sizeof(value)); + value_init_boolean(val, lhs->val.real_float > rhs->val.real_float, lhs->lineno); + vm_push_value(self, val); + + value_free(rhs); + free(rhs); + value_free(lhs); + free(lhs); + + self->pc++; +} + +void vm_fge(vm* self) +{ + assert(self); + + value* rhs = vm_pop_value(self); + value* lhs = vm_pop_value(self); + + value* val = malloc(sizeof(value)); + value_init_boolean(val, lhs->val.real_float >= rhs->val.real_float, lhs->lineno); + vm_push_value(self, val); + + value_free(rhs); + free(rhs); + value_free(lhs); + free(lhs); + + self->pc++; +} + +void vm_ilt(vm* self) +{ + assert(self); + + value* rhs = vm_pop_value(self); + value* lhs = vm_pop_value(self); + + value* val = malloc(sizeof(value)); + value_init_boolean(val, lhs->val.integer < rhs->val.integer, lhs->lineno); + vm_push_value(self, val); + + value_free(rhs); + free(rhs); + value_free(lhs); + free(lhs); + + self->pc++; +} + +void vm_ile(vm* self) +{ + assert(self); + + value* rhs = vm_pop_value(self); + value* lhs = vm_pop_value(self); + + value* val = malloc(sizeof(value)); + value_init_boolean(val, lhs->val.integer <= rhs->val.integer, lhs->lineno); + vm_push_value(self, val); + + value_free(rhs); + free(rhs); + value_free(lhs); + free(lhs); + + self->pc++; +} + +void vm_igt(vm* self) +{ + assert(self); + + value* rhs = vm_pop_value(self); + value* lhs = vm_pop_value(self); + + value* val = malloc(sizeof(value)); + value_init_boolean(val, lhs->val.integer > rhs->val.integer, lhs->lineno); + vm_push_value(self, val); + + value_free(rhs); + free(rhs); + value_free(lhs); + free(lhs); + + self->pc++; +} + +void vm_ige(vm* self) +{ + assert(self); + + value* rhs = vm_pop_value(self); + value* lhs = vm_pop_value(self); + + value* val = malloc(sizeof(value)); + value_init_boolean(val, lhs->val.integer >= rhs->val.integer, lhs->lineno); + vm_push_value(self, val); + + value_free(rhs); + free(rhs); + value_free(lhs); + free(lhs); + + self->pc++; +} diff --git a/src/vm.h b/src/vm.h index 7f460ca..9e188bc 100644 --- a/src/vm.h +++ b/src/vm.h @@ -60,4 +60,14 @@ void vm_amul(vm* self); void vm_tmul(vm* self); void vm_tadd(vm* self); +void vm_ilt(vm* self); +void vm_ile(vm* self); +void vm_igt(vm* self); +void vm_ige(vm* self); + +void vm_flt(vm* self); +void vm_fle(vm* self); +void vm_fgt(vm* self); +void vm_fge(vm* self); + #endif diff --git a/tests/err_cmp.wuz b/tests/err_cmp.wuz new file mode 100644 index 0000000..afc3bbd --- /dev/null +++ b/tests/err_cmp.wuz @@ -0,0 +1,24 @@ +5 < 5.2 +5 > 5.2 +5 <= 5.2 +5 >= 5.2 + +52.3 < 5 +5.7 > 5 +5.28 <= 2 +5.34 >= 2 + +52.3 < bool +5.7 > bool +5.28 <= bool +5.34 >= bool + +bool < bool +bool > bool +bool <= bool +bool >= bool + +str < str +str > str +str <= str +str >= str diff --git a/tests/test_cmp.wuz b/tests/test_cmp.wuz new file mode 100644 index 0000000..da511c5 --- /dev/null +++ b/tests/test_cmp.wuz @@ -0,0 +1,33 @@ +assert 4 < 10 +assert !(16 < 15) +assert !(36 < 36) + +assert 9 <= 15 +assert !(19 <= 3) +assert 37 <= 37 + +assert 100 > 10 +assert !(99 > 215) +assert !(33 > 33) + +assert 29 >= 2 +assert !(296 >= 720) +assert 348 >= 348 + +assert 4.0 < 10.0 +assert !(16.0 < 15.0) +assert !(36.0 < 36.0) + +assert 9.0 <= 15.0 +assert !(19.0 <= 3.0) +assert 37.0 <= 37.0 + +assert 100.0 > 10.0 +assert !(99.0 > 215.0) +assert !(33.0 > 33.0) + +assert 29.0 >= 2.0 +assert !(296.0 >= 720.0) +assert 348.0 >= 348.0 + +assert 5 > 3 == true