Patch to clean up C parser

Joseph S. Myers jsm28@cam.ac.uk
Mon Jan 15 16:13:00 GMT 2001


When looking at fixing c/166, I found that the way the C grammer
handled attributes had so many shift/reduce conflicts that any trivial
change was liable to add more (which would then need individual
analysis).  To reduce this problem, the patch below gets rid of many
of these conflicts (reducing the %expect number from 53 to 22 for C).
The general form of the conflicts was that various forms of declarator
could begin with attributes, and what came before them could also end
with attributes.

Examination of the Bison debug output for the modified grammar
indicates that the remaining conflicts (though I didn't examine those
relating to error recovery, which are the main group after those
relating to attributes, particularly closely) are as already existed
in the grammar.  This patch shouldn't change how any programs are
parsed.  Some of the remaining conflicts - which I'll deal with later
- do affect how some programs get parsed.  Consider, for example, the
code

void bar (int (__attribute__((__mode__(SI))) int foo));

which GCC fails to parse.  After an open parenthesis in an abstract
declarator, there may be another abstract declarator, or a parameter
list; either of these may start with an attribute, and the token after
the attribute list will distinguish them.  However, because parmlist
has an action immediately after the open parenthesis, there is a
conflict between shifting the attribute (parsing as an abstract
declarator) and reducing an empty sequence of tokens (parsing as a
parameter list) - in the case above, shifting is wrong.  Fixing this
will require that attributes starting a parmlist move into the
parmlist production, before any action.

Bootstrapped with no regressions on i686-pc-linux-gnu.  OK to commit
to the mainline after 3.0 branches?

2001-01-16  Joseph S. Myers  <jsm28@cam.ac.uk>

	* c-parse.in: Remove many shift/reduce conflicts.  Update %expect
	values.
	(reserved_declspecs_noendattr, declmods_nonattr_nonattr,
	declmods_nonattr_attr, declmods_attr_nonattr, declmods_attr_attr,
	maybe_setattrs, absdcl_maybe_attribute): New syntax productions.
	(setattrs): Update comment.
	(datadecl, reserved_declspecs, declmods, initdecls,
	after_type_declarator, parm_declarator, notype_declarator,
	component_declarator, typename, absdcl1, parm, ivar_declarator,
	myparm): Adjust so that attributes cannot begin a declarator, but
	instead appear before declarators in the grammar where they
	couldn't already do so.

--- c-parse.in.orig	Sat Jan 13 17:31:32 2001
+++ c-parse.in	Mon Jan 15 18:45:26 2001
@@ -29,10 +29,10 @@ Boston, MA 02111-1307, USA.  */
    written by AT&T, but I have never seen it.  */

 ifobjc
-%expect 74
+%expect 38
 end ifobjc
 ifc
