OSDN Git Service

(__objc_send_message_in_list): When setting a new entry in
[pf3gnuchains/gcc-fork.git] / gcc / c-parse.in
index e4daad6..3a1c17e 100644 (file)
@@ -1,6 +1,6 @@
 /* YACC parser for C syntax and for Objective C.  -*-c-*-
    Copyright (C) 1987, 1988, 1989, 1992, 1993, 1994, 1995, 1996,
-   1997, 1998, 1999, 2000 Free Software Foundation, Inc.
+   1997, 1998, 1999, 2000, 2001 Free Software Foundation, Inc.
 
 This file is part of GNU CC.
 
@@ -29,10 +29,10 @@ Boston, MA 02111-1307, USA.  */
    written by AT&T, but I have never seen it.  */
 
 ifobjc
-%expect 74
+%expect 31
 end ifobjc
 ifc
-%expect 53
+%expect 10
 end ifc
 
 %{
@@ -72,14 +72,17 @@ end ifc
 /* Like YYERROR but do call yyerror.  */
 #define YYERROR1 { yyerror ("syntax error"); YYERROR; }
 
-/* Cause the `yydebug' variable to be defined.  */
+/* Cause the "yydebug" variable to be defined.  */
 #define YYDEBUG 1
+
+/* Rename the "yyparse" function so that we can override it elsewhere.  */
+#define yyparse yyparse_1
 %}
 
 %start program
 
 %union {long itype; tree ttype; enum tree_code code;
-       const char *filename; int lineno; int ends_in_label; }
+       const char *filename; int lineno; }
 
 /* All identifiers that are not reserved words
    and are not declared typedefs in the current block */
@@ -121,6 +124,9 @@ end ifc
 %token REALPART IMAGPART VA_ARG
 %token PTR_VALUE PTR_BASE PTR_EXTENT
 
+/* function name can be a string const or a var decl. */
+%token STRING_FUNC_NAME VAR_FUNC_NAME
+
 /* Add precedence rules to solve dangling else s/r conflict */
 %nonassoc IF
 %nonassoc ELSE
@@ -161,40 +167,53 @@ 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_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> SCSPEC TYPESPEC TYPE_QUAL nonempty_type_quals maybe_type_qual
+%type <ttype> declspecs_nosc_nots_nosa_noea declspecs_nosc_nots_nosa_ea
+%type <ttype> declspecs_nosc_nots_sa_noea declspecs_nosc_nots_sa_ea
+%type <ttype> declspecs_nosc_ts_nosa_noea declspecs_nosc_ts_nosa_ea
+%type <ttype> declspecs_nosc_ts_sa_noea declspecs_nosc_ts_sa_ea
+%type <ttype> declspecs_sc_nots_nosa_noea declspecs_sc_nots_nosa_ea
+%type <ttype> declspecs_sc_nots_sa_noea declspecs_sc_nots_sa_ea
+%type <ttype> declspecs_sc_ts_nosa_noea declspecs_sc_ts_nosa_ea
+%type <ttype> declspecs_sc_ts_sa_noea declspecs_sc_ts_sa_ea
+%type <ttype> declspecs_ts declspecs_nots
+%type <ttype> declspecs_ts_nosa declspecs_nots_nosa
+%type <ttype> declspecs_nosc_ts declspecs_nosc_nots declspecs_nosc declspecs
+%type <ttype> maybe_type_quals_setattrs typespec_nonattr typespec_attr
+%type <ttype> typespec_reserved_nonattr typespec_reserved_attr
+%type <ttype> typespec_nonreserved_nonattr
+
+%type <ttype> SCSPEC TYPESPEC TYPE_QUAL 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
-%type <ttype> do_stmt_start poplevel
+%type <ttype> do_stmt_start poplevel stmt label
 
 %type <ttype> c99_block_start c99_block_end
 %type <ttype> declarator
 %type <ttype> notype_declarator after_type_declarator
 %type <ttype> parm_declarator
+%type <ttype> parm_declarator_starttypename parm_declarator_nostarttypename
 
-%type <ttype> structsp component_decl_list component_decl_list2
-%type <ttype> component_decl components component_declarator
+%type <ttype> structsp_attr structsp_nonattr
+%type <ttype> component_decl_list component_decl_list2
+%type <ttype> component_decl components components_notype component_declarator
+%type <ttype> component_notype_declarator
 %type <ttype> enumlist enumerator
 %type <ttype> struct_head union_head enum_head
-%type <ttype> typename absdcl absdcl1 type_quals
-%type <ttype> xexpr parms parm identifiers
+%type <ttype> typename absdcl absdcl1 absdcl1_ea absdcl1_noea
+%type <ttype> direct_absdcl1 absdcl_maybe_attribute
+%type <ttype> xexpr parms parm firstparm identifiers
 
 %type <ttype> parmlist parmlist_1 parmlist_2
 %type <ttype> parmlist_or_identifiers parmlist_or_identifiers_1
 %type <ttype> identifiers_or_typenames
 
-%type <itype> setspecs
-
-%type <ends_in_label> lineno_stmt_or_label lineno_stmt_or_labels stmt_or_label
+%type <itype> setspecs setspecs_fp
 
 %type <filename> save_filename
 %type <lineno> save_lineno
@@ -253,6 +272,7 @@ tree objc_ivar_context;
 enum tree_code objc_inherit_code;
 int objc_receiver_context;
 int objc_public_flag;
+int objc_pq_context;
 
 end ifobjc
 
@@ -262,6 +282,7 @@ end ifobjc
 
 static void yyprint      PARAMS ((FILE *, int, YYSTYPE));
 static void yyerror      PARAMS ((const char *));
+static int yylexname     PARAMS ((void));
 static inline int _yylex  PARAMS ((void));
 static int  yylex        PARAMS ((void));
 static void init_reswords PARAMS ((void));
@@ -296,7 +317,10 @@ program: /* empty */
                     get us back to the global binding level.  */
                  while (! global_bindings_p ())
                    poplevel (0, 0, 0);
-                 finish_file ();
+ifc
+                 finish_fname_decls ();
+end ifc
+                  finish_file ();
                }
        ;
 
@@ -337,17 +361,15 @@ datadef:
                  current_declspecs = TREE_VALUE (declspec_stack);
                  prefix_attributes = TREE_PURPOSE (declspec_stack);
                  declspec_stack = TREE_CHAIN (declspec_stack); }
-        | declmods setspecs notype_initdecls ';'
+        | declspecs_nots setspecs notype_initdecls ';'
                { current_declspecs = TREE_VALUE (declspec_stack);
                  prefix_attributes = TREE_PURPOSE (declspec_stack);
                  declspec_stack = TREE_CHAIN (declspec_stack); }
-       | typed_declspecs setspecs initdecls ';'
+       | declspecs_ts setspecs initdecls ';'
                { current_declspecs = TREE_VALUE (declspec_stack);
                  prefix_attributes = TREE_PURPOSE (declspec_stack);
                  declspec_stack = TREE_CHAIN (declspec_stack); }
-        | declmods ';'
-         { pedwarn ("empty declaration"); }
-       | typed_declspecs ';'
+       | declspecs ';'
          { shadow_tag ($1); }
        | error ';'
        | error '}'
@@ -357,35 +379,39 @@ datadef:
        ;
 \f
 fndef:
-         typed_declspecs setspecs declarator
+         declspecs_ts setspecs declarator
                { if (! start_function (current_declspecs, $3,
                                        prefix_attributes, NULL_TREE))
                    YYERROR1;
                }
          old_style_parm_decls
                { store_parm_decls (); }
-         compstmt_or_error
-               { finish_function (0); 
+         save_filename save_lineno compstmt_or_error
+               { DECL_SOURCE_FILE (current_function_decl) = $7;
+                 DECL_SOURCE_LINE (current_function_decl) = $8;
+                 finish_function (0); 
                  current_declspecs = TREE_VALUE (declspec_stack);
                  prefix_attributes = TREE_PURPOSE (declspec_stack);
                  declspec_stack = TREE_CHAIN (declspec_stack); }
-       | typed_declspecs setspecs declarator error
+       | declspecs_ts setspecs declarator error
                { current_declspecs = TREE_VALUE (declspec_stack);
                  prefix_attributes = TREE_PURPOSE (declspec_stack);
                  declspec_stack = TREE_CHAIN (declspec_stack); }
-       | declmods setspecs notype_declarator
+       | declspecs_nots setspecs notype_declarator
                { if (! start_function (current_declspecs, $3,
                                        prefix_attributes, NULL_TREE))
                    YYERROR1;
                }
          old_style_parm_decls
                { store_parm_decls (); }
-         compstmt_or_error
-               { finish_function (0); 
+         save_filename save_lineno compstmt_or_error
+               { DECL_SOURCE_FILE (current_function_decl) = $7;
+                 DECL_SOURCE_LINE (current_function_decl) = $8;
+                 finish_function (0); 
                  current_declspecs = TREE_VALUE (declspec_stack);
                  prefix_attributes = TREE_PURPOSE (declspec_stack);
                  declspec_stack = TREE_CHAIN (declspec_stack); }
-       | declmods setspecs notype_declarator error
+       | declspecs_nots setspecs notype_declarator error
                { current_declspecs = TREE_VALUE (declspec_stack);
                  prefix_attributes = TREE_PURPOSE (declspec_stack);
                  declspec_stack = TREE_CHAIN (declspec_stack); }
@@ -396,8 +422,10 @@ fndef:
                }
          old_style_parm_decls
                { store_parm_decls (); }
-         compstmt_or_error
-               { finish_function (0); 
+         save_filename save_lineno compstmt_or_error
+               { DECL_SOURCE_FILE (current_function_decl) = $6;
+                 DECL_SOURCE_LINE (current_function_decl) = $7;
+                 finish_function (0); 
                  current_declspecs = TREE_VALUE (declspec_stack);
                  prefix_attributes = TREE_PURPOSE (declspec_stack);
                  declspec_stack = TREE_CHAIN (declspec_stack); }
@@ -467,18 +495,7 @@ unary_expr:
                  overflow_warning ($$); }
        /* Refer to the address of a label as a pointer.  */
        | ANDAND identifier
-               { tree label = lookup_label ($2);
-                 if (pedantic)
-                   pedwarn ("ISO C forbids `&&'");
-                 if (label == 0)
-                   $$ = null_pointer_node;
-                 else
-                   {
-                     TREE_USED (label) = 1;
-                     $$ = build1 (ADDR_EXPR, ptr_type_node, label);
-                     TREE_CONSTANT ($$) = 1;
-                   }
-               }
+               { $$ = finish_label_address_expr ($2); }
 /* This seems to be impossible on some machines, so let's turn it off.
    You can use __builtin_next_arg to find the anonymous stack args.
        | '&' ELLIPSIS
@@ -513,8 +530,6 @@ unary_expr:
                { $$ = build_unary_op (REALPART_EXPR, $2, 0); }
        | IMAGPART cast_expr %prec UNARY
                { $$ = build_unary_op (IMAGPART_EXPR, $2, 0); }
-       | VA_ARG '(' expr_no_commas ',' typename ')'
-               { $$ = build_va_arg ($3, groktypename ($5)); }
        ;
 
 sizeof:
@@ -528,44 +543,7 @@ alignof:
 cast_expr:
        unary_expr
        | '(' typename ')' cast_expr  %prec UNARY
-               { tree type;
-                 int SAVED_warn_strict_prototypes = warn_strict_prototypes;
-                 /* This avoids warnings about unprototyped casts on
-                     integers.  E.g. "#define SIG_DFL (void(*)())0".  */
-                 if (TREE_CODE ($4) == INTEGER_CST)
-                   warn_strict_prototypes = 0;
-                 type = groktypename ($2);
-                 warn_strict_prototypes = SAVED_warn_strict_prototypes;
-                 $$ = build_c_cast (type, $4); }
-       | '(' typename ')' '{' 
-               { start_init (NULL_TREE, NULL, 0);
-                 $2 = groktypename ($2);
-                 really_start_incremental_init ($2); }
-         initlist_maybe_comma '}'  %prec UNARY
-               { const char *name;
-                 tree result = pop_init_level (0);
-                 tree type = $2;
-                 finish_init ();
-
-                 if (pedantic && ! flag_isoc99)
-                   pedwarn ("ISO C89 forbids constructor expressions");
-                 if (TYPE_NAME (type) != 0)
-                   {
-                     if (TREE_CODE (TYPE_NAME (type)) == IDENTIFIER_NODE)
-                       name = IDENTIFIER_POINTER (TYPE_NAME (type));
-                     else
-                       name = IDENTIFIER_POINTER (DECL_NAME (TYPE_NAME (type)));
-                   }
-                 else
-                   name = "";
-                 $$ = result;
-                 if (TREE_CODE (type) == ARRAY_TYPE && !COMPLETE_TYPE_P (type))
-                   {
-                     int failure = complete_array_type (type, $$, 1);
-                     if (failure)
-                       abort ();
-                   }
-               }
+               { $$ = c_cast_expr ($2, $4); }
        ;
 
 expr_no_commas:
