OSDN Git Service

Remove CYGNUS LOCAL tags.
[pf3gnuchains/gcc-fork.git] / gcc / c-parse.in
index 06fd36f..11db40f 100644 (file)
@@ -1,5 +1,5 @@
 /* YACC parser for C syntax and for Objective C.  -*-c-*-
-   Copyright (C) 1987, 1988, 1989, 1992 Free Software Foundation, Inc.
+   Copyright (C) 1987, 88, 89, 92-5, 1996 Free Software Foundation, Inc.
 
 This file is part of GNU CC.
 
@@ -15,7 +15,8 @@ GNU General Public License for more details.
 
 You should have received a copy of the GNU General Public License
 along with GNU CC; see the file COPYING.  If not, write to
-the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.  */
+the Free Software Foundation, 59 Temple Place - Suite 330,
+Boston, MA 02111-1307, USA.  */
 
 /* This file defines the grammar of C and that of Objective C.
    ifobjc ... end ifobjc  conditionals contain code for Objective C only.
@@ -24,26 +25,36 @@ the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.  */
    c-parse.y and into objc-parse.y.  */
 
 /* To whomever it may concern: I have heard that such a thing was once
-written by AT&T, but I have never seen it.  */
+   written by AT&T, but I have never seen it.  */
 
 ifobjc
-%expect 20
+%expect 52
 end ifobjc
 ifc
-%expect 8
+%expect 34
 
-/* These are the 8 conflicts you should get in parse.output;
+/* These are the 23 conflicts you should get in parse.output;
    the state numbers may vary if minor changes in the grammar are made.
 
-State 41 contains 1 shift/reduce conflict.  (Two ways to recover from error.)
-State 92 contains 1 shift/reduce conflict.  (Two ways to recover from error.)
-State 99 contains 1 shift/reduce conflict.  (Two ways to recover from error.)
+State 42 contains 1 shift/reduce conflict.  (Two ways to parse ATTRIBUTE.)
+State 44 contains 1 shift/reduce conflict.  (Two ways to recover from error.)
 State 103 contains 1 shift/reduce conflict.  (Two ways to recover from error.)
-State 119 contains 1 shift/reduce conflict.  (See comment at component_decl.)
-State 183 contains 1 shift/reduce conflict.  (Two ways to recover from error.)
-State 193 contains 1 shift/reduce conflict.  (Two ways to recover from error.)
-State 199 contains 1 shift/reduce conflict.  (Two ways to recover from error.)
-*/
+State 110 contains 1 shift/reduce conflict.  (Two ways to parse ATTRIBUTE.)
+State 111 contains 1 shift/reduce conflict.  (Two ways to recover from error.)
+State 115 contains 1 shift/reduce conflict.  (Two ways to recover from error.)
+State 132 contains 1 shift/reduce conflict.  (See comment at component_decl.)
+State 180 contains 1 shift/reduce conflict.  (Two ways to parse ATTRIBUTE.)
+State 194 contains 2 shift/reduce conflict.  (Four ways to parse this.)
+State 202 contains 1 shift/reduce conflict.  (Two ways to recover from error.)
+State 214 contains 1 shift/reduce conflict.  (Two ways to recover from error.)
+State 220 contains 1 shift/reduce conflict.  (Two ways to recover from error.)
+State 304 contains 2 shift/reduce conflicts.  (Four ways to parse this.)
+State 335 contains 2 shift/reduce conflicts.  (Four ways to parse this.)
+State 347 contains 1 shift/reduce conflict.  (Two ways to parse ATTRIBUTES.)
+State 352 contains 1 shift/reduce conflict.  (Two ways to parse ATTRIBUTES.)
+State 383 contains 2 shift/reduce conflicts.  (Four ways to parse this.)
+State 434 contains 2 shift/reduce conflicts.  (Four ways to parse this.)  */
+
 end ifc
 
 %{
@@ -92,7 +103,7 @@ void yyerror ();
 %start program
 
 %union {long itype; tree ttype; enum tree_code code;
-       char *filename; int lineno; }
+       char *filename; int lineno; int ends_in_label; }
 
 /* All identifiers that are not reserved words
    and are not declared typedefs in the current block */
@@ -129,7 +140,7 @@ void yyerror ();
 /* the reserved words */
 /* SCO include files test "ASM", so use something else. */
 %token SIZEOF ENUM STRUCT UNION IF ELSE WHILE DO FOR SWITCH CASE DEFAULT
-%token BREAK CONTINUE RETURN GOTO ASM_KEYWORD TYPEOF ALIGNOF ALIGN
+%token BREAK CONTINUE RETURN GOTO ASM_KEYWORD TYPEOF ALIGNOF
 %token ATTRIBUTE EXTENSION LABEL
 %token REALPART IMAGPART
 
@@ -178,7 +189,8 @@ void yyerror ();
 %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 attribute_list attrib
+%type <ttype> maybe_attribute attributes attribute attribute_list attrib
+%type <ttype> any_word
 
 %type <ttype> compstmt
 
@@ -198,6 +210,8 @@ void yyerror ();
 
 %type <itype> setspecs
 
+%type <ends_in_label> lineno_stmt_or_label lineno_stmt_or_labels stmt_or_label
+
 %type <filename> save_filename
 %type <lineno> save_lineno
 \f
