diff --git a/src/commons.h b/src/commons.h index 887001c..7958e5c 100644 --- a/src/commons.h +++ b/src/commons.h @@ -1,6 +1,7 @@ #ifndef COMMONS_H #define COMMON_H +#include #include #include #include diff --git a/src/compiler.c b/src/compiler.c index 80b70d4..ea67d17 100644 --- a/src/compiler.c +++ b/src/compiler.c @@ -1,4 +1,5 @@ #include "compiler.h" +#include "cstatic.h" void compiler_init(compiler* self) { @@ -15,7 +16,7 @@ void compile_node(compiler* self, node* root, program* prog) assert(self); assert(root); assert(prog); - + if (root->type == NODE_BOOLEAN) { value val; @@ -26,6 +27,16 @@ void compile_node(compiler* self, node* root, program* prog) program_add_instr(prog, OP_PUSH, idx); value_free(&val); } + else if (root->type == NODE_FLOAT) + { + value val; + value_init_float(&val, + atof(root->value), + root->lineno); + size_t idx = program_add_pool(prog, &val); + program_add_instr(prog, OP_PUSH, idx); + value_free(&val); + } else if (root->type == NODE_INTEGER) { value val; @@ -43,43 +54,35 @@ void compile_node(compiler* self, node* root, program* prog) } else if (root->type == NODE_UADD) { - compile_children(self, root, prog); - program_add_instr(prog, OP_IUADD, NO_PARAM); + compile_number(self, root, prog, OP_IUADD, OP_FUADD); } else if (root->type == NODE_USUB) { - compile_children(self, root, prog); - program_add_instr(prog, OP_IUSUB, NO_PARAM); + compile_number(self, root, prog, OP_IUSUB, OP_FUSUB); } else if (root->type == NODE_ADD) { - compile_children(self, root, prog); - program_add_instr(prog, OP_IADD, NO_PARAM); + compile_number(self, root, prog, OP_IADD, OP_FADD); } else if (root->type == NODE_SUB) { - compile_children(self, root, prog); - program_add_instr(prog, OP_ISUB, NO_PARAM); + compile_number(self, root, prog, OP_ISUB, OP_FSUB); } else if (root->type == NODE_MUL) { - compile_children(self, root, prog); - program_add_instr(prog, OP_IMUL, NO_PARAM); + compile_number(self, root, prog, OP_IMUL, OP_FMUL); } else if (root->type == NODE_DIV) { - compile_children(self, root, prog); - program_add_instr(prog, OP_IDIV, NO_PARAM); + compile_number(self, root, prog, OP_IDIV, OP_FDIV); } else if (root->type == NODE_MOD) { - compile_children(self, root, prog); - program_add_instr(prog, OP_IMOD, NO_PARAM); + compile_number(self, root, prog, OP_IMOD, OP_FMOD); } else if (root->type == NODE_POW) { - compile_children(self, root, prog); - program_add_instr(prog, OP_IPOW, NO_PARAM); + compile_number(self, root, prog, OP_IPOW, OP_FPOW); } else if (root->type == NODE_EQ) { @@ -124,3 +127,35 @@ void compile_children(compiler* self, node* root, program* prog) compile_node(self, root->children.data[i], prog); } } + +void compile_number(compiler* self, node* root, program* prog, + int integer_op, + int float_op) +{ + compile_children(self, root, prog); + + cstatic cs; + cstatic_init(&cs); + + int ty = cstatic_resolve(&cs, root); + + switch (ty) + { + case TY_INTEGER: + program_add_instr(prog, integer_op, NO_PARAM); + break; + + case TY_FLOAT: + program_add_instr(prog, float_op, NO_PARAM); + break; + + default: + fprintf(stderr, "E(%d): cannot add type '%s'.", + root->lineno, + TypesStr[ty]); + exit(-1); + break; + } + + cstatic_free(&cs); +} diff --git a/src/compiler.h b/src/compiler.h index ab92535..835fcfd 100644 --- a/src/compiler.h +++ b/src/compiler.h @@ -15,4 +15,7 @@ void compiler_free(compiler* self); void compile_node(compiler* self, node* root, program* prog); void compile_children(compiler* self, node* root, program* prog); +void compile_number(compiler* self, node* root, program* prog, + int integer_op, + int float_op); #endif diff --git a/src/cstatic.c b/src/cstatic.c index 6627c4e..cb71407 100644 --- a/src/cstatic.c +++ b/src/cstatic.c @@ -20,6 +20,10 @@ int cstatic_resolve(cstatic* self, node* ast) { return TY_INTEGER; } + else if (ast->type == NODE_FLOAT) + { + return TY_FLOAT; + } else if (ast->type == NODE_BOOLEAN || ast->type == NODE_EQ || ast->type == NODE_NE) @@ -82,9 +86,10 @@ int cstatic_check(cstatic* self, node* ast, char* msg, size_t size) { int status = cstatic_check_type(self, ast->children.data[0], - TY_BOOLEAN, msg, - size); + size, + TY_BOOLEAN, + TYPE_END); if (!status) { @@ -109,9 +114,10 @@ int cstatic_check(cstatic* self, node* ast, char* msg, size_t size) status = cstatic_check_type(self, ast->children.data[0], - TY_BOOLEAN, msg, - size); + size, + TY_BOOLEAN, + TYPE_END); if (!status) { return status; @@ -124,9 +130,11 @@ int cstatic_check(cstatic* self, node* ast, char* msg, size_t size) { int status = cstatic_check_type(self, ast->children.data[0], - TY_INTEGER, msg, - size); + size, + TY_INTEGER, + TY_FLOAT, + TYPE_END); if (!status) { return status; @@ -155,9 +163,11 @@ int cstatic_check(cstatic* self, node* ast, char* msg, size_t size) status = cstatic_check_type(self, ast->children.data[0], - TY_INTEGER, msg, - size); + size, + TY_INTEGER, + TY_FLOAT, + TYPE_END); if (!status) { return status; @@ -167,24 +177,56 @@ int cstatic_check(cstatic* self, node* ast, char* msg, size_t size) return 1; } -int cstatic_check_type(cstatic* self, node* lhs, int rhs, - char* msg, size_t size) +int cstatic_check_type(cstatic* self, node* lhs, + char* msg, size_t size, int types, ...) { assert(self); assert(lhs); - - int left = cstatic_resolve(self, lhs); + char aze[512]; + node_str(lhs, aze, 512); - if (left != rhs) + va_list args; + va_start(args, types); + int rhs = types; + + int left = cstatic_resolve(self, lhs); + + int all_types[TY_TYPE_COUNT]; + memset(all_types, TYPE_END, TY_TYPE_COUNT * sizeof(int)); + size_t i = 0; + + while (rhs != TYPE_END) { - snprintf(msg, size, "E(%d): expected '%s', got '%s'.", + all_types[i] = rhs; + + if (left == rhs) + { + va_end(args); + return 1; + } + + rhs = va_arg(args, int); + i++; + } + + va_end(args); + + size_t sz = snprintf(msg, size, "E(%d): type mismatch, got '%s', ", lhs->lineno, - TypesStr[left], - TypesStr[rhs]); - return 0; + TypesStr[left]); + + sz += snprintf(msg + sz, size - sz, "expected: \n"); + + size_t j = 0; + + while (all_types[j] != TYPE_END) + { + sz += snprintf(msg + sz, size - sz, "\t '%s'\n", + TypesStr[all_types[j]]); + j++; } - return 1; + return 0; } int cstatic_check_same_type(cstatic* self, node* lhs, node* rhs, diff --git a/src/cstatic.h b/src/cstatic.h index f0974af..1b00c1e 100644 --- a/src/cstatic.h +++ b/src/cstatic.h @@ -4,6 +4,8 @@ #include "commons.h" #include "node.h" +#define TYPE_END (-1) + typedef struct { int _unused; } cstatic; @@ -14,8 +16,8 @@ void cstatic_free(cstatic* self); int cstatic_resolve(cstatic* self, node* ast); int cstatic_check(cstatic* self, node* ast, char* msg, size_t size); -int cstatic_check_type(cstatic* self, node* lhs, int rhs, - char* msg, size_t size); +int cstatic_check_type(cstatic* self, node* lhs, + char* msg, size_t size, int types, ...); int cstatic_check_same_type(cstatic* self, node* lhs, node* rhs, char* msg, size_t size); diff --git a/src/lex.l b/src/lex.l index ee8f3e6..1b30856 100644 --- a/src/lex.l +++ b/src/lex.l @@ -11,6 +11,7 @@ COMMENT ::[^\n]* WHITESPACES [ \t]+ BOOLEAN true|false INTEGER -?[0-9]+ +FLOAT -?[0-9]+\.[0-9]+ %% "\n" { line++; } @@ -38,6 +39,11 @@ INTEGER -?[0-9]+ return BOOLEAN; } +{FLOAT} { + yylval.str = yytext; + return FLOAT; +} + {INTEGER} { yylval.str = yytext; return INTEGER; diff --git a/src/node.h b/src/node.h index aa21b4f..95da6cb 100644 --- a/src/node.h +++ b/src/node.h @@ -3,7 +3,7 @@ #define NODE_TYPE(G) \ G(NODE_PROG), \ - G(NODE_BOOLEAN), G(NODE_INTEGER), \ + G(NODE_BOOLEAN), G(NODE_INTEGER), G(NODE_FLOAT), \ G(NODE_AND), G(NODE_OR), G(NODE_NOT), \ G(NODE_EQ), G(NODE_NE), \ G(NODE_ASSERT), \ diff --git a/src/opcodes.h b/src/opcodes.h index 1f7aac1..cc24be0 100644 --- a/src/opcodes.h +++ b/src/opcodes.h @@ -17,7 +17,15 @@ G(OP_IMOD), \ G(OP_IPOW), \ G(OP_IUADD), \ - G(OP_IUSUB), + G(OP_IUSUB), \ + G(OP_FADD), \ + G(OP_FSUB), \ + G(OP_FMUL), \ + G(OP_FDIV), \ + G(OP_FMOD), \ + G(OP_FPOW), \ + G(OP_FUADD), \ + G(OP_FUSUB), enum Opcodes { OPCODES(GEN_ENUM) diff --git a/src/parser.y b/src/parser.y index 8d924dd..fe76565 100644 --- a/src/parser.y +++ b/src/parser.y @@ -22,8 +22,7 @@ }; %left ASSERT -%token BOOLEAN -%token INTEGER +%token BOOLEAN INTEGER FLOAT %left EQ NE %left AND %left OR @@ -179,6 +178,12 @@ expr: node_init(n, NODE_INTEGER, $1, line); $$ = n; } + + | FLOAT { + node* n = malloc(sizeof(node)); + node_init(n, NODE_FLOAT, $1, line); + $$ = n; + } ; %% diff --git a/src/type.h b/src/type.h index 8bb66da..ea0d9e4 100644 --- a/src/type.h +++ b/src/type.h @@ -6,7 +6,9 @@ #define TYPES(G) \ G(TY_NIL), \ G(TY_BOOLEAN), \ - G(TY_INTEGER), + G(TY_INTEGER), \ + G(TY_FLOAT), \ + G(TY_TYPE_COUNT) enum Types { TYPES(GEN_ENUM) diff --git a/src/value.c b/src/value.c index efe2020..b84c689 100644 --- a/src/value.c +++ b/src/value.c @@ -20,6 +20,16 @@ void value_init_integer(value* self, int integer, int lineno) type_init(self->type, TY_INTEGER); } +void value_init_float(value* self, float real_float, int lineno) +{ + assert(self); + self->val.real_float = real_float; + self->lineno = lineno; + + self->type = malloc(sizeof(type)); + type_init(self->type, TY_FLOAT); +} + void value_free(value* self) { assert(self); @@ -60,6 +70,11 @@ int value_equals(value* self, value* rhs) return self->val.integer == rhs->val.integer; } + if (self->type->base_type == TY_FLOAT) + { + return self->val.real_float == rhs->val.real_float; + } + size_t const SZ = 512; char ty_str[SZ]; diff --git a/src/value.h b/src/value.h index bc6245a..6cb51d6 100644 --- a/src/value.h +++ b/src/value.h @@ -10,11 +10,13 @@ typedef struct { union { int boolean; int integer; + float real_float; } val; } value; void value_init_boolean(value* self, int boolean, int lineno); void value_init_integer(value* self, int integer, int lineno); +void value_init_float(value* self, float real_float, int lineno); void value_free(value* self); value* value_new_clone(value* self); diff --git a/src/vm.c b/src/vm.c index 08e29bc..fe08c48 100644 --- a/src/vm.c +++ b/src/vm.c @@ -54,6 +54,16 @@ void vm_exec(vm* self, program* prog) case OP_IDIV: vm_idiv(self); break; case OP_IMOD: vm_imod(self); break; case OP_IPOW: vm_ipow(self); break; + + case OP_FADD: vm_fadd(self); break; + case OP_FUADD: vm_fuadd(self); break; + case OP_FSUB: vm_fsub(self); break; + case OP_FUSUB: vm_fusub(self); break; + case OP_FMUL: vm_fmul(self); break; + case OP_FDIV: vm_fdiv(self); break; + case OP_FMOD: vm_fmod(self); break; + case OP_FPOW: vm_fpow(self); break; + case OP_ASSERT: vm_assert(self); break; default: { fprintf(stderr, "unknown opcode %s\n", @@ -303,6 +313,142 @@ void vm_ipow(vm* self) self->pc++; } +void vm_fadd(vm* self) +{ + value* rhs = vm_pop_value(self); + value* lhs = vm_pop_value(self); + + value* val = malloc(sizeof(value)); + value_init_float(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_fuadd(vm* self) +{ + value* lhs = vm_pop_value(self); + + value* val = malloc(sizeof(value)); + value_init_float(val, lhs->val.real_float, lhs->lineno); + vm_push_value(self, val); + + value_free(lhs); + free(lhs); + + self->pc++; +} + +void vm_fsub(vm* self) +{ + value* rhs = vm_pop_value(self); + value* lhs = vm_pop_value(self); + + value* val = malloc(sizeof(value)); + value_init_float(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_fusub(vm* self) +{ + value* lhs = vm_pop_value(self); + + value* val = malloc(sizeof(value)); + value_init_float(val, -lhs->val.real_float, lhs->lineno); + vm_push_value(self, val); + + value_free(lhs); + free(lhs); + + self->pc++; +} + +void vm_fmul(vm* self) +{ + value* rhs = vm_pop_value(self); + value* lhs = vm_pop_value(self); + + value* val = malloc(sizeof(value)); + value_init_float(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_fdiv(vm* self) +{ + value* rhs = vm_pop_value(self); + value* lhs = vm_pop_value(self); + + value* val = malloc(sizeof(value)); + value_init_float(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_fmod(vm* self) +{ + value* rhs = vm_pop_value(self); + value* lhs = vm_pop_value(self); + + value* val = malloc(sizeof(value)); + value_init_float(val, fmod(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_fpow(vm* self) +{ + value* rhs = vm_pop_value(self); + value* lhs = vm_pop_value(self); + + value* val = malloc(sizeof(value)); + value_init_float(val, pow(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_eq(vm* self) { assert(self); diff --git a/src/vm.h b/src/vm.h index c9f4932..c84055e 100644 --- a/src/vm.h +++ b/src/vm.h @@ -38,6 +38,14 @@ void vm_idiv(vm* self); void vm_imod(vm* self); void vm_ipow(vm* self); +void vm_fadd(vm* self); +void vm_fuadd(vm* self); +void vm_fsub(vm* self); +void vm_fusub(vm* self); +void vm_fmul(vm* self); +void vm_fdiv(vm* self); +void vm_fmod(vm* self); +void vm_fpow(vm* self); void vm_eq(vm* self); void vm_assert(vm* self); diff --git a/tests/err_ty_float.wuz b/tests/err_ty_float.wuz new file mode 100644 index 0000000..0c1253f --- /dev/null +++ b/tests/err_ty_float.wuz @@ -0,0 +1,27 @@ +5 + 2.0 +3.0 + 9 +5 - 2.0 +3.0 - 9 +5 * 2.0 +3.0 * 9 +5 / 2.0 +3.0 / 9 +5 % 2.0 +3.0 % 9 +1.2 ^ 3 + +true + 2.0 +3.0 + false +false - 2.0 +3.0 - true +false * 2.0 +false * 9 +5 / true +true / 9 +5 % false +true % 9 +(false && false) ^ 3 + +1.2 && 2.3 +1.2 || 2.3 +!12.0 diff --git a/tests/test_float.wuz b/tests/test_float.wuz new file mode 100644 index 0000000..53cfc6f --- /dev/null +++ b/tests/test_float.wuz @@ -0,0 +1,13 @@ +assert 5.2 == 5.2 +assert 5.2 != 5.3 + +:: Arithmetic +assert 7.2 == 5.1 + 2.1 +assert 2.0 == + 2.0 +assert 3.0 == 5.0 - 2.0 +assert -5.0 == - 5.0 +assert 10.0 == 5.0 * 2.0 +assert 2.5 == 5.0 / 2.0 +assert 1.0 == 5.0 % 2.0 +assert 0.5 == 5.0 % 1.5 +assert 25.0 == 5.0 ^ 2.0