@@ -654,6 +632,37 @@ primary:
        | CONSTANT
        | string
                { $$ = combine_strings ($1); }
+       | VAR_FUNC_NAME
+               { $$ = fname_decl (C_RID_CODE ($$), $$); }
+       | '(' typename ')' '{' 
+               { start_init (NULL_TREE, NULL, 0);
+                 $2 = groktypename ($2);
+                 really_start_incremental_init ($2); }
+         initlist_maybe_comma '}'  %prec UNARY
+               { const char *name;
+                 tree result = pop_init_level (0);
+                 tree type = $2;
+                 finish_init ();
+
+                 if (pedantic && ! flag_isoc99)
+                   pedwarn ("ISO C89 forbids compound literals");
+                 if (TYPE_NAME (type) != 0)
+                   {
+                     if (TREE_CODE (TYPE_NAME (type)) == IDENTIFIER_NODE)
+                       name = IDENTIFIER_POINTER (TYPE_NAME (type));
+                     else
+                       name = IDENTIFIER_POINTER (DECL_NAME (TYPE_NAME (type)));
+                   }
+                 else
+                   name = "";
+                 $$ = result;
+                 if (TREE_CODE (type) == ARRAY_TYPE && !COMPLETE_TYPE_P (type))
+                   {
+                     int failure = complete_array_type (type, $$, 1);
+                     if (failure)
+                       abort ();
+                   }
+               }
        | '(' expr ')'
                { char class = TREE_CODE_CLASS (TREE_CODE ($2));
                  if (class == 'e' || class == '1'
@@ -687,37 +696,29 @@ primary:
                }
        | primary '(' exprlist ')'   %prec '.'
                { $$ = build_function_call ($1, $3); }
+       | VA_ARG '(' expr_no_commas ',' typename ')'
+               { $$ = build_va_arg ($3, groktypename ($5)); }
        | primary '[' expr ']'   %prec '.'
                { $$ = build_array_ref ($1, $3); }
        | primary '.' identifier
                {
 ifobjc
-                  if (doing_objc_thang)
-                    {
-                     if (is_public ($1, $3))
-                       $$ = build_component_ref ($1, $3);
-                     else
-                       $$ = error_mark_node;
-                   }
-                  else
+                   if (!is_public ($1, $3))
+                     $$ = error_mark_node;
+                   else
 end ifobjc
-                   $$ = build_component_ref ($1, $3);
+                     $$ = build_component_ref ($1, $3);
                }
        | primary POINTSAT identifier
                {
                   tree expr = build_indirect_ref ($1, "->");
 
 ifobjc
-                  if (doing_objc_thang)
-                    {
-                     if (is_public (expr, $3))
-                       $$ = build_component_ref (expr, $3);
-                     else
+                     if (!is_public (expr, $3))
                        $$ = error_mark_node;
-                   }
-                  else
+                     else
 end ifobjc
-                    $$ = build_component_ref (expr, $3);
+                       $$ = build_component_ref (expr, $3);
                }
        | primary PLUSPLUS
                { $$ = build_unary_op (POSTINCREMENT_EXPR, $1, 0); }
@@ -800,18 +801,18 @@ datadecls:
    attribute suffix, or function defn with attribute prefix on first old
    style parm.  */
 datadecl:
-       typed_declspecs_no_prefix_attr setspecs initdecls ';'
+       declspecs_ts_nosa setspecs 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 ';'
+       | declspecs_nots_nosa setspecs notype_initdecls ';'
                { current_declspecs = TREE_VALUE (declspec_stack);      
                  prefix_attributes = TREE_PURPOSE (declspec_stack);
                  declspec_stack = TREE_CHAIN (declspec_stack); }
-       | typed_declspecs_no_prefix_attr ';'
+       | declspecs_ts_nosa ';'
                { shadow_tag_warned ($1, 1);
                  pedwarn ("empty declaration"); }
-       | declmods_no_prefix_attr ';'
+       | declspecs_nots_nosa ';'
                { pedwarn ("empty declaration"); }
        ;
 
@@ -824,13 +825,6 @@ lineno_decl:
                { }
        ;
 
-decls:
-       lineno_decl
-       | errstmt
-       | decls lineno_decl
-       | lineno_decl errstmt
-       ;
-
 /* records the type and storage class specs to use for processing
    the declarators that follow.
    Maintains a stack of outer-level values of current_declspecs,
@@ -844,106 +838,338 @@ 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:
+       /* ??? 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).  */
+         maybe_attribute setattrs
+       ;
+
 decl:
-       typed_declspecs setspecs initdecls ';'
+       declspecs_ts setspecs initdecls ';'
                { current_declspecs = TREE_VALUE (declspec_stack);
                  prefix_attributes = TREE_PURPOSE (declspec_stack);
                  declspec_stack = TREE_CHAIN (declspec_stack); }
-       | declmods setspecs notype_initdecls ';'
+       | declspecs_nots setspecs notype_initdecls ';'
                { current_declspecs = TREE_VALUE (declspec_stack);
                  prefix_attributes = TREE_PURPOSE (declspec_stack);
                  declspec_stack = TREE_CHAIN (declspec_stack); }
-       | typed_declspecs setspecs nested_function
+       | declspecs_ts setspecs nested_function
                { current_declspecs = TREE_VALUE (declspec_stack);
                  prefix_attributes = TREE_PURPOSE (declspec_stack);
                  declspec_stack = TREE_CHAIN (declspec_stack); }
-       | declmods setspecs notype_nested_function
+       | declspecs_nots setspecs notype_nested_function
                { current_declspecs = TREE_VALUE (declspec_stack);
                  prefix_attributes = TREE_PURPOSE (declspec_stack);
                  declspec_stack = TREE_CHAIN (declspec_stack); }
-       | typed_declspecs ';'
+       | declspecs ';'
                { shadow_tag ($1); }
-       | declmods ';'
-               { pedwarn ("empty declaration"); }
        | extension decl
                { RESTORE_WARN_FLAGS ($1); }
        ;
 
+/* A list of declaration specifiers.  These are:
+
+   - Storage class specifiers (SCSPEC), which for GCC currently include
+   function specifiers ("inline").
+
+   - Type specifiers (typespec_*).
+
+   - Type qualifiers (TYPE_QUAL).
+
+   - Attribute specifier lists (attributes).
+
+   These are stored as a TREE_LIST; the head of the list is the last
+   item in the specifier list.  Each entry in the list has either a
+   TREE_PURPOSE that is an attribute specifier list, or a TREE_VALUE that
+   is a single other specifier or qualifier; and a TREE_CHAIN that is the
+   rest of the list.  TREE_STATIC is set on the list if something other
+   than a storage class specifier or attribute has been seen; this is used
+   to warn for the obsolescent usage of storage class specifiers other than
+   at the start of the list.  (Doing this properly would require function
+   specifiers to be handled separately from storage class specifiers.)
+
+   The various cases below are classified according to:
+
+   (a) Whether a storage class specifier is included or not; some
+   places in the grammar disallow storage class specifiers (_sc or _nosc).
+
+   (b) Whether a type specifier has been seen; after a type specifier,
+   a typedef name is an identifier to redeclare (_ts or _nots).
+
+   (c) Whether the list starts with an attribute; in certain places,
+   the grammar requires specifiers that don't start with an attribute
+   (_sa or _nosa).
+
+   (d) Whether the list ends with an attribute (or a specifier such that
+   any following attribute would have been parsed as part of that specifier);
+   this avoids shift-reduce conflicts in the parsing of attributes
+   (_ea or _noea).
+
+   TODO:
+
+   (i) Distinguish between function specifiers and storage class specifiers,
+   at least for the purpose of warnings about obsolescent usage.
+
+   (ii) Halve the number of productions here by eliminating the _sc/_nosc
+   distinction and instead checking where required that storage class
+   specifiers aren't present.  */
+
 /* Declspecs which contain at least one type specifier or typedef name.
    (Just `const' or `volatile' is not enough.)
    A typedef'd name following these is taken as a name to be declared.
    Declspecs have a non-NULL TREE_VALUE, attributes do not.  */
 
-typed_declspecs:
-         typespec reserved_declspecs
-               { $$ = tree_cons (NULL_TREE, $1, $2); }
-       | declmods typespec reserved_declspecs
-               { $$ = chainon ($3, tree_cons (NULL_TREE, $2, $1)); }
+declspecs_nosc_nots_nosa_noea:
+         TYPE_QUAL
+               { $$ = tree_cons (NULL_TREE, $1, NULL_TREE);
+                 TREE_STATIC ($$) = 1; }
+       | declspecs_nosc_nots_nosa_noea TYPE_QUAL
+               { $$ = tree_cons (NULL_TREE, $2, $1);
+                 TREE_STATIC ($$) = 1; }
+       | declspecs_nosc_nots_nosa_ea TYPE_QUAL
+               { $$ = tree_cons (NULL_TREE, $2, $1);
+                 TREE_STATIC ($$) = 1; }
        ;
 
-reserved_declspecs:  /* empty */
-               { $$ = NULL_TREE; }
-       | reserved_declspecs typespecqual_reserved
-               { $$ = tree_cons (NULL_TREE, $2, $1); }
-       | reserved_declspecs SCSPEC
-               { if (extra_warnings)
+declspecs_nosc_nots_nosa_ea:
+         declspecs_nosc_nots_nosa_noea attributes
+               { $$ = tree_cons ($2, NULL_TREE, $1);
+                 TREE_STATIC ($$) = TREE_STATIC ($1); }
+       ;
+
+declspecs_nosc_nots_sa_noea:
+         declspecs_nosc_nots_sa_noea TYPE_QUAL
+               { $$ = tree_cons (NULL_TREE, $2, $1);
+                 TREE_STATIC ($$) = 1; }
+       | declspecs_nosc_nots_sa_ea TYPE_QUAL
+               { $$ = tree_cons (NULL_TREE, $2, $1);
+                 TREE_STATIC ($$) = 1; }
+       ;
+
+declspecs_nosc_nots_sa_ea:
+         attributes
+               { $$ = tree_cons ($1, NULL_TREE, NULL_TREE);
+                 TREE_STATIC ($$) = 0; }
+       | declspecs_nosc_nots_sa_noea attributes
+               { $$ = tree_cons ($2, NULL_TREE, $1);
+                 TREE_STATIC ($$) = TREE_STATIC ($1); }
+       ;
+
+declspecs_nosc_ts_nosa_noea:
+         typespec_nonattr
+               { $$ = tree_cons (NULL_TREE, $1, NULL_TREE);
+                 TREE_STATIC ($$) = 1; }
+       | declspecs_nosc_ts_nosa_noea TYPE_QUAL
+               { $$ = tree_cons (NULL_TREE, $2, $1);
+                 TREE_STATIC ($$) = 1; }
+       | declspecs_nosc_ts_nosa_ea TYPE_QUAL
+               { $$ = tree_cons (NULL_TREE, $2, $1);
+                 TREE_STATIC ($$) = 1; }
+       | declspecs_nosc_ts_nosa_noea typespec_reserved_nonattr
+               { $$ = tree_cons (NULL_TREE, $2, $1);
+                 TREE_STATIC ($$) = 1; }
+       | declspecs_nosc_ts_nosa_ea typespec_reserved_nonattr
+               { $$ = tree_cons (NULL_TREE, $2, $1);
+                 TREE_STATIC ($$) = 1; }
+       | declspecs_nosc_nots_nosa_noea typespec_nonattr
+               { $$ = tree_cons (NULL_TREE, $2, $1);
+                 TREE_STATIC ($$) = 1; }
+       | declspecs_nosc_nots_nosa_ea typespec_nonattr
+               { $$ = tree_cons (NULL_TREE, $2, $1);
+                 TREE_STATIC ($$) = 1; }
+       ;
+
+declspecs_nosc_ts_nosa_ea:
+         typespec_attr
+               { $$ = tree_cons (NULL_TREE, $1, NULL_TREE);
+                 TREE_STATIC ($$) = 1; }
+       | declspecs_nosc_ts_nosa_noea attributes
+               { $$ = tree_cons ($2, NULL_TREE, $1);
+                 TREE_STATIC ($$) = TREE_STATIC ($1); }
+       | declspecs_nosc_ts_nosa_noea typespec_reserved_attr
+               { $$ = tree_cons (NULL_TREE, $2, $1);
+                 TREE_STATIC ($$) = 1; }
+       | declspecs_nosc_ts_nosa_ea typespec_reserved_attr
+               { $$ = tree_cons (NULL_TREE, $2, $1);
+                 TREE_STATIC ($$) = 1; }
+       | declspecs_nosc_nots_nosa_noea typespec_attr
+               { $$ = tree_cons (NULL_TREE, $2, $1);
+                 TREE_STATIC ($$) = 1; }
+       | declspecs_nosc_nots_nosa_ea typespec_attr
+               { $$ = tree_cons (NULL_TREE, $2, $1);
+                 TREE_STATIC ($$) = 1; }
+       ;
+
+declspecs_nosc_ts_sa_noea:
+         declspecs_nosc_ts_sa_noea TYPE_QUAL
+               { $$ = tree_cons (NULL_TREE, $2, $1);
+                 TREE_STATIC ($$) = 1; }
+       | declspecs_nosc_ts_sa_ea TYPE_QUAL
+               { $$ = tree_cons (NULL_TREE, $2, $1);
+                 TREE_STATIC ($$) = 1; }
+       | declspecs_nosc_ts_sa_noea typespec_reserved_nonattr
+               { $$ = tree_cons (NULL_TREE, $2, $1);
+                 TREE_STATIC ($$) = 1; }
+       | declspecs_nosc_ts_sa_ea typespec_reserved_nonattr
+               { $$ = tree_cons (NULL_TREE, $2, $1);
+                 TREE_STATIC ($$) = 1; }
+       | declspecs_nosc_nots_sa_noea typespec_nonattr
+               { $$ = tree_cons (NULL_TREE, $2, $1);
+                 TREE_STATIC ($$) = 1; }
+       | declspecs_nosc_nots_sa_ea typespec_nonattr
+               { $$ = tree_cons (NULL_TREE, $2, $1);
+                 TREE_STATIC ($$) = 1; }
+       ;
+
+declspecs_nosc_ts_sa_ea:
+         declspecs_nosc_ts_sa_noea attributes
+               { $$ = tree_cons ($2, NULL_TREE, $1);
+                 TREE_STATIC ($$) = TREE_STATIC ($1); }
+       | declspecs_nosc_ts_sa_noea typespec_reserved_attr
+               { $$ = tree_cons (NULL_TREE, $2, $1);
+                 TREE_STATIC ($$) = 1; }
+       | declspecs_nosc_ts_sa_ea typespec_reserved_attr
+               { $$ = tree_cons (NULL_TREE, $2, $1);
+                 TREE_STATIC ($$) = 1; }
+       | declspecs_nosc_nots_sa_noea typespec_attr
+               { $$ = tree_cons (NULL_TREE, $2, $1);
+                 TREE_STATIC ($$) = 1; }
+       | declspecs_nosc_nots_sa_ea typespec_attr
+               { $$ = tree_cons (NULL_TREE, $2, $1);
+                 TREE_STATIC ($$) = 1; }
+       ;
+
+declspecs_sc_nots_nosa_noea:
+         SCSPEC
+               { $$ = tree_cons (NULL_TREE, $1, NULL_TREE);
+                 TREE_STATIC ($$) = 0; }
+       | declspecs_sc_nots_nosa_noea TYPE_QUAL
+               { $$ = tree_cons (NULL_TREE, $2, $1);
+                 TREE_STATIC ($$) = 1; }
+       | declspecs_sc_nots_nosa_ea TYPE_QUAL
+               { $$ = tree_cons (NULL_TREE, $2, $1);
+                 TREE_STATIC ($$) = 1; }
+       | declspecs_nosc_nots_nosa_noea SCSPEC
+               { if (extra_warnings && TREE_STATIC ($1))
+                   warning ("`%s' is not at beginning of declaration",
+                            IDENTIFIER_POINTER ($2));
+                 $$ = tree_cons (NULL_TREE, $2, $1);
+                 TREE_STATIC ($$) = TREE_STATIC ($1); }
+       | declspecs_nosc_nots_nosa_ea SCSPEC
+               { if (extra_warnings && TREE_STATIC ($1))
+                   warning ("`%s' is not at beginning of declaration",
+                            IDENTIFIER_POINTER ($2));
+                 $$ = tree_cons (NULL_TREE, $2, $1);
+                 TREE_STATIC ($$) = TREE_STATIC ($1); }
+       | declspecs_sc_nots_nosa_noea SCSPEC
+               { if (extra_warnings && TREE_STATIC ($1))
+                   warning ("`%s' is not at beginning of declaration",
+                            IDENTIFIER_POINTER ($2));
+                 $$ = tree_cons (NULL_TREE, $2, $1);
+                 TREE_STATIC ($$) = TREE_STATIC ($1); }
+       | declspecs_sc_nots_nosa_ea SCSPEC
+               { if (extra_warnings && TREE_STATIC ($1))
                    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); }
+                 $$ = tree_cons (NULL_TREE, $2, $1);
+                 TREE_STATIC ($$) = TREE_STATIC ($1); }
        ;
 