@@ -210,7 +224,8 @@ ifobjc
 %type <ttype> keywordexpr keywordarglist keywordarg
 %type <ttype> myparms myparm optparmlist reservedwords objcselectorexpr
 %type <ttype> selectorarg keywordnamelist keywordname objcencodeexpr
-%type <ttype> objc_string protocolrefs identifier_list objcprotocolexpr
+%type <ttype> objc_string non_empty_protocolrefs protocolrefs identifier_list objcprotocolexpr
+
 %type <ttype> CLASSNAME OBJC_STRING OBJECTNAME
 end ifobjc
 \f
@@ -225,8 +240,9 @@ static int if_stmt_line;
 
 /* List of types and structure classes of the current declaration.  */
 static tree current_declspecs;
+static tree prefix_attributes = NULL_TREE;
 
-/* Stack of saved values of current_declspecs.  */
+/* Stack of saved values of current_declspecs and prefix_attributes.  */
 static tree declspec_stack;
 
 /* 1 if we explained undeclared var errors.  */
@@ -256,9 +272,7 @@ extern void yyprint ();
 program: /* empty */
                { if (pedantic)
                    pedwarn ("ANSI C forbids an empty source file");
-ifobjc
-                 objc_finish ();
-end ifobjc
+                 finish_file ();
                }
        | extdefs
                {
@@ -266,9 +280,7 @@ end ifobjc
                     get us back to the global binding level.  */
                  while (! global_bindings_p ())
                    poplevel (0, 0, 0);
-ifobjc
-                 objc_finish ();
-end ifobjc
+                 finish_file ();
                }
        ;
 
@@ -302,11 +314,22 @@ datadef:
                { if (pedantic)
                    error ("ANSI C forbids data definition with no type or storage class");
                  else if (!flag_traditional)
-                   warning ("data definition has no type or storage class"); }
+                   warning ("data definition has no type or storage class"); 
+
+                 current_declspecs = TREE_VALUE (declspec_stack);
+                 prefix_attributes = TREE_PURPOSE (declspec_stack);
+                 declspec_stack = TREE_CHAIN (declspec_stack);
+                 resume_momentary ($1); }
         | declmods setspecs notype_initdecls ';'
-         {}
+               { current_declspecs = TREE_VALUE (declspec_stack);
+                 prefix_attributes = TREE_PURPOSE (declspec_stack);
+                 declspec_stack = TREE_CHAIN (declspec_stack);
+                 resume_momentary ($2); }
        | typed_declspecs setspecs initdecls ';'
-         {}
+               { current_declspecs = TREE_VALUE (declspec_stack);
+                 prefix_attributes = TREE_PURPOSE (declspec_stack);
+                 declspec_stack = TREE_CHAIN (declspec_stack);
+                 resume_momentary ($2);  }
         | declmods ';'
          { pedwarn ("empty declaration"); }
        | typed_declspecs ';'
@@ -320,35 +343,59 @@ datadef:
 \f
 fndef:
          typed_declspecs setspecs declarator
