OSDN Git Service

* builtins.c, c-common.c, c-decl.c, c-format.c, c-format.h,
[pf3gnuchains/gcc-fork.git] / gcc / c-parse.in
index 7a68dbf..86880ac 100644 (file)
@@ -29,7 +29,7 @@ Software Foundation, 59 Temple Place - Suite 330, Boston, MA
    written by AT&T, but I have never seen it.  */
 
 @@ifc
-%expect 10 /* shift/reduce conflicts, and no reduce/reduce conflicts.  */
+%expect 13 /* shift/reduce conflicts, and no reduce/reduce conflicts.  */
 @@end_ifc
 
 %{
@@ -50,12 +50,8 @@ Software Foundation, 59 Temple Place - Suite 330, Boston, MA
 #include "output.h"
 #include "toplev.h"
 #include "ggc.h"
+#include "c-common.h"
 
-@@ifobjc
-#include "objc-act.h"
-@@end_ifobjc
-
-/* Like YYERROR but do call yyerror.  */
 #define YYERROR1 { yyerror ("syntax error"); YYERROR; }
 
 /* Like the default stack expander, except (1) use realloc when possible,
@@ -102,8 +98,11 @@ do {                                                                        \
 
 %start program
 
-%union {long itype; tree ttype; enum tree_code code;
-       location_t location; }
+%union {long itype; tree ttype; void *otype; struct c_expr exprtype;
+       struct c_arg_info *arginfotype; struct c_declarator *dtrtype;
+       struct c_type_name *typenametype; struct c_parm *parmtype;
+       struct c_declspecs *dsptype; struct c_typespec tstype;
+       enum tree_code code; location_t location; }
 
 /* All identifiers that are not reserved words
    and are not declared typedefs in the current block */
@@ -127,6 +126,10 @@ do {                                                                       \
    yylval contains an IDENTIFIER_NODE which indicates which one.  */
 %token TYPE_QUAL
 
+/* Objective-C protocol qualifiers.  These acquire their magic powers
+   only in certain contexts.  */
+%token OBJC_TYPE_QUAL
+
 /* Character or numeric constants.
    yylval is the node for the constant.  */
 %token CONSTANT
@@ -145,8 +148,7 @@ do {                                                                        \
 %token BREAK CONTINUE RETURN GOTO ASM_KEYWORD TYPEOF ALIGNOF
 %token ATTRIBUTE EXTENSION LABEL
 %token REALPART IMAGPART VA_ARG CHOOSE_EXPR TYPES_COMPATIBLE_P
-%token PTR_VALUE PTR_BASE PTR_EXTENT
-%token FUNC_NAME
+%token FUNC_NAME OFFSETOF
 
 /* Add precedence rules to solve dangling else s/r conflict */
 %nonassoc IF
@@ -174,8 +176,9 @@ do {                                                                        \
 
 /* The Objective-C keywords.  These are included in C and in
    Objective C, so that the token codes are the same in both.  */
-%token INTERFACE IMPLEMENTATION END SELECTOR DEFS ENCODE
-%token CLASSNAME PUBLIC PRIVATE PROTECTED PROTOCOL OBJECTNAME CLASS ALIAS
+%token AT_INTERFACE AT_IMPLEMENTATION AT_END AT_SELECTOR AT_DEFS AT_ENCODE
+%token CLASSNAME AT_PUBLIC AT_PRIVATE AT_PROTECTED AT_PROTOCOL
+%token AT_CLASS AT_ALIAS
 %token AT_THROW AT_TRY AT_CATCH AT_FINALLY AT_SYNCHRONIZED
 %token OBJC_STRING
 
@@ -183,88 +186,88 @@ do {                                                                      \
 %type <ttype> ENUM STRUCT UNION IF ELSE WHILE DO FOR SWITCH CASE DEFAULT
 %type <ttype> BREAK CONTINUE RETURN GOTO ASM_KEYWORD SIZEOF TYPEOF ALIGNOF
 
-%type <ttype> identifier IDENTIFIER TYPENAME CONSTANT expr nonnull_exprlist exprlist
-%type <ttype> expr_no_commas cast_expr unary_expr primary STRING
-%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_attrs typespec_nonattr typespec_attr
-%type <ttype> typespec_reserved_nonattr typespec_reserved_attr
-%type <ttype> typespec_nonreserved_nonattr
+%type <ttype> identifier IDENTIFIER TYPENAME CONSTANT STRING FUNC_NAME
+%type <ttype> nonnull_exprlist exprlist
+%type <exprtype> expr expr_no_commas cast_expr unary_expr primary
+%type <dsptype> declspecs_nosc_nots_nosa_noea declspecs_nosc_nots_nosa_ea
+%type <dsptype> declspecs_nosc_nots_sa_noea declspecs_nosc_nots_sa_ea
+%type <dsptype> declspecs_nosc_ts_nosa_noea declspecs_nosc_ts_nosa_ea
+%type <dsptype> declspecs_nosc_ts_sa_noea declspecs_nosc_ts_sa_ea
+%type <dsptype> declspecs_sc_nots_nosa_noea declspecs_sc_nots_nosa_ea
+%type <dsptype> declspecs_sc_nots_sa_noea declspecs_sc_nots_sa_ea
+%type <dsptype> declspecs_sc_ts_nosa_noea declspecs_sc_ts_nosa_ea
+%type <dsptype> declspecs_sc_ts_sa_noea declspecs_sc_ts_sa_ea
+%type <dsptype> declspecs_ts declspecs_nots
+%type <dsptype> declspecs_ts_nosa declspecs_nots_nosa
+%type <dsptype> declspecs_nosc_ts declspecs_nosc_nots declspecs_nosc declspecs
+%type <dsptype> maybe_type_quals_attrs
+%type <tstype> typespec_nonattr typespec_attr
+%type <tstype> typespec_reserved_nonattr typespec_reserved_attr
+%type <tstype> typespec_nonreserved_nonattr
+%type <ttype> offsetof_member_designator
 
 %type <ttype> scspec SCSPEC STATIC TYPESPEC TYPE_QUAL maybe_volatile
-%type <ttype> initdecls notype_initdecls initdcl notype_initdcl init
-%type <ttype> simple_asm_expr maybeasm asmdef asm_stmt asm_argument
+%type <ttype> initdecls notype_initdecls initdcl notype_initdcl
+%type <exprtype> init
+%type <ttype> simple_asm_expr maybeasm asm_stmt asm_argument
 %type <ttype> asm_operands nonnull_asm_operands asm_operand asm_clobbers
 %type <ttype> maybe_attribute attributes attribute attribute_list attrib
 %type <ttype> any_word
 
-%type <ttype> compstmt compstmt_start compstmt_nostart compstmt_primary_start
-%type <ttype> do_stmt_start poplevel stmt label
+%type <ttype> compstmt compstmt_start compstmt_primary_start
+%type <ttype> stmt label stmt_nocomp start_break start_continue
 
-%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> array_declarator
+%type <ttype> c99_block_start c99_block_lineno_labeled_stmt
+%type <ttype> if_statement_1 if_statement_2
+%type <dtrtype> declarator
+%type <dtrtype> notype_declarator after_type_declarator
+%type <dtrtype> parm_declarator
+%type <dtrtype> parm_declarator_starttypename parm_declarator_nostarttypename
+%type <dtrtype> array_declarator
 
-%type <ttype> structsp_attr structsp_nonattr
+%type <tstype> 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 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 <typenametype> typename
+%type <dtrtype> absdcl absdcl1 absdcl1_ea absdcl1_noea direct_absdcl1
+%type <parmtype> absdcl_maybe_attribute
+%type <ttype> condition xexpr for_cond_expr for_incr_expr
+%type <parmtype> parm firstparm
+%type <ttype> identifiers
+
+%type <arginfotype> parms parmlist parmlist_1 parmlist_2
+%type <arginfotype> parmlist_or_identifiers parmlist_or_identifiers_1
 %type <ttype> identifiers_or_typenames
 
 %type <itype> setspecs setspecs_fp extension
 
 %type <location> save_location
+
+%type <otype> save_obstack_position
 \f
 @@ifobjc
 /* the Objective-C nonterminals */
 
-%type <ttype> ivar_decl_list ivar_decls ivar_decl ivars ivar_declarator
 %type <ttype> methoddecl unaryselector keywordselector selector
+%type <code> methodtype
 %type <ttype> keyworddecl receiver objcmessageexpr messageargs
 %type <ttype> keywordexpr keywordarglist keywordarg
-%type <ttype> myparms myparm optparmlist reservedwords objcselectorexpr
+%type <ttype> optparmlist optparms reservedwords objcselectorexpr
 %type <ttype> selectorarg keywordnamelist keywordname objcencodeexpr
 %type <ttype> non_empty_protocolrefs protocolrefs identifier_list objcprotocolexpr
 
-%type <ttype> CLASSNAME OBJECTNAME OBJC_STRING
+%type <ttype> CLASSNAME OBJC_STRING OBJC_TYPE_QUAL
 
-%type <ttype> superclass
-%type <itype> objc_try_catch_stmt objc_finally_block
+%type <ttype> superclass objc_quals objc_qual objc_typename
+%type <itype> objc_try_catch_stmt optellipsis
 @@end_ifobjc
 \f
 %{
-/* Number of statements (loosely speaking) and compound statements
-   seen so far.  */
-static int stmt_count;
-static int compstmt_count;
-
-/* Input location of the end of the body of last simple_if;
-   used by the stmt-rule immediately after simple_if returns.  */
-static location_t if_stmt_locus;
-
-
-/* List of types and structure classes of the current declaration.  */
-static GTY(()) tree current_declspecs;
+/* Declaration specifiers of the current declaration.  */
+static struct c_declspecs *current_declspecs;
 static GTY(()) tree prefix_attributes;
 
 /* List of all the attributes applying to the identifier currently being
@@ -272,26 +275,44 @@ static GTY(()) tree prefix_attributes;
    just after a comma.  */
 static GTY(()) tree all_prefix_attributes;
 
+/* Structure to save declaration specifiers.  */
+struct c_declspec_stack {
+  /* Saved value of current_declspecs.  */
+  struct c_declspecs *current_declspecs;
+  /* Saved value of prefix_attributes.  */
+  tree prefix_attributes;
+  /* Saved value of all_prefix_attributes.  */
+  tree all_prefix_attributes;
+  /* Next level of stack.  */
+  struct c_declspec_stack *next;
+};
+
 /* Stack of saved values of current_declspecs, prefix_attributes and
    all_prefix_attributes.  */
-static GTY(()) tree declspec_stack;
+static struct c_declspec_stack *declspec_stack;
+
+/* INDIRECT_REF with a TREE_TYPE of the type being queried for offsetof.  */
+static tree offsetof_base;
 
 /* PUSH_DECLSPEC_STACK is called from setspecs; POP_DECLSPEC_STACK
    should be called from the productions making use of setspecs.  */
-#define PUSH_DECLSPEC_STACK                                             \
-  do {                                                                  \
-    declspec_stack = tree_cons (build_tree_list (prefix_attributes,     \
-                                                all_prefix_attributes), \
-                               current_declspecs,                       \
-                               declspec_stack);                         \
+#define PUSH_DECLSPEC_STACK                                            \
+  do {                                                                 \
+    struct c_declspec_stack *t = XOBNEW (&parser_obstack,              \
+                                        struct c_declspec_stack);      \
+    t->current_declspecs = current_declspecs;                          \
+    t->prefix_attributes = prefix_attributes;                          \
+    t->all_prefix_attributes = all_prefix_attributes;                  \
+    t->next = declspec_stack;                                          \
+    declspec_stack = t;                                                        \
   } while (0)
 
 #define POP_DECLSPEC_STACK                                             \
   do {                                                                 \
-    current_declspecs = TREE_VALUE (declspec_stack);                   \
-    prefix_attributes = TREE_PURPOSE (TREE_PURPOSE (declspec_stack));  \
-    all_prefix_attributes = TREE_VALUE (TREE_PURPOSE (declspec_stack));        \
-    declspec_stack = TREE_CHAIN (declspec_stack);                      \
+    current_declspecs = declspec_stack->current_declspecs;             \
+    prefix_attributes = declspec_stack->prefix_attributes;             \
+    all_prefix_attributes = declspec_stack->all_prefix_attributes;     \
+    declspec_stack = declspec_stack->next;                             \
   } while (0)
 
 /* For __extension__, save/restore the warning flags which are
@@ -313,8 +334,7 @@ static GTY(()) tree declspec_stack;
 @@ifobjc
 /* Objective-C specific parser/lexer information */
 
-static enum tree_code objc_inherit_code;
-static int objc_pq_context = 0, objc_public_flag = 0;
+static int objc_pq_context = 0;
 
 /* The following flag is needed to contextualize ObjC lexical analysis.
    In some cases (e.g., 'int NSObject;'), it is undesirable to bind
@@ -328,8 +348,6 @@ static int objc_need_raw_identifier;
 #define OBJC_NEED_RAW_IDENTIFIER(VAL)  /* nothing */
 @@end_ifc
 
-static bool parsing_iso_function_signature;
-
 /* Tell yyparse how to print a token's value, if yydebug is set.  */
 
 #define YYPRINT(FILE,YYCHAR,YYLVAL) yyprint(FILE,YYCHAR,YYLVAL)
@@ -341,7 +359,7 @@ static inline int _yylex (void);
 static int  yylex (void);
 static void init_reswords (void);
 
-  /* Initialisation routine for this file.  */
+  /* Initialization routine for this file.  */
 void
 c_parse_init (void)
 {
@@ -360,19 +378,17 @@ program: /* empty */
 
 /* the reason for the strange actions in this rule
  is so that notype_initdecls when reached via datadef
- can find a valid list of type and sc specs in $0. */
+ can find valid declaration specifiers in $0. */
 
 extdefs:
-       {$<ttype>$ = NULL_TREE; } extdef
-       | extdefs {$<ttype>$ = NULL_TREE; ggc_collect(); } extdef
+       save_obstack_position { $<dsptype>$ = NULL; } extdef
+               { obstack_free (&parser_obstack, $1); }
+       | extdefs save_obstack_position
+               { $<dsptype>$ = NULL; ggc_collect (); } extdef
+               { obstack_free (&parser_obstack, $2); }
        ;
 
 extdef:
-       extdef_1
-       { parsing_iso_function_signature = false; } /* Reset after any external definition.  */
-       ;
-
-extdef_1:
        fndef
        | datadef
        | asmdef
@@ -383,31 +399,33 @@ extdef_1:
 @@end_ifobjc
        ;
 
+/* Record the current position of parser_obstack before a
+   declaration to restore it afterwards.  */
+save_obstack_position:
+               { $$ = obstack_alloc (&parser_obstack, 0); }
+       ;
+
 datadef:
          setspecs notype_initdecls ';'
-               { if (pedantic)
-                   error ("ISO C forbids data definition with no type or storage class");
-                 else
-                   warning ("data definition has no type or storage class");
-
+               { pedwarn ("data definition has no type or storage class");
                  POP_DECLSPEC_STACK; }
         | declspecs_nots setspecs notype_initdecls ';'
                { POP_DECLSPEC_STACK; }
        | declspecs_ts setspecs initdecls ';'
                { POP_DECLSPEC_STACK; }
        | declspecs ';'
-         { shadow_tag ($1); }
+         { shadow_tag (finish_declspecs ($1)); }
        | error ';'
        | error '}'
        | ';'
                { if (pedantic)
-                   pedwarn ("ISO C does not allow extra `;' outside of a function"); }
+                   pedwarn ("ISO C does not allow extra %<;%> outside of a function"); }
        ;
 \f
 fndef:
          declspecs_ts setspecs declarator
-               { if (! start_function (current_declspecs, $3,
-                                       all_prefix_attributes))
+               { if (!start_function (current_declspecs, $3,
+                                      all_prefix_attributes))
                    YYERROR1;
                }
          old_style_parm_decls save_location
@@ -419,8 +437,8 @@ fndef:
        | declspecs_ts setspecs declarator error
                { POP_DECLSPEC_STACK; }
        | declspecs_nots setspecs notype_declarator
-               { if (! start_function (current_declspecs, $3,
-                                       all_prefix_attributes))
+               { if (!start_function (current_declspecs, $3,
+                                      all_prefix_attributes))
                    YYERROR1;
                }
          old_style_parm_decls save_location
@@ -432,8 +450,8 @@ fndef:
        | declspecs_nots setspecs notype_declarator error
                { POP_DECLSPEC_STACK; }
        | setspecs notype_declarator
-               { if (! start_function (NULL_TREE, $2,
-                                       all_prefix_attributes))
+               { if (!start_function (current_declspecs, $2,
+                                      all_prefix_attributes))
                    YYERROR1;
                }
          old_style_parm_decls save_location
@@ -450,7 +468,6 @@ identifier:
        IDENTIFIER
        | TYPENAME
 @@ifobjc
-       | OBJECTNAME
        | CLASSNAME
 @@end_ifobjc
        ;
@@ -476,8 +493,10 @@ unop:     '&'
                { $$ = TRUTH_NOT_EXPR; }
        ;
 
-expr:  nonnull_exprlist
-               { $$ = build_compound_expr ($1); }
+expr:  expr_no_commas
+       | expr ',' expr_no_commas
+               { $$.value = build_compound_expr ($1.value, $3.value);
+                 $$.original_code = COMPOUND_EXPR; }
        ;
 
 exprlist:
@@ -488,62 +507,74 @@ exprlist:
 
 nonnull_exprlist:
        expr_no_commas
-               { $$ = build_tree_list (NULL_TREE, $1); }
+               { $$ = build_tree_list (NULL_TREE, $1.value); }
        | nonnull_exprlist ',' expr_no_commas
-               { chainon ($1, build_tree_list (NULL_TREE, $3)); }
+               { chainon ($1, build_tree_list (NULL_TREE, $3.value)); }
        ;
 
 unary_expr:
        primary
        | '*' cast_expr   %prec UNARY
-               { $$ = build_indirect_ref ($2, "unary *"); }
+               { $$.value = build_indirect_ref ($2.value, "unary *");
+                 $$.original_code = ERROR_MARK; }
        /* __extension__ turns off -pedantic for following primary.  */
        | extension cast_expr     %prec UNARY
                { $$ = $2;
                  RESTORE_EXT_FLAGS ($1); }
        | unop cast_expr  %prec UNARY
-               { $$ = build_unary_op ($1, $2, 0);
-                 overflow_warning ($$); }
+               { $$.value = build_unary_op ($1, $2.value, 0);
+                 overflow_warning ($$.value);
+                 $$.original_code = ERROR_MARK; }
        /* Refer to the address of a label as a pointer.  */
        | ANDAND identifier
-               { $$ = finish_label_address_expr ($2); }
+               { $$.value = finish_label_address_expr ($2);
+                 $$.original_code = ERROR_MARK; }
        | sizeof unary_expr  %prec UNARY
                { skip_evaluation--;
-                 if (TREE_CODE ($2) == COMPONENT_REF
-                     && DECL_C_BIT_FIELD (TREE_OPERAND ($2, 1)))
-                   error ("`sizeof' applied to a bit-field");
-                 $$ = c_sizeof (TREE_TYPE ($2)); }
+                 in_sizeof--;
+                 if (TREE_CODE ($2.value) == COMPONENT_REF
+                     && DECL_C_BIT_FIELD (TREE_OPERAND ($2.value, 1)))
+                   error ("%<sizeof%> applied to a bit-field");
+                 $$ = c_expr_sizeof_expr ($2); }
        | sizeof '(' typename ')'  %prec HYPERUNARY
                { skip_evaluation--;
-                 $$ = c_sizeof (groktypename ($3)); }
+                 in_sizeof--;
+                 $$ = c_expr_sizeof_type ($3); }
        | alignof unary_expr  %prec UNARY
                { skip_evaluation--;
-                 $$ = c_alignof_expr ($2); }
+                 in_alignof--;
+                 $$.value = c_alignof_expr ($2.value);
+                 $$.original_code = ERROR_MARK; }
        | alignof '(' typename ')'  %prec HYPERUNARY
                { skip_evaluation--;
-                 $$ = c_alignof (groktypename ($3)); }
+                 in_alignof--;
+                 $$.value = c_alignof (groktypename ($3));
+                 $$.original_code = ERROR_MARK; }
        | REALPART cast_expr %prec UNARY
-               { $$ = build_unary_op (REALPART_EXPR, $2, 0); }
+               { $$.value = build_unary_op (REALPART_EXPR, $2.value, 0);
+                 $$.original_code = ERROR_MARK; }
        | IMAGPART cast_expr %prec UNARY
-               { $$ = build_unary_op (IMAGPART_EXPR, $2, 0); }
+               { $$.value = build_unary_op (IMAGPART_EXPR, $2.value, 0);
+                 $$.original_code = ERROR_MARK; }
        ;
 
 sizeof:
-       SIZEOF { skip_evaluation++; }
+       SIZEOF { skip_evaluation++; in_sizeof++; }
        ;
 
 alignof:
-       ALIGNOF { skip_evaluation++; }
+       ALIGNOF { skip_evaluation++; in_alignof++; }
        ;
 
 typeof:
-       TYPEOF { skip_evaluation++; }
+       TYPEOF { skip_evaluation++; in_typeof++; }
        ;
 
 cast_expr:
        unary_expr
        | '(' typename ')' cast_expr  %prec UNARY
-               { $$ = c_cast_expr ($2, $4); }
+               { $$.value = c_cast_expr ($2, $4.value);
+                 $$.original_code = ERROR_MARK; }
        ;
 
 expr_no_commas:
@@ -573,54 +604,51 @@ expr_no_commas:
        | expr_no_commas '^' expr_no_commas
                { $$ = parser_build_binary_op ($2, $1, $3); }
        | expr_no_commas ANDAND
-               { $1 = (*lang_hooks.truthvalue_conversion)
-                   (default_conversion ($1));
-                 skip_evaluation += $1 == truthvalue_false_node; }
+               { $1.value = lang_hooks.truthvalue_conversion
+                   (default_conversion ($1.value));
+                 skip_evaluation += $1.value == truthvalue_false_node; }
          expr_no_commas
-               { skip_evaluation -= $1 == truthvalue_false_node;
+               { skip_evaluation -= $1.value == truthvalue_false_node;
                  $$ = parser_build_binary_op (TRUTH_ANDIF_EXPR, $1, $4); }
        | expr_no_commas OROR
-               { $1 = (*lang_hooks.truthvalue_conversion)
-                   (default_conversion ($1));
-                 skip_evaluation += $1 == truthvalue_true_node; }
+               { $1.value = lang_hooks.truthvalue_conversion
+                   (default_conversion ($1.value));
+                 skip_evaluation += $1.value == truthvalue_true_node; }
          expr_no_commas
-               { skip_evaluation -= $1 == truthvalue_true_node;
+               { skip_evaluation -= $1.value == truthvalue_true_node;
                  $$ = parser_build_binary_op (TRUTH_ORIF_EXPR, $1, $4); }
        | expr_no_commas '?'
-               { $1 = (*lang_hooks.truthvalue_conversion)
-                   (default_conversion ($1));
-                 skip_evaluation += $1 == truthvalue_false_node; }
+               { $1.value = lang_hooks.truthvalue_conversion
+                   (default_conversion ($1.value));
+                 skip_evaluation += $1.value == truthvalue_false_node; }
           expr ':'
-               { skip_evaluation += (($1 == truthvalue_true_node)
-                                     - ($1 == truthvalue_false_node)); }
+               { skip_evaluation += (($1.value == truthvalue_true_node)
+                                     - ($1.value == truthvalue_false_node)); }
          expr_no_commas
-               { skip_evaluation -= $1 == truthvalue_true_node;
-                 $$ = build_conditional_expr ($1, $4, $7); }
+               { skip_evaluation -= $1.value == truthvalue_true_node;
+                 $$.value = build_conditional_expr ($1.value, $4.value,
+                                                    $7.value);
+                 $$.original_code = ERROR_MARK; }
        | expr_no_commas '?'
                { if (pedantic)
                    pedwarn ("ISO C forbids omitting the middle term of a ?: expression");
                  /* Make sure first operand is calculated only once.  */
-                 $<ttype>2 = save_expr (default_conversion ($1));
-                 $1 = (*lang_hooks.truthvalue_conversion) ($<ttype>2);
-                 skip_evaluation += $1 == truthvalue_true_node; }
+                 $<ttype>2 = save_expr (default_conversion ($1.value));
+                 $1.value = lang_hooks.truthvalue_conversion ($<ttype>2);
+                 skip_evaluation += $1.value == truthvalue_true_node; }
          ':' expr_no_commas
-               { skip_evaluation -= $1 == truthvalue_true_node;
-                 $$ = build_conditional_expr ($1, $<ttype>2, $5); }
+               { skip_evaluation -= $1.value == truthvalue_true_node;
+                 $$.value = build_conditional_expr ($1.value, $<ttype>2,
+                                                    $5.value);
+                 $$.original_code = ERROR_MARK; }
        | expr_no_commas '=' expr_no_commas
-               { char class;
-                 $$ = build_modify_expr ($1, NOP_EXPR, $3);
-                 class = TREE_CODE_CLASS (TREE_CODE ($$));
-                 if (IS_EXPR_CODE_CLASS (class))
-                   C_SET_EXP_ORIGINAL_CODE ($$, MODIFY_EXPR);
+               { $$.value = build_modify_expr ($1.value, NOP_EXPR, $3.value);
+                 $$.original_code = MODIFY_EXPR;
                }
        | expr_no_commas ASSIGN expr_no_commas
-               { char class;
-                 $$ = build_modify_expr ($1, $2, $3);
-                 /* This inhibits warnings in
-                    c_common_truthvalue_conversion.  */
-                 class = TREE_CODE_CLASS (TREE_CODE ($$));
-                 if (IS_EXPR_CODE_CLASS (class))
-                   C_SET_EXP_ORIGINAL_CODE ($$, ERROR_MARK);
+               { $$.value = build_modify_expr ($1.value, $2, $3.value);
+                 TREE_NO_WARNING ($$.value) = 1;
+                 $$.original_code = ERROR_MARK;
                }
        ;
 
@@ -629,140 +657,155 @@ primary:
                {
                  if (yychar == YYEMPTY)
                    yychar = YYLEX;
-                 $$ = build_external_ref ($1, yychar == '(');
+                 $$.value = build_external_ref ($1, yychar == '(');
+                 $$.original_code = ERROR_MARK;
                }
        | CONSTANT
+               { $$.value = $1; $$.original_code = ERROR_MARK; }
        | STRING
+               { $$.value = $1; $$.original_code = STRING_CST; }
        | FUNC_NAME
-               { $$ = fname_decl (C_RID_CODE ($$), $$); }
+               { $$.value = fname_decl (C_RID_CODE ($1), $1);
+                 $$.original_code = ERROR_MARK; }
        | '(' typename ')' '{'
                { start_init (NULL_TREE, NULL, 0);
-                 $2 = groktypename ($2);
-                 really_start_incremental_init ($2); }
+                 $<ttype>$ = groktypename ($2);
+                 if (C_TYPE_VARIABLE_SIZE ($<ttype>$))
+                   {
+                     error ("compound literal has variable size");
+                     $<ttype>$ = error_mark_node;
+                   }
+                 really_start_incremental_init ($<ttype>$); }
          initlist_maybe_comma '}'  %prec UNARY
-               { tree constructor = pop_init_level (0);
-                 tree type = $2;
+               { struct c_expr init = pop_init_level (0);
+                 tree constructor = init.value;
+                 tree type = $<ttype>5;
                  finish_init ();
+                 maybe_warn_string_init (type, init);
 
-                 if (pedantic && ! flag_isoc99)
+                 if (pedantic && !flag_isoc99)
                    pedwarn ("ISO C90 forbids compound literals");
-                 $$ = build_compound_literal (type, constructor);
+                 $$.value = build_compound_literal (type, constructor);
+                 $$.original_code = ERROR_MARK;
                }
        | '(' expr ')'
-               { char class = TREE_CODE_CLASS (TREE_CODE ($2));
-                 if (IS_EXPR_CODE_CLASS (class))
-                   C_SET_EXP_ORIGINAL_CODE ($2, ERROR_MARK);
-                 $$ = $2; }
+               { $$.value = $2.value;
+                 if (TREE_CODE ($$.value) == MODIFY_EXPR)
+                   TREE_NO_WARNING ($$.value) = 1;
+                 $$.original_code = ERROR_MARK; }
        | '(' error ')'
-               { $$ = error_mark_node; }
+               { $$.value = error_mark_node; $$.original_code = ERROR_MARK; }
        | compstmt_primary_start compstmt_nostart ')'
-                 { tree saved_last_tree;
-
-                  if (pedantic)
-                    pedwarn ("ISO C forbids braced-groups within expressions");
-                 saved_last_tree = COMPOUND_BODY ($1);
-                 RECHAIN_STMTS ($1, COMPOUND_BODY ($1));
-                 last_tree = saved_last_tree;
-                 TREE_CHAIN (last_tree) = NULL_TREE;
-                 if (!last_expr_type)
-                   last_expr_type = void_type_node;
-                 $$ = build1 (STMT_EXPR, last_expr_type, $1);
-                 TREE_SIDE_EFFECTS ($$) = 1;
+                { if (pedantic)
+                   pedwarn ("ISO C forbids braced-groups within expressions");
+                 $$.value = c_finish_stmt_expr ($1);
+                 $$.original_code = ERROR_MARK;
                }
        | compstmt_primary_start error ')'
-               {
-                 last_tree = COMPOUND_BODY ($1);
-                 TREE_CHAIN (last_tree) = NULL_TREE;
-                 $$ = error_mark_node;
+               { c_finish_stmt_expr ($1);
+                 $$.value = error_mark_node;
+                 $$.original_code = ERROR_MARK;
                }
        | primary '(' exprlist ')'   %prec '.'
-               { $$ = build_function_call ($1, $3); }
+               { $$.value = build_function_call ($1.value, $3);
+                 $$.original_code = ERROR_MARK; }
        | VA_ARG '(' expr_no_commas ',' typename ')'
-               { $$ = build_va_arg ($3, groktypename ($5)); }
+               { $$.value = build_va_arg ($3.value, groktypename ($5));
+                 $$.original_code = ERROR_MARK; }
 
-      | CHOOSE_EXPR '(' expr_no_commas ',' expr_no_commas ',' expr_no_commas ')'
+       | OFFSETOF '(' typename ','
+               { tree type = groktypename ($3);
+                 if (type == error_mark_node)
+                   offsetof_base = error_mark_node;
+                 else
+                   offsetof_base = build1 (INDIRECT_REF, type, NULL);
+               }
+         offsetof_member_designator ')'
+               { $$.value = fold_offsetof ($6);
+                 $$.original_code = ERROR_MARK; }
+       | OFFSETOF '(' error ')'
+               { $$.value = error_mark_node; $$.original_code = ERROR_MARK; }
+       | CHOOSE_EXPR '(' expr_no_commas ',' expr_no_commas ','
+                         expr_no_commas ')'
                {
                   tree c;
 
-                  c = fold ($3);
+                  c = fold ($3.value);
                   STRIP_NOPS (c);
                   if (TREE_CODE (c) != INTEGER_CST)
-                    error ("first argument to __builtin_choose_expr not a constant");
+                    error ("first argument to %<__builtin_choose_expr%> not"
+                          " a constant");
                   $$ = integer_zerop (c) ? $7 : $5;
                }
-      | TYPES_COMPATIBLE_P '(' typename ',' typename ')'
+       | CHOOSE_EXPR '(' error ')'
+               { $$.value = error_mark_node; $$.original_code = ERROR_MARK; }
+       | TYPES_COMPATIBLE_P '(' typename ',' typename ')'
                {
                  tree e1, e2;
 
                  e1 = TYPE_MAIN_VARIANT (groktypename ($3));
                  e2 = TYPE_MAIN_VARIANT (groktypename ($5));
 
-                 $$ = comptypes (e1, e2, COMPARE_STRICT)
-                   ? build_int_2 (1, 0) : build_int_2 (0, 0);
+                 $$.value = comptypes (e1, e2)
+                   ? build_int_cst (NULL_TREE, 1)
+                   : build_int_cst (NULL_TREE, 0);
+                 $$.original_code = ERROR_MARK;
                }
+       | TYPES_COMPATIBLE_P '(' error ')'
+               { $$.value = error_mark_node; $$.original_code = ERROR_MARK; }
        | primary '[' expr ']'   %prec '.'
-               { $$ = build_array_ref ($1, $3); }
+               { $$.value = build_array_ref ($1.value, $3.value);
+                 $$.original_code = ERROR_MARK; }
        | primary '.' identifier
-               {
-@@ifobjc
-                   if (!is_public ($1, $3))
-                     $$ = error_mark_node;
-                   else
-@@end_ifobjc
-                     $$ = build_component_ref ($1, $3);
-               }
+               { $$.value = build_component_ref ($1.value, $3);
+                 $$.original_code = ERROR_MARK; }
        | primary POINTSAT identifier
                {
-                  tree expr = build_indirect_ref ($1, "->");
-
-@@ifobjc
-                     if (!is_public (expr, $3))
-                       $$ = error_mark_node;
-                     else
-@@end_ifobjc
-                       $$ = build_component_ref (expr, $3);
+                  tree expr = build_indirect_ref ($1.value, "->");
+                 $$.value = build_component_ref (expr, $3);
+                 $$.original_code = ERROR_MARK;
                }
        | primary PLUSPLUS
-               { $$ = build_unary_op (POSTINCREMENT_EXPR, $1, 0); }
+               { $$.value = build_unary_op (POSTINCREMENT_EXPR, $1.value, 0);
+                 $$.original_code = ERROR_MARK; }
        | primary MINUSMINUS
-               { $$ = build_unary_op (POSTDECREMENT_EXPR, $1, 0); }
+               { $$.value = build_unary_op (POSTDECREMENT_EXPR, $1.value, 0);
+                 $$.original_code = ERROR_MARK; }
 @@ifobjc
        | objcmessageexpr
-               { $$ = build_message_expr ($1); }
+               { $$.value = objc_build_message_expr ($1);
+                 $$.original_code = ERROR_MARK; }
        | objcselectorexpr
-               { $$ = build_selector_expr ($1); }
+               { $$.value = objc_build_selector_expr ($1);
+                 $$.original_code = ERROR_MARK; }
        | objcprotocolexpr
-               { $$ = build_protocol_expr ($1); }
+               { $$.value = objc_build_protocol_expr ($1);
+                 $$.original_code = ERROR_MARK; }
        | objcencodeexpr
-               { $$ = build_encode_expr ($1); }
+               { $$.value = objc_build_encode_expr ($1);
+                 $$.original_code = ERROR_MARK; }
        | OBJC_STRING
-               { $$ = build_objc_string_object ($1); }
+               { $$.value = objc_build_string_object ($1);
+                 $$.original_code = ERROR_MARK; }
 @@end_ifobjc
        ;
 
-old_style_parm_decls:
-       old_style_parm_decls_1
-       {
-         parsing_iso_function_signature = false; /* Reset after decls.  */
-       }
+/* This is the second argument to __builtin_offsetof.  We must have one
+   identifier, and beyond that we want to accept sub structure and sub
+   array references.  */
+
+offsetof_member_designator:
+         identifier
+               { $$ = build_component_ref (offsetof_base, $1); }
+       | offsetof_member_designator '.' identifier
+               { $$ = build_component_ref ($1, $3); }
+       | offsetof_member_designator '[' expr ']'
+               { $$ = build_array_ref ($1, $3.value); }
        ;
 
-old_style_parm_decls_1:
+old_style_parm_decls:
        /* empty */
-       {
-         if (warn_traditional && !in_system_header
-             && parsing_iso_function_signature)
-           warning ("traditional C rejects ISO C style function definitions");
-         if (warn_old_style_definition && !in_system_header
-             && !parsing_iso_function_signature)
-           warning ("old-style parameter declaration");
-         parsing_iso_function_signature = false; /* Reset after warning.  */
-       }
        | datadecls
-       {
-         if (warn_old_style_definition && !in_system_header)
-           warning ("old-style parameter declaration");
-       }
        ;
 
 /* The following are analogous to lineno_decl, decls and decl
@@ -790,7 +833,7 @@ datadecl:
        | declspecs_nots_nosa setspecs notype_initdecls ';'
                { POP_DECLSPEC_STACK; }
        | declspecs_ts_nosa ';'
-               { shadow_tag_warned ($1, 1);
+               { shadow_tag_warned (finish_declspecs ($1), 1);
                  pedwarn ("empty declaration"); }
        | declspecs_nots_nosa ';'
                { pedwarn ("empty declaration"); }
@@ -812,8 +855,18 @@ lineno_decl:
 setspecs: /* empty */
                { pending_xref_error ();
                  PUSH_DECLSPEC_STACK;
-                 split_specs_attrs ($<ttype>0,
-                                    &current_declspecs, &prefix_attributes);
+                 if ($<dsptype>0)
+                   {
+                     prefix_attributes = $<dsptype>0->attrs;
+                     $<dsptype>0->attrs = NULL_TREE;
+                     current_declspecs = $<dsptype>0;
+                   }
+                 else
+                   {
+                     prefix_attributes = NULL_TREE;
+                     current_declspecs = build_null_declspecs ();
+                   }
+                 current_declspecs = finish_declspecs (current_declspecs);
                  all_prefix_attributes = prefix_attributes; }
        ;
 
@@ -834,7 +887,7 @@ decl:
        | declspecs_nots setspecs notype_nested_function
                { POP_DECLSPEC_STACK; }
        | declspecs ';'
-               { shadow_tag ($1); }
+               { shadow_tag (finish_declspecs ($1)); }
        | extension decl
                { RESTORE_EXT_FLAGS ($1); }
        ;
@@ -850,16 +903,6 @@ decl:
 
    - 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
@@ -888,334 +931,208 @@ decl:
 
 /* 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.  */
+   A typedef'd name following these is taken as a name to be declared.  */
 
 declspecs_nosc_nots_nosa_noea:
          TYPE_QUAL
-               { $$ = tree_cons (NULL_TREE, $1, NULL_TREE);
-                 TREE_STATIC ($$) = 1; }
+               { $$ = declspecs_add_qual (build_null_declspecs (), $1); }
        | declspecs_nosc_nots_nosa_noea TYPE_QUAL
-               { $$ = tree_cons (NULL_TREE, $2, $1);
-                 TREE_STATIC ($$) = 1; }
+               { $$ = declspecs_add_qual ($1, $2); }
        | declspecs_nosc_nots_nosa_ea TYPE_QUAL
-               { $$ = tree_cons (NULL_TREE, $2, $1);
-                 TREE_STATIC ($$) = 1; }
+               { $$ = declspecs_add_qual ($1, $2); }
        ;
 
 declspecs_nosc_nots_nosa_ea:
          declspecs_nosc_nots_nosa_noea attributes
-               { $$ = tree_cons ($2, NULL_TREE, $1);
-                 TREE_STATIC ($$) = TREE_STATIC ($1); }
+               { $$ = declspecs_add_attrs ($1, $2); }
        ;
 
 declspecs_nosc_nots_sa_noea:
          declspecs_nosc_nots_sa_noea TYPE_QUAL
-               { $$ = tree_cons (NULL_TREE, $2, $1);
-                 TREE_STATIC ($$) = 1; }
+               { $$ = declspecs_add_qual ($1, $2); }
        | declspecs_nosc_nots_sa_ea TYPE_QUAL
-               { $$ = tree_cons (NULL_TREE, $2, $1);
-                 TREE_STATIC ($$) = 1; }
+               { $$ = declspecs_add_qual ($1, $2); }
        ;
 
 declspecs_nosc_nots_sa_ea:
          attributes
-               { $$ = tree_cons ($1, NULL_TREE, NULL_TREE);
-                 TREE_STATIC ($$) = 0; }
+               { $$ = declspecs_add_attrs (build_null_declspecs (), $1); }
        | declspecs_nosc_nots_sa_noea attributes
-               { $$ = tree_cons ($2, NULL_TREE, $1);
-                 TREE_STATIC ($$) = TREE_STATIC ($1); }
+               { $$ = declspecs_add_attrs ($1, $2); }
        ;
 
 declspecs_nosc_ts_nosa_noea:
          typespec_nonattr
-               { $$ = tree_cons (NULL_TREE, $1, NULL_TREE);
-                 TREE_STATIC ($$) = 1; }
+               { $$ = declspecs_add_type (build_null_declspecs (), $1); }
        | declspecs_nosc_ts_nosa_noea TYPE_QUAL
-               { $$ = tree_cons (NULL_TREE, $2, $1);
-                 TREE_STATIC ($$) = 1; }
+               { $$ = declspecs_add_qual ($1, $2); }
        | declspecs_nosc_ts_nosa_ea TYPE_QUAL
-               { $$ = tree_cons (NULL_TREE, $2, $1);
-                 TREE_STATIC ($$) = 1; }
+               { $$ = declspecs_add_qual ($1, $2); }
        | declspecs_nosc_ts_nosa_noea typespec_reserved_nonattr
-               { $$ = tree_cons (NULL_TREE, $2, $1);
-                 TREE_STATIC ($$) = 1; }
+               { $$ = declspecs_add_type ($1, $2); }
        | declspecs_nosc_ts_nosa_ea typespec_reserved_nonattr
-               { $$ = tree_cons (NULL_TREE, $2, $1);
-                 TREE_STATIC ($$) = 1; }
+               { $$ = declspecs_add_type ($1, $2); }
        | declspecs_nosc_nots_nosa_noea typespec_nonattr
-               { $$ = tree_cons (NULL_TREE, $2, $1);
-                 TREE_STATIC ($$) = 1; }
+               { $$ = declspecs_add_type ($1, $2); }
        | declspecs_nosc_nots_nosa_ea typespec_nonattr
-               { $$ = tree_cons (NULL_TREE, $2, $1);
-                 TREE_STATIC ($$) = 1; }
+               { $$ = declspecs_add_type ($1, $2); }
        ;
 
 declspecs_nosc_ts_nosa_ea:
          typespec_attr
-               { $$ = tree_cons (NULL_TREE, $1, NULL_TREE);
-                 TREE_STATIC ($$) = 1; }
+               { $$ = declspecs_add_type (build_null_declspecs (), $1); }
        | declspecs_nosc_ts_nosa_noea attributes
-               { $$ = tree_cons ($2, NULL_TREE, $1);
-                 TREE_STATIC ($$) = TREE_STATIC ($1); }
+               { $$ = declspecs_add_attrs ($1, $2); }
        | declspecs_nosc_ts_nosa_noea typespec_reserved_attr
-               { $$ = tree_cons (NULL_TREE, $2, $1);
-                 TREE_STATIC ($$) = 1; }
+               { $$ = declspecs_add_type ($1, $2); }
        | declspecs_nosc_ts_nosa_ea typespec_reserved_attr
-               { $$ = tree_cons (NULL_TREE, $2, $1);
-                 TREE_STATIC ($$) = 1; }
+               { $$ = declspecs_add_type ($1, $2); }
        | declspecs_nosc_nots_nosa_noea typespec_attr
-               { $$ = tree_cons (NULL_TREE, $2, $1);
-                 TREE_STATIC ($$) = 1; }
+               { $$ = declspecs_add_type ($1, $2); }
        | declspecs_nosc_nots_nosa_ea typespec_attr
-               { $$ = tree_cons (NULL_TREE, $2, $1);
-                 TREE_STATIC ($$) = 1; }
+               { $$ = declspecs_add_type ($1, $2); }
        ;
 
 declspecs_nosc_ts_sa_noea:
          declspecs_nosc_ts_sa_noea TYPE_QUAL
-               { $$ = tree_cons (NULL_TREE, $2, $1);
-                 TREE_STATIC ($$) = 1; }
+               { $$ = declspecs_add_qual ($1, $2); }
        | declspecs_nosc_ts_sa_ea TYPE_QUAL
-               { $$ = tree_cons (NULL_TREE, $2, $1);
-                 TREE_STATIC ($$) = 1; }
+               { $$ = declspecs_add_qual ($1, $2); }
        | declspecs_nosc_ts_sa_noea typespec_reserved_nonattr
-               { $$ = tree_cons (NULL_TREE, $2, $1);
-                 TREE_STATIC ($$) = 1; }
+               { $$ = declspecs_add_type ($1, $2); }
        | declspecs_nosc_ts_sa_ea typespec_reserved_nonattr
-               { $$ = tree_cons (NULL_TREE, $2, $1);
-                 TREE_STATIC ($$) = 1; }
+               { $$ = declspecs_add_type ($1, $2); }
        | declspecs_nosc_nots_sa_noea typespec_nonattr
-               { $$ = tree_cons (NULL_TREE, $2, $1);
-                 TREE_STATIC ($$) = 1; }
+               { $$ = declspecs_add_type ($1, $2); }
        | declspecs_nosc_nots_sa_ea typespec_nonattr
-               { $$ = tree_cons (NULL_TREE, $2, $1);
-                 TREE_STATIC ($$) = 1; }
+               { $$ = declspecs_add_type ($1, $2); }
        ;
 
 declspecs_nosc_ts_sa_ea:
          declspecs_nosc_ts_sa_noea attributes
-               { $$ = tree_cons ($2, NULL_TREE, $1);
-                 TREE_STATIC ($$) = TREE_STATIC ($1); }
+               { $$ = declspecs_add_attrs ($1, $2); }
        | declspecs_nosc_ts_sa_noea typespec_reserved_attr
-               { $$ = tree_cons (NULL_TREE, $2, $1);
-                 TREE_STATIC ($$) = 1; }
+               { $$ = declspecs_add_type ($1, $2); }
        | declspecs_nosc_ts_sa_ea typespec_reserved_attr
-               { $$ = tree_cons (NULL_TREE, $2, $1);
-                 TREE_STATIC ($$) = 1; }
+               { $$ = declspecs_add_type ($1, $2); }
        | declspecs_nosc_nots_sa_noea typespec_attr
-               { $$ = tree_cons (NULL_TREE, $2, $1);
-                 TREE_STATIC ($$) = 1; }
+               { $$ = declspecs_add_type ($1, $2); }
        | declspecs_nosc_nots_sa_ea typespec_attr
-               { $$ = tree_cons (NULL_TREE, $2, $1);
-                 TREE_STATIC ($$) = 1; }
+               { $$ = declspecs_add_type ($1, $2); }
        ;
 
 declspecs_sc_nots_nosa_noea:
          scspec
-               { $$ = tree_cons (NULL_TREE, $1, NULL_TREE);
-                 TREE_STATIC ($$) = 0; }
+               { $$ = declspecs_add_scspec (build_null_declspecs (), $1); }
        | declspecs_sc_nots_nosa_noea TYPE_QUAL
-               { $$ = tree_cons (NULL_TREE, $2, $1);
-                 TREE_STATIC ($$) = 1; }
+               { $$ = declspecs_add_qual ($1, $2); }
        | declspecs_sc_nots_nosa_ea TYPE_QUAL
-               { $$ = tree_cons (NULL_TREE, $2, $1);
-                 TREE_STATIC ($$) = 1; }
+               { $$ = declspecs_add_qual ($1, $2); }
        | 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_add_scspec ($1, $2); }
        | 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_add_scspec ($1, $2); }
        | 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_add_scspec ($1, $2); }
        | 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);
-                 TREE_STATIC ($$) = TREE_STATIC ($1); }
+               { $$ = declspecs_add_scspec ($1, $2); }
        ;
 
 declspecs_sc_nots_nosa_ea:
          declspecs_sc_nots_nosa_noea attributes
-               { $$ = tree_cons ($2, NULL_TREE, $1);
-                 TREE_STATIC ($$) = TREE_STATIC ($1); }
+               { $$ = declspecs_add_attrs ($1, $2); }
        ;
 
 declspecs_sc_nots_sa_noea:
          declspecs_sc_nots_sa_noea TYPE_QUAL
-               { $$ = tree_cons (NULL_TREE, $2, $1);
-                 TREE_STATIC ($$) = 1; }
+               { $$ = declspecs_add_qual ($1, $2); }
        | declspecs_sc_nots_sa_ea TYPE_QUAL
-               { $$ = tree_cons (NULL_TREE, $2, $1);
-                 TREE_STATIC ($$) = 1; }
+               { $$ = declspecs_add_qual ($1, $2); }
        | 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_add_scspec ($1, $2); }
        | 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_STATIC ($$) = TREE_STATIC ($1); }
+               { $$ = declspecs_add_scspec ($1, $2); }
        | 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_add_scspec ($1, $2); }
        | 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); }
+               { $$ = declspecs_add_scspec ($1, $2); }
        ;
 
 declspecs_sc_nots_sa_ea:
          declspecs_sc_nots_sa_noea attributes
-               { $$ = tree_cons ($2, NULL_TREE, $1);
-                 TREE_STATIC ($$) = TREE_STATIC ($1); }
+               { $$ = declspecs_add_attrs ($1, $2); }
        ;
 
 declspecs_sc_ts_nosa_noea:
          declspecs_sc_ts_nosa_noea TYPE_QUAL
-               { $$ = tree_cons (NULL_TREE, $2, $1);
-                 TREE_STATIC ($$) = 1; }
+               { $$ = declspecs_add_qual ($1, $2); }
        | declspecs_sc_ts_nosa_ea TYPE_QUAL
-               { $$ = tree_cons (NULL_TREE, $2, $1);
-                 TREE_STATIC ($$) = 1; }
+               { $$ = declspecs_add_qual ($1, $2); }
        | declspecs_sc_ts_nosa_noea typespec_reserved_nonattr
-               { $$ = tree_cons (NULL_TREE, $2, $1);
-                 TREE_STATIC ($$) = 1; }
+               { $$ = declspecs_add_type ($1, $2); }
        | declspecs_sc_ts_nosa_ea typespec_reserved_nonattr
-               { $$ = tree_cons (NULL_TREE, $2, $1);
-                 TREE_STATIC ($$) = 1; }
+               { $$ = declspecs_add_type ($1, $2); }
        | declspecs_sc_nots_nosa_noea typespec_nonattr
-               { $$ = tree_cons (NULL_TREE, $2, $1);
-                 TREE_STATIC ($$) = 1; }
+               { $$ = declspecs_add_type ($1, $2); }
        | declspecs_sc_nots_nosa_ea typespec_nonattr
-               { $$ = tree_cons (NULL_TREE, $2, $1);
-                 TREE_STATIC ($$) = 1; }
+               { $$ = declspecs_add_type ($1, $2); }
        | 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_add_scspec ($1, $2); }
        | 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_add_scspec ($1, $2); }
        | 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_add_scspec ($1, $2); }
        | declspecs_sc_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_add_scspec ($1, $2); }
        ;
 
 declspecs_sc_ts_nosa_ea:
          declspecs_sc_ts_nosa_noea attributes