-typed_declspecs_no_prefix_attr:
-         typespec reserved_declspecs_no_prefix_attr
-               { $$ = tree_cons (NULL_TREE, $1, $2); }
-       | declmods_no_prefix_attr typespec reserved_declspecs_no_prefix_attr
-               { $$ = chainon ($3, tree_cons (NULL_TREE, $2, $1)); }
+declspecs_sc_nots_nosa_ea:
+         declspecs_sc_nots_nosa_noea attributes
+               { $$ = tree_cons ($2, NULL_TREE, $1);
+                 TREE_STATIC ($$) = TREE_STATIC ($1); }
        ;
 
-reserved_declspecs_no_prefix_attr:
-         /* empty */
-               { $$ = NULL_TREE; }
-       | reserved_declspecs_no_prefix_attr typespecqual_reserved
-               { $$ = tree_cons (NULL_TREE, $2, $1); }
-       | reserved_declspecs_no_prefix_attr SCSPEC
-               { if (extra_warnings)
+declspecs_sc_nots_sa_noea:
+         declspecs_sc_nots_sa_noea TYPE_QUAL
+               { $$ = tree_cons (NULL_TREE, $2, $1);
+                 TREE_STATIC ($$) = 1; }
+       | declspecs_sc_nots_sa_ea TYPE_QUAL
+               { $$ = tree_cons (NULL_TREE, $2, $1);
+                 TREE_STATIC ($$) = 1; }
+       | declspecs_nosc_nots_sa_noea SCSPEC
+               { if (extra_warnings && TREE_STATIC ($1))
+                   warning ("`%s' is not at beginning of declaration",
+                            IDENTIFIER_POINTER ($2));
+                 $$ = tree_cons (NULL_TREE, $2, $1);
+                 TREE_STATIC ($$) = TREE_STATIC ($1); }
+       | declspecs_nosc_nots_sa_ea SCSPEC
+               { if (extra_warnings && TREE_STATIC ($1))
                    warning ("`%s' is not at beginning of declaration",
                             IDENTIFIER_POINTER ($2));
-                 $$ = tree_cons (NULL_TREE, $2, $1); }
+                 $$ = tree_cons (NULL_TREE, $2, $1);
+                 TREE_STATIC ($$) = TREE_STATIC ($1); }
+       | declspecs_sc_nots_sa_noea SCSPEC
+               { if (extra_warnings && TREE_STATIC ($1))
+                   warning ("`%s' is not at beginning of declaration",
+                            IDENTIFIER_POINTER ($2));
+                 $$ = tree_cons (NULL_TREE, $2, $1);
+                 TREE_STATIC ($$) = TREE_STATIC ($1); }
+       | declspecs_sc_nots_sa_ea SCSPEC
+               { if (extra_warnings && TREE_STATIC ($1))
+                   warning ("`%s' is not at beginning of declaration",
+                            IDENTIFIER_POINTER ($2));
+                 $$ = tree_cons (NULL_TREE, $2, $1);
+                 TREE_STATIC ($$) = TREE_STATIC ($1); }
        ;
 
-/* List of just storage classes, type modifiers, and prefix attributes.
-   A declaration can start with just this, but then it cannot be used
-   to redeclare a typedef-name.
-   Declspecs have a non-NULL TREE_VALUE, attributes do not.  */
-
-declmods:
-         declmods_no_prefix_attr
-               { $$ = $1; }
-       | attributes
-               { $$ = tree_cons ($1, NULL_TREE, NULL_TREE); }
-       | declmods declmods_no_prefix_attr
-               { $$ = chainon ($2, $1); }
-       | declmods attributes
-               { $$ = tree_cons ($2, NULL_TREE, $1); }
+declspecs_sc_nots_sa_ea:
+         declspecs_sc_nots_sa_noea attributes
+               { $$ = tree_cons ($2, NULL_TREE, $1);
+                 TREE_STATIC ($$) = TREE_STATIC ($1); }
        ;
 