-               { if (! start_function ($1, $3, 0))
+               { if (! start_function ($1, $3, prefix_attributes,
+                                       NULL_TREE, 0))
                    YYERROR1;
                  reinit_parse_for_function (); }
          xdecls
                { store_parm_decls (); }
          compstmt_or_error
-               { finish_function (0); }
+               { finish_function (0); 
+                 current_declspecs = TREE_VALUE (declspec_stack);
+                 prefix_attributes = TREE_PURPOSE (declspec_stack);
+                 declspec_stack = TREE_CHAIN (declspec_stack);
+                 resume_momentary ($2); }
        | typed_declspecs setspecs declarator error
-               { }
+               { current_declspecs = TREE_VALUE (declspec_stack);
+                 prefix_attributes = TREE_PURPOSE (declspec_stack);
+                 declspec_stack = TREE_CHAIN (declspec_stack);
+                 resume_momentary ($2); }
        | declmods setspecs notype_declarator
-               { if (! start_function ($1, $3, 0))
+               { if (! start_function ($1, $3, prefix_attributes,
+                                       NULL_TREE, 0))
                    YYERROR1;
                  reinit_parse_for_function (); }
          xdecls
                { store_parm_decls (); }
          compstmt_or_error
-               { finish_function (0); }
+               { finish_function (0); 
+                 current_declspecs = TREE_VALUE (declspec_stack);
+                 prefix_attributes = TREE_PURPOSE (declspec_stack);
+                 declspec_stack = TREE_CHAIN (declspec_stack);
+                 resume_momentary ($2); }
        | declmods setspecs notype_declarator error
-               { }
+               { current_declspecs = TREE_VALUE (declspec_stack);
+                 prefix_attributes = TREE_PURPOSE (declspec_stack);
+                 declspec_stack = TREE_CHAIN (declspec_stack);
+                 resume_momentary ($2); }
        | setspecs notype_declarator
-               { if (! start_function (NULL_TREE, $2, 0))
+               { if (! start_function (NULL_TREE, $2,
+                                       prefix_attributes, NULL_TREE, 0))
                    YYERROR1;
                  reinit_parse_for_function (); }
          xdecls
                { store_parm_decls (); }
          compstmt_or_error
-               { finish_function (0); }
+               { finish_function (0); 
+                 current_declspecs = TREE_VALUE (declspec_stack);
+                 prefix_attributes = TREE_PURPOSE (declspec_stack);
+                 declspec_stack = TREE_CHAIN (declspec_stack);
+                 resume_momentary ($1); }
        | setspecs notype_declarator error
-               { }
+               { current_declspecs = TREE_VALUE (declspec_stack);
+                 prefix_attributes = TREE_PURPOSE (declspec_stack);
+                 declspec_stack = TREE_CHAIN (declspec_stack);
+                 resume_momentary ($1); }
        ;
 
 identifier:
@@ -410,6 +457,8 @@ unary_expr:
        /* Refer to the address of a label as a pointer.  */
        | ANDAND identifier
                { tree label = lookup_label ($2);
+                 if (pedantic)
+                   pedwarn ("ANSI C forbids `&&'");
                  if (label == 0)
                    $$ = null_pointer_node;
                  else
@@ -531,8 +580,6 @@ expr_no_commas:
 primary:
        IDENTIFIER
                {
-                 tree context;
-
                  $$ = lastiddecl;
                  if (!$$ || $$ == error_mark_node)
                    {
@@ -806,7 +853,7 @@ string:
        ;
 
 ifobjc
-/* Produces an OBJC_STRING_CST with prehaps more OBJC_STRING_CSTs chained
+/* Produces an OBJC_STRING_CST with perhaps more OBJC_STRING_CSTs chained
    onto it.  */
 objc_string:
          OBJC_STRING
@@ -843,10 +890,12 @@ datadecls:
 datadecl:
        typed_declspecs setspecs initdecls ';'
                { current_declspecs = TREE_VALUE (declspec_stack);
+                 prefix_attributes = TREE_PURPOSE (declspec_stack);
                  declspec_stack = TREE_CHAIN (declspec_stack);
                  resume_momentary ($2); }
        | declmods setspecs notype_initdecls ';'
-               { current_declspecs = TREE_VALUE (declspec_stack);
+               { current_declspecs = TREE_VALUE (declspec_stack);      
+                 prefix_attributes = TREE_PURPOSE (declspec_stack);
                  declspec_stack = TREE_CHAIN (declspec_stack);
                  resume_momentary ($2); }
        | typed_declspecs ';'
@@ -879,26 +928,36 @@ decls:
 setspecs: /* empty */
                { $$ = suspend_momentary ();
                  pending_xref_error ();
-                 declspec_stack = tree_cons (NULL_TREE, current_declspecs,
+                 declspec_stack = tree_cons (prefix_attributes,
+                                             current_declspecs,
                                              declspec_stack);
-                 current_declspecs = $<ttype>0; }
+                 current_declspecs = $<ttype>0; 
+                 prefix_attributes = NULL_TREE; }
+       ;
+
+setattrs: /* empty */
+               { prefix_attributes = chainon (prefix_attributes, $<ttype>0); }
        ;
 
 decl:
        typed_declspecs setspecs initdecls ';'
                { current_declspecs = TREE_VALUE (declspec_stack);
+                 prefix_attributes = TREE_PURPOSE (declspec_stack);
                  declspec_stack = TREE_CHAIN (declspec_stack);
                  resume_momentary ($2); }
        | declmods setspecs notype_initdecls ';'
                { current_declspecs = TREE_VALUE (declspec_stack);
+                 prefix_attributes = TREE_PURPOSE (declspec_stack);
                  declspec_stack = TREE_CHAIN (declspec_stack);
                  resume_momentary ($2); }
        | typed_declspecs setspecs nested_function
                { current_declspecs = TREE_VALUE (declspec_stack);
+                 prefix_attributes = TREE_PURPOSE (declspec_stack);
                  declspec_stack = TREE_CHAIN (declspec_stack);
                  resume_momentary ($2); }
        | declmods setspecs notype_nested_function
                { current_declspecs = TREE_VALUE (declspec_stack);
+                 prefix_attributes = TREE_PURPOSE (declspec_stack);
                  declspec_stack = TREE_CHAIN (declspec_stack);
                  resume_momentary ($2); }
        | typed_declspecs ';'
@@ -983,6 +1042,11 @@ ifobjc
                { $$ = get_static_reference ($1, $2); }
        | OBJECTNAME protocolrefs
                { $$ = get_object_reference ($2); }
+
+/* Make "<SomeProtocol>" equivalent to "id <SomeProtocol>"
+   - nisse@lysator.liu.se */
+        | non_empty_protocolrefs
+                { $$ = get_object_reference ($1); }
 end ifobjc
        | TYPEOF '(' expr ')'
                { $$ = TREE_TYPE ($3); }
@@ -1018,97 +1082,85 @@ maybeasm:
 
 initdcl:
          declarator maybeasm maybe_attribute '='
-               { $<ttype>$ = start_decl ($1, current_declspecs, 1);
-                 decl_attributes ($<ttype>$, $3);
+               { $<ttype>$ = start_decl ($1, current_declspecs, 1,
+                                         $3, prefix_attributes);
                  start_init ($<ttype>$, $2, global_bindings_p ()); }
          init
 /* Note how the declaration of the variable is in effect while its init is parsed! */
                { finish_init ();
-                 decl_attributes ($<ttype>5, $3);
                  finish_decl ($<ttype>5, $6, $2); }
        | declarator maybeasm maybe_attribute
-               { tree d = start_decl ($1, current_declspecs, 0);
-                 decl_attributes (d, $3);
-                 finish_decl (d, NULL_TREE, $2); }
+               { tree d = start_decl ($1, current_declspecs, 0,
+                                      $3, prefix_attributes);
+                 finish_decl (d, NULL_TREE, $2); 
+                }
        ;
 
 notype_initdcl:
          notype_declarator maybeasm maybe_attribute '='
-               { $<ttype>$ = start_decl ($1, current_declspecs, 1);
-                 decl_attributes ($<ttype>$, $3);
+               { $<ttype>$ = start_decl ($1, current_declspecs, 1,
+                                         $3, prefix_attributes);
                  start_init ($<ttype>$, $2, global_bindings_p ()); }
          init
 /* Note how the declaration of the variable is in effect while its init is parsed! */
                { finish_init ();
-                 decl_attributes ($<ttype>5, $3);
+                 decl_attributes ($<ttype>5, $3, prefix_attributes);
                  finish_decl ($<ttype>5, $6, $2); }
        | notype_declarator maybeasm maybe_attribute
-               { tree d = start_decl ($1, current_declspecs, 0);
-                 decl_attributes (d, $3);
+               { tree d = start_decl ($1, current_declspecs, 0,
+                                      $3, prefix_attributes);
                  finish_decl (d, NULL_TREE, $2); }
        ;
 /* the * rules are dummies to accept the Apollo extended syntax
    so that the header files compile. */
 maybe_attribute:
+      /* empty */
+               { $$ = NULL_TREE; }
+       | attributes
+               { $$ = $1; }
+       ;
+attributes:
+      attribute
+               { $$ = $1; }
+       | attributes attribute
+               { $$ = chainon ($1, $2); }
+       ;
+
+attribute:
+      ATTRIBUTE '(' '(' attribute_list ')' ')'
+               { $$ = $4; }
+       ;
+
+attribute_list:
+      attrib
+               { $$ = $1; }
+       | attribute_list ',' attrib
+               { $$ = chainon ($1, $3); }
+       ;
+attrib:
     /* empty */
                { $$ = NULL_TREE; }
-    | ATTRIBUTE '(' '(' attribute_list ')' ')'
-               { $$ = $4; }
-    ;
-
-attribute_list
-    : attrib
-       { $$ = tree_cons (NULL_TREE, $1, NULL_TREE); }
-    | attribute_list ',' attrib
-       { $$ = tree_cons (NULL_TREE, $3, $1); }
-    ;
-
-attrib
-    : IDENTIFIER
-       { if (strcmp (IDENTIFIER_POINTER ($1), "packed")
-             && strcmp (IDENTIFIER_POINTER ($1), "noreturn"))
-           warning ("`%s' attribute directive ignored",
-                    IDENTIFIER_POINTER ($1));
-         $$ = $1; }
-    | TYPE_QUAL
-    | IDENTIFIER '(' IDENTIFIER ')'
-       { /* If not "mode (m)", then issue warning.  */
-         if (strcmp (IDENTIFIER_POINTER ($1), "mode") != 0)
-           {
-             warning ("`%s' attribute directive ignored",
-                      IDENTIFIER_POINTER ($1));
-             $$ = $1;
-           }
-         else
-           $$ = tree_cons ($1, $3, NULL_TREE); }
-    | IDENTIFIER '(' CONSTANT ')'
-       { /* if not "aligned(n)", then issue warning */
-         if (strcmp (IDENTIFIER_POINTER ($1), "aligned") != 0
-             || TREE_CODE ($3) != INTEGER_CST)
-           {
-             warning ("`%s' attribute directive ignored",
-                      IDENTIFIER_POINTER ($1));
-             $$ = $1;
-           }
-         else
-           $$ = tree_cons ($1, $3, NULL_TREE); }
-    | IDENTIFIER '(' IDENTIFIER ',' CONSTANT ',' CONSTANT ')'
-       { /* if not "format(...)", then issue warning */
-         if (strcmp (IDENTIFIER_POINTER ($1), "format") != 0
-             || TREE_CODE ($5) != INTEGER_CST
-             || TREE_CODE ($7) != INTEGER_CST)
-           {
-             warning ("`%s' attribute directive ignored",
-                      IDENTIFIER_POINTER ($1));
-             $$ = $1;
-           }
-         else
-           $$ = tree_cons ($1,
-                           tree_cons ($3,
-                                      tree_cons ($5, $7, NULL_TREE),
-                                      NULL_TREE),
-                           NULL_TREE); }
-    ;
+       | any_word
+               { $$ = build_tree_list ($1, NULL_TREE); }
+       | any_word '(' IDENTIFIER ')'
+               { $$ = build_tree_list ($1, build_tree_list (NULL_TREE, $3)); }
+       | any_word '(' IDENTIFIER ',' nonnull_exprlist ')'
+               { $$ = build_tree_list ($1, tree_cons (NULL_TREE, $3, $5)); }
+       | any_word '(' exprlist ')'
+               { $$ = build_tree_list ($1, $3); }
+       ;
+
+/* This still leaves out most reserved keywords,
+   shouldn't we include them?  */
+
+any_word:
+         identifier
+       | SCSPEC
+       | TYPESPEC
+       | TYPE_QUAL
+       ;
 \f
 /* Initializers.  `init' is the entry point.  */
 
@@ -1121,7 +1173,8 @@ init:
                  push_momentary (); }
          initlist_maybe_comma '}'
                { $$ = pop_init_level (0);
-                 if ($$ == error_mark_node)
+                 if ($$ == error_mark_node
+                     && ! (yychar == STRING || yychar == CONSTANT))
                    pop_momentary ();
                  else
                    pop_momentary_nofree (); }
@@ -1155,7 +1208,7 @@ initelt:
        | error
        /* These are for labeled elements.  The syntax for an array element
           initializer conflicts with the syntax for an Objective-C message,
-          so don't include these productions in the Objective-C grammer.  */
+          so don't include these productions in the Objective-C grammar.  */
 ifc
        | '[' expr_no_commas ELLIPSIS expr_no_commas ']' '='
                { set_init_index ($2, $4); }
@@ -1163,6 +1216,9 @@ ifc
        | '[' expr_no_commas ']' '='
                { set_init_index ($2, NULL_TREE); }
          initelt
+       | '[' expr_no_commas ']'
+               { set_init_index ($2, NULL_TREE); }
+         initelt
 end ifc
        | identifier ':'
                { set_init_label ($1); }
@@ -1175,13 +1231,15 @@ end ifc
 nested_function:
          declarator
                { push_c_function_context ();
-                 if (! start_function (current_declspecs, $1, 1))
+                 if (! start_function (current_declspecs, $1,
+                                       prefix_attributes, NULL_TREE, 1))
                    {
                      pop_c_function_context ();
                      YYERROR1;
                    }
-                 reinit_parse_for_function ();
-                 store_parm_decls (); }
+                 reinit_parse_for_function (); }
+          xdecls
+               { store_parm_decls (); }
 /* This used to use compstmt_or_error.
    That caused a bug with input `f(g) int g {}',
    where the use of YYERROR1 above caused an error
@@ -1196,13 +1254,15 @@ nested_function:
 notype_nested_function:
          notype_declarator
                { push_c_function_context ();
-                 if (! start_function (current_declspecs, $1, 1))
+                 if (! start_function (current_declspecs, $1,
+                                       prefix_attributes, NULL_TREE, 1))
                    {
                      pop_c_function_context ();
                      YYERROR1;
                    }
-                 reinit_parse_for_function ();
-                 store_parm_decls (); }
+                 reinit_parse_for_function (); }
+         xdecls
+               { store_parm_decls (); }
 /* This used to use compstmt_or_error.
    That caused a bug with input `f(g) int g {}',
    where the use of YYERROR1 above caused an error
@@ -1238,6 +1298,8 @@ after_type_declarator:
                { $$ = build_nt (ARRAY_REF, $1, NULL_TREE); }
        | '*' type_quals after_type_declarator  %prec UNARY
                { $$ = make_pointer_declarator ($2, $3); }
+       | attributes setattrs after_type_declarator
+               { $$ = $3; }
        | TYPENAME
 ifobjc
        | OBJECTNAME
@@ -1261,6 +1323,8 @@ parm_declarator:
                { $$ = build_nt (ARRAY_REF, $1, NULL_TREE); }
        | '*' type_quals parm_declarator  %prec UNARY
                { $$ = make_pointer_declarator ($2, $3); }
+       | attributes setattrs parm_declarator
+               { $$ = $3; }
        | TYPENAME
        ;
 
@@ -1281,6 +1345,8 @@ notype_declarator:
                { $$ = build_nt (ARRAY_REF, $1, $3); }
        | notype_declarator '[' ']'  %prec '.'
                { $$ = build_nt (ARRAY_REF, $1, NULL_TREE); }
+       | attributes setattrs notype_declarator
+               { $$ = $3; }
        | IDENTIFIER
        ;
 
@@ -1289,35 +1355,35 @@ structsp:
                { $$ = start_struct (RECORD_TYPE, $2);
                  /* Start scope of tag before parsing components.  */
                }
-         component_decl_list '}'
-               { $$ = finish_struct ($<ttype>4, $5);
-                 /* Really define the structure.  */
-               }
-       | STRUCT '{' component_decl_list '}'
+         component_decl_list '}' maybe_attribute 
+               { $$ = finish_struct ($<ttype>4, $5, $7); }
+       | STRUCT '{' component_decl_list '}' maybe_attribute
                { $$ = finish_struct (start_struct (RECORD_TYPE, NULL_TREE),
-                                     $3); }
+                                     $3, $5);
+               }
        | STRUCT identifier
                { $$ = xref_tag (RECORD_TYPE, $2); }
        | UNION identifier '{'
                { $$ = start_struct (UNION_TYPE, $2); }
-         component_decl_list '}'
-               { $$ = finish_struct ($<ttype>4, $5); }
-       | UNION '{' component_decl_list '}'
+         component_decl_list '}' maybe_attribute
+               { $$ = finish_struct ($<ttype>4, $5, $7); }
+       | UNION '{' component_decl_list '}' maybe_attribute
                { $$ = finish_struct (start_struct (UNION_TYPE, NULL_TREE),
-                                     $3); }
+                                     $3, $5);
+               }
        | UNION identifier
                { $$ = xref_tag (UNION_TYPE, $2); }
        | ENUM identifier '{'
                { $<itype>3 = suspend_momentary ();
                  $$ = start_enum ($2); }
-         enumlist maybecomma_warn '}'
-               { $$ = finish_enum ($<ttype>4, nreverse ($5));
+         enumlist maybecomma_warn '}' maybe_attribute
+               { $$ = finish_enum ($<ttype>4, nreverse ($5), $8);
                  resume_momentary ($<itype>3); }
        | ENUM '{'
                { $<itype>2 = suspend_momentary ();
                  $$ = start_enum (NULL_TREE); }
-         enumlist maybecomma_warn '}'
-               { $$ = finish_enum ($<ttype>3, nreverse ($4));
+         enumlist maybecomma_warn '}' maybe_attribute
+               { $$ = finish_enum ($<ttype>3, nreverse ($4), $7);
                  resume_momentary ($<itype>2); }
        | ENUM identifier
                { $$ = xref_tag (ENUMERAL_TYPE, $2); }
@@ -1380,6 +1446,7 @@ component_decl:
          typed_typespecs setspecs components
                { $$ = $3;
                  current_declspecs = TREE_VALUE (declspec_stack);
+                 prefix_attributes = TREE_PURPOSE (declspec_stack);
                  declspec_stack = TREE_CHAIN (declspec_stack);
                  resume_momentary ($2); }
        | typed_typespecs
@@ -1390,6 +1457,7 @@ component_decl:
        | nonempty_type_quals setspecs components
                { $$ = $3;
                  current_declspecs = TREE_VALUE (declspec_stack);
+                 prefix_attributes = TREE_PURPOSE (declspec_stack);
                  declspec_stack = TREE_CHAIN (declspec_stack);
                  resume_momentary ($2); }
        | nonempty_type_quals
@@ -1410,14 +1478,14 @@ components:
 component_declarator:
          save_filename save_lineno declarator maybe_attribute
                { $$ = grokfield ($1, $2, $3, current_declspecs, NULL_TREE);
-                 decl_attributes ($$, $4); }
+                 decl_attributes ($$, $4, prefix_attributes); }
        | save_filename save_lineno
          declarator ':' expr_no_commas maybe_attribute
                { $$ = grokfield ($1, $2, $3, current_declspecs, $5);
-                 decl_attributes ($$, $6); }
+                 decl_attributes ($$, $6, prefix_attributes); }
        | save_filename save_lineno ':' expr_no_commas maybe_attribute
                { $$ = grokfield ($1, $2, NULL_TREE, current_declspecs, $4);
-                 decl_attributes ($$, $5); }
+                 decl_attributes ($$, $5, prefix_attributes); }
        ;
 
 /* We chain the enumerators in reverse order.
@@ -1428,7 +1496,12 @@ component_declarator:
 enumlist:
          enumerator
        | enumlist ',' enumerator
-               { $$ = chainon ($3, $1); }
+               { if ($1 == error_mark_node)
+                   $$ = $1;
+                 else
+                   $$ = chainon ($3, $1); }
+       | error
+               { $$ = error_mark_node; }
        ;
 
 
@@ -1486,6 +1559,8 @@ absdcl1:  /* a nonempty absolute declarator */
                { $$ = build_nt (ARRAY_REF, NULL_TREE, $2); }
        | '[' ']'  %prec '.'
                { $$ = build_nt (ARRAY_REF, NULL_TREE, NULL_TREE); }
+       | attributes setattrs absdcl1
+               { $$ = $3; }
        ;
 
 /* at least one statement, the first of which parses without error.  */
@@ -1493,9 +1568,19 @@ absdcl1:  /* a nonempty absolute declarator */
    is actually regarded as an invalid decl and part of the decls.  */
 
 stmts:
+       lineno_stmt_or_labels
+               {
+                 if (pedantic && $1)
+                   pedwarn ("ANSI C forbids label at end of compound statement");
+               }
+       ;
+
+lineno_stmt_or_labels:
          lineno_stmt_or_label
-       | stmts lineno_stmt_or_label
-       | stmts errstmt
+       | lineno_stmt_or_labels lineno_stmt_or_label
+               { $$ = $2; }
+       | lineno_stmt_or_labels errstmt
+               { $$ = 0; }
        ;
 
 xstmts:
@@ -1559,17 +1644,26 @@ compstmt: '{' '}'
                { emit_line_note (input_filename, lineno);
                  expand_end_bindings (getdecls (), 1, 0);
                  $$ = poplevel (1, 1, 0);
-                 pop_momentary (); }
+                 if (yychar == CONSTANT || yychar == STRING)
+                   pop_momentary_nofree ();
+                 else
+                   pop_momentary (); }
        | '{' pushlevel maybe_label_decls error '}'
                { emit_line_note (input_filename, lineno);
                  expand_end_bindings (getdecls (), kept_level_p (), 0);
                  $$ = poplevel (kept_level_p (), 0, 0);
-                 pop_momentary (); }
+                 if (yychar == CONSTANT || yychar == STRING)
+                   pop_momentary_nofree ();
+                 else
+                   pop_momentary (); }
        | '{' pushlevel maybe_label_decls stmts '}'
                { emit_line_note (input_filename, lineno);
                  expand_end_bindings (getdecls (), kept_level_p (), 0);
                  $$ = poplevel (kept_level_p (), 0, 0);
-                 pop_momentary (); }
+                 if (yychar == CONSTANT || yychar == STRING)
+                   pop_momentary_nofree ();
+                 else
+                   pop_momentary (); }
        ;
 
 /* Value is number of statements counted as of the closeparen.  */