-               { $$ = tree_cons ($2, NULL_TREE, $1);
-                 TREE_STATIC ($$) = TREE_STATIC ($1); }
+               { $$ = declspecs_add_attrs ($1, $2); }
        | declspecs_sc_ts_nosa_noea typespec_reserved_attr
-               { $$ = tree_cons (NULL_TREE, $2, $1);
-                 TREE_STATIC ($$) = 1; }
+               { $$ = declspecs_add_type ($1, $2); }
        | declspecs_sc_ts_nosa_ea typespec_reserved_attr
-               { $$ = tree_cons (NULL_TREE, $2, $1);
-                 TREE_STATIC ($$) = 1; }
+               { $$ = declspecs_add_type ($1, $2); }
        | declspecs_sc_nots_nosa_noea typespec_attr
-               { $$ = tree_cons (NULL_TREE, $2, $1);
-                 TREE_STATIC ($$) = 1; }
+               { $$ = declspecs_add_type ($1, $2); }
        | declspecs_sc_nots_nosa_ea typespec_attr
-               { $$ = tree_cons (NULL_TREE, $2, $1);
-                 TREE_STATIC ($$) = 1; }
+               { $$ = declspecs_add_type ($1, $2); }
        ;
 
 declspecs_sc_ts_sa_noea:
          declspecs_sc_ts_sa_noea TYPE_QUAL