-%expect 53
+%expect 22
 end ifc

 %{
@@ -164,16 +164,18 @@ end ifc

 %type <ttype> identifier IDENTIFIER TYPENAME CONSTANT expr nonnull_exprlist exprlist
 %type <ttype> expr_no_commas cast_expr unary_expr primary string STRING
-%type <ttype> typed_declspecs reserved_declspecs
+%type <ttype> typed_declspecs reserved_declspecs reserved_declspecs_noendattr
 %type <ttype> typed_typespecs reserved_typespecquals
 %type <ttype> declmods typespec typespecqual_reserved
 %type <ttype> typed_declspecs_no_prefix_attr reserved_declspecs_no_prefix_attr
-%type <ttype> declmods_no_prefix_attr
+%type <ttype> declmods_no_prefix_attr declmods_nonattr_nonattr
+%type <ttype> declmods_nonattr_attr declmods_attr_nonattr declmods_attr_attr
 %type <ttype> SCSPEC TYPESPEC TYPE_QUAL nonempty_type_quals maybe_type_qual
 %type <ttype> initdecls notype_initdecls initdcl notype_initdcl
 %type <ttype> init maybeasm
 %type <ttype> asm_operands nonnull_asm_operands asm_operand asm_clobbers
 %type <ttype> maybe_attribute attributes attribute attribute_list attrib
+%type <ttype> maybe_setattrs
 %type <ttype> any_word extension

 %type <ttype> compstmt compstmt_start compstmt_nostart compstmt_primary_start
@@ -188,7 +190,7 @@ end ifc
 %type <ttype> component_decl components component_declarator
 %type <ttype> enumlist enumerator
 %type <ttype> struct_head union_head enum_head
-%type <ttype> typename absdcl absdcl1 type_quals
+%type <ttype> typename absdcl absdcl1 absdcl_maybe_attribute type_quals
 %type <ttype> xexpr parms parm identifiers

 %type <ttype> parmlist parmlist_1 parmlist_2
@@ -807,11 +809,11 @@ datadecls:
    attribute suffix, or function defn with attribute prefix on first old
    style parm.  */
 datadecl:
-	typed_declspecs_no_prefix_attr setspecs initdecls ';'
+	typed_declspecs_no_prefix_attr setspecs maybe_setattrs initdecls ';'
 		{ current_declspecs = TREE_VALUE (declspec_stack);
 		  prefix_attributes = TREE_PURPOSE (declspec_stack);
 		  declspec_stack = TREE_CHAIN (declspec_stack); }
-	| declmods_no_prefix_attr setspecs notype_initdecls ';'
+	| declmods_no_prefix_attr setspecs maybe_setattrs notype_initdecls ';'
 		{ current_declspecs = TREE_VALUE (declspec_stack);
 		  prefix_attributes = TREE_PURPOSE (declspec_stack);
 		  declspec_stack = TREE_CHAIN (declspec_stack); }
@@ -844,11 +846,25 @@ setspecs: /* empty */
 				     &current_declspecs, &prefix_attributes); }
 	;

-/* ??? Yuck.  See after_type_declarator.  */
+/* ??? Yuck.  See maybe_setattrs.  */
 setattrs: /* empty */
 		{ prefix_attributes = chainon (prefix_attributes, $<ttype>0); }
 	;

+maybe_setattrs: /* empty */
+		{ $$ = NULL_TREE; }
+	/* ??? Yuck.  setattrs is a quick hack.  We can't use
+	   prefix_attributes because $1 only applies to this
+	   declarator.  We assume setspecs has already been done.
+	   setattrs also avoids 5 reduce/reduce conflicts (otherwise multiple
+	   attributes could be recognized here or in `attributes').
+	   Properly attributes ought to be able to apply to any level of
+	   nested declarator, but the necessary compiler support isn't
+	   present, so the attributes apply to a declaration (which may be
+	   nested).  */
+	| attributes setattrs
+	;
+
 decl:
 	typed_declspecs setspecs initdecls ';'
 		{ current_declspecs = TREE_VALUE (declspec_stack);
@@ -886,7 +902,13 @@ typed_declspecs:
 		{ $$ = chainon ($3, tree_cons (NULL_TREE, $2, $1)); }
 	;

-reserved_declspecs:  /* empty */
+reserved_declspecs:
+	  reserved_declspecs_noendattr
+	| reserved_declspecs_noendattr attributes
+		{ $$ = tree_cons ($2, NULL_TREE, $1); }
+	;
+
+reserved_declspecs_noendattr:  /* empty */
 		{ $$ = NULL_TREE; }
 	| reserved_declspecs typespecqual_reserved
 		{ $$ = tree_cons (NULL_TREE, $2, $1); }
@@ -895,8 +917,6 @@ reserved_declspecs:  /* empty */
 		    warning ("`%s' is not at beginning of declaration",
 			     IDENTIFIER_POINTER ($2));
 		  $$ = tree_cons (NULL_TREE, $2, $1); }
-	| reserved_declspecs attributes
-		{ $$ = tree_cons ($2, NULL_TREE, $1); }
 	;

 typed_declspecs_no_prefix_attr:
@@ -924,16 +944,40 @@ reserved_declspecs_no_prefix_attr:
    Declspecs have a non-NULL TREE_VALUE, attributes do not.  */

 declmods:
-	  declmods_no_prefix_attr
+	  declmods_attr_attr
 		{ $$ = $1; }