@@ -1626,19 +1720,14 @@ lineno_labeled_stmt:
 
 lineno_stmt_or_label:
          save_filename save_lineno stmt_or_label
-               { }
+               { $$ = $3; }
        ;
 
 stmt_or_label:
          stmt
+               { $$ = 0; }
        | label
-               { int next;
-                 position_after_white_space ();
-                 next = getc (finput);
-                 ungetc (next, finput);
-                 if (pedantic && next == '}')
-                   pedwarn ("ANSI C forbids label at end of compound statement");
-               }
+               { $$ = 1; }
        ;
 
 /* Parse a single real statement, not including any labels.  */
@@ -1675,8 +1764,9 @@ stmt:
                { expand_end_cond ();
                  /* This warning is here instead of in simple_if, because we
                     do not want a warning if an empty if is followed by an
-                    else statement.  */
-                 if (extra_warnings && stmt_count == $<itype>1)
+                    else statement.  Increment stmt_count so we don't
+                    give a second error if this is a nested `if'.  */
+                 if (extra_warnings && stmt_count++ == $<itype>1)
                    warning_with_file_and_line (if_stmt_file, if_stmt_line,
                                                "empty body in an if-statement"); }
 /* Make sure expand_end_cond is run once
@@ -1754,7 +1844,10 @@ stmt:
                  expand_loop_continue_here ();
                  if ($9)
                    c_expand_expr_stmt ($9);
-                 pop_momentary ();
+                 if (yychar == CONSTANT || yychar == STRING)
+                   pop_momentary_nofree ();
+                 else
+                   pop_momentary ();
                  expand_end_loop (); }
        | SWITCH '(' expr ')'
                { stmt_count++;
@@ -1766,7 +1859,10 @@ stmt:
                  position_after_white_space (); }
          lineno_labeled_stmt
                { expand_end_case ($3);
-                 pop_momentary (); }
+                 if (yychar == CONSTANT || yychar == STRING)
+                   pop_momentary_nofree ();
+                 else
+                   pop_momentary (); }
        | BREAK ';'
                { stmt_count++;
                  emit_line_note ($<filename>-1, $<lineno>0);
@@ -1829,7 +1925,9 @@ stmt:
                    }
                }
        | GOTO '*' expr ';'
-               { stmt_count++;
+               { if (pedantic)
+                   pedwarn ("ANSI C forbids `goto *expr;'");
+                 stmt_count++;
                  emit_line_note ($<filename>-1, $<lineno>0);
                  expand_computed_goto (convert (ptr_type_node, $3)); }
        | ';'