-               { $$ = tree_cons (NULL_TREE, $2, $1);
-                 TREE_STATIC ($$) = 1; }
+               { $$ = declspecs_add_qual ($1, $2); }
        | declspecs_sc_ts_sa_ea TYPE_QUAL
-               { $$ = tree_cons (NULL_TREE, $2, $1);
-                 TREE_STATIC ($$) = 1; }
+               { $$ = declspecs_add_qual ($1, $2); }
        | declspecs_sc_ts_sa_noea typespec_reserved_nonattr
-               { $$ = tree_cons (NULL_TREE, $2, $1);
-                 TREE_STATIC ($$) = 1; }
+               { $$ = declspecs_add_type ($1, $2); }
        | declspecs_sc_ts_sa_ea typespec_reserved_nonattr
-               { $$ = tree_cons (NULL_TREE, $2, $1);
-                 TREE_STATIC ($$) = 1; }
+               { $$ = declspecs_add_type ($1, $2); }
        | declspecs_sc_nots_sa_noea typespec_nonattr
-               { $$ = tree_cons (NULL_TREE, $2, $1);
-                 TREE_STATIC ($$) = 1; }
+               { $$ = declspecs_add_type ($1, $2); }
        | declspecs_sc_nots_sa_ea typespec_nonattr
-               { $$ = tree_cons (NULL_TREE, $2, $1);
-                 TREE_STATIC ($$) = 1; }
+               { $$ = declspecs_add_type ($1, $2); }
        | 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_add_scspec ($1, $2); }
        | 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_add_scspec ($1, $2); }
        | 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_add_scspec ($1, $2); }
        | 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); }
