]> git.draconx.ca Git - cdecl99.git/blobdiff - src/parse-decl.c
libcdecl: Combine several postprocessing steps into one.
[cdecl99.git] / src / parse-decl.c
index 0f660295e6963d3aaeeccc5e5dc8f3cc081c4267..f156ba9f0052c23146cc2147f4b91b4f29b871a2 100644 (file)
@@ -312,119 +312,118 @@ reduce_parentheses(struct cdecl_declarator **p, struct cdecl_declarator *d)
 }
 
 /*
- * Function parameters and return types have a few restrictions that are
- * really easy to check in comparison to the above absurdity.
+ * Returns nonzero iff the given specifier list contains a specifier
+ * of the indicated type.
  */
-static int
-check_parameters(struct cdecl_declarator **p, struct cdecl_declarator *d)
+static int have_specifier(struct cdecl_declspec *s, unsigned type)
 {
-       struct cdecl_declspec *spec;
-       struct cdecl *param;
-
-       if (d->type != CDECL_DECL_FUNCTION)
-               return 0;
-
-       for (param = d->u.function.parameters; param; param = param->next) {
-               if (!valid_declspecs(param, false))
-                       return -1;
-
-               /* Check for "void" function parameters as a special case. */
-               for (spec = param->specifiers; spec; spec = spec->next) {
-                       if (param->declarators->type != CDECL_DECL_NULL)
-                               continue;
-                       if (spec->type != CDECL_TYPE_VOID)
-                               continue;
-
-                       if (spec != param->specifiers || spec->next != NULL) {
-                               cdecl__errmsg(CDECL__EVOIDPARAM);
-                               return -1;
-                       } else if (d->u.function.parameters->next) {
-                               cdecl__errmsg(CDECL__EVOIDPARAM);
-                               return -1;
-                       } else if (d->u.function.variadic) {
-                               cdecl__errmsg(CDECL__EVOIDPARAM);
-                               return -1;
-                       }
-               }
-       }
-
+       for (; s; s = s->next)
+               if (s->type == type)
+                       return 1;
        return 0;
 }
 
 /*
- * Functions cannot return arrays or functions.  Since the parse tree is
- * "inside-out", we need to look for functions as the child declarator.
+ * Check syntax restrictions on a function declarator's child declarator.
+ * That is, "pointer to function", "array of function" and "function
+ * returning function".
+ *
+ * Returns -1 if the declaration is invalid, or 0 otherwise.
  */
-static int
-check_rettypes(struct cdecl_declarator **p, struct cdecl_declarator *d)
+static int check_function_child(struct cdecl_declarator *d)
 {
-       if (!d->child || d->child->type != CDECL_DECL_FUNCTION)
-               return 0;
+       struct cdecl_pointer *ptr;
 
        switch (d->type) {
+       case CDECL_DECL_POINTER:
+               ptr = &d->u.pointer;
+               if (have_specifier(ptr->qualifiers, CDECL_QUAL_RESTRICT)) {
+                       /* pointer to function cannot be restrict qualified. */
+                       cdecl__errmsg(CDECL__ERESTRICTFUNC);
+                       return -1;
+               }
+               return 0;
        case CDECL_DECL_FUNCTION:
+               /* function returning function is never allowed. */
                cdecl__errmsg(CDECL__ERETFUNC);
                return -1;
        case CDECL_DECL_ARRAY:
-               cdecl__errmsg(CDECL__ERETARRAY);
+               /* array of function is never allowed. */
+               cdecl__errmsg(CDECL__EFUNCARRAY);
                return -1;
        }
 
        return 0;
 }
 
