X-Git-Url: https://git.xonotic.org/?a=blobdiff_plain;f=parser.c;h=f53167ad8e66ae1438da62a34cc062322e509599;hb=40b2a26e896fd7a3f54c94ccb2abd9d517491822;hp=23a3ed6fc7bae059e7ac69dc696a70b936f2ba7d;hpb=ebb7cb2ae39dad8eb59310b16ad4958a69c385c3;p=xonotic%2Fgmqcc.git diff --git a/parser.c b/parser.c index 23a3ed6..f53167a 100644 --- a/parser.c +++ b/parser.c @@ -62,7 +62,8 @@ typedef struct { */ ast_label **labels; ast_goto **gotos; - const char **loops; + const char **breaks; + const char **continues; /* A list of hashtables for each scope */ ht *variables; @@ -1664,7 +1665,7 @@ static ast_expression* parse_expression_leave(parser_t *parser, bool stopatcomma const oper_info *olast = NULL; size_t o; for (o = 0; o < operator_count; ++o) { - if ((!(operators[o].flags & OP_PREFIX) == wantop) && + if (((!(operators[o].flags & OP_PREFIX) == !!wantop)) && /* !(operators[o].flags & OP_SUFFIX) && / * remove this */ !strcmp(parser_tokval(parser), operators[o].op)) { @@ -2054,19 +2055,22 @@ static bool parse_while(parser_t *parser, ast_block *block, ast_expression **out return false; } - vec_push(parser->loops, label); + vec_push(parser->breaks, label); + vec_push(parser->continues, label); rv = parse_while_go(parser, block, out); if (label) mem_d(label); - if (vec_last(parser->loops) != label) { + if (vec_last(parser->breaks) != label || vec_last(parser->continues) != label) { parseerror(parser, "internal error: label stack corrupted"); rv = false; ast_delete(*out); *out = NULL; } - else - vec_pop(parser->loops); + else { + vec_pop(parser->breaks); + vec_pop(parser->continues); + } return rv; } @@ -2081,11 +2085,6 @@ static bool parse_while_go(parser_t *parser, ast_block *block, ast_expression ** (void)block; /* not touching */ - /* skip the 'while' and check for opening paren */ - if (!parser_next(parser) || parser->tok != '(') { - parseerror(parser, "expected 'while' condition in parenthesis"); - return false; - } /* parse into the expression */ if (!parser_next(parser)) { parseerror(parser, "expected 'while' condition after opening paren"); @@ -2152,19 +2151,22 @@ static bool parse_dowhile(parser_t *parser, ast_block *block, ast_expression **o } } - vec_push(parser->loops, label); + vec_push(parser->breaks, label); + vec_push(parser->continues, label); rv = parse_dowhile_go(parser, block, out); if (label) mem_d(label); - if (vec_last(parser->loops) != label) { + if (vec_last(parser->breaks) != label || vec_last(parser->continues) != label) { parseerror(parser, "internal error: label stack corrupted"); rv = false; ast_delete(*out); *out = NULL; } - else - vec_pop(parser->loops); + else { + vec_pop(parser->breaks); + vec_pop(parser->continues); + } return rv; } @@ -2274,19 +2276,22 @@ static bool parse_for(parser_t *parser, ast_block *block, ast_expression **out) return false; } - vec_push(parser->loops, label); + vec_push(parser->breaks, label); + vec_push(parser->continues, label); rv = parse_for_go(parser, block, out); if (label) mem_d(label); - if (vec_last(parser->loops) != label) { + if (vec_last(parser->breaks) != label || vec_last(parser->continues) != label) { parseerror(parser, "internal error: label stack corrupted"); rv = false; ast_delete(*out); *out = NULL; } - else - vec_pop(parser->loops); + else { + vec_pop(parser->breaks); + vec_pop(parser->continues); + } return rv; } static bool parse_for_go(parser_t *parser, ast_block *block, ast_expression **out) @@ -2449,9 +2454,10 @@ static bool parse_return(parser_t *parser, ast_block *block, ast_expression **ou static bool parse_break_continue(parser_t *parser, ast_block *block, ast_expression **out, bool is_continue) { - size_t i; + size_t i; unsigned int levels = 0; - lex_ctx ctx = parser_ctx(parser); + lex_ctx ctx = parser_ctx(parser); + const char **loops = (is_continue ? parser->continues : parser->breaks); (void)block; /* not touching */ if (!parser_next(parser)) { @@ -2462,9 +2468,9 @@ static bool parse_break_continue(parser_t *parser, ast_block *block, ast_express if (parser->tok == TOKEN_IDENT) { if (!OPTS_FLAG(LOOP_LABELS)) parseerror(parser, "labeled loops not activated, try using -floop-labels"); - i = vec_size(parser->loops); + i = vec_size(loops); while (i--) { - if (parser->loops[i] && !strcmp(parser->loops[i], parser_tokval(parser))) + if (loops[i] && !strcmp(loops[i], parser_tokval(parser))) break; if (!i) { parseerror(parser, "no such loop to %s: `%s`", @@ -2577,7 +2583,59 @@ onerr: return true; } +static bool parse_switch_go(parser_t *parser, ast_block *block, ast_expression **out); static bool parse_switch(parser_t *parser, ast_block *block, ast_expression **out) +{ + bool rv; + char *label = NULL; + + /* skip the 'while' and get the body */ + if (!parser_next(parser)) { + if (OPTS_FLAG(LOOP_LABELS)) + parseerror(parser, "expected loop label or 'switch' operand in parenthesis"); + else + parseerror(parser, "expected 'switch' operand in parenthesis"); + return false; + } + + if (parser->tok == ':') { + if (!OPTS_FLAG(LOOP_LABELS)) + parseerror(parser, "labeled loops not activated, try using -floop-labels"); + if (!parser_next(parser) || parser->tok != TOKEN_IDENT) { + parseerror(parser, "expected loop label"); + return false; + } + label = util_strdup(parser_tokval(parser)); + if (!parser_next(parser)) { + mem_d(label); + parseerror(parser, "expected 'switch' operand in parenthesis"); + return false; + } + } + + if (parser->tok != '(') { + parseerror(parser, "expected 'switch' operand in parenthesis"); + return false; + } + + vec_push(parser->breaks, label); + + rv = parse_switch_go(parser, block, out); + if (label) + mem_d(label); + if (vec_last(parser->breaks) != label) { + parseerror(parser, "internal error: label stack corrupted"); + rv = false; + ast_delete(*out); + *out = NULL; + } + else { + vec_pop(parser->breaks); + } + return rv; +} + +static bool parse_switch_go(parser_t *parser, ast_block *block, ast_expression **out) { ast_expression *operand; ast_value *opval; @@ -2593,12 +2651,6 @@ static bool parse_switch(parser_t *parser, ast_block *block, ast_expression **ou (void)block; /* not touching */ (void)opval; - /* parse over the opening paren */ - if (!parser_next(parser) || parser->tok != '(') { - parseerror(parser, "expected switch operand in parenthesis"); - return false; - } - /* parse into the expression */ if (!parser_next(parser)) { parseerror(parser, "expected switch operand"); @@ -4985,6 +5037,8 @@ void parser_cleanup() vec_free(parser->labels); vec_free(parser->gotos); + vec_free(parser->breaks); + vec_free(parser->continues); mem_d(parser); }