From b9eb183319263e62b6b3814be69b54ef12515c0a Mon Sep 17 00:00:00 2001 From: bog Date: Sat, 26 Aug 2023 22:45:36 +0200 Subject: [PATCH] ADD: while loop and break keyword. --- meson.build | 1 + src/block_info.c | 42 ++++++++++++++ src/block_info.h | 32 +++++++++++ src/compiler.c | 127 ++++++++++++++++++++++++++++++++++++++++++- src/compiler.h | 14 +++++ src/lex.l | 4 ++ src/node.h | 3 +- src/parser.y | 28 +++++++++- src/program.c | 13 ++--- src/program.h | 3 +- tests/test_while.wuz | 36 ++++++++++++ 11 files changed, 288 insertions(+), 15 deletions(-) create mode 100644 src/block_info.c create mode 100644 src/block_info.h create mode 100644 tests/test_while.wuz diff --git a/meson.build b/meson.build index 589b88c..9d0f71a 100644 --- a/meson.build +++ b/meson.build @@ -40,6 +40,7 @@ executable( 'src/utils.c', 'src/opcodes.c', 'src/program.c', + 'src/block_info.c', 'src/value.c', 'src/array.c', diff --git a/src/block_info.c b/src/block_info.c new file mode 100644 index 0000000..f36e8ad --- /dev/null +++ b/src/block_info.c @@ -0,0 +1,42 @@ +#include "block_info.h" + +void block_info_init(block_info* self, int kind) +{ + assert(self); + self->size = 0; + self->capacity = 1; + self->data = malloc(sizeof(info*) * self->capacity); + self->kind = kind; +} + +void block_info_free(block_info* self) +{ + for (size_t i=0; isize; i++) + { + free(self->data[i]); + } + + free(self->data); + + self->size = 0; + self->capacity = 0; + self->data = NULL; +} + +void block_info_push(block_info* self, size_t addr, int hint) +{ + assert(self); + + if (self->size >= self->capacity) + { + self->capacity *= 2; + self->data = realloc(self->data, sizeof(info*) * self->capacity); + } + + self->data[self->size] = malloc(sizeof(info)); + + self->data[self->size]->addr = addr; + self->data[self->size]->hint = hint; + + self->size++; +} diff --git a/src/block_info.h b/src/block_info.h new file mode 100644 index 0000000..2b70000 --- /dev/null +++ b/src/block_info.h @@ -0,0 +1,32 @@ +#ifndef BLOCK_INFO_H +#define BLOCK_INFO_H + +#include "commons.h" + +enum BlockInfoHints { + HINT_END, +}; + +enum BlockInfoKind { + INFO_KIND_LOOP, + INFO_KIND_IF +}; + +typedef struct { + size_t addr; + int hint; +} info; + +typedef struct { + size_t size; + size_t capacity; + info** data; + int kind; +} block_info; + +void block_info_init(block_info* self, int kind); +void block_info_free(block_info* self); + +void block_info_push(block_info* self, size_t addr, int hint); + +#endif diff --git a/src/compiler.c b/src/compiler.c index 39348e1..a0d4856 100644 --- a/src/compiler.c +++ b/src/compiler.c @@ -7,6 +7,10 @@ void compiler_init(compiler* self) self->sym = malloc(sizeof(symtable)); symtable_init(self->sym); + self->binfo.size = 0; + self->binfo.capacity = 1; + self->binfo.data = malloc(sizeof(block_info*) * self->binfo.capacity); + } void compiler_free(compiler* self) @@ -16,6 +20,74 @@ void compiler_free(compiler* self) symtable_free(self->sym); free(self->sym); self->sym = NULL; + + for (size_t i=0; ibinfo.size; i++) + { + block_info_free(self->binfo.data[i]); + free(self->binfo.data[i]); + } + + free(self->binfo.data); + + self->binfo.size = 0; + self->binfo.capacity = 0; + self->binfo.data = NULL; +} + +block_info* compiler_current_info(compiler* self) +{ + assert(self); + assert(self->binfo.size > 0); + + return self->binfo.data[self->binfo.size - 1]; +} + +block_info* compiler_find_info(compiler* self, int kind) +{ + assert(self); + + for (size_t i=0; ibinfo.size; i++) + { + size_t j = self->binfo.size - 1 - i; + + if (self->binfo.data[j]->kind == kind) + { + return self->binfo.data[j]; + } + } + + return NULL; +} + +block_info* compiler_push_info(compiler* self, int kind) +{ + assert(self); + + if (self->binfo.size >= self->binfo.capacity) + { + self->binfo.capacity *= 2; + self->binfo.data = realloc( + self->binfo.data, + sizeof(block_info*) * self->binfo.capacity + ); + } + + self->binfo.data[self->binfo.size] = malloc(sizeof(block_info)); + block_info_init(self->binfo.data[self->binfo.size], kind); + + self->binfo.size++; + + return self->binfo.data[self->binfo.size - 1]; +} + +void compiler_pop_info(compiler* self) +{ + assert(self); + assert(self->binfo.size > 0); + + block_info_free(self->binfo.data[self->binfo.size - 1]); + free(self->binfo.data[self->binfo.size - 1]); + self->binfo.size--; } void compile_node(compiler* self, node* root, program* prog) @@ -32,8 +104,52 @@ void compile_node(compiler* self, node* root, program* prog) } else if (root->type == NODE_IF) { + block_info* info = compiler_push_info(self, INFO_KIND_IF); + compile_if(self, root, prog); - program_set_mark_params(prog, prog->instrs.size); + + for (size_t i=0; isize; i++) + { + size_t addr = info->data[i]->addr; + int hint = info->data[i]->hint; + program_set_param(prog, addr, prog->instrs.size); + } + + compiler_pop_info(self); + } + else if (root->type == NODE_WHILE) + { + block_info* bi = compiler_push_info(self, INFO_KIND_LOOP); + + node* cond = root->children.data[0]; + node* block = root->children.data[1]; + + size_t start_addr = prog->instrs.size; + compile_node(self, cond, prog); + + block_info_push(bi, prog->instrs.size, HINT_END); + program_add_instr(prog, OP_BRF, 0); + + compile_node(self, block, prog); + + program_add_instr(prog, OP_BR, start_addr); + + for (size_t i=0; isize; i++) + { + if (bi->data[i]->hint == HINT_END) + { + program_set_param(prog, bi->data[i]->addr, + prog->instrs.size); + } + } + + compiler_pop_info(self); + } + else if (root->type == NODE_BREAK) + { + block_info* bi = compiler_find_info(self, INFO_KIND_LOOP); + block_info_push(bi, prog->instrs.size, HINT_END); + program_add_instr(prog, OP_BR, NO_PARAM); } else if (root->type == NODE_INDEX) { @@ -528,7 +644,12 @@ void compile_if(compiler* self, node* root, program* prog) // then block node* then_block = root->children.data[1]; compile_node(self, then_block, prog); - program_add_instr(prog, OP_BR, MARK_PARAM); + + size_t to_end_addr = prog->instrs.size; + block_info* info = compiler_current_info(self); + block_info_push(info, to_end_addr, HINT_END); + + program_add_instr(prog, OP_BR, NO_PARAM); // next program_set_instr(prog, cond_addr, OP_BRF, prog->instrs.size); @@ -536,7 +657,6 @@ void compile_if(compiler* self, node* root, program* prog) if (root->children.size >= 3) { node* next_node = root->children.data[2]; - //char c [512]; node_str(next_node, c, 512); printf("=> %s\n", c); compile_if(self, next_node, prog); } } @@ -572,3 +692,4 @@ void compile_number(compiler* self, node* root, program* prog, cstatic_free(&cs); } + diff --git a/src/compiler.h b/src/compiler.h index 2c3f322..b6d6227 100644 --- a/src/compiler.h +++ b/src/compiler.h @@ -5,15 +5,28 @@ #include "program.h" #include "node.h" #include "symtable.h" +#include "block_info.h" typedef struct { symtable* sym; + + struct { + size_t size; + size_t capacity; + block_info** data; + } binfo; } compiler; void compiler_init(compiler* self); void compiler_free(compiler* self); + +block_info* compiler_current_info(compiler* self); +block_info* compiler_find_info(compiler* self, int kind); +block_info* compiler_push_info(compiler* self, int kind); +void compiler_pop_info(compiler* self); + void compile_node(compiler* self, node* root, program* prog); void compile_children(compiler* self, node* root, program* prog); @@ -25,4 +38,5 @@ void compile_number(compiler* self, node* root, program* prog, void compile_if(compiler* self, node* root, program* prog); + #endif diff --git a/src/lex.l b/src/lex.l index 76c3c70..4e1e2fa 100644 --- a/src/lex.l +++ b/src/lex.l @@ -25,6 +25,10 @@ IDENT [_A-Za-z][_A-Za-z0-9]* yylval.str = str_new(yytext); return TYPE; } + +"while" { return WHILE; } +"break" { return BREAK; } +"continue" { return CONTINUE; } "if" { return IF_COND; } "else" { return ELSE_COND; } "is" { return IS; } diff --git a/src/node.h b/src/node.h index 85b8d42..9ebf9de 100644 --- a/src/node.h +++ b/src/node.h @@ -13,7 +13,8 @@ G(NODE_ARRAY), G(NODE_INDEX), G(NODE_LT), G(NODE_LE), \ G(NODE_GT), G(NODE_GE), G(NODE_VARDECL), G(NODE_IDENT), \ G(NODE_CONSTDECL), G(NODE_ASSIGN), G(NODE_DO), G(NODE_IS), \ - G(NODE_IF), G(NODE_ELSE), G(NODE_BLOCK) + G(NODE_IF), G(NODE_ELSE), G(NODE_BLOCK), \ + G(NODE_WHILE), G(NODE_CONTINUE), G(NODE_BREAK) #include "mutils.h" diff --git a/src/parser.y b/src/parser.y index 5a0d2a1..416a217 100644 --- a/src/parser.y +++ b/src/parser.y @@ -23,6 +23,9 @@ %token IF_COND %token ELSE_COND +%token WHILE +%left CONTINUE +%token BREAK %left ASSERT %token TYPE BOOLEAN INTEGER FLOAT STRING IDENT %type expr exprs prog array builtins @@ -82,8 +85,31 @@ exprs: expr: + BREAK { + node* n = malloc(sizeof(node)); + node_init(n, NODE_BREAK, "", line); + stack_push(n); + $$ = 1; + } + + | WHILE expr block END { + node* n = malloc(sizeof(node)); + node_init(n, NODE_WHILE, "", line); + + + node* body = stack_pop(); + node* condition = stack_pop(); + + node_add_child(n, condition); + node_add_child(n, body); + + stack_push(n); + + $$ = 1; + } + // TYPE OPERATORS - expr IS type { + | expr IS type { node* n = malloc(sizeof(node)); node_init(n, NODE_IS, "", line); diff --git a/src/program.c b/src/program.c index eea07e1..9c9f3a5 100644 --- a/src/program.c +++ b/src/program.c @@ -46,15 +46,12 @@ void program_set_instr(program* self, size_t index, int opcode, int param) self->instrs.data[index]->param = param; } -void program_set_mark_params(program* self, int param) +void program_set_param(program* self, size_t index, int param) { - for (size_t i=0; iinstrs.size; i++) - { - if (self->instrs.data[i]->param == MARK_PARAM) - { - self->instrs.data[i]->param = param; - } - } + assert(self); + assert(index < self->instrs.size); + + self->instrs.data[index]->param = param; } size_t program_add_instr(program* self, int opcode, int param) diff --git a/src/program.h b/src/program.h index 14e678d..c0bdd72 100644 --- a/src/program.h +++ b/src/program.h @@ -6,7 +6,6 @@ #include "value.h" #define NO_PARAM (-1) -#define MARK_PARAM (-2) typedef struct { int opcode; @@ -32,7 +31,7 @@ void program_free(program* self); size_t program_add_instr(program* self, int opcode, int param); void program_set_instr(program* self, size_t index, int opcode, int param); -void program_set_mark_params(program* self, int param); +void program_set_param(program* self, size_t index, int param); size_t program_add_pool(program* self, value* val); diff --git a/tests/test_while.wuz b/tests/test_while.wuz new file mode 100644 index 0000000..fe12c29 --- /dev/null +++ b/tests/test_while.wuz @@ -0,0 +1,36 @@ +let! a = 7 + +while a < 100 + a = a + 1 +end + +assert 100 == a + +let! b = 0 +let! c = 0 +let! d = 0 + +while b < 16 + c = 0 + + while c < 16 + c = c + 1 + d = d + 1 + end + + b = b + 1 +end + +assert d == 256 + +let! e = 0 + +while true + e = e + 1 + if e >= 17 + break + end +end + +assert 17 == e +