From 40b8b7f68e16eaa107e328dbbed0e2b6600673cc Mon Sep 17 00:00:00 2001 From: bog Date: Fri, 22 Mar 2024 23:01:20 +0100 Subject: [PATCH] :sparkles: while expression. --- doc/grammar.bnf | 4 +++ lib/ccm.c | 5 ++++ lib/compiler.c | 80 ++++++++++++++++++++++++++++++++++++++++++++----- lib/compiler.h | 6 ++++ lib/lexer.c | 4 +++ lib/module.c | 4 +-- lib/node.h | 3 +- lib/parser.c | 39 ++++++++++++++++++++++++ lib/parser.h | 1 + lib/sym.c | 3 ++ lib/sym.h | 2 ++ tests/loop.ccm | 65 ++++++++++++++++++++++++++++++++++++++++ 12 files changed, 205 insertions(+), 11 deletions(-) create mode 100644 tests/loop.ccm diff --git a/doc/grammar.bnf b/doc/grammar.bnf index 0ef9097..485fc5f 100644 --- a/doc/grammar.bnf +++ b/doc/grammar.bnf @@ -6,6 +6,10 @@ EXPR ::= | ASSIGN | BEGIN | IF end +| WHILE +| continue +| break +WHILE ::= while EXPR BLOCK end IF ::= | if EXPR BLOCK (else (IF | BLOCK))? BEGIN ::= begin BLOCK end diff --git a/lib/ccm.c b/lib/ccm.c index bf31fbe..38dfbc3 100644 --- a/lib/ccm.c +++ b/lib/ccm.c @@ -40,6 +40,11 @@ size_t ccm_str(ccm_t* self, char* buffer, size_t size) for (size_t i=0; istack.size; i++) { + if (sz >= size) + { + break; + } + value_t* val = ccm_to_value(self, (CCM) self->stack.data[i]); sz += value_str(val, buffer + sz, size - sz); sz += snprintf(buffer + sz, size - sz, "\n"); diff --git a/lib/compiler.c b/lib/compiler.c index ea5d846..ddb734e 100644 --- a/lib/compiler.c +++ b/lib/compiler.c @@ -6,12 +6,15 @@ void compiler_init(compiler_t* self, module_t* module) err_init(&self->err); self->module = module; self->loc_counter = 0; + vec_init(&self->loop_infos); } void compiler_free(compiler_t* self) { assert(self); err_free(&self->err); + vec_free_elements(&self->loop_infos, NULL); + vec_free(&self->loop_infos); } void compiler_compile(compiler_t* self, @@ -32,6 +35,63 @@ void compiler_compile(compiler_t* self, switch (node->kind) { + case NODE_CONTINUE: { + assert(self->loop_infos.size > 0); + + loop_info_t const* info + = self->loop_infos.data[ + self->loop_infos.size - 1 + ]; + + prog_add_instr(prog, OP_BR, info->start_point); + + } break; + + case NODE_BREAK: { + assert(self->loop_infos.size > 0); + + loop_info_t* info + = self->loop_infos.data[ + self->loop_infos.size - 1 + ]; + + size_t point = prog_add_instr(prog, OP_BR, 0); + vec_push(&info->to_end, (void*) point); + + } break; + case NODE_WHILE: { + node_t* expr = node->children.data[0]; + node_t* block = node->children.data[1]; + + int start = prog->instrs.size; + loop_info_t* info = malloc(sizeof(loop_info_t)); + info->start_point = start; + vec_init(&info->to_end); + + vec_push(&self->loop_infos, info); + + compiler_compile(self, expr, prog); + int cond_point = prog_add_instr(prog, OP_BRF, 0); + + compiler_compile(self, block, prog); + prog_add_instr(prog, OP_BR, start); + + int end_point = prog->instrs.size; + ((instr_t*)prog->instrs.data[cond_point])->param + = end_point; + + for (size_t i=0; ito_end.size; i++) + { + int addr = (size_t)info->to_end.data[i]; + instr_t* instr = prog->instrs.data[addr]; + instr->param = end_point; + } + + info = vec_pop(&self->loop_infos); + vec_free(&info->to_end); + free(info); + } break; + case NODE_IF: { vec_t to_end; vec_init(&to_end); @@ -51,7 +111,6 @@ void compiler_compile(compiler_t* self, } break; case NODE_BLOCK: { - sym_open_scope(sym); for (size_t i=0; ichildren.size; i++) { @@ -108,17 +167,18 @@ void compiler_compile(compiler_t* self, prog_add_instr(prog, OP_ASTORE, indexes_count); } else { compiler_compile(self, expr, prog); - int status = - sym_try_assign( - sym, - target->value, self->loc_counter - ); sym_entry_t* entry = sym_try_get_value( sym, target->value ); + int status = + sym_try_assign( + sym, + target->value, self->loc_counter + ); + assert(entry); if (entry->is_const) { @@ -135,7 +195,11 @@ void compiler_compile(compiler_t* self, return; } - prog_add_instr(prog, OP_LOCAL_STORE, self->loc_counter); + prog_add_instr( + prog, + OP_LOCAL_STORE, + entry->id + ); } } break; @@ -170,7 +234,7 @@ void compiler_compile(compiler_t* self, return; } - prog_add_instr(prog, OP_LOCAL_LOAD, entry->local_addr); + prog_add_instr(prog, OP_LOCAL_LOAD, entry->id); } break; case NODE_ARRAY: { diff --git a/lib/compiler.h b/lib/compiler.h index 12d777d..953e32e 100644 --- a/lib/compiler.h +++ b/lib/compiler.h @@ -8,10 +8,16 @@ #include "err.h" #include "module.h" +typedef struct { + int start_point; + vec_t to_end; +} loop_info_t; + typedef struct { module_t* module; err_t err; int loc_counter; + vec_t loop_infos; } compiler_t; void compiler_init(compiler_t* self, module_t* module); diff --git a/lib/lexer.c b/lib/lexer.c index d42a109..40aaf74 100644 --- a/lib/lexer.c +++ b/lib/lexer.c @@ -171,6 +171,10 @@ node_t* lexer_try_new_next(lexer_t* self) } } + CCM_KEYWORD("break", NODE_BREAK, 0); + CCM_KEYWORD("continue", NODE_CONTINUE, 0); + CCM_KEYWORD("for", NODE_FOR, 0); + CCM_KEYWORD("while", NODE_WHILE, 0); CCM_KEYWORD("if", NODE_IF, 0); CCM_KEYWORD("else", NODE_ELSE, 0); CCM_KEYWORD("begin", NODE_BEGIN, 0); diff --git a/lib/module.c b/lib/module.c index e79b50d..7a1d404 100644 --- a/lib/module.c +++ b/lib/module.c @@ -17,7 +17,7 @@ void module_init(module_t* self) void module_free(module_t* self) { assert(self); - + sym_free(&self->sym); if (self->source) @@ -68,7 +68,7 @@ int module_load(module_t* self, char const* path) compiler_t compiler; compiler_init(&compiler, self); compiler_compile(&compiler, ast, &self->prog); - + if (!err_is_ok(&compiler.err)) { err_print_stack_trace(&compiler.err); diff --git a/lib/node.h b/lib/node.h index 4e15c8b..fb7a901 100644 --- a/lib/node.h +++ b/lib/node.h @@ -17,7 +17,8 @@ G(NODE_GE), G(NODE_EQ), G(NODE_NE), G(NODE_ARRAY), \ G(NODE_VAR), G(NODE_IDENT), G(NODE_ASSIGN), \ G(NODE_VARDECL), G(NODE_CONST), G(NODE_CONSTDECL), \ G(NODE_BEGIN), G(NODE_BLOCK), G(NODE_END), G(NODE_IF), \ -G(NODE_ELSE) +G(NODE_ELSE), G(NODE_WHILE), G(NODE_FOR), G(NODE_BREAK), \ +G(NODE_CONTINUE) CCM_ENUM_H(NodeKind, NODE_KIND); diff --git a/lib/parser.c b/lib/parser.c index 063b2fa..a9a819c 100644 --- a/lib/parser.c +++ b/lib/parser.c @@ -163,6 +163,17 @@ node_t* parser_try_new_expr(parser_t* self) return CCM_TRY(parser_try_new_begin); } + if (lexer_peek_kind(self->lexer, NODE_WHILE, 0)) + { + return CCM_TRY(parser_try_new_while); + } + + if (lexer_peek_kind(self->lexer, NODE_CONTINUE, 0) + || lexer_peek_kind(self->lexer, NODE_BREAK, 0)) + { + return lexer_try_new_next(self->lexer); + } + if (lexer_peek_kind(self->lexer, NODE_IF, 0)) { node_t* node = CCM_TRY(parser_try_new_if); @@ -177,6 +188,34 @@ node_t* parser_try_new_expr(parser_t* self) return CCM_TRY(parser_try_new_or); } +node_t* parser_try_new_while(parser_t* self) +{ + assert(self); + + if (!parser_consume(self, NODE_WHILE)) + { + return NULL; + } + + node_t* expr = CCM_TRY(parser_try_new_expr); + if (!expr) { return NULL; } + + node_t* block = CCM_TRY(parser_try_new_block); + + if (!block || !parser_consume(self, NODE_END)) + { + node_free(expr); free(expr); + return NULL; + } + + node_t* node = malloc(sizeof(node_t)); + node_init(node, NODE_WHILE, "", expr->line); + node_push_new_child(node, expr); + node_push_new_child(node, block); + + return node; +} + node_t* parser_try_new_if(parser_t* self) { assert(self); diff --git a/lib/parser.h b/lib/parser.h index f39733f..0ba2b23 100644 --- a/lib/parser.h +++ b/lib/parser.h @@ -26,6 +26,7 @@ int parser_ensure(parser_t* self, node_t* node, NodeKind kind); node_t* parser_try_new_module(parser_t* self); node_t* parser_try_new_expr(parser_t* self); +node_t* parser_try_new_while(parser_t* self); node_t* parser_try_new_if(parser_t* self); node_t* parser_try_new_begin(parser_t* self); node_t* parser_try_new_block(parser_t* self); diff --git a/lib/sym.c b/lib/sym.c index 32323e8..9c69ebe 100644 --- a/lib/sym.c +++ b/lib/sym.c @@ -4,6 +4,7 @@ void sym_init(sym_t* self) { assert(self); self->env = NULL; + self->id_counter = 0; } void sym_free(sym_t* self) @@ -91,7 +92,9 @@ int sym_declare(sym_t* self, entry->name = strdup(name); entry->local_addr = addr; entry->is_const = is_const; + entry->id = self->id_counter; vec_push(&self->env->entries, entry); + self->id_counter++; return 1; } diff --git a/lib/sym.h b/lib/sym.h index 3695226..aa38394 100644 --- a/lib/sym.h +++ b/lib/sym.h @@ -7,6 +7,7 @@ typedef struct { char* name; + int id; int local_addr; int is_const; } sym_entry_t; @@ -18,6 +19,7 @@ typedef struct env { typedef struct { env_t* env; + int id_counter; } sym_t; void sym_init(sym_t* self); diff --git a/tests/loop.ccm b/tests/loop.ccm new file mode 100644 index 0000000..719bd55 --- /dev/null +++ b/tests/loop.ccm @@ -0,0 +1,65 @@ +var a = 0 + +while a < 100 + a = a + 1 +end + +assert_eq (100, a) + +var b = 0 +var c = 0 +var d = 0 + +while b < 6 + c = 0 + while c < 7 + d = d + 1 + c = c + 1 + end + + b = b + 1 +end + +assert_eq (d, 42) + +var e = 0 +var f = 0 + +while e < 128 + e = e + 1 + if e % 2 == 0 + continue + end + + f = f + 1 +end + +assert_eq (64, f) + +var g = 0 +var h = 0 +var i = 0 + +while g < 100 + h = 0 + + if g >= 7 + break + end + + while h < 100 + if h >= 6 + break + end + + h = h + 1 + if h % 2 == 0 + continue + end + i = i + 1 + end + + g = g + 1 +end + +assert_eq (21, i)