From: Wolfgang Bumiller Date: Fri, 18 Oct 2013 14:28:28 +0000 (+0200) Subject: type and argument parsing improved to handle the field/vararg ambiguity; tests added X-Git-Tag: 0.3.5~1^2~7^2 X-Git-Url: https://git.rm.cloudns.org/?a=commitdiff_plain;h=3988aae73e889975892af76920d1d16177de56b8;p=xonotic%2Fgmqcc.git type and argument parsing improved to handle the field/vararg ambiguity; tests added --- diff --git a/parser.c b/parser.c index c7257bb..b503435 100644 --- a/parser.c +++ b/parser.c @@ -44,7 +44,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 ast_value *parse_typename(parser_t *parser, ast_value **storebase, ast_value *cached_typedef, bool *is_vararg); static void parseerror(parser_t *parser, const char *fmt, ...) { @@ -1422,7 +1422,7 @@ static ast_expression* parse_vararg_do(parser_t *parser) return NULL; } - typevar = parse_typename(parser, NULL, NULL); + typevar = parse_typename(parser, NULL, NULL, NULL); if (!typevar) { ast_unref(idx); return NULL; @@ -4505,7 +4505,6 @@ static bool parser_create_array_getter(parser_t *parser, ast_value *array, const return parser_create_array_getter_impl(parser, array); } -static ast_value *parse_typename(parser_t *parser, ast_value **storebase, ast_value *cached_typedef); static ast_value *parse_parameter_list(parser_t *parser, ast_value *var) { lex_ctx_t ctx; @@ -4531,6 +4530,8 @@ static ast_value *parse_parameter_list(parser_t *parser, ast_value *var) /* parse variables until we hit a closing paren */ while (parser->tok != ')') { + bool is_varargs = false; + if (!first) { /* there must be commas between them */ if (parser->tok != ',') { @@ -4544,10 +4545,13 @@ static ast_value *parse_parameter_list(parser_t *parser, ast_value *var) } first = false; - if (parser->tok == TOKEN_DOTS) { + param = parse_typename(parser, NULL, NULL, &is_varargs); + if (!param && !is_varargs) + goto on_error; + if (is_varargs) { /* '...' indicates a varargs function */ variadic = true; - if (!parser_next(parser) || (parser->tok != ')' && parser->tok != TOKEN_IDENT)) { + if (parser->tok != ')' && parser->tok != TOKEN_IDENT) { parseerror(parser, "`...` must be the last parameter of a variadic function declaration"); goto on_error; } @@ -4558,13 +4562,7 @@ static ast_value *parse_parameter_list(parser_t *parser, ast_value *var) goto on_error; } } - } - else - { - /* for anything else just parse a typename */ - param = parse_typename(parser, NULL, NULL); - if (!param) - goto on_error; + } else { vec_push(params, param); if (param->expression.vtype >= TYPE_VARIANT) { char tname[1024]; /* typename is reserved in C++ */ @@ -4716,7 +4714,7 @@ static ast_value *parse_arraysize(parser_t *parser, ast_value *var) * void() foo(), bar * then the type-information 'void()' can be stored in 'storebase' */ -static ast_value *parse_typename(parser_t *parser, ast_value **storebase, ast_value *cached_typedef) +static ast_value *parse_typename(parser_t *parser, ast_value **storebase, ast_value *cached_typedef, bool *is_vararg) { ast_value *var, *tmp; lex_ctx_t ctx; @@ -4726,6 +4724,8 @@ static ast_value *parse_typename(parser_t *parser, ast_value **storebase, ast_va bool wasarray = false; size_t morefields = 0; + bool vararg = (parser->tok == TOKEN_DOTS); + ctx = parser_ctx(parser); /* types may start with a dot */ @@ -4749,6 +4749,7 @@ static ast_value *parse_typename(parser_t *parser, ast_value **storebase, ast_va morefields += 3; else break; + vararg = false; if (!parser_next(parser)) { parseerror(parser, "expected typename for field definition"); return NULL; @@ -4758,6 +4759,10 @@ static ast_value *parse_typename(parser_t *parser, ast_value **storebase, ast_va if (parser->tok == TOKEN_IDENT) cached_typedef = parser_find_typedef(parser, parser_tokval(parser), 0); if (!cached_typedef && parser->tok != TOKEN_TYPENAME) { + if (vararg && is_vararg) { + *is_vararg = true; + return NULL; + } parseerror(parser, "expected typename"); return NULL; } @@ -4878,7 +4883,7 @@ static bool parse_typedef(parser_t *parser) ast_value *typevar, *oldtype; ast_expression *old; - typevar = parse_typename(parser, NULL, NULL); + typevar = parse_typename(parser, NULL, NULL, NULL); if (!typevar) return false; @@ -5048,7 +5053,7 @@ static bool parse_variable(parser_t *parser, ast_block *localblock, bool nofield parseerror(parser, "`static` qualifier is not supported in global scope"); /* get the first complete variable */ - var = parse_typename(parser, &basetype, cached_typedef); + var = parse_typename(parser, &basetype, cached_typedef, NULL); if (!var) { if (basetype) ast_delete(basetype); diff --git a/tests/dots.qc b/tests/dots.qc new file mode 100644 index 0000000..ccca3f9 --- /dev/null +++ b/tests/dots.qc @@ -0,0 +1,27 @@ +entity self; +.float f; +..float fp; +...float fpp; + +void try(entity e, ...float pp) { + print("and: ", ftos( e.(e.(e.pp)) ), "\n"); +} + +typedef float Float; + +void try2(entity e, ...Float pp) { + print("and: ", ftos( e.(e.(e.pp)) ), "\n"); +} + +// whereas the varargs are tested in vararg tests + +void main() { + self = spawn(); + self.f = 123; + self.fp = f; + self.fpp = fp; + print(ftos( self.(self.fp) ), "\n"); + print(ftos( self.(self.(self.fpp)) ), "\n"); + try(self, fpp); + try2(self, fpp); +} diff --git a/tests/dots.tmpl b/tests/dots.tmpl new file mode 100644 index 0000000..e99ad95 --- /dev/null +++ b/tests/dots.tmpl @@ -0,0 +1,8 @@ +I: dots.qc +D: TOKEN_DOTS disambiguation +T: -execute +C: -std=fteqcc +M: 123 +M: 123 +M: and: 123 +M: and: 123