@@ -1886,7 +1984,10 @@ all_iter_stmt_with_decl:
            emit_line_note (input_filename, lineno);
            expand_end_bindings (getdecls (), 1, 0);
            $<ttype>$ = poplevel (1, 1, 0);
-           pop_momentary ();       
+           if (yychar == CONSTANT || yychar == STRING)
+             pop_momentary_nofree ();
+           else
+             pop_momentary ();     
          }
 */
 
@@ -1925,6 +2026,8 @@ label:      CASE expr_no_commas ':'
                  register tree label
                    = build_decl (LABEL_DECL, NULL_TREE, NULL_TREE);
 
+                 if (pedantic)
+                   pedwarn ("ANSI C forbids case ranges");
                  stmt_count++;
 
                  if (value1 != error_mark_node && value2 != error_mark_node)
@@ -2047,8 +2150,13 @@ parmlist_2:  /* empty */
                { $$ = get_parm_info (0); }
        | ELLIPSIS
                { $$ = get_parm_info (0);
-                 if (pedantic)
-                   pedwarn ("ANSI C requires a named argument before `...'");
+                 /* Gcc used to allow this as an extension.  However, it does
+                    not work for all targets, and thus has been disabled.
+                    Also, since func (...) and func () are indistinguishable,
+                    it caused problems with the code in expand_builtin which
+                    tries to verify that BUILT_IN_NEXT_ARG is being used
+                    correctly.  */
+                 error ("ANSI C requires a named argument before `...'");
                }
        | parms
                { $$ = get_parm_info (1); }