-declmods_no_prefix_attr:
-         TYPE_QUAL
-               { $$ = tree_cons (NULL_TREE, $1, NULL_TREE);
+declspecs_sc_ts_nosa_noea:
+         declspecs_sc_ts_nosa_noea TYPE_QUAL
+               { $$ = tree_cons (NULL_TREE, $2, $1);
                  TREE_STATIC ($$) = 1; }
-       | SCSPEC
-               { $$ = tree_cons (NULL_TREE, $1, NULL_TREE); }
-       | declmods_no_prefix_attr TYPE_QUAL
+       | declspecs_sc_ts_nosa_ea TYPE_QUAL
+               { $$ = tree_cons (NULL_TREE, $2, $1);
+                 TREE_STATIC ($$) = 1; }
+       | declspecs_sc_ts_nosa_noea typespec_reserved_nonattr
                { $$ = tree_cons (NULL_TREE, $2, $1);
                  TREE_STATIC ($$) = 1; }
-       | declmods_no_prefix_attr SCSPEC
+       | declspecs_sc_ts_nosa_ea typespec_reserved_nonattr
+               { $$ = tree_cons (NULL_TREE, $2, $1);
+                 TREE_STATIC ($$) = 1; }
+       | declspecs_sc_nots_nosa_noea typespec_nonattr
+               { $$ = tree_cons (NULL_TREE, $2, $1);
+                 TREE_STATIC ($$) = 1; }
+       | declspecs_sc_nots_nosa_ea typespec_nonattr
+               { $$ = tree_cons (NULL_TREE, $2, $1);
+                 TREE_STATIC ($$) = 1; }
+       | declspecs_nosc_ts_nosa_noea SCSPEC
+               { if (extra_warnings && TREE_STATIC ($1))
+                   warning ("`%s' is not at beginning of declaration",
+                            IDENTIFIER_POINTER ($2));
+                 $$ = tree_cons (NULL_TREE, $2, $1);
+                 TREE_STATIC ($$) = TREE_STATIC ($1); }
+       | declspecs_nosc_ts_nosa_ea SCSPEC
+               { if (extra_warnings && TREE_STATIC ($1))
+                   warning ("`%s' is not at beginning of declaration",
+                            IDENTIFIER_POINTER ($2));
+                 $$ = tree_cons (NULL_TREE, $2, $1);
+                 TREE_STATIC ($$) = TREE_STATIC ($1); }
+       | declspecs_sc_ts_nosa_noea SCSPEC
+               { if (extra_warnings && TREE_STATIC ($1))
+                   warning ("`%s' is not at beginning of declaration",
+                            IDENTIFIER_POINTER ($2));
+                 $$ = tree_cons (NULL_TREE, $2, $1);
+                 TREE_STATIC ($$) = TREE_STATIC ($1); }
+       | declspecs_sc_ts_nosa_ea SCSPEC
                { if (extra_warnings && TREE_STATIC ($1))
                    warning ("`%s' is not at beginning of declaration",
                             IDENTIFIER_POINTER ($2));
@@ -951,31 +1177,223 @@ declmods_no_prefix_attr:
                  TREE_STATIC ($$) = TREE_STATIC ($1); }
        ;
 
+declspecs_sc_ts_nosa_ea:
+         declspecs_sc_ts_nosa_noea attributes
+               { $$ = tree_cons ($2, NULL_TREE, $1);
+                 TREE_STATIC ($$) = TREE_STATIC ($1); }
+       | declspecs_sc_ts_nosa_noea typespec_reserved_attr
+               { $$ = tree_cons (NULL_TREE, $2, $1);
+                 TREE_STATIC ($$) = 1; }
+       | declspecs_sc_ts_nosa_ea typespec_reserved_attr
+               { $$ = tree_cons (NULL_TREE, $2, $1);
+                 TREE_STATIC ($$) = 1; }
+       | declspecs_sc_nots_nosa_noea typespec_attr
+               { $$ = tree_cons (NULL_TREE, $2, $1);
+                 TREE_STATIC ($$) = 1; }
+       | declspecs_sc_nots_nosa_ea typespec_attr
+               { $$ = tree_cons (NULL_TREE, $2, $1);
+                 TREE_STATIC ($$) = 1; }
+       ;
 
-/* Used instead of declspecs where storage classes are not allowed
-   (that is, for typenames and structure components).
-   Don't accept a typedef-name if anything but a modifier precedes it.  */
+declspecs_sc_ts_sa_noea:
+         declspecs_sc_ts_sa_noea TYPE_QUAL
+               { $$ = tree_cons (NULL_TREE, $2, $1);
+                 TREE_STATIC ($$) = 1; }
+       | declspecs_sc_ts_sa_ea TYPE_QUAL
+               { $$ = tree_cons (NULL_TREE, $2, $1);
+                 TREE_STATIC ($$) = 1; }
+       | declspecs_sc_ts_sa_noea typespec_reserved_nonattr
+               { $$ = tree_cons (NULL_TREE, $2, $1);
+                 TREE_STATIC ($$) = 1; }
+       | declspecs_sc_ts_sa_ea typespec_reserved_nonattr
+               { $$ = tree_cons (NULL_TREE, $2, $1);
+                 TREE_STATIC ($$) = 1; }
+       | declspecs_sc_nots_sa_noea typespec_nonattr
+               { $$ = tree_cons (NULL_TREE, $2, $1);
+                 TREE_STATIC ($$) = 1; }
+       | declspecs_sc_nots_sa_ea typespec_nonattr
+               { $$ = tree_cons (NULL_TREE, $2, $1);
+                 TREE_STATIC ($$) = 1; }
+       | declspecs_nosc_ts_sa_noea SCSPEC
+               { if (extra_warnings && TREE_STATIC ($1))
+                   warning ("`%s' is not at beginning of declaration",
+                            IDENTIFIER_POINTER ($2));
+                 $$ = tree_cons (NULL_TREE, $2, $1);
+                 TREE_STATIC ($$) = TREE_STATIC ($1); }
+       | declspecs_nosc_ts_sa_ea SCSPEC
+               { if (extra_warnings && TREE_STATIC ($1))
+                   warning ("`%s' is not at beginning of declaration",
+                            IDENTIFIER_POINTER ($2));
+                 $$ = tree_cons (NULL_TREE, $2, $1);
+                 TREE_STATIC ($$) = TREE_STATIC ($1); }
+       | declspecs_sc_ts_sa_noea SCSPEC
+               { if (extra_warnings && TREE_STATIC ($1))
+                   warning ("`%s' is not at beginning of declaration",
+                            IDENTIFIER_POINTER ($2));
+                 $$ = tree_cons (NULL_TREE, $2, $1);
+                 TREE_STATIC ($$) = TREE_STATIC ($1); }
+       | declspecs_sc_ts_sa_ea SCSPEC
+               { if (extra_warnings && TREE_STATIC ($1))
+                   warning ("`%s' is not at beginning of declaration",
+                            IDENTIFIER_POINTER ($2));
+                 $$ = tree_cons (NULL_TREE, $2, $1);
+                 TREE_STATIC ($$) = TREE_STATIC ($1); }
+       ;
 
-typed_typespecs:
-         typespec reserved_typespecquals
-               { $$ = tree_cons (NULL_TREE, $1, $2); }
-       | nonempty_type_quals typespec reserved_typespecquals
-               { $$ = chainon ($3, tree_cons (NULL_TREE, $2, $1)); }
+declspecs_sc_ts_sa_ea:
+         declspecs_sc_ts_sa_noea attributes
+               { $$ = tree_cons ($2, NULL_TREE, $1);
+                 TREE_STATIC ($$) = TREE_STATIC ($1); }
+       | declspecs_sc_ts_sa_noea typespec_reserved_attr
+               { $$ = tree_cons (NULL_TREE, $2, $1);
+                 TREE_STATIC ($$) = 1; }
+       | declspecs_sc_ts_sa_ea typespec_reserved_attr
+               { $$ = tree_cons (NULL_TREE, $2, $1);
+                 TREE_STATIC ($$) = 1; }
+       | declspecs_sc_nots_sa_noea typespec_attr
+               { $$ = tree_cons (NULL_TREE, $2, $1);
+                 TREE_STATIC ($$) = 1; }
+       | declspecs_sc_nots_sa_ea typespec_attr
+               { $$ = tree_cons (NULL_TREE, $2, $1);
+                 TREE_STATIC ($$) = 1; }
        ;
 
-reserved_typespecquals:  /* empty */
+/* Particular useful classes of declspecs.  */
+declspecs_ts:
+         declspecs_nosc_ts_nosa_noea
+       | declspecs_nosc_ts_nosa_ea
+       | declspecs_nosc_ts_sa_noea
+       | declspecs_nosc_ts_sa_ea
+       | declspecs_sc_ts_nosa_noea
+       | declspecs_sc_ts_nosa_ea
+       | declspecs_sc_ts_sa_noea
+       | declspecs_sc_ts_sa_ea
+       ;
+
+declspecs_nots:
+         declspecs_nosc_nots_nosa_noea
+       | declspecs_nosc_nots_nosa_ea
+       | declspecs_nosc_nots_sa_noea
+       | declspecs_nosc_nots_sa_ea
+       | declspecs_sc_nots_nosa_noea
+       | declspecs_sc_nots_nosa_ea
+       | declspecs_sc_nots_sa_noea
+       | declspecs_sc_nots_sa_ea
+       ;
+
+declspecs_ts_nosa:
+         declspecs_nosc_ts_nosa_noea
+       | declspecs_nosc_ts_nosa_ea
+       | declspecs_sc_ts_nosa_noea
+       | declspecs_sc_ts_nosa_ea
+       ;
+
+declspecs_nots_nosa:
+         declspecs_nosc_nots_nosa_noea
+       | declspecs_nosc_nots_nosa_ea
+       | declspecs_sc_nots_nosa_noea
+       | declspecs_sc_nots_nosa_ea
+       ;
+
+declspecs_nosc_ts:
+         declspecs_nosc_ts_nosa_noea
+       | declspecs_nosc_ts_nosa_ea
+       | declspecs_nosc_ts_sa_noea
+       | declspecs_nosc_ts_sa_ea
+       ;
+
+declspecs_nosc_nots:
+         declspecs_nosc_nots_nosa_noea
+       | declspecs_nosc_nots_nosa_ea
+       | declspecs_nosc_nots_sa_noea
+       | declspecs_nosc_nots_sa_ea
+       ;
+
+declspecs_nosc:
+         declspecs_nosc_ts_nosa_noea
+       | declspecs_nosc_ts_nosa_ea
+       | declspecs_nosc_ts_sa_noea
+       | declspecs_nosc_ts_sa_ea
+       | declspecs_nosc_nots_nosa_noea
+       | declspecs_nosc_nots_nosa_ea
+       | declspecs_nosc_nots_sa_noea
+       | declspecs_nosc_nots_sa_ea
+       ;
+
+declspecs:
+         declspecs_nosc_nots_nosa_noea
+       | declspecs_nosc_nots_nosa_ea
+       | declspecs_nosc_nots_sa_noea
+       | declspecs_nosc_nots_sa_ea
+       | declspecs_nosc_ts_nosa_noea
+       | declspecs_nosc_ts_nosa_ea
+       | declspecs_nosc_ts_sa_noea
+       | declspecs_nosc_ts_sa_ea
+       | declspecs_sc_nots_nosa_noea
+       | declspecs_sc_nots_nosa_ea
+       | declspecs_sc_nots_sa_noea
+       | declspecs_sc_nots_sa_ea
+       | declspecs_sc_ts_nosa_noea
+       | declspecs_sc_ts_nosa_ea
+       | declspecs_sc_ts_sa_noea
+       | declspecs_sc_ts_sa_ea
+       ;
+
+/* A (possibly empty) sequence of type qualifiers and attributes, to be
+   followed by the effect of setattrs if any attributes were present.  */
+maybe_type_quals_setattrs:
+         /* empty */
                { $$ = NULL_TREE; }
-       | reserved_typespecquals typespecqual_reserved
-               { $$ = tree_cons (NULL_TREE, $2, $1); }
+       | declspecs_nosc_nots
+               { tree specs, attrs;
+                 split_specs_attrs ($1, &specs, &attrs);
+                 /* ??? Yuck.  See maybe_setattrs.  */
+                 if (attrs != NULL_TREE)
+                   prefix_attributes = chainon (prefix_attributes, attrs);
+                 $$ = specs; }
        ;
 
-/* A typespec (but not a type qualifier).
+/* A type specifier (but not a type qualifier).
    Once we have seen one of these in a declaration,
-   if a typedef name appears then it is being redeclared.  */
+   if a typedef name appears then it is being redeclared.
 
-typespec: TYPESPEC
-       | structsp
-       | TYPENAME
+   The _reserved versions start with a reserved word and may appear anywhere
+   in the declaration specifiers; the _nonreserved versions may only
+   appear before any other type specifiers, and after that are (if names)
+   being redeclared.
+
+   FIXME: should the _nonreserved version be restricted to names being
+   redeclared only?  The other entries there relate only the GNU extensions
+   and Objective C, and are historically parsed thus, and don't make sense
+   after other type specifiers, but it might be cleaner to count them as
+   _reserved.
+
+   _attr means: specifiers that either end with attributes,
+   or are such that any following attributes would
+   be parsed as part of the specifier.
+
+   _nonattr: specifiers.  */
+
+typespec_nonattr:
+         typespec_reserved_nonattr
+       | typespec_nonreserved_nonattr
+       ;
+
+typespec_attr:
+         typespec_reserved_attr
+       ;
+
+typespec_reserved_nonattr:
+         TYPESPEC
+       | structsp_nonattr
+       ;
+
+typespec_reserved_attr:
+         structsp_attr
+       ;
+
+typespec_nonreserved_nonattr:
+         TYPENAME
                { /* For a typedef name, record the meaning, not the name.
                     In case of `foo foo, bar;'.  */
                  $$ = lookup_name ($1); }
@@ -996,21 +1414,16 @@ end ifobjc
                { $$ = groktypename ($3); }
        ;
 
-/* A typespec that is a reserved word, or a type qualifier.  */
-
-typespecqual_reserved: TYPESPEC
-       | TYPE_QUAL
-       | structsp
-       ;
+/* typespec_nonreserved_attr does not exist.  */
 
 initdecls:
        initdcl
-       | initdecls ',' initdcl
+       | initdecls ',' maybe_setattrs initdcl
        ;
 
 notype_initdecls:
        notype_initdcl
-       | notype_initdecls ',' initdcl
+       | notype_initdecls ',' maybe_setattrs notype_initdcl
        ;
 
 maybeasm:
@@ -1198,8 +1611,10 @@ nested_function:
    which then was handled by compstmt_or_error.
    There followed a repeated execution of that same rule,
    which called YYERROR1 again, and so on.  */
-         compstmt
+         save_filename save_lineno compstmt
                { tree decl = current_function_decl;
+                 DECL_SOURCE_FILE (decl) = $5;
+                 DECL_SOURCE_LINE (decl) = $6;
                  finish_function (1);
                  pop_function_context (); 
                  add_decl_stmt (decl); }
@@ -1226,8 +1641,10 @@ notype_nested_function:
    which then was handled by compstmt_or_error.
    There followed a repeated execution of that same rule,
    which called YYERROR1 again, and so on.  */
-         compstmt
+         save_filename save_lineno compstmt
                { tree decl = current_function_decl;
+                 DECL_SOURCE_FILE (decl) = $5;
+                 DECL_SOURCE_LINE (decl) = $6;
                  finish_function (1);
                  pop_function_context (); 
                  add_decl_stmt (decl); }
@@ -1244,8 +1661,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 '.'
@@ -1255,15 +1672,8 @@ after_type_declarator:
                { $$ = build_nt (ARRAY_REF, $1, $3); }
        | after_type_declarator '[' ']'  %prec '.'
                { $$ = build_nt (ARRAY_REF, $1, NULL_TREE); }
-       | '*' type_quals after_type_declarator  %prec UNARY
+       | '*' maybe_type_quals_setattrs 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; }
        | TYPENAME
 ifobjc
        | OBJECTNAME
@@ -1274,34 +1684,54 @@ end ifobjc
    in addition to notype_declarator.  This is like after_type_declarator
    but does not allow a typedef name in parentheses as an identifier
    (because it would conflict with a function with that typedef as arg).  */
-
 parm_declarator:
-         parm_declarator '(' parmlist_or_identifiers  %prec '.'
+         parm_declarator_starttypename
+       | parm_declarator_nostarttypename
+       ;
+
+parm_declarator_starttypename:
+         parm_declarator_starttypename '(' parmlist_or_identifiers  %prec '.'
+               { $$ = build_nt (CALL_EXPR, $1, $3, NULL_TREE); }
+/*     | parm_declarator_starttypename '(' error ')'  %prec '.'
+               { $$ = build_nt (CALL_EXPR, $1, NULL_TREE, NULL_TREE);
+                 poplevel (0, 0, 0); }  */
+ifc
+       | parm_declarator_starttypename '[' '*' ']'  %prec '.'
+               { $$ = build_nt (ARRAY_REF, $1, NULL_TREE);
+                 if (! flag_isoc99)
+                   error ("`[*]' in parameter declaration only allowed in ISO C 99");
+               }
+end ifc
+       | parm_declarator_starttypename '[' expr ']'  %prec '.'
+               { $$ = build_nt (ARRAY_REF, $1, $3); }
+       | parm_declarator_starttypename '[' ']'  %prec '.'
+               { $$ = build_nt (ARRAY_REF, $1, NULL_TREE); }
+       | TYPENAME
+       ;
+
+parm_declarator_nostarttypename:
+         parm_declarator_nostarttypename '(' parmlist_or_identifiers  %prec '.'
                { $$ = build_nt (CALL_EXPR, $1, $3, NULL_TREE); }
-/*     | parm_declarator '(' error ')'  %prec '.'
+/*     | parm_declarator_nostarttypename '(' error ')'  %prec '.'
                { $$ = build_nt (CALL_EXPR, $1, NULL_TREE, NULL_TREE);
                  poplevel (0, 0, 0); }  */
 ifc
-       | parm_declarator '[' '*' ']'  %prec '.'
+       | parm_declarator_nostarttypename '[' '*' ']'  %prec '.'
                { $$ = build_nt (ARRAY_REF, $1, NULL_TREE);
                  if (! flag_isoc99)
                    error ("`[*]' in parameter declaration only allowed in ISO C 99");
                }
 end ifc
-       | parm_declarator '[' expr ']'  %prec '.'
+       | parm_declarator_nostarttypename '[' expr ']'  %prec '.'
                { $$ = build_nt (ARRAY_REF, $1, $3); }
-       | parm_declarator '[' ']'  %prec '.'
+       | parm_declarator_nostarttypename '[' ']'  %prec '.'
                { $$ = build_nt (ARRAY_REF, $1, NULL_TREE); }
-       | '*' type_quals parm_declarator  %prec UNARY
+       | '*' maybe_type_quals_setattrs parm_declarator_starttypename  %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
+       | '*' maybe_type_quals_setattrs parm_declarator_nostarttypename  %prec UNARY
+               { $$ = make_pointer_declarator ($2, $3); }
+       | '(' maybe_setattrs parm_declarator_nostarttypename ')'
                { $$ = $3; }
-       | TYPENAME
        ;
 
 /* A declarator allowed whether or not there has been
@@ -1313,9 +1743,9 @@ notype_declarator:
 /*     | notype_declarator '(' error ')'  %prec '.'
                { $$ = build_nt (CALL_EXPR, $1, NULL_TREE, NULL_TREE);
                  poplevel (0, 0, 0); }  */
-       | '(' notype_declarator ')'
-               { $$ = $2; }
-       | '*' type_quals notype_declarator  %prec UNARY
+       | '(' maybe_setattrs notype_declarator ')'
+               { $$ = $3; }
+       | '*' maybe_type_quals_setattrs notype_declarator  %prec UNARY
                { $$ = make_pointer_declarator ($2, $3); }
 ifc
        | notype_declarator '[' '*' ']'  %prec '.'
@@ -1327,14 +1757,7 @@ end ifc
        | notype_declarator '[' expr ']'  %prec '.'
                { $$ = 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; }
+               { $$ = build_nt (ARRAY_REF, $1, NULL_TREE); }
        | IDENTIFIER
        ;
 
@@ -1359,7 +1782,13 @@ enum_head:
                { $$ = $2; }
        ;
 
