}
%{
+static void yyerror(YYLTYPE *, yyscan_t, struct cdecl **, const char *);
static void free_decl(struct cdecl *);
static void free_declspec(struct cdecl_declspec *x)
free_decl(decl);
}
-static void
-yyerror(YYLTYPE *loc, yyscan_t scanner, struct cdecl **out, const char *err)
+/*
+ * Join two declaration specifier lists into a single list, with "a" being the
+ * head of the new list.
+ *
+ * The list "a" is assumed to be nonempty.
+ */
+static void join_specs(struct cdecl_declspec *a, struct cdecl_declspec *b)
{
- if (strstr(err, "T_LEX_ERROR"))
- return;
-
- cdecl__err(CDECL_ENOPARSE, "%s", err);
+ while (a->next)
+ a = a->next;
+ a->next = b;
}
%}
declaration: declspecs declarators semi {
$$ = $2;
-
- for (struct cdecl *i = $$; i; i = i->next)
- i->specifiers = $1;
+ $$->specifiers = $1;
};
+/*
+ * We support parsing declarations using arbitrary identifiers as type
+ * specifiers (a la C typedef). To avoid confusion with identifiers that
+ * may also be used as declarators, note the following:
+ *
+ * (a) Every valid C declaration must have at least one type specifier, and
+ * (b) Valid declarations with typedef names have exactly one type specifier.
+ *
+ * So the rule applied when parsing specifiers is: an identifier is a type
+ * specifier only if we have not yet seen any type specifiers whatsoever
+ * (within one declaration specifier list).
+ *
+ * Treating identifiers as type specifiers by default can lead to strange and
+ * unexpected parses; libcdecl applies a simplification step to the resulting
+ * parse tree afterwards.
+ */
declspecs: declspec_notype declspecs {
$$ = $1;
$$->next = $2;
* together three different specifiers lists.
*/
post_specs: qualifiers typespec type_qual_specs {
+ $2->next = $3;
+ join_specs($2, $1);
$$ = $2;
- $$->next = $1;
- for (struct cdecl_declspec *s = $$; s; s = s->next) {
- if (!s->next) {
- s->next = $3;
- break;
- }
- }
}
english_declaration: storage_func_specs english_declarator post_specs {
+ join_specs($3, $1);
ALLOC_STRUCT($$, struct cdecl,
.specifiers = $3,
.declarators = $2);
-
- for (struct cdecl_declspec *s = $$->specifiers; s; s = s->next) {
- if (!s->next) {
- s->next = $1;
- break;
- }
- }
}
english_declarator: {
{
return yytname[YYTRANSLATE(token)];
}
+
+static void
+yyerror(YYLTYPE *loc, yyscan_t scanner, struct cdecl **out, const char *err)
+{
+ if (strstr(err, yytname[YYTRANSLATE(T_LEX_ERROR)]))
+ return;
+
+ cdecl__err(CDECL_ENOPARSE, "%s", err);
+}