X-Git-Url: https://git.xonotic.org/?a=blobdiff_plain;f=parser.c;h=33eba59f7960d774ad03dbb4a8bc72dc1f77d741;hb=c84830bdee1bc4b36d55fdfd320b301f59a1e361;hp=ef7b5154060dd28c33d0af1cc13c9adad8ef00fc;hpb=d4077f6884edd0a4e6755fab11856a8d904e5f9e;p=xonotic%2Fgmqcc.git diff --git a/parser.c b/parser.c index ef7b515..33eba59 100644 --- a/parser.c +++ b/parser.c @@ -44,7 +44,7 @@ MEM_VEC_FUNCTIONS(parser_t, ast_value*, imm_vector) MEM_VEC_FUNCTIONS(parser_t, varentry_t, locals) MEM_VEC_FUNCTIONS(parser_t, ast_function*, functions) -static void parser_pop_local(parser_t *parser); +static bool GMQCC_WARN parser_pop_local(parser_t *parser); static bool parser_variable(parser_t *parser, ast_block *localblock); static ast_block* parser_parse_block(parser_t *parser, bool warnreturn); static bool parser_parse_block_into(parser_t *parser, ast_block *block, bool warnreturn); @@ -306,6 +306,7 @@ static ast_value *parser_parse_type(parser_t *parser, int basetype, bool *isfunc int vtype = basetype; int temptype; size_t i; + bool variadic = false; MEM_VECTOR_INIT(¶ms, p); @@ -333,6 +334,22 @@ static ast_value *parser_parse_type(parser_t *parser, int basetype, bool *isfunc } } + if (parser->tok == TOKEN_DOTS) { + /* variadic args */ + variadic = true; + if (!parser_next(parser)) + goto on_error; + if (parser->tok != ')') { + parseerror(parser, "`...` must be the last parameter of a variadic function declaration"); + goto on_error; + } + if (opts_standard == COMPILER_QCC) { + if (parsewarning(parser, WARN_EXTENSIONS, "variadic functions are not available in this standard")) + goto on_error; + } + break; + } + temptype = parser_token(parser)->constval.t; if (!parser_next(parser)) goto on_error; @@ -359,6 +376,7 @@ static ast_value *parser_parse_type(parser_t *parser, int basetype, bool *isfunc } fval->expression.next = (ast_expression*)param; MEM_VECTOR_MOVE(¶m->expression, params, &fval->expression, params); + fval->expression.variadic = param->expression.variadic; param = fval; } @@ -387,6 +405,7 @@ static ast_value *parser_parse_type(parser_t *parser, int basetype, bool *isfunc var = ast_value_new(ctx, "", vtype); if (!var) goto on_error; + var->expression.variadic = variadic; MEM_VECTOR_MOVE(¶ms, p, &var->expression, params); return var; on_error: @@ -952,16 +971,21 @@ static bool parser_close_call(parser_t *parser, shunt *sy) parseerror(parser, "could not determine function return type"); return false; } else { - if (fun->expression.params_count != paramcount) { + if (fun->expression.params_count != paramcount && + !(fun->expression.variadic && + fun->expression.params_count < paramcount)) + { ast_value *fval; + const char *fewmany = (fun->expression.params_count > paramcount) ? "few" : "many"; + fval = (ast_istype(fun, ast_value) ? ((ast_value*)fun) : NULL); if (opts_standard == COMPILER_GMQCC) { if (fval) - parseerror(parser, "too few parameters for call to %s: expected %i, got %i", + parseerror(parser, "too %s parameters for call to %s: expected %i, got %i", fewmany, fval->name, (int)fun->expression.params_count, paramcount); else - parseerror(parser, "too few parameters for function call: expected %i, got %i", + parseerror(parser, "too %s parameters for function call: expected %i, got %i", fewmany, (int)fun->expression.params_count, paramcount); return false; } @@ -969,11 +993,11 @@ static bool parser_close_call(parser_t *parser, shunt *sy) { if (fval) return !parsewarning(parser, WARN_TOO_FEW_PARAMETERS, - "too few parameters for call to %s: expected %i, got %i", + "too %s parameters for call to %s: expected %i, got %i", fewmany, fval->name, (int)fun->expression.params_count, paramcount); else return !parsewarning(parser, WARN_TOO_FEW_PARAMETERS, - "too few parameters for function call: expected %i, got %i", + "too %s parameters for function call: expected %i, got %i", fewmany, (int)fun->expression.params_count, paramcount); } } @@ -1084,6 +1108,8 @@ static ast_expression* parser_expression_leave(parser_t *parser, bool stopatcomm parseerror(parser, "unexpected ident: %s", parser_tokval(parser)); goto onerr; } + if (ast_istype(var, ast_value)) + ((ast_value*)var)->uses++; if (!shunt_out_add(&sy, syexp(parser_ctx(parser), var))) { parseerror(parser, "out of memory"); goto onerr; @@ -1496,6 +1522,7 @@ static bool parser_parse_for(parser_t *parser, ast_block *block, ast_expression ast_loop *aloop; ast_expression *initexpr, *cond, *increment, *ontrue; size_t oldblocklocal; + bool retval = true; lex_ctx ctx = parser_ctx(parser); @@ -1590,15 +1617,15 @@ static bool parser_parse_for(parser_t *parser, ast_block *block, ast_expression *out = (ast_expression*)aloop; while (parser->locals_count > parser->blocklocal) - parser_pop_local(parser); + retval = retval && parser_pop_local(parser); parser->blocklocal = oldblocklocal; - return true; + return retval; onerr: if (initexpr) ast_delete(initexpr); if (cond) ast_delete(cond); if (increment) ast_delete(increment); while (parser->locals_count > parser->blocklocal) - parser_pop_local(parser); + (void)!parser_pop_local(parser); parser->blocklocal = oldblocklocal; return false; } @@ -1719,15 +1746,24 @@ static bool parser_parse_statement(parser_t *parser, ast_block *block, ast_expre } } -static void parser_pop_local(parser_t *parser) +static bool GMQCC_WARN parser_pop_local(parser_t *parser) { + varentry_t *ve; parser->locals_count--; + + ve = &parser->locals[parser->locals_count]; + if (ast_istype(ve->var, ast_value) && !(((ast_value*)(ve->var))->uses)) { + if (parsewarning(parser, WARN_UNUSED_VARIABLE, "unused variable: `%s`", ve->name)) + return false; + } mem_d(parser->locals[parser->locals_count].name); + return true; } static bool parser_parse_block_into(parser_t *parser, ast_block *block, bool warnreturn) { size_t oldblocklocal; + bool retval = true; oldblocklocal = parser->blocklocal; parser->blocklocal = parser->locals_count; @@ -1776,7 +1812,7 @@ static bool parser_parse_block_into(parser_t *parser, ast_block *block, bool war cleanup: while (parser->locals_count > parser->blocklocal) - parser_pop_local(parser); + retval = retval && parser_pop_local(parser); parser->blocklocal = oldblocklocal; return !!block; } @@ -1878,6 +1914,8 @@ static bool parser_variable(parser_t *parser, ast_block *localblock) bool hadproto; bool isparam; + bool retval = true; + int basetype = parser_token(parser)->constval.t; if (!parser_next(parser)) { @@ -2024,6 +2062,7 @@ static bool parser_variable(parser_t *parser, ast_block *localblock) fval->expression.next = (ast_expression*)var; MEM_VECTOR_MOVE(&var->expression, params, &fval->expression, params); + fval->expression.variadic = var->expression.variadic; /* we compare the type late here, but it's easier than * messing with the parameter-vector etc. earlier @@ -2080,10 +2119,10 @@ static bool parser_variable(parser_t *parser, ast_block *localblock) !ast_block_collect(localblock, vy.var) || !ast_block_collect(localblock, vz.var)) { - parser_pop_local(parser); - parser_pop_local(parser); - parser_pop_local(parser); - parser_pop_local(parser); + (void)!parser_pop_local(parser); + (void)!parser_pop_local(parser); + (void)!parser_pop_local(parser); + (void)!parser_pop_local(parser); ast_value_delete(var); ast_value_delete(typevar); return false; @@ -2101,7 +2140,7 @@ static bool parser_variable(parser_t *parser, ast_block *localblock) } if (localblock && !ast_block_locals_add(localblock, var)) { - parser_pop_local(parser); + (void)!parser_pop_local(parser); ast_value_delete(var); ast_value_delete(typevar); return false; @@ -2217,6 +2256,15 @@ nextvar: has_frame_think = false; old = parser->function; + if (var->expression.variadic) { + if (parsewarning(parser, WARN_VARIADIC_FUNCTION, + "variadic function with implementation will not be able to access additional parameters")) + { + ast_value_delete(typevar); + return false; + } + } + if (localblock) { parseerror(parser, "cannot declare functions within functions"); ast_value_delete(typevar); @@ -2413,9 +2461,9 @@ nextvar: !ast_block_collect(block, vy.var) || !ast_block_collect(block, vz.var) ) { - parser_pop_local(parser); - parser_pop_local(parser); - parser_pop_local(parser); + (void)!parser_pop_local(parser); + (void)!parser_pop_local(parser); + (void)!parser_pop_local(parser); ast_block_delete(block); ast_value_delete(typevar); return false; @@ -2449,7 +2497,7 @@ nextvar: } parser->function = old; while (parser->locals_count) - parser_pop_local(parser); + retval = retval && parser_pop_local(parser); if (!block) { ast_value_delete(typevar); @@ -2469,12 +2517,17 @@ nextvar: else if (opts_standard == COMPILER_QCC) parseerror(parser, "missing semicolon after function body (mandatory with -std=qcc)"); ast_value_delete(typevar); - return true; + return retval; } else { ast_expression *cexp; ast_value *cval; cexp = parser_expression_leave(parser, true); + if (!cexp) { + ast_value_delete(typevar); + return false; + } + cval = (ast_value*)cexp; if (!ast_istype(cval, ast_value) || !cval->isconst) parseerror(parser, "cannot initialize a global constant variable with a non-constant expression"); @@ -2579,6 +2632,7 @@ static bool parser_do(parser_t *parser) } fval->expression.next = (ast_expression*)var; MEM_VECTOR_MOVE(&var->expression, params, &fval->expression, params); + fval->expression.variadic = var->expression.variadic; var = fval; }