+               { $$ = declspecs_add_scspec ($1, $2); }
        ;
 
 declspecs_sc_ts_sa_ea:
          declspecs_sc_ts_sa_noea attributes
-               { $$ = tree_cons ($2, NULL_TREE, $1);
-                 TREE_STATIC ($$) = TREE_STATIC ($1); }
+               { $$ = declspecs_add_attrs ($1, $2); }
        | declspecs_sc_ts_sa_noea typespec_reserved_attr
-               { $$ = tree_cons (NULL_TREE, $2, $1);
-                 TREE_STATIC ($$) = 1; }
+               { $$ = declspecs_add_type ($1, $2); }
        | declspecs_sc_ts_sa_ea typespec_reserved_attr
-               { $$ = tree_cons (NULL_TREE, $2, $1);
-                 TREE_STATIC ($$) = 1; }
+               { $$ = declspecs_add_type ($1, $2); }
        | declspecs_sc_nots_sa_noea typespec_attr
-               { $$ = tree_cons (NULL_TREE, $2, $1);
-                 TREE_STATIC ($$) = 1; }
+               { $$ = declspecs_add_type ($1, $2); }
        | declspecs_sc_nots_sa_ea typespec_attr
-               { $$ = tree_cons (NULL_TREE, $2, $1);
-                 TREE_STATIC ($$) = 1; }
+               { $$ = declspecs_add_type ($1, $2); }
        ;
 
 /* Particular useful classes of declspecs.  */
@@ -1302,7 +1219,7 @@ declspecs:
 /* A (possibly empty) sequence of type qualifiers and attributes.  */
 maybe_type_quals_attrs:
          /* empty */
-               { $$ = NULL_TREE; }
+               { $$ = NULL; }
        | declspecs_nosc_nots
                { $$ = $1; }
        ;
@@ -1326,7 +1243,7 @@ maybe_type_quals_attrs:
    or are such that any following attributes would
    be parsed as part of the specifier.
 
-   _nonattr: specifiers.  */
+   _nonattr: other specifiers not ending with attributes.  */
 
 typespec_nonattr:
          typespec_reserved_nonattr
@@ -1339,7 +1256,9 @@ typespec_attr:
 
 typespec_reserved_nonattr:
          TYPESPEC
-               { OBJC_NEED_RAW_IDENTIFIER (1); }
+               { OBJC_NEED_RAW_IDENTIFIER (1);
+                 $$.kind = ctsk_resword;
+                 $$.spec = $1; }
        | structsp_nonattr
        ;
 
@@ -1351,26 +1270,39 @@ typespec_nonreserved_nonattr:
          TYPENAME
                { /* For a typedef name, record the meaning, not the name.
                     In case of `foo foo, bar;'.  */
-                 $$ = lookup_name ($1); }
+                 $$.kind = ctsk_typedef;
+                 $$.spec = lookup_name ($1); }
 @@ifobjc
        | CLASSNAME protocolrefs
-               { $$ = get_static_reference ($1, $2); }
-       | OBJECTNAME protocolrefs
-               { $$ = get_object_reference ($2); }
+               { $$.kind = ctsk_objc;
+                 $$.spec = objc_get_protocol_qualified_type ($1, $2); }
+       | TYPENAME non_empty_protocolrefs
+               { $$.kind = ctsk_objc;
+                 $$.spec = objc_get_protocol_qualified_type ($1, $2); }
 
 /* Make "<SomeProtocol>" equivalent to "id <SomeProtocol>"
    - nisse@lysator.liu.se */
         | non_empty_protocolrefs
-                { $$ = get_object_reference ($1); }
+                { $$.kind = ctsk_objc;
+                 $$.spec = objc_get_protocol_qualified_type (NULL_TREE, $1); }
 @@end_ifobjc
        | typeof '(' expr ')'
                { skip_evaluation--;
-                 if (TREE_CODE ($3) == COMPONENT_REF
-                     && DECL_C_BIT_FIELD (TREE_OPERAND ($3, 1)))
-                   error ("`typeof' applied to a bit-field");
-                 $$ = TREE_TYPE ($3); }
+                 in_typeof--;
+                 if (TREE_CODE ($3.value) == COMPONENT_REF
+                     && DECL_C_BIT_FIELD (TREE_OPERAND ($3.value, 1)))
+                   error ("%<typeof%> applied to a bit-field");
+                 $$.kind = ctsk_typeof;
+                 $$.spec = TREE_TYPE ($3.value);
+                 pop_maybe_used (variably_modified_type_p ($$.spec,
+                                                           NULL_TREE)); }
        | typeof '(' typename ')'
-               { skip_evaluation--; $$ = groktypename ($3); }
+               { skip_evaluation--;
+                 in_typeof--;
+                 $$.kind = ctsk_typeof;
+                 $$.spec = groktypename ($3);
+                 pop_maybe_used (variably_modified_type_p ($$.spec,
+                                                           NULL_TREE)); }
        ;
 
 /* typespec_nonreserved_attr does not exist.  */
@@ -1387,15 +1319,16 @@ notype_initdecls:
 
 initdcl:
          declarator maybeasm maybe_attribute '='
