X-Git-Url: https://git.xonotic.org/?p=xonotic%2Fgmqcc.git;a=blobdiff_plain;f=parser.c;h=14d58b645ad80e90b1b8844b73b5e7aea459d12c;hp=482410677becfaeb2749bd79bfbdf81c389b1366;hb=062180e9a8578ffbbf941154f2c4fd43163d2ca4;hpb=2923b718e16d7c82b9cd3244d77bb8c701fd5b53 diff --git a/parser.c b/parser.c index 4824106..14d58b6 100644 --- a/parser.c +++ b/parser.c @@ -266,6 +266,7 @@ static ast_value* parser_const_string(parser_t *parser, const char *str, bool do char name[32]; util_snprintf(name, sizeof(name), "dotranslate_%lu", (unsigned long)(parser->translated++)); ast_value_set_name(out, name); + out->expression.flags |= AST_FLAG_INCLUDE_DEF; } return out; } @@ -279,6 +280,7 @@ static ast_value* parser_const_string(parser_t *parser, const char *str, bool do char name[32]; util_snprintf(name, sizeof(name), "dotranslate_%lu", (unsigned long)(parser->translated++)); out = ast_value_new(parser_ctx(parser), name, TYPE_STRING); + out->expression.flags |= AST_FLAG_INCLUDE_DEF; } else out = ast_value_new(parser_ctx(parser), "#IMMEDIATE", TYPE_STRING); out->cvq = CV_CONST; @@ -2893,8 +2895,10 @@ onerr: static bool parse_return(parser_t *parser, ast_block *block, ast_expression **out) { - ast_expression *exp = NULL; - ast_return *ret = NULL; + ast_expression *exp = NULL; + ast_expression *var = NULL; + ast_return *ret = NULL; + ast_value *retval = parser->function->return_value; ast_value *expected = parser->function->vtype; lex_ctx ctx = parser_ctx(parser); @@ -2906,6 +2910,62 @@ static bool parse_return(parser_t *parser, ast_block *block, ast_expression **ou return false; } + /* return assignments */ + if (parser->tok == '=') { + if (!OPTS_FLAG(RETURN_ASSIGNMENTS)) { + parseerror(parser, "return assignments not activated, try using -freturn-assigments"); + return false; + } + + if (type_store_instr[expected->expression.next->vtype] == VINSTR_END) { + char ty1[1024]; + ast_type_to_string(expected->expression.next, ty1, sizeof(ty1)); + parseerror(parser, "invalid return type: `%s'", ty1); + return false; + } + + if (!parser_next(parser)) { + parseerror(parser, "expected return assignment expression"); + return false; + } + + if (!(exp = parse_expression_leave(parser, false, false, false))) + return false; + + /* prepare the return value */ + if (!retval) { + retval = ast_value_new(ctx, "#LOCAL_RETURN", TYPE_VOID); + ast_type_adopt(retval, expected->expression.next); + parser->function->return_value = retval; + } + + if (!ast_compare_type(exp, (ast_expression*)retval)) { + char ty1[1024], ty2[1024]; + ast_type_to_string(exp, ty1, sizeof(ty1)); + ast_type_to_string(&retval->expression, ty2, sizeof(ty2)); + parseerror(parser, "invalid type for return value: `%s', expected `%s'", ty1, ty2); + } + + /* store to 'return' local variable */ + var = (ast_expression*)ast_store_new( + ctx, + type_store_instr[expected->expression.next->vtype], + (ast_expression*)retval, exp); + + if (!var) { + ast_unref(exp); + return false; + } + + if (parser->tok != ';') + parseerror(parser, "missing semicolon after return assignment"); + else if (!parser_next(parser)) + parseerror(parser, "parse error after return assignment"); + + *out = var; + return true; + } + if (parser->tok != ';') { exp = parse_expression(parser, false, false); if (!exp) @@ -2925,10 +2985,12 @@ static bool parse_return(parser_t *parser, ast_block *block, ast_expression **ou } else { if (!parser_next(parser)) parseerror(parser, "parse error"); - if (expected->expression.next->vtype != TYPE_VOID) { + + if (!retval && expected->expression.next->vtype != TYPE_VOID) + { (void)!parsewarning(parser, WARN_MISSING_RETURN_VALUES, "return without value"); } - ret = ast_return_new(ctx, NULL); + ret = ast_return_new(ctx, (ast_expression*)retval); } *out = (ast_expression*)ret; return true; @@ -3676,7 +3738,7 @@ static bool parse_statement(parser_t *parser, ast_block *block, ast_expression * } return parse_typedef(parser); } - parseerror(parser, "Unexpected keyword"); + parseerror(parser, "Unexpected keyword: `%s'", parser_tokval(parser)); return false; } else if (parser->tok == '{') @@ -4276,6 +4338,7 @@ static bool parse_function_body(parser_t *parser, ast_value *var) } vec_push(func->blocks, block); + parser->function = old; if (!parser_leaveblock(parser)) @@ -4997,6 +5060,7 @@ static ast_value *parse_typename(parser_t *parser, ast_value **storebase, ast_va /* parse on */ if (!parser_next(parser)) { ast_delete(var); + mem_d(name); parseerror(parser, "error after variable or field declaration"); return NULL; } @@ -5006,8 +5070,10 @@ static ast_value *parse_typename(parser_t *parser, ast_value **storebase, ast_va if (parser->tok == '[') { wasarray = true; var = parse_arraysize(parser, var); - if (!var) + if (!var) { + if (name) mem_d(name); return NULL; + } } /* This is the point where we can turn it into a field */ @@ -5026,8 +5092,7 @@ static ast_value *parse_typename(parser_t *parser, ast_value **storebase, ast_va while (parser->tok == '(') { var = parse_parameter_list(parser, var); if (!var) { - if (name) - mem_d((void*)name); + if (name) mem_d(name); return NULL; } } @@ -5036,11 +5101,12 @@ static ast_value *parse_typename(parser_t *parser, ast_value **storebase, ast_va if (name) { if (!ast_value_set_name(var, name)) { ast_delete(var); + mem_d(name); parseerror(parser, "internal error: failed to set name"); return NULL; } /* free the name, ast_value_set_name duplicates */ - mem_d((void*)name); + mem_d(name); } return var;