From: Wolfgang (Blub) Bumiller Date: Sun, 25 Nov 2012 20:53:14 +0000 (+0100) Subject: parsing goto X-Git-Tag: 0.1.9~233 X-Git-Url: https://git.rm.cloudns.org/?a=commitdiff_plain;h=24f9b634759db31d46262fbbc8245558f781129d;p=xonotic%2Fgmqcc.git parsing goto --- diff --git a/ast.c b/ast.c index a73c586..9a1fbe3 100644 --- a/ast.c +++ b/ast.c @@ -844,6 +844,11 @@ void ast_goto_delete(ast_goto *self) mem_d(self); } +void ast_goto_set_label(ast_goto *self, ast_label *label) +{ + self->target = label; +} + ast_call* ast_call_new(lex_ctx ctx, ast_expression *funcexpr) { diff --git a/ast.h b/ast.h index 3a133ac..29c3192 100644 --- a/ast.h +++ b/ast.h @@ -525,7 +525,7 @@ struct ast_goto_s 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*); +void ast_goto_set_label(ast_goto*, ast_label*); bool ast_goto_codegen(ast_goto*, ast_function*, bool lvalue, ir_value**); diff --git a/parser.c b/parser.c index 1d752c4..67cf0fd 100644 --- a/parser.c +++ b/parser.c @@ -58,6 +58,12 @@ typedef struct { ast_function *function; + /* All the labels the function defined... + * Should they be in ast_function instead? + */ + ast_label **labels; + ast_goto **gotos; + /* A list of hashtables for each scope */ ht *variables; ht htfields; @@ -2227,6 +2233,40 @@ static bool parse_switch(parser_t *parser, ast_block *block, ast_expression **ou return true; } +static bool parse_goto(parser_t *parser, ast_expression **out) +{ + size_t i; + ast_goto *gt; + + if (!parser_next(parser) || parser->tok != TOKEN_IDENT) { + parseerror(parser, "expected label name after `goto`"); + return false; + } + + gt = ast_goto_new(parser_ctx(parser), parser_tokval(parser)); + + for (i = 0; i < vec_size(parser->labels); ++i) { + if (!strcmp(parser->labels[i]->name, parser_tokval(parser))) { + ast_goto_set_label(gt, parser->labels[i]); + break; + } + } + if (i == vec_size(parser->labels)) + vec_push(parser->gotos, gt); + + if (!parser_next(parser) || parser->tok != ';') { + parseerror(parser, "semicolon expected after goto label"); + return false; + } + if (!parser_next(parser)) { + parseerror(parser, "parse error after goto"); + return false; + } + + *out = (ast_expression*)gt; + return true; +} + static bool parse_statement(parser_t *parser, ast_block *block, ast_expression **out, bool allow_cases) { ast_value *typevar = NULL; @@ -2316,6 +2356,10 @@ static bool parse_statement(parser_t *parser, ast_block *block, ast_expression * } return true; } + else if (!strcmp(parser_tokval(parser), "goto")) + { + return parse_goto(parser, out); + } else if (!strcmp(parser_tokval(parser), "typedef")) { if (!parser_next(parser)) { @@ -2350,6 +2394,7 @@ static bool parse_statement(parser_t *parser, ast_block *block, ast_expression * label = ast_label_new(parser_ctx(parser), parser_tokval(parser)); if (!label) return false; + vec_push(parser->labels, label); *out = (ast_expression*)label; if (!parser_next(parser)) { parseerror(parser, "parse error after label"); @@ -2495,6 +2540,11 @@ static bool parse_function_body(parser_t *parser, ast_value *var) has_frame_think = false; old = parser->function; + if (vec_size(parser->gotos) || vec_size(parser->labels)) { + parseerror(parser, "gotos/labels leaking"); + return false; + } + if (var->expression.variadic) { if (parsewarning(parser, WARN_VARIADIC_FUNCTION, "variadic function with implementation will not be able to access additional parameters")) @@ -3871,6 +3921,8 @@ skipvar: if (!parse_function_body(parser, var)) break; ast_delete(basetype); + vec_free(parser->gotos); + vec_free(parser->labels); return true; } else { ast_expression *cexp; @@ -4248,6 +4300,9 @@ void parser_cleanup() vec_free(parser->typedefs); vec_free(parser->_blocktypedefs); + vec_free(parser->labels); + vec_free(parser->gotos); + mem_d(parser); }