]> git.draconx.ca Git - cdecl99.git/blobdiff - src/parse-decl.c
cdecl99: Don't check blank lines if no history support.
[cdecl99.git] / src / parse-decl.c
index 0f660295e6963d3aaeeccc5e5dc8f3cc081c4267..3137859708b5745d24ec489309efd97a0edfdd69 100644 (file)
@@ -254,177 +254,170 @@ simplify_functions(struct cdecl_declarator **p, struct cdecl_declarator *d)
  * simplify_functions pass.
  */
 
-static int
-reduce_parentheses(struct cdecl_declarator **p, struct cdecl_declarator *d)
+static struct cdecl *fake_function_param(struct cdecl_declarator *d)
 {
        struct cdecl *param;
 
        if (d->type != CDECL_DECL_FUNCTION)
-               return 0;
+               return NULL;
 
        param = d->u.function.parameters;
-       if (param && param->specifiers == NULL) {
-               struct cdecl_declarator *decl;
-
-               assert(!param->next);
+       if (!param || param->specifiers)
+               return NULL;
 
-               decl = param->declarators;
-               if (decl->type == CDECL_DECL_NULL) {
-                       free(decl);
-                       free(param);
-                       d->u.function.parameters = NULL;
-                       return 0;
-               }
+       assert(!param->next);
+       return param;
+}
 
-               if (d->child->type != CDECL_DECL_NULL) {
-                       cdecl__errmsg(CDECL__EBADPARAM);
-                       return -1;
-               }
+static int
+reduce_parentheses(struct cdecl_declarator **p, struct cdecl_declarator *d)
+{
+       struct cdecl *param;
+       int fake = 0;
 
-               free(d->child);
-               free(param);
-               free(d);
-               *p = decl;
+       while ((param = fake_function_param(d))) {
+               struct cdecl_declarator *decl = param->declarators;
+               d->u.function.parameters = NULL;
 
-               /*
-                * We may have replaced d with another fake function which
-                * also needs to be eliminated.
-                */
-               if (reduce_parentheses(p, decl) < 0)
-                       return -1;
+               if (decl->type != CDECL_DECL_NULL) {
+                       if (d->child->type != CDECL_DECL_NULL) {
+                               /* Found fake parameter on real function. */
+                               d->u.function.parameters = param;
+                               cdecl__errmsg(CDECL__EBADPARAM);
+                               return -1;
+                       }
 
-               /*
-                * If the remaining declarator is a function, make sure it's
-                * valid by checking its reducibility.
-                */
-               decl = *p;
-               if (decl->type == CDECL_DECL_FUNCTION
-                   && decl->child->type == CDECL_DECL_NULL
-                   && !function_is_reducible(decl)) {
-                       cdecl__errmsg(CDECL__EMANYPAREN);
-                       return -1;
+                       param->declarators = d;
+                       *p = d = decl;
+                       fake = 1;
                }
 
-               return 0;
+               cdecl__free(param);
+       }
+
+       simplify_functions(p, d);
+       if (fake && (*p)->type == CDECL_DECL_FUNCTION) {
+               /* Started with a fake function but ended with a real one. */
+               cdecl__errmsg(CDECL__EMANYPAREN);
+               return -1;
        }
 
        return 0;
 }
 
 /*
- * 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;
@@ -513,26 +506,16 @@ static int do_postprocess(struct cdecl *decl, int english_mode)
                if (!english_mode) {
                        if (forall_declarators(i, reduce_parentheses) < 0)
                                return 0;
-                       if (forall_declarators(i, simplify_functions) < 0)
-                               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))
                        return 0;
 
-               if (cdecl_is_abstract(i->declarators)
-                   && (i != decl || i->next)) {
+               if (decl->next && cdecl_is_abstract(i->declarators)) {
+                       /* Abstract full declarators: there can only be one. */
                        cdecl__errmsg(CDECL__EDECLTYPE);
                        return 0;
                }