diff --git a/core/codegen.c b/core/codegen.c index 015efce..b8c29af 100644 --- a/core/codegen.c +++ b/core/codegen.c @@ -67,6 +67,29 @@ resolve_return(struct rifle_state *state, struct ast_node *root) return 0; } +static int +resolve_loop(struct rifle_state *state, struct ast_node *root) +{ + char label[32]; + + if (state == NULL || root == NULL) { + return -1; + } + + if (root->epilogue) { + snprintf(label, sizeof(label), "L.%zu", state->loop_count - 1); + mu_gen_blab(state, label); + + snprintf(label, sizeof(label), "L.%zu.1", state->loop_count - 1); + mu_gen_label(state, label, false); + } else { + snprintf(label, sizeof(label), "L.%zu", state->loop_count++); + mu_gen_label(state, label, false); + } + + return 0; +} + int cg_resolve_node(struct rifle_state *state, struct ast_node *root) { @@ -86,6 +109,12 @@ cg_resolve_node(struct rifle_state *state, struct ast_node *root) return -1; } + break; + case AST_LOOP: + if (resolve_loop(state, root) < 0) { + return -1; + } + break; default: trace_error(state, "unknown ast node %d\n", root->type); diff --git a/core/parser.c b/core/parser.c index b4b4d1d..de5480d 100644 --- a/core/parser.c +++ b/core/parser.c @@ -545,6 +545,14 @@ parse_rbrace(struct rifle_state *state, struct token *tok, struct ast_node **res return -1; } + root->epilogue = 1; + break; + case TT_LOOP: + if (ast_alloc_node(state, AST_LOOP, &root) < 0) { + trace_error(state, "failed to allocate AST_LOOP\n"); + return -1; + } + root->epilogue = 1; break; default: @@ -677,6 +685,45 @@ parse_return(struct rifle_state *state, struct token *tok, struct ast_node **res return 0; } +/* + * Parse a loop statement + * + * @state: Compiler state + * @tok: Last token + * @res: AST result + * + * Returns zero on success + */ +static int +parse_loop(struct rifle_state *state, struct token *tok, struct ast_node **res) +{ + struct ast_node *root; + + if (state == NULL || tok == NULL) { + return -1; + } + + if (res == NULL) { + return -1; + } + + if (tok->type != TT_LOOP) { + return -1; + } + + if (parse_lbrace(state, TT_LOOP, tok) < 0) { + return -1; + } + + if (ast_alloc_node(state, AST_LOOP, &root) < 0) { + trace_error(state, "failed to allocate AST_LOOP\n"); + return -1; + } + + *res = root; + return 0; +} + static int parse_begin(struct rifle_state *state) { @@ -702,6 +749,12 @@ parse_begin(struct rifle_state *state) return -1; } + break; + case TT_LOOP: + if (parse_loop(state, &tok, &root) < 0) { + return -1; + } + break; case TT_PUB: break; diff --git a/inc/rifle/ast.h b/inc/rifle/ast.h index bc93c0f..31b8396 100644 --- a/inc/rifle/ast.h +++ b/inc/rifle/ast.h @@ -13,12 +13,14 @@ * @AST_FUNC: This node represents a function * @AST_RETURN: This node represents a return statement * @AST_NUMBER: This node represents a number + * @AST_LOOP: This node represents a loop statement */ typedef enum { AST_NONE, AST_FUNC, AST_RETURN, - AST_NUMBER + AST_NUMBER, + AST_LOOP } ast_type_t; /* diff --git a/inc/rifle/state.h b/inc/rifle/state.h index d8dc0c9..30bda2c 100644 --- a/inc/rifle/state.h +++ b/inc/rifle/state.h @@ -27,6 +27,7 @@ * @ptrbox: Global pointer box * @symtab: Global symbol table * @ifx_depth: IF directive depth + * @loop_count: Number of loop statements * @scope_depth: How deep in scope we are * @have_ret: If set, function has return statement * @scope_stack: Used to track scopes @@ -42,6 +43,7 @@ struct rifle_state { struct ptrbox ptrbox; struct symbol_table symtab; size_t ifx_depth; + size_t loop_count; uint8_t scope_depth; uint8_t have_ret : 1; tt_t scope_stack[SCOPE_STACK_MAX];