-static int
-check_arrays(struct cdecl_declarator **p, struct cdecl_declarator *d)
+/*
+ * Check a function parameter declaration for validity, which means it has a
+ * valid combination of declaration specifiers and, if it is a void parameter,
+ * that it is the one special case where this is allowed.
+ *
+ * Returns -1 if the declaration is invalid, or 0 otherwise.
+ */
+static int check_function_param(struct cdecl_function *f, struct cdecl *param)
 {
-       if (!d->child || d->child->type != CDECL_DECL_ARRAY)
-               return 0;
-
-       switch (d->type) {
-       case CDECL_DECL_FUNCTION:
-               cdecl__errmsg(CDECL__EFUNCARRAY);
+       if (!valid_declspecs(param, false))
                return -1;
+
+       /* Check for "void" function parameters as a special case. */
+       if (param->declarators->type == CDECL_DECL_NULL
+           && have_specifier(param->specifiers, CDECL_TYPE_VOID))
+       {
+               struct cdecl *fp = f->parameters;
+
+               if (f->variadic || fp->next || fp->specifiers->next) {
+                       cdecl__errmsg(CDECL__EVOIDPARAM);
+                       return -1;
+               }
        }
 
        return 0;
 }
 
-static int
-normalize_specs(struct cdecl_declarator **p, struct cdecl_declarator *d)
+/*
+ * Normalize the specifier lists for function parameters, and then check the
+ * function declarator for validity.
+ *
+ * Returns -1 if the declaration is invalid, or 0 otherwise.
+ */
+static int postproc_function(struct cdecl_declarator *d)
 {
-       struct cdecl_function *func;
-       struct cdecl_pointer *ptr;
+       struct cdecl_function *func = &d->u.function;
+       struct cdecl *param;
+       int rc;
 
-       switch (d->type) {
-       case CDECL_DECL_POINTER:
-               ptr = &d->u.pointer;
-               ptr->qualifiers = cdecl__normalize_specs(ptr->qualifiers);
-               break;
-       case CDECL_DECL_FUNCTION:
-               func = &d->u.function;
-               for (struct cdecl *i = func->parameters; i; i = i->next)
-                       i->specifiers = cdecl__normalize_specs(i->specifiers);
-               break;
+       for (param = func->parameters; param; param = param->next) {
+               param->specifiers = cdecl__normalize_specs(param->specifiers);
+
+               if ((rc = check_function_param(func, param)) < 0)
+                       return rc;
        }
 
-       return 0;
+       return check_function_child(d->child);
 }
 
 static int
-check_qualifiers(struct cdecl_declarator **p, struct cdecl_declarator *d)
+postproc_common(struct cdecl_declarator **p, struct cdecl_declarator *d)
 {
-       struct cdecl_declspec *spec;
        struct cdecl_pointer *ptr;
 
-       if (!d->child || d->child->type != CDECL_DECL_POINTER)
+       switch (d->type) {
+       case CDECL_DECL_POINTER:
+               ptr = &d->u.pointer;
+               ptr->qualifiers = cdecl__normalize_specs(ptr->qualifiers);
                return 0;
-
-       ptr = &d->child->u.pointer;
-       for (spec = ptr->qualifiers; spec; spec = spec->next) {
-               if (spec->type == CDECL_QUAL_RESTRICT
-                   && d->type == CDECL_DECL_FUNCTION) {
-                       cdecl__errmsg(CDECL__ERESTRICTFUNC);
+       case CDECL_DECL_FUNCTION:
+               return postproc_function(d);
+       case CDECL_DECL_ARRAY:
+               if (d->child && d->child->type == CDECL_DECL_FUNCTION) {
+                       /* function returning array is never allowed. */
+                       cdecl__errmsg(CDECL__ERETARRAY);
                        return -1;
                }
+               return 0;
        }
 
        return 0;
@@ -517,15 +516,7 @@ static int do_postprocess(struct cdecl *decl, int english_mode)
                                return 0;
                }
 
-               if (forall_declarators(i, check_parameters) < 0)
-                       return 0;
-               if (forall_declarators(i, check_rettypes) < 0)
-                       return 0;
-               if (forall_declarators(i, check_arrays) < 0)
-                       return 0;
-               if (forall_declarators(i, normalize_specs) < 0)
-                       return 0;
-               if (forall_declarators(i, check_qualifiers) < 0)
+               if (forall_declarators(i, postproc_common) < 0)
                        return 0;
 
                if (!valid_declspecs(i, true))