]> git.draconx.ca Git - cdecl99.git/blobdiff - src/parse.y
Solve Bison conflicts using precedence declarations.
[cdecl99.git] / src / parse.y
index 1542c0904e5bea5320ec864646fcfd4ddb63bd64..ec7ea1b74b5e78f1738a240c84b459f39e051575 100644 (file)
        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 {
@@ -181,7 +188,6 @@ static struct cdecl *insert_identifier(struct cdecl *decl, char *ident)
 
 /* Magic tokens */
 %token T_LEX_ERROR
-%token T_ENGLISH
 
 %token <strval> T_IDENT "identifier"
 %token <uintval> T_UINT "integer constant"
@@ -259,16 +265,14 @@ static struct cdecl *insert_identifier(struct cdecl *decl, char *ident)
 %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;
 };
@@ -343,7 +347,7 @@ typespec_simple: T_VOID
        | 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
@@ -365,10 +369,6 @@ typespec: typespec_noid | typespec_tagged T_IDENT {
        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
@@ -458,7 +458,12 @@ english: T_DECLARE T_IDENT T_AS english_declaration {
        $$ = $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);
@@ -537,14 +542,18 @@ null_decl: {
 }
 
 /*
- * 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,