-	| attributes
+	| declmods_nonattr_attr
+		{ $$ = $1; }
+	| declmods_attr_nonattr
+		{ $$ = $1; }
+	| declmods_nonattr_nonattr
+		{ $$ = $1; }
+	;
+
+declmods_attr_attr:
+	  attributes
 		{ $$ = tree_cons ($1, NULL_TREE, NULL_TREE); }
-	| declmods declmods_no_prefix_attr
-		{ $$ = chainon ($2, $1); }
-	| declmods attributes
+	| declmods_attr_nonattr attributes
+		{ $$ = tree_cons ($2, NULL_TREE, $1); }
+	;
+
+declmods_nonattr_attr:
+	  declmods_nonattr_nonattr attributes
 		{ $$ = tree_cons ($2, NULL_TREE, $1); }
 	;

+declmods_attr_nonattr:
+	  declmods_attr_attr declmods_no_prefix_attr
+		{ $$ = chainon ($2, $1); }
+	;
+
+declmods_nonattr_nonattr:
+	  declmods_no_prefix_attr
+		{ $$ = $1; }
+	| declmods_nonattr_attr declmods_no_prefix_attr
+		{ $$ = chainon ($2, $1); }
+	;
+
 declmods_no_prefix_attr:
 	  TYPE_QUAL
 		{ $$ = tree_cons (NULL_TREE, $1, NULL_TREE);
@@ -1005,7 +1049,7 @@ typespecqual_reserved: TYPESPEC

 initdecls:
 	initdcl
-	| initdecls ',' initdcl
+	| initdecls ',' maybe_setattrs initdcl
 	;

 notype_initdecls:
@@ -1248,8 +1292,8 @@ declarator:
 /* A declarator that is allowed only after an explicit typespec.  */

 after_type_declarator:
-	  '(' after_type_declarator ')'
-		{ $$ = $2; }
+	  '(' maybe_setattrs after_type_declarator ')'
+		{ $$ = $3; }
 	| after_type_declarator '(' parmlist_or_identifiers  %prec '.'
 		{ $$ = build_nt (CALL_EXPR, $1, $3, NULL_TREE); }
 /*	| after_type_declarator '(' error ')'  %prec '.'
@@ -1261,13 +1305,8 @@ after_type_declarator:
 		{ $$ = build_nt (ARRAY_REF, $1, NULL_TREE); }
 	| '*' type_quals after_type_declarator  %prec UNARY
 		{ $$ = make_pointer_declarator ($2, $3); }
-	/* ??? Yuck.  setattrs is a quick hack.  We can't use
-	   prefix_attributes because $1 only applies to this
-	   declarator.  We assume setspecs has already been done.
-	   setattrs also avoids 5 reduce/reduce conflicts (otherwise multiple
-	   attributes could be recognized here or in `attributes').  */
-	| attributes setattrs after_type_declarator
-		{ $$ = $3; }
+	| '*' type_quals attributes setattrs after_type_declarator  %prec UNARY
+		{ $$ = make_pointer_declarator ($2, $5); }
 	| TYPENAME
 ifobjc
 	| OBJECTNAME
@@ -1298,13 +1337,8 @@ end ifc
 		{ $$ = build_nt (ARRAY_REF, $1, NULL_TREE); }
 	| '*' type_quals parm_declarator  %prec UNARY
 		{ $$ = make_pointer_declarator ($2, $3); }
-	/* ??? Yuck.  setattrs is a quick hack.  We can't use
-	   prefix_attributes because $1 only applies to this
-	   declarator.  We assume setspecs has already been done.
-	   setattrs also avoids 5 reduce/reduce conflicts (otherwise multiple
-	   attributes could be recognized here or in `attributes').  */
-	| attributes setattrs parm_declarator
-		{ $$ = $3; }
+	| '*' type_quals attributes setattrs parm_declarator  %prec UNARY
+		{ $$ = make_pointer_declarator ($2, $5); }
 	| TYPENAME
 	;

@@ -1317,10 +1351,12 @@ notype_declarator:
 /*	| notype_declarator '(' error ')'  %prec '.'
 		{ $$ = build_nt (CALL_EXPR, $1, NULL_TREE, NULL_TREE);
 		  poplevel (0, 0, 0); }  */
-	| '(' notype_declarator ')'
-		{ $$ = $2; }
+	| '(' maybe_setattrs notype_declarator ')'
+		{ $$ = $3; }
 	| '*' type_quals notype_declarator  %prec UNARY
 		{ $$ = make_pointer_declarator ($2, $3); }
+	| '*' type_quals attributes setattrs notype_declarator  %prec UNARY
+		{ $$ = make_pointer_declarator ($2, $5); }
 ifc
 	| notype_declarator '[' '*' ']'  %prec '.'
 		{ $$ = build_nt (ARRAY_REF, $1, NULL_TREE);
@@ -1332,13 +1368,6 @@ end ifc
 		{ $$ = build_nt (ARRAY_REF, $1, $3); }
 	| notype_declarator '[' ']'  %prec '.'
 		{ $$ = build_nt (ARRAY_REF, $1, NULL_TREE); }
-	/* ??? Yuck.  setattrs is a quick hack.  We can't use
-	   prefix_attributes because $1 only applies to this
-	   declarator.  We assume setspecs has already been done.
-	   setattrs also avoids 5 reduce/reduce conflicts (otherwise multiple
-	   attributes could be recognized here or in `attributes').  */
-	| attributes setattrs notype_declarator
-		{ $$ = $3; }
 	| IDENTIFIER
 	;

@@ -1497,13 +1526,13 @@ components:
 	;

 component_declarator:
-	  save_filename save_lineno declarator maybe_attribute
-		{ $$ = grokfield ($1, $2, $3, current_declspecs, NULL_TREE);
-		  decl_attributes ($$, $4, prefix_attributes); }
-	| save_filename save_lineno
+	  save_filename save_lineno maybe_setattrs declarator maybe_attribute
+		{ $$ = grokfield ($1, $2, $4, current_declspecs, NULL_TREE);
+		  decl_attributes ($$, $5, prefix_attributes); }
+	| save_filename save_lineno maybe_setattrs
 	  declarator ':' expr_no_commas maybe_attribute
-		{ $$ = grokfield ($1, $2, $3, current_declspecs, $5);
-		  decl_attributes ($$, $6, prefix_attributes); }
+		{ $$ = grokfield ($1, $2, $4, current_declspecs, $6);
+		  decl_attributes ($$, $7, prefix_attributes); }
 	| save_filename save_lineno ':' expr_no_commas maybe_attribute
 		{ $$ = grokfield ($1, $2, NULL_TREE, current_declspecs, $4);
 		  decl_attributes ($$, $5, prefix_attributes); }
@@ -1534,10 +1563,10 @@ enumerator:
 	;

 typename:
-	typed_typespecs absdcl
-		{ $$ = build_tree_list ($1, $2); }
-	| nonempty_type_quals absdcl
-		{ $$ = build_tree_list ($1, $2); }
+	typed_typespecs maybe_setattrs absdcl
+		{ $$ = build_tree_list ($1, $3); }
+	| nonempty_type_quals maybe_setattrs absdcl
+		{ $$ = build_tree_list ($1, $3); }
 	;

 absdcl:   /* an absolute declarator */
@@ -1546,6 +1575,24 @@ absdcl:   /* an absolute declarator */
 	| absdcl1
 	;

+absdcl_maybe_attribute:   /* absdcl maybe_attribute, but not just attributes */
+	/* empty */
+		{ $$ = build_tree_list (build_tree_list (current_declspecs,
+							 NULL_TREE),
+					build_tree_list (prefix_attributes,
+							 NULL_TREE)); }
+	| absdcl1
+		{ $$ = build_tree_list (build_tree_list (current_declspecs,
+							 $1),
+					build_tree_list (prefix_attributes,
+							 NULL_TREE)); }
+	| absdcl1 attributes
+		{ $$ = build_tree_list (build_tree_list (current_declspecs,
+							 $1),
+					build_tree_list (prefix_attributes,
+							 $2)); }
+	;
+
 nonempty_type_quals:
 	  TYPE_QUAL
 		{ $$ = tree_cons (NULL_TREE, $1, NULL_TREE); }
@@ -1561,11 +1608,13 @@ type_quals:
 	;

 absdcl1:  /* a nonempty absolute declarator */
-	  '(' absdcl1 ')'
-		{ $$ = $2; }
+	  '(' maybe_setattrs absdcl1 ')'
+		{ $$ = $3; }
 	  /* `(typedef)1' is `int'.  */
 	| '*' type_quals absdcl1  %prec UNARY
 		{ $$ = make_pointer_declarator ($2, $3); }
+	| '*' type_quals attributes setattrs absdcl1  %prec UNARY
+		{ $$ = make_pointer_declarator ($2, $5); }
 	| '*' type_quals  %prec UNARY
 		{ $$ = make_pointer_declarator ($2, NULL_TREE); }
 	| absdcl1 '(' parmlist  %prec '.'
@@ -1580,10 +1629,6 @@ absdcl1:  /* a nonempty absolute declara
 		{ $$ = build_nt (ARRAY_REF, NULL_TREE, $2); }
 	| '[' ']'  %prec '.'
 		{ $$ = build_nt (ARRAY_REF, NULL_TREE, NULL_TREE); }
-	/* ??? It appears we have to support attributes here, however
-	   using prefix_attributes is wrong.  */
-	| attributes setattrs absdcl1
-		{ $$ = $3; }
 	;

 /* A nonempty series of declarations and statements (possibly followed by
@@ -2138,11 +2183,8 @@ parm:
 		  current_declspecs = TREE_VALUE (declspec_stack);
 		  prefix_attributes = TREE_PURPOSE (declspec_stack);
 		  declspec_stack = TREE_CHAIN (declspec_stack); }
-	| typed_declspecs setspecs absdcl maybe_attribute
-		{ $$ = build_tree_list (build_tree_list (current_declspecs,
-							 $3),
-					build_tree_list (prefix_attributes,
-							 $4));
+	| typed_declspecs setspecs absdcl_maybe_attribute
+		{ $$ = $3;
 		  current_declspecs = TREE_VALUE (declspec_stack);
 		  prefix_attributes = TREE_PURPOSE (declspec_stack);
 		  declspec_stack = TREE_CHAIN (declspec_stack); }
@@ -2155,11 +2197,8 @@ parm:
 		  prefix_attributes = TREE_PURPOSE (declspec_stack);
 		  declspec_stack = TREE_CHAIN (declspec_stack); }

-	| declmods setspecs absdcl maybe_attribute
-		{ $$ = build_tree_list (build_tree_list (current_declspecs,
-							 $3),
-					build_tree_list (prefix_attributes,
-							 $4));
+	| declmods setspecs absdcl_maybe_attribute
+		{ $$ = $3;
 		  current_declspecs = TREE_VALUE (declspec_stack);
 		  prefix_attributes = TREE_PURPOSE (declspec_stack);
 		  declspec_stack = TREE_CHAIN (declspec_stack); }
@@ -2466,18 +2505,18 @@ ivars:
 	;

 ivar_declarator:
-	  declarator
+	  maybe_setattrs declarator
 		{
 		  $$ = add_instance_variable (objc_ivar_context,
 					      objc_public_flag,
-					      $1, current_declspecs,
+					      $2, current_declspecs,
 					      NULL_TREE);
                 }
-	| declarator ':' expr_no_commas
+	| maybe_setattrs declarator ':' expr_no_commas
 		{
 		  $$ = add_instance_variable (objc_ivar_context,
 					      objc_public_flag,
-					      $1, current_declspecs, $3);
+					      $2, current_declspecs, $4);
                 }
 	| ':' expr_no_commas
 		{
@@ -2668,11 +2707,8 @@ myparm:
 							 $1),
 					build_tree_list (prefix_attributes,
 							 $2)); }
-	| absdcl maybe_attribute
-		{ $$ = build_tree_list (build_tree_list (current_declspecs,
-							 $1),
-					build_tree_list (prefix_attributes,
-							 $2)); }
+	| absdcl_maybe_attribute
+		{ $$ = $1; }
 	;

 optparmlist:

-- 
Joseph S. Myers
jsm28@cam.ac.uk



More information about the Gcc-patches mailing list