X-Git-Url: https://git.xonotic.org/?p=xonotic%2Fgmqcc.git;a=blobdiff_plain;f=parser.c;h=53c7867bff857f4db8c60223b6320a9d9a8ddb52;hp=2fc6510e7f7d25716c4e555cd3b86ab3d27b6aec;hb=08200d4f77484b875651171e9cf4694310514a83;hpb=c10d127fd738deeffc57732bbad57a2c6a5f2dfc diff --git a/parser.c b/parser.c index 2fc6510..53c7867 100644 --- a/parser.c +++ b/parser.c @@ -105,7 +105,7 @@ typedef struct { size_t max_param_count; } parser_t; -static const ast_expression *intrinsic_debug_typestring = (ast_expression*)0x10; +static ast_expression * const intrinsic_debug_typestring = (ast_expression*)0x1; static void parser_enterblock(parser_t *parser); static bool parser_leaveblock(parser_t *parser); @@ -121,6 +121,7 @@ static ast_expression* parse_expression_leave(parser_t *parser, bool stopatcomma static ast_expression* parse_expression(parser_t *parser, bool stopatcomma, bool with_labels); static ast_value* parser_create_array_setter_proto(parser_t *parser, ast_value *array, const char *funcname); static ast_value* parser_create_array_getter_proto(parser_t *parser, ast_value *array, const ast_expression *elemtype, const char *funcname); +static ast_value *parse_typename(parser_t *parser, ast_value **storebase, ast_value *cached_typedef); static void parseerror(parser_t *parser, const char *fmt, ...) { @@ -1426,7 +1427,7 @@ static bool parser_close_call(parser_t *parser, shunt *sy) if (ast_istype(fun, ast_value)) { funval = (ast_value*)fun; if ((fun->expression.flags & AST_FLAG_VARIADIC) && - !(funval->cvq == CV_CONST && funval->hasvalue && funval->constval.vfunc->builtin)) + !(/*funval->cvq == CV_CONST && */ funval->hasvalue && funval->constval.vfunc->builtin)) { size_t va_count; if (paramcount < vec_size(fun->expression.params)) @@ -1555,6 +1556,102 @@ static void parser_reclassify_token(parser_t *parser) } } +static ast_expression* parse_vararg_do(parser_t *parser) +{ + ast_expression *idx, *out; + ast_value *typevar; + ast_value *funtype = parser->function->vtype; + + lex_ctx ctx = parser_ctx(parser); + + if (!parser_next(parser) || parser->tok != '(') { + parseerror(parser, "expected parameter index and type in parenthesis"); + return NULL; + } + if (!parser_next(parser)) { + parseerror(parser, "error parsing parameter index"); + return NULL; + } + + idx = parse_expression_leave(parser, true, false, false); + if (!idx) + return NULL; + + if (parser->tok != ',') { + ast_unref(idx); + parseerror(parser, "expected comma after parameter index"); + return NULL; + } + + if (!parser_next(parser) || (parser->tok != TOKEN_IDENT && parser->tok != TOKEN_TYPENAME)) { + ast_unref(idx); + parseerror(parser, "expected typename for vararg"); + return NULL; + } + + typevar = parse_typename(parser, NULL, NULL); + if (!typevar) { + ast_unref(idx); + return NULL; + } + + if (parser->tok != ')') { + ast_unref(idx); + ast_delete(typevar); + parseerror(parser, "expected closing paren"); + return NULL; + } + +#if 0 + if (!parser_next(parser)) { + ast_unref(idx); + ast_delete(typevar); + parseerror(parser, "parse error after vararg"); + return NULL; + } +#endif + + if (!parser->function->varargs) { + ast_unref(idx); + ast_delete(typevar); + parseerror(parser, "function has no variable argument list"); + return NULL; + } + + if (funtype->expression.varparam && + !ast_compare_type((ast_expression*)typevar, (ast_expression*)funtype->expression.varparam)) + { + char ty1[1024]; + char ty2[1024]; + ast_type_to_string((ast_expression*)typevar, ty1, sizeof(ty1)); + ast_type_to_string((ast_expression*)funtype->expression.varparam, ty2, sizeof(ty2)); + compile_error(ast_ctx(typevar), + "function was declared to take varargs of type `%s`, requested type is: %s", + ty2, ty1); + } + + out = (ast_expression*)ast_array_index_new(ctx, (ast_expression*)(parser->function->varargs), idx); + ast_type_adopt(out, typevar); + ast_delete(typevar); + return out; +} + +static ast_expression* parse_vararg(parser_t *parser) +{ + bool old_noops = parser->lex->flags.noops; + enum parser_pot *old_pot = parser->pot; + + ast_expression *out; + + parser->pot = NULL; + parser->lex->flags.noops = true; + out = parse_vararg_do(parser); + + parser->pot = old_pot; + parser->lex->flags.noops = old_noops; + return out; +} + static ast_expression* parse_expression_leave(parser_t *parser, bool stopatcomma, bool truthvalue, bool with_labels) { ast_expression *expr = NULL; @@ -1613,6 +1710,24 @@ static ast_expression* parse_expression_leave(parser_t *parser, bool stopatcomma goto onerr; } } + else if (parser->tok == TOKEN_DOTS) + { + ast_expression *va; + if (!OPTS_FLAG(VARIADIC_ARGS)) { + parseerror(parser, "cannot access varargs (try -fvariadic-args)"); + goto onerr; + } + if (wantop) { + parseerror(parser, "expected operator or end of statement"); + goto onerr; + } + wantop = true; + va = parse_vararg(parser); + if (!va) + goto onerr; + vec_push(sy.out, syexp(parser_ctx(parser), va)); + DEBUGSHUNTDO(con_out("push `...`\n")); + } else if (parser->tok == TOKEN_IDENT) { const char *ctoken = parser_tokval(parser); @@ -3665,7 +3780,7 @@ static bool parse_function_body(parser_t *parser, ast_value *var) return false; } - if (var->expression.flags & AST_FLAG_VARIADIC) { + if (!OPTS_FLAG(VARIADIC_ARGS) && var->expression.flags & AST_FLAG_VARIADIC) { if (parsewarning(parser, WARN_VARIADIC_FUNCTION, "variadic function with implementation will not be able to access additional parameters")) { @@ -3895,7 +4010,13 @@ static bool parse_function_body(parser_t *parser, ast_value *var) } vec_push(parser->functions, func); - if (var->expression.flags & AST_FLAG_VARIADIC) { + if (var->argcounter) { + ast_value *argc = ast_value_new(ast_ctx(var), var->argcounter, TYPE_FLOAT); + parser_addlocal(parser, argc->name, (ast_expression*)argc); + func->argc = argc; + } + + if (OPTS_FLAG(VARIADIC_ARGS) && var->expression.flags & AST_FLAG_VARIADIC) { char name[1024]; ast_value *varargs = ast_value_new(ast_ctx(var), "reserved:va_args", TYPE_ARRAY); varargs->expression.flags |= AST_FLAG_IS_VARARG; @@ -4074,6 +4195,9 @@ static ast_expression *array_field_setter_node( if (!subscript) return NULL; + subscript->expression.next = ast_type_copy(ast_ctx(subscript), (ast_expression*)subscript); + subscript->expression.vtype = TYPE_FIELD; + entfield = ast_entfield_new_force(ctx, (ast_expression*)entity, (ast_expression*)subscript, @@ -4894,7 +5018,7 @@ static bool parse_variable(parser_t *parser, ast_block *localblock, bool nofield goto cleanup; */ } - if (opts.standard == COMPILER_QCC && + if ((opts.standard == COMPILER_QCC || opts.standard == COMPILER_FTEQCC) && (old = parser_find_global(parser, var->name))) { parseerror(parser, "cannot declare a field and a global of the same name with -std=qcc");