X-Git-Url: https://git.xonotic.org/?a=blobdiff_plain;ds=sidebyside;f=parser.c;h=14b4c810dab20c866ebbffbb025f89078d223feb;hb=e146fd121caad020e2f5259ed71dc3146c2dafb1;hp=8701a8fa93b0d159aee8761f87504e1b548ad0d6;hpb=a421d9a33bf371492b5ccba8294a6df31f397412;p=xonotic%2Fgmqcc.git diff --git a/parser.c b/parser.c index 8701a8f..14b4c81 100644 --- a/parser.c +++ b/parser.c @@ -111,8 +111,8 @@ static ast_block* parse_block(parser_t *parser); static bool parse_block_into(parser_t *parser, ast_block *block); static bool parse_statement_or_block(parser_t *parser, ast_expression **out); static bool parse_statement(parser_t *parser, ast_block *block, ast_expression **out, bool allow_cases); -static ast_expression* parse_expression_leave(parser_t *parser, bool stopatcomma, bool truthvalue); -static ast_expression* parse_expression(parser_t *parser, bool stopatcomma); +static ast_expression* parse_expression_leave(parser_t *parser, bool stopatcomma, bool truthvalue, bool with_labels); +static ast_expression* parse_expression(parser_t *parser, bool stopatcomma, bool with_labels); static void parseerror(parser_t *parser, const char *fmt, ...) { @@ -300,11 +300,9 @@ static ast_expression* parser_find_field(parser_t *parser, const char *name) return ( ast_expression*)util_htget(parser->htfields, name); } -static ast_expression* parser_find_label(parser_t *parser, const char *name) { +static ast_expression* parser_find_label(parser_t *parser, const char *name) +{ size_t i; - if (!parser->labels) - return NULL; - for(i = 0; i < vec_size(parser->labels); i++) if (!strcmp(parser->labels[i]->name, name)) return (ast_expression*)parser->labels[i]; @@ -1494,7 +1492,7 @@ static void parser_reclassify_token(parser_t *parser) } } -static ast_expression* parse_expression_leave(parser_t *parser, bool stopatcomma, bool truthvalue) +static ast_expression* parse_expression_leave(parser_t *parser, bool stopatcomma, bool truthvalue, bool with_labels) { ast_expression *expr = NULL; shunt sy; @@ -1584,14 +1582,20 @@ static ast_expression* parse_expression_leave(parser_t *parser, bool stopatcomma parseerror(parser, "namespace for member not found"); goto onerr; } - else if (!(var = parser_find_var(parser, parser_tokval(parser)))) - var = (ast_expression*)parser_find_label(parser, parser_tokval(parser)); + else + var = parser_find_var(parser, parser_tokval(parser)); } else { var = parser_find_var(parser, parser_tokval(parser)); if (!var) var = parser_find_field(parser, parser_tokval(parser)); - if (!var) - var = parser_find_label(parser, parser_tokval(parser)); + } + if (!var && with_labels) { + var = (ast_expression*)parser_find_label(parser, parser_tokval(parser)); + if (!with_labels) { + ast_label *lbl = ast_label_new(parser_ctx(parser), parser_tokval(parser), true); + var = (ast_expression*)lbl; + vec_push(parser->labels, lbl); + } } if (!var) { /* intrinsics */ @@ -1920,9 +1924,9 @@ onerr: return NULL; } -static ast_expression* parse_expression(parser_t *parser, bool stopatcomma) +static ast_expression* parse_expression(parser_t *parser, bool stopatcomma, bool with_labels) { - ast_expression *e = parse_expression_leave(parser, stopatcomma, false); + ast_expression *e = parse_expression_leave(parser, stopatcomma, false, with_labels); if (!e) return NULL; if (!parser_next(parser)) { @@ -2072,7 +2076,7 @@ static bool parse_if(parser_t *parser, ast_block *block, ast_expression **out) return false; } /* parse the condition */ - cond = parse_expression_leave(parser, false, true); + cond = parse_expression_leave(parser, false, true, false); if (!cond) return false; /* closing paren */ @@ -2193,7 +2197,7 @@ static bool parse_while_go(parser_t *parser, ast_block *block, ast_expression ** return false; } /* parse the condition */ - cond = parse_expression_leave(parser, false, true); + cond = parse_expression_leave(parser, false, true, false); if (!cond) return false; /* closing paren */ @@ -2308,7 +2312,7 @@ static bool parse_dowhile_go(parser_t *parser, ast_block *block, ast_expression return false; } /* parse the condition */ - cond = parse_expression_leave(parser, false, true); + cond = parse_expression_leave(parser, false, true, false); if (!cond) return false; /* closing paren */ @@ -2437,7 +2441,7 @@ static bool parse_for_go(parser_t *parser, ast_block *block, ast_expression **ou } else if (parser->tok != ';') { - initexpr = parse_expression_leave(parser, false, false); + initexpr = parse_expression_leave(parser, false, false, false); if (!initexpr) goto onerr; } @@ -2454,7 +2458,7 @@ static bool parse_for_go(parser_t *parser, ast_block *block, ast_expression **ou /* parse the condition */ if (parser->tok != ';') { - cond = parse_expression_leave(parser, false, true); + cond = parse_expression_leave(parser, false, true, false); if (!cond) goto onerr; } @@ -2471,7 +2475,7 @@ static bool parse_for_go(parser_t *parser, ast_block *block, ast_expression **ou /* parse the incrementor */ if (parser->tok != ')') { - increment = parse_expression_leave(parser, false, false); + increment = parse_expression_leave(parser, false, false, false); if (!increment) goto onerr; if (!ast_side_effects(increment)) { @@ -2528,7 +2532,7 @@ static bool parse_return(parser_t *parser, ast_block *block, ast_expression **ou } if (parser->tok != ';') { - exp = parse_expression(parser, false); + exp = parse_expression(parser, false, false); if (!exp) return false; @@ -2814,7 +2818,7 @@ static bool parse_switch_go(parser_t *parser, ast_block *block, ast_expression * return false; } /* parse the operand */ - operand = parse_expression_leave(parser, false, false); + operand = parse_expression_leave(parser, false, false, false); if (!operand) return false; @@ -2878,7 +2882,7 @@ static bool parse_switch_go(parser_t *parser, ast_block *block, ast_expression * parseerror(parser, "expected expression for case"); return false; } - swcase.value = parse_expression_leave(parser, false, false); + swcase.value = parse_expression_leave(parser, false, false, false); if (!swcase.value) { ast_delete(switchnode); parseerror(parser, "expected expression for case"); @@ -2981,6 +2985,13 @@ static ast_expression *parse_goto_computed(parser_t *parser, ast_expression *sid on_true = parse_goto_computed(parser, ((ast_ternary*)side)->on_true); on_false = parse_goto_computed(parser, ((ast_ternary*)side)->on_false); + if (!on_true || !on_false) { + parseerror(parser, "expected label or expression in ternary"); + if (((ast_ternary*)side)->on_false) ast_unref(((ast_ternary*)side)->on_false); + if (((ast_ternary*)side)->on_true) ast_unref(((ast_ternary*)side)->on_true); + return NULL; + } + return (ast_expression*)ast_ifthen_new(parser_ctx(parser), ((ast_ternary*)side)->cond, on_true, on_false); } else if (ast_istype(side, ast_label)) { ast_goto *gt = ast_goto_new(parser_ctx(parser), ((ast_label*)side)->name); @@ -2992,14 +3003,15 @@ static ast_expression *parse_goto_computed(parser_t *parser, ast_expression *sid static bool parse_goto(parser_t *parser, ast_expression **out) { - size_t i; - ast_goto *gt = NULL; + ast_goto *gt = NULL; + ast_expression *lbl; if (!parser_next(parser)) return false; if (parser->tok != TOKEN_IDENT) { ast_expression *expression; + /* could be an expression i.e computed goto :-) */ if (parser->tok != '(') { parseerror(parser, "expected label name after `goto`"); @@ -3007,29 +3019,32 @@ static bool parse_goto(parser_t *parser, ast_expression **out) } /* failed to parse expression for goto */ - if (!(expression = parse_expression(parser, false))) - return false; - - if (!(*out = parse_goto_computed(parser, expression))) + if (!(expression = parse_expression(parser, false, true)) || + !(*out = parse_goto_computed(parser, expression))) { + parseerror(parser, "invalid goto expression"); + ast_unref(expression); return false; + } return true; } /* not computed goto */ 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; + lbl = parser_find_label(parser, gt->name); + if (lbl) { + if (!ast_istype(lbl, ast_label)) { + parseerror(parser, "internal error: label is not an ast_label"); + ast_delete(gt); + return false; } + ast_goto_set_label(gt, (ast_label*)lbl); } - if (i == vec_size(parser->labels)) + else vec_push(parser->gotos, gt); if (!parser_next(parser) || parser->tok != ';') { - parseerror(parser, "semicolon expected after goto label got"); + parseerror(parser, "semicolon expected after goto label"); return false; } if (!parser_next(parser)) { @@ -3260,10 +3275,18 @@ static bool parse_statement(parser_t *parser, ast_block *block, ast_expression * parseerror(parser, "label must be an identifier"); return false; } - label = ast_label_new(parser_ctx(parser), parser_tokval(parser)); - if (!label) - return false; - vec_push(parser->labels, label); + label = (ast_label*)parser_find_label(parser, parser_tokval(parser)); + if (label) { + if (!label->undefined) { + parseerror(parser, "label `%s` already defined", label->name); + return false; + } + label->undefined = false; + } + else { + label = ast_label_new(parser_ctx(parser), parser_tokval(parser), false); + vec_push(parser->labels, label); + } *out = (ast_expression*)label; if (!parser_next(parser)) { parseerror(parser, "parse error after label"); @@ -3288,7 +3311,7 @@ static bool parse_statement(parser_t *parser, ast_block *block, ast_expression * } else { - ast_expression *exp = parse_expression(parser, false); + ast_expression *exp = parse_expression(parser, false, false); if (!exp) return false; *out = exp; @@ -3449,7 +3472,7 @@ static bool parse_function_body(parser_t *parser, ast_value *var) if (!parser_next(parser)) return false; - framenum = parse_expression_leave(parser, true, false); + framenum = parse_expression_leave(parser, true, false, false); if (!framenum) { parseerror(parser, "expected a framenumber constant in[frame,think] notation"); return false; @@ -3497,7 +3520,7 @@ static bool parse_function_body(parser_t *parser, ast_value *var) nextthink = (ast_expression*)thinkfunc; } else { - nextthink = parse_expression_leave(parser, true, false); + nextthink = parse_expression_leave(parser, true, false, false); if (!nextthink) { ast_unref(framenum); parseerror(parser, "expected a think-function in [frame,think] notation"); @@ -4163,7 +4186,7 @@ static ast_value *parse_arraysize(parser_t *parser, ast_value *var) return NULL; } - cexp = parse_expression_leave(parser, true, false); + cexp = parse_expression_leave(parser, true, false, false); if (!cexp || !ast_istype(cexp, ast_value)) { if (cexp) @@ -4929,7 +4952,7 @@ skipvar: ast_expression *cexp; ast_value *cval; - cexp = parse_expression_leave(parser, true, false); + cexp = parse_expression_leave(parser, true, false, false); if (!cexp) break;