ALLOC(ptr, sizeof (type)); \
*(ptr) = (type) { __VA_ARGS__ }; \
} while (0)
+
+/*
+ * With the postprocessing performed by fix-yytname.awk, all the symbol
+ * name strings can be used directly in error messages and there is no
+ * need for any string processing.
+ */
+#define yytnamerr(a, b) cdecl__strlcpy(a, b, (a) ? INT_MAX : 0)
%}
%code requires {
/* Magic tokens */
%token T_LEX_ERROR
-%token T_ENGLISH
%token <strval> T_IDENT "identifier"
%token <uintval> T_UINT "integer constant"
%type <decl> english english_declaration
%type <decl> english_parameter
-/*
- * Harmless shift/reduce conflicts in english_parameter. See comments below
- * for more details.
- */
-%expect 2
+/* Precedence declaration to avoid conflict in english_parameter; see below. */
+%right T_TYPE
+%right T_IDENT
%%
-input: T_ENGLISH english {
- *out = $2;
+input: english {
+ *out = $1;
} | declaration {
*out = $1;
};
| T_COMPLEX
| T_IMAGINARY
-typespec_tagged: T_STRUCT | T_UNION | T_ENUM
+typespec_tagged: T_STRUCT | T_UNION | T_ENUM | { $$ = CDECL_TYPE_IDENT; }
qualifier_simple: T_CONST
| T_RESTRICT
ALLOC_STRUCT($$, struct cdecl_declspec,
.type = $1,
.ident = $2);
-} | T_IDENT {
- ALLOC_STRUCT($$, struct cdecl_declspec,
- .type = CDECL_TYPE_IDENT,
- .ident = $1);
}
declspec_noid: declspec_notype | typespec_noid
$$ = $2;
}
-storage_func_specs: { $$ = NULL; } | declspec_simple storage_func_specs {
+/*
+ * We use a precedence declaration to prefer shifting an identifier
+ * over reducing this empty rule; see below.
+ */
+storage_func_specs: %prec T_TYPE { $$ = NULL; }
+storage_func_specs: declspec_simple storage_func_specs {
ALLOC_STRUCT($$, struct cdecl_declspec,
.type = $1,
.next = $2);
}
/*
- * There is a small shift/reduce conflict here. An unadorned identifier
- * as the first thing in the parameter might be a typedef name deep in the
- * first english_declaration (thus empty storage_func_specs and empty
- * english_declarator need to be reduced) or it might be the identifier
- * before the "as" (thus the identifier should be shifted).
+ * There is a shift/reduce conflict here when an identifier appears as the
+ * first token. The conflict is between shifting T_IDENT, or reducing the
+ * empty production for storage_func_specs (cf. english_declaration).
+ *
+ * - In either case, if we reduce, we won't match T_IDENT T_AS since the
+ * stack now has the extra storage_func_specs nonterminal symbol.
+ * - And if we shift, we won't match english_declaration since it is
+ * too late to add storage_func_specs to the stack.
*
- * The typedef name conflict is the only issue, so treating it as a special
- * case makes the shift harmless.
+ * The only valid input affected by the conflict is a simple type names,
+ * possibly followed by qualifiers. So the conflict is adequately resolved
+ * by shifting, so long as we have a special-case reduction to handle this.
*/
english_parameter: english_declaration | typedef_name_qual null_decl {
ALLOC_STRUCT($$, struct cdecl,