@@ -2066,16 +2174,52 @@ parms:
 /* A single parameter declaration or parameter type name,
    as found in a parmlist.  */
 parm:
-         typed_declspecs parm_declarator
-               { $$ = build_tree_list ($1, $2) ; }
-       | typed_declspecs notype_declarator
-               { $$ = build_tree_list ($1, $2) ; }
-       | typed_declspecs absdcl
-               { $$ = build_tree_list ($1, $2); }
-       | declmods notype_declarator
-               { $$ = build_tree_list ($1, $2) ; }
-       | declmods absdcl
-               { $$ = build_tree_list ($1, $2); }
+         typed_declspecs setspecs parm_declarator maybe_attribute
+               { $$ = build_tree_list (build_tree_list (current_declspecs,
+                                                        $3),
+                                       build_tree_list (prefix_attributes,
+                                                        $4));
+                 current_declspecs = TREE_VALUE (declspec_stack);
+                 prefix_attributes = TREE_PURPOSE (declspec_stack);
+                 declspec_stack = TREE_CHAIN (declspec_stack);
+                 resume_momentary ($2); }
+       | typed_declspecs setspecs notype_declarator maybe_attribute
+               { $$ = build_tree_list (build_tree_list (current_declspecs,
+                                                        $3),
+                                       build_tree_list (prefix_attributes,
+                                                        $4)); 
+                 current_declspecs = TREE_VALUE (declspec_stack);
+                 prefix_attributes = TREE_PURPOSE (declspec_stack);
+                 declspec_stack = TREE_CHAIN (declspec_stack);
+                 resume_momentary ($2); }
+       | typed_declspecs setspecs absdcl maybe_attribute
+               { $$ = build_tree_list (build_tree_list (current_declspecs,
+                                                        $3),
+                                       build_tree_list (prefix_attributes,
+                                                        $4));
+                 current_declspecs = TREE_VALUE (declspec_stack);
+                 prefix_attributes = TREE_PURPOSE (declspec_stack);
+                 declspec_stack = TREE_CHAIN (declspec_stack);
+                 resume_momentary ($2); }
+       | declmods setspecs notype_declarator maybe_attribute
+               { $$ = build_tree_list (build_tree_list (current_declspecs,
+                                                        $3),
+                                       build_tree_list (prefix_attributes,
+                                                        $4));
+                 current_declspecs = TREE_VALUE (declspec_stack);
+                 prefix_attributes = TREE_PURPOSE (declspec_stack);
+                 declspec_stack = TREE_CHAIN (declspec_stack);
+                 resume_momentary ($2);  }
+
+       | declmods setspecs absdcl maybe_attribute
+               { $$ = build_tree_list (build_tree_list (current_declspecs,
+                                                        $3),
+                                       build_tree_list (prefix_attributes,
+                                                        $4));
+                 current_declspecs = TREE_VALUE (declspec_stack);
+                 prefix_attributes = TREE_PURPOSE (declspec_stack);
+                 declspec_stack = TREE_CHAIN (declspec_stack);
+                 resume_momentary ($2);  }
        ;
 
 /* This is used in a function definition
@@ -2302,7 +2446,11 @@ protocolrefs:
                {
                  $$ = NULL_TREE;
                }
-       | ARITHCOMPARE identifier_list ARITHCOMPARE
+       | non_empty_protocolrefs
+       ;
+
+non_empty_protocolrefs:
+         ARITHCOMPARE identifier_list ARITHCOMPARE
                {
                  if ($1 == LT_EXPR && $3 == GT_EXPR)
                    $$ = $2;
@@ -2347,15 +2495,17 @@ ivar_decls:
 
 ivar_decl:
        typed_typespecs setspecs ivars
-               {
-                  $$ = $3;
-                 resume_momentary ($2);
-                }
+               { $$ = $3;
+                 current_declspecs = TREE_VALUE (declspec_stack);
+                 prefix_attributes = TREE_PURPOSE (declspec_stack);
+                 declspec_stack = TREE_CHAIN (declspec_stack);
+                 resume_momentary ($2); }
        | nonempty_type_quals setspecs ivars
-               {
-                  $$ = $3;
-                 resume_momentary ($2);
-                }
+               { $$ = $3;
+                 current_declspecs = TREE_VALUE (declspec_stack);
+                 prefix_attributes = TREE_PURPOSE (declspec_stack);
+                 declspec_stack = TREE_CHAIN (declspec_stack);
+                 resume_momentary ($2); }
        | error
                { $$ = NULL_TREE; }
        ;
@@ -2532,7 +2682,10 @@ mydecls:
 
 mydecl:
        typed_declspecs setspecs myparms ';'
-               { resume_momentary ($2); }
+               { current_declspecs = TREE_VALUE (declspec_stack);
+                 prefix_attributes = TREE_PURPOSE (declspec_stack);
+                 declspec_stack = TREE_CHAIN (declspec_stack);
+                 resume_momentary ($2); }
        | typed_declspecs ';'
                { shadow_tag ($1); }
        | declmods ';'
@@ -2550,12 +2703,21 @@ myparms:
    as found in a parmlist. DOES NOT ALLOW AN INITIALIZER OR ASMSPEC */
 
 myparm:
-         parm_declarator
-               { $$ = build_tree_list (current_declspecs, $1)  ; }
-       | notype_declarator
-               { $$ = build_tree_list (current_declspecs, $1)  ; }
-       | absdcl
-               { $$ = build_tree_list (current_declspecs, $1)  ; }
+         parm_declarator maybe_attribute
+               { $$ = build_tree_list (build_tree_list (current_declspecs,
+                                                        $1),
+                                       build_tree_list (prefix_attributes,
+                                                        $2)); }
+       | notype_declarator maybe_attribute
+               { $$ = build_tree_list (build_tree_list (current_declspecs,
+                                                        $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)); }
        ;
 
 optparmlist: