]> git.draconx.ca Git - cdecl99.git/blobdiff - src/parse-decl.c
libcdecl: Fix parsing of int (x(*)()) etc.
[cdecl99.git] / src / parse-decl.c
index 8f0bd388a1bcad91f83b23a4676e16652e2ccee8..3c60dd267156580e474f04ee077e8af8af902cdf 100644 (file)
@@ -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 = &param->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 = &param->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);