-               { $<ttype>$ = start_decl ($1, current_declspecs, 1,
+               { $<ttype>$ = start_decl ($1, current_declspecs, true,
                                          chainon ($3, all_prefix_attributes));
                  start_init ($<ttype>$, $2, global_bindings_p ()); }
          init
 /* Note how the declaration of the variable is in effect while its init is parsed! */
                { finish_init ();
-                 finish_decl ($<ttype>5, $6, $2); }
+                 maybe_warn_string_init (TREE_TYPE ($<ttype>5), $6);
+                 finish_decl ($<ttype>5, $6.value, $2); }
        | declarator maybeasm maybe_attribute
-               { tree d = start_decl ($1, current_declspecs, 0,
+               { tree d = start_decl ($1, current_declspecs, false,
                                       chainon ($3, all_prefix_attributes));
                  finish_decl (d, NULL_TREE, $2);
                 }
@@ -1403,15 +1336,16 @@ initdcl:
 
 notype_initdcl:
          notype_declarator maybeasm maybe_attribute '='
-               { $<ttype>$ = start_decl ($1, current_declspecs, 1,
+               { $<ttype>$ = start_decl ($1, current_declspecs, true,
                                          chainon ($3, all_prefix_attributes));
                  start_init ($<ttype>$, $2, global_bindings_p ()); }
          init
 /* Note how the declaration of the variable is in effect while its init is parsed! */
                { finish_init ();
-                 finish_decl ($<ttype>5, $6, $2); }
+                 maybe_warn_string_init (TREE_TYPE ($<ttype>5), $6);
+                 finish_decl ($<ttype>5, $6.value, $2); }
        | notype_declarator maybeasm maybe_attribute
-               { tree d = start_decl ($1, current_declspecs, 0,
+               { tree d = start_decl ($1, current_declspecs, false,
                                       chainon ($3, all_prefix_attributes));
                  finish_decl (d, NULL_TREE, $2); }
        ;
@@ -1432,8 +1366,11 @@ attributes:
        ;
 
 attribute:
-      ATTRIBUTE '(' '(' attribute_list ')' ')'
-               { $$ = $4; }
+      ATTRIBUTE stop_string_translation
+                '(' '(' attribute_list ')' ')' start_string_translation
+               { $$ = $5; }
+      | ATTRIBUTE error start_string_translation
+                { $$ = NULL_TREE; }
        ;
 
 attribute_list:
@@ -1475,12 +1412,13 @@ scspec:
 
 init:
        expr_no_commas
+               { $$ = $1; }
        | '{'
                { really_start_incremental_init (NULL_TREE); }
          initlist_maybe_comma '}'
                { $$ = pop_init_level (0); }
        | error
-               { $$ = error_mark_node; }
+               { $$.value = error_mark_node; $$.original_code = ERROR_MARK; }
        ;
 
 /* `initlist_maybe_comma' is the guts of an initializer in braces.  */
@@ -1500,15 +1438,15 @@ initlist1:
    It may use braces.  */
 initelt:
          designator_list '=' initval
-               { if (pedantic && ! flag_isoc99)
+               { if (pedantic && !flag_isoc99)
                    pedwarn ("ISO C90 forbids specifying subobject to initialize"); }
-       | designator initval
+       | array_designator initval
                { if (pedantic)
-                   pedwarn ("obsolete use of designated initializer without `='"); }
+                   pedwarn ("obsolete use of designated initializer without %<=%>"); }
        | identifier ':'
                { set_init_label ($1);
                  if (pedantic)
-                   pedwarn ("obsolete use of designated initializer with `:'"); }
+                   pedwarn ("obsolete use of designated initializer with %<:%>"); }
          initval
                {}
        | initval
@@ -1532,74 +1470,76 @@ designator_list:
 designator:
          '.' identifier
                { set_init_label ($2); }
-       | '[' expr_no_commas ELLIPSIS expr_no_commas ']'
-               { set_init_index ($2, $4);
+       | array_designator
+       ;
+
+array_designator:
+         '[' expr_no_commas ELLIPSIS expr_no_commas ']'
+               { set_init_index ($2.value, $4.value);
                  if (pedantic)
                    pedwarn ("ISO C forbids specifying range of elements to initialize"); }
        | '[' expr_no_commas ']'
-               { set_init_index ($2, NULL_TREE); }
+               { set_init_index ($2.value, NULL_TREE); }
        ;
 \f
 nested_function:
-         declarator
+       declarator
                { if (pedantic)
                    pedwarn ("ISO C forbids nested functions");
 
                  push_function_context ();
-                 if (! start_function (current_declspecs, $1,
-                                       all_prefix_attributes))
+                 if (!start_function (current_declspecs, $1,
+                                      all_prefix_attributes))
                    {
                      pop_function_context ();
                      YYERROR1;
                    }
-                 parsing_iso_function_signature = false; /* Don't warn about nested functions.  */
                }
-          old_style_parm_decls save_location
+       old_style_parm_decls save_location
                { tree decl = current_function_decl;
                  DECL_SOURCE_LOCATION (decl) = $4;
                  store_parm_decls (); }
-/* This used to use compstmt_or_error.
-   That caused a bug with input `f(g) int g {}',
-   where the use of YYERROR1 above caused an error
-   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
+       /* This used to use compstmt_or_error.  That caused a bug with
+          input `f(g) int g {}', where the use of YYERROR1 above caused
+          an error 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
                { tree decl = current_function_decl;
+                 add_stmt ($6);
                  finish_function ();
                  pop_function_context ();
-                 add_decl_stmt (decl); }
+                 add_stmt (build_stmt (DECL_EXPR, decl)); }
        ;
 
 notype_nested_function:
-         notype_declarator
+       notype_declarator
                { if (pedantic)
                    pedwarn ("ISO C forbids nested functions");
 
                  push_function_context ();
-                 if (! start_function (current_declspecs, $1,
-                                       all_prefix_attributes))
+                 if (!start_function (current_declspecs, $1,
+                                      all_prefix_attributes))
                    {
                      pop_function_context ();
                      YYERROR1;
                    }
-                 parsing_iso_function_signature = false; /* Don't warn about nested functions.  */
                }
-         old_style_parm_decls save_location
+       old_style_parm_decls save_location
                { tree decl = current_function_decl;
                  DECL_SOURCE_LOCATION (decl) = $4;
                  store_parm_decls (); }
-/* This used to use compstmt_or_error.
-   That caused a bug with input `f(g) int g {}',
-   where the use of YYERROR1 above caused an error
-   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
+       /* This used to use compstmt_or_error.  That caused a bug with
+          input `f(g) int g {}', where the use of YYERROR1 above caused
+          an error 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
                { tree decl = current_function_decl;
+                 add_stmt ($6);
                  finish_function ();
                  pop_function_context ();
-                 add_decl_stmt (decl); }
+                 add_stmt (build_stmt (DECL_EXPR, decl)); }
        ;
 
 /* Any kind of declarator (thus, all declarators allowed
@@ -1614,20 +1554,15 @@ declarator:
 
 after_type_declarator:
          '(' maybe_attribute after_type_declarator ')'
-               { $$ = $2 ? tree_cons ($2, $3, NULL_TREE) : $3; }
+               { $$ = $2 ? build_attrs_declarator ($2, $3) : $3; }
        | after_type_declarator '(' parmlist_or_identifiers  %prec '.'
-               { $$ = build_nt (CALL_EXPR, $1, $3, NULL_TREE); }
-/*     | after_type_declarator '(' error ')'  %prec '.'
-               { $$ = build_nt (CALL_EXPR, $1, NULL_TREE, NULL_TREE);
-                 poplevel (0, 0, 0); }  */
+               { $$ = build_function_declarator ($3, $1); }
        | after_type_declarator array_declarator  %prec '.'
-               { $$ = set_array_declarator_type ($2, $1, 0); }
+               { $$ = set_array_declarator_inner ($2, $1, false); }
        | '*' maybe_type_quals_attrs after_type_declarator  %prec UNARY
                { $$ = make_pointer_declarator ($2, $3); }
        | TYPENAME
-@@ifobjc
-       | OBJECTNAME
-@@end_ifobjc
+               { $$ = build_id_declarator ($1); }
        ;
 
 /* Kinds of declarator that can appear in a parameter list
@@ -1641,32 +1576,24 @@ parm_declarator:
 
 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); }  */
+               { $$ = build_function_declarator ($3, $1); }
        | parm_declarator_starttypename array_declarator  %prec '.'
-               { $$ = set_array_declarator_type ($2, $1, 0); }
+               { $$ = set_array_declarator_inner ($2, $1, false); }
        | TYPENAME
-@@ifobjc
-       | OBJECTNAME
-@@end_ifobjc
+               { $$ = build_id_declarator ($1); }
        ;
 
 parm_declarator_nostarttypename:
          parm_declarator_nostarttypename '(' parmlist_or_identifiers  %prec '.'
-               { $$ = build_nt (CALL_EXPR, $1, $3, NULL_TREE); }
-/*     | parm_declarator_nostarttypename '(' error ')'  %prec '.'
-               { $$ = build_nt (CALL_EXPR, $1, NULL_TREE, NULL_TREE);
-                 poplevel (0, 0, 0); }  */
+               { $$ = build_function_declarator ($3, $1); }
        | parm_declarator_nostarttypename array_declarator  %prec '.'
-               { $$ = set_array_declarator_type ($2, $1, 0); }
+               { $$ = set_array_declarator_inner ($2, $1, false); }
        | '*' maybe_type_quals_attrs parm_declarator_starttypename  %prec UNARY
                { $$ = make_pointer_declarator ($2, $3); }
        | '*' maybe_type_quals_attrs parm_declarator_nostarttypename  %prec UNARY
                { $$ = make_pointer_declarator ($2, $3); }
        | '(' maybe_attribute parm_declarator_nostarttypename ')'
-               { $$ = $2 ? tree_cons ($2, $3, NULL_TREE) : $3; }
+               { $$ = $2 ? build_attrs_declarator ($2, $3) : $3; }
        ;
 
 /* A declarator allowed whether or not there has been
@@ -1674,17 +1601,15 @@ parm_declarator_nostarttypename:
 
 notype_declarator:
          notype_declarator '(' parmlist_or_identifiers  %prec '.'
-               { $$ = build_nt (CALL_EXPR, $1, $3, NULL_TREE); }
-/*     | notype_declarator '(' error ')'  %prec '.'
-               { $$ = build_nt (CALL_EXPR, $1, NULL_TREE, NULL_TREE);
-                 poplevel (0, 0, 0); }  */
+               { $$ = build_function_declarator ($3, $1); }
        | '(' maybe_attribute notype_declarator ')'
-               { $$ = $2 ? tree_cons ($2, $3, NULL_TREE) : $3; }
+               { $$ = $2 ? build_attrs_declarator ($2, $3) : $3; }
        | '*' maybe_type_quals_attrs notype_declarator  %prec UNARY
                { $$ = make_pointer_declarator ($2, $3); }
        | notype_declarator array_declarator  %prec '.'
-               { $$ = set_array_declarator_type ($2, $1, 0); }
+               { $$ = set_array_declarator_inner ($2, $1, false); }
        | IDENTIFIER
+               { $$ = build_id_declarator ($1); }
        ;
 
 struct_head:
@@ -1716,48 +1641,56 @@ enum_head:
 
 structsp_attr:
          struct_head identifier '{'
-               { $$ = start_struct (RECORD_TYPE, $2);
+               { $<ttype>$ = start_struct (RECORD_TYPE, $2);
                  /* Start scope of tag before parsing components.  */
                }
          component_decl_list '}' maybe_attribute
-               { $$ = finish_struct ($<ttype>4, nreverse ($5),
-                                     chainon ($1, $7)); }
+               { $$.spec = finish_struct ($<ttype>4, nreverse ($5),
+                                          chainon ($1, $7));
+                 $$.kind = ctsk_tagdef; }
        | struct_head '{' component_decl_list '}' maybe_attribute
-               { $$ = finish_struct (start_struct (RECORD_TYPE, NULL_TREE),
-                                     nreverse ($3), chainon ($1, $5));
+               { $$.spec = finish_struct (start_struct (RECORD_TYPE,
+                                                        NULL_TREE),
+                                          nreverse ($3), chainon ($1, $5));
+                 $$.kind = ctsk_tagdef;
                }
        | union_head identifier '{'
-               { $$ = start_struct (UNION_TYPE, $2); }
+               { $<ttype>$ = start_struct (UNION_TYPE, $2); }
          component_decl_list '}' maybe_attribute
-               { $$ = finish_struct ($<ttype>4, nreverse ($5),
-                                     chainon ($1, $7)); }
+               { $$.spec = finish_struct ($<ttype>4, nreverse ($5),
+                                          chainon ($1, $7));
+                 $$.kind = ctsk_tagdef; }
        | union_head '{' component_decl_list '}' maybe_attribute
-               { $$ = finish_struct (start_struct (UNION_TYPE, NULL_TREE),
-                                     nreverse ($3), chainon ($1, $5));
+               { $$.spec = finish_struct (start_struct (UNION_TYPE,
+                                                        NULL_TREE),
+                                          nreverse ($3), chainon ($1, $5));
+                 $$.kind = ctsk_tagdef;
                }
        | enum_head identifier '{'
-               { $$ = start_enum ($2); }
+               { $<ttype>$ = start_enum ($2); }
          enumlist maybecomma_warn '}' maybe_attribute
-               { $$ = finish_enum ($<ttype>4, nreverse ($5),
-                                   chainon ($1, $8)); }
+               { $$.spec = finish_enum ($<ttype>4, nreverse ($5),
+                                        chainon ($1, $8));
+                 $$.kind = ctsk_tagdef; }
        | enum_head '{'
-               { $$ = start_enum (NULL_TREE); }
+               { $<ttype>$ = start_enum (NULL_TREE); }
          enumlist maybecomma_warn '}' maybe_attribute
-               { $$ = finish_enum ($<ttype>3, nreverse ($4),
-                                   chainon ($1, $7)); }
+               { $$.spec = finish_enum ($<ttype>3, nreverse ($4),
+                                        chainon ($1, $7));
+                 $$.kind = ctsk_tagdef; }
        ;
 
 structsp_nonattr:
          struct_head identifier
-               { $$ = xref_tag (RECORD_TYPE, $2); }
+               { $$ = parser_xref_tag (RECORD_TYPE, $2); }
        | union_head identifier
-               { $$ = xref_tag (UNION_TYPE, $2); }
+               { $$ = parser_xref_tag (UNION_TYPE, $2); }
        | enum_head identifier
-               { $$ = xref_tag (ENUMERAL_TYPE, $2);
+               { $$ = parser_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"); }
+                 if (pedantic && !COMPLETE_TYPE_P ($$.spec))
+                   pedwarn ("ISO C forbids forward references to %<enum%> types"); }
        ;
 
 maybecomma:
@@ -1768,7 +1701,7 @@ maybecomma:
 maybecomma_warn:
          /* empty */
        | ','
-               { if (pedantic && ! flag_isoc99)
+               { if (pedantic && !flag_isoc99)
                    pedwarn ("comma at end of enumerator list"); }
        ;
 
@@ -1801,8 +1734,8 @@ component_decl_list2:     /* empty */
                    pedwarn ("extra semicolon in struct or union specified"); }
 @@ifobjc
        /* foo(sizeof(struct{ @defs(ClassName)})); */
-       | DEFS '(' CLASSNAME ')'
-               { $$ = nreverse (get_class_ivars_from_name ($3)); }
+       | AT_DEFS '(' CLASSNAME ')'
+               { $$ = nreverse (objc_get_class_ivars ($3)); }
 @@end_ifobjc
        ;
 
@@ -1815,10 +1748,8 @@ component_decl:
                  /* Support for unnamed structs or unions as members of
                     structs or unions (which is [a] useful and [b] supports
                     MS P-SDK).  */
-                 if (pedantic)
-                   pedwarn ("ISO C doesn't support unnamed structs/unions");
-
-                 $$ = grokfield(NULL, current_declspecs, NULL_TREE);
+                 $$ = grokfield (build_id_declarator (NULL_TREE),
+                                 current_declspecs, NULL_TREE);
                  POP_DECLSPEC_STACK; }
        | declspecs_nosc_nots setspecs components_notype
                { $$ = $3;
@@ -1826,7 +1757,7 @@ component_decl:
        | declspecs_nosc_nots
                { if (pedantic)
                    pedwarn ("ISO C forbids member declarations with no members");
-                 shadow_tag_warned ($1, pedantic);
+                 shadow_tag_warned (finish_declspecs ($1), pedantic);
                  $$ = NULL_TREE; }
        | error
                { $$ = NULL_TREE; }
@@ -1853,11 +1784,12 @@ component_declarator:
                  decl_attributes (&$$,
                                   chainon ($2, all_prefix_attributes), 0); }
        | declarator ':' expr_no_commas maybe_attribute
-               { $$ = grokfield ($1, current_declspecs, $3);
+               { $$ = grokfield ($1, current_declspecs, $3.value);
                  decl_attributes (&$$,
                                   chainon ($4, all_prefix_attributes), 0); }
        | ':' expr_no_commas maybe_attribute
-               { $$ = grokfield (NULL_TREE, current_declspecs, $2);
+               { $$ = grokfield (build_id_declarator (NULL_TREE),
+                                 current_declspecs, $2.value);
                  decl_attributes (&$$,
                                   chainon ($3, all_prefix_attributes), 0); }
        ;
@@ -1868,11 +1800,12 @@ component_notype_declarator:
                  decl_attributes (&$$,
                                   chainon ($2, all_prefix_attributes), 0); }
        | notype_declarator ':' expr_no_commas maybe_attribute
-               { $$ = grokfield ($1, current_declspecs, $3);
+               { $$ = grokfield ($1, current_declspecs, $3.value);
                  decl_attributes (&$$,
                                   chainon ($4, all_prefix_attributes), 0); }
        | ':' expr_no_commas maybe_attribute
-               { $$ = grokfield (NULL_TREE, current_declspecs, $2);
+               { $$ = grokfield (build_id_declarator (NULL_TREE),
+                                 current_declspecs, $2.value);
                  decl_attributes (&$$,
                                   chainon ($3, all_prefix_attributes), 0); }
        ;
@@ -1896,36 +1829,36 @@ enumerator:
          identifier
                { $$ = build_enumerator ($1, NULL_TREE); }
        | identifier '=' expr_no_commas
-               { $$ = build_enumerator ($1, $3); }
+               { $$ = build_enumerator ($1, $3.value); }
        ;
 
 typename:
          declspecs_nosc
                { pending_xref_error ();
-                 $<ttype>$ = $1; }
+                 $<dsptype>$ = finish_declspecs ($1); }
          absdcl
-               { $$ = build_tree_list ($<ttype>2, $3); }
+               { $$ = XOBNEW (&parser_obstack, struct c_type_name);
+                 $$->specs = $<dsptype>2;
+                 $$->declarator = $3; }
        ;
 
 absdcl:   /* an absolute declarator */
        /* empty */
-               { $$ = NULL_TREE; }
+               { $$ = build_id_declarator (NULL_TREE); }
        | absdcl1
        ;
 
 absdcl_maybe_attribute:   /* absdcl maybe_attribute, but not just attributes */
        /* empty */
-               { $$ = build_tree_list (build_tree_list (current_declspecs,
-                                                        NULL_TREE),
-                                       all_prefix_attributes); }
+               { $$ = build_c_parm (current_declspecs, all_prefix_attributes,
+                                    build_id_declarator (NULL_TREE)); }
        | absdcl1
-               { $$ = build_tree_list (build_tree_list (current_declspecs,
-                                                        $1),
-                                       all_prefix_attributes); }
+               { $$ = build_c_parm (current_declspecs, all_prefix_attributes,
+                                    $1); }
        | absdcl1_noea attributes
-               { $$ = build_tree_list (build_tree_list (current_declspecs,
-                                                        $1),
-                                       chainon ($2, all_prefix_attributes)); }
+               { $$ = build_c_parm (current_declspecs,
+                                    chainon ($2, all_prefix_attributes),
+                                    $1); }
        ;
 
 absdcl1:  /* a nonempty absolute declarator */
@@ -1941,38 +1874,41 @@ absdcl1_noea:
 
 absdcl1_ea:
          '*' maybe_type_quals_attrs
-               { $$ = make_pointer_declarator ($2, NULL_TREE); }
+               { $$ = make_pointer_declarator
+                   ($2, build_id_declarator (NULL_TREE)); }
        | '*' maybe_type_quals_attrs absdcl1_ea
                { $$ = make_pointer_declarator ($2, $3); }
        ;
 
 direct_absdcl1:
          '(' maybe_attribute absdcl1 ')'
-               { $$ = $2 ? tree_cons ($2, $3, NULL_TREE) : $3; }
+               { $$ = $2 ? build_attrs_declarator ($2, $3) : $3; }
        | direct_absdcl1 '(' parmlist
-               { $$ = build_nt (CALL_EXPR, $1, $3, NULL_TREE); }
+               { $$ = build_function_declarator ($3, $1); }
        | direct_absdcl1 array_declarator
-               { $$ = set_array_declarator_type ($2, $1, 1); }
+               { $$ = set_array_declarator_inner ($2, $1, true); }
        | '(' parmlist
-               { $$ = build_nt (CALL_EXPR, NULL_TREE, $2, NULL_TREE); }
+               { $$ = build_function_declarator
+                   ($2, build_id_declarator (NULL_TREE)); }
        | array_declarator
-               { $$ = set_array_declarator_type ($1, NULL_TREE, 1); }
+               { $$ = set_array_declarator_inner
+                   ($1, build_id_declarator (NULL_TREE), true); }
        ;
 
 /* The [...] part of a declarator for an array type.  */
 
 array_declarator:
        '[' maybe_type_quals_attrs expr_no_commas ']'
-               { $$ = build_array_declarator ($3, $2, 0, 0); }
+               { $$ = build_array_declarator ($3.value, $2, false, false); }
        | '[' maybe_type_quals_attrs ']'
-               { $$ = build_array_declarator (NULL_TREE, $2, 0, 0); }
+               { $$ = build_array_declarator (NULL_TREE, $2, false, false); }
        | '[' maybe_type_quals_attrs '*' ']'
-               { $$ = build_array_declarator (NULL_TREE, $2, 0, 1); }
+               { $$ = build_array_declarator (NULL_TREE, $2, false, true); }
        | '[' STATIC maybe_type_quals_attrs expr_no_commas ']'
-               { $$ = build_array_declarator ($4, $3, 1, 0); }
+               { $$ = build_array_declarator ($4.value, $3, true, false); }
        /* declspecs_nosc_nots is a synonym for type_quals_attrs.  */
        | '[' declspecs_nosc_nots STATIC expr_no_commas ']'
-               { $$ = build_array_declarator ($4, $2, 1, 0); }
+               { $$ = build_array_declarator ($4.value, $2, true, false); }
        ;
 
 /* A nonempty series of declarations and statements (possibly followed by
@@ -2034,51 +1970,9 @@ lineno_stmt_decl_or_labels:
 errstmt:  error ';'
        ;
 
-pushlevel:  /* empty */
-               { pushlevel (0);
-                 clear_last_expr ();
-                 add_scope_stmt (/*begin_p=*/1, /*partial_p=*/0);
-               }
-       ;
-
-poplevel:  /* empty */
-                {
-@@ifobjc
-                 if (c_dialect_objc ())
-                   objc_clear_super_receiver ();
-@@end_ifobjc
-                 $$ = add_scope_stmt (/*begin_p=*/0, /*partial_p=*/0);
-               }
-        ;
-
 /* Start and end blocks created for the new scopes of C99.  */
 c99_block_start: /* empty */
-               { if (flag_isoc99)
-                   {
-                     $$ = c_begin_compound_stmt ();
-                     pushlevel (0);
-                     clear_last_expr ();
-                     add_scope_stmt (/*begin_p=*/1, /*partial_p=*/0);
-                   }
-                 else
-                   $$ = NULL_TREE;
-               }
-       ;
-
-/* Productions using c99_block_start and c99_block_end will need to do what's
-   in compstmt: RECHAIN_STMTS ($1, COMPOUND_BODY ($1)); $$ = $2; where
-   $1 is the value of c99_block_start and $2 of c99_block_end.  */
-c99_block_end: /* empty */
-                { if (flag_isoc99)
-                   {
-                     tree scope_stmt = add_scope_stmt (/*begin_p=*/0, /*partial_p=*/0);
-                     $$ = poplevel (KEEP_MAYBE, 0, 0);
-                     SCOPE_STMT_BLOCK (TREE_PURPOSE (scope_stmt))
-                       = SCOPE_STMT_BLOCK (TREE_VALUE (scope_stmt))
-                       = $$;
-                   }
-                 else
-                   $$ = NULL_TREE; }
+               { $$ = c_begin_compound_stmt (flag_isoc99); }
        ;
 
 /* Read zero or more forward-declarations for labels
@@ -2102,7 +1996,7 @@ label_decl:
                    {
                      tree label = declare_label (TREE_VALUE (link));
                      C_DECLARED_LABEL_FLAG (label) = 1;
-                     add_decl_stmt (label);
+                     add_stmt (build_stmt (DECL_EXPR, label));
                    }
                }
        ;
@@ -2111,21 +2005,15 @@ label_decl:
    It causes syntax errors to ignore to the next openbrace.  */
 compstmt_or_error:
          compstmt
-               {}
+               { add_stmt ($1); }
        | error compstmt
        ;
 
-compstmt_start: '{' { compstmt_count++;
-                      $$ = c_begin_compound_stmt (); }
+compstmt_start: '{' { $$ = c_begin_compound_stmt (true); }
         ;
 
 compstmt_nostart: '}'
-               { $$ = convert (void_type_node, integer_zero_node); }
-       | pushlevel maybe_label_decls compstmt_contents_nonempty '}' poplevel
-               { $$ = poplevel (KEEP_MAYBE, 0, 0);
-                 SCOPE_STMT_BLOCK (TREE_PURPOSE ($5))
-                   = SCOPE_STMT_BLOCK (TREE_VALUE ($5))
-                   = $$; }
+       | maybe_label_decls compstmt_contents_nonempty '}'
        ;
 
 compstmt_contents_nonempty:
@@ -2135,75 +2023,18 @@ compstmt_contents_nonempty:
 
 compstmt_primary_start:
        '(' '{'
-               { if (current_function_decl == 0)
+               { if (cur_stmt_list == NULL)
                    {
-                     error ("braced-group within expression allowed only inside a function");
+                     error ("braced-group within expression allowed "
+                            "only inside a function");
                      YYERROR;
                    }
-                 /* We must force a BLOCK for this level
-                    so that, if it is not expanded later,
-                    there is a way to turn off the entire subtree of blocks
-                    that are contained in it.  */
-                 keep_next_level ();
-                 compstmt_count++;
-                 $$ = add_stmt (build_stmt (COMPOUND_STMT, last_tree));
+                 $$ = c_begin_stmt_expr ();
                }
         ;
 
 compstmt: compstmt_start compstmt_nostart
-               { RECHAIN_STMTS ($1, COMPOUND_BODY ($1));
-                 last_expr_type = NULL_TREE;
-                  $$ = $1; }
-       ;
-
-/* Value is number of statements counted as of the closeparen.  */
-simple_if:
-         if_prefix c99_block_lineno_labeled_stmt
-                { c_finish_then (); }
-/* Make sure c_expand_end_cond is run once
-   for each call to c_expand_start_cond.
-   Otherwise a crash is likely.  */
-       | if_prefix error
-       ;
-
-if_prefix:
-         /* We must build the IF_STMT node before parsing its
-            condition so that STMT_LINENO refers to the line
-            containing the "if", and not the line containing
-            the close-parenthesis.
-
-            c_begin_if_stmt returns the IF_STMT node, which
-            we later pass to c_expand_start_cond to fill
-            in the condition and other tidbits.  */
-          IF
-                { $<ttype>$ = c_begin_if_stmt (); }
-            '(' expr ')'
-               { c_expand_start_cond ((*lang_hooks.truthvalue_conversion) ($4),
-                                      compstmt_count,$<ttype>2);
-                 $<itype>$ = stmt_count;
-                 if_stmt_locus = $<location>-1; }
-        ;
-
-/* This is a subroutine of stmt.
-   It is used twice, once for valid DO statements
-   and once for catching errors in parsing the end test.  */
-do_stmt_start:
-         DO
-               { stmt_count++;
-                 compstmt_count++;
-                 c_in_iteration_stmt++;
-                 $<ttype>$
-                   = add_stmt (build_stmt (DO_STMT, NULL_TREE,
-                                           NULL_TREE));
-                 /* In the event that a parse error prevents
-                    parsing the complete do-statement, set the
-                    condition now.  Otherwise, we can get crashes at
-                    RTL-generation time.  */
-                 DO_COND ($<ttype>$) = error_mark_node; }
-         c99_block_lineno_labeled_stmt WHILE
-               { $$ = $<ttype>2;
-                 RECHAIN_STMTS ($$, DO_BODY ($$));
-                 c_in_iteration_stmt--; }
+               { $$ = c_end_compound_stmt ($1, true); }
        ;
 
 /* The forced readahead in here is because we might be at the end of a
@@ -2216,259 +2047,263 @@ save_location:
                  $$ = input_location; }
        ;
 
-lineno_labeled_stmt:
-         lineno_stmt
-       | lineno_label lineno_labeled_stmt
+lineno_labels:
+         /* empty */
+       | lineno_labels lineno_label
        ;
 
-/* Like lineno_labeled_stmt, but a block in C99.  */
+/* A labeled statement.  In C99 it also generates an implicit block.  */
 c99_block_lineno_labeled_stmt:
-         c99_block_start lineno_labeled_stmt c99_block_end
-               { if (flag_isoc99)
-                   RECHAIN_STMTS ($1, COMPOUND_BODY ($1)); }
+         c99_block_start lineno_labels lineno_stmt
+                { $$ = c_end_compound_stmt ($1, flag_isoc99); }
        ;
 
 lineno_stmt:
          save_location stmt
-               { if ($2)
-                   {
-                     STMT_LINENO ($2) = $1.line;
-                     /* ??? 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 occur when
-                        doing inlining at the tree level.  */
-                   }
+               {
+                 /* Two cases cannot and do not have line numbers associated:
+                    If stmt is degenerate, such as "2;", then stmt is an
+                    INTEGER_CST, which cannot hold line numbers.  But that's
+                    ok because the statement will either be changed to a
+                    MODIFY_EXPR during gimplification of the statement expr,
+                    or discarded.  If stmt was compound, but without new
+                    variables, we will have skipped the creation of a BIND
+                    and will have a bare STATEMENT_LIST.  But that's ok
+                    because (recursively) all of the component statments
+                    should already have line numbers assigned.  */
+                 if ($2 && EXPR_P ($2))
+                   SET_EXPR_LOCATION ($2, $1);
                }
        ;
 
 lineno_label:
          save_location label
-               { if ($2)
-                   {
-                     STMT_LINENO ($2) = $1.line;
-                   }
-               }
+               { if ($2) SET_EXPR_LOCATION ($2, $1); }
        ;
 
-select_or_iter_stmt:
-         simple_if ELSE
-               { c_expand_start_else ();
-                 $<itype>1 = stmt_count; }
-         c99_block_lineno_labeled_stmt
-                { c_finish_else ();
-                 c_expand_end_cond ();
-                 if (extra_warnings && stmt_count == $<itype>1)
-                   warning ("empty body in an else-statement"); }
-       | simple_if %prec IF
-               { c_expand_end_cond ();
-                 /* This warning is here instead of in simple_if, because we
-                    do not want a warning if an empty if is followed by an
-                    else statement.  Increment stmt_count so we don't
-                    give a second error if this is a nested `if'.  */
-                 if (extra_warnings && stmt_count++ == $<itype>1)
-                   warning ("%Hempty body in an if-statement",
-                             &if_stmt_locus); }
-/* Make sure c_expand_end_cond is run once
-   for each call to c_expand_start_cond.
-   Otherwise a crash is likely.  */
-       | simple_if ELSE error
-               { c_expand_end_cond (); }
-       /* We must build the WHILE_STMT node before parsing its
-         condition so that STMT_LINENO refers to the line
-         containing the "while", and not the line containing
-         the close-parenthesis.
-
-         c_begin_while_stmt returns the WHILE_STMT node, which
-         we later pass to c_finish_while_stmt_cond to fill
-         in the condition and other tidbits.  */
-       | WHILE
-                { stmt_count++;
-                 $<ttype>$ = c_begin_while_stmt (); }
-         '(' expr ')'
-                { c_in_iteration_stmt++;
-                 $4 = (*lang_hooks.truthvalue_conversion) ($4);
-                 c_finish_while_stmt_cond
-                   ((*lang_hooks.truthvalue_conversion) ($4), $<ttype>2);
-                 $<ttype>$ = add_stmt ($<ttype>2); }
-         c99_block_lineno_labeled_stmt
-                { c_in_iteration_stmt--;
-                 RECHAIN_STMTS ($<ttype>6, WHILE_BODY ($<ttype>6)); }
-       | do_stmt_start
-         '(' expr ')' ';'
-                { DO_COND ($1) = (*lang_hooks.truthvalue_conversion) ($3); }
-       | do_stmt_start error
-               { }
-       | FOR
-               { $<ttype>$ = build_stmt (FOR_STMT, NULL_TREE, NULL_TREE,
-                                         NULL_TREE, NULL_TREE);
-                 add_stmt ($<ttype>$); }
-         '(' for_init_stmt
-               { stmt_count++;
-                 RECHAIN_STMTS ($<ttype>2, FOR_INIT_STMT ($<ttype>2)); }
-         xexpr ';'
-                { if ($6)
-                   FOR_COND ($<ttype>2)
-                     = (*lang_hooks.truthvalue_conversion) ($6); }
-         xexpr ')'
-                { c_in_iteration_stmt++;
-                 FOR_EXPR ($<ttype>2) = $9; }
-         c99_block_lineno_labeled_stmt
-                { RECHAIN_STMTS ($<ttype>2, FOR_BODY ($<ttype>2));
-                 c_in_iteration_stmt--;}
-       | SWITCH '(' expr ')'
-               { stmt_count++;
-                 $<ttype>$ = c_start_case ($3);
-                 c_in_case_stmt++; }
-         c99_block_lineno_labeled_stmt
-                { c_finish_case ();
-                 c_in_case_stmt--; }
+condition: save_location expr
+               { $$ = lang_hooks.truthvalue_conversion ($2.value);
+                 if (EXPR_P ($$))
+                   SET_EXPR_LOCATION ($$, $1); }
        ;
 
-for_init_stmt:
-         xexpr ';'
-               { add_stmt (build_stmt (EXPR_STMT, $1)); }
-       | decl
-               { check_for_loop_decls (); }
+/* Implement -Wparenthesis by special casing IF statement directly nested
+   within IF statement.  This requires some amount of duplication of the
+   productions under c99_block_lineno_labeled_stmt in order to work out.
+   But it's still likely more maintainable than lots of state outside the
+   parser...  */
+
+if_statement_1:
+       c99_block_start lineno_labels if_statement
+               { $$ = c_end_compound_stmt ($1, flag_isoc99); }
+       ;
+
+if_statement_2:
+         c99_block_start lineno_labels ';'
+               { if (extra_warnings)
+                   add_stmt (build (NOP_EXPR, NULL_TREE, NULL_TREE));
+                 $$ = c_end_compound_stmt ($1, flag_isoc99); }
+       | c99_block_lineno_labeled_stmt
+       ;
+
+if_statement:
+         IF c99_block_start save_location '(' condition ')'
+           if_statement_1 ELSE if_statement_2
+               { c_finish_if_stmt ($3, $5, $7, $9, true);
+                 add_stmt (c_end_compound_stmt ($2, flag_isoc99)); }
+       | IF c99_block_start save_location '(' condition ')'
+           if_statement_2 ELSE if_statement_2
+               { c_finish_if_stmt ($3, $5, $7, $9, false);
+                 add_stmt (c_end_compound_stmt ($2, flag_isoc99)); }
+       | IF c99_block_start save_location '(' condition ')'
+           if_statement_1                              %prec IF
+               { c_finish_if_stmt ($3, $5, $7, NULL, true);
+                 add_stmt (c_end_compound_stmt ($2, flag_isoc99)); }
+       | IF c99_block_start save_location '(' condition ')'
+           if_statement_2                              %prec IF
+               { c_finish_if_stmt ($3, $5, $7, NULL, false);
+                 add_stmt (c_end_compound_stmt ($2, flag_isoc99)); }
+       ;
+
+start_break: /* empty */
+               { $$ = c_break_label; c_break_label = NULL; }
+       ;
+
+start_continue: /* empty */
+               { $$ = c_cont_label; c_cont_label = NULL; }
+       ;
+
+while_statement:
+       WHILE c99_block_start save_location '(' condition ')'
+       start_break start_continue c99_block_lineno_labeled_stmt
+               { c_finish_loop ($3, $5, NULL, $9, c_break_label,
+                                c_cont_label, true);
+                 add_stmt (c_end_compound_stmt ($2, flag_isoc99));
+                 c_break_label = $7; c_cont_label = $8; }
+       ;
+
+do_statement:
+       DO c99_block_start save_location start_break start_continue
+       c99_block_lineno_labeled_stmt WHILE
+               { $<ttype>$ = c_break_label; c_break_label = $4; }
+               { $<ttype>$ = c_cont_label; c_cont_label = $5; }
+       '(' condition ')' ';'
+                { c_finish_loop ($3, $11, NULL, $6, $<ttype>8,
+                                $<ttype>9, false);
+                 add_stmt (c_end_compound_stmt ($2, flag_isoc99)); }
        ;
 
 xexpr:
        /* empty */
                { $$ = NULL_TREE; }
        | expr
+               { $$ = $1.value; }
        ;
 
-/* Parse a single real statement, not including any labels.  */
-stmt:
-         compstmt
-               { stmt_count++; $$ = $1; }
-       | expr ';'
-               { stmt_count++;
-                 $$ = c_expand_expr_stmt ($1); }
-       | c99_block_start select_or_iter_stmt c99_block_end
-               { if (flag_isoc99)
-                   RECHAIN_STMTS ($1, COMPOUND_BODY ($1));
-                 $$ = NULL_TREE; }
+for_init_stmt:
+         xexpr ';'
+               { c_finish_expr_stmt ($1); }
+       | decl
+               { check_for_loop_decls (); }
+       ;
+
+for_cond_expr: save_location xexpr
+               { if ($2)
+                   {
+                     $$ = lang_hooks.truthvalue_conversion ($2);
+                     if (EXPR_P ($$))
+                       SET_EXPR_LOCATION ($$, $1);
+                   }
+                 else
+                   $$ = NULL;
+               }
+       ;
+
+for_incr_expr: xexpr
+               { $$ = c_process_expr_stmt ($1); }
+       ;
+
+for_statement:
+       FOR c99_block_start '(' for_init_stmt
+       save_location for_cond_expr ';' for_incr_expr ')'
+       start_break start_continue c99_block_lineno_labeled_stmt
+               { c_finish_loop ($5, $6, $8, $12, c_break_label,
+                                c_cont_label, true);
+                 add_stmt (c_end_compound_stmt ($2, flag_isoc99));
+                 c_break_label = $10; c_cont_label = $11; }
+       ;
+
+switch_statement:
+       SWITCH c99_block_start '(' expr ')'
+               { $<ttype>$ = c_start_case ($4.value); }
+       start_break c99_block_lineno_labeled_stmt
+                { c_finish_case ($8);
+                 if (c_break_label)
+                   add_stmt (build (LABEL_EXPR, void_type_node,
+                                    c_break_label));
+                 c_break_label = $7;
+                 add_stmt (c_end_compound_stmt ($2, flag_isoc99)); }
+       ;
+
+/* Parse a single real statement, not including any labels or compounds.  */
+stmt_nocomp:
+         expr ';'
+               { $$ = c_finish_expr_stmt ($1.value); }
+       | if_statement
+               { $$ = NULL_TREE; }
+       | while_statement
+               { $$ = NULL_TREE; }
+       | do_statement
+               { $$ = NULL_TREE; }
+       | for_statement
+               { $$ = NULL_TREE; }
+       | switch_statement
+               { $$ = NULL_TREE; }
        | BREAK ';'
-               { stmt_count++;
-               if (!(c_in_iteration_stmt || c_in_case_stmt))
-                 {
-                   error ("break statement not within loop or switch");
-                   $$ = NULL_TREE;
-                 }
-               else
-                 $$ = add_stmt (build_break_stmt ()); }
+               { $$ = c_finish_bc_stmt (&c_break_label, true); }
        | CONTINUE ';'
-                { stmt_count++;
-               if (!c_in_iteration_stmt)
-                 {
-                   error ("continue statement not within a loop");
-                   $$ = NULL_TREE;
-                 }
-               else
-                 $$ = add_stmt (build_continue_stmt ()); }
+                { $$ = c_finish_bc_stmt (&c_cont_label, false); }
        | RETURN ';'
-                { stmt_count++;
-                 $$ = c_expand_return (NULL_TREE); }
+                { $$ = c_finish_return (NULL_TREE); }
        | RETURN expr ';'
-                { stmt_count++;
-                 $$ = c_expand_return ($2); }
+                { $$ = c_finish_return ($2.value); }
        | asm_stmt
        | GOTO identifier ';'
-               { tree decl;
-                 stmt_count++;
-                 decl = lookup_label ($2);
-                 if (decl != 0)
-                   {
-                     TREE_USED (decl) = 1;
-                     $$ = add_stmt (build_stmt (GOTO_STMT, decl));
-                   }
-                 else
-                   $$ = NULL_TREE;
-               }
+               { $$ = c_finish_goto_label ($2); }
        | 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)); }
+               { $$ = c_finish_goto_ptr ($3.value); }
        | ';'
                { $$ = NULL_TREE; }
 @@ifobjc
        | AT_THROW expr ';'
-               { stmt_count++;
-                 $$ = objc_build_throw_stmt ($2);
-               }
+               { $$ = objc_build_throw_stmt ($2.value); }
        | AT_THROW ';'
-               { stmt_count++;
-                 $$ = objc_build_throw_stmt (NULL_TREE);
-               }
+               { $$ = objc_build_throw_stmt (NULL_TREE); }
        | objc_try_catch_stmt
-               { objc_build_finally_prologue (); }
-         objc_finally_block
-               { $$ = objc_build_try_catch_finally_stmt ($1, $3); }
-       | AT_SYNCHRONIZED '(' expr ')'
-               { objc_build_synchronized_prologue ($3); }
-         compstmt
-               { $$ = objc_build_synchronized_epilogue (); }
+               { $$ = NULL_TREE; }
+       | AT_SYNCHRONIZED save_location '(' expr ')' compstmt
+               { objc_build_synchronized ($2, $4.value, $6); $$ = NULL_TREE; }
        ;
 
-objc_try_catch_stmt:
-         objc_try_stmt
-               { objc_build_try_epilogue (1); }
-         objc_catch_list
-               { objc_build_catch_epilogue (); $$ = 1; }
-       | objc_try_stmt
-               { objc_build_try_epilogue (0); $$ = 0; }
+objc_catch_prefix:
+       AT_CATCH '(' parm ')'
+               { objc_begin_catch_clause (grokparm ($3)); }
        ;
 
+objc_catch_clause:
+         objc_catch_prefix '{' compstmt_nostart
+               { objc_finish_catch_clause (); }
+       | objc_catch_prefix '{' error '}'
+               { objc_finish_catch_clause (); }
+       ;
 
-objc_try_stmt:
-         AT_TRY
-               { objc_build_try_prologue (); }
-         compstmt
+objc_opt_catch_list:
+         /* empty */
+       | objc_opt_catch_list objc_catch_clause
        ;
 
-objc_catch_list:
-         objc_catch_list objc_catch_block
-       | objc_catch_block
+objc_try_catch_clause:
+       AT_TRY save_location compstmt
+               { objc_begin_try_stmt ($2, $3); }
+       objc_opt_catch_list
        ;
 
-objc_catch_block:
-         AT_CATCH '(' parm ')'
-               { objc_build_catch_stmt ($3); }
-         compstmt
-               { stmt_count++; }
+objc_finally_clause:
+       AT_FINALLY save_location compstmt
+               { objc_build_finally_clause ($2, $3); }
        ;
 
-objc_finally_block:
-         AT_FINALLY compstmt
-           { $$ = 1; }
-       | /* NULL */
-           { $$ = 0; }
+objc_try_catch_stmt:
+         objc_try_catch_clause
+               { objc_finish_try_stmt (); }
+       | objc_try_catch_clause objc_finally_clause
+               { objc_finish_try_stmt (); }
 @@end_ifobjc
        ;
 
+/* Parse a single or compound real statement, not including any labels.  */
+stmt:
+         compstmt
+               { add_stmt ($1); $$ = NULL_TREE; }
+       | stmt_nocomp
+       ;
+
 /* Any kind of label, including jump labels and case labels.
    ANSI C accepts labels only before statements, but we allow them
    also at the end of a compound statement.  */
 
 label:   CASE expr_no_commas ':'
-                { stmt_count++;
-                 $$ = do_case ($2, NULL_TREE); }
+                { $$ = do_case ($2.value, NULL_TREE); }
        | CASE expr_no_commas ELLIPSIS expr_no_commas ':'
-                { stmt_count++;
-                 $$ = do_case ($2, $4); }
+                { $$ = do_case ($2.value, $4.value); }
        | DEFAULT ':'
-                { stmt_count++;
-                 $$ = do_case (NULL_TREE, NULL_TREE); }
+                { $$ = do_case (NULL_TREE, NULL_TREE); }
        | identifier save_location ':' maybe_attribute
                { tree label = define_label ($2, $1);
-                 stmt_count++;
                  if (label)
                    {
                      decl_attributes (&label, $4, 0);
-                     $$ = add_stmt (build_stmt (LABEL_STMT, label));
+                     $$ = add_stmt (build_stmt (LABEL_EXPR, label));
                    }
                  else
                    $$ = NULL_TREE;
@@ -2480,8 +2315,9 @@ label:      CASE expr_no_commas ':'
 /* simple_asm_expr is used in restricted contexts, where a full
    expression with inputs and outputs does not make sense.  */
 simple_asm_expr:
-       ASM_KEYWORD '(' STRING ')'
-               { $$ = $3; }
+       ASM_KEYWORD stop_string_translation
+             '(' STRING ')' start_string_translation
+               { $$ = $4; }
        ;
 
 /* maybeasm: used for assembly names for declarations */
@@ -2495,14 +2331,16 @@ maybeasm:
 asmdef:
        simple_asm_expr ';'
                { assemble_asm ($1); }
+        | ASM_KEYWORD error start_string_translation ';'
+                {}
        ;
 
 /* Full-blown asm statement with inputs, outputs, clobbers, and
    volatile tag allowed.  */
 asm_stmt:
-       ASM_KEYWORD maybe_volatile '(' asm_argument ')' ';'
-               { stmt_count++;
-                 $$ = build_asm_stmt ($2, $4); }
+       ASM_KEYWORD maybe_volatile stop_string_translation
+               '(' asm_argument ')' start_string_translation ';'
+               { $$ = build_asm_stmt ($2, $5); }
        ;
 
 asm_argument:
@@ -2550,12 +2388,14 @@ nonnull_asm_operands:
        ;
 
 asm_operand:
-         STRING '(' expr ')'
-               { $$ = build_tree_list (build_tree_list (NULL_TREE, $1), $3); }
-       | '[' identifier ']' STRING '(' expr ')'
+         STRING start_string_translation '(' expr ')' stop_string_translation
+               { $$ = build_tree_list (build_tree_list (NULL_TREE, $1),
+                                       $4.value); }
+       | '[' identifier ']' STRING start_string_translation
+         '(' expr ')' stop_string_translation
                { $2 = build_string (IDENTIFIER_LENGTH ($2),
                                     IDENTIFIER_POINTER ($2));
-                 $$ = build_tree_list (build_tree_list ($2, $4), $6); }
+                 $$ = build_tree_list (build_tree_list ($2, $4), $7.value); }
        ;
 
 asm_clobbers:
@@ -2564,6 +2404,15 @@ asm_clobbers:
        | asm_clobbers ',' STRING
                { $$ = tree_cons (NULL_TREE, $3, $1); }
        ;
+
+stop_string_translation:
+        { c_lex_string_translate = 0; }
+        ;
+
+start_string_translation:
+        { c_lex_string_translate = 1; }
+        ;
+
 \f
 /* This is what appears inside the parens in a function declarator.
    Its value is a list of ..._TYPE nodes.  Attributes must appear here
@@ -2572,11 +2421,11 @@ asm_clobbers:
    "void bar (int (__attribute__((__mode__(SI))) int foo));".  */
 parmlist:
          maybe_attribute
-               { pushlevel (0);
+               { push_scope ();
                  declare_parm_level (); }
          parmlist_1
                { $$ = $3;
-                 poplevel (0, 0, 0); }
+                 pop_scope (); }
        ;
 
 parmlist_1:
@@ -2589,32 +2438,34 @@ parmlist_1:
          parmlist_1
                { $$ = $6; }
        | error ')'
-               { $$ = tree_cons (NULL_TREE, NULL_TREE, NULL_TREE); }
+               { $$ = XOBNEW (&parser_obstack, struct c_arg_info);
+                 $$->parms = 0;
+                 $$->tags = 0;
+                 $$->types = 0;
+                 $$->others = 0; }
        ;
 
 /* This is what appears inside the parens in a function declarator.
-   Is value is represented in the format that grokdeclarator expects.  */
+   Its value is represented in the format that grokdeclarator expects.  */
 parmlist_2:  /* empty */
-               { $$ = get_parm_info (0); }
+               { $$ = XOBNEW (&parser_obstack, struct c_arg_info);
+                 $$->parms = 0;
+                 $$->tags = 0;
+                 $$->types = 0;
+                 $$->others = 0; }
        | ELLIPSIS
-               { $$ = get_parm_info (0);
-                 /* Gcc used to allow this as an extension.  However, it does
-                    not work for all targets, and thus has been disabled.
-                    Also, since func (...) and func () are indistinguishable,
-                    it caused problems with the code in expand_builtin which
-                    tries to verify that BUILT_IN_NEXT_ARG is being used
-                    correctly.  */
-                 error ("ISO C requires a named argument before `...'");
-                 parsing_iso_function_signature = true;
+               { $$ = XOBNEW (&parser_obstack, struct c_arg_info);
+                 $$->parms = 0;
+                 $$->tags = 0;
+                 $$->others = 0;
+                 /* Suppress -Wold-style-definition for this case.  */
+                 $$->types = error_mark_node;
+                 error ("ISO C requires a named argument before %<...%>");
                }
        | parms
-               { $$ = get_parm_info (1);
-                 parsing_iso_function_signature = true;
-               }
+               { $$ = get_parm_info (/*ellipsis=*/false); }
        | parms ',' ELLIPSIS
-               { $$ = get_parm_info (0);
-                 parsing_iso_function_signature = true;
-               }
+               { $$ = get_parm_info (/*ellipsis=*/true); }
        ;
 
 parms:
@@ -2628,22 +2479,19 @@ parms:
    as found in a parmlist.  */
 parm:
          declspecs_ts setspecs parm_declarator maybe_attribute
-               { $$ = build_tree_list (build_tree_list (current_declspecs,
-                                                        $3),
-                                       chainon ($4, all_prefix_attributes));
+               { $$ = build_c_parm (current_declspecs,
+                                    chainon ($4, all_prefix_attributes), $3);
                  POP_DECLSPEC_STACK; }
        | declspecs_ts setspecs notype_declarator maybe_attribute
-               { $$ = build_tree_list (build_tree_list (current_declspecs,
-                                                        $3),
-                                       chainon ($4, all_prefix_attributes));
+               { $$ = build_c_parm (current_declspecs,
+                                    chainon ($4, all_prefix_attributes), $3);
                  POP_DECLSPEC_STACK; }
        | declspecs_ts setspecs absdcl_maybe_attribute
                { $$ = $3;
                  POP_DECLSPEC_STACK; }
        | declspecs_nots setspecs notype_declarator maybe_attribute
-               { $$ = build_tree_list (build_tree_list (current_declspecs,
-                                                        $3),
-                                       chainon ($4, all_prefix_attributes));
+               { $$ = build_c_parm (current_declspecs,
+                                    chainon ($4, all_prefix_attributes), $3);
                  POP_DECLSPEC_STACK; }
 
        | declspecs_nots setspecs absdcl_maybe_attribute
@@ -2655,22 +2503,19 @@ parm:
    stack.  */
 firstparm:
          declspecs_ts_nosa setspecs_fp parm_declarator maybe_attribute
-               { $$ = build_tree_list (build_tree_list (current_declspecs,
-                                                        $3),
-                                       chainon ($4, all_prefix_attributes));
+               { $$ = build_c_parm (current_declspecs,
+                                    chainon ($4, all_prefix_attributes), $3);
                  POP_DECLSPEC_STACK; }
        | declspecs_ts_nosa setspecs_fp notype_declarator maybe_attribute
-               { $$ = build_tree_list (build_tree_list (current_declspecs,
-                                                        $3),
-                                       chainon ($4, all_prefix_attributes));
+               { $$ = build_c_parm (current_declspecs,
+                                    chainon ($4, all_prefix_attributes), $3);
                  POP_DECLSPEC_STACK; }
        | declspecs_ts_nosa setspecs_fp absdcl_maybe_attribute
                { $$ = $3;
                  POP_DECLSPEC_STACK; }
        | declspecs_nots_nosa setspecs_fp notype_declarator maybe_attribute
-               { $$ = build_tree_list (build_tree_list (current_declspecs,
-                                                        $3),
-                                       chainon ($4, all_prefix_attributes));
+               { $$ = build_c_parm (current_declspecs,
+                                    chainon ($4, all_prefix_attributes), $3);
                  POP_DECLSPEC_STACK; }
 
        | declspecs_nots_nosa setspecs_fp absdcl_maybe_attribute
@@ -2689,27 +2534,24 @@ setspecs_fp:
    Its value is a list of ..._TYPE nodes or a list of identifiers.  */
 parmlist_or_identifiers:
          maybe_attribute
-               { pushlevel (0);
+               { push_scope ();
                  declare_parm_level (); }
          parmlist_or_identifiers_1
                { $$ = $3;
-                 poplevel (0, 0, 0); }
+                 pop_scope (); }
        ;
 
 parmlist_or_identifiers_1:
          parmlist_1
        | identifiers ')'
-               { tree t;
-                 for (t = $1; t; t = TREE_CHAIN (t))
-                   if (TREE_VALUE (t) == NULL_TREE)
-                     error ("`...' in old-style identifier list");
-                 $$ = tree_cons (NULL_TREE, NULL_TREE, $1);
+               { $$ = XOBNEW (&parser_obstack, struct c_arg_info);
+                 $$->parms = 0;
+                 $$->tags = 0;
+                 $$->types = $1;
+                 $$->others = 0;
 
                  /* Make sure we have a parmlist after attributes.  */
-                 if ($<ttype>-1 != 0
-                     && (TREE_CODE ($$) != TREE_LIST
-                         || TREE_PURPOSE ($$) == 0
-                         || TREE_CODE (TREE_PURPOSE ($$)) != PARM_DECL))
+                 if ($<ttype>-1 != 0)
                    YYERROR1;
                }
        ;
@@ -2732,7 +2574,7 @@ identifiers_or_typenames:
 
 extension:
        EXTENSION
-               { $$ = SAVE_EXT_FLAGS();
+               { $$ = SAVE_EXT_FLAGS ();
                  pedantic = 0;
                  warn_pointer_arith = 0;
                  warn_traditional = 0;
@@ -2748,16 +2590,9 @@ objcdef:
        | aliasdecl
        | protocoldef
        | methoddef
-       | END
+       | AT_END
                {
-                 if (objc_implementation_context)
-                    {
-                     finish_class (objc_implementation_context);
-                     objc_ivar_chain = NULL_TREE;
-                     objc_implementation_context = NULL_TREE;
-                   }
-                 else
-                   warning ("`@end' must appear in an implementation context");
+                 objc_finish_implementation ();
                }
        ;
 
@@ -2770,14 +2605,14 @@ identifier_list:
        ;
 
 classdecl:
-         CLASS identifier_list ';'
+         AT_CLASS identifier_list ';'
                {
                  objc_declare_class ($2);
                }
        ;
 
 aliasdecl:
-         ALIAS identifier identifier ';'
+         AT_ALIAS identifier identifier ';'
                {
                  objc_declare_alias ($2, $3);
                }
@@ -2794,72 +2629,58 @@ class_ivars:
        ;
 
 classdef:
-         INTERFACE identifier superclass protocolrefs
+         AT_INTERFACE identifier superclass protocolrefs
                {
-                 objc_interface_context = objc_ivar_context
-                   = start_class (CLASS_INTERFACE_TYPE, $2, $3, $4);
-                  objc_public_flag = 0;
+                 objc_start_class_interface ($2, $3, $4);
                }
          class_ivars
                {
-                  continue_class (objc_interface_context);
+                 objc_continue_interface ();
                }
-         methodprotolist END
+         methodprotolist AT_END
                {
-                 finish_class (objc_interface_context);
-                 objc_interface_context = NULL_TREE;
+                 objc_finish_interface ();
                }
 
-       | IMPLEMENTATION identifier superclass
+       | AT_IMPLEMENTATION identifier superclass
                {
-                 objc_implementation_context = objc_ivar_context
-                   = start_class (CLASS_IMPLEMENTATION_TYPE, $2, $3, NULL_TREE);
-                  objc_public_flag = 0;
+                 objc_start_class_implementation ($2, $3);
                }
          class_ivars
                {
-                  objc_ivar_chain
-                   = continue_class (objc_implementation_context);
+                 objc_continue_implementation ();
                }
 
-       | INTERFACE identifier '(' identifier ')' protocolrefs
+       | AT_INTERFACE identifier '(' identifier ')' protocolrefs
                {
-                 objc_interface_context
-                   = start_class (CATEGORY_INTERFACE_TYPE, $2, $4, $6);
-                  continue_class (objc_interface_context);
+                 objc_start_category_interface ($2, $4, $6);
                }
-         methodprotolist END
+         methodprotolist AT_END
                {
-                 finish_class (objc_interface_context);
-                 objc_interface_context = NULL_TREE;
+                 objc_finish_interface ();
                }
 
-       | IMPLEMENTATION identifier '(' identifier ')'
+       | AT_IMPLEMENTATION identifier '(' identifier ')'
                {
-                 objc_implementation_context
-                   = start_class (CATEGORY_IMPLEMENTATION_TYPE, $2, $4, NULL_TREE);
-                  objc_ivar_chain
-                   = continue_class (objc_implementation_context);
+                 objc_start_category_implementation ($2, $4);
                }
        ;
 
 protocoldef:
-         PROTOCOL identifier protocolrefs
+         AT_PROTOCOL identifier protocolrefs
                {
                  objc_pq_context = 1;
-                 objc_interface_context
-                   = start_protocol(PROTOCOL_INTERFACE_TYPE, $2, $3);
+                 objc_start_protocol ($2, $3);
                }
-         methodprotolist END
+         methodprotolist AT_END
                {
                  objc_pq_context = 0;
-                 finish_protocol(objc_interface_context);
-                 objc_interface_context = NULL_TREE;
+                 objc_finish_interface ();
                }
        /* The @protocol forward-declaration production introduces a
           reduce/reduce conflict on ';', which should be resolved in
           favor of the production 'identifier_list -> identifier'.  */
-       | PROTOCOL identifier_list ';'
+       | AT_PROTOCOL identifier_list ';'
                {
                  objc_declare_protocols ($2);
                }
@@ -2884,109 +2705,67 @@ non_empty_protocolrefs:
        ;
 
 ivar_decl_list:
-          ivar_decl_list visibility_spec ivar_decls
-        | ivar_decls
+         /* empty */
+        | ivar_decl_list visibility_spec ivar_decls
         ;
 
 visibility_spec:
-         PRIVATE { objc_public_flag = 2; }
-       | PROTECTED { objc_public_flag = 0; }
-       | PUBLIC { objc_public_flag = 1; }
+         /* empty */
+       | AT_PRIVATE { objc_set_visibility (2); }
+       | AT_PROTECTED { objc_set_visibility (0); }
+       | AT_PUBLIC { objc_set_visibility (1); }
        ;
 
 ivar_decls:
-          /* empty */
-               {
-                  $$ = NULL_TREE;
-                }
+         /* empty */
        | ivar_decls ivar_decl ';'
        | ivar_decls ';'
                {
-                  if (pedantic)
+                 if (pedantic)
                    pedwarn ("extra semicolon in struct or union specified");
-                }
+               }
        ;
 
-
-/* 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.  */
-
 ivar_decl:
-       declspecs_nosc_ts setspecs ivars
-               { $$ = $3;
-                 POP_DECLSPEC_STACK; }
-       | declspecs_nosc_nots setspecs ivars
-               { $$ = $3;
-                 POP_DECLSPEC_STACK; }
-       | error
-               { $$ = NULL_TREE; }
-       ;
+       component_decl
+               {
+                 /* Comma-separated ivars are chained together in
+                    reverse order; add them one by one.  */
+                 tree ivar = nreverse ($1);
 
-ivars:
-         /* empty */
-               { $$ = NULL_TREE; }
-       | ivar_declarator
-       | ivars ',' maybe_resetattrs ivar_declarator
+                 for (; ivar; ivar = TREE_CHAIN (ivar))
+                   objc_add_instance_variable (copy_node (ivar));
+               }
        ;
 
-ivar_declarator:
-         declarator
-               {
-                 $$ = add_instance_variable (objc_ivar_context,
-                                             objc_public_flag,
-                                             $1, current_declspecs,
-                                             NULL_TREE);
-                }
-       | declarator ':' expr_no_commas
-               {
-                 $$ = add_instance_variable (objc_ivar_context,
-                                             objc_public_flag,
-                                             $1, current_declspecs, $3);
-                }
-       | ':' expr_no_commas
+opt_semi:
+         /* NULL */
+       | ';'
                {
-                 $$ = add_instance_variable (objc_ivar_context,
-                                             objc_public_flag,
-                                             NULL_TREE,
-                                             current_declspecs, $2);
-                }
+                 if (pedantic)
+                   pedwarn ("extra semicolon in method definition specified");
+               }
        ;
 
 methodtype:
          '+'
-               { objc_inherit_code = CLASS_METHOD_DECL; }
        | '-'
-               { objc_inherit_code = INSTANCE_METHOD_DECL; }
        ;
 
 methoddef:
          methodtype
                {
+                 objc_set_method_type ($1);
                  objc_pq_context = 1;
-                 if (!objc_implementation_context)
-                   fatal_error ("method definition not in class context");
                }
-         methoddecl
+         methoddecl opt_semi
                {
                  objc_pq_context = 0;
-                 objc_add_method (objc_implementation_context,
-                                  $3,
-                                  objc_inherit_code == CLASS_METHOD_DECL);
-                 start_method_def ($3);
-               }
-         optarglist
-               {
-                 continue_method_def ();
+                 objc_start_method_definition ($3);
                }
          compstmt_or_error
                {
-                 finish_method_def ();
+                 objc_finish_method_definition (current_function_decl);
                }
        ;
 
@@ -3008,6 +2787,7 @@ semi_or_error:
 methodproto:
          methodtype
                {
+                 objc_set_method_type ($1);
                  /* Remember protocol qualifiers in prototypes.  */
                  objc_pq_context = 1;
                }
@@ -3015,109 +2795,63 @@ methodproto:
                {
                  /* Forget protocol qualifiers here.  */
                  objc_pq_context = 0;
-                 objc_add_method (objc_interface_context,
-                                  $3,
-                                  objc_inherit_code == CLASS_METHOD_DECL);
+                 objc_add_method_declaration ($3);
                }
          semi_or_error
        ;
 
 methoddecl:
-         '(' typename ')' unaryselector
+         '(' objc_typename ')' unaryselector
                {
-                 $$ = build_method_decl (objc_inherit_code, $2, $4, NULL_TREE);
+                 $$ = objc_build_method_signature ($2, $4, NULL_TREE);
                }
 
        | unaryselector
                {
-                 $$ = build_method_decl (objc_inherit_code, NULL_TREE, $1, NULL_TREE);
+                 $$ = objc_build_method_signature (NULL_TREE, $1, NULL_TREE);
                }
 
-       | '(' typename ')' keywordselector optparmlist
+       | '(' objc_typename ')' keywordselector optparmlist
                {
-                 $$ = build_method_decl (objc_inherit_code, $2, $4, $5);
+                 $$ = objc_build_method_signature ($2, $4, $5);
                }
 
        | keywordselector optparmlist
                {
-                 $$ = build_method_decl (objc_inherit_code, NULL_TREE, $1, $2);
+                 $$ = objc_build_method_signature (NULL_TREE, $1, $2);
                }
        ;
 
-/* "optarglist" assumes that start_method_def has already been called...
-   if it is not, the "xdecls" will not be placed in the proper scope */
-
-optarglist:
-         /* empty */
-       | ';' myxdecls
-       ;
-
-/* to get around the following situation: "int foo (int a) int b; {}" that
-   is synthesized when parsing "- a:a b:b; id c; id d; { ... }" */
+/* Optional ObjC method parameters follow the C syntax, and may include '...'
+   to denote a variable number of arguments.  */
 
-myxdecls:
-         /* empty */
-       | mydecls
-       ;
-
-mydecls:
-       mydecl
-       | errstmt
-       | mydecls mydecl
-       | mydecl errstmt
-       ;
-
-mydecl:
-       declspecs_ts setspecs myparms ';'
-               { POP_DECLSPEC_STACK; }
-       | declspecs_ts ';'
-               { shadow_tag ($1); }
-       | declspecs_nots ';'
-               { pedwarn ("empty declaration"); }
-       ;
-
-myparms:
-       myparm
-               { push_parm_decl ($1); }
-       | myparms ',' myparm
-               { push_parm_decl ($3); }
-       ;
-
-/* A single parameter declaration or parameter type name,
-   as found in a parmlist. DOES NOT ALLOW AN INITIALIZER OR ASMSPEC */
-
-myparm:
-         parm_declarator maybe_attribute
-               { $$ = build_tree_list (build_tree_list (current_declspecs,
-                                                        $1),
-                                       chainon ($2, all_prefix_attributes)); }
-       | notype_declarator maybe_attribute
-               { $$ = build_tree_list (build_tree_list (current_declspecs,
-                                                        $1),
-                                       chainon ($2, all_prefix_attributes)); }
-       | absdcl_maybe_attribute
-               { $$ = $1; }
+optparmlist:
+         optparms optellipsis
+               {
+                 TREE_OVERFLOW ($$) = $2;
+               }
        ;
 
-optparmlist:
-         /* empty */
+optparms:
+         /* NULL */
                {
-                 $$ = NULL_TREE;
+                 $$ = make_node (TREE_LIST);
                }
-       | ',' ELLIPSIS
+       | optparms ',' parm
                {
-                 /* oh what a kludge! */
-                 $$ = objc_ellipsis_node;
+                 $$ = chainon ($1, build_tree_list (NULL_TREE,
+                                                    grokparm ($3)));
                }
-       | ','
+       ;
+
+optellipsis:
+         /* NULL */
                {
-                 pushlevel (0);
+                 $$ = 0;
                }
-         parmlist_2
+       | ',' ELLIPSIS
                {
-                 /* returns a tree list node generated by get_parm_info */
-                 $$ = $3;
-                 poplevel (0, 0, 0);
+                 $$ = 1;
                }
        ;
 
@@ -3138,36 +2872,61 @@ selector:
          IDENTIFIER
        | TYPENAME
        | CLASSNAME
-       | OBJECTNAME
        | reservedwords
        ;
 
 reservedwords:
-         ENUM | STRUCT | UNION | IF | ELSE | WHILE | DO | FOR
+         ENUM | STRUCT | UNION | IF | ELSE | WHILE | DO | FOR
        | SWITCH | CASE | DEFAULT | BREAK | CONTINUE | RETURN
        | GOTO | ASM_KEYWORD | SIZEOF | TYPEOF | ALIGNOF
-       | TYPESPEC | TYPE_QUAL
+       | TYPESPEC | TYPE_QUAL | OBJC_TYPE_QUAL
+       ;
+
+objc_qual:
+         OBJC_TYPE_QUAL
+       ;
+
+objc_quals:
+         objc_quals objc_qual
+               {
+                 $$ = chainon ($1, build_tree_list (NULL_TREE, $2));
+               }
+       | /* NULL */
+               {
+                 $$ = NULL_TREE;
+               }
+       ;
+
+objc_typename:
+         objc_quals typename
+               {
+                 $$ = build_tree_list ($1, groktypename ($2));
+               }
+       | objc_quals
+               {
+                 $$ = build_tree_list ($1, NULL_TREE);
+               }
        ;
 
 keyworddecl:
-         selector ':' '(' typename ')' identifier
+         selector ':' '(' objc_typename ')' identifier
                {
-                 $$ = build_keyword_decl ($1, $4, $6);
+                 $$ = objc_build_keyword_decl ($1, $4, $6);
                }
 
        | selector ':' identifier
                {
-                 $$ = build_keyword_decl ($1, NULL_TREE, $3);
+                 $$ = objc_build_keyword_decl ($1, NULL_TREE, $3);
                }
 
-       | ':' '(' typename ')' identifier
+       | ':' '(' objc_typename ')' identifier
                {
-                 $$ = build_keyword_decl (NULL_TREE, $3, $5);
+                 $$ = objc_build_keyword_decl (NULL_TREE, $3, $5);
                }
 
        | ':' identifier
                {
-                 $$ = build_keyword_decl (NULL_TREE, NULL_TREE, $2);
+                 $$ = objc_build_keyword_decl (NULL_TREE, NULL_TREE, $2);
                }
        ;
 
@@ -3210,13 +2969,14 @@ keywordarg:
 
 receiver:
          expr
+               { $$ = $1.value; }
        | CLASSNAME
                {
-                 $$ = get_class_reference ($1);
+                 $$ = objc_get_class_reference ($1);
                }
        | TYPENAME
                {
-                 $$ = get_class_reference ($1);
+                 $$ = objc_get_class_reference ($1);
                }
        ;
 
@@ -3250,14 +3010,14 @@ keywordname:
        ;
 
 objcselectorexpr:
-         SELECTOR '(' selectorarg ')'
+         AT_SELECTOR '(' selectorarg ')'
                {
                  $$ = $3;
                }
        ;
 
 objcprotocolexpr:
-         PROTOCOL '(' identifier ')'
+         AT_PROTOCOL '(' identifier ')'
                {
                  $$ = $3;
                }
@@ -3266,7 +3026,7 @@ objcprotocolexpr:
 /* extension to support C-structures in the archiver */
 
 objcencodeexpr:
-         ENCODE '(' typename ')'
+         AT_ENCODE '(' typename ')'
                {
                  $$ = groktypename ($3);
                }
@@ -3308,6 +3068,7 @@ static const struct resword reswords[] =
   { "__attribute",     RID_ATTRIBUTE,  0 },
   { "__attribute__",   RID_ATTRIBUTE,  0 },
   { "__builtin_choose_expr", RID_CHOOSE_EXPR, 0 },
+  { "__builtin_offsetof", RID_OFFSETOF, 0 },
   { "__builtin_types_compatible_p", RID_TYPES_COMPATIBLE_P, 0 },
   { "__builtin_va_arg",        RID_VA_ARG,     0 },
   { "__complex",       RID_COMPLEX,    0 },
@@ -3321,12 +3082,6 @@ static const struct resword reswords[] =
   { "__inline",                RID_INLINE,     0 },
   { "__inline__",      RID_INLINE,     0 },
   { "__label__",       RID_LABEL,      0 },
-  { "__ptrbase",       RID_PTRBASE,    0 },
-  { "__ptrbase__",     RID_PTRBASE,    0 },
-  { "__ptrextent",     RID_PTREXTENT,  0 },
-  { "__ptrextent__",   RID_PTREXTENT,  0 },
-  { "__ptrvalue",      RID_PTRVALUE,   0 },
-  { "__ptrvalue__",    RID_PTRVALUE,   0 },
   { "__real",          RID_REALPART,   0 },
   { "__real__",                RID_REALPART,   0 },
   { "__restrict",      RID_RESTRICT,   0 },
@@ -3374,8 +3129,8 @@ static const struct resword reswords[] =
   { "void",            RID_VOID,       0 },
   { "volatile",                RID_VOLATILE,   0 },
   { "while",           RID_WHILE,      0 },
+
 @@ifobjc
-  { "id",              RID_ID,                 D_OBJC },
 
   /* These objc keywords are recognized only immediately after
      an '@'.  */
@@ -3439,12 +3194,12 @@ static const short rid_to_yy[RID_MAX] =
   /* RID_MUTABLE */    0,
 
   /* ObjC */
-  /* RID_IN */         TYPE_QUAL,
-  /* RID_OUT */                TYPE_QUAL,
-  /* RID_INOUT */      TYPE_QUAL,
-  /* RID_BYCOPY */     TYPE_QUAL,
-  /* RID_BYREF */      TYPE_QUAL,
-  /* RID_ONEWAY */     TYPE_QUAL,
+  /* RID_IN */         OBJC_TYPE_QUAL,
+  /* RID_OUT */                OBJC_TYPE_QUAL,
+  /* RID_INOUT */      OBJC_TYPE_QUAL,
+  /* RID_BYCOPY */     OBJC_TYPE_QUAL,
+  /* RID_BYREF */      OBJC_TYPE_QUAL,
+  /* RID_ONEWAY */     OBJC_TYPE_QUAL,
 
   /* C */
   /* RID_INT */                TYPESPEC,
@@ -3479,9 +3234,6 @@ static const short rid_to_yy[RID_MAX] =
   /* RID_IMAGPART */   IMAGPART,
   /* RID_REALPART */   REALPART,
   /* RID_LABEL */      LABEL,
-  /* RID_PTRBASE */    PTR_BASE,
-  /* RID_PTREXTENT */  PTR_EXTENT,
-  /* RID_PTRVALUE */   PTR_VALUE,
 
   /* RID_CHOOSE_EXPR */                        CHOOSE_EXPR,
   /* RID_TYPES_COMPATIBLE_P */         TYPES_COMPATIBLE_P,
@@ -3504,7 +3256,7 @@ static const short rid_to_yy[RID_MAX] =
   /* RID_FALSE */      0,
   /* RID_NAMESPACE */  0,
   /* RID_NEW */                0,
-  /* RID_OFFSETOF */    0,
+  /* RID_OFFSETOF */    OFFSETOF,
   /* RID_OPERATOR */   0,
   /* RID_THIS */       0,
   /* RID_THROW */      0,
@@ -3521,24 +3273,23 @@ static const short rid_to_yy[RID_MAX] =
   /* RID_STATCAST */   0,
 
   /* Objective C */
-  /* RID_ID */                 OBJECTNAME,
-  /* RID_AT_ENCODE */          ENCODE,
-  /* RID_AT_END */             END,
-  /* RID_AT_CLASS */           CLASS,
-  /* RID_AT_ALIAS */           ALIAS,
-  /* RID_AT_DEFS */            DEFS,
-  /* RID_AT_PRIVATE */         PRIVATE,
-  /* RID_AT_PROTECTED */       PROTECTED,
-  /* RID_AT_PUBLIC */          PUBLIC,
-  /* RID_AT_PROTOCOL */                PROTOCOL,
-  /* RID_AT_SELECTOR */                SELECTOR,
+  /* RID_AT_ENCODE */          AT_ENCODE,
+  /* RID_AT_END */             AT_END,
+  /* RID_AT_CLASS */           AT_CLASS,
+  /* RID_AT_ALIAS */           AT_ALIAS,
+  /* RID_AT_DEFS */            AT_DEFS,
+  /* RID_AT_PRIVATE */         AT_PRIVATE,
+  /* RID_AT_PROTECTED */       AT_PROTECTED,
+  /* RID_AT_PUBLIC */          AT_PUBLIC,
+  /* RID_AT_PROTOCOL */                AT_PROTOCOL,
+  /* RID_AT_SELECTOR */                AT_SELECTOR,
   /* RID_AT_THROW */           AT_THROW,
   /* RID_AT_TRY */             AT_TRY,
   /* RID_AT_CATCH */           AT_CATCH,
   /* RID_AT_FINALLY */         AT_FINALLY,
   /* RID_AT_SYNCHRONIZED */    AT_SYNCHRONIZED,
-  /* RID_AT_INTERFACE */       INTERFACE,
-  /* RID_AT_IMPLEMENTATION */  IMPLEMENTATION
+  /* RID_AT_INTERFACE */       AT_INTERFACE,
+  /* RID_AT_IMPLEMENTATION */  AT_IMPLEMENTATION
 };
 
 static void
@@ -3552,7 +3303,7 @@ init_reswords (void)
   if (!c_dialect_objc ())
      mask |= D_OBJC;
 
-  ridpointers = ggc_calloc ((int) RID_MAX, sizeof (tree));
+  ridpointers = GGC_CNEWVEC (tree, (int) RID_MAX);
   for (i = 0; i < N_reswords; i++)
     {
       /* If a keyword is disabled, do not enter it into the table
@@ -3590,15 +3341,6 @@ yylexname (void)
       enum rid rid_code = C_RID_CODE (yylval.ttype);
 
 @@ifobjc
-      /* Turn non-typedefed refs to "id" into plain identifiers; this
-        allows constructs like "void foo(id id);" to work.  */
-      if (rid_code == RID_ID)
-      {
-       decl = lookup_name (yylval.ttype);
-       if (decl == NULL_TREE || TREE_CODE (decl) != TYPE_DECL)
-         return IDENTIFIER;
-      }
-
       if (!OBJC_IS_AT_KEYWORD (rid_code)
          && (!OBJC_IS_PQ_KEYWORD (rid_code) || objc_pq_context))
 @@end_ifobjc
@@ -3618,7 +3360,7 @@ yylexname (void)
 @@ifobjc
   else
     {
-      tree objc_interface_decl = is_class_name (yylval.ttype);
+      tree objc_interface_decl = objc_is_class_name (yylval.ttype);
       /* ObjC class names are in the same namespace as variables and
         typedefs, and hence are shadowed by local declarations.  */
       if (objc_interface_decl
@@ -3729,7 +3471,7 @@ _yylex (void)
       /* These tokens should not survive translation phase 4.  */
     case CPP_HASH:
     case CPP_PASTE:
-      error ("syntax error at '%s' token", NAME(last_token));
+      error ("syntax error at %qs token", NAME(last_token));
       goto get_next;
 
     default:
@@ -3761,13 +3503,12 @@ yyprint (FILE *file, int yychar, YYSTYPE yyl)
     {
     case IDENTIFIER:
     case TYPENAME:
-    case OBJECTNAME:
     case TYPESPEC:
     case TYPE_QUAL:
     case SCSPEC:
     case STATIC:
       if (IDENTIFIER_POINTER (t))
-       fprintf (file, " `%s'", IDENTIFIER_POINTER (t));
+       fprintf (file, " '%s'", IDENTIFIER_POINTER (t));
       break;
 
     case CONSTANT:
@@ -3782,22 +3523,14 @@ yyprint (FILE *file, int yychar, YYSTYPE yyl)
     }
 }
 \f
-/* This is not the ideal place to put these, but we have to get them out
-   of c-lex.c because cp/lex.c has its own versions.  */
+/* This is not the ideal place to put this, but we have to get it out
+   of c-lex.c because cp/lex.c has its own version.  */
 
 /* Parse the file.  */
 void
 c_parse_file (void)
 {
   yyparse ();
-  /* In case there were missing closebraces, get us back to the global
-     binding level.  */
-  while (! global_bindings_p ())
-    poplevel (0, 0, 0);
-  /* __FUNCTION__ is defined at file scope ("").  This
-     call may not be necessary as my tests indicate it
-     still works without it.  */
-  finish_fname_decls ();
 
   if (malloced_yyss)
     {
@@ -3807,4 +3540,21 @@ c_parse_file (void)
     }
 }
 
+#ifdef __XGETTEXT__
+/* Depending on the version of Bison used to compile this grammar,
+   it may issue generic diagnostics spelled "syntax error" or
+   "parse error".  To prevent this from changing the translation
+   template randomly, we list all the variants of this particular
+   diagnostic here.  Translators: there is no fine distinction
+   between diagnostics with "syntax error" in them, and diagnostics
+   with "parse error" in them.  It's okay to give them both the same
+   translation.  */
+const char d1[] = N_("syntax error");
+const char d2[] = N_("parse error");
+const char d3[] = N_("syntax error; also virtual memory exhausted");
+const char d4[] = N_("parse error; also virtual memory exhausted");
+const char d5[] = N_("syntax error: cannot back up");
+const char d6[] = N_("parse error: cannot back up");
+#endif
+
 #include "gt-c-parse.h"