-structsp:
+/* structsp_attr: struct/union/enum specifiers that either
+   end with attributes, or are such that any following attributes would
+   be parsed as part of the struct/union/enum specifier.
+
+   structsp_nonattr: other struct/union/enum specifiers.  */
+
+structsp_attr:
          struct_head identifier '{'
                { $$ = start_struct (RECORD_TYPE, $2);
                  /* Start scope of tag before parsing components.  */
@@ -1370,8 +1799,6 @@ structsp:
                { $$ = finish_struct (start_struct (RECORD_TYPE, NULL_TREE),
                                      $3, chainon ($1, $5));
                }
-       | struct_head identifier
-               { $$ = xref_tag (RECORD_TYPE, $2); }
        | union_head identifier '{'
                { $$ = start_struct (UNION_TYPE, $2); }
          component_decl_list '}' maybe_attribute
@@ -1380,8 +1807,6 @@ structsp:
                { $$ = finish_struct (start_struct (UNION_TYPE, NULL_TREE),
                                      $3, chainon ($1, $5));
                }
-       | union_head identifier
-               { $$ = xref_tag (UNION_TYPE, $2); }
        | enum_head identifier '{'
                { $$ = start_enum ($2); }
          enumlist maybecomma_warn '}' maybe_attribute
@@ -1392,8 +1817,19 @@ structsp:
          enumlist maybecomma_warn '}' maybe_attribute
                { $$ = finish_enum ($<ttype>3, nreverse ($4),
                                    chainon ($1, $7)); }
+       ;
+
+structsp_nonattr:
+         struct_head identifier
+               { $$ = xref_tag (RECORD_TYPE, $2); }
+       | union_head identifier
+               { $$ = xref_tag (UNION_TYPE, $2); }
        | enum_head identifier
-               { $$ = xref_tag (ENUMERAL_TYPE, $2); }
+               { $$ = xref_tag (ENUMERAL_TYPE, $2);
+                 /* In ISO C, enumerated types can be referred to
+                    only if already defined.  */
+                 if (pedantic && !COMPLETE_TYPE_P ($$))
+                   pedwarn ("ISO C forbids forward references to `enum' types"); }
        ;
 
 maybecomma:
@@ -1441,22 +1877,13 @@ ifobjc
 end ifobjc
        ;
 
-/* There is a shift-reduce conflict here, because `components' may
-   start with a `typename'.  It happens that shifting (the default resolution)
-   does the right thing, because it treats the `typename' as part of
-   a `typed_typespecs'.
-
-   It is possible that this same technique would allow the distinction
-   between `notype_initdecls' and `initdecls' to be eliminated.
-   But I am being cautious and not trying it.  */
-
 component_decl:
-         typed_typespecs setspecs components
+         declspecs_nosc_ts setspecs components
                { $$ = $3;
                  current_declspecs = TREE_VALUE (declspec_stack);
                  prefix_attributes = TREE_PURPOSE (declspec_stack);
                  declspec_stack = TREE_CHAIN (declspec_stack); }
-       | typed_typespecs setspecs save_filename save_lineno maybe_attribute
+       | declspecs_nosc_ts setspecs save_filename save_lineno
                {
                  /* Support for unnamed structs or unions as members of 
                     structs or unions (which is [a] useful and [b] supports 
@@ -1469,12 +1896,12 @@ component_decl:
                  prefix_attributes = TREE_PURPOSE (declspec_stack);
                  declspec_stack = TREE_CHAIN (declspec_stack);
                }
-    | nonempty_type_quals setspecs components
+       | declspecs_nosc_nots setspecs components_notype
                { $$ = $3;
                  current_declspecs = TREE_VALUE (declspec_stack);
                  prefix_attributes = TREE_PURPOSE (declspec_stack);
                  declspec_stack = TREE_CHAIN (declspec_stack); }
-       | nonempty_type_quals
+       | declspecs_nosc_nots
                { if (pedantic)
                    pedwarn ("ISO C forbids member declarations with no members");
                  shadow_tag($1);
@@ -1488,8 +1915,14 @@ component_decl:
 
 components:
          component_declarator
-       | components ',' component_declarator
-               { $$ = chainon ($1, $3); }
+       | components ',' maybe_setattrs component_declarator
+               { $$ = chainon ($1, $4); }
+       ;
+
+components_notype:
+         component_notype_declarator
+       | components_notype ',' maybe_setattrs component_notype_declarator
+               { $$ = chainon ($1, $4); }
        ;
 
 component_declarator:
@@ -1505,6 +1938,19 @@ component_declarator:
                  decl_attributes ($$, $5, prefix_attributes); }
        ;
 
+component_notype_declarator:
+         save_filename save_lineno notype_declarator maybe_attribute
+               { $$ = grokfield ($1, $2, $3, current_declspecs, NULL_TREE);
+                 decl_attributes ($$, $4, prefix_attributes); }
+       | save_filename save_lineno
+         notype_declarator ':' expr_no_commas maybe_attribute
+               { $$ = grokfield ($1, $2, $3, current_declspecs, $5);
+                 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, prefix_attributes); }
+       ;
+
 /* We chain the enumerators in reverse order.
    They are put in forward order where enumlist is used.
    (The order used to be significant, but no longer is so.
@@ -1530,10 +1976,16 @@ enumerator:
        ;
 
 typename:
-       typed_typespecs absdcl
-               { $$ = build_tree_list ($1, $2); }
-       | nonempty_type_quals absdcl
-               { $$ = build_tree_list ($1, $2); }
+         declspecs_nosc
+               { tree specs, attrs;
+                 pending_xref_error ();
+                 split_specs_attrs ($1, &specs, &attrs);
+                 /* We don't yet support attributes here.  */
+                 if (attrs != NULL_TREE)
+                   warning ("attributes on type name ignored");
+                 $<ttype>$ = specs; }
+         absdcl
+               { $$ = build_tree_list ($<ttype>2, $3); }
        ;
 
 absdcl:   /* an absolute declarator */
@@ -1542,69 +1994,109 @@ absdcl:   /* an absolute declarator */
        | absdcl1
        ;
 
-nonempty_type_quals:
-         TYPE_QUAL
-               { $$ = tree_cons (NULL_TREE, $1, NULL_TREE); }
-       | nonempty_type_quals TYPE_QUAL
-               { $$ = tree_cons (NULL_TREE, $2, $1); }
+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_noea attributes
+               { $$ = build_tree_list (build_tree_list (current_declspecs,
+                                                        $1),
+                                       build_tree_list (prefix_attributes,
+                                                        $2)); }
        ;
 
-type_quals:
-         /* empty */
-               { $$ = NULL_TREE; }
-       | type_quals TYPE_QUAL
-               { $$ = tree_cons (NULL_TREE, $2, $1); }
+absdcl1:  /* a nonempty absolute declarator */
+         absdcl1_ea
+       | absdcl1_noea
        ;
 
-absdcl1:  /* a nonempty absolute declarator */
-         '(' absdcl1 ')'
-               { $$ = $2; }
-         /* `(typedef)1' is `int'.  */
-       | '*' type_quals absdcl1  %prec UNARY
+absdcl1_noea:
+         direct_absdcl1
+       | '*' maybe_type_quals_setattrs absdcl1_noea
                { $$ = make_pointer_declarator ($2, $3); }
-       | '*' type_quals  %prec UNARY
+       ;
+
+absdcl1_ea:
+         '*' maybe_type_quals_setattrs
                { $$ = make_pointer_declarator ($2, NULL_TREE); }
-       | absdcl1 '(' parmlist  %prec '.'
+       | '*' maybe_type_quals_setattrs absdcl1_ea
+               { $$ = make_pointer_declarator ($2, $3); }
+       ;
+
+direct_absdcl1:
+         '(' maybe_setattrs absdcl1 ')'
+               { $$ = $3; }
+       | direct_absdcl1 '(' parmlist
                { $$ = build_nt (CALL_EXPR, $1, $3, NULL_TREE); }
-       | absdcl1 '[' expr ']'  %prec '.'
+       | direct_absdcl1 '[' expr ']'
                { $$ = build_nt (ARRAY_REF, $1, $3); }
-       | absdcl1 '[' ']'  %prec '.'
+       | direct_absdcl1 '[' ']'
                { $$ = build_nt (ARRAY_REF, $1, NULL_TREE); }
-       | '(' parmlist  %prec '.'
+       | '(' parmlist
                { $$ = build_nt (CALL_EXPR, NULL_TREE, $2, NULL_TREE); }
-       | '[' expr ']'  %prec '.'
+       | '[' expr ']'
                { $$ = 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; }
-       ;
 
-/* at least one statement, the first of which parses without error.  */
-/* stmts is used only after decls, so an invalid first statement
-   is actually regarded as an invalid decl and part of the decls.  */
+/* A nonempty series of declarations and statements (possibly followed by
+   some labels) that can form the body of a compound statement.
+   NOTE: we don't allow labels on declarations; this might seem like a
+   natural extension, but there would be a conflict between attributes
+   on the label and prefix attributes on the declaration.  */
 
-stmts:
-       lineno_stmt_or_labels
+stmts_and_decls:
+         lineno_stmt_decl_or_labels_ending_stmt
+       | lineno_stmt_decl_or_labels_ending_decl
+       | lineno_stmt_decl_or_labels_ending_label
                {
-                 if (pedantic && $1)
-                   pedwarn ("ISO C forbids label at end of compound statement");
+                 pedwarn ("deprecated use of label at end of compound statement");
                }
+       | lineno_stmt_decl_or_labels_ending_error
        ;
 
-lineno_stmt_or_labels:
-         lineno_stmt_or_label
-       | lineno_stmt_or_labels lineno_stmt_or_label
-               { $$ = $2; }
-       | lineno_stmt_or_labels errstmt
-               { $$ = 0; }
+lineno_stmt_decl_or_labels_ending_stmt:
+         lineno_stmt
+       | lineno_stmt_decl_or_labels_ending_stmt lineno_stmt
+       | lineno_stmt_decl_or_labels_ending_decl lineno_stmt
+       | lineno_stmt_decl_or_labels_ending_label lineno_stmt
+       | lineno_stmt_decl_or_labels_ending_error lineno_stmt
        ;
 
-xstmts:
-       /* empty */
-       | stmts
+lineno_stmt_decl_or_labels_ending_decl:
+         lineno_decl
+       | lineno_stmt_decl_or_labels_ending_stmt lineno_decl
+               { if (pedantic && !flag_isoc99)
+                   pedwarn ("ISO C89 forbids mixed declarations and code"); }
+       | lineno_stmt_decl_or_labels_ending_decl lineno_decl
+       | lineno_stmt_decl_or_labels_ending_error lineno_decl
+       ;
+
+lineno_stmt_decl_or_labels_ending_label:
+         lineno_label
+       | lineno_stmt_decl_or_labels_ending_stmt lineno_label
+       | lineno_stmt_decl_or_labels_ending_decl lineno_label
+       | lineno_stmt_decl_or_labels_ending_label lineno_label
+       | lineno_stmt_decl_or_labels_ending_error lineno_label
+       ;
+
+lineno_stmt_decl_or_labels_ending_error:
+       errstmt
+       | lineno_stmt_decl_or_labels errstmt
+       ;
+
+lineno_stmt_decl_or_labels:
+         lineno_stmt_decl_or_labels_ending_stmt
+       | lineno_stmt_decl_or_labels_ending_decl
+       | lineno_stmt_decl_or_labels_ending_label
+       | lineno_stmt_decl_or_labels_ending_error
        ;
 
 errstmt:  error ';'
@@ -1697,23 +2189,18 @@ compstmt_start: '{' { compstmt_count++;
 
 compstmt_nostart: '}'
                { $$ = convert (void_type_node, integer_zero_node); }
-       | pushlevel maybe_label_decls decls xstmts '}' poplevel
-               { $$ = poplevel (1, 1, 0); 
-                 SCOPE_STMT_BLOCK (TREE_PURPOSE ($6)) 
-                   = SCOPE_STMT_BLOCK (TREE_VALUE ($6))
-                   = $$; }
-       | pushlevel maybe_label_decls error '}' poplevel
-               { $$ = poplevel (kept_level_p (), 0, 0); 
-                 SCOPE_STMT_BLOCK (TREE_PURPOSE ($5)) 
-                   = SCOPE_STMT_BLOCK (TREE_VALUE ($5))
-                   = $$; }
-       | pushlevel maybe_label_decls stmts '}' poplevel
-               { $$ = poplevel (kept_level_p (), 0, 0); 
+       | pushlevel maybe_label_decls compstmt_contents_nonempty '}' poplevel
+               { $$ = poplevel (kept_level_p (), 1, 0); 
                  SCOPE_STMT_BLOCK (TREE_PURPOSE ($5)) 
                    = SCOPE_STMT_BLOCK (TREE_VALUE ($5))
                    = $$; }
        ;
 
+compstmt_contents_nonempty:
+         stmts_and_decls
+       | error
+       ;
+
 compstmt_primary_start:
        '(' '{'
                { if (current_function_decl == 0)
@@ -1733,7 +2220,7 @@ compstmt_primary_start:
 
 compstmt: compstmt_start compstmt_nostart
                { RECHAIN_STMTS ($1, COMPOUND_BODY ($1)); 
-                  $$ = $2; }
+                  $$ = $1; }
        ;
 
 /* Value is number of statements counted as of the closeparen.  */
@@ -1751,8 +2238,8 @@ if_prefix:
                { c_expand_start_cond (truthvalue_conversion ($3), 
                                       compstmt_count);
                  $<itype>$ = stmt_count;
-                 if_stmt_file = $<filename>-1;
-                 if_stmt_line = $<lineno>0; }
+                 if_stmt_file = $<filename>-2;
+                 if_stmt_line = $<lineno>-1; }
        ;
 
 /* This is a subroutine of stmt.
@@ -1791,13 +2278,8 @@ save_lineno:
        ;
 
 lineno_labeled_stmt:
-         save_filename save_lineno stmt
-               { }
-/*     | save_filename save_lineno error
-               { }
-*/
-       | save_filename save_lineno label lineno_labeled_stmt
-               { }
+         lineno_stmt
+       | lineno_label lineno_labeled_stmt
        ;
 
 /* Like lineno_labeled_stmt, but a block in C99.  */
@@ -1807,16 +2289,27 @@ c99_block_lineno_labeled_stmt:
                    RECHAIN_STMTS ($1, COMPOUND_BODY ($1)); }
        ;
 
-lineno_stmt_or_label:
-         save_filename save_lineno stmt_or_label
-               { $$ = $3; }
+lineno_stmt:
+         save_filename save_lineno stmt
+               { if ($3)
+                   {
+                     STMT_LINENO ($3) = $2;
+                     /* ??? We currently have no way of recording
+                        the filename for a statement.  This probably
+                        matters little in practice at the moment,
+                        but I suspect that problems will ocurr when
+                        doing inlining at the tree level.  */
+                   }
+               }
        ;
 
-stmt_or_label:
-         stmt
-               { $$ = 0; }
-       | label
-               { $$ = 1; }
+lineno_label:
+         save_filename save_lineno label
+               { if ($3)
+                   {
+                     STMT_LINENO ($3) = $2;
+                   }
+               }
        ;
 
 select_or_iter_stmt:
@@ -1856,19 +2349,19 @@ select_or_iter_stmt:
        | do_stmt_start error
                { }
        | FOR
-         '(' xexpr ';'
-               { stmt_count++;
-                 $3 = build_stmt (EXPR_STMT, $3); 
-                 $<ttype>$ = build_stmt (FOR_STMT, $3, NULL_TREE,
+               { $<ttype>$ = build_stmt (FOR_STMT, NULL_TREE, NULL_TREE,
                                          NULL_TREE, NULL_TREE);
-                 add_stmt ($<ttype>$);
-               }
+                 add_stmt ($<ttype>$); } 
+         '(' for_init_stmt
+               { stmt_count++;
+                 RECHAIN_STMTS ($<ttype>2, FOR_INIT_STMT ($<ttype>2)); }
          xexpr ';'
-                { FOR_COND ($<ttype>5) = $6; }
+                { if ($6) 
+                   FOR_COND ($<ttype>2) = truthvalue_conversion ($6); }
          xexpr ')'
-               { FOR_EXPR ($<ttype>5) = $9; }
+               { FOR_EXPR ($<ttype>2) = $9; }
          c99_block_lineno_labeled_stmt
-                { RECHAIN_STMTS ($<ttype>5, FOR_BODY ($<ttype>5)); }
+                { RECHAIN_STMTS ($<ttype>2, FOR_BODY ($<ttype>2)); }
        | SWITCH '(' expr ')'
                { stmt_count++;
                  $<ttype>$ = c_start_case ($3); }
@@ -1876,63 +2369,53 @@ select_or_iter_stmt:
                 { c_finish_case (); }
        ;
 
+for_init_stmt:
+         xexpr ';'
+               { add_stmt (build_stmt (EXPR_STMT, $1)); } 
+       | decl
+               { check_for_loop_decls (); }
+       ;
+
 /* Parse a single real statement, not including any labels.  */
 stmt:
          compstmt
-               { stmt_count++; }
+               { stmt_count++; $$ = $1; }
        | expr ';'
                { stmt_count++;
-                 c_expand_expr_stmt ($1); }
+                 $$ = c_expand_expr_stmt ($1); }
        | c99_block_start select_or_iter_stmt c99_block_end
                { if (flag_isoc99)
-                   RECHAIN_STMTS ($1, COMPOUND_BODY ($1)); }
+                   RECHAIN_STMTS ($1, COMPOUND_BODY ($1));
+                 $$ = NULL_TREE; }
        | BREAK ';'
                { stmt_count++;
-                 add_stmt (build_break_stmt ()); }
+                 $$ = add_stmt (build_break_stmt ()); }
        | CONTINUE ';'
                 { stmt_count++;
-                 add_stmt (build_continue_stmt ()); }
+                 $$ = add_stmt (build_continue_stmt ()); }
        | RETURN ';'
                 { stmt_count++;
-                 c_expand_return (NULL_TREE); }
+                 $$ = c_expand_return (NULL_TREE); }
        | RETURN expr ';'
                 { stmt_count++;
-                 c_expand_return ($2); }
+                 $$ = c_expand_return ($2); }
        | ASM_KEYWORD maybe_type_qual '(' expr ')' ';'
                { stmt_count++;
-                 STRIP_NOPS ($4);
-                 if ((TREE_CODE ($4) == ADDR_EXPR
-                      && TREE_CODE (TREE_OPERAND ($4, 0)) == STRING_CST)
-                     || TREE_CODE ($4) == STRING_CST)
-                   {
-                     if (TREE_CODE ($4) == ADDR_EXPR)
-                       $4 = TREE_OPERAND ($4, 0);
-                     if (TREE_CHAIN ($4))
-                       $4 = combine_strings ($4);
-                     add_stmt (build_stmt (ASM_STMT, NULL_TREE, $4,
-                                           NULL_TREE, NULL_TREE, NULL_TREE));
-                   }
-                 else
-                   error ("argument of `asm' is not a constant string"); }
+                 $$ = simple_asm_stmt ($4); }
        /* This is the case with just output operands.  */
        | ASM_KEYWORD maybe_type_qual '(' expr ':' asm_operands ')' ';'
                { stmt_count++;
-                 c_expand_asm_operands ($4, $6, NULL_TREE, NULL_TREE,
-                                        $2 == ridpointers[(int)RID_VOLATILE],
-                                        input_filename, lineno); }
+                 $$ = build_asm_stmt ($2, $4, $6, NULL_TREE, NULL_TREE); }
        /* This is the case with input operands as well.  */
-       | ASM_KEYWORD maybe_type_qual '(' expr ':' asm_operands ':' asm_operands ')' ';'
+       | ASM_KEYWORD maybe_type_qual '(' expr ':' asm_operands ':'
+         asm_operands ')' ';'
                { stmt_count++;
-                 c_expand_asm_operands ($4, $6, $8, NULL_TREE,
-                                        $2 == ridpointers[(int)RID_VOLATILE],
-                                        input_filename, lineno); }
+                 $$ = build_asm_stmt ($2, $4, $6, $8, NULL_TREE); }
        /* This is the case with clobbered registers as well.  */
        | ASM_KEYWORD maybe_type_qual '(' expr ':' asm_operands ':'
          asm_operands ':' asm_clobbers ')' ';'
                { stmt_count++;
-                 c_expand_asm_operands ($4, $6, $8, $10,
-                                        $2 == ridpointers[(int)RID_VOLATILE],
-                                        input_filename, lineno); }
+                 $$ = build_asm_stmt ($2, $4, $6, $8, $10); }
        | GOTO identifier ';'
                { tree decl;
                  stmt_count++;
@@ -1940,16 +2423,19 @@ stmt:
                  if (decl != 0)
                    {
                      TREE_USED (decl) = 1;
-                     add_stmt (build_stmt (GOTO_STMT, decl));
+                     $$ = add_stmt (build_stmt (GOTO_STMT, decl));
                    }
+                 else
+                   $$ = NULL_TREE;
                }
        | GOTO '*' expr ';'
                { if (pedantic)
                    pedwarn ("ISO C forbids `goto *expr;'");
                  stmt_count++;
                  $3 = convert (ptr_type_node, $3);
-                 add_stmt (build_stmt (GOTO_STMT, $3)); }
+                 $$ = add_stmt (build_stmt (GOTO_STMT, $3)); }
        | ';'
