free(d->child);
free(d);
- return 0;
+ return 1;
}
/*
- * The parser's bias towards considering things as functions whenever possible
- * makes nested parentheses tricky. (x) is considered to be part of a function
- * declarator until simplify_functions converts it. The problem is that
- * (((x))) is not valid as part of a function declarator, but it *is* valid
- * as an identifier enclosed 3 times in parentheses. This is complicated by
- * the fact that things like (((int))) are not valid anywhere.
+ * The main parser's bias towards considering things as functions whenever
+ * possible makes nested parentheses tricky. "(x)" is considered to be part
+ * of a function declarator until simplify_functions converts it. The problem
+ * is that "(((x)))" is not valid as part of a function declarator, but it _is_
+ * valid as either an identifier enclosed thrice in parentheses, or an abstract
+ * function declarator enclosed twice in parentheses.
+ *
+ * To avoid ambiguities, the main parser actually returns a function declarator
+ * for every pair of parentheses. The ones we need to look at consist of a
+ * single parameter with an empty specifier list (noting that every real
+ * function parameter will have at least one type specifier).
+ *
+ * There are two cases:
*
- * To avoid ambiguities, the parser actually emits a "function" declarator for
- * every pair of parentheses. The ones that can't reasonably be functions
- * consist of a single "parameter" with no declaration specifiers (note that
- * every valid function parameter will have at least one type specifier).
+ * - For (), the parser emits a parameter with a lone null declarator.
+ * This fake parameter simply gets deleted, leaving us with a normal
+ * function declarator with an empty identifier list.
*
- * This pass is to remove these fake functions from the parse tree. We take
- * care to avoid turning invalid things like ((int)) into valid things like
- * (int) by observing that the only valid function declarators that appear
- * in these "fake" parentheses are those that have a non-null child declarator
- * (for instance, int ((*)(int)) *or* those that will be eliminated by the
- * simplify_functions pass.
+ * - Otherwise, the parameter's outermost declarator is not null. The
+ * function itself is deleted, replaced in the parse tree with the
+ * fake parameter's declarator.
+ *
+ * Repeating until there no fake parameters, this reduction transforms, for
+ * example, "(((x)))" into "(x)", an abstract function declarator. The result
+ * is then subject to the function simplification step, which will turn "(x)"
+ * into x (declaring an identifier).
+ *
+ * The whole process is repeated until no more changes are made to the parse
+ * tree, or a syntax error is detected.
*/
-
static struct cdecl *fake_function_param(struct cdecl_declarator *d)
{
struct cdecl *param;
reduce_parentheses(struct cdecl_declarator **p, struct cdecl_declarator *d)
{
struct cdecl *param;
- int fake = 0;
-
- while ((param = fake_function_param(d))) {
- struct cdecl_declarator *decl = param->declarators;
- d->u.function.parameters = NULL;
-
- 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;
+
+ do {
+ d = *p;
+ while ((param = fake_function_param(d))) {
+ struct cdecl_declarator *decl = param->declarators;
+ d->u.function.parameters = NULL;
+
+ if (decl->type != CDECL_DECL_NULL) {
+ if (d->child->type != CDECL_DECL_NULL) {
+ /* Fake parameter on real function. */
+ d->u.function.parameters = param;
+ cdecl__errmsg(CDECL__EBADPARAM);
+ return -1;
+ }
+
+ param->declarators = d;
+ *p = d = decl;
}
- param->declarators = d;
- *p = d = decl;
- fake = 1;
+ cdecl__free(param);
}
-
- 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;
- }
+ } while (simplify_functions(p, d));
return 0;
}