X-Git-Url: https://git.draconx.ca/gitweb/cdecl99.git/blobdiff_plain/a41aa156f28753613f38924fc856d3dc992cfc56..23bee8f66fbd14c308d3c509a59024768bc2feef:/src/parse-decl.c diff --git a/src/parse-decl.c b/src/parse-decl.c index 8f0bd38..3c60dd2 100644 --- a/src/parse-decl.c +++ b/src/parse-decl.c @@ -1,6 +1,6 @@ /* * Parse and validate C declarations. - * Copyright © 2011-2012, 2020-2021, 2023 Nick Bowler + * Copyright © 2011-2012, 2020-2021, 2023-2024 Nick Bowler * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -27,6 +27,8 @@ #include "scan.h" #include "errmsg.h" +static struct cdecl *fake_function_param(struct cdecl_declarator *); + /* * Allocate a "parse item", which is a union of several parse tree * structure types, together with a string buffer. The s_sz argument @@ -177,6 +179,36 @@ static bool valid_declspecs(struct cdecl *decl, bool top) return true; } +/* + * Find the tree pointer which leads to the parameter's leaf node. + * + * Return a null pointer if the traversal locates a syntactic element which + * prevents function reduction. This occurs if the leaf node declares an + * identifier, or for nontrivial fake function parameters (see below). + */ +static struct cdecl_declarator **leaf_pointer(struct cdecl *param) +{ + struct cdecl_declarator *d, **p = ¶m->declarators; + + if ((param = fake_function_param(param->declarators))) { + if (param->declarators->type != CDECL_DECL_NULL) + return NULL; /* e.g. int (x (*)) */ + } + + while ((d = *p)->child) { + p = &d->child; + + if (fake_function_param(d->child)) + return NULL; /* e.g. int (x (*)[][1]) */ + } + + if (d->type != CDECL_DECL_NULL) + return NULL; /* e.g. int (x y) */ + + return p; +} + + /* * The C grammar leaves ambiguous some cases where parentheses represent a * function declarator or just parentheses. The language uses additional @@ -201,13 +233,10 @@ static bool valid_declspecs(struct cdecl *decl, bool top) static struct cdecl_declarator *reduce_function(struct cdecl *param) { - struct cdecl_declarator *d, **p = ¶m->declarators; struct parse_item *spec = (void *)param->specifiers; + struct cdecl_declarator *d, **p; - while ((d = *p)->child) - p = &d->child; - - if (d->type != CDECL_DECL_NULL) + if (!(p = leaf_pointer(param))) return NULL; /* @@ -260,7 +289,7 @@ simplify_functions(struct cdecl_declarator **p, struct cdecl_declarator *d) new = reduce_function(d->u.function.parameters); if (!new) - return 0; /* e.g. int (foo bar) */ + return 0; *p = new; free(d);