+               { $$ = NULL_TREE; }
        ;
 
 /* Any kind of label, including jump labels and case labels.
@@ -1958,21 +2444,23 @@ stmt:
 
 label:   CASE expr_no_commas ':'
                 { stmt_count++;
-                 do_case ($2, NULL_TREE); }
+                 $$ = do_case ($2, NULL_TREE); }
        | CASE expr_no_commas ELLIPSIS expr_no_commas ':'
                 { stmt_count++;
-                 do_case ($2, $4); }
+                 $$ = do_case ($2, $4); }
        | DEFAULT ':'
                 { stmt_count++;
-                 do_case (NULL_TREE, NULL_TREE); }
+                 $$ = do_case (NULL_TREE, NULL_TREE); }
        | identifier save_filename save_lineno ':' maybe_attribute
                { tree label = define_label ($2, $3, $1);
                  stmt_count++;
                  if (label)
                    {
                      decl_attributes (label, $5, NULL_TREE);
-                     add_stmt (build_stmt (LABEL_STMT, label));
+                     $$ = add_stmt (build_stmt (LABEL_STMT, label));
                    }
+                 else
+                   $$ = NULL_TREE;
                }
        ;
 
@@ -2018,13 +2506,17 @@ asm_clobbers:
        ;
 \f
 /* This is what appears inside the parens in a function declarator.
-   Its value is a list of ..._TYPE nodes.  */
+   Its value is a list of ..._TYPE nodes.  Attributes must appear here
+   to avoid a conflict with their appearance after an open parenthesis
+   in an abstract declarator, as in
+   "void bar (int (__attribute__((__mode__(SI))) int foo));".  */
 parmlist:
+         maybe_attribute
                { pushlevel (0);
                  clear_parm_order ();
                  declare_parm_level (0); }
          parmlist_1
-               { $$ = $2;
+               { $$ = $3;
                  parmlist_tags_warning ();
                  poplevel (0, 0, 0); }
        ;
@@ -2039,8 +2531,11 @@ parmlist_1:
                  for (parm = getdecls (); parm; parm = TREE_CHAIN (parm))
                    TREE_ASM_WRITTEN (parm) = 1;
                  clear_parm_order (); }
+         maybe_attribute
+               { /* Dummy action so attributes are in known place
+                    on parser stack.  */ }
          parmlist_1
-               { $$ = $4; }
+               { $$ = $6; }
        | error ')'
                { $$ = tree_cons (NULL_TREE, NULL_TREE, NULL_TREE); }
        ;
@@ -2066,7 +2561,7 @@ parmlist_2:  /* empty */
        ;
 
 parms:
-       parm
+       firstparm
                { push_parm_decl ($1); }
        | parms ',' parm
                { push_parm_decl ($3); }
@@ -2075,7 +2570,7 @@ parms:
 /* A single parameter declaration or parameter type name,
    as found in a parmlist.  */
 parm:
