From f431b7a693f73810b05c5f4f049de0df8ac50ac4 Mon Sep 17 00:00:00 2001 From: "Wolfgang (Blub) Bumiller" Date: Sun, 25 Nov 2012 21:40:26 +0100 Subject: [PATCH] Support codegen of ast_label and ast_goto in any order --- ast.c | 74 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ ast.h | 24 ++++++++++++++++++- 2 files changed, 97 insertions(+), 1 deletion(-) diff --git a/ast.c b/ast.c index 16141b8..a73c586 100644 --- a/ast.c +++ b/ast.c @@ -807,11 +807,37 @@ ast_label* ast_label_new(lex_ctx ctx, const char *name) self->name = util_strdup(name); self->irblock = NULL; + self->gotos = NULL; return self; } void ast_label_delete(ast_label *self) +{ + mem_d((void*)self->name); + vec_free(self->gotos); + ast_expression_delete((ast_expression*)self); + mem_d(self); +} + +void ast_label_register_goto(ast_label *self, ast_goto *g) +{ + vec_push(self->gotos, g); +} + +ast_goto* ast_goto_new(lex_ctx ctx, const char *name) +{ + ast_instantiate(ast_goto, ctx, ast_goto_delete); + ast_expression_init((ast_expression*)self, (ast_expression_codegen*)&ast_goto_codegen); + + self->name = util_strdup(name); + self->target = NULL; + self->irblock_from = NULL; + + return self; +} + +void ast_goto_delete(ast_goto *self) { mem_d((void*)self->name); ast_expression_delete((ast_expression*)self); @@ -2655,6 +2681,9 @@ bool ast_switch_codegen(ast_switch *self, ast_function *func, bool lvalue, ir_va bool ast_label_codegen(ast_label *self, ast_function *func, bool lvalue, ir_value **out) { + size_t i; + ir_value *dummy; + *out = NULL; if (lvalue) { asterror(ast_ctx(self), "internal error: ast_label cannot be an lvalue"); @@ -2674,6 +2703,51 @@ bool ast_label_codegen(ast_label *self, ast_function *func, bool lvalue, ir_valu /* enter the new block */ func->curblock = self->irblock; + + /* Generate all the leftover gotos */ + for (i = 0; i < vec_size(self->gotos); ++i) { + if (!ast_goto_codegen(self->gotos[i], func, false, &dummy)) + return false; + } + + return true; +} + +bool ast_goto_codegen(ast_goto *self, ast_function *func, bool lvalue, ir_value **out) +{ + *out = NULL; + if (lvalue) { + asterror(ast_ctx(self), "internal error: ast_goto cannot be an lvalue"); + return false; + } + + if (self->target->irblock) { + if (self->irblock_from) { + /* we already tried once, this is the callback */ + self->irblock_from->final = false; + if (!ir_block_create_jump(self->irblock_from, self->target->irblock)) { + asterror(ast_ctx(self), "failed to generate goto to `%s`", self->name); + return false; + } + } + else + { + if (!ir_block_create_jump(func->curblock, self->target->irblock)) { + asterror(ast_ctx(self), "failed to generate goto to `%s`", self->name); + return false; + } + } + } + else + { + /* the target has not yet been created... + * close this block in a sneaky way: + */ + func->curblock->final = true; + self->irblock_from = func->curblock; + ast_label_register_goto(self->target, self); + } + return true; } diff --git a/ast.h b/ast.h index 62287fe..3a133ac 100644 --- a/ast.h +++ b/ast.h @@ -49,6 +49,7 @@ typedef struct ast_array_index_s ast_array_index; typedef struct ast_breakcont_s ast_breakcont; typedef struct ast_switch_s ast_switch; typedef struct ast_label_s ast_label; +typedef struct ast_goto_s ast_goto; enum { TYPE_ast_node, @@ -70,7 +71,8 @@ enum { TYPE_ast_array_index, TYPE_ast_breakcont, TYPE_ast_switch, - TYPE_ast_label + TYPE_ast_label, + TYPE_ast_goto }; #define ast_istype(x, t) ( ((ast_node_common*)x)->nodetype == (TYPE_##t) ) @@ -500,13 +502,33 @@ struct ast_label_s ast_expression_common expression; const char *name; ir_block *irblock; + ast_goto **gotos; }; ast_label* ast_label_new(lex_ctx ctx, const char *name); void ast_label_delete(ast_label*); +void ast_label_register_goto(ast_label*, ast_goto*); bool ast_label_codegen(ast_label*, ast_function*, bool lvalue, ir_value**); +/* GOTO nodes + * + * Go to a label, the label node is filled in at a later point! + */ +struct ast_goto_s +{ + ast_expression_common expression; + const char *name; + ast_label *target; + ir_block *irblock_from; +}; + +ast_goto* ast_goto_new(lex_ctx ctx, const char *name); +void ast_goto_delete(ast_goto*); +void ast_goto_setlabel(ast_goto*, ast_label*); + +bool ast_goto_codegen(ast_goto*, ast_function*, bool lvalue, ir_value**); + /* CALL node * * Contains an ast_expression as target, rather than an ast_function/value. -- 2.39.2