-         typed_declspecs setspecs parm_declarator maybe_attribute
+         declspecs_ts setspecs parm_declarator maybe_attribute
                { $$ = build_tree_list (build_tree_list (current_declspecs,
                                                         $3),
                                        build_tree_list (prefix_attributes,
@@ -2083,7 +2578,7 @@ parm:
                  current_declspecs = TREE_VALUE (declspec_stack);
                  prefix_attributes = TREE_PURPOSE (declspec_stack);
                  declspec_stack = TREE_CHAIN (declspec_stack); }
-       | typed_declspecs setspecs notype_declarator maybe_attribute
+       | declspecs_ts setspecs notype_declarator maybe_attribute
                { $$ = build_tree_list (build_tree_list (current_declspecs,
                                                         $3),
                                        build_tree_list (prefix_attributes,
@@ -2091,7 +2586,12 @@ 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
+       | declspecs_ts setspecs absdcl_maybe_attribute
+               { $$ = $3;
+                 current_declspecs = TREE_VALUE (declspec_stack);
+                 prefix_attributes = TREE_PURPOSE (declspec_stack);
+                 declspec_stack = TREE_CHAIN (declspec_stack); }
+       | declspecs_nots setspecs notype_declarator maybe_attribute
                { $$ = build_tree_list (build_tree_list (current_declspecs,
                                                         $3),
                                        build_tree_list (prefix_attributes,
@@ -2099,7 +2599,18 @@ parm:
                  current_declspecs = TREE_VALUE (declspec_stack);
                  prefix_attributes = TREE_PURPOSE (declspec_stack);
                  declspec_stack = TREE_CHAIN (declspec_stack); }
-       | declmods setspecs notype_declarator maybe_attribute
+
+       | declspecs_nots setspecs absdcl_maybe_attribute
+               { $$ = $3;
+                 current_declspecs = TREE_VALUE (declspec_stack);
+                 prefix_attributes = TREE_PURPOSE (declspec_stack);
+                 declspec_stack = TREE_CHAIN (declspec_stack); }
+       ;
+
+/* The first parm, which must suck attributes from off the top of the parser
+   stack.  */
+firstparm:
+         declspecs_ts_nosa setspecs_fp parm_declarator maybe_attribute
                { $$ = build_tree_list (build_tree_list (current_declspecs,
                                                         $3),
                                        build_tree_list (prefix_attributes,
@@ -2107,8 +2618,20 @@ parm:
                  current_declspecs = TREE_VALUE (declspec_stack);
                  prefix_attributes = TREE_PURPOSE (declspec_stack);
                  declspec_stack = TREE_CHAIN (declspec_stack); }
-
-       | declmods setspecs absdcl maybe_attribute
+       | declspecs_ts_nosa setspecs_fp 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); }
+       | declspecs_ts_nosa setspecs_fp absdcl_maybe_attribute
+               { $$ = $3;
+                 current_declspecs = TREE_VALUE (declspec_stack);
+                 prefix_attributes = TREE_PURPOSE (declspec_stack);
+                 declspec_stack = TREE_CHAIN (declspec_stack); }
+       | declspecs_nots_nosa setspecs_fp notype_declarator maybe_attribute
                { $$ = build_tree_list (build_tree_list (current_declspecs,
                                                         $3),
                                        build_tree_list (prefix_attributes,
@@ -2116,6 +2639,17 @@ parm:
                  current_declspecs = TREE_VALUE (declspec_stack);
                  prefix_attributes = TREE_PURPOSE (declspec_stack);
                  declspec_stack = TREE_CHAIN (declspec_stack); }
+
+       | declspecs_nots_nosa setspecs_fp absdcl_maybe_attribute
+               { $$ = $3;
+                 current_declspecs = TREE_VALUE (declspec_stack);
+                 prefix_attributes = TREE_PURPOSE (declspec_stack);
+                 declspec_stack = TREE_CHAIN (declspec_stack); }
+       ;
+
+setspecs_fp:
+         setspecs
+               { prefix_attributes = chainon (prefix_attributes, $<ttype>-2); }
        ;
 
 /* This is used in a function definition
@@ -2332,13 +2866,13 @@ classdef:
 protocoldef:
          PROTOCOL identifier protocolrefs
                {
-                 remember_protocol_qualifiers ();
+                 objc_pq_context = 1;
                  objc_interface_context
                    = start_protocol(PROTOCOL_INTERFACE_TYPE, $2, $3);
                }
          methodprotolist END
                {
-                 forget_protocol_qualifiers();
+                 objc_pq_context = 0;
                  finish_protocol(objc_interface_context);
                  objc_interface_context = NULL_TREE;
                }
@@ -2397,12 +2931,12 @@ ivar_decls:
    But I am being cautious and not trying it.  */
 
 ivar_decl:
-       typed_typespecs setspecs ivars
+       declspecs_nosc_ts setspecs ivars
                { $$ = $3;
                  current_declspecs = TREE_VALUE (declspec_stack);
                  prefix_attributes = TREE_PURPOSE (declspec_stack);
                  declspec_stack = TREE_CHAIN (declspec_stack); }
-       | nonempty_type_quals setspecs ivars
+       | declspecs_nosc_nots setspecs ivars
                { $$ = $3;
                  current_declspecs = TREE_VALUE (declspec_stack);
                  prefix_attributes = TREE_PURPOSE (declspec_stack);
@@ -2415,7 +2949,7 @@ ivars:
          /* empty */
                { $$ = NULL_TREE; }
        | ivar_declarator
-       | ivars ',' ivar_declarator
+       | ivars ',' maybe_setattrs ivar_declarator
        ;
 
 ivar_declarator:
@@ -2441,44 +2975,27 @@ ivar_declarator:
                 }
        ;
 
-methoddef:
+methodtype:
          '+'
-               {
-                 remember_protocol_qualifiers ();
-                 if (objc_implementation_context)
-                   objc_inherit_code = CLASS_METHOD_DECL;
-                  else
-                   fatal ("method definition not in class context");
-               }
-         methoddecl
-               {
-                 forget_protocol_qualifiers ();
-                 add_class_method (objc_implementation_context, $3);
-                 start_method_def ($3);
-                 objc_method_context = $3;
-               }
-         optarglist
-               {
-                 continue_method_def ();
-               }
-         compstmt_or_error
-               {
-                 finish_method_def ();
-                 objc_method_context = NULL_TREE;
-               }
-
+               { objc_inherit_code = CLASS_METHOD_DECL; }
        | '-'
+               { objc_inherit_code = INSTANCE_METHOD_DECL; }
+       ;
+
+methoddef:
+         methodtype
                {
-                 remember_protocol_qualifiers ();
-                 if (objc_implementation_context)
-                   objc_inherit_code = INSTANCE_METHOD_DECL;
-                  else
-                   fatal ("method definition not in class context");
+                 objc_pq_context = 1;
+                 if (!objc_implementation_context)
+                   fatal_error ("method definition not in class context");
                }
          methoddecl
                {
-                 forget_protocol_qualifiers ();
-                 add_instance_method (objc_implementation_context, $3);
+                 objc_pq_context = 0;
+                 if (objc_inherit_code == CLASS_METHOD_DECL)
+                   add_class_method (objc_implementation_context, $3);
+                 else
+                   add_instance_method (objc_implementation_context, $3);
                  start_method_def ($3);
                  objc_method_context = $3;
                }
@@ -2515,31 +3032,19 @@ semi_or_error:
        ;
 
 methodproto:
-         '+'
-               {
-                 /* Remember protocol qualifiers in prototypes.  */
-                 remember_protocol_qualifiers ();
-                 objc_inherit_code = CLASS_METHOD_DECL;
-               }
-         methoddecl
-               {
-                 /* Forget protocol qualifiers here.  */
-                 forget_protocol_qualifiers ();
-                 add_class_method (objc_interface_context, $3);
-               }
-         semi_or_error
-
-       | '-'
+         methodtype
                {
                  /* Remember protocol qualifiers in prototypes.  */
-                 remember_protocol_qualifiers ();
-                 objc_inherit_code = INSTANCE_METHOD_DECL;
+                 objc_pq_context = 1;
                }
          methoddecl
                {
                  /* Forget protocol qualifiers here.  */
-                 forget_protocol_qualifiers ();
-                 add_instance_method (objc_interface_context, $3);
+                 objc_pq_context = 0;
+                 if (objc_inherit_code == CLASS_METHOD_DECL)
+                   add_class_method (objc_interface_context, $3);
+                 else
+                   add_instance_method (objc_interface_context, $3);
                }
          semi_or_error
        ;
@@ -2590,13 +3095,13 @@ mydecls:
        ;
 
 mydecl:
-       typed_declspecs setspecs myparms ';'
+       declspecs_ts setspecs myparms ';'
                { current_declspecs = TREE_VALUE (declspec_stack);
                  prefix_attributes = TREE_PURPOSE (declspec_stack);
                  declspec_stack = TREE_CHAIN (declspec_stack); }
-       | typed_declspecs ';'
+       | declspecs_ts ';'
                { shadow_tag ($1); }
-       | declmods ';'
+       | declspecs_nots ';'
                { pedwarn ("empty declaration"); }
        ;
 
@@ -2621,11 +3126,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:
@@ -2809,9 +3311,6 @@ end ifobjc
    cpplib.h's token codes into yacc's token codes.  */
 
 static enum cpp_ttype last_token;
-#if USE_CPPLIB
-extern cpp_reader parse_in;
-#endif
 
 /* The reserved keyword table.  */
 struct resword
@@ -2828,12 +3327,13 @@ struct resword
 #define D_EXT  0x04    /* GCC extension */
 #define D_EXT89        0x08    /* GCC extension incorporated in C99 */
 #define D_OBJC 0x10    /* Objective C only */
-#define D_YES  0x20    /* always starts disabled */
 
 static const struct resword reswords[] =
 {
   { "_Bool",           RID_BOOL,       0 },
   { "_Complex",                RID_COMPLEX,    0 },
+  { "__FUNCTION__",    RID_FUNCTION_NAME, 0 },
+  { "__PRETTY_FUNCTION__", RID_PRETTY_FUNCTION_NAME, 0 },
   { "__alignof",       RID_ALIGNOF,    0 },
   { "__alignof__",     RID_ALIGNOF,    0 },
   { "__asm",           RID_ASM,        0 },
@@ -2848,6 +3348,7 @@ static const struct resword reswords[] =
   { "__const",         RID_CONST,      0 },
   { "__const__",       RID_CONST,      0 },
   { "__extension__",   RID_EXTENSION,  0 },
+  { "__func__",                RID_C99_FUNCTION_NAME, 0 },
   { "__imag",          RID_IMAGPART,   0 },
   { "__imag__",                RID_IMAGPART,   0 },
   { "__inline",                RID_INLINE,     0 },
@@ -2921,12 +3422,12 @@ ifobjc
   { "@public",         RID_AT_PUBLIC,          D_OBJC },
   { "@selector",       RID_AT_SELECTOR,        D_OBJC },
   { "id",              RID_ID,                 D_OBJC },
-  { "bycopy",          RID_BYCOPY,             D_OBJC|D_YES },
-  { "byref",           RID_BYREF,              D_OBJC|D_YES },
-  { "in",              RID_IN,                 D_OBJC|D_YES },
-  { "inout",           RID_INOUT,              D_OBJC|D_YES },
-  { "oneway",          RID_ONEWAY,             D_OBJC|D_YES },
-  { "out",             RID_OUT,                D_OBJC|D_YES },
+  { "bycopy",          RID_BYCOPY,             D_OBJC },
+  { "byref",           RID_BYREF,              D_OBJC },
+  { "in",              RID_IN,                 D_OBJC },
+  { "inout",           RID_INOUT,              D_OBJC },
+  { "oneway",          RID_ONEWAY,             D_OBJC },
+  { "out",             RID_OUT,                D_OBJC },
 end ifobjc
 };
 #define N_reswords (sizeof reswords / sizeof (struct resword))
@@ -3007,6 +3508,10 @@ static const short rid_to_yy[RID_MAX] =
   /* RID_PTREXTENT */  PTR_EXTENT,
   /* RID_PTRVALUE */   PTR_VALUE,
 
+  /* RID_FUNCTION_NAME */              STRING_FUNC_NAME,
+  /* RID_PRETTY_FUNCTION_NAME */       STRING_FUNC_NAME,
+  /* RID_C99_FUNCTION_NAME */          VAR_FUNC_NAME,
+
   /* C++ */
   /* RID_BOOL */       TYPESPEC,
   /* RID_WCHAR */      0,
@@ -3048,7 +3553,7 @@ static const short rid_to_yy[RID_MAX] =
   /* RID_BITAND */     0,
   /* RID_BITOR */      0,
   /* RID_COMPL */      0,
-
+  
   /* Objective C */
   /* RID_ID */                 OBJECTNAME,
   /* RID_AT_ENCODE */          ENCODE,
@@ -3065,15 +3570,24 @@ static const short rid_to_yy[RID_MAX] =
   /* RID_AT_IMPLEMENTATION */  IMPLEMENTATION
 };
 
+ifobjc
+/* Lookup table for ObjC keywords beginning with '@'.  Crude but
+   hopefully effective.  */
+#define N_at_reswords ((int) RID_AT_IMPLEMENTATION - (int)RID_AT_ENCODE + 1)
+static tree objc_rid_sans_at[N_at_reswords];
+end ifobjc
+
 static void
 init_reswords ()
 {
   unsigned int i;
   tree id;
-  int mask = ((doing_objc_thang ? 0 : D_OBJC)
-             | (flag_isoc99 ? 0 : D_C89)
+  int mask = (flag_isoc99 ? 0 : D_C89)
              | (flag_traditional ? D_TRAD : 0)
-             | (flag_no_asm ? (flag_isoc99 ? D_EXT : D_EXT|D_EXT89) : 0));
+             | (flag_no_asm ? (flag_isoc99 ? D_EXT : D_EXT|D_EXT89) : 0);
+
+  if (c_language != clk_objective_c)
+     mask |= D_OBJC;
 
   /* It is not necessary to register ridpointers as a GC root, because
      all the trees it points to are permanently interned in the
@@ -3088,13 +3602,18 @@ init_reswords ()
 
       id = get_identifier (reswords[i].word);
       C_RID_CODE (id) = reswords[i].rid;
+      C_IS_RESERVED_WORD (id) = 1;
       ridpointers [(int) reswords[i].rid] = id;
 
-      /* Objective C does tricky things with enabling and disabling 
-        keywords.  So these we must not elide in the test above, but
-        wait and not mark them reserved now.  */
-      if (! (reswords[i].disable & D_YES))
-       C_IS_RESERVED_WORD (id) = 1;
+ifobjc
+      /* Enter ObjC @-prefixed keywords into the "sans" table
+        _without_ their leading at-sign.  Again, all these
+        identifiers are reachable by the get_identifer table, so it's
+        not necessary to make objc_rid_sans_at a GC root.  */
+      if (reswords[i].word[0] == '@')
+       objc_rid_sans_at[(int) reswords[i].rid - (int) RID_AT_ENCODE]
+         = get_identifier (reswords[i].word + 1);
+end ifobjc
     }
 }
 
@@ -3116,25 +3635,12 @@ init_parse (filename)
 void
 finish_parse ()
 {
-#if USE_CPPLIB
-  cpp_finish (&parse_in);
-  errorcount += parse_in.errors;
-#else
-  fclose (finput);
-#endif
+  cpp_finish (parse_in);
+  /* Call to cpp_destroy () omitted for performance reasons.  */
+  errorcount += cpp_errors (parse_in);
 }
 
-#if USE_CPPLIB
 #define NAME(type) cpp_type2name (type)
-#else
-/* Bleah */
-#include "symcat.h"
-#define OP(e, s) s,
-#define TK(e, s) STRINGX(e),
-
-static const char *type2name[N_TTYPES] = { TTYPE_TABLE };
-#define NAME(type) type2name[type]
-#endif
 
 static void
 yyerror (msgid)
@@ -3154,8 +3660,7 @@ yyerror (msgid)
        error ("%s before %s'\\x%x'", string, ell, val);
     }
   else if (last_token == CPP_STRING
-          || last_token == CPP_WSTRING
-          || last_token == CPP_OSTRING)
+          || last_token == CPP_WSTRING)
     error ("%s before string constant", string);
   else if (last_token == CPP_NUMBER
           || last_token == CPP_INT
@@ -3167,12 +3672,69 @@ yyerror (msgid)
     error ("%s before '%s' token", string, NAME(last_token));
 }
 
+static int
+yylexname ()
+{
+  tree decl;
+
+  if (C_IS_RESERVED_WORD (yylval.ttype))
+    {
+      enum rid rid_code = C_RID_CODE (yylval.ttype);
+
+ifobjc
+      if (!((unsigned int) rid_code - (unsigned int) RID_FIRST_PQ < 6)
+         || objc_pq_context)
+end ifobjc
+      {
+       int yycode = rid_to_yy[(int) rid_code];
+       if (yycode == STRING_FUNC_NAME)
+         {
+           /* __FUNCTION__ and __PRETTY_FUNCTION__ get converted
+              to string constants.  */
+           const char *name = fname_string (rid_code);
+         
+           yylval.ttype = build_string (strlen (name) + 1, name);
+           last_token = CPP_STRING;  /* so yyerror won't choke */
+           return STRING;
+         }
+      
+       /* Return the canonical spelling for this keyword.  */
+       yylval.ttype = ridpointers[(int) rid_code];
+       return yycode;
+      }
+    }
+
+  decl = lookup_name (yylval.ttype);
+  if (decl)
+    {
+      if (TREE_CODE (decl) == TYPE_DECL)
+       return TYPENAME;
+    }
+ifobjc
+  else
+    {
+      tree objc_interface_decl = is_class_name (yylval.ttype);
+
+      if (objc_interface_decl)
+       {
+         yylval.ttype = objc_interface_decl;
+         return CLASSNAME;
+       }
+    }
+end ifobjc
+
+  return IDENTIFIER;
+}
+
+
 static inline int
 _yylex ()
 {
retry:
get_next:
   last_token = c_lex (&yylval.ttype);
-
+ifobjc
+ reconsider:
+end ifobjc
   switch (last_token)
     {
     case CPP_EQ:                                       return '=';
@@ -3227,68 +3789,12 @@ _yylex ()
     case CPP_DOT:                                      return '.';
 
     case CPP_EOF:
-#if USE_CPPLIB
-      cpp_pop_buffer (&parse_in);
-      if (! CPP_BUFFER (&parse_in))
-#endif
+      if (cpp_pop_buffer (parse_in) == 0)
        return 0;
-      goto retry;
+      goto get_next;
 
     case CPP_NAME:
-      if (C_IS_RESERVED_WORD (yylval.ttype))
-       {
-         enum rid rid_code = C_RID_CODE (yylval.ttype);
-         /* Return the canonical spelling for this keyword.  */
-         yylval.ttype = ridpointers[(int) rid_code];
-         return rid_to_yy[(int) rid_code];
-       }
-
-      if (IDENTIFIER_POINTER (yylval.ttype)[0] == '@')
-       {
-         error ("invalid identifier `%s'", IDENTIFIER_POINTER (yylval.ttype));
-         return IDENTIFIER;
-       }
-
-      {
-       tree decl;
-
-       decl = lookup_name (yylval.ttype);
-
-       if (decl)
-         {
-           if (TREE_CODE (decl) == TYPE_DECL)
-             return TYPENAME;
-           /* A user-invisible read-only initialized variable
-              should be replaced by its value.
-              We handle only strings since that's the only case used in C.  */
-           else if (TREE_CODE (decl) == VAR_DECL
-                    && DECL_IGNORED_P (decl)
-                    && TREE_READONLY (decl)
-                    && DECL_INITIAL (decl) != 0
-                    && TREE_CODE (DECL_INITIAL (decl)) == STRING_CST)
-             {
-               tree stringval = DECL_INITIAL (decl);
-
-               /* Copy the string value so that we won't clobber anything
-                  if we put something in the TREE_CHAIN of this one.  */
-               yylval.ttype = build_string (TREE_STRING_LENGTH (stringval),
-                                            TREE_STRING_POINTER (stringval));
-               return STRING;
-             }
-         }
-       else if (doing_objc_thang)
-         {
-           tree objc_interface_decl = is_class_name (yylval.ttype);
-
-           if (objc_interface_decl)
-             {
-               yylval.ttype = objc_interface_decl;
-               return CLASSNAME;
-             }
-         }
-
-       return IDENTIFIER;
-      }
+      return yylexname ();
 
     case CPP_INT:
     case CPP_FLOAT:
@@ -3301,9 +3807,27 @@ _yylex ()
     case CPP_WSTRING:
       return STRING;
       
-    case CPP_OSTRING:
-      return OBJC_STRING;
-
+      /* This token is Objective-C specific.  It gives the next
+        token special significance.  */
+    case CPP_ATSIGN:
+ifobjc
+      last_token = c_lex (&yylval.ttype);
+      if (last_token == CPP_STRING)
+       return OBJC_STRING;
+      else if (last_token == CPP_NAME)
+       {
+         int i;
+         for (i = 0; i < N_at_reswords; i++)
+           if (objc_rid_sans_at[i] == yylval.ttype)
+             {
+               int rid_code = i + (int) RID_AT_ENCODE;
+               yylval.ttype = ridpointers[rid_code];
+               return rid_to_yy[rid_code];
+             }
+       }
+      error ("syntax error at '@' token");
+      goto reconsider;
+end ifobjc
       /* These tokens are C++ specific (and will not be generated
          in C mode, but let's be cautious).  */
     case CPP_SCOPE:
@@ -3316,13 +3840,12 @@ _yylex ()
       /* These tokens should not survive translation phase 4.  */
     case CPP_HASH:
     case CPP_PASTE:
-      error ("syntax error before '%s' token", NAME(last_token));
-      goto retry;
+      error ("syntax error at '%s' token", NAME(last_token));
+      goto get_next;
 
     default:
       abort ();
     }
-
   /* NOTREACHED */
 }