c-parser.c: New file.
authorJoseph Myers <joseph@codesourcery.com>
Fri, 25 Feb 2005 23:20:48 +0000 (23:20 +0000)
committerJoseph Myers <jsm28@gcc.gnu.org>
Fri, 25 Feb 2005 23:20:48 +0000 (23:20 +0000)
* c-parser.c: New file.
* c-parse.in: Remove.
* Makefile.in (c-parse.o-warn, c-parse.o, c-parse.c, c-parse.y):
Remove.
(c-parser.o): Add dependencies.
(C_AND_OBJC_OBJC, C_OBJS, gcc.srcextra, GTFILES, distclean,
maintainer-clean, TAGS): Update.
* c-config-lang.in (gtfiles): Update.
* gengtype-lex.l: Don't handle "@@".
* stub-objc.c (objc_get_class_ivars, objc_build_throw_stmt,
objc_build_synchronized, objc_begin_try_stmt,
objc_begin_catch_clause, objc_finish_catch_clause,
objc_build_finally_clause, objc_finish_try_stmt): New.
* c-tree.h (struct c_declspecs): Add declspecs_seen_p and
type_seen_p.
(c_parse_init): Update comment.
* c-decl.c (c_init_decl_processing): Update comment.
(build_null_declspecs, declspecs_add_qual, declspecs_add_type,
declspecs_add_scspec, declspecs_add_attrs): Initialize and update
new c_declspecs members.

objc:
* Make-lang.in (objc/objc-parse.o-warn, objc/objc-parse.o,
objc/objc-parse.c, objc/objc-parse.y): Remove
(OBJC_OBJS, objc.srcextra, objc.tags, objc.mostlyclean,
objc.distclean, objc.maintainer-clean): Update for new parser.
* config-lang.in (gtfiles): Update for new parser.

testsuite:
* gcc.dg/cpp/separate-1.c, gcc.dg/noncompile/971104-1.c,
gcc.dg/noncompile/990416-1.c: Adjust expected messages for new
parser.

From-SVN: r95558

16 files changed:
gcc/ChangeLog
gcc/Makefile.in
gcc/c-config-lang.in
gcc/c-decl.c
gcc/c-parse.in [deleted file]
gcc/c-parser.c [new file with mode: 0644]
gcc/c-tree.h
gcc/gengtype-lex.l
gcc/objc/ChangeLog
gcc/objc/Make-lang.in
gcc/objc/config-lang.in
gcc/stub-objc.c
gcc/testsuite/ChangeLog
gcc/testsuite/gcc.dg/cpp/separate-1.c
gcc/testsuite/gcc.dg/noncompile/971104-1.c
gcc/testsuite/gcc.dg/noncompile/990416-1.c

index eebeac4..bc843db 100644 (file)
@@ -1,3 +1,26 @@
+2005-02-25  Joseph S. Myers  <joseph@codesourcery.com>
+
+       * c-parser.c: New file.
+       * c-parse.in: Remove.
+       * Makefile.in (c-parse.o-warn, c-parse.o, c-parse.c, c-parse.y):
+       Remove.
+       (c-parser.o): Add dependencies.
+       (C_AND_OBJC_OBJC, C_OBJS, gcc.srcextra, GTFILES, distclean,
+       maintainer-clean, TAGS): Update.
+       * c-config-lang.in (gtfiles): Update.
+       * gengtype-lex.l: Don't handle "@@".
+       * stub-objc.c (objc_get_class_ivars, objc_build_throw_stmt,
+       objc_build_synchronized, objc_begin_try_stmt,
+       objc_begin_catch_clause, objc_finish_catch_clause,
+       objc_build_finally_clause, objc_finish_try_stmt): New.
+       * c-tree.h (struct c_declspecs): Add declspecs_seen_p and
+       type_seen_p.
+       (c_parse_init): Update comment.
+       * c-decl.c (c_init_decl_processing): Update comment.
+       (build_null_declspecs, declspecs_add_qual, declspecs_add_type,
+       declspecs_add_scspec, declspecs_add_attrs): Initialize and update
+       new c_declspecs members.
+
 2005-02-25  Julian Brown  <julian@codesourcery.com>
 
        * config/elfos.h (MAKE_DECL_ONE_ONLY): Redefined to stop DECL_WEAK
index 93c3399..1be15cd 100644 (file)
@@ -193,7 +193,6 @@ gcc.o-warn = -Wno-error
 build/insn-conditions.o-warn = -Wno-error
 # Bison-1.75 output often yields (harmless) -Wtraditional warnings
 build/gengtype-yacc.o-warn = -Wno-error
-c-parse.o-warn = -Wno-error
 # flex output may yield harmless "no previous prototype" warnings
 build/gengtype-lex.o-warn = -Wno-error
 # SYSCALLS.c misses prototypes
@@ -884,11 +883,11 @@ CXX_TARGET_OBJS=@cxx_target_objs@
 C_AND_OBJC_OBJS = attribs.o c-errors.o c-lex.o c-pragma.o c-decl.o c-typeck.o \
   c-convert.o c-aux-info.o c-common.o c-opts.o c-format.o c-semantics.o \
   c-incpath.o cppdefault.o c-ppoutput.o c-cppbuiltin.o prefix.o \
-  c-objc-common.o c-dump.o c-pch.o $(C_TARGET_OBJS) \
+  c-objc-common.o c-dump.o c-pch.o c-parser.o $(C_TARGET_OBJS) \
   c-gimplify.o tree-mudflap.o c-pretty-print.o
 
 # Language-specific object files for C.
-C_OBJS = c-parse.o c-lang.o stub-objc.o $(C_AND_OBJC_OBJS)
+C_OBJS = c-lang.o stub-objc.o $(C_AND_OBJC_OBJS)
 
 # Language-independent object files.
 OBJS-common = \
@@ -1347,24 +1346,15 @@ s-crt0: $(CRT0_S) $(MCRT0_S) $(GCC_PASSES) $(CONFIG_H)
 
 c-errors.o: c-errors.c $(CONFIG_H) $(SYSTEM_H) coretypes.h $(TM_H) $(TREE_H) \
     $(C_TREE_H) $(FLAGS_H) $(DIAGNOSTIC_H) $(TM_P_H)
-c-parse.o : c-parse.c $(CONFIG_H) $(SYSTEM_H) coretypes.h $(TM_H) $(TREE_H) \
+c-parser.o : c-parser.c $(CONFIG_H) $(SYSTEM_H) coretypes.h $(TM_H) $(TREE_H) \
     $(GGC_H) intl.h $(C_TREE_H) input.h $(FLAGS_H) toplev.h output.h \
-    $(CPPLIB_H) varray.h gt-c-parse.h langhooks.h $(C_COMMON_H) $(C_PRAGMA_H)
+    $(CPPLIB_H) varray.h gt-c-parser.h langhooks.h $(C_COMMON_H) $(C_PRAGMA_H)
 
 srcextra: gcc.srcextra lang.srcextra
 
-gcc.srcextra: c-parse.y c-parse.c gengtype-lex.c gengtype-yacc.c gengtype-yacc.h
+gcc.srcextra: gengtype-lex.c gengtype-yacc.c gengtype-yacc.h
        -cp -p $^ $(srcdir)
 
-c-parse.c: c-parse.y
-       -$(BISON) $(BISONFLAGS) -o $@ $<
-
-c-parse.y: c-parse.in
-       echo '/*WARNING: This file is automatically generated!*/' >tmp-c-parse.y
-       sed -e "/^@@ifobjc.*/,/^@@end_ifobjc.*/d" \
-           -e "/^@@ifc.*/d" -e "/^@@end_ifc.*/d" $< >>tmp-c-parse.y
-       $(SHELL) $(srcdir)/../move-if-change tmp-c-parse.y $@
-
 c-incpath.o: c-incpath.c c-incpath.h $(CONFIG_H) $(SYSTEM_H) $(CPPLIB_H) \
                intl.h prefix.h coretypes.h $(TM_H) cppdefault.h $(TARGET_H) \
                $(MACHMODE_H)
@@ -2427,7 +2417,7 @@ GTFILES = $(srcdir)/input.h $(srcdir)/coretypes.h \
   $(srcdir)/sdbout.c $(srcdir)/stor-layout.c \
   $(srcdir)/stringpool.c $(srcdir)/tree.c $(srcdir)/varasm.c \
   $(srcdir)/tree-mudflap.c $(srcdir)/tree-flow.h \
-  $(srcdir)/c-objc-common.c $(srcdir)/c-common.c $(srcdir)/c-parse.in \
+  $(srcdir)/c-objc-common.c $(srcdir)/c-common.c $(srcdir)/c-parser.c \
   $(srcdir)/tree-ssanames.c $(srcdir)/tree-eh.c \
   $(srcdir)/tree-phinodes.c $(srcdir)/tree-cfg.c \
   $(srcdir)/tree-dfa.c $(srcdir)/tree-ssa-propagate.c \
@@ -2449,7 +2439,7 @@ gt-emit-rtl.h gt-explow.h gt-stor-layout.h gt-regclass.h \
 gt-lists.h gt-alias.h gt-cselib.h gt-gcse.h \
 gt-expr.h gt-sdbout.h gt-optabs.h gt-bitmap.h gt-dojump.h \
 gt-dwarf2out.h gt-reg-stack.h gt-dwarf2asm.h \
-gt-dbxout.h gt-c-common.h gt-c-decl.h gt-c-parse.h \
+gt-dbxout.h gt-c-common.h gt-c-decl.h gt-c-parser.h \
 gt-c-pragma.h gtype-c.h gt-cfglayout.h \
 gt-tree-mudflap.h gt-tree-complex.h \
 gt-tree-eh.h \
@@ -3166,7 +3156,7 @@ distclean: clean lang.distclean
        -rm -f Makefile *.oaux
        -rm -f gthr-default.h
        -rm -f */stage1 */stage2 */stage3 */stage4 */include */stageprofile */stagefeedback
-       -rm -f c-parse.y c-parse.c c-parse.output TAGS */TAGS
+       -rm -f TAGS */TAGS
        -rm -f *.asm
        -rm -f site.exp site.bak testsuite/site.exp testsuite/site.bak
        -rm -f testsuite/*.log testsuite/*.sum
@@ -3186,7 +3176,6 @@ maintainer-clean:
        @echo 'This command is intended for maintainers to use; it'
        @echo 'deletes files that may need special tools to rebuild.'
        $(MAKE) lang.maintainer-clean distclean
-       -rm -f $(srcdir)/c-parse.y $(srcdir)/c-parse.c
        -rm -f cpp.??s cpp.*aux
        -rm -f gcc.??s gcc.*aux
        -rm -f $(docdir)/*.info $(docdir)/*.1 $(docdir)/*.7 $(docdir)/*.dvi
@@ -3648,7 +3637,7 @@ TAGS: lang.tags
            incs="$$incs --include $$dir/TAGS.sub";     \
          fi;                                           \
        done;                                           \
-       etags -o TAGS.sub *.y *.h *.c -l yacc c-parse.in; \
+       etags -o TAGS.sub *.y *.h *.c; \
        etags --include TAGS.sub $$incs)
 
 # ------------------------------------------------------
index c0a786f..6b5edc2 100644 (file)
@@ -1,5 +1,5 @@
 # Top level configure fragment for GNU C - C language.
-# Copyright (C) 1994, 1995, 1997, 1998, 2000, 2001, 2002 Free Software Foundation, Inc.
+# Copyright (C) 1994, 1995, 1997, 1998, 2000, 2001, 2002, 2005 Free Software Foundation, Inc.
 
 #This file is part of GCC.
 
@@ -23,4 +23,4 @@
 # files used by C that have garbage collection GTY macros in them
 # which therefore need to be scanned by gengtype.c.
 
-gtfiles="\$(srcdir)/c-lang.c \$(srcdir)/c-parse.in \$(srcdir)/c-tree.h \$(srcdir)/c-decl.c \$(srcdir)/c-common.c \$(srcdir)/c-common.h \$(srcdir)/c-pragma.c \$(srcdir)/c-objc-common.c"
+gtfiles="\$(srcdir)/c-lang.c \$(srcdir)/c-tree.h \$(srcdir)/c-decl.c \$(srcdir)/c-common.c \$(srcdir)/c-common.h \$(srcdir)/c-pragma.c \$(srcdir)/c-objc-common.c \$(srcdir)/c-parser.c"
index 0b7b97e..690d3b3 100644 (file)
@@ -2581,7 +2581,7 @@ c_init_decl_processing (void)
   tree ptr_ftype_void, ptr_ftype_ptr;
   location_t save_loc = input_location;
 
-  /* Adds some ggc roots, and reserved words for c-parse.in.  */
+  /* Initialize reserved words for parser.  */
   c_parse_init ();
 
   current_function_decl = 0;
@@ -6746,6 +6746,8 @@ build_null_declspecs (void)
   ret->attrs = 0;
   ret->typespec_word = cts_none;
   ret->storage_class = csc_none;
+  ret->declspecs_seen_p = false;
+  ret->type_seen_p = false;
   ret->non_sc_seen_p = false;
   ret->typedef_p = false;
   ret->tag_defined_p = false;
@@ -6775,6 +6777,7 @@ declspecs_add_qual (struct c_declspecs *specs, tree qual)
   enum rid i;
   bool dupe = false;
   specs->non_sc_seen_p = true;
+  specs->declspecs_seen_p = true;
   gcc_assert (TREE_CODE (qual) == IDENTIFIER_NODE
              && C_IS_RESERVED_WORD (qual));
   i = C_RID_CODE (qual);
@@ -6808,6 +6811,8 @@ declspecs_add_type (struct c_declspecs *specs, struct c_typespec spec)
 {
   tree type = spec.spec;
   specs->non_sc_seen_p = true;
+  specs->declspecs_seen_p = true;
+  specs->type_seen_p = true;
   if (TREE_DEPRECATED (type))
     specs->deprecated_p = true;
 
@@ -7102,6 +7107,7 @@ declspecs_add_scspec (struct c_declspecs *specs, tree scspec)
   enum rid i;
   enum c_storage_class n = csc_none;
   bool dupe = false;
+  specs->declspecs_seen_p = true;
   gcc_assert (TREE_CODE (scspec) == IDENTIFIER_NODE
              && C_IS_RESERVED_WORD (scspec));
   i = C_RID_CODE (scspec);
@@ -7184,6 +7190,7 @@ struct c_declspecs *
 declspecs_add_attrs (struct c_declspecs *specs, tree attrs)
 {
   specs->attrs = chainon (attrs, specs->attrs);
+  specs->declspecs_seen_p = true;
   return specs;
 }
 
diff --git a/gcc/c-parse.in b/gcc/c-parse.in
deleted file mode 100644 (file)
index fe0d517..0000000
+++ /dev/null
@@ -1,3588 +0,0 @@
-/* YACC parser for C syntax and for Objective C.  -*-c-*-
-   Copyright (C) 1987, 1988, 1989, 1992, 1993, 1994, 1995, 1996, 1997, 1998,
-   1999, 2000, 2001, 2002, 2003, 2004, 2005 Free Software Foundation, Inc.
-
-This file is part of GCC.
-
-GCC is free software; you can redistribute it and/or modify it under
-the terms of the GNU General Public License as published by the Free
-Software Foundation; either version 2, or (at your option) any later
-version.
-
-GCC is distributed in the hope that it will be useful, but WITHOUT ANY
-WARRANTY; without even the implied warranty of MERCHANTABILITY or
-FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
-for more details.
-
-You should have received a copy of the GNU General Public License
-along with GCC; see the file COPYING.  If not, write to the Free
-Software Foundation, 59 Temple Place - Suite 330, Boston, MA
-02111-1307, USA.  */
-
-/* This file defines the grammar of C and that of Objective C.
-   @@ifobjc ... @@end_ifobjc  conditionals contain code for Objective C only.
-   @@ifc ... @@end_ifc  conditionals contain code for C only.
-   Sed commands in Makefile.in are used to convert this file into
-   c-parse.y and into objc-parse.y.  */
-
-/* To whomever it may concern: I have heard that such a thing was once
-   written by AT&T, but I have never seen it.  */
-
-@@ifc
-%expect 13 /* shift/reduce conflicts, and no reduce/reduce conflicts.  */
-@@end_ifc
-
-%{
-#include "config.h"
-#include "system.h"
-#include "coretypes.h"
-#include "tm.h"
-#include "tree.h"
-#include "langhooks.h"
-#include "input.h"
-#include "cpplib.h"
-#include "intl.h"
-#include "timevar.h"
-#include "c-pragma.h"          /* For YYDEBUG definition, and parse_in.  */
-#include "c-tree.h"
-#include "flags.h"
-#include "varray.h"
-#include "output.h"
-#include "toplev.h"
-#include "ggc.h"
-#include "c-common.h"
-
-#define YYERROR1 { yyerror ("syntax error"); YYERROR; }
-
-/* Like the default stack expander, except (1) use realloc when possible,
-   (2) impose no hard maxiumum on stack size, (3) REALLY do not use alloca.
-
-   Irritatingly, YYSTYPE is defined after this %{ %} block, so we cannot
-   give malloced_yyvs its proper type.  This is ok since all we need from
-   it is to be able to free it.  */
-
-static short *malloced_yyss;
-static void *malloced_yyvs;
-
-#define yyoverflow(MSG, SS, SSSIZE, VS, VSSIZE, YYSSZ)                 \
-do {                                                                   \
-  size_t newsize;                                                      \
-  short *newss;                                                                \
-  YYSTYPE *newvs;                                                      \
-  newsize = *(YYSSZ) *= 2;                                             \
-  if (malloced_yyss)                                                   \
-    {                                                                  \
-      newss = really_call_realloc (*(SS), newsize * sizeof (short));   \
-      newvs = really_call_realloc (*(VS), newsize * sizeof (YYSTYPE)); \
-    }                                                                  \
-  else                                                                 \
-    {                                                                  \
-      newss = really_call_malloc (newsize * sizeof (short));           \
-      newvs = really_call_malloc (newsize * sizeof (YYSTYPE));         \
-      if (newss)                                                       \
-        memcpy (newss, *(SS), (SSSIZE));                               \
-      if (newvs)                                                       \
-        memcpy (newvs, *(VS), (VSSIZE));                               \
-    }                                                                  \
-  if (!newss || !newvs)                                                        \
-    {                                                                  \
-      yyerror (MSG);                                                   \
-      return 2;                                                                \
-    }                                                                  \
-  *(SS) = newss;                                                       \
-  *(VS) = newvs;                                                       \
-  malloced_yyss = newss;                                               \
-  malloced_yyvs = (void *) newvs;                                      \
-} while (0)
-%}
-
-%start program
-
-%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 */
-%token IDENTIFIER
-
-/* All identifiers that are declared typedefs in the current block.
-   In some contexts, they are treated just like IDENTIFIER,
-   but they can also serve as typespecs in declarations.  */
-%token TYPENAME
-
-/* Reserved words that specify storage class.
-   yylval contains an IDENTIFIER_NODE which indicates which one.  */
-%token SCSPEC                  /* Storage class other than static.  */
-%token STATIC                  /* Static storage class.  */
-
-/* Reserved words that specify type.
-   yylval contains an IDENTIFIER_NODE which indicates which one.  */
-%token TYPESPEC
-
-/* Reserved words that qualify type: "const", "volatile", or "restrict".
-   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
-
-/* String constants in raw form.
-   yylval is a STRING_CST node.  */
-
-%token STRING
-
-/* "...", used for functions with variable arglists.  */
-%token ELLIPSIS
-
-/* the reserved words */
-/* SCO include files test "ASM", so use something else. */
-%token SIZEOF ENUM STRUCT UNION IF ELSE WHILE DO FOR SWITCH CASE DEFAULT
-%token BREAK CONTINUE RETURN GOTO ASM_KEYWORD TYPEOF ALIGNOF
-%token ATTRIBUTE EXTENSION LABEL
-%token REALPART IMAGPART VA_ARG CHOOSE_EXPR TYPES_COMPATIBLE_P
-%token FUNC_NAME OFFSETOF
-
-/* Add precedence rules to solve dangling else s/r conflict */
-%nonassoc IF
-%nonassoc ELSE
-
-/* Define the operator tokens and their precedences.
-   The value is an integer because, if used, it is the tree code
-   to use in the expression made from the operator.  */
-
-%right <code> ASSIGN '='
-%right <code> '?' ':'
-%left <code> OROR
-%left <code> ANDAND
-%left <code> '|'
-%left <code> '^'
-%left <code> '&'
-%left <code> EQCOMPARE
-%left <code> ARITHCOMPARE
-%left <code> LSHIFT RSHIFT
-%left <code> '+' '-'
-%left <code> '*' '/' '%'
-%right <code> UNARY PLUSPLUS MINUSMINUS
-%left HYPERUNARY
-%left <code> POINTSAT '.' '(' '['
-
-/* The Objective-C keywords.  These are included in C and in
-   Objective C, so that the token codes are the same in both.  */
-%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
-
-%type <code> unop
-%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 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
-%type <exprtype> init
-%type <ttype> simple_asm_expr maybeasm asm_stmt asm_argument asm_string
-%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_primary_start
-%type <ttype> stmt label stmt_nocomp start_break start_continue
-
-%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 <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 <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> methoddecl unaryselector keywordselector selector
-%type <code> methodtype
-%type <ttype> keyworddecl receiver objcmessageexpr messageargs
-%type <ttype> keywordexpr keywordarglist keywordarg
-%type <ttype> optparmlist optparms reservedwords objcselectorexpr
-%type <ttype> selectorarg keywordnamelist keywordname objcencodeexpr
-%type <ttype> non_empty_protocolrefs protocolrefs identifier_list objcprotocolexpr
-
-%type <ttype> CLASSNAME OBJC_STRING OBJC_TYPE_QUAL
-
-%type <ttype> superclass objc_quals objc_qual objc_typename
-%type <itype> objc_try_catch_stmt optellipsis
-@@end_ifobjc
-\f
-%{
-/* 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
-   declared; includes prefix_attributes and possibly some more 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 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 {                                                                 \
-    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 = 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
-   controlled by __extension__.  */
-#define SAVE_EXT_FLAGS()               \
-       (pedantic                       \
-        | (warn_pointer_arith << 1)    \
-        | (warn_traditional << 2)      \
-        | (flag_iso << 3))
-
-#define RESTORE_EXT_FLAGS(val)                 \
-  do {                                         \
-    pedantic = val & 1;                                \
-    warn_pointer_arith = (val >> 1) & 1;       \
-    warn_traditional = (val >> 2) & 1;         \
-    flag_iso = (val >> 3) & 1;                 \
-  } while (0)
-
-@@ifobjc
-/* Objective-C specific parser/lexer information */
-
-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
-   an identifier to an ObjC class, even if a class with that name
-   exists.  */
-static int objc_need_raw_identifier;
-#define OBJC_NEED_RAW_IDENTIFIER(VAL)  objc_need_raw_identifier = VAL
-@@end_ifobjc
-
-@@ifc
-#define OBJC_NEED_RAW_IDENTIFIER(VAL)  /* nothing */
-@@end_ifc
-
-/* Tell yyparse how to print a token's value, if yydebug is set.  */
-
-#define YYPRINT(FILE,YYCHAR,YYLVAL) yyprint(FILE,YYCHAR,YYLVAL)
-
-static void yyprint (FILE *, int, YYSTYPE);
-static void yyerror (const char *);
-static int yylexname (void);
-static inline int _yylex (void);
-static int  yylex (void);
-static void init_reswords (void);
-
-  /* Initialization routine for this file.  */
-void
-c_parse_init (void)
-{
-  init_reswords ();
-}
-
-%}
-\f
-%%
-program: /* empty */
-               { if (pedantic)
-                   pedwarn ("ISO C forbids an empty source file");
-               }
-       | extdefs
-       ;
-
-/* the reason for the strange actions in this rule
- is so that notype_initdecls when reached via datadef
- can find valid declaration specifiers in $0. */
-
-extdefs:
-       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:
-       fndef
-       | datadef
-       | asmdef
-       | extension extdef
-               { RESTORE_EXT_FLAGS ($1); }
-@@ifobjc
-       | objcdef
-@@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 ';'
-               { 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 (finish_declspecs ($1)); }
-       | error ';'
-       | error '}'
-       | ';'
-               { if (pedantic)
-                   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))
-                   YYERROR1;
-               }
-         old_style_parm_decls save_location
-               { DECL_SOURCE_LOCATION (current_function_decl) = $6;
-                 store_parm_decls (); }
-         compstmt_or_error
-               { finish_function ();
-                 POP_DECLSPEC_STACK; }
-       | declspecs_ts setspecs declarator error
-               { POP_DECLSPEC_STACK; }
-       | declspecs_nots setspecs notype_declarator
-               { if (!start_function (current_declspecs, $3,
-                                      all_prefix_attributes))
-                   YYERROR1;
-               }
-         old_style_parm_decls save_location
-               { DECL_SOURCE_LOCATION (current_function_decl) = $6;
-                 store_parm_decls (); }
-         compstmt_or_error
-               { finish_function ();
-                 POP_DECLSPEC_STACK; }
-       | declspecs_nots setspecs notype_declarator error
-               { POP_DECLSPEC_STACK; }
-       | setspecs notype_declarator
-               { if (!start_function (current_declspecs, $2,
-                                      all_prefix_attributes))
-                   YYERROR1;
-               }
-         old_style_parm_decls save_location
-               { DECL_SOURCE_LOCATION (current_function_decl) = $5;
-                 store_parm_decls (); }
-         compstmt_or_error
-               { finish_function ();
-                 POP_DECLSPEC_STACK; }
-       | setspecs notype_declarator error
-               { POP_DECLSPEC_STACK; }
-       ;
-
-identifier:
-       IDENTIFIER
-       | TYPENAME
-@@ifobjc
-       | CLASSNAME
-@@end_ifobjc
-       ;
-
-unop:     '&'
-               { $$ = ADDR_EXPR; }
-       | '-'
-               { $$ = NEGATE_EXPR; }
-       | '+'
-               { $$ = CONVERT_EXPR;
-@@ifc
-  if (warn_traditional && !in_system_header)
-    warning ("traditional C rejects the unary plus operator");
-@@end_ifc
-               }
-       | PLUSPLUS
-               { $$ = PREINCREMENT_EXPR; }
-       | MINUSMINUS
-               { $$ = PREDECREMENT_EXPR; }
-       | '~'
-               { $$ = BIT_NOT_EXPR; }
-       | '!'
-               { $$ = TRUTH_NOT_EXPR; }
-       ;
-
-expr:  expr_no_commas
-       | expr ',' expr_no_commas
-               { $$.value = build_compound_expr ($1.value, $3.value);
-                 $$.original_code = COMPOUND_EXPR; }
-       ;
-
-exprlist:
-         /* empty */
-               { $$ = NULL_TREE; }
-       | nonnull_exprlist
-       ;
-
-nonnull_exprlist:
-       expr_no_commas
-               { $$ = build_tree_list (NULL_TREE, $1.value); }
-       | nonnull_exprlist ',' expr_no_commas
-               { chainon ($1, build_tree_list (NULL_TREE, $3.value)); }
-       ;
-
-unary_expr:
-       primary
-       | '*' cast_expr   %prec 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
-               { $$.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
-               { $$.value = finish_label_address_expr ($2);
-                 $$.original_code = ERROR_MARK; }
-       | sizeof unary_expr  %prec UNARY
-               { skip_evaluation--;
-                 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--;
-                 in_sizeof--;
-                 $$ = c_expr_sizeof_type ($3); }
-       | alignof unary_expr  %prec UNARY
-               { skip_evaluation--;
-                 in_alignof--;
-                 $$.value = c_alignof_expr ($2.value);
-                 $$.original_code = ERROR_MARK; }
-       | alignof '(' typename ')'  %prec HYPERUNARY
-               { skip_evaluation--;
-                 in_alignof--;
-                 $$.value = c_alignof (groktypename ($3));
-                 $$.original_code = ERROR_MARK; }
-       | REALPART cast_expr %prec UNARY
-               { $$.value = build_unary_op (REALPART_EXPR, $2.value, 0);
-                 $$.original_code = ERROR_MARK; }
-       | IMAGPART cast_expr %prec UNARY
-               { $$.value = build_unary_op (IMAGPART_EXPR, $2.value, 0);
-                 $$.original_code = ERROR_MARK; }
-       ;
-
-sizeof:
-       SIZEOF { skip_evaluation++; in_sizeof++; }
-       ;
-
-alignof:
-       ALIGNOF { skip_evaluation++; in_alignof++; }
-       ;
-
-typeof:
-       TYPEOF { skip_evaluation++; in_typeof++; }
-       ;
-
-cast_expr:
-       unary_expr
-       | '(' typename ')' cast_expr  %prec UNARY
-               { $$.value = c_cast_expr ($2, $4.value);
-                 $$.original_code = ERROR_MARK; }
-       ;
-
-expr_no_commas:
-         cast_expr
-       | expr_no_commas '+' expr_no_commas
-               { $$ = parser_build_binary_op ($2, $1, $3); }
-       | expr_no_commas '-' expr_no_commas
-               { $$ = parser_build_binary_op ($2, $1, $3); }
-       | expr_no_commas '*' expr_no_commas
-               { $$ = parser_build_binary_op ($2, $1, $3); }
-       | expr_no_commas '/' expr_no_commas
-               { $$ = parser_build_binary_op ($2, $1, $3); }
-       | expr_no_commas '%' expr_no_commas
-               { $$ = parser_build_binary_op ($2, $1, $3); }
-       | expr_no_commas LSHIFT expr_no_commas
-               { $$ = parser_build_binary_op ($2, $1, $3); }
-       | expr_no_commas RSHIFT expr_no_commas
-               { $$ = parser_build_binary_op ($2, $1, $3); }
-       | expr_no_commas ARITHCOMPARE expr_no_commas
-               { $$ = parser_build_binary_op ($2, $1, $3); }
-       | expr_no_commas EQCOMPARE expr_no_commas
-               { $$ = parser_build_binary_op ($2, $1, $3); }
-       | expr_no_commas '&' expr_no_commas
-               { $$ = parser_build_binary_op ($2, $1, $3); }
-       | expr_no_commas '|' expr_no_commas
-               { $$ = parser_build_binary_op ($2, $1, $3); }
-       | expr_no_commas '^' expr_no_commas
-               { $$ = parser_build_binary_op ($2, $1, $3); }
-       | expr_no_commas ANDAND
-               { $1.value = lang_hooks.truthvalue_conversion
-                   (default_conversion ($1.value));
-                 skip_evaluation += $1.value == truthvalue_false_node; }
-         expr_no_commas
-               { skip_evaluation -= $1.value == truthvalue_false_node;
-                 $$ = parser_build_binary_op (TRUTH_ANDIF_EXPR, $1, $4); }
-       | expr_no_commas OROR
-               { $1.value = lang_hooks.truthvalue_conversion
-                   (default_conversion ($1.value));
-                 skip_evaluation += $1.value == truthvalue_true_node; }
-         expr_no_commas
-               { skip_evaluation -= $1.value == truthvalue_true_node;
-                 $$ = parser_build_binary_op (TRUTH_ORIF_EXPR, $1, $4); }
-       | expr_no_commas '?'
-               { $1.value = lang_hooks.truthvalue_conversion
-                   (default_conversion ($1.value));
-                 skip_evaluation += $1.value == truthvalue_false_node; }
-          expr ':'
-               { skip_evaluation += (($1.value == truthvalue_true_node)
-                                     - ($1.value == truthvalue_false_node)); }
-         expr_no_commas
-               { 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.value));
-                 $1.value = lang_hooks.truthvalue_conversion ($<ttype>2);
-                 skip_evaluation += $1.value == truthvalue_true_node; }
-         ':' expr_no_commas
-               { 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
-               { $$.value = build_modify_expr ($1.value, NOP_EXPR, $3.value);
-                 $$.original_code = MODIFY_EXPR;
-               }
-       | expr_no_commas ASSIGN expr_no_commas
-               { $$.value = build_modify_expr ($1.value, $2, $3.value);
-                 TREE_NO_WARNING ($$.value) = 1;
-                 $$.original_code = ERROR_MARK;
-               }
-       ;
-
-primary:
-       IDENTIFIER
-               {
-                 if (yychar == YYEMPTY)
-                   yychar = YYLEX;
-                 $$.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
-               { $$.value = fname_decl (C_RID_CODE ($1), $1);
-                 $$.original_code = ERROR_MARK; }
-       | '(' typename ')' '{'
-               { start_init (NULL_TREE, NULL, 0);
-                 $<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
-               { 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)
-                   pedwarn ("ISO C90 forbids compound literals");
-                 $$.value = build_compound_literal (type, constructor);
-                 $$.original_code = ERROR_MARK;
-               }
-       | '(' expr ')'
-               { $$.value = $2.value;
-                 if (TREE_CODE ($$.value) == MODIFY_EXPR)
-                   TREE_NO_WARNING ($$.value) = 1;
-                 $$.original_code = ERROR_MARK; }
-       | '(' error ')'
-               { $$.value = error_mark_node; $$.original_code = ERROR_MARK; }
-       | compstmt_primary_start compstmt_nostart ')'
-                { if (pedantic)
-                   pedwarn ("ISO C forbids braced-groups within expressions");
-                 $$.value = c_finish_stmt_expr ($1);
-                 $$.original_code = ERROR_MARK;
-               }
-       | compstmt_primary_start error ')'
-               { c_finish_stmt_expr ($1);
-                 $$.value = error_mark_node;
-                 $$.original_code = ERROR_MARK;
-               }
-       | primary '(' exprlist ')'   %prec '.'
-               { $$.value = build_function_call ($1.value, $3);
-                 $$.original_code = ERROR_MARK; }
-       | VA_ARG '(' expr_no_commas ',' typename ')'
-               { $$.value = build_va_arg ($3.value, groktypename ($5));
-                 $$.original_code = ERROR_MARK; }
-
-       | 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.value);
-                  STRIP_NOPS (c);
-                  if (TREE_CODE (c) != INTEGER_CST)
-                    error ("first argument to %<__builtin_choose_expr%> not"
-                          " a constant");
-                  $$ = integer_zerop (c) ? $7 : $5;
-               }
-       | 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));
-
-                 $$.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 '.'
-               { $$.value = build_array_ref ($1.value, $3.value);
-                 $$.original_code = ERROR_MARK; }
-       | primary '.' identifier
-               { $$.value = build_component_ref ($1.value, $3);
-                 $$.original_code = ERROR_MARK; }
-       | primary POINTSAT identifier
-               {
-                  tree expr = build_indirect_ref ($1.value, "->");
-                 $$.value = build_component_ref (expr, $3);
-                 $$.original_code = ERROR_MARK;
-               }
-       | primary PLUSPLUS
-               { $$.value = build_unary_op (POSTINCREMENT_EXPR, $1.value, 0);
-                 $$.original_code = ERROR_MARK; }
-       | primary MINUSMINUS
-               { $$.value = build_unary_op (POSTDECREMENT_EXPR, $1.value, 0);
-                 $$.original_code = ERROR_MARK; }
-@@ifobjc
-       | objcmessageexpr
-               { $$.value = objc_build_message_expr ($1);
-                 $$.original_code = ERROR_MARK; }
-       | objcselectorexpr
-               { $$.value = objc_build_selector_expr ($1);
-                 $$.original_code = ERROR_MARK; }
-       | objcprotocolexpr
-               { $$.value = objc_build_protocol_expr ($1);
-                 $$.original_code = ERROR_MARK; }
-       | objcencodeexpr
-               { $$.value = objc_build_encode_expr ($1);
-                 $$.original_code = ERROR_MARK; }
-       | OBJC_STRING
-               { $$.value = objc_build_string_object ($1);
-                 $$.original_code = ERROR_MARK; }
-@@end_ifobjc
-       ;
-
-/* 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:
-       /* empty */
-       | datadecls
-       ;
-
-/* The following are analogous to lineno_decl, decls and decl
-   except that they do not allow nested functions.
-   They are used for old-style parm decls.  */
-lineno_datadecl:
-         save_location datadecl
-               { }
-       ;
-
-datadecls:
-       lineno_datadecl
-       | errstmt
-       | datadecls lineno_datadecl
-       | lineno_datadecl errstmt
-       ;
-
-/* We don't allow prefix attributes here because they cause reduce/reduce
-   conflicts: we can't know whether we're parsing a function decl with
-   attribute suffix, or function defn with attribute prefix on first old
-   style parm.  */
-datadecl:
-       declspecs_ts_nosa setspecs initdecls ';'
-               { POP_DECLSPEC_STACK; }
-       | declspecs_nots_nosa setspecs notype_initdecls ';'
-               { POP_DECLSPEC_STACK; }
-       | declspecs_ts_nosa ';'
-               { shadow_tag_warned (finish_declspecs ($1), 1);
-                 pedwarn ("empty declaration"); }
-       | declspecs_nots_nosa ';'
-               { pedwarn ("empty declaration"); }
-       ;
-
-/* This combination which saves a lineno before a decl
-   is the normal thing to use, rather than decl itself.
-   This is to avoid shift/reduce conflicts in contexts
-   where statement labels are allowed.  */
-lineno_decl:
-         save_location decl
-               { }
-       ;
-
-/* records the type and storage class specs to use for processing
-   the declarators that follow.
-   Maintains a stack of outer-level values of current_declspecs,
-   for the sake of parm declarations nested in function declarators.  */
-setspecs: /* empty */
-               { pending_xref_error ();
-                 PUSH_DECLSPEC_STACK;
-                 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; }
-       ;
-
-/* Possibly attributes after a comma, which should reset all_prefix_attributes
-   to prefix_attributes with these ones chained on the front.  */
-maybe_resetattrs:
-         maybe_attribute
-               { all_prefix_attributes = chainon ($1, prefix_attributes); }
-       ;
-
-decl:
-       declspecs_ts setspecs initdecls ';'
-               { POP_DECLSPEC_STACK; }
-       | declspecs_nots setspecs notype_initdecls ';'
-               { POP_DECLSPEC_STACK; }
-       | declspecs_ts setspecs nested_function
-               { POP_DECLSPEC_STACK; }
-       | declspecs_nots setspecs notype_nested_function
-               { POP_DECLSPEC_STACK; }
-       | declspecs ';'
-               { shadow_tag (finish_declspecs ($1)); }
-       | extension decl
-               { RESTORE_EXT_FLAGS ($1); }
-       ;
-
-/* A list of declaration specifiers.  These are:
-
-   - Storage class specifiers (scspec), which for GCC currently includes
-   function specifiers ("inline").
-
-   - Type specifiers (typespec_*).
-
-   - Type qualifiers (TYPE_QUAL).
-
-   - Attribute specifier lists (attributes).
-
-   The various cases below are classified according to:
-
-   (a) Whether a storage class specifier is included or not; some
-   places in the grammar disallow storage class specifiers (_sc or _nosc).
-
-   (b) Whether a type specifier has been seen; after a type specifier,
-   a typedef name is an identifier to redeclare (_ts or _nots).
-
-   (c) Whether the list starts with an attribute; in certain places,
-   the grammar requires specifiers that don't start with an attribute
-   (_sa or _nosa).
-
-   (d) Whether the list ends with an attribute (or a specifier such that
-   any following attribute would have been parsed as part of that specifier);
-   this avoids shift-reduce conflicts in the parsing of attributes
-   (_ea or _noea).
-
-   TODO:
-
-   (i) Distinguish between function specifiers and storage class specifiers,
-   at least for the purpose of warnings about obsolescent usage.
-
-   (ii) Halve the number of productions here by eliminating the _sc/_nosc
-   distinction and instead checking where required that storage class
-   specifiers aren't present.  */
-
-/* Declspecs which contain at least one type specifier or typedef name.
-   (Just `const' or `volatile' is not enough.)
-   A typedef'd name following these is taken as a name to be declared.  */
-
-declspecs_nosc_nots_nosa_noea:
-         TYPE_QUAL
-               { $$ = declspecs_add_qual (build_null_declspecs (), $1); }
-       | declspecs_nosc_nots_nosa_noea TYPE_QUAL
-               { $$ = declspecs_add_qual ($1, $2); }
-       | declspecs_nosc_nots_nosa_ea TYPE_QUAL
-               { $$ = declspecs_add_qual ($1, $2); }
-       ;
-
-declspecs_nosc_nots_nosa_ea:
-         declspecs_nosc_nots_nosa_noea attributes
-               { $$ = declspecs_add_attrs ($1, $2); }
-       ;
-
-declspecs_nosc_nots_sa_noea:
-         declspecs_nosc_nots_sa_noea TYPE_QUAL
-               { $$ = declspecs_add_qual ($1, $2); }
-       | declspecs_nosc_nots_sa_ea TYPE_QUAL
-               { $$ = declspecs_add_qual ($1, $2); }
-       ;
-
-declspecs_nosc_nots_sa_ea:
-         attributes
-               { $$ = declspecs_add_attrs (build_null_declspecs (), $1); }
-       | declspecs_nosc_nots_sa_noea attributes
-               { $$ = declspecs_add_attrs ($1, $2); }
-       ;
-
-declspecs_nosc_ts_nosa_noea:
-         typespec_nonattr
-               { $$ = declspecs_add_type (build_null_declspecs (), $1); }
-       | declspecs_nosc_ts_nosa_noea TYPE_QUAL
-               { $$ = declspecs_add_qual ($1, $2); }
-       | declspecs_nosc_ts_nosa_ea TYPE_QUAL
-               { $$ = declspecs_add_qual ($1, $2); }
-       | declspecs_nosc_ts_nosa_noea typespec_reserved_nonattr
-               { $$ = declspecs_add_type ($1, $2); }
-       | declspecs_nosc_ts_nosa_ea typespec_reserved_nonattr
-               { $$ = declspecs_add_type ($1, $2); }
-       | declspecs_nosc_nots_nosa_noea typespec_nonattr
-               { $$ = declspecs_add_type ($1, $2); }
-       | declspecs_nosc_nots_nosa_ea typespec_nonattr
-               { $$ = declspecs_add_type ($1, $2); }
-       ;
-
-declspecs_nosc_ts_nosa_ea:
-         typespec_attr
-               { $$ = declspecs_add_type (build_null_declspecs (), $1); }
-       | declspecs_nosc_ts_nosa_noea attributes
-               { $$ = declspecs_add_attrs ($1, $2); }
-       | declspecs_nosc_ts_nosa_noea typespec_reserved_attr
-               { $$ = declspecs_add_type ($1, $2); }
-       | declspecs_nosc_ts_nosa_ea typespec_reserved_attr
-               { $$ = declspecs_add_type ($1, $2); }
-       | declspecs_nosc_nots_nosa_noea typespec_attr
-               { $$ = declspecs_add_type ($1, $2); }
-       | declspecs_nosc_nots_nosa_ea typespec_attr
-               { $$ = declspecs_add_type ($1, $2); }
-       ;
-
-declspecs_nosc_ts_sa_noea:
-         declspecs_nosc_ts_sa_noea TYPE_QUAL
-               { $$ = declspecs_add_qual ($1, $2); }
-       | declspecs_nosc_ts_sa_ea TYPE_QUAL
-               { $$ = declspecs_add_qual ($1, $2); }
-       | declspecs_nosc_ts_sa_noea typespec_reserved_nonattr
-               { $$ = declspecs_add_type ($1, $2); }
-       | declspecs_nosc_ts_sa_ea typespec_reserved_nonattr
-               { $$ = declspecs_add_type ($1, $2); }
-       | declspecs_nosc_nots_sa_noea typespec_nonattr
-               { $$ = declspecs_add_type ($1, $2); }
-       | declspecs_nosc_nots_sa_ea typespec_nonattr
-               { $$ = declspecs_add_type ($1, $2); }
-       ;
-
-declspecs_nosc_ts_sa_ea:
-         declspecs_nosc_ts_sa_noea attributes
-               { $$ = declspecs_add_attrs ($1, $2); }
-       | declspecs_nosc_ts_sa_noea typespec_reserved_attr
-               { $$ = declspecs_add_type ($1, $2); }
-       | declspecs_nosc_ts_sa_ea typespec_reserved_attr
-               { $$ = declspecs_add_type ($1, $2); }
-       | declspecs_nosc_nots_sa_noea typespec_attr
-               { $$ = declspecs_add_type ($1, $2); }
-       | declspecs_nosc_nots_sa_ea typespec_attr
-               { $$ = declspecs_add_type ($1, $2); }
-       ;
-
-declspecs_sc_nots_nosa_noea:
-         scspec
-               { $$ = declspecs_add_scspec (build_null_declspecs (), $1); }
-       | declspecs_sc_nots_nosa_noea TYPE_QUAL
-               { $$ = declspecs_add_qual ($1, $2); }
-       | declspecs_sc_nots_nosa_ea TYPE_QUAL
-               { $$ = declspecs_add_qual ($1, $2); }
-       | declspecs_nosc_nots_nosa_noea scspec
-               { $$ = declspecs_add_scspec ($1, $2); }
-       | declspecs_nosc_nots_nosa_ea scspec
-               { $$ = declspecs_add_scspec ($1, $2); }
-       | declspecs_sc_nots_nosa_noea scspec
-               { $$ = declspecs_add_scspec ($1, $2); }
-       | declspecs_sc_nots_nosa_ea scspec
-               { $$ = declspecs_add_scspec ($1, $2); }
-       ;
-
-declspecs_sc_nots_nosa_ea:
-         declspecs_sc_nots_nosa_noea attributes
-               { $$ = declspecs_add_attrs ($1, $2); }
-       ;
-
-declspecs_sc_nots_sa_noea:
-         declspecs_sc_nots_sa_noea TYPE_QUAL
-               { $$ = declspecs_add_qual ($1, $2); }
-       | declspecs_sc_nots_sa_ea TYPE_QUAL
-               { $$ = declspecs_add_qual ($1, $2); }
-       | declspecs_nosc_nots_sa_noea scspec
-               { $$ = declspecs_add_scspec ($1, $2); }
-       | declspecs_nosc_nots_sa_ea scspec
-               { $$ = declspecs_add_scspec ($1, $2); }
-       | declspecs_sc_nots_sa_noea scspec
-               { $$ = declspecs_add_scspec ($1, $2); }
-       | declspecs_sc_nots_sa_ea scspec
-               { $$ = declspecs_add_scspec ($1, $2); }
-       ;
-
-declspecs_sc_nots_sa_ea:
-         declspecs_sc_nots_sa_noea attributes
-               { $$ = declspecs_add_attrs ($1, $2); }
-       ;
-
-declspecs_sc_ts_nosa_noea:
-         declspecs_sc_ts_nosa_noea TYPE_QUAL
-               { $$ = declspecs_add_qual ($1, $2); }
-       | declspecs_sc_ts_nosa_ea TYPE_QUAL
-               { $$ = declspecs_add_qual ($1, $2); }
-       | declspecs_sc_ts_nosa_noea typespec_reserved_nonattr
-               { $$ = declspecs_add_type ($1, $2); }
-       | declspecs_sc_ts_nosa_ea typespec_reserved_nonattr
-               { $$ = declspecs_add_type ($1, $2); }
-       | declspecs_sc_nots_nosa_noea typespec_nonattr
-               { $$ = declspecs_add_type ($1, $2); }
-       | declspecs_sc_nots_nosa_ea typespec_nonattr
-               { $$ = declspecs_add_type ($1, $2); }
-       | declspecs_nosc_ts_nosa_noea scspec
-               { $$ = declspecs_add_scspec ($1, $2); }
-       | declspecs_nosc_ts_nosa_ea scspec
-               { $$ = declspecs_add_scspec ($1, $2); }
-       | declspecs_sc_ts_nosa_noea scspec
-               { $$ = declspecs_add_scspec ($1, $2); }
-       | declspecs_sc_ts_nosa_ea scspec
-               { $$ = declspecs_add_scspec ($1, $2); }
-       ;
-
-declspecs_sc_ts_nosa_ea:
-         declspecs_sc_ts_nosa_noea attributes
-               { $$ = declspecs_add_attrs ($1, $2); }
-       | declspecs_sc_ts_nosa_noea typespec_reserved_attr
-               { $$ = declspecs_add_type ($1, $2); }
-       | declspecs_sc_ts_nosa_ea typespec_reserved_attr
-               { $$ = declspecs_add_type ($1, $2); }
-       | declspecs_sc_nots_nosa_noea typespec_attr
-               { $$ = declspecs_add_type ($1, $2); }
-       | declspecs_sc_nots_nosa_ea typespec_attr
-               { $$ = declspecs_add_type ($1, $2); }
-       ;
-
-declspecs_sc_ts_sa_noea:
-         declspecs_sc_ts_sa_noea TYPE_QUAL
-               { $$ = declspecs_add_qual ($1, $2); }
-       | declspecs_sc_ts_sa_ea TYPE_QUAL
-               { $$ = declspecs_add_qual ($1, $2); }
-       | declspecs_sc_ts_sa_noea typespec_reserved_nonattr
-               { $$ = declspecs_add_type ($1, $2); }
-       | declspecs_sc_ts_sa_ea typespec_reserved_nonattr
-               { $$ = declspecs_add_type ($1, $2); }
-       | declspecs_sc_nots_sa_noea typespec_nonattr
-               { $$ = declspecs_add_type ($1, $2); }
-       | declspecs_sc_nots_sa_ea typespec_nonattr
-               { $$ = declspecs_add_type ($1, $2); }
-       | declspecs_nosc_ts_sa_noea scspec
-               { $$ = declspecs_add_scspec ($1, $2); }
-       | declspecs_nosc_ts_sa_ea scspec
-               { $$ = declspecs_add_scspec ($1, $2); }
-       | declspecs_sc_ts_sa_noea scspec
-               { $$ = declspecs_add_scspec ($1, $2); }
-       | declspecs_sc_ts_sa_ea scspec
-               { $$ = declspecs_add_scspec ($1, $2); }
-       ;
-
-declspecs_sc_ts_sa_ea:
-         declspecs_sc_ts_sa_noea attributes
-               { $$ = declspecs_add_attrs ($1, $2); }
-       | declspecs_sc_ts_sa_noea typespec_reserved_attr
-               { $$ = declspecs_add_type ($1, $2); }
-       | declspecs_sc_ts_sa_ea typespec_reserved_attr
-               { $$ = declspecs_add_type ($1, $2); }
-       | declspecs_sc_nots_sa_noea typespec_attr
-               { $$ = declspecs_add_type ($1, $2); }
-       | declspecs_sc_nots_sa_ea typespec_attr
-               { $$ = declspecs_add_type ($1, $2); }
-       ;
-
-/* Particular useful classes of declspecs.  */
-declspecs_ts:
-         declspecs_nosc_ts_nosa_noea
-       | declspecs_nosc_ts_nosa_ea
-       | declspecs_nosc_ts_sa_noea
-       | declspecs_nosc_ts_sa_ea
-       | declspecs_sc_ts_nosa_noea
-       | declspecs_sc_ts_nosa_ea
-       | declspecs_sc_ts_sa_noea
-       | declspecs_sc_ts_sa_ea
-       ;
-
-declspecs_nots:
-         declspecs_nosc_nots_nosa_noea
-       | declspecs_nosc_nots_nosa_ea
-       | declspecs_nosc_nots_sa_noea
-       | declspecs_nosc_nots_sa_ea
-       | declspecs_sc_nots_nosa_noea
-       | declspecs_sc_nots_nosa_ea
-       | declspecs_sc_nots_sa_noea
-       | declspecs_sc_nots_sa_ea
-       ;
-
-declspecs_ts_nosa:
-         declspecs_nosc_ts_nosa_noea
-       | declspecs_nosc_ts_nosa_ea
-       | declspecs_sc_ts_nosa_noea
-       | declspecs_sc_ts_nosa_ea
-       ;
-
-declspecs_nots_nosa:
-         declspecs_nosc_nots_nosa_noea
-       | declspecs_nosc_nots_nosa_ea
-       | declspecs_sc_nots_nosa_noea
-       | declspecs_sc_nots_nosa_ea
-       ;
-
-declspecs_nosc_ts:
-         declspecs_nosc_ts_nosa_noea
-       | declspecs_nosc_ts_nosa_ea
-       | declspecs_nosc_ts_sa_noea
-       | declspecs_nosc_ts_sa_ea
-       ;
-
-declspecs_nosc_nots:
-         declspecs_nosc_nots_nosa_noea
-       | declspecs_nosc_nots_nosa_ea
-       | declspecs_nosc_nots_sa_noea
-       | declspecs_nosc_nots_sa_ea
-       ;
-
-declspecs_nosc:
-         declspecs_nosc_ts_nosa_noea
-       | declspecs_nosc_ts_nosa_ea
-       | declspecs_nosc_ts_sa_noea
-       | declspecs_nosc_ts_sa_ea
-       | declspecs_nosc_nots_nosa_noea
-       | declspecs_nosc_nots_nosa_ea
-       | declspecs_nosc_nots_sa_noea
-       | declspecs_nosc_nots_sa_ea
-       ;
-
-declspecs:
-         declspecs_nosc_nots_nosa_noea
-       | declspecs_nosc_nots_nosa_ea
-       | declspecs_nosc_nots_sa_noea
-       | declspecs_nosc_nots_sa_ea
-       | declspecs_nosc_ts_nosa_noea
-       | declspecs_nosc_ts_nosa_ea
-       | declspecs_nosc_ts_sa_noea
-       | declspecs_nosc_ts_sa_ea
-       | declspecs_sc_nots_nosa_noea
-       | declspecs_sc_nots_nosa_ea
-       | declspecs_sc_nots_sa_noea
-       | declspecs_sc_nots_sa_ea
-       | declspecs_sc_ts_nosa_noea
-       | declspecs_sc_ts_nosa_ea
-       | declspecs_sc_ts_sa_noea
-       | declspecs_sc_ts_sa_ea
-       ;
-
-/* A (possibly empty) sequence of type qualifiers and attributes.  */
-maybe_type_quals_attrs:
-         /* empty */
-               { $$ = NULL; }
-       | declspecs_nosc_nots
-               { $$ = $1; }
-       ;
-
-/* A type specifier (but not a type qualifier).
-   Once we have seen one of these in a declaration,
-   if a typedef name appears then it is being redeclared.
-
-   The _reserved versions start with a reserved word and may appear anywhere
-   in the declaration specifiers; the _nonreserved versions may only
-   appear before any other type specifiers, and after that are (if names)
-   being redeclared.
-
-   FIXME: should the _nonreserved version be restricted to names being
-   redeclared only?  The other entries there relate only the GNU extensions
-   and Objective C, and are historically parsed thus, and don't make sense
-   after other type specifiers, but it might be cleaner to count them as
-   _reserved.
-
-   _attr means: specifiers that either end with attributes,
-   or are such that any following attributes would
-   be parsed as part of the specifier.
-
-   _nonattr: other specifiers not ending with attributes.  */
-
-typespec_nonattr:
-         typespec_reserved_nonattr
-       | typespec_nonreserved_nonattr
-       ;
-
-typespec_attr:
-         typespec_reserved_attr
-       ;
-
-typespec_reserved_nonattr:
-         TYPESPEC
-               { OBJC_NEED_RAW_IDENTIFIER (1);
-                 $$.kind = ctsk_resword;
-                 $$.spec = $1; }
-       | structsp_nonattr
-       ;
-
-typespec_reserved_attr:
-         structsp_attr
-       ;
-
-typespec_nonreserved_nonattr:
-         TYPENAME
-               { /* For a typedef name, record the meaning, not the name.
-                    In case of `foo foo, bar;'.  */
-                 $$.kind = ctsk_typedef;
-                 $$.spec = lookup_name ($1); }
-@@ifobjc
-       | CLASSNAME protocolrefs
-               { $$.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
-                { $$.kind = ctsk_objc;
-                 $$.spec = objc_get_protocol_qualified_type (NULL_TREE, $1); }
-@@end_ifobjc
-       | typeof '(' expr ')'
-               { skip_evaluation--;
-                 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--;
-                 in_typeof--;
-                 $$.kind = ctsk_typeof;
-                 $$.spec = groktypename ($3);
-                 pop_maybe_used (variably_modified_type_p ($$.spec,
-                                                           NULL_TREE)); }
-       ;
-
-/* typespec_nonreserved_attr does not exist.  */
-
-initdecls:
-       initdcl
-       | initdecls ',' maybe_resetattrs initdcl
-       ;
-
-notype_initdecls:
-       notype_initdcl
-       | notype_initdecls ',' maybe_resetattrs notype_initdcl
-       ;
-
-initdcl:
-         declarator maybeasm maybe_attribute '='
-               { $<ttype>$ = start_decl ($1, current_declspecs, true,
-                                         chainon ($3, all_prefix_attributes));
-                 if (!$<ttype>$)
-                   $<ttype>$ = error_mark_node;
-                 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 ();
-                 if ($<ttype>5 != error_mark_node)
-                   {
-                     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, false,
-                                      chainon ($3, all_prefix_attributes));
-                 if (d)
-                   finish_decl (d, NULL_TREE, $2);
-                }
-       ;
-
-notype_initdcl:
-         notype_declarator maybeasm maybe_attribute '='
-               { $<ttype>$ = start_decl ($1, current_declspecs, true,
-                                         chainon ($3, all_prefix_attributes));
-                 if (!$<ttype>$)
-                   $<ttype>$ = error_mark_node;
-                 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 ();
-                 if ($<ttype>5 != error_mark_node)
-                   {
-                     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, false,
-                                      chainon ($3, all_prefix_attributes));
-                 if (d)
-                    finish_decl (d, NULL_TREE, $2); }
-       ;
-/* the * rules are dummies to accept the Apollo extended syntax
-   so that the header files compile. */
-maybe_attribute:
-      /* empty */
-               { $$ = NULL_TREE; }
-       | attributes
-               { $$ = $1; }
-       ;
-
-attributes:
-      attribute
-               { $$ = $1; }
-       | attributes attribute
-               { $$ = chainon ($1, $2); }
-       ;
-
-attribute:
-      ATTRIBUTE stop_string_translation
-                '(' '(' attribute_list ')' ')' start_string_translation
-               { $$ = $5; }
-      | ATTRIBUTE error start_string_translation
-                { $$ = NULL_TREE; }
-       ;
-
-attribute_list:
-      attrib
-               { $$ = $1; }
-       | attribute_list ',' attrib
-               { $$ = chainon ($1, $3); }
-       ;
-
-attrib:
-    /* empty */
-               { $$ = NULL_TREE; }
-       | any_word
-               { $$ = build_tree_list ($1, NULL_TREE); }
-       | any_word '(' IDENTIFIER ')'
-               { $$ = build_tree_list ($1, build_tree_list (NULL_TREE, $3)); }
-       | any_word '(' IDENTIFIER ',' nonnull_exprlist ')'
-               { $$ = build_tree_list ($1, tree_cons (NULL_TREE, $3, $5)); }
-       | any_word '(' exprlist ')'
-               { $$ = build_tree_list ($1, $3); }
-       ;
-
-/* This still leaves out most reserved keywords,
-   shouldn't we include them?  */
-
-any_word:
-         identifier
-       | scspec
-       | TYPESPEC
-       | TYPE_QUAL
-       ;
-
-scspec:
-         STATIC
-       | SCSPEC
-       ;
-\f
-/* Initializers.  `init' is the entry point.  */
-
-init:
-       expr_no_commas
-               { $$ = $1; }
-       | '{'
-               { really_start_incremental_init (NULL_TREE); }
-         initlist_maybe_comma '}'
-               { $$ = pop_init_level (0); }
-       | error
-               { $$.value = error_mark_node; $$.original_code = ERROR_MARK; }
-       ;
-
-/* `initlist_maybe_comma' is the guts of an initializer in braces.  */
-initlist_maybe_comma:
-         /* empty */
-               { if (pedantic)
-                   pedwarn ("ISO C forbids empty initializer braces"); }
-       | initlist1 maybecomma
-       ;
-
-initlist1:
-         initelt
-       | initlist1 ',' initelt
-       ;
-
-/* `initelt' is a single element of an initializer.
-   It may use braces.  */
-initelt:
-         designator_list '=' initval
-               { if (pedantic && !flag_isoc99)
-                   pedwarn ("ISO C90 forbids specifying subobject to initialize"); }
-       | array_designator initval
-               { if (pedantic)
-                   pedwarn ("obsolete use of designated initializer without %<=%>"); }
-       | identifier ':'
-               { set_init_label ($1);
-                 if (pedantic)
-                   pedwarn ("obsolete use of designated initializer with %<:%>"); }
-         initval
-               {}
-       | initval
-       ;
-
-initval:
-         '{'
-               { push_init_level (0); }
-         initlist_maybe_comma '}'
-               { process_init_element (pop_init_level (0)); }
-       | expr_no_commas
-               { process_init_element ($1); }
-       | error
-       ;
-
-designator_list:
-         designator
-       | designator_list designator
-       ;
-
-designator:
-         '.' identifier
-               { set_init_label ($2); }
-       | 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.value, NULL_TREE); }
-       ;
-\f
-nested_function:
-       declarator
-               { if (pedantic)
-                   pedwarn ("ISO C forbids nested functions");
-
-                 push_function_context ();
-                 if (!start_function (current_declspecs, $1,
-                                      all_prefix_attributes))
-                   {
-                     pop_function_context ();
-                     YYERROR1;
-                   }
-               }
-       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
-               { tree decl = current_function_decl;
-                 add_stmt ($6);
-                 finish_function ();
-                 pop_function_context ();
-                 add_stmt (build_stmt (DECL_EXPR, decl)); }
-       ;
-
-notype_nested_function:
-       notype_declarator
-               { if (pedantic)
-                   pedwarn ("ISO C forbids nested functions");
-
-                 push_function_context ();
-                 if (!start_function (current_declspecs, $1,
-                                      all_prefix_attributes))
-                   {
-                     pop_function_context ();
-                     YYERROR1;
-                   }
-               }
-       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
-               { tree decl = current_function_decl;
-                 add_stmt ($6);
-                 finish_function ();
-                 pop_function_context ();
-                 add_stmt (build_stmt (DECL_EXPR, decl)); }
-       ;
-
-/* Any kind of declarator (thus, all declarators allowed
-   after an explicit typespec).  */
-
-declarator:
-         after_type_declarator
-       | notype_declarator
-       ;
-
-/* A declarator that is allowed only after an explicit typespec.  */
-
-after_type_declarator:
-         '(' maybe_attribute after_type_declarator ')'
-               { $$ = $2 ? build_attrs_declarator ($2, $3) : $3; }
-       | after_type_declarator '(' parmlist_or_identifiers  %prec '.'
-               { $$ = build_function_declarator ($3, $1); }
-       | after_type_declarator array_declarator  %prec '.'
-               { $$ = set_array_declarator_inner ($2, $1, false); }
-       | '*' maybe_type_quals_attrs after_type_declarator  %prec UNARY
-               { $$ = make_pointer_declarator ($2, $3); }
-       | TYPENAME
-               { $$ = build_id_declarator ($1); }
-       ;
-
-/* Kinds of declarator that can appear in a parameter list
-   in addition to notype_declarator.  This is like after_type_declarator
-   but does not allow a typedef name in parentheses as an identifier
-   (because it would conflict with a function with that typedef as arg).  */
-parm_declarator:
-         parm_declarator_starttypename
-       | parm_declarator_nostarttypename
-       ;
-
-parm_declarator_starttypename:
-         parm_declarator_starttypename '(' parmlist_or_identifiers  %prec '.'
-               { $$ = build_function_declarator ($3, $1); }
-       | parm_declarator_starttypename array_declarator  %prec '.'
-               { $$ = set_array_declarator_inner ($2, $1, false); }
-       | TYPENAME
-               { $$ = build_id_declarator ($1); }
-       ;
-
-parm_declarator_nostarttypename:
-         parm_declarator_nostarttypename '(' parmlist_or_identifiers  %prec '.'
-               { $$ = build_function_declarator ($3, $1); }
-       | parm_declarator_nostarttypename array_declarator  %prec '.'
-               { $$ = 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 ? build_attrs_declarator ($2, $3) : $3; }
-       ;
-
-/* A declarator allowed whether or not there has been
-   an explicit typespec.  These cannot redeclare a typedef-name.  */
-
-notype_declarator:
-         notype_declarator '(' parmlist_or_identifiers  %prec '.'
-               { $$ = build_function_declarator ($3, $1); }
-       | '(' maybe_attribute notype_declarator ')'
-               { $$ = $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_inner ($2, $1, false); }
-       | IDENTIFIER
-               { $$ = build_id_declarator ($1); }
-       ;
-
-struct_head:
-         STRUCT
-               { $$ = NULL_TREE; }
-       | STRUCT attributes
-               { $$ = $2; }
-       ;
-
-union_head:
-         UNION
-               { $$ = NULL_TREE; }
-       | UNION attributes
-               { $$ = $2; }
-       ;
-
-enum_head:
-         ENUM
-               { $$ = NULL_TREE; }
-       | ENUM attributes
-               { $$ = $2; }
-       ;
-
-/* structsp_attr: struct/union/enum specifiers that either
-   end with attributes, or are such that any following attributes would
-   be parsed as part of the struct/union/enum specifier.
-
-   structsp_nonattr: other struct/union/enum specifiers.  */
-
-structsp_attr:
-         struct_head identifier '{'
-               { $<ttype>$ = start_struct (RECORD_TYPE, $2);
-                 /* Start scope of tag before parsing components.  */
-               }
-         component_decl_list '}' maybe_attribute
-               { $$.spec = finish_struct ($<ttype>4, nreverse ($5),
-                                          chainon ($1, $7));
-                 $$.kind = ctsk_tagdef; }
-       | struct_head '{' component_decl_list '}' maybe_attribute
-               { $$.spec = finish_struct (start_struct (RECORD_TYPE,
-                                                        NULL_TREE),
-                                          nreverse ($3), chainon ($1, $5));
-                 $$.kind = ctsk_tagdef;
-               }
-       | union_head identifier '{'
-               { $<ttype>$ = start_struct (UNION_TYPE, $2); }
-         component_decl_list '}' maybe_attribute
-               { $$.spec = finish_struct ($<ttype>4, nreverse ($5),
-                                          chainon ($1, $7));
-                 $$.kind = ctsk_tagdef; }
-       | union_head '{' component_decl_list '}' maybe_attribute
-               { $$.spec = finish_struct (start_struct (UNION_TYPE,
-                                                        NULL_TREE),
-                                          nreverse ($3), chainon ($1, $5));
-                 $$.kind = ctsk_tagdef;
-               }
-       | enum_head identifier '{'
-               { $<ttype>$ = start_enum ($2); }
-         enumlist maybecomma_warn '}' maybe_attribute
-               { $$.spec = finish_enum ($<ttype>4, nreverse ($5),
-                                        chainon ($1, $8));
-                 $$.kind = ctsk_tagdef; }
-       | enum_head '{'
-               { $<ttype>$ = start_enum (NULL_TREE); }
-         enumlist maybecomma_warn '}' maybe_attribute
-               { $$.spec = finish_enum ($<ttype>3, nreverse ($4),
-                                        chainon ($1, $7));
-                 $$.kind = ctsk_tagdef; }
-       ;
-
-structsp_nonattr:
-         struct_head identifier
-               { $$ = parser_xref_tag (RECORD_TYPE, $2); }
-       | union_head identifier
-               { $$ = parser_xref_tag (UNION_TYPE, $2); }
-       | enum_head identifier
-               { $$ = parser_xref_tag (ENUMERAL_TYPE, $2);
-                 /* In ISO C, enumerated types can be referred to
-                    only if already defined.  */
-                 if (pedantic && !COMPLETE_TYPE_P ($$.spec))
-                   pedwarn ("ISO C forbids forward references to %<enum%> types"); }
-       ;
-
-maybecomma:
-         /* empty */
-       | ','
-       ;
-
-maybecomma_warn:
-         /* empty */
-       | ','
-               { if (pedantic && !flag_isoc99)
-                   pedwarn ("comma at end of enumerator list"); }
-       ;
-
-/* We chain the components in reverse order.  They are put in forward
-   order in structsp_attr.
-
-   Note that component_declarator returns single decls, so components
-   and components_notype can use TREE_CHAIN directly, wheras components
-   and components_notype return lists (of comma separated decls), so
-   component_decl_list and component_decl_list2 must use chainon.
-
-   The theory behind all this is that there will be more semicolon
-   separated fields than comma separated fields, and so we'll be
-   minimizing the number of node traversals required by chainon.  */
-
-component_decl_list:
-         component_decl_list2
-               { $$ = $1; }
-       | component_decl_list2 component_decl
-               { $$ = chainon ($2, $1);
-                 pedwarn ("no semicolon at end of struct or union"); }
-       ;
-
-component_decl_list2:  /* empty */
-               { $$ = NULL_TREE; }
-       | component_decl_list2 component_decl ';'
-               { $$ = chainon ($2, $1); }
-       | component_decl_list2 ';'
-               { if (pedantic)
-                   pedwarn ("extra semicolon in struct or union specified"); }
-@@ifobjc
-       /* foo(sizeof(struct{ @defs(ClassName)})); */
-       | AT_DEFS '(' CLASSNAME ')'
-               { $$ = nreverse (objc_get_class_ivars ($3)); }
-@@end_ifobjc
-       ;
-
-component_decl:
-         declspecs_nosc_ts setspecs components
-               { $$ = $3;
-                 POP_DECLSPEC_STACK; }
-       | declspecs_nosc_ts setspecs
-               {
-                 /* Support for unnamed structs or unions as members of
-                    structs or unions (which is [a] useful and [b] supports
-                    MS P-SDK).  */
-                 $$ = grokfield (build_id_declarator (NULL_TREE),
-                                 current_declspecs, NULL_TREE);
-                 POP_DECLSPEC_STACK; }
-       | declspecs_nosc_nots setspecs components_notype
-               { $$ = $3;
-                 POP_DECLSPEC_STACK; }
-       | declspecs_nosc_nots
-               { if (pedantic)
-                   pedwarn ("ISO C forbids member declarations with no members");
-                 shadow_tag_warned (finish_declspecs ($1), pedantic);
-                 $$ = NULL_TREE; }
-       | error
-               { $$ = NULL_TREE; }
-       | extension component_decl
-               { $$ = $2;
-                 RESTORE_EXT_FLAGS ($1); }
-       ;
-
-components:
-         component_declarator
-       | components ',' maybe_resetattrs component_declarator
-               { TREE_CHAIN ($4) = $1; $$ = $4; }
-       ;
-
-components_notype:
-         component_notype_declarator
-       | components_notype ',' maybe_resetattrs component_notype_declarator
-               { TREE_CHAIN ($4) = $1; $$ = $4; }
-       ;
-
-component_declarator:
-         declarator maybe_attribute
-               { $$ = grokfield ($1, current_declspecs, NULL_TREE);
-                 decl_attributes (&$$,
-                                  chainon ($2, all_prefix_attributes), 0); }
-       | declarator ':' expr_no_commas maybe_attribute
-               { $$ = grokfield ($1, current_declspecs, $3.value);
-                 decl_attributes (&$$,
-                                  chainon ($4, all_prefix_attributes), 0); }
-       | ':' expr_no_commas maybe_attribute
-               { $$ = grokfield (build_id_declarator (NULL_TREE),
-                                 current_declspecs, $2.value);
-                 decl_attributes (&$$,
-                                  chainon ($3, all_prefix_attributes), 0); }
-       ;
-
-component_notype_declarator:
-         notype_declarator maybe_attribute
-               { $$ = grokfield ($1, current_declspecs, NULL_TREE);
-                 decl_attributes (&$$,
-                                  chainon ($2, all_prefix_attributes), 0); }
-       | notype_declarator ':' expr_no_commas maybe_attribute
-               { $$ = grokfield ($1, current_declspecs, $3.value);
-                 decl_attributes (&$$,
-                                  chainon ($4, all_prefix_attributes), 0); }
-       | ':' expr_no_commas maybe_attribute
-               { $$ = grokfield (build_id_declarator (NULL_TREE),
-                                 current_declspecs, $2.value);
-                 decl_attributes (&$$,
-                                  chainon ($3, all_prefix_attributes), 0); }
-       ;
-
-/* We chain the enumerators in reverse order.
-   They are put in forward order in structsp_attr.  */
-
-enumlist:
-         enumerator
-       | enumlist ',' enumerator
-               { if ($1 == error_mark_node)
-                   $$ = $1;
-                 else
-                   TREE_CHAIN ($3) = $1, $$ = $3; }
-       | error
-               { $$ = error_mark_node; }
-       ;
-
-
-enumerator:
-         identifier
-               { $$ = build_enumerator ($1, NULL_TREE); }
-       | identifier '=' expr_no_commas
-               { $$ = build_enumerator ($1, $3.value); }
-       ;
-
-typename:
-         declspecs_nosc
-               { pending_xref_error ();
-                 $<dsptype>$ = finish_declspecs ($1); }
-         absdcl
-               { $$ = XOBNEW (&parser_obstack, struct c_type_name);
-                 $$->specs = $<dsptype>2;
-                 $$->declarator = $3; }
-       ;
-
-absdcl:   /* an absolute declarator */
-       /* empty */
-               { $$ = build_id_declarator (NULL_TREE); }
-       | absdcl1
-       ;
-
-absdcl_maybe_attribute:   /* absdcl maybe_attribute, but not just attributes */
-       /* empty */
-               { $$ = build_c_parm (current_declspecs, all_prefix_attributes,
-                                    build_id_declarator (NULL_TREE)); }
-       | absdcl1
-               { $$ = build_c_parm (current_declspecs, all_prefix_attributes,
-                                    $1); }
-       | absdcl1_noea attributes
-               { $$ = build_c_parm (current_declspecs,
-                                    chainon ($2, all_prefix_attributes),
-                                    $1); }
-       ;
-
-absdcl1:  /* a nonempty absolute declarator */
-         absdcl1_ea
-       | absdcl1_noea
-       ;
-
-absdcl1_noea:
-         direct_absdcl1
-       | '*' maybe_type_quals_attrs absdcl1_noea
-               { $$ = make_pointer_declarator ($2, $3); }
-       ;
-
-absdcl1_ea:
-         '*' maybe_type_quals_attrs
-               { $$ = 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 ? build_attrs_declarator ($2, $3) : $3; }
-       | direct_absdcl1 '(' parmlist
-               { $$ = build_function_declarator ($3, $1); }
-       | direct_absdcl1 array_declarator
-               { $$ = set_array_declarator_inner ($2, $1, true); }
-       | '(' parmlist
-               { $$ = build_function_declarator
-                   ($2, build_id_declarator (NULL_TREE)); }
-       | array_declarator
-               { $$ = 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.value, $2, false, false); }
-       | '[' maybe_type_quals_attrs ']'
-               { $$ = build_array_declarator (NULL_TREE, $2, false, false); }
-       | '[' maybe_type_quals_attrs '*' ']'
-               { $$ = build_array_declarator (NULL_TREE, $2, false, true); }
-       | '[' STATIC maybe_type_quals_attrs expr_no_commas ']'
-               { $$ = 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.value, $2, true, false); }
-       ;
-
-/* A nonempty series of declarations and statements (possibly followed by
-   some labels) that can form the body of a compound statement.
-   NOTE: we don't allow labels on declarations; this might seem like a
-   natural extension, but there would be a conflict between attributes
-   on the label and prefix attributes on the declaration.  */
-
-stmts_and_decls:
-         lineno_stmt_decl_or_labels_ending_stmt
-       | lineno_stmt_decl_or_labels_ending_decl
-       | lineno_stmt_decl_or_labels_ending_label
-               {
-                 error ("label at end of compound statement");
-               }
-       | lineno_stmt_decl_or_labels_ending_error
-       ;
-
-lineno_stmt_decl_or_labels_ending_stmt:
-         lineno_stmt
-       | lineno_stmt_decl_or_labels_ending_stmt lineno_stmt
-       | lineno_stmt_decl_or_labels_ending_decl lineno_stmt
-       | lineno_stmt_decl_or_labels_ending_label lineno_stmt
-       | lineno_stmt_decl_or_labels_ending_error lineno_stmt
-       ;
-
-lineno_stmt_decl_or_labels_ending_decl:
-         lineno_decl
-       | lineno_stmt_decl_or_labels_ending_stmt lineno_decl
-               {
-                 if ((pedantic && !flag_isoc99)
-                     || warn_declaration_after_statement)
-                   pedwarn_c90 ("ISO C90 forbids mixed declarations and code");
-               }
-       | lineno_stmt_decl_or_labels_ending_decl lineno_decl
-       | lineno_stmt_decl_or_labels_ending_error lineno_decl
-       ;
-
-lineno_stmt_decl_or_labels_ending_label:
-         lineno_label
-       | lineno_stmt_decl_or_labels_ending_stmt lineno_label
-       | lineno_stmt_decl_or_labels_ending_decl lineno_label
-       | lineno_stmt_decl_or_labels_ending_label lineno_label
-       | lineno_stmt_decl_or_labels_ending_error lineno_label
-       ;
-
-lineno_stmt_decl_or_labels_ending_error:
-       errstmt
-       | lineno_stmt_decl_or_labels errstmt
-       ;
-
-lineno_stmt_decl_or_labels:
-         lineno_stmt_decl_or_labels_ending_stmt
-       | lineno_stmt_decl_or_labels_ending_decl
-       | lineno_stmt_decl_or_labels_ending_label
-       | lineno_stmt_decl_or_labels_ending_error
-       ;
-
-errstmt:  error ';'
-       ;
-
-/* Start and end blocks created for the new scopes of C99.  */
-c99_block_start: /* empty */
-               { $$ = c_begin_compound_stmt (flag_isoc99); }
-       ;
-
-/* Read zero or more forward-declarations for labels
-   that nested functions can jump to.  */
-maybe_label_decls:
-         /* empty */
-       | label_decls
-               { if (pedantic)
-                   pedwarn ("ISO C forbids label declarations"); }
-       ;
-
-label_decls:
-         label_decl
-       | label_decls label_decl
-       ;
-
-label_decl:
-         LABEL identifiers_or_typenames ';'
-               { tree link;
-                 for (link = $2; link; link = TREE_CHAIN (link))
-                   {
-                     tree label = declare_label (TREE_VALUE (link));
-                     C_DECLARED_LABEL_FLAG (label) = 1;
-                     add_stmt (build_stmt (DECL_EXPR, label));
-                   }
-               }
-       ;
-
-/* This is the body of a function definition.
-   It causes syntax errors to ignore to the next openbrace.  */
-compstmt_or_error:
-         compstmt
-               { add_stmt ($1); }
-       | error compstmt
-       ;
-
-compstmt_start: '{' { $$ = c_begin_compound_stmt (true); }
-        ;
-
-compstmt_nostart: '}'
-       | maybe_label_decls compstmt_contents_nonempty '}'
-       ;
-
-compstmt_contents_nonempty:
-         stmts_and_decls
-       | error
-       ;
-
-compstmt_primary_start:
-       '(' '{'
-               { if (cur_stmt_list == NULL)
-                   {
-                     error ("braced-group within expression allowed "
-                            "only inside a function");
-                     YYERROR;
-                   }
-                 $$ = c_begin_stmt_expr ();
-               }
-        ;
-
-compstmt: compstmt_start compstmt_nostart
-               { $$ = c_end_compound_stmt ($1, true); }
-       ;
-
-/* The forced readahead in here is because we might be at the end of a
-   line, and the line and file won't be bumped until yylex absorbs the
-   first token on the next line.  */
-
-save_location:
-               { if (yychar == YYEMPTY)
-                   yychar = YYLEX;
-                 $$ = input_location; }
-       ;
-
-lineno_labels:
-         /* empty */
-       | lineno_labels lineno_label
-       ;
-
-/* A labeled statement.  In C99 it also generates an implicit block.  */
-c99_block_lineno_labeled_stmt:
-         c99_block_start lineno_labels lineno_stmt
-                { $$ = c_end_compound_stmt ($1, flag_isoc99); }
-       ;
-
-lineno_stmt:
-         save_location stmt
-               {
-                 /* 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) SET_EXPR_LOCATION ($2, $1); }
-       ;
-
-condition: save_location expr
-               { $$ = lang_hooks.truthvalue_conversion ($2.value);
-                 if (EXPR_P ($$))
-                   SET_EXPR_LOCATION ($$, $1); }
-       ;
-
-/* 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; }
-       ;
-
-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 ';'
-               { $$ = c_finish_bc_stmt (&c_break_label, true); }
-       | CONTINUE ';'
-                { $$ = c_finish_bc_stmt (&c_cont_label, false); }
-       | RETURN ';'
-                { $$ = c_finish_return (NULL_TREE); }
-       | RETURN expr ';'
-                { $$ = c_finish_return ($2.value); }
-       | asm_stmt
-       | GOTO identifier ';'
-               { $$ = c_finish_goto_label ($2); }
-       | GOTO '*' expr ';'
-               { $$ = c_finish_goto_ptr ($3.value); }
-       | ';'
-               { $$ = NULL_TREE; }
-@@ifobjc
-       | AT_THROW expr ';'
-               { $$ = objc_build_throw_stmt ($2.value); }
-       | AT_THROW ';'
-               { $$ = objc_build_throw_stmt (NULL_TREE); }
-       | objc_try_catch_stmt
-               { $$ = NULL_TREE; }
-       | AT_SYNCHRONIZED save_location '(' expr ')' compstmt
-               { objc_build_synchronized ($2, $4.value, $6); $$ = NULL_TREE; }
-       ;
-
-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_opt_catch_list:
-         /* empty */
-       | objc_opt_catch_list objc_catch_clause
-       ;
-
-objc_try_catch_clause:
-       AT_TRY save_location compstmt
-               { objc_begin_try_stmt ($2, $3); }
-       objc_opt_catch_list
-       ;
-
-objc_finally_clause:
-       AT_FINALLY save_location compstmt
-               { objc_build_finally_clause ($2, $3); }
-       ;
-
-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 ':'
-                { $$ = do_case ($2.value, NULL_TREE); }
-       | CASE expr_no_commas ELLIPSIS expr_no_commas ':'
-                { $$ = do_case ($2.value, $4.value); }
-       | DEFAULT ':'
-                { $$ = do_case (NULL_TREE, NULL_TREE); }
-       | identifier save_location ':' maybe_attribute
-               { tree label = define_label ($2, $1);
-                 if (label)
-                   {
-                     decl_attributes (&label, $4, 0);
-                     $$ = add_stmt (build_stmt (LABEL_EXPR, label));
-                   }
-                 else
-                   $$ = NULL_TREE;
-               }
-       ;
-
-/* Asm expressions and statements */
-
-/* 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 stop_string_translation
-             '(' asm_string ')' start_string_translation
-               { $$ = $4; }
-       ;
-
-/* maybeasm: used for assembly names for declarations */
-maybeasm:
-         /* empty */
-               { $$ = NULL_TREE; }
-       | simple_asm_expr
-       ;
-
-/* asmdef: asm() outside a function body.  */
-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 stop_string_translation
-               '(' asm_argument ')' start_string_translation ';'
-               { $$ = build_asm_stmt ($2, $5); }
-       ;
-
-asm_argument:
-       /* no operands */
-       asm_string
-               { $$ = build_asm_expr ($1, 0, 0, 0, true); }
-       /* output operands */
-       | asm_string ':' asm_operands
-               { $$ = build_asm_expr ($1, $3, 0, 0, false); }
-       /* output and input operands */
-       | asm_string ':' asm_operands ':' asm_operands
-               { $$ = build_asm_expr ($1, $3, $5, 0, false); }
-       /* output and input operands and clobbers */
-       | asm_string ':' asm_operands ':' asm_operands ':' asm_clobbers
-               { $$ = build_asm_expr ($1, $3, $5, $7, false); }
-       ;
-
-/* Either 'volatile' or nothing.  First thing in an `asm' statement.  */
-
-maybe_volatile:
-       /* empty */
-               { $$ = 0; }
-       | TYPE_QUAL
-               { if ($1 != ridpointers[RID_VOLATILE])
-                   {
-                     warning ("%E qualifier ignored on asm", $1);
-                     $$ = 0;
-                   }
-                 else
-                   $$ = $1;
-               }
-       ;
-
-/* These are the operands other than the first string and colon
-   in  asm ("addextend %2,%1": "=dm" (x), "0" (y), "g" (*x))  */
-asm_operands: /* empty */
-               { $$ = NULL_TREE; }
-       | nonnull_asm_operands
-       ;
-
-nonnull_asm_operands:
-         asm_operand
-       | nonnull_asm_operands ',' asm_operand
-               { $$ = chainon ($1, $3); }
-       ;
-
-asm_operand:
-         asm_string start_string_translation '(' expr ')'
-           stop_string_translation
-               { $$ = build_tree_list (build_tree_list (NULL_TREE, $1),
-                                       $4.value); }
-       | '[' identifier ']' asm_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), $7.value); }
-       ;
-
-asm_clobbers:
-         asm_string
-               { $$ = tree_cons (NULL_TREE, $1, NULL_TREE); }
-       | asm_clobbers ',' asm_string
-               { $$ = tree_cons (NULL_TREE, $3, $1); }
-       ;
-
-/* Strings in 'asm' must be narrow strings.  */
-asm_string:
-         STRING
-               { if (TYPE_MAIN_VARIANT (TREE_TYPE (TREE_TYPE ($1)))
-                     != char_type_node)
-                   {
-                     error ("wide string literal in %<asm%>");
-                     $$ = build_string (1, "");
-                   }
-                 else
-                   $$ = $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
-   to avoid a conflict with their appearance after an open parenthesis
-   in an abstract declarator, as in
-   "void bar (int (__attribute__((__mode__(SI))) int foo));".  */
-parmlist:
-         maybe_attribute
-               { push_scope ();
-                 declare_parm_level (); }
-         parmlist_1
-               { $$ = $3;
-                 pop_scope (); }
-       ;
-
-parmlist_1:
-         parmlist_2 ')'
-       | parms ';'
-               { mark_forward_parm_decls (); }
-         maybe_attribute
-               { /* Dummy action so attributes are in known place
-                    on parser stack.  */ }
-         parmlist_1
-               { $$ = $6; }
-       | error ')'
-               { $$ = 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.
-   Its value is represented in the format that grokdeclarator expects.  */
-parmlist_2:  /* empty */
-               { $$ = XOBNEW (&parser_obstack, struct c_arg_info);
-                 $$->parms = 0;
-                 $$->tags = 0;
-                 $$->types = 0;
-                 $$->others = 0; }
-       | ELLIPSIS
-               { $$ = 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 (/*ellipsis=*/false); }
-       | parms ',' ELLIPSIS
-               { $$ = get_parm_info (/*ellipsis=*/true); }
-       ;
-
-parms:
-       firstparm
-               { push_parm_decl ($1); }
-       | parms ',' parm
-               { push_parm_decl ($3); }
-       ;
-
-/* A single parameter declaration or parameter type name,
-   as found in a parmlist.  */
-parm:
-         declspecs_ts setspecs parm_declarator maybe_attribute
-               { $$ = build_c_parm (current_declspecs,
-                                    chainon ($4, all_prefix_attributes), $3);
-                 POP_DECLSPEC_STACK; }
-       | declspecs_ts setspecs notype_declarator maybe_attribute
-               { $$ = 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_c_parm (current_declspecs,
-                                    chainon ($4, all_prefix_attributes), $3);
-                 POP_DECLSPEC_STACK; }
-
-       | declspecs_nots setspecs absdcl_maybe_attribute
-               { $$ = $3;
-                 POP_DECLSPEC_STACK; }
-       ;
-
-/* The first parm, which must suck attributes from off the top of the parser
-   stack.  */
-firstparm:
-         declspecs_ts_nosa setspecs_fp parm_declarator maybe_attribute
-               { $$ = build_c_parm (current_declspecs,
-                                    chainon ($4, all_prefix_attributes), $3);
-                 POP_DECLSPEC_STACK; }
-       | declspecs_ts_nosa setspecs_fp notype_declarator maybe_attribute
-               { $$ = 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_c_parm (current_declspecs,
-                                    chainon ($4, all_prefix_attributes), $3);
-                 POP_DECLSPEC_STACK; }
-
-       | declspecs_nots_nosa setspecs_fp absdcl_maybe_attribute
-               { $$ = $3;
-                 POP_DECLSPEC_STACK; }
-       ;
-
-setspecs_fp:
-         setspecs
-               { prefix_attributes = chainon (prefix_attributes, $<ttype>-2);
-                 all_prefix_attributes = prefix_attributes; }
-       ;
-
-/* This is used in a function definition
-   where either a parmlist or an identifier list is ok.
-   Its value is a list of ..._TYPE nodes or a list of identifiers.  */
-parmlist_or_identifiers:
-         maybe_attribute
-               { push_scope ();
-                 declare_parm_level (); }
-         parmlist_or_identifiers_1
-               { $$ = $3;
-                 pop_scope (); }
-       ;
-
-parmlist_or_identifiers_1:
-         parmlist_1
-       | identifiers ')'
-               { $$ = 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)
-                   YYERROR1;
-               }
-       ;
-
-/* A nonempty list of identifiers.  */
-identifiers:
-       IDENTIFIER
-               { $$ = build_tree_list (NULL_TREE, $1); }
-       | identifiers ',' IDENTIFIER
-               { $$ = chainon ($1, build_tree_list (NULL_TREE, $3)); }
-       ;
-
-/* A nonempty list of identifiers, including typenames.  */
-identifiers_or_typenames:
-       identifier
-               { $$ = build_tree_list (NULL_TREE, $1); }
-       | identifiers_or_typenames ',' identifier
-               { $$ = chainon ($1, build_tree_list (NULL_TREE, $3)); }
-       ;
-
-extension:
-       EXTENSION
-               { $$ = SAVE_EXT_FLAGS ();
-                 pedantic = 0;
-                 warn_pointer_arith = 0;
-                 warn_traditional = 0;
-                 flag_iso = 0; }
-       ;
-\f
-@@ifobjc
-/* Objective-C productions.  */
-
-objcdef:
-         classdef
-       | classdecl
-       | aliasdecl
-       | protocoldef
-       | methoddef
-       | AT_END
-               {
-                 objc_finish_implementation ();
-               }
-       ;
-
-/* A nonempty list of identifiers.  */
-identifier_list:
-       identifier
-               { $$ = build_tree_list (NULL_TREE, $1); }
-       | identifier_list ',' identifier
-               { $$ = chainon ($1, build_tree_list (NULL_TREE, $3)); }
-       ;
-
-classdecl:
-         AT_CLASS identifier_list ';'
-               {
-                 objc_declare_class ($2);
-               }
-       ;
-
-aliasdecl:
-         AT_ALIAS identifier identifier ';'
-               {
-                 objc_declare_alias ($2, $3);
-               }
-       ;
-
-superclass:
-         ':' identifier { $$ = $2; }
-       | /* NULL */ %prec HYPERUNARY    { $$ = NULL_TREE; }
-       ;
-
-class_ivars:
-         '{' ivar_decl_list '}'
-       | /* NULL */
-       ;
-
-classdef:
-         AT_INTERFACE identifier superclass protocolrefs
-               {
-                 objc_start_class_interface ($2, $3, $4);
-               }
-         class_ivars
-               {
-                 objc_continue_interface ();
-               }
-         methodprotolist AT_END
-               {
-                 objc_finish_interface ();
-               }
-
-       | AT_IMPLEMENTATION identifier superclass
-               {
-                 objc_start_class_implementation ($2, $3);
-               }
-         class_ivars
-               {
-                 objc_continue_implementation ();
-               }
-
-       | AT_INTERFACE identifier '(' identifier ')' protocolrefs
-               {
-                 objc_start_category_interface ($2, $4, $6);
-               }
-         methodprotolist AT_END
-               {
-                 objc_finish_interface ();
-               }
-
-       | AT_IMPLEMENTATION identifier '(' identifier ')'
-               {
-                 objc_start_category_implementation ($2, $4);
-               }
-       ;
-
-protocoldef:
-         AT_PROTOCOL identifier protocolrefs
-               {
-                 objc_pq_context = 1;
-                 objc_start_protocol ($2, $3);
-               }
-         methodprotolist AT_END
-               {
-                 objc_pq_context = 0;
-                 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'.  */
-       | AT_PROTOCOL identifier_list ';'
-               {
-                 objc_declare_protocols ($2);
-               }
-       ;
-
-protocolrefs:
-         /* empty */
-               {
-                 $$ = NULL_TREE;
-               }
-       | non_empty_protocolrefs
-       ;
-
-non_empty_protocolrefs:
-         ARITHCOMPARE identifier_list ARITHCOMPARE
-               {
-                 if ($1 == LT_EXPR && $3 == GT_EXPR)
-                   $$ = $2;
-                 else
-                   YYERROR1;
-               }
-       ;
-
-ivar_decl_list:
-         /* empty */
-        | ivar_decl_list visibility_spec ivar_decls
-        ;
-
-visibility_spec:
-         /* empty */
-       | AT_PRIVATE { objc_set_visibility (2); }
-       | AT_PROTECTED { objc_set_visibility (0); }
-       | AT_PUBLIC { objc_set_visibility (1); }
-       ;
-
-ivar_decls:
-         /* empty */
-       | ivar_decls ivar_decl ';'
-       | ivar_decls ';'
-               {
-                 if (pedantic)
-                   pedwarn ("extra semicolon in struct or union specified");
-               }
-       ;
-
-ivar_decl:
-       component_decl
-               {
-                 /* Comma-separated ivars are chained together in
-                    reverse order; add them one by one.  */
-                 tree ivar = nreverse ($1);
-
-                 for (; ivar; ivar = TREE_CHAIN (ivar))
-                   objc_add_instance_variable (copy_node (ivar));
-               }
-       ;
-
-opt_semi:
-         /* NULL */
-       | ';'
-               {
-                 if (pedantic)
-                   pedwarn ("extra semicolon in method definition specified");
-               }
-       ;
-
-methodtype:
-         '+'
-       | '-'
-       ;
-
-methoddef:
-         methodtype
-               {
-                 objc_set_method_type ($1);
-                 objc_pq_context = 1;
-               }
-         methoddecl opt_semi
-               {
-                 objc_pq_context = 0;
-                 objc_start_method_definition ($3);
-               }
-         compstmt_or_error
-               {
-                 objc_finish_method_definition (current_function_decl);
-               }
-       ;
-
-/* 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. */
-
-methodprotolist:
-         /* empty  */
-       | methodprotolist methodproto
-       | methodprotolist { $<ttype>$ = NULL_TREE; } datadef
-       ;
-
-semi_or_error:
-         ';'
-       | error
-       ;
-
-methodproto:
-         methodtype
-               {
-                 objc_set_method_type ($1);
-                 /* Remember protocol qualifiers in prototypes.  */
-                 objc_pq_context = 1;
-               }
-         methoddecl
-               {
-                 /* Forget protocol qualifiers here.  */
-                 objc_pq_context = 0;
-                 objc_add_method_declaration ($3);
-               }
-         semi_or_error
-       ;
-
-methoddecl:
-         '(' objc_typename ')' unaryselector
-               {
-                 $$ = objc_build_method_signature ($2, $4, NULL_TREE);
-               }
-
-       | unaryselector
-               {
-                 $$ = objc_build_method_signature (NULL_TREE, $1, NULL_TREE);
-               }
-
-       | '(' objc_typename ')' keywordselector optparmlist
-               {
-                 $$ = objc_build_method_signature ($2, $4, $5);
-               }
-
-       | keywordselector optparmlist
-               {
-                 $$ = objc_build_method_signature (NULL_TREE, $1, $2);
-               }
-       ;
-
-/* Optional ObjC method parameters follow the C syntax, and may include '...'
-   to denote a variable number of arguments.  */
-
-optparmlist:
-         optparms optellipsis
-               {
-                 TREE_OVERFLOW ($$) = $2;
-               }
-       ;
-
-optparms:
-         /* NULL */
-               {
-                 $$ = make_node (TREE_LIST);
-               }
-       | optparms ',' parm
-               {
-                 $$ = chainon ($1, build_tree_list (NULL_TREE,
-                                                    grokparm ($3)));
-               }
-       ;
-
-optellipsis:
-         /* NULL */
-               {
-                 $$ = 0;
-               }
-       | ',' ELLIPSIS
-               {
-                 $$ = 1;
-               }
-       ;
-
-unaryselector:
-         selector
-       ;
-
-keywordselector:
-         keyworddecl
-
-       | keywordselector keyworddecl
-               {
-                 $$ = chainon ($1, $2);
-               }
-       ;
-
-selector:
-         IDENTIFIER
-       | TYPENAME
-       | CLASSNAME
-       | reservedwords
-       ;
-
-reservedwords:
-         ENUM | STRUCT | UNION | IF | ELSE | WHILE | DO | FOR
-       | SWITCH | CASE | DEFAULT | BREAK | CONTINUE | RETURN
-       | GOTO | ASM_KEYWORD | SIZEOF | TYPEOF | ALIGNOF
-       | 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 ':' '(' objc_typename ')' identifier
-               {
-                 $$ = objc_build_keyword_decl ($1, $4, $6);
-               }
-
-       | selector ':' identifier
-               {
-                 $$ = objc_build_keyword_decl ($1, NULL_TREE, $3);
-               }
-
-       | ':' '(' objc_typename ')' identifier
-               {
-                 $$ = objc_build_keyword_decl (NULL_TREE, $3, $5);
-               }
-
-       | ':' identifier
-               {
-                 $$ = objc_build_keyword_decl (NULL_TREE, NULL_TREE, $2);
-               }
-       ;
-
-messageargs:
-         selector
-        | keywordarglist
-       ;
-
-keywordarglist:
-         keywordarg
-       | keywordarglist keywordarg
-               {
-                 $$ = chainon ($1, $2);
-               }
-       ;
-
-
-keywordexpr:
-         nonnull_exprlist
-               {
-                 if (TREE_CHAIN ($1) == NULL_TREE)
-                   /* just return the expr., remove a level of indirection */
-                   $$ = TREE_VALUE ($1);
-                  else
-                   /* we have a comma expr., we will collapse later */
-                   $$ = $1;
-               }
-       ;
-
-keywordarg:
-         selector ':' keywordexpr
-               {
-                 $$ = build_tree_list ($1, $3);
-               }
-       | ':' keywordexpr
-               {
-                 $$ = build_tree_list (NULL_TREE, $2);
-               }
-       ;
-
-receiver:
-         expr
-               { $$ = $1.value; }
-       | CLASSNAME
-               {
-                 $$ = objc_get_class_reference ($1);
-               }
-       | TYPENAME
-               {
-                 $$ = objc_get_class_reference ($1);
-               }
-       ;
-
-objcmessageexpr:
-         '[' receiver messageargs ']'
-               { $$ = build_tree_list ($2, $3); }
-       ;
-
-selectorarg:
-         selector
-        | keywordnamelist
-       ;
-
-keywordnamelist:
-         keywordname
-       | keywordnamelist keywordname
-               {
-                 $$ = chainon ($1, $2);
-               }
-       ;
-
-keywordname:
-         selector ':'
-               {
-                 $$ = build_tree_list ($1, NULL_TREE);
-               }
-       | ':'
-               {
-                 $$ = build_tree_list (NULL_TREE, NULL_TREE);
-               }
-       ;
-
-objcselectorexpr:
-         AT_SELECTOR '(' selectorarg ')'
-               {
-                 $$ = $3;
-               }
-       ;
-
-objcprotocolexpr:
-         AT_PROTOCOL '(' identifier ')'
-               {
-                 $$ = $3;
-               }
-       ;
-
-/* extension to support C-structures in the archiver */
-
-objcencodeexpr:
-         AT_ENCODE '(' typename ')'
-               {
-                 $$ = groktypename ($3);
-               }
-       ;
-
-@@end_ifobjc
-%%
-
-/* yylex() is a thin wrapper around c_lex(), all it does is translate
-   cpplib.h's token codes into yacc's token codes.  */
-
-static enum cpp_ttype last_token;
-
-/* The reserved keyword table.  */
-struct resword
-{
-  const char *word;
-  ENUM_BITFIELD(rid) rid : 16;
-  unsigned int disable   : 16;
-};
-
-/* Disable mask.  Keywords are disabled if (reswords[i].disable & mask) is
-   _true_.  */
-#define D_C89  0x01    /* not in C89 */
-#define D_EXT  0x02    /* GCC extension */
-#define D_EXT89        0x04    /* GCC extension incorporated in C99 */
-#define D_OBJC 0x08    /* Objective C only */
-
-static const struct resword reswords[] =
-{
-  { "_Bool",           RID_BOOL,       0 },
-  { "_Complex",                RID_COMPLEX,    0 },
-  { "__FUNCTION__",    RID_FUNCTION_NAME, 0 },
-  { "__PRETTY_FUNCTION__", RID_PRETTY_FUNCTION_NAME, 0 },
-  { "__alignof",       RID_ALIGNOF,    0 },
-  { "__alignof__",     RID_ALIGNOF,    0 },
-  { "__asm",           RID_ASM,        0 },
-  { "__asm__",         RID_ASM,        0 },
-  { "__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 },
-  { "__complex__",     RID_COMPLEX,    0 },
-  { "__const",         RID_CONST,      0 },
-  { "__const__",       RID_CONST,      0 },
-  { "__extension__",   RID_EXTENSION,  0 },
-  { "__func__",                RID_C99_FUNCTION_NAME, 0 },
-  { "__imag",          RID_IMAGPART,   0 },
-  { "__imag__",                RID_IMAGPART,   0 },
-  { "__inline",                RID_INLINE,     0 },
-  { "__inline__",      RID_INLINE,     0 },
-  { "__label__",       RID_LABEL,      0 },
-  { "__real",          RID_REALPART,   0 },
-  { "__real__",                RID_REALPART,   0 },
-  { "__restrict",      RID_RESTRICT,   0 },
-  { "__restrict__",    RID_RESTRICT,   0 },
-  { "__signed",                RID_SIGNED,     0 },
-  { "__signed__",      RID_SIGNED,     0 },
-  { "__thread",                RID_THREAD,     0 },
-  { "__typeof",                RID_TYPEOF,     0 },
-  { "__typeof__",      RID_TYPEOF,     0 },
-  { "__volatile",      RID_VOLATILE,   0 },
-  { "__volatile__",    RID_VOLATILE,   0 },
-  { "asm",             RID_ASM,        D_EXT },
-  { "auto",            RID_AUTO,       0 },
-  { "break",           RID_BREAK,      0 },
-  { "case",            RID_CASE,       0 },
-  { "char",            RID_CHAR,       0 },
-  { "const",           RID_CONST,      0 },
-  { "continue",                RID_CONTINUE,   0 },
-  { "default",         RID_DEFAULT,    0 },
-  { "do",              RID_DO,         0 },
-  { "double",          RID_DOUBLE,     0 },
-  { "else",            RID_ELSE,       0 },
-  { "enum",            RID_ENUM,       0 },
-  { "extern",          RID_EXTERN,     0 },
-  { "float",           RID_FLOAT,      0 },
-  { "for",             RID_FOR,        0 },
-  { "goto",            RID_GOTO,       0 },
-  { "if",              RID_IF,         0 },
-  { "inline",          RID_INLINE,     D_EXT89 },
-  { "int",             RID_INT,        0 },
-  { "long",            RID_LONG,       0 },
-  { "register",                RID_REGISTER,   0 },
-  { "restrict",                RID_RESTRICT,   D_C89 },
-  { "return",          RID_RETURN,     0 },
-  { "short",           RID_SHORT,      0 },
-  { "signed",          RID_SIGNED,     0 },
-  { "sizeof",          RID_SIZEOF,     0 },
-  { "static",          RID_STATIC,     0 },
-  { "struct",          RID_STRUCT,     0 },
-  { "switch",          RID_SWITCH,     0 },
-  { "typedef",         RID_TYPEDEF,    0 },
-  { "typeof",          RID_TYPEOF,     D_EXT },
-  { "union",           RID_UNION,      0 },
-  { "unsigned",                RID_UNSIGNED,   0 },
-  { "void",            RID_VOID,       0 },
-  { "volatile",                RID_VOLATILE,   0 },
-  { "while",           RID_WHILE,      0 },
-
-@@ifobjc
-
-  /* These objc keywords are recognized only immediately after
-     an '@'.  */
-  { "class",           RID_AT_CLASS,           D_OBJC },
-  { "compatibility_alias", RID_AT_ALIAS,       D_OBJC },
-  { "defs",            RID_AT_DEFS,            D_OBJC },
-  { "encode",          RID_AT_ENCODE,          D_OBJC },
-  { "end",             RID_AT_END,             D_OBJC },
-  { "implementation",  RID_AT_IMPLEMENTATION,  D_OBJC },
-  { "interface",       RID_AT_INTERFACE,       D_OBJC },
-  { "private",         RID_AT_PRIVATE,         D_OBJC },
-  { "protected",       RID_AT_PROTECTED,       D_OBJC },
-  { "protocol",                RID_AT_PROTOCOL,        D_OBJC },
-  { "public",          RID_AT_PUBLIC,          D_OBJC },
-  { "selector",                RID_AT_SELECTOR,        D_OBJC },
-  { "throw",           RID_AT_THROW,           D_OBJC },
-  { "try",             RID_AT_TRY,             D_OBJC },
-  { "catch",           RID_AT_CATCH,           D_OBJC },
-  { "finally",         RID_AT_FINALLY,         D_OBJC },
-  { "synchronized",    RID_AT_SYNCHRONIZED,    D_OBJC },
-  /* These are recognized only in protocol-qualifier context
-     (see above) */
-  { "bycopy",          RID_BYCOPY,             D_OBJC },
-  { "byref",           RID_BYREF,              D_OBJC },
-  { "in",              RID_IN,                 D_OBJC },
-  { "inout",           RID_INOUT,              D_OBJC },
-  { "oneway",          RID_ONEWAY,             D_OBJC },
-  { "out",             RID_OUT,                D_OBJC },
-@@end_ifobjc
-};
-#define N_reswords (sizeof reswords / sizeof (struct resword))
-
-/* Table mapping from RID_* constants to yacc token numbers.
-   Unfortunately we have to have entries for all the keywords in all
-   three languages.  */
-static const short rid_to_yy[RID_MAX] =
-{
-  /* RID_STATIC */     STATIC,
-  /* RID_UNSIGNED */   TYPESPEC,
-  /* RID_LONG */       TYPESPEC,
-  /* RID_CONST */      TYPE_QUAL,
-  /* RID_EXTERN */     SCSPEC,
-  /* RID_REGISTER */   SCSPEC,
-  /* RID_TYPEDEF */    SCSPEC,
-  /* RID_SHORT */      TYPESPEC,
-  /* RID_INLINE */     SCSPEC,
-  /* RID_VOLATILE */   TYPE_QUAL,
-  /* RID_SIGNED */     TYPESPEC,
-  /* RID_AUTO */       SCSPEC,
-  /* RID_RESTRICT */   TYPE_QUAL,
-
-  /* C extensions */
-  /* RID_COMPLEX */    TYPESPEC,
-  /* RID_THREAD */     SCSPEC,
-
-  /* C++ */
-  /* RID_FRIEND */     0,
-  /* RID_VIRTUAL */    0,
-  /* RID_EXPLICIT */   0,
-  /* RID_EXPORT */     0,
-  /* RID_MUTABLE */    0,
-
-  /* ObjC */
-  /* 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,
-  /* RID_CHAR */       TYPESPEC,
-  /* RID_FLOAT */      TYPESPEC,
-  /* RID_DOUBLE */     TYPESPEC,
-  /* RID_VOID */       TYPESPEC,
-  /* RID_ENUM */       ENUM,
-  /* RID_STRUCT */     STRUCT,
-  /* RID_UNION */      UNION,
-  /* RID_IF */         IF,
-  /* RID_ELSE */       ELSE,
-  /* RID_WHILE */      WHILE,
-  /* RID_DO */         DO,
-  /* RID_FOR */                FOR,
-  /* RID_SWITCH */     SWITCH,
-  /* RID_CASE */       CASE,
-  /* RID_DEFAULT */    DEFAULT,
-  /* RID_BREAK */      BREAK,
-  /* RID_CONTINUE */   CONTINUE,
-  /* RID_RETURN */     RETURN,
-  /* RID_GOTO */       GOTO,
-  /* RID_SIZEOF */     SIZEOF,
-
-  /* C extensions */
-  /* RID_ASM */                ASM_KEYWORD,
-  /* RID_TYPEOF */     TYPEOF,
-  /* RID_ALIGNOF */    ALIGNOF,
-  /* RID_ATTRIBUTE */  ATTRIBUTE,
-  /* RID_VA_ARG */     VA_ARG,
-  /* RID_EXTENSION */  EXTENSION,
-  /* RID_IMAGPART */   IMAGPART,
-  /* RID_REALPART */   REALPART,
-  /* RID_LABEL */      LABEL,
-
-  /* RID_CHOOSE_EXPR */                        CHOOSE_EXPR,
-  /* RID_TYPES_COMPATIBLE_P */         TYPES_COMPATIBLE_P,
-
-  /* RID_FUNCTION_NAME */              FUNC_NAME,
-  /* RID_PRETTY_FUNCTION_NAME */       FUNC_NAME,
-  /* RID_C99_FUNCTION_NAME */          FUNC_NAME,
-
-  /* C++ */
-  /* RID_BOOL */       TYPESPEC,
-  /* RID_WCHAR */      0,
-  /* RID_CLASS */      0,
-  /* RID_PUBLIC */     0,
-  /* RID_PRIVATE */    0,
-  /* RID_PROTECTED */  0,
-  /* RID_TEMPLATE */   0,
-  /* RID_NULL */       0,
-  /* RID_CATCH */      0,
-  /* RID_DELETE */     0,
-  /* RID_FALSE */      0,
-  /* RID_NAMESPACE */  0,
-  /* RID_NEW */                0,
-  /* RID_OFFSETOF */    OFFSETOF,
-  /* RID_OPERATOR */   0,
-  /* RID_THIS */       0,
-  /* RID_THROW */      0,
-  /* RID_TRUE */       0,
-  /* RID_TRY */                0,
-  /* RID_TYPENAME */   0,
-  /* RID_TYPEID */     0,
-  /* RID_USING */      0,
-
-  /* casts */
-  /* RID_CONSTCAST */  0,
-  /* RID_DYNCAST */    0,
-  /* RID_REINTCAST */  0,
-  /* RID_STATCAST */   0,
-
-  /* Objective C */
-  /* 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 */       AT_INTERFACE,
-  /* RID_AT_IMPLEMENTATION */  AT_IMPLEMENTATION
-};
-
-static void
-init_reswords (void)
-{
-  unsigned int i;
-  tree id;
-  int mask = (flag_isoc99 ? 0 : D_C89)
-             | (flag_no_asm ? (flag_isoc99 ? D_EXT : D_EXT|D_EXT89) : 0);
-
-  if (!c_dialect_objc ())
-     mask |= D_OBJC;
-
-  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
-        and so create a canonical spelling that isn't a keyword.  */
-      if (reswords[i].disable & mask)
-       continue;
-
-      id = get_identifier (reswords[i].word);
-      C_RID_CODE (id) = reswords[i].rid;
-      C_IS_RESERVED_WORD (id) = 1;
-      ridpointers [(int) reswords[i].rid] = id;
-    }
-}
-
-#define NAME(type) cpp_type2name (type)
-
-static void
-yyerror (const char *msgid)
-{
-  c_parse_error (msgid, last_token, yylval.ttype);
-}
-
-static int
-yylexname (void)
-{
-  tree decl;
-
-@@ifobjc
-  int objc_force_identifier = objc_need_raw_identifier;
-  OBJC_NEED_RAW_IDENTIFIER (0);
-@@end_ifobjc
-
-  if (C_IS_RESERVED_WORD (yylval.ttype))
-    {
-      enum rid rid_code = C_RID_CODE (yylval.ttype);
-
-@@ifobjc
-      if (!OBJC_IS_AT_KEYWORD (rid_code)
-         && (!OBJC_IS_PQ_KEYWORD (rid_code) || objc_pq_context))
-@@end_ifobjc
-      {
-       /* Return the canonical spelling for this keyword.  */
-       yylval.ttype = ridpointers[(int) rid_code];
-       return rid_to_yy[(int) rid_code];
-      }
-    }
-
-  decl = lookup_name (yylval.ttype);
-  if (decl)
-    {
-      if (TREE_CODE (decl) == TYPE_DECL)
-       return TYPENAME;
-    }
-@@ifobjc
-  else
-    {
-      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
-         && (global_bindings_p ()
-             || (!objc_force_identifier && !decl)))
-       {
-         yylval.ttype = objc_interface_decl;
-         return CLASSNAME;
-       }
-    }
-@@end_ifobjc
-
-  return IDENTIFIER;
-}
-
-static inline int
-_yylex (void)
-{
- get_next:
-  last_token = c_lex (&yylval.ttype);
-  switch (last_token)
-    {
-    case CPP_EQ:                                       return '=';
-    case CPP_NOT:                                      return '!';
-    case CPP_GREATER:  yylval.code = GT_EXPR;          return ARITHCOMPARE;
-    case CPP_LESS:     yylval.code = LT_EXPR;          return ARITHCOMPARE;
-    case CPP_PLUS:     yylval.code = PLUS_EXPR;        return '+';
-    case CPP_MINUS:    yylval.code = MINUS_EXPR;       return '-';
-    case CPP_MULT:     yylval.code = MULT_EXPR;        return '*';
-    case CPP_DIV:      yylval.code = TRUNC_DIV_EXPR;   return '/';
-    case CPP_MOD:      yylval.code = TRUNC_MOD_EXPR;   return '%';
-    case CPP_AND:      yylval.code = BIT_AND_EXPR;     return '&';
-    case CPP_OR:       yylval.code = BIT_IOR_EXPR;     return '|';
-    case CPP_XOR:      yylval.code = BIT_XOR_EXPR;     return '^';
-    case CPP_RSHIFT:   yylval.code = RSHIFT_EXPR;      return RSHIFT;
-    case CPP_LSHIFT:   yylval.code = LSHIFT_EXPR;      return LSHIFT;
-
-    case CPP_COMPL:                                    return '~';
-    case CPP_AND_AND:                                  return ANDAND;
-    case CPP_OR_OR:                                    return OROR;
-    case CPP_QUERY:                                    return '?';
-    case CPP_OPEN_PAREN:                               return '(';
-    case CPP_EQ_EQ:    yylval.code = EQ_EXPR;          return EQCOMPARE;
-    case CPP_NOT_EQ:   yylval.code = NE_EXPR;          return EQCOMPARE;
-    case CPP_GREATER_EQ:yylval.code = GE_EXPR;         return ARITHCOMPARE;
-    case CPP_LESS_EQ:  yylval.code = LE_EXPR;          return ARITHCOMPARE;
-
-    case CPP_PLUS_EQ:  yylval.code = PLUS_EXPR;        return ASSIGN;
-    case CPP_MINUS_EQ: yylval.code = MINUS_EXPR;       return ASSIGN;
-    case CPP_MULT_EQ:  yylval.code = MULT_EXPR;        return ASSIGN;
-    case CPP_DIV_EQ:   yylval.code = TRUNC_DIV_EXPR;   return ASSIGN;
-    case CPP_MOD_EQ:   yylval.code = TRUNC_MOD_EXPR;   return ASSIGN;
-    case CPP_AND_EQ:   yylval.code = BIT_AND_EXPR;     return ASSIGN;
-    case CPP_OR_EQ:    yylval.code = BIT_IOR_EXPR;     return ASSIGN;
-    case CPP_XOR_EQ:   yylval.code = BIT_XOR_EXPR;     return ASSIGN;
-    case CPP_RSHIFT_EQ:        yylval.code = RSHIFT_EXPR;      return ASSIGN;
-    case CPP_LSHIFT_EQ:        yylval.code = LSHIFT_EXPR;      return ASSIGN;
-
-    case CPP_OPEN_SQUARE:                              return '[';
-    case CPP_CLOSE_SQUARE:                             return ']';
-    case CPP_OPEN_BRACE:                               return '{';
-    case CPP_CLOSE_BRACE:                              return '}';
-    case CPP_ELLIPSIS:                                 return ELLIPSIS;
-
-    case CPP_PLUS_PLUS:                                        return PLUSPLUS;
-    case CPP_MINUS_MINUS:                              return MINUSMINUS;
-    case CPP_DEREF:                                    return POINTSAT;
-    case CPP_DOT:                                      return '.';
-
-      /* The following tokens may affect the interpretation of any
-        identifiers following, if doing Objective-C.  */
-    case CPP_COLON:            OBJC_NEED_RAW_IDENTIFIER (0);   return ':';
-    case CPP_COMMA:            OBJC_NEED_RAW_IDENTIFIER (0);   return ',';
-    case CPP_CLOSE_PAREN:      OBJC_NEED_RAW_IDENTIFIER (0);   return ')';
-    case CPP_SEMICOLON:                OBJC_NEED_RAW_IDENTIFIER (0);   return ';';
-
-    case CPP_EOF:
-      return 0;
-
-    case CPP_NAME:
-      return yylexname ();
-
-    case CPP_AT_NAME:
-      /* This only happens in Objective-C; it must be a keyword.  */
-      return rid_to_yy [(int) C_RID_CODE (yylval.ttype)];
-
-    case CPP_NUMBER:
-    case CPP_CHAR:
-    case CPP_WCHAR:
-      return CONSTANT;
-
-    case CPP_STRING:
-    case CPP_WSTRING:
-      return STRING;
-
-    case CPP_OBJC_STRING:
-      return OBJC_STRING;
-
-      /* These tokens are C++ specific (and will not be generated
-         in C mode, but let's be cautious).  */
-    case CPP_SCOPE:
-    case CPP_DEREF_STAR:
-    case CPP_DOT_STAR:
-    case CPP_MIN_EQ:
-    case CPP_MAX_EQ:
-    case CPP_MIN:
-    case CPP_MAX:
-      /* These tokens should not survive translation phase 4.  */
-    case CPP_HASH:
-    case CPP_PASTE:
-      error ("syntax error at %qs token", NAME(last_token));
-      goto get_next;
-
-    default:
-      abort ();
-    }
-  /* NOTREACHED */
-}
-
-static int
-yylex (void)
-{
-  int r;
-  timevar_push (TV_LEX);
-  r = _yylex();
-  timevar_pop (TV_LEX);
-  return r;
-}
-
-/* Function used when yydebug is set, to print a token in more detail.  */
-
-static void
-yyprint (FILE *file, int yychar, YYSTYPE yyl)
-{
-  tree t = yyl.ttype;
-
-  fprintf (file, " [%s]", NAME(last_token));
-
-  switch (yychar)
-    {
-    case IDENTIFIER:
-    case TYPENAME:
-    case TYPESPEC:
-    case TYPE_QUAL:
-    case SCSPEC:
-    case STATIC:
-      if (IDENTIFIER_POINTER (t))
-       fprintf (file, " '%s'", IDENTIFIER_POINTER (t));
-      break;
-
-    case CONSTANT:
-      fprintf (file, " %s", GET_MODE_NAME (TYPE_MODE (TREE_TYPE (t))));
-      if (TREE_CODE (t) == INTEGER_CST)
-       {
-         fputs (" ", file);
-         fprintf (file, HOST_WIDE_INT_PRINT_DOUBLE_HEX,
-                  TREE_INT_CST_HIGH (t), TREE_INT_CST_LOW (t));
-       }
-      break;
-    }
-}
-\f
-/* 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 ();
-
-  if (malloced_yyss)
-    {
-      free (malloced_yyss);
-      free (malloced_yyvs);
-      malloced_yyss = 0;
-    }
-}
-
-#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"
diff --git a/gcc/c-parser.c b/gcc/c-parser.c
new file mode 100644 (file)
index 0000000..adebfd2
--- /dev/null
@@ -0,0 +1,6219 @@
+/* Parser for C and Objective-C.
+   Copyright (C) 1987, 1988, 1989, 1992, 1993, 1994, 1995, 1996, 1997, 1998,
+   1999, 2000, 2001, 2002, 2003, 2004, 2005 Free Software Foundation, Inc.
+
+   Parser actions based on the old Bison parser; structure somewhat
+   influenced by and fragments based on the C++ parser.
+
+This file is part of GCC.
+
+GCC is free software; you can redistribute it and/or modify it under
+the terms of the GNU General Public License as published by the Free
+Software Foundation; either version 2, or (at your option) any later
+version.
+
+GCC is distributed in the hope that it will be useful, but WITHOUT ANY
+WARRANTY; without even the implied warranty of MERCHANTABILITY or
+FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received a copy of the GNU General Public License
+along with GCC; see the file COPYING.  If not, write to the Free
+Software Foundation, 59 Temple Place - Suite 330, Boston, MA
+02111-1307, USA.  */
+
+/* TODO:
+
+   Make sure all relevant comments, and all relevant code from all
+   actions, brought over from old parser.  Verify exact correspondence
+   of syntax accepted.
+
+   Add testcases covering every input symbol in every state in old and
+   new parsers.
+
+   Include full syntax for GNU C, including erroneous cases accepted
+   with error messages, in syntax productions in comments.
+
+   Make more diagnostics in the front end generally take an explicit
+   location rather than implicitly using input_location.  */
+
+#include "config.h"
+#include "system.h"
+#include "coretypes.h"
+#include "tm.h"
+#include "tree.h"
+#include "langhooks.h"
+#include "input.h"
+#include "cpplib.h"
+#include "timevar.h"
+#include "c-pragma.h"
+#include "c-tree.h"
+#include "flags.h"
+#include "output.h"
+#include "toplev.h"
+#include "ggc.h"
+#include "c-common.h"
+
+\f
+/* Miscellaneous data and functions needed for the parser.  */
+
+int yydebug;
+
+/* Objective-C specific parser/lexer information.  */
+
+static int objc_pq_context = 0;
+
+/* The following flag is needed to contextualize Objective-C lexical
+   analysis.  In some cases (e.g., 'int NSObject;'), it is undesirable
+   to bind an identifier to an Objective-C class, even if a class with
+   that name exists.  */
+static int objc_need_raw_identifier = 0;
+#define OBJC_NEED_RAW_IDENTIFIER(VAL)          \
+  do {                                         \
+    if (c_dialect_objc ())                     \
+      objc_need_raw_identifier = VAL;          \
+  } while (0)
+
+/* The reserved keyword table.  */
+struct resword
+{
+  const char *word;
+  ENUM_BITFIELD(rid) rid : 16;
+  unsigned int disable   : 16;
+};
+
+/* Disable mask.  Keywords are disabled if (reswords[i].disable &
+   mask) is _true_.  */
+#define D_C89  0x01    /* not in C89 */
+#define D_EXT  0x02    /* GCC extension */
+#define D_EXT89        0x04    /* GCC extension incorporated in C99 */
+#define D_OBJC 0x08    /* Objective C only */
+
+static const struct resword reswords[] =
+{
+  { "_Bool",           RID_BOOL,       0 },
+  { "_Complex",                RID_COMPLEX,    0 },
+  { "__FUNCTION__",    RID_FUNCTION_NAME, 0 },
+  { "__PRETTY_FUNCTION__", RID_PRETTY_FUNCTION_NAME, 0 },
+  { "__alignof",       RID_ALIGNOF,    0 },
+  { "__alignof__",     RID_ALIGNOF,    0 },
+  { "__asm",           RID_ASM,        0 },
+  { "__asm__",         RID_ASM,        0 },
+  { "__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 },
+  { "__complex__",     RID_COMPLEX,    0 },
+  { "__const",         RID_CONST,      0 },
+  { "__const__",       RID_CONST,      0 },
+  { "__extension__",   RID_EXTENSION,  0 },
+  { "__func__",                RID_C99_FUNCTION_NAME, 0 },
+  { "__imag",          RID_IMAGPART,   0 },
+  { "__imag__",                RID_IMAGPART,   0 },
+  { "__inline",                RID_INLINE,     0 },
+  { "__inline__",      RID_INLINE,     0 },
+  { "__label__",       RID_LABEL,      0 },
+  { "__real",          RID_REALPART,   0 },
+  { "__real__",                RID_REALPART,   0 },
+  { "__restrict",      RID_RESTRICT,   0 },
+  { "__restrict__",    RID_RESTRICT,   0 },
+  { "__signed",                RID_SIGNED,     0 },
+  { "__signed__",      RID_SIGNED,     0 },
+  { "__thread",                RID_THREAD,     0 },
+  { "__typeof",                RID_TYPEOF,     0 },
+  { "__typeof__",      RID_TYPEOF,     0 },
+  { "__volatile",      RID_VOLATILE,   0 },
+  { "__volatile__",    RID_VOLATILE,   0 },
+  { "asm",             RID_ASM,        D_EXT },
+  { "auto",            RID_AUTO,       0 },
+  { "break",           RID_BREAK,      0 },
+  { "case",            RID_CASE,       0 },
+  { "char",            RID_CHAR,       0 },
+  { "const",           RID_CONST,      0 },
+  { "continue",                RID_CONTINUE,   0 },
+  { "default",         RID_DEFAULT,    0 },
+  { "do",              RID_DO,         0 },
+  { "double",          RID_DOUBLE,     0 },
+  { "else",            RID_ELSE,       0 },
+  { "enum",            RID_ENUM,       0 },
+  { "extern",          RID_EXTERN,     0 },
+  { "float",           RID_FLOAT,      0 },
+  { "for",             RID_FOR,        0 },
+  { "goto",            RID_GOTO,       0 },
+  { "if",              RID_IF,         0 },
+  { "inline",          RID_INLINE,     D_EXT89 },
+  { "int",             RID_INT,        0 },
+  { "long",            RID_LONG,       0 },
+  { "register",                RID_REGISTER,   0 },
+  { "restrict",                RID_RESTRICT,   D_C89 },
+  { "return",          RID_RETURN,     0 },
+  { "short",           RID_SHORT,      0 },
+  { "signed",          RID_SIGNED,     0 },
+  { "sizeof",          RID_SIZEOF,     0 },
+  { "static",          RID_STATIC,     0 },
+  { "struct",          RID_STRUCT,     0 },
+  { "switch",          RID_SWITCH,     0 },
+  { "typedef",         RID_TYPEDEF,    0 },
+  { "typeof",          RID_TYPEOF,     D_EXT },
+  { "union",           RID_UNION,      0 },
+  { "unsigned",                RID_UNSIGNED,   0 },
+  { "void",            RID_VOID,       0 },
+  { "volatile",                RID_VOLATILE,   0 },
+  { "while",           RID_WHILE,      0 },
+  /* These Objective-C keywords are recognized only immediately after
+     an '@'.  */
+  { "class",           RID_AT_CLASS,           D_OBJC },
+  { "compatibility_alias", RID_AT_ALIAS,       D_OBJC },
+  { "defs",            RID_AT_DEFS,            D_OBJC },
+  { "encode",          RID_AT_ENCODE,          D_OBJC },
+  { "end",             RID_AT_END,             D_OBJC },
+  { "implementation",  RID_AT_IMPLEMENTATION,  D_OBJC },
+  { "interface",       RID_AT_INTERFACE,       D_OBJC },
+  { "private",         RID_AT_PRIVATE,         D_OBJC },
+  { "protected",       RID_AT_PROTECTED,       D_OBJC },
+  { "protocol",                RID_AT_PROTOCOL,        D_OBJC },
+  { "public",          RID_AT_PUBLIC,          D_OBJC },
+  { "selector",                RID_AT_SELECTOR,        D_OBJC },
+  { "throw",           RID_AT_THROW,           D_OBJC },
+  { "try",             RID_AT_TRY,             D_OBJC },
+  { "catch",           RID_AT_CATCH,           D_OBJC },
+  { "finally",         RID_AT_FINALLY,         D_OBJC },
+  { "synchronized",    RID_AT_SYNCHRONIZED,    D_OBJC },
+  /* These are recognized only in protocol-qualifier context
+     (see above) */
+  { "bycopy",          RID_BYCOPY,             D_OBJC },
+  { "byref",           RID_BYREF,              D_OBJC },
+  { "in",              RID_IN,                 D_OBJC },
+  { "inout",           RID_INOUT,              D_OBJC },
+  { "oneway",          RID_ONEWAY,             D_OBJC },
+  { "out",             RID_OUT,                D_OBJC },
+};
+#define N_reswords (sizeof reswords / sizeof (struct resword))
+
+/* Initialization routine for this file.  */
+
+void
+c_parse_init (void)
+{
+  /* The only initialization required is of the reserved word
+     identifiers.  */
+  unsigned int i;
+  tree id;
+  int mask = (flag_isoc99 ? 0 : D_C89)
+             | (flag_no_asm ? (flag_isoc99 ? D_EXT : D_EXT|D_EXT89) : 0);
+
+  if (!c_dialect_objc ())
+     mask |= D_OBJC;
+
+  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
+        and so create a canonical spelling that isn't a keyword.  */
+      if (reswords[i].disable & mask)
+       continue;
+
+      id = get_identifier (reswords[i].word);
+      C_RID_CODE (id) = reswords[i].rid;
+      C_IS_RESERVED_WORD (id) = 1;
+      ridpointers [(int) reswords[i].rid] = id;
+    }
+}
+\f
+/* The C lexer intermediates between the lexer in cpplib and c-lex.c
+   and the C parser.  Unlike the C++ lexer, the parser structure
+   stores the lexer information instead of using a separate structure.
+   Identifiers are separated into ordinary identifiers, type names,
+   keywords and some other Objective-C types of identifiers, and some
+   look-ahead is maintained.
+
+   ??? It might be a good idea to lex the whole file up front (as for
+   C++).  It would then be possible to share more of the C and C++
+   lexer code, if desired.  */
+
+/* The following local token type is used.  */
+
+/* A keyword.  */
+#define CPP_KEYWORD ((enum cpp_ttype) (N_TTYPES + 1))
+
+/* The number of token types, including C-specific ones.  */
+#define N_C_TTYPES ((int) (CPP_KEYWORD + 1))
+
+/* More information about the type of a CPP_NAME token.  */
+typedef enum c_id_kind {
+  /* An ordinary identifier.  */
+  C_ID_ID,
+  /* An identifier declared as a typedef name.  */
+  C_ID_TYPENAME,
+  /* An identifier declared as an Objective-C class name.  */
+  C_ID_CLASSNAME,
+  /* Not an identifier.  */
+  C_ID_NONE
+} c_id_kind;
+
+/* A single C token after string literal concatenation and conversion
+   of preprocessing tokens to tokens.  */
+typedef struct c_token GTY (())
+{
+  /* The kind of token.  */
+  ENUM_BITFIELD (cpp_ttype) type : 8;
+  /* If this token is a CPP_NAME, this value indicates whether also
+     declared as some kind of type.  Otherwise, it is C_ID_NONE.  */
+  ENUM_BITFIELD (c_id_kind) id_kind : 8;
+  /* If this token is a keyword, this value indicates which keyword.
+     Otherwise, this value is RID_MAX.  */
+  ENUM_BITFIELD (rid) keyword : 8;
+  /* True if this token is from a system header.  */
+  BOOL_BITFIELD in_system_header : 1;
+  /* The value associated with this token, if any.  */
+  tree value;
+  /* The location at which this token was found.  */
+  location_t location;
+} c_token;
+
+/* A parser structure recording information about the state and
+   context of parsing.  Includes lexer information with up to two
+   tokens of look-ahead; more are not needed for C.  */
+typedef struct c_parser GTY(())
+{
+  /* The look-ahead tokens.  */
+  c_token tokens[2];
+  /* How many look-ahead tokens are available (0, 1 or 2).  */
+  short tokens_avail;
+  /* True if a syntax error is being recovered from; false otherwise.
+     c_parser_error sets this flag.  It should clear this flag when
+     enough tokens have been consumed to recover from the error.  */
+  BOOL_BITFIELD error : 1;
+} c_parser;
+
+/* Read in and lex a single token, storing it in *TOKEN.  */
+
+static void
+c_lex_one_token (c_token *token)
+{
+  timevar_push (TV_LEX);
+  token->type = c_lex (&token->value);
+  token->location = input_location;
+  token->in_system_header = in_system_header;
+  switch (token->type)
+    {
+    case CPP_NAME:
+      token->id_kind = C_ID_NONE;
+      token->keyword = RID_MAX;
+      {
+       tree decl;
+
+       int objc_force_identifier = objc_need_raw_identifier;
+       OBJC_NEED_RAW_IDENTIFIER (0);
+
+       if (C_IS_RESERVED_WORD (token->value))
+         {
+           enum rid rid_code = C_RID_CODE (token->value);
+
+           if (c_dialect_objc ())
+             {
+               if (!OBJC_IS_AT_KEYWORD (rid_code)
+                   && (!OBJC_IS_PQ_KEYWORD (rid_code) || objc_pq_context))
+                 {
+                   /* Return the canonical spelling for this keyword.  */
+                   token->value = ridpointers[(int) rid_code];
+                   token->type = CPP_KEYWORD;
+                   token->keyword = rid_code;
+                   break;
+                 }
+             }
+           else
+             {
+               /* Return the canonical spelling for this keyword.  */
+               token->value = ridpointers[(int) rid_code];
+               token->type = CPP_KEYWORD;
+               token->keyword = rid_code;
+               break;
+             }
+         }
+
+       decl = lookup_name (token->value);
+       if (decl)
+         {
+           if (TREE_CODE (decl) == TYPE_DECL)
+             {
+               token->id_kind = C_ID_TYPENAME;
+               break;
+             }
+         }
+       else if (c_dialect_objc ())
+         {
+           tree objc_interface_decl = objc_is_class_name (token->value);
+           /* Objective-C class names are in the same namespace as
+              variables and typedefs, and hence are shadowed by local
+              declarations.  */
+           if (objc_interface_decl
+               && (global_bindings_p ()
+                   || (!objc_force_identifier && !decl)))
+             {
+               token->value = objc_interface_decl;
+               token->id_kind = C_ID_CLASSNAME;
+               break;
+             }
+         }
+      }
+      token->id_kind = C_ID_ID;
+      break;
+    case CPP_AT_NAME:
+      /* This only happens in Objective-C; it must be a keyword.  */
+      token->type = CPP_KEYWORD;
+      token->id_kind = C_ID_NONE;
+      token->keyword = C_RID_CODE (token->value);
+      break;
+    case CPP_COLON:
+    case CPP_COMMA:
+    case CPP_CLOSE_PAREN:
+    case CPP_SEMICOLON:
+      /* These tokens may affect the interpretation of any identifiers
+        following, if doing Objective-C.  */
+      OBJC_NEED_RAW_IDENTIFIER (0);
+      token->id_kind = C_ID_NONE;
+      token->keyword = RID_MAX;
+      break;
+    default:
+      token->id_kind = C_ID_NONE;
+      token->keyword = RID_MAX;
+      break;
+    }
+  timevar_pop (TV_LEX);
+}
+
+/* Return a pointer to the next token from PARSER, reading it in if
+   necessary.  */
+
+static inline c_token *
+c_parser_peek_token (c_parser *parser)
+{
+  if (parser->tokens_avail == 0)
+    {
+      c_lex_one_token (&parser->tokens[0]);
+      parser->tokens_avail = 1;
+    }
+  return &parser->tokens[0];
+}
+
+/* Return true if the next token from PARSER has the indicated
+   TYPE.  */
+
+static inline bool
+c_parser_next_token_is (c_parser *parser, enum cpp_ttype type)
+{
+  return c_parser_peek_token (parser)->type == type;
+}
+
+/* Return true if the next token from PARSER does not have the
+   indicated TYPE.  */
+
+static inline bool
+c_parser_next_token_is_not (c_parser *parser, enum cpp_ttype type)
+{
+  return !c_parser_next_token_is (parser, type);
+}
+
+/* Return true if the next token from PARSER is the indicated
+   KEYWORD.  */
+
+static inline bool
+c_parser_next_token_is_keyword (c_parser *parser, enum rid keyword)
+{
+  c_token *token;
+
+  /* Peek at the next token.  */
+  token = c_parser_peek_token (parser);
+  /* Check to see if it is the indicated keyword.  */
+  return token->keyword == keyword;
+}
+
+/* Return true if TOKEN can start a type name,
+   false otherwise.  */
+static bool
+c_token_starts_typename (c_token *token)
+{
+  switch (token->type)
+    {
+    case CPP_NAME:
+      switch (token->id_kind)
+       {
+       case C_ID_ID:
+         return false;
+       case C_ID_TYPENAME:
+         return true;
+       case C_ID_CLASSNAME:
+         gcc_assert (c_dialect_objc ());
+         return true;
+       default:
+         gcc_unreachable ();
+       }
+    case CPP_KEYWORD:
+      switch (token->keyword)
+       {
+       case RID_UNSIGNED:
+       case RID_LONG:
+       case RID_SHORT:
+       case RID_SIGNED:
+       case RID_COMPLEX:
+       case RID_INT:
+       case RID_CHAR:
+       case RID_FLOAT:
+       case RID_DOUBLE:
+       case RID_VOID:
+       case RID_BOOL:
+       case RID_ENUM:
+       case RID_STRUCT:
+       case RID_UNION:
+       case RID_TYPEOF:
+       case RID_CONST:
+       case RID_VOLATILE:
+       case RID_RESTRICT:
+       case RID_ATTRIBUTE:
+         return true;
+       default:
+         return false;
+       }
+    case CPP_LESS:
+      if (c_dialect_objc ())
+       return true;
+      return false;
+    default:
+      return false;
+    }
+}
+
+/* Return true if the next token from PARSER can start a type name,
+   false otherwise.  */
+static inline bool
+c_parser_next_token_starts_typename (c_parser *parser)
+{
+  c_token *token = c_parser_peek_token (parser);
+  return c_token_starts_typename (token);
+}
+
+/* Return true if TOKEN can start declaration specifiers, false
+   otherwise.  */
+static bool
+c_token_starts_declspecs (c_token *token)
+{
+  switch (token->type)
+    {
+    case CPP_NAME:
+      switch (token->id_kind)
+       {
+       case C_ID_ID:
+         return false;
+       case C_ID_TYPENAME:
+         return true;
+       case C_ID_CLASSNAME:
+         gcc_assert (c_dialect_objc ());
+         return true;
+       default:
+         gcc_unreachable ();
+       }
+    case CPP_KEYWORD:
+      switch (token->keyword)
+       {
+       case RID_STATIC:
+       case RID_EXTERN:
+       case RID_REGISTER:
+       case RID_TYPEDEF:
+       case RID_INLINE:
+       case RID_AUTO:
+       case RID_THREAD:
+       case RID_UNSIGNED:
+       case RID_LONG:
+       case RID_SHORT:
+       case RID_SIGNED:
+       case RID_COMPLEX:
+       case RID_INT:
+       case RID_CHAR:
+       case RID_FLOAT:
+       case RID_DOUBLE:
+       case RID_VOID:
+       case RID_BOOL:
+       case RID_ENUM:
+       case RID_STRUCT:
+       case RID_UNION:
+       case RID_TYPEOF:
+       case RID_CONST:
+       case RID_VOLATILE:
+       case RID_RESTRICT:
+       case RID_ATTRIBUTE:
+         return true;
+       default:
+         return false;
+       }
+    case CPP_LESS:
+      if (c_dialect_objc ())
+       return true;
+      return false;
+    default:
+      return false;
+    }
+}
+
+/* Return true if the next token from PARSER can start declaration
+   specifiers, false otherwise.  */
+static inline bool
+c_parser_next_token_starts_declspecs (c_parser *parser)
+{
+  c_token *token = c_parser_peek_token (parser);
+  return c_token_starts_declspecs (token);
+}
+
+/* Return a pointer to the next-but-one token from PARSER, reading it
+   in if necessary.  The next token is already read in.  */
+
+static c_token *
+c_parser_peek_2nd_token (c_parser *parser)
+{
+  if (parser->tokens_avail >= 2)
+    return &parser->tokens[1];
+  gcc_assert (parser->tokens_avail == 1);
+  gcc_assert (parser->tokens[0].type != CPP_EOF);
+  c_lex_one_token (&parser->tokens[1]);
+  parser->tokens_avail = 2;
+  return &parser->tokens[1];
+}
+
+/* Consume the next token from PARSER.  */
+
+static void
+c_parser_consume_token (c_parser *parser)
+{
+  if (parser->tokens_avail == 2)
+    parser->tokens[0] = parser->tokens[1];
+  else
+    {
+      gcc_assert (parser->tokens_avail == 1);
+      gcc_assert (parser->tokens[0].type != CPP_EOF);
+    }
+  parser->tokens_avail--;
+}
+
+/* Update the globals input_location and in_system_header from
+   TOKEN.  */
+static inline void
+c_parser_set_source_position_from_token (c_token *token)
+{
+  if (token->type != CPP_EOF)
+    {
+      input_location = token->location;
+      in_system_header = token->in_system_header;
+    }
+}
+
+/* Allocate a new parser.  */
+
+static c_parser *
+c_parser_new (void)
+{
+  /* Use local storage to lex the first token because loading a PCH
+     file may cause garbage collection.  */
+  c_parser tparser;
+  c_parser *ret;
+  memset (&tparser, 0, sizeof tparser);
+  c_lex_one_token (&tparser.tokens[0]);
+  tparser.tokens_avail = 1;
+  ret = GGC_NEW (c_parser);
+  memcpy (ret, &tparser, sizeof tparser);
+  return ret;
+}
+
+/* Issue a diagnostic of the form
+      FILE:LINE: MESSAGE before TOKEN
+   where TOKEN is the next token in the input stream of PARSER.
+   MESSAGE (specified by the caller) is usually of the form "expected
+   OTHER-TOKEN".
+
+   Do not issue a diagnostic if still recovering from an error.
+
+   ??? This is taken from the C++ parser, but building up messages in
+   this way is not i18n-friendly and some other approach should be
+   used.  */
+
+static void
+c_parser_error (c_parser *parser, const char *msgid)
+{
+  c_token *token = c_parser_peek_token (parser);
+  if (parser->error)
+    return;
+  parser->error = true;
+  if (!msgid)
+    return;
+  /* This diagnostic makes more sense if it is tagged to the line of
+     the token we just peeked at.  */
+  c_parser_set_source_position_from_token (token);
+  c_parse_error (msgid,
+                /* Because c_parse_error does not understand
+                   CPP_KEYWORD, keywords are treated like
+                   identifiers.  */
+                (token->type == CPP_KEYWORD ? CPP_NAME : token->type),
+                token->value);
+}
+
+/* If the next token is of the indicated TYPE, consume it.  Otherwise,
+   issue the error MSGID.  If MSGID is NULL then a message has already
+   been produced and no message will be produced this time.  Returns
+   true if found, false otherwise.  */
+
+static bool
+c_parser_require (c_parser *parser,
+                 enum cpp_ttype type,
+                 const char *msgid)
+{
+  if (c_parser_next_token_is (parser, type))
+    {
+      c_parser_consume_token (parser);
+      return true;
+    }
+  else
+    {
+      c_parser_error (parser, msgid);
+      return false;
+    }
+}
+
+/* If the next token is the indicated keyword, consume it.  Otherwise,
+   issue the error MSGID.  Returns true if found, false otherwise.  */
+
+static bool
+c_parser_require_keyword (c_parser *parser,
+                         enum rid keyword,
+                         const char *msgid)
+{
+  if (c_parser_next_token_is_keyword (parser, keyword))
+    {
+      c_parser_consume_token (parser);
+      return true;
+    }
+  else
+    {
+      c_parser_error (parser, msgid);
+      return false;
+    }
+}
+
+/* Like c_parser_require, except that tokens will be skipped until the
+   desired token is found.  An error message is still produced if the
+   next token is not as expected.  If MSGID is NULL then a message has
+   already been produced and no message will be produced this
+   time.  */
+
+static void
+c_parser_skip_until_found (c_parser *parser,
+                          enum cpp_ttype type,
+                          const char *msgid)
+{
+  unsigned nesting_depth = 0;
+
+  if (c_parser_require (parser, type, msgid))
+    return;
+
+  /* Skip tokens until the desired token is found.  */
+  while (true)
+    {
+      /* Peek at the next token.  */
+      c_token *token = c_parser_peek_token (parser);
+      /* If we've reached the token we want, consume it and stop.  */
+      if (token->type == type && !nesting_depth)
+       {
+         c_parser_consume_token (parser);
+         break;
+       }
+      /* If we've run out of tokens, stop.  */
+      if (token->type == CPP_EOF)
+       return;
+      if (token->type == CPP_OPEN_BRACE
+         || token->type == CPP_OPEN_PAREN
+         || token->type == CPP_OPEN_SQUARE)
+       ++nesting_depth;
+      else if (token->type == CPP_CLOSE_BRACE
+              || token->type == CPP_CLOSE_PAREN
+              || token->type == CPP_CLOSE_SQUARE)
+       {
+         if (nesting_depth-- == 0)
+           break;
+       }
+      /* Consume this token.  */
+      c_parser_consume_token (parser);
+    }
+  parser->error = false;
+}
+
+/* Skip tokens until the end of a parameter is found, but do not
+   consume the comma, semicolon or closing delimiter.  */
+
+static void
+c_parser_skip_to_end_of_parameter (c_parser *parser)
+{
+  unsigned nesting_depth = 0;
+
+  while (true)
+    {
+      c_token *token = c_parser_peek_token (parser);
+      if ((token->type == CPP_COMMA || token->type == CPP_SEMICOLON)
+         && !nesting_depth)
+       break;
+      /* If we've run out of tokens, stop.  */
+      if (token->type == CPP_EOF)
+       return;
+      if (token->type == CPP_OPEN_BRACE
+         || token->type == CPP_OPEN_PAREN
+         || token->type == CPP_OPEN_SQUARE)
+       ++nesting_depth;
+      else if (token->type == CPP_CLOSE_BRACE
+              || token->type == CPP_CLOSE_PAREN
+              || token->type == CPP_CLOSE_SQUARE)
+       {
+         if (nesting_depth-- == 0)
+           break;
+       }
+      /* Consume this token.  */
+      c_parser_consume_token (parser);
+    }
+  parser->error = false;
+}
+
+/* Skip tokens until we have consumed an entire block, or until we
+   have consumed a non-nested ';'.  */
+
+static void
+c_parser_skip_to_end_of_block_or_statement (c_parser *parser)
+{
+  unsigned nesting_depth = 0;
+
+  while (true)
+    {
+      c_token *token;
+
+      /* Peek at the next token.  */
+      token = c_parser_peek_token (parser);
+      /* If we've run out of tokens, stop.  */
+      if (token->type == CPP_EOF)
+       return;
+      /* If the next token is a ';', we have reached the end of the
+        statement.  */
+      if (token->type == CPP_SEMICOLON && !nesting_depth)
+       {
+         /* Consume the ';'.  */
+         c_parser_consume_token (parser);
+         break;
+       }
+      /* If the next token is a non-nested '}', then we have reached
+        the end of the current block.  */
+      if (token->type == CPP_CLOSE_BRACE
+         && (nesting_depth == 0 || --nesting_depth == 0))
+       {
+         c_parser_consume_token (parser);
+         break;
+       }
+      /* If it the next token is a '{', then we are entering a new
+        block.  Consume the entire block.  */
+      if (token->type == CPP_OPEN_BRACE)
+       ++nesting_depth;
+      c_parser_consume_token (parser);
+    }
+  parser->error = false;
+}
+
+
+/* Save the warning flags which are controlled by __extension__.  */
+
+static inline int
+disable_extension_diagnostics (void)
+{
+  int ret = (pedantic
+            | (warn_pointer_arith << 1)
+            | (warn_traditional << 2)
+            | (flag_iso << 3));
+  pedantic = 0;
+  warn_pointer_arith = 0;
+  warn_traditional = 0;
+  flag_iso = 0;
+  return ret;
+}
+
+/* Restore the warning flags which are controlled by __extension__.
+   FLAGS is the return value from disable_extension_diagnostics.  */
+
+static inline void
+restore_extension_diagnostics (int flags)
+{
+  pedantic = flags & 1;
+  warn_pointer_arith = (flags >> 1) & 1;
+  warn_traditional = (flags >> 2) & 1;
+  flag_iso = (flags >> 3) & 1;
+}
+
+/* Possibly kinds of declarator to parse.  */
+typedef enum c_dtr_syn {
+  /* A normal declarator with an identifier.  */
+  C_DTR_NORMAL,
+  /* An abstract declarator (maybe empty).  */
+  C_DTR_ABSTRACT,
+  /* A parameter declarator: may be either, but after a type name does
+     not redeclare a typedef name as an identifier if it can
+     alternatively be interpreted as a typedef name; see DR#009,
+     applied in C90 TC1, omitted from C99 and reapplied in C99 TC2
+     following DR#249.  For example, given a typedef T, "int T" and
+     "int *T" are valid parameter declarations redeclaring T, while
+     "int (T)" and "int * (T)" and "int (T[])" and "int (T (int))" are
+     abstract declarators rather than involving redundant parentheses;
+     the same applies with attributes inside the parentheses before
+     "T".  */
+  C_DTR_PARM
+} c_dtr_syn;
+
+static void c_parser_external_declaration (c_parser *);
+static void c_parser_asm_definition (c_parser *);
+static void c_parser_declaration_or_fndef (c_parser *, bool, bool, bool, bool);
+static void c_parser_declspecs (c_parser *, struct c_declspecs *, bool, bool,
+                               bool);
+static struct c_typespec c_parser_enum_specifier (c_parser *);
+static struct c_typespec c_parser_struct_or_union_specifier (c_parser *);
+static tree c_parser_struct_declaration (c_parser *);
+static struct c_typespec c_parser_typeof_specifier (c_parser *);
+static struct c_declarator *c_parser_declarator (c_parser *, bool, c_dtr_syn,
+                                                bool *);
+static struct c_declarator *c_parser_direct_declarator (c_parser *, bool,
+                                                       c_dtr_syn, bool *);
+static struct c_declarator *c_parser_direct_declarator_inner (c_parser *,
+                                                             bool,
+                                                             struct c_declarator *);
+static struct c_arg_info *c_parser_parms_declarator (c_parser *, bool, tree);
+static struct c_arg_info *c_parser_parms_list_declarator (c_parser *, tree);
+static struct c_parm *c_parser_parameter_declaration (c_parser *, tree);
+static tree c_parser_simple_asm_expr (c_parser *);
+static tree c_parser_attributes (c_parser *);
+static struct c_type_name *c_parser_type_name (c_parser *);
+static struct c_expr c_parser_initializer (c_parser *);
+static struct c_expr c_parser_braced_init (c_parser *, tree, bool);
+static void c_parser_initelt (c_parser *);
+static void c_parser_initval (c_parser *, struct c_expr *);
+static tree c_parser_compound_statement (c_parser *);
+static void c_parser_compound_statement_nostart (c_parser *);
+static void c_parser_label (c_parser *);
+static void c_parser_statement (c_parser *);
+static void c_parser_statement_after_labels (c_parser *);
+static void c_parser_if_statement (c_parser *);
+static void c_parser_switch_statement (c_parser *);
+static void c_parser_while_statement (c_parser *);
+static void c_parser_do_statement (c_parser *);
+static void c_parser_for_statement (c_parser *);
+static tree c_parser_asm_statement (c_parser *);
+static tree c_parser_asm_operands (c_parser *);
+static tree c_parser_asm_clobbers (c_parser *);
+static struct c_expr c_parser_expr_no_commas (c_parser *, struct c_expr *);
+static struct c_expr c_parser_conditional_expression (c_parser *,
+                                                     struct c_expr *);
+static struct c_expr c_parser_binary_expression (c_parser *, struct c_expr *);
+static struct c_expr c_parser_cast_expression (c_parser *, struct c_expr *);
+static struct c_expr c_parser_unary_expression (c_parser *);
+static struct c_expr c_parser_sizeof_expression (c_parser *);
+static struct c_expr c_parser_alignof_expression (c_parser *);
+static struct c_expr c_parser_postfix_expression (c_parser *);
+static struct c_expr c_parser_postfix_expression_after_paren_type (c_parser *,
+                                                                  struct c_type_name *);
+static struct c_expr c_parser_postfix_expression_after_primary (c_parser *,
+                                                               struct c_expr);
+static struct c_expr c_parser_expression (c_parser *);
+static tree c_parser_expr_list (c_parser *);
+
+/* These Objective-C parser functions are only ever called when
+   compiling Objective-C.  */
+static void c_parser_objc_class_definition (c_parser *);
+static void c_parser_objc_class_instance_variables (c_parser *);
+static void c_parser_objc_class_declaration (c_parser *);
+static void c_parser_objc_alias_declaration (c_parser *);
+static void c_parser_objc_protocol_definition (c_parser *);
+static enum tree_code c_parser_objc_method_type (c_parser *);
+static void c_parser_objc_method_definition (c_parser *);
+static void c_parser_objc_methodprotolist (c_parser *);
+static void c_parser_objc_methodproto (c_parser *);
+static tree c_parser_objc_method_decl (c_parser *);
+static tree c_parser_objc_type_name (c_parser *);
+static tree c_parser_objc_protocol_refs (c_parser *);
+static void c_parser_objc_try_catch_statement (c_parser *);
+static void c_parser_objc_synchronized_statement (c_parser *);
+static tree c_parser_objc_selector (c_parser *);
+static tree c_parser_objc_selector_arg (c_parser *);
+static tree c_parser_objc_receiver (c_parser *);
+static tree c_parser_objc_message_args (c_parser *);
+static tree c_parser_objc_keywordexpr (c_parser *);
+
+/* Parse a translation unit (C90 6.7, C99 6.9).
+
+   translation-unit:
+     external-declarations
+
+   external-declarations:
+     external-declaration
+     external-declarations external-declaration
+
+   GNU extensions:
+
+   translation-unit:
+     empty
+*/
+
+static void
+c_parser_translation_unit (c_parser *parser)
+{
+  if (c_parser_next_token_is (parser, CPP_EOF))
+    {
+      if (pedantic)
+       pedwarn ("ISO C forbids an empty source file");
+    }
+  else
+    {
+      void *obstack_position = obstack_alloc (&parser_obstack, 0);
+      do
+       {
+         ggc_collect ();
+         c_parser_external_declaration (parser);
+         obstack_free (&parser_obstack, obstack_position);
+       }
+      while (c_parser_next_token_is_not (parser, CPP_EOF));
+    }
+}
+
+/* Parse an external declaration (C90 6.7, C99 6.9).
+
+   external-declaration:
+     function-definition
+     declaration
+
+   GNU extensions:
+
+   external-declaration:
+     asm-definition
+     ;
+     __extension__ external-declaration
+
+   Objective-C:
+
+   external-declaration:
+     objc-class-definition
+     objc-class-declaration
+     objc-alias-declaration
+     objc-protocol-definition
+     objc-method-definition
+     @end
+*/
+
+static void
+c_parser_external_declaration (c_parser *parser)
+{
+  int ext;
+  switch (c_parser_peek_token (parser)->type)
+    {
+    case CPP_KEYWORD:
+      switch (c_parser_peek_token (parser)->keyword)
+       {
+       case RID_EXTENSION:
+         ext = disable_extension_diagnostics ();
+         c_parser_consume_token (parser);
+         c_parser_external_declaration (parser);
+         restore_extension_diagnostics (ext);
+         break;
+       case RID_ASM:
+         c_parser_asm_definition (parser);
+         break;
+       case RID_AT_INTERFACE:
+       case RID_AT_IMPLEMENTATION:
+         gcc_assert (c_dialect_objc ());
+         c_parser_objc_class_definition (parser);
+         break;
+       case RID_AT_CLASS:
+         gcc_assert (c_dialect_objc ());
+         c_parser_objc_class_declaration (parser);
+         break;
+       case RID_AT_ALIAS:
+         gcc_assert (c_dialect_objc ());
+         c_parser_objc_alias_declaration (parser);
+         break;
+       case RID_AT_PROTOCOL:
+         gcc_assert (c_dialect_objc ());
+         c_parser_objc_protocol_definition (parser);
+         break;
+       case RID_AT_END:
+         gcc_assert (c_dialect_objc ());
+         c_parser_consume_token (parser);
+         objc_finish_implementation ();
+         break;
+       default:
+         goto decl_or_fndef;
+       }
+      break;
+    case CPP_SEMICOLON:
+      if (pedantic)
+       pedwarn ("ISO C does not allow extra %<;%> outside of a function");
+      c_parser_consume_token (parser);
+      break;
+    case CPP_PLUS:
+    case CPP_MINUS:
+      if (c_dialect_objc ())
+       {
+         c_parser_objc_method_definition (parser);
+         break;
+       }
+      /* Else fall through, and yield a syntax error trying to parse
+        as a declaration or function definition.  */
+    default:
+    decl_or_fndef:
+      /* A declaration or a function definition.  We can only tell
+        which after parsing the declaration specifiers, if any, and
+        the first declarator.  */
+      c_parser_declaration_or_fndef (parser, true, true, false, true);
+      break;
+    }
+}
+
+/* Parse a declaration or function definition (C90 6.5, 6.7.1, C99
+   6.7, 6.9.1).  If FNDEF_OK is true, a function definition is
+   accepted; otherwise (old-style parameter declarations) only other
+   declarations are accepted.  If NESTED is true, we are inside a
+   function or parsing old-style parameter declarations; any functions
+   encountered are nested functions and declaration specifiers are
+   required; otherwise we are at top level and functions are normal
+   functions and declaration specifiers may be optional.  If EMPTY_OK
+   is true, empty declarations are OK (subject to all other
+   constraints); otherwise (old-style parameter declarations) they are
+   diagnosed.  If START_ATTR_OK is true, the declaration specifiers
+   may start with attributes; otherwise they may not.
+
+   declaration:
+     declaration-specifiers init-declarator-list[opt] ;
+
+   function-definition:
+     declaration-specifiers[opt] declarator declaration-list[opt]
+       compound-statement
+
+   declaration-list:
+     declaration
+     declaration-list declaration
+
+   init-declarator-list:
+     init-declarator
+     init-declarator-list , init-declarator
+
+   init-declarator:
+     declarator simple-asm-expr[opt] attributes[opt]
+     declarator simple-asm-expr[opt] attributes[opt] = initializer
+
+   GNU extensions:
+
+   nested-function-definition:
+     declaration-specifiers declarator declaration-list[opt]
+       compound-statement
+
+   The simple-asm-expr and attributes are GNU extensions.
+
+   This function does not handle __extension__; that is handled in its
+   callers.  ??? Following the old parser, __extension__ may start
+   external declarations, declarations in functions and declarations
+   at the start of "for" loops, but not old-style parameter
+   declarations.
+
+   C99 requires declaration specifiers in a function definition; the
+   absence is diagnosed through the diagnosis of implicit int.  In GNU
+   C we also allow but diagnose declarations without declaration
+   specifiers, but only at top level (elsewhere they conflict with
+   other syntax).  */
+
+static void
+c_parser_declaration_or_fndef (c_parser *parser, bool fndef_ok, bool empty_ok,
+                              bool nested, bool start_attr_ok)
+{
+  struct c_declspecs *specs;
+  tree prefix_attrs;
+  tree all_prefix_attrs;
+  bool diagnosed_no_specs = false;
+  specs = build_null_declspecs ();
+  c_parser_declspecs (parser, specs, true, true, start_attr_ok);
+  if (parser->error)
+    {
+      c_parser_skip_to_end_of_block_or_statement (parser);
+      return;
+    }
+  if (nested && !specs->declspecs_seen_p)
+    {
+      c_parser_error (parser, "expected declaration specifiers");
+      c_parser_skip_to_end_of_block_or_statement (parser);
+      return;
+    }
+  finish_declspecs (specs);
+  if (c_parser_next_token_is (parser, CPP_SEMICOLON))
+    {
+      if (empty_ok)
+       shadow_tag (specs);
+      else
+       {
+         shadow_tag_warned (specs, 1);
+         pedwarn ("empty declaration");
+       }
+      c_parser_consume_token (parser);
+      return;
+    }
+  pending_xref_error ();
+  prefix_attrs = specs->attrs;
+  all_prefix_attrs = prefix_attrs;
+  specs->attrs = NULL_TREE;
+  while (true)
+    {
+      struct c_declarator *declarator;
+      bool dummy = false;
+      tree fnbody;
+      /* Declaring either one or more declarators (in which case we
+        should diagnose if there were no declaration specifiers) or a
+        function definition (in which case the diagnostic for
+        implicit int suffices).  */
+      declarator = c_parser_declarator (parser, specs->type_seen_p,
+                                       C_DTR_NORMAL, &dummy);
+      if (declarator == NULL)
+       {
+         c_parser_skip_to_end_of_block_or_statement (parser);
+         return;
+       }
+      if (c_parser_next_token_is (parser, CPP_EQ)
+         || c_parser_next_token_is (parser, CPP_COMMA)
+         || c_parser_next_token_is (parser, CPP_SEMICOLON)
+         || c_parser_next_token_is_keyword (parser, RID_ASM)
+         || c_parser_next_token_is_keyword (parser, RID_ATTRIBUTE))
+       {
+         tree asm_name = NULL_TREE;
+         tree postfix_attrs = NULL_TREE;
+         if (!diagnosed_no_specs && !specs->declspecs_seen_p)
+           {
+             diagnosed_no_specs = true;
+             pedwarn ("data definition has no type or storage class");
+           }
+         /* Having seen a data definition, there cannot now be a
+            function definition.  */
+         fndef_ok = false;
+         if (c_parser_next_token_is_keyword (parser, RID_ASM))
+           asm_name = c_parser_simple_asm_expr (parser);
+         if (c_parser_next_token_is_keyword (parser, RID_ATTRIBUTE))
+           postfix_attrs = c_parser_attributes (parser);
+         if (c_parser_next_token_is (parser, CPP_EQ))
+           {
+             tree d;
+             struct c_expr init;
+             c_parser_consume_token (parser);
+             /* The declaration of the variable is in effect while
+                its initializer is parsed.  */
+             d = start_decl (declarator, specs, true,
+                             chainon (postfix_attrs, all_prefix_attrs));
+             if (!d)
+               d = error_mark_node;
+             start_init (d, asm_name, global_bindings_p ());
+             init = c_parser_initializer (parser);
+             finish_init ();
+             if (d != error_mark_node)
+               {
+                 maybe_warn_string_init (TREE_TYPE (d), init);
+                 finish_decl (d, init.value, asm_name);
+               }
+           }
+         else
+           {
+             tree d = start_decl (declarator, specs, false,
+                                  chainon (postfix_attrs,
+                                           all_prefix_attrs));
+             if (d)
+               finish_decl (d, NULL_TREE, asm_name);
+           }
+         if (c_parser_next_token_is (parser, CPP_COMMA))
+           {
+             c_parser_consume_token (parser);
+             if (c_parser_next_token_is_keyword (parser, RID_ATTRIBUTE))
+               all_prefix_attrs = chainon (c_parser_attributes (parser),
+                                           prefix_attrs);
+             else
+               all_prefix_attrs = prefix_attrs;
+             continue;
+           }
+         else if (c_parser_next_token_is (parser, CPP_SEMICOLON))
+           {
+             c_parser_consume_token (parser);
+             return;
+           }
+         else
+           {
+             c_parser_error (parser, "expected %<,%> or %<;%>");
+             c_parser_skip_to_end_of_block_or_statement (parser);
+             return;
+           }
+       }
+      else if (!fndef_ok)
+       {
+         c_parser_error (parser, "expected %<=%>, %<,%>, %<;%>, "
+                         "%<asm%> or %<__attribute__%>");
+         c_parser_skip_to_end_of_block_or_statement (parser);
+         return;
+       }
+      /* Function definition (nested or otherwise).  */
+      if (nested)
+       {
+         if (pedantic)
+           pedwarn ("ISO C forbids nested functions");
+         push_function_context ();
+       }
+      if (!start_function (specs, declarator, all_prefix_attrs))
+       {
+         /* This can appear in many cases looking nothing like a
+            function definition, so we don't give a more specific
+            error suggesting there was one.  */
+         c_parser_error (parser, "expected %<=%>, %<,%>, %<;%>, %<asm%> "
+                         "or %<__attribute__%>");
+         if (nested)
+           pop_function_context ();
+         break;
+       }
+      /* Parse old-style parameter declarations.  ??? Attributes are
+        not allowed to start declaration specifiers here because of a
+        syntax conflict between a function declaration with attribute
+        suffix and a function definition with an attribute prefix on
+        first old-style parameter declaration.  Following the old
+        parser, they are not accepted on subsequent old-style
+        parameter declarations either.  However, there is no
+        ambiguity after the first declaration, nor indeed on the
+        first as long as we don't allow postfix attributes after a
+        declarator with a nonempty identifier list in a definition;
+        and postfix attributes have never been accepted here in
+        function definitions either.  */
+      while (c_parser_next_token_is_not (parser, CPP_EOF)
+            && c_parser_next_token_is_not (parser, CPP_OPEN_BRACE))
+       c_parser_declaration_or_fndef (parser, false, false, true, false);
+      DECL_SOURCE_LOCATION (current_function_decl)
+       = c_parser_peek_token (parser)->location;
+      store_parm_decls ();
+      fnbody = c_parser_compound_statement (parser);
+      if (nested)
+       {
+         tree decl = current_function_decl;
+         add_stmt (fnbody);
+         finish_function ();
+         pop_function_context ();
+         add_stmt (build_stmt (DECL_EXPR, decl));
+       }
+      else
+       {
+         add_stmt (fnbody);
+         finish_function ();
+       }
+      break;
+    }
+}
+
+/* Parse an asm-definition (asm() outside a function body).  This is a
+   GNU extension.
+
+   asm-definition:
+     simple-asm-expr ;
+*/
+
+static void
+c_parser_asm_definition (c_parser *parser)
+{
+  tree asm_str = c_parser_simple_asm_expr (parser);
+  /* ??? This only works sensibly in the presence of
+     -fno-unit-at-a-time; file-scope asms really need to be passed to
+     cgraph which needs to preserve the order of functions and
+     file-scope asms.  */
+  if (asm_str)
+    assemble_asm (asm_str);
+  c_parser_skip_until_found (parser, CPP_SEMICOLON, "expected %<;%>");
+}
+
+/* Parse some declaration specifiers (possibly none) (C90 6.5, C99
+   6.7), adding them to SPECS (which may already include some).
+   Storage class specifiers are accepted iff SCSPEC_OK; type
+   specifiers are accepted iff TYPESPEC_OK; attributes are accepted at
+   the start iff START_ATTR_OK.
+
+   declaration-specifiers:
+     storage-class-specifier declaration-specifiers[opt]
+     type-specifier declaration-specifiers[opt]
+     type-qualifier declaration-specifiers[opt]
+     function-specifier declaration-specifiers[opt]
+
+   Function specifiers (inline) are from C99, and are currently
+   handled as storage class specifiers, as is __thread.
+
+   C90 6.5.1, C99 6.7.1:
+   storage-class-specifier:
+     typedef
+     extern
+     static
+     auto
+     register
+
+   C99 6.7.4:
+   function-specifier:
+     inline
+
+   C90 6.5.2, C99 6.7.2:
+   type-specifier:
+     void
+     char
+     short
+     int
+     long
+     float
+     double
+     signed
+     unsigned
+     _Bool
+     _Complex
+     [_Imaginary removed in C99 TC2]
+     struct-or-union-specifier
+     enum-specifier
+     typedef-name
+
+   (_Bool and _Complex are new in C99.)
+
+   C90 6.5.3, C99 6.7.3:
+
+   type-qualifier:
+     const
+     restrict
+     volatile
+
+   (restrict is new in C99.)
+
+   GNU extensions:
+
+   declaration-specifiers:
+     attributes declaration-specifiers[opt]
+
+   storage-class-specifier:
+     __thread
+
+   type-specifier:
+     typeof-specifier
+
+   Objective-C:
+
+   type-specifier:
+     class-name objc-protocol-refs[opt]
+     typedef-name objc-protocol-refs
+     objc-protocol-refs
+*/
+
+static void
+c_parser_declspecs (c_parser *parser, struct c_declspecs *specs,
+                   bool scspec_ok, bool typespec_ok, bool start_attr_ok)
+{
+  bool attrs_ok = start_attr_ok;
+  bool seen_type = specs->type_seen_p;
+  while (c_parser_next_token_is (parser, CPP_NAME)
+        || c_parser_next_token_is (parser, CPP_KEYWORD)
+        || (c_dialect_objc () && c_parser_next_token_is (parser, CPP_LESS)))
+    {
+      struct c_typespec t;
+      tree attrs;
+      if (c_parser_next_token_is (parser, CPP_NAME))
+       {
+         tree value = c_parser_peek_token (parser)->value;
+         c_id_kind kind = c_parser_peek_token (parser)->id_kind;
+         /* This finishes the specifiers unless a type name is OK, it
+            is declared as a type name and a type name hasn't yet
+            been seen.  */
+         if (!typespec_ok || seen_type
+             || (kind != C_ID_TYPENAME && kind != C_ID_CLASSNAME))
+           break;
+         c_parser_consume_token (parser);
+         seen_type = true;
+         attrs_ok = true;
+         if (kind == C_ID_TYPENAME
+             && (!c_dialect_objc ()
+                 || c_parser_next_token_is_not (parser, CPP_LESS)))
+           {
+             t.kind = ctsk_typedef;
+             /* For a typedef name, record the meaning, not the name.
+                In case of 'foo foo, bar;'.  */
+             t.spec = lookup_name (value);
+           }
+         else
+           {
+             tree proto = NULL_TREE;
+             gcc_assert (c_dialect_objc ());
+             t.kind = ctsk_objc;
+             if (c_parser_next_token_is (parser, CPP_LESS))
+               proto = c_parser_objc_protocol_refs (parser);
+             t.spec = objc_get_protocol_qualified_type (value, proto);
+           }
+         declspecs_add_type (specs, t);
+         continue;
+       }
+      if (c_parser_next_token_is (parser, CPP_LESS))
+       {
+         /* Make "<SomeProtocol>" equivalent to "id <SomeProtocol>" -
+            nisse@lysator.liu.se.  */
+         tree proto;
+         gcc_assert (c_dialect_objc ());
+         if (!typespec_ok || seen_type)
+           break;
+         proto = c_parser_objc_protocol_refs (parser);
+         t.kind = ctsk_objc;
+         t.spec = objc_get_protocol_qualified_type (NULL_TREE, proto);
+         declspecs_add_type (specs, t);
+         continue;
+       }
+      gcc_assert (c_parser_next_token_is (parser, CPP_KEYWORD));
+      switch (c_parser_peek_token (parser)->keyword)
+       {
+       case RID_STATIC:
+       case RID_EXTERN:
+       case RID_REGISTER:
+       case RID_TYPEDEF:
+       case RID_INLINE:
+       case RID_AUTO:
+       case RID_THREAD:
+         if (!scspec_ok)
+           goto out;
+         attrs_ok = true;
+         /* TODO: Distinguish between function specifiers (inline)
+            and storage class specifiers, either here or in
+            declspecs_add_scspec.  */
+         declspecs_add_scspec (specs, c_parser_peek_token (parser)->value);
+         c_parser_consume_token (parser);
+         break;
+       case RID_UNSIGNED:
+       case RID_LONG:
+       case RID_SHORT:
+       case RID_SIGNED:
+       case RID_COMPLEX:
+       case RID_INT:
+       case RID_CHAR:
+       case RID_FLOAT:
+       case RID_DOUBLE:
+       case RID_VOID:
+       case RID_BOOL:
+         if (!typespec_ok)
+           goto out;
+         attrs_ok = true;
+         seen_type = true;
+         OBJC_NEED_RAW_IDENTIFIER (1);
+         t.kind = ctsk_resword;
+         t.spec = c_parser_peek_token (parser)->value;
+         declspecs_add_type (specs, t);
+         c_parser_consume_token (parser);
+         break;
+       case RID_ENUM:
+         if (!typespec_ok)
+           goto out;
+         attrs_ok = true;
+         seen_type = true;
+         t = c_parser_enum_specifier (parser);
+         declspecs_add_type (specs, t);
+         break;
+       case RID_STRUCT:
+       case RID_UNION:
+         if (!typespec_ok)
+           goto out;
+         attrs_ok = true;
+         seen_type = true;
+         t = c_parser_struct_or_union_specifier (parser);
+         declspecs_add_type (specs, t);
+         break;
+       case RID_TYPEOF:
+         /* ??? The old parser rejected typeof after other type
+            specifiers, but is a syntax error the best way of
+            handling this?  */
+         if (!typespec_ok || seen_type)
+           goto out;
+         attrs_ok = true;
+         seen_type = true;
+         t = c_parser_typeof_specifier (parser);
+         declspecs_add_type (specs, t);
+         break;
+       case RID_CONST:
+       case RID_VOLATILE:
+       case RID_RESTRICT:
+         attrs_ok = true;
+         declspecs_add_qual (specs, c_parser_peek_token (parser)->value);
+         c_parser_consume_token (parser);
+         break;
+       case RID_ATTRIBUTE:
+         if (!attrs_ok)
+           goto out;
+         attrs = c_parser_attributes (parser);
+         declspecs_add_attrs (specs, attrs);
+         break;
+       default:
+         goto out;
+       }
+    }
+ out: ;
+}
+
+/* Parse an enum specifier (C90 6.5.2.2, C99 6.7.2.2).
+
+   enum-specifier:
+     enum attributes[opt] identifier[opt] { enumerator-list } attributes[opt]
+     enum attributes[opt] identifier[opt] { enumerator-list , } attributes[opt]
+     enum attributes[opt] identifier
+
+   The form with trailing comma is new in C99.  The forms with
+   attributes are GNU extensions.  In GNU C, we accept any expression
+   without commas in the syntax (assignment expressions, not just
+   conditional expressions); assignment expressions will be diagnosed
+   as non-constant.
+
+   enumerator-list:
+     enumerator
+     enumerator-list , enumerator
+
+   enumerator:
+     enumeration-constant
+     enumeration-constant = constant-expression
+*/
+
+static struct c_typespec
+c_parser_enum_specifier (c_parser *parser)
+{
+  struct c_typespec ret;
+  tree attrs;
+  tree ident = NULL_TREE;
+  gcc_assert (c_parser_next_token_is_keyword (parser, RID_ENUM));
+  c_parser_consume_token (parser);
+  attrs = c_parser_attributes (parser);
+  if (c_parser_next_token_is (parser, CPP_NAME))
+    {
+      ident = c_parser_peek_token (parser)->value;
+      c_parser_consume_token (parser);
+    }
+  if (c_parser_next_token_is (parser, CPP_OPEN_BRACE))
+    {
+      /* Parse an enum definition.  */
+      tree type = start_enum (ident);
+      tree postfix_attrs;
+      /* We chain the enumerators in reverse order, then put them in
+        forward order at the end.  */
+      tree values = NULL_TREE;
+      c_parser_consume_token (parser);
+      while (true)
+       {
+         tree enum_id;
+         tree enum_value;
+         tree enum_decl;
+         bool seen_comma;
+         if (c_parser_next_token_is_not (parser, CPP_NAME))
+           {
+             c_parser_error (parser, "expected identifier");
+             c_parser_skip_until_found (parser, CPP_CLOSE_BRACE, NULL);
+             values = error_mark_node;
+             break;
+           }
+         enum_id = c_parser_peek_token (parser)->value;
+         c_parser_consume_token (parser);
+         if (c_parser_next_token_is (parser, CPP_EQ))
+           {
+             c_parser_consume_token (parser);
+             enum_value = c_parser_expr_no_commas (parser, NULL).value;
+           }
+         else
+           enum_value = NULL_TREE;
+         enum_decl = build_enumerator (enum_id, enum_value);
+         TREE_CHAIN (enum_decl) = values;
+         values = enum_decl;
+         seen_comma = false;
+         if (c_parser_next_token_is (parser, CPP_COMMA))
+           {
+             seen_comma = true;
+             c_parser_consume_token (parser);
+           }
+         if (c_parser_next_token_is (parser, CPP_CLOSE_BRACE))
+           {
+             if (seen_comma && pedantic && !flag_isoc99)
+               pedwarn ("comma at end of enumerator list");
+             c_parser_consume_token (parser);
+             break;
+           }
+         if (!seen_comma)
+           {
+             c_parser_error (parser, "expected %<,%> or %<}%>");
+             c_parser_skip_until_found (parser, CPP_CLOSE_BRACE, NULL);
+             values = error_mark_node;
+             break;
+           }
+       }
+      postfix_attrs = c_parser_attributes (parser);
+      ret.spec = finish_enum (type, nreverse (values),
+                             chainon (attrs, postfix_attrs));
+      ret.kind = ctsk_tagdef;
+      return ret;
+    }
+  else if (!ident)
+    {
+      c_parser_error (parser, "expected %<{%>");
+      ret.spec = error_mark_node;
+      ret.kind = ctsk_tagref;
+      return ret;
+    }
+  ret = parser_xref_tag (ENUMERAL_TYPE, ident);
+  /* In ISO C, enumerated types can be referred to only if already
+     defined.  */
+  if (pedantic && !COMPLETE_TYPE_P (ret.spec))
+    pedwarn ("ISO C forbids forward references to %<enum%> types");
+  return ret;
+}
+
+/* Parse a struct or union specifier (C90 6.5.2.1, C99 6.7.2.1).
+
+   struct-or-union-specifier:
+     struct-or-union attributes[opt] identifier[opt]
+       { struct-contents } attributes[opt]
+     struct-or-union attributes[opt] identifier
+
+   struct-contents:
+     struct-declaration-list
+
+   struct-declaration-list:
+     struct-declaration ;
+     struct-declaration-list struct-declaration ;
+
+   GNU extensions:
+
+   struct-contents:
+     empty
+     struct-declaration
+     struct-declaration-list struct-declaration
+
+   struct-declaration-list:
+     struct-declaration-list ;
+     ;
+
+   (Note that in the syntax here, unlike that in ISO C, the semicolons
+   are included here rather than in struct-declaration, in order to
+   describe the syntax with extra semicolons and missing semicolon at
+   end.)
+
+   Objective-C:
+
+   struct-declaration-list:
+     @defs ( class-name )
+
+   (Note this does not include a trailing semicolon, but can be
+   followed by further declarations, and gets a pedwarn-if-pedantic
+   when followed by a semicolon.)  */
+
+static struct c_typespec
+c_parser_struct_or_union_specifier (c_parser *parser)
+{
+  struct c_typespec ret;
+  tree attrs;
+  tree ident = NULL_TREE;
+  enum tree_code code;
+  switch (c_parser_peek_token (parser)->keyword)
+    {
+    case RID_STRUCT:
+      code = RECORD_TYPE;
+      break;
+    case RID_UNION:
+      code = UNION_TYPE;
+      break;
+    default:
+      gcc_unreachable ();
+    }
+  c_parser_consume_token (parser);
+  attrs = c_parser_attributes (parser);
+  if (c_parser_next_token_is (parser, CPP_NAME))
+    {
+      ident = c_parser_peek_token (parser)->value;
+      c_parser_consume_token (parser);
+    }
+  if (c_parser_next_token_is (parser, CPP_OPEN_BRACE))
+    {
+      /* Parse a struct or union definition.  Start the scope of the
+        tag before parsing components.  */
+      tree type = start_struct (code, ident);
+      tree postfix_attrs;
+      /* We chain the components in reverse order, then put them in
+        forward order at the end.  Each struct-declaration may
+        declare multiple components (comma-separated), so we must use
+        chainon to join them, although when parsing each
+        struct-declaration we can use TREE_CHAIN directly.
+
+        The theory behind all this is that there will be more
+        semicolon separated fields than comma separated fields, and
+        so we'll be minimizing the number of node traversals required
+        by chainon.  */
+      tree contents = NULL_TREE;
+      c_parser_consume_token (parser);
+      /* Handle the Objective-C @defs construct,
+        e.g. foo(sizeof(struct{ @defs(ClassName) }));.  */
+      if (c_parser_next_token_is_keyword (parser, RID_AT_DEFS))
+       {
+         tree name;
+         gcc_assert (c_dialect_objc ());
+         c_parser_consume_token (parser);
+         if (!c_parser_require (parser, CPP_OPEN_PAREN, "expected %<(%>"))
+           goto end_at_defs;
+         if (c_parser_next_token_is (parser, CPP_NAME)
+             && c_parser_peek_token (parser)->id_kind == C_ID_CLASSNAME)
+           {
+             name = c_parser_peek_token (parser)->value;
+             c_parser_consume_token (parser);
+           }
+         else
+           {
+             c_parser_error (parser, "expected class name");
+             c_parser_skip_until_found (parser, CPP_CLOSE_PAREN, NULL);
+             goto end_at_defs;
+           }
+         c_parser_skip_until_found (parser, CPP_CLOSE_PAREN,
+                                    "expected %<)%>");
+         contents = nreverse (objc_get_class_ivars (name));
+       }
+    end_at_defs:
+      /* Parse the struct-declarations and semicolons.  Problems with
+        semicolons are diagnosed here; empty structures are diagnosed
+        elsewhere.  */
+      while (true)
+       {
+         tree decls;
+         /* Parse any stray semicolon.  */
+         if (c_parser_next_token_is (parser, CPP_SEMICOLON))
+           {
+             if (pedantic)
+               pedwarn ("extra semicolon in struct or union specified");
+             c_parser_consume_token (parser);
+             continue;
+           }
+         /* Stop if at the end of the struct or union contents.  */
+         if (c_parser_next_token_is (parser, CPP_CLOSE_BRACE))
+           {
+             c_parser_consume_token (parser);
+             break;
+           }
+         /* Parse some comma-separated declarations, but not the
+            trailing semicolon if any.  */
+         decls = c_parser_struct_declaration (parser);
+         contents = chainon (decls, contents);
+         /* If no semicolon follows, either we have a parse error or
+            are at the end of the struct or union and should
+            pedwarn.  */
+         if (c_parser_next_token_is (parser, CPP_SEMICOLON))
+           c_parser_consume_token (parser);
+         else
+           {
+             if (c_parser_next_token_is (parser, CPP_CLOSE_BRACE))
+               pedwarn ("no semicolon at end of struct or union");
+             else
+               {
+                 c_parser_error (parser, "expected %<;%>");
+                 c_parser_skip_until_found (parser, CPP_CLOSE_BRACE, NULL);
+                 break;
+               }
+           }
+       }
+      postfix_attrs = c_parser_attributes (parser);
+      ret.spec = finish_struct (type, nreverse (contents),
+                               chainon (attrs, postfix_attrs));
+      ret.kind = ctsk_tagdef;
+      return ret;
+    }
+  else if (!ident)
+    {
+      c_parser_error (parser, "expected %<{%>");
+      ret.spec = error_mark_node;
+      ret.kind = ctsk_tagref;
+    }
+  ret = parser_xref_tag (code, ident);
+  return ret;
+}
+
+/* Parse a struct-declaration (C90 6.5.2.1, C99 6.7.2.1), *without*
+   the trailing semicolon.
+
+   struct-declaration:
+     specifier-qualifier-list struct-declarator-list
+
+   specifier-qualifier-list:
+     type-specifier specifier-qualifier-list[opt]
+     type-qualifier specifier-qualifier-list[opt]
+     attributes specifier-qualifier-list[opt]
+
+   struct-declarator-list:
+     struct-declarator
+     struct-declarator-list , attributes[opt] struct-declarator
+
+   struct-declarator:
+     declarator attributes[opt]
+     declarator[opt] : constant-expression attributes[opt]
+
+   GNU extensions:
+
+   struct-declaration:
+     __extension__ struct-declaration
+     specifier-qualifier-list
+
+   Unlike the ISO C syntax, semicolons are handled elsewhere.  The use
+   of attributes where shown is a GNU extension.  In GNU C, we accept
+   any expression without commas in the syntax (assignment
+   expressions, not just conditional expressions); assignment
+   expressions will be diagnosed as non-constant.  */
+
+static tree
+c_parser_struct_declaration (c_parser *parser)
+{
+  struct c_declspecs *specs;
+  tree prefix_attrs;
+  tree all_prefix_attrs;
+  tree decls;
+  if (c_parser_next_token_is_keyword (parser, RID_EXTENSION))
+    {
+      int ext;
+      tree decl;
+      ext = disable_extension_diagnostics ();
+      c_parser_consume_token (parser);
+      decl = c_parser_struct_declaration (parser);
+      restore_extension_diagnostics (ext);
+      return decl;
+    }
+  specs = build_null_declspecs ();
+  c_parser_declspecs (parser, specs, false, true, true);
+  if (parser->error)
+    return error_mark_node;
+  if (!specs->declspecs_seen_p)
+    {
+      c_parser_error (parser, "expected specifier-qualifier-list");
+      return NULL_TREE;
+    }
+  finish_declspecs (specs);
+  if (c_parser_next_token_is (parser, CPP_SEMICOLON))
+    {
+      tree ret;
+      if (!specs->type_seen_p)
+       {
+         if (pedantic)
+           pedwarn ("ISO C forbids member declarations with no members");
+         shadow_tag_warned (specs, pedantic);
+         ret = NULL_TREE;
+       }
+      else
+       {
+         /* Support for unnamed structs or unions as members of
+            structs or unions (which is [a] useful and [b] supports
+            MS P-SDK).  */
+         ret = grokfield (build_id_declarator (NULL_TREE), specs, NULL_TREE);
+       }
+      return ret;
+    }
+  pending_xref_error ();
+  prefix_attrs = specs->attrs;
+  all_prefix_attrs = prefix_attrs;
+  specs->attrs = NULL_TREE;
+  decls = NULL_TREE;
+  while (true)
+    {
+      /* Declaring one or more declarators or un-named bit-fields.  */
+      struct c_declarator *declarator;
+      bool dummy = false;
+      if (c_parser_next_token_is (parser, CPP_COLON))
+       declarator = build_id_declarator (NULL_TREE);
+      else
+       declarator = c_parser_declarator (parser, specs->type_seen_p,
+                                         C_DTR_NORMAL, &dummy);
+      if (declarator == NULL)
+       {
+         c_parser_skip_to_end_of_block_or_statement (parser);
+         break;
+       }
+      if (c_parser_next_token_is (parser, CPP_COLON)
+         || c_parser_next_token_is (parser, CPP_COMMA)
+         || c_parser_next_token_is (parser, CPP_SEMICOLON)
+         || c_parser_next_token_is (parser, CPP_CLOSE_BRACE)
+         || c_parser_next_token_is_keyword (parser, RID_ATTRIBUTE))
+       {
+         tree postfix_attrs = NULL_TREE;
+         tree width = NULL_TREE;
+         tree d;
+         if (c_parser_next_token_is (parser, CPP_COLON))
+           {
+             c_parser_consume_token (parser);
+             width = c_parser_expr_no_commas (parser, NULL).value;
+           }
+         if (c_parser_next_token_is_keyword (parser, RID_ATTRIBUTE))
+           postfix_attrs = c_parser_attributes (parser);
+         d = grokfield (declarator, specs, width);
+         decl_attributes (&d, chainon (postfix_attrs,
+                                       all_prefix_attrs), 0);
+         TREE_CHAIN (d) = decls;
+         decls = d;
+         if (c_parser_next_token_is_keyword (parser, RID_ATTRIBUTE))
+           all_prefix_attrs = chainon (c_parser_attributes (parser),
+                                       prefix_attrs);
+         else
+           all_prefix_attrs = prefix_attrs;
+         if (c_parser_next_token_is (parser, CPP_COMMA))
+           c_parser_consume_token (parser);
+         else if (c_parser_next_token_is (parser, CPP_SEMICOLON)
+                  || c_parser_next_token_is (parser, CPP_CLOSE_BRACE))
+           {
+             /* Semicolon consumed in caller.  */
+             break;
+           }
+         else
+           {
+             c_parser_error (parser, "expected %<,%>, %<;%> or %<}%>");
+             break;
+           }
+       }
+      else
+       {
+         c_parser_error (parser,
+                         "expected %<:%>, %<,%>, %<;%>, %<}%> or "
+                         "%<__attribute__%>");
+         break;
+       }
+    }
+  return decls;
+}
+
+/* Parse a typeof specifier (a GNU extension).
+
+   typeof-specifier:
+     typeof ( expression )
+     typeof ( type-name )
+*/
+
+static struct c_typespec
+c_parser_typeof_specifier (c_parser *parser)
+{
+  struct c_typespec ret;
+  ret.kind = ctsk_typeof;
+  ret.spec = error_mark_node;
+  gcc_assert (c_parser_next_token_is_keyword (parser, RID_TYPEOF));
+  c_parser_consume_token (parser);
+  skip_evaluation++;
+  in_typeof++;
+  if (!c_parser_require (parser, CPP_OPEN_PAREN, "expected %<(%>"))
+    {
+      skip_evaluation--;
+      in_typeof--;
+      return ret;
+    }
+  if (c_parser_next_token_starts_typename (parser))
+    {
+      struct c_type_name *type = c_parser_type_name (parser);
+      skip_evaluation--;
+      in_typeof--;
+      if (type != NULL)
+       {
+         ret.spec = groktypename (type);
+         pop_maybe_used (variably_modified_type_p (ret.spec, NULL_TREE));
+       }
+    }
+  else
+    {
+      struct c_expr expr = c_parser_expression (parser);
+      skip_evaluation--;
+      in_typeof--;
+      if (TREE_CODE (expr.value) == COMPONENT_REF
+         && DECL_C_BIT_FIELD (TREE_OPERAND (expr.value, 1)))
+       error ("%<typeof%> applied to a bit-field");
+      ret.spec = TREE_TYPE (expr.value);
+      pop_maybe_used (variably_modified_type_p (ret.spec, NULL_TREE));
+    }
+  c_parser_skip_until_found (parser, CPP_CLOSE_PAREN, "expected %<)%>");
+  return ret;
+}
+
+/* Parse a declarator, possibly an abstract declarator (C90 6.5.4,
+   6.5.5, C99 6.7.5, 6.7.6).  If TYPE_SEEN_P then a typedef name may
+   be redeclared; otherwise it may not.  KIND indicates which kind of
+   declarator is wanted.  Returns a valid declarator except in the
+   case of a syntax error in which case NULL is returned.  *SEEN_ID is
+   set to true if an identifier being declared is seen; this is used
+   to diagnose bad forms of abstract array declarators and to
+   determine whether an identifier list is syntactically permitted.
+
+   declarator:
+     pointer[opt] direct-declarator
+
+   direct-declarator:
+     identifier
+     ( attributes[opt] declarator )
+     direct-declarator array-declarator
+     direct-declarator ( parameter-type-list )
+     direct-declarator ( identifier-list[opt] )
+
+   pointer:
+     * type-qualifier-list[opt]
+     * type-qualifier-list[opt] pointer
+
+   type-qualifier-list:
+     type-qualifier
+     attributes
+     type-qualifier-list type-qualifier
+     type-qualifier-list attributes
+
+   parameter-type-list:
+     parameter-list
+     parameter-list , ...
+
+   parameter-list:
+     parameter-declaration
+     parameter-list , parameter-declaration
+
+   parameter-declaration:
+     declaration-specifiers declarator attributes[opt]
+     declaration-specifiers abstract-declarator[opt] attributes[opt]
+
+   identifier-list:
+     identifier
+     identifier-list , identifier
+
+   abstract-declarator:
+     pointer
+     pointer[opt] direct-abstract-declarator
+
+   direct-abstract-declarator:
+     ( attributes[opt] abstract-declarator )
+     direct-abstract-declarator[opt] array-declarator
+     direct-abstract-declarator[opt] ( parameter-type-list[opt] )
+
+   GNU extensions:
+
+   direct-declarator:
+     direct-declarator ( parameter-forward-declarations
+                        parameter-type-list[opt] )
+
+   direct-abstract-declarator:
+     direct-abstract-declarator[opt] ( parameter-forward-declarations 
+                                      parameter-type-list[opt] )
+
+   parameter-forward-declarations:
+     parameter-list ;
+     parameter-forward-declarations parameter-list ;
+
+   The uses of attributes shown above are GNU extensions.
+
+   Some forms of array declarator are not included in C99 in the
+   syntax for abstract declarators; these are disallowed elsewhere.
+   This may be a defect (DR#289).
+
+   This function also accepts an omitted abstract declarator as being
+   an abstract declarator, although not part of the formal syntax.  */
+
+static struct c_declarator *
+c_parser_declarator (c_parser *parser, bool type_seen_p, c_dtr_syn kind,
+                    bool *seen_id)
+{
+  /* Parse any initial pointer part.  */
+  if (c_parser_next_token_is (parser, CPP_MULT))
+    {
+      struct c_declspecs *quals_attrs = build_null_declspecs ();
+      struct c_declarator *inner;
+      c_parser_consume_token (parser);
+      c_parser_declspecs (parser, quals_attrs, false, false, true);
+      inner = c_parser_declarator (parser, type_seen_p, kind, seen_id);
+      if (inner == NULL)
+       return NULL;
+      else
+       return make_pointer_declarator (quals_attrs, inner);
+    }
+  /* Now we have a direct declarator, direct abstract declarator or
+     nothing (which counts as a direct abstract declarator here).  */
+  return c_parser_direct_declarator (parser, type_seen_p, kind, seen_id);
+}
+
+/* Parse a direct declarator or direct abstract declarator; arguments
+   as c_parser_declarator.  */
+
+static struct c_declarator *
+c_parser_direct_declarator (c_parser *parser, bool type_seen_p, c_dtr_syn kind,
+                           bool *seen_id)
+{
+  /* The direct declarator must start with an identifier (possibly
+     omitted) or a parenthesized declarator (possibly abstract).  In
+     an ordinary declarator, initial parentheses must start a
+     parenthesized declarator.  In an abstract declarator or parameter
+     declarator, they could start a parenthesized declarator or a
+     parameter list.  To tell which, the open parenthesis and any
+     following attributes must be read.  If a declaration specifier
+     follows, then it is a parameter list; if the specifier is a
+     typedef name, there might be an ambiguity about redeclaring it,
+     which is resolved in the direction of treating it as a typedef
+     name.  If a close parenthesis follows, it is also an empty
+     parameter list, as the syntax does not permit empty abstract
+     declarators.  Otherwise, it is a parenthesised declarator (in
+     which case the analysis may be repeated inside it, recursively).
+
+     ??? There is an ambiguity in a parameter declaration "int
+     (__attribute__((foo)) x)", where x is not a typedef name: it
+     could be an abstract declarator for a function, or declare x with
+     parentheses.  The proper resolution of this ambiguity needs
+     documenting.  At present we follow an accident of the old
+     parser's implementation, whereby the first parameter must have
+     some declaration specifiers other than just attributes.  Thus as
+     a parameter declaration it is treated as a parenthesised
+     parameter named x, and as an abstract declarator it is
+     rejected.
+
+     ??? Also following the old parser, attributes inside an empty
+     parameter list are ignored, making it a list not yielding a
+     prototype, rather than giving an error or making it have one
+     parameter with implicit type int.
+
+     ??? Also following the old parser, typedef names may be
+     redeclared in declarators, but not Objective-C class names.  */
+
+  if (kind != C_DTR_ABSTRACT
+      && c_parser_next_token_is (parser, CPP_NAME)
+      && ((type_seen_p
+          && c_parser_peek_token (parser)->id_kind == C_ID_TYPENAME)
+         || c_parser_peek_token (parser)->id_kind == C_ID_ID))
+    {
+      struct c_declarator *inner
+       = build_id_declarator (c_parser_peek_token (parser)->value);
+      *seen_id = true;
+      c_parser_consume_token (parser);
+      return c_parser_direct_declarator_inner (parser, *seen_id, inner);
+    }
+
+  if (kind != C_DTR_NORMAL
+      && c_parser_next_token_is (parser, CPP_OPEN_SQUARE))
+    {
+      struct c_declarator *inner = build_id_declarator (NULL_TREE);
+      return c_parser_direct_declarator_inner (parser, *seen_id, inner);
+    }
+
+  /* Either we are at the end of an abstract declarator, or we have
+     parentheses.  */
+
+  if (c_parser_next_token_is (parser, CPP_OPEN_PAREN))
+    {
+      tree attrs;
+      struct c_declarator *inner;
+      c_parser_consume_token (parser);
+      attrs = c_parser_attributes (parser);
+      if (kind != C_DTR_NORMAL
+         && (c_parser_next_token_starts_declspecs (parser)
+             || c_parser_next_token_is (parser, CPP_CLOSE_PAREN)))
+       {
+         struct c_arg_info *args
+           = c_parser_parms_declarator (parser, kind == C_DTR_NORMAL,
+                                        attrs);
+         if (args == NULL)
+           return NULL;
+         else
+           {
+             inner
+               = build_function_declarator (args,
+                                            build_id_declarator (NULL_TREE));
+             return c_parser_direct_declarator_inner (parser, *seen_id,
+                                                      inner);
+           }
+       }
+      /* A parenthesized declarator.  */
+      inner = c_parser_declarator (parser, type_seen_p, kind, seen_id);
+      if (inner != NULL && attrs != NULL)
+       inner = build_attrs_declarator (attrs, inner);
+      if (c_parser_next_token_is (parser, CPP_CLOSE_PAREN))
+       {
+         c_parser_consume_token (parser);
+         if (inner == NULL)
+           return NULL;
+         else
+           return c_parser_direct_declarator_inner (parser, *seen_id, inner);
+       }
+      else
+       {
+         c_parser_skip_until_found (parser, CPP_CLOSE_PAREN,
+                                    "expected %<)%>");
+         return NULL;
+       }
+    }
+  else
+    {
+      if (kind == C_DTR_NORMAL)
+       {
+         c_parser_error (parser, "expected identifier or %<(%>");
+         return NULL;
+       }
+      else
+       return build_id_declarator (NULL_TREE);
+    }
+}
+
+/* Parse part of a direct declarator or direct abstract declarator,
+   given that some (in INNER) has already been parsed; ID_PRESENT is
+   true if an identifier is present, false for an abstract
+   declarator.  */
+
+static struct c_declarator *
+c_parser_direct_declarator_inner (c_parser *parser, bool id_present,
+                                 struct c_declarator *inner)
+{
+  /* Parse a sequence of array declarators and parameter lists.  */
+  if (c_parser_next_token_is (parser, CPP_OPEN_SQUARE))
+    {
+      struct c_declarator *declarator;
+      struct c_declspecs *quals_attrs = build_null_declspecs ();
+      bool static_seen;
+      bool star_seen;
+      tree dimen;
+      c_parser_consume_token (parser);
+      c_parser_declspecs (parser, quals_attrs, false, false, true);
+      static_seen = c_parser_next_token_is_keyword (parser, RID_STATIC);
+      if (static_seen)
+       c_parser_consume_token (parser);
+      if (static_seen && !quals_attrs->declspecs_seen_p)
+       c_parser_declspecs (parser, quals_attrs, false, false, true);
+      if (!quals_attrs->declspecs_seen_p)
+       quals_attrs = NULL;
+      /* If "static" is present, there must be an array dimension.
+        Otherwise, there may be a dimension, "*", or no
+        dimension.  */
+      if (static_seen)
+       {
+         star_seen = false;
+         dimen = c_parser_expr_no_commas (parser, NULL).value;
+       }
+      else
+       {
+         if (c_parser_next_token_is (parser, CPP_CLOSE_SQUARE))
+           {
+             dimen = NULL_TREE;
+             star_seen = false;
+           }
+         else if (c_parser_next_token_is (parser, CPP_MULT))
+           {
+             if (c_parser_peek_2nd_token (parser)->type == CPP_CLOSE_SQUARE)
+               {
+                 dimen = NULL_TREE;
+                 star_seen = true;
+                 c_parser_consume_token (parser);
+               }
+             else
+               {
+                 star_seen = false;
+                 dimen = c_parser_expr_no_commas (parser, NULL).value;
+               }
+           }
+         else
+           {
+             star_seen = false;
+             dimen = c_parser_expr_no_commas (parser, NULL).value;
+           }
+       }
+      if (c_parser_next_token_is (parser, CPP_CLOSE_SQUARE))
+       c_parser_consume_token (parser);
+      else
+       {
+         c_parser_skip_until_found (parser, CPP_CLOSE_SQUARE,
+                                    "expected %<]%>");
+         return NULL;
+       }
+      declarator = build_array_declarator (dimen, quals_attrs, static_seen,
+                                          star_seen);
+      inner = set_array_declarator_inner (declarator, inner, !id_present);
+      return c_parser_direct_declarator_inner (parser, id_present, inner);
+    }
+  else if (c_parser_next_token_is (parser, CPP_OPEN_PAREN))
+    {
+      tree attrs;
+      struct c_arg_info *args;
+      c_parser_consume_token (parser);
+      attrs = c_parser_attributes (parser);
+      args = c_parser_parms_declarator (parser, id_present, attrs);
+      if (args == NULL)
+       return NULL;
+      else
+       {
+         inner = build_function_declarator (args, inner);
+         return c_parser_direct_declarator_inner (parser, id_present, inner);
+       }
+    }
+  return inner;
+}
+
+/* Parse a parameter list or identifier list, including the closing
+   parenthesis but not the opening one.  ATTRS are the attributes at
+   the start of the list.  ID_LIST_OK is true if an identifier list is
+   acceptable; such a list must not have attributes at the start.  */
+
+static struct c_arg_info *
+c_parser_parms_declarator (c_parser *parser, bool id_list_ok, tree attrs)
+{
+  push_scope ();
+  declare_parm_level ();
+  /* If the list starts with an identifier, it is an identifier list.
+     Otherwise, it is either a prototype list or an empty list.  */
+  if (id_list_ok
+      && !attrs
+      && c_parser_next_token_is (parser, CPP_NAME)
+      && c_parser_peek_token (parser)->id_kind == C_ID_ID)
+    {
+      tree list = NULL_TREE;
+      while (c_parser_next_token_is (parser, CPP_NAME)
+            && c_parser_peek_token (parser)->id_kind == C_ID_ID)
+       {
+         list = chainon (list, build_tree_list (NULL_TREE,
+                                                c_parser_peek_token (parser)->value));
+         c_parser_consume_token (parser);
+         if (c_parser_next_token_is_not (parser, CPP_COMMA))
+           break;
+         c_parser_consume_token (parser);
+         if (c_parser_next_token_is (parser, CPP_CLOSE_PAREN))
+           {
+             c_parser_error (parser, "expected identifier");
+             break;
+           }
+       }
+      if (c_parser_next_token_is (parser, CPP_CLOSE_PAREN))
+       {
+         struct c_arg_info *ret = XOBNEW (&parser_obstack, struct c_arg_info);
+         ret->parms = 0;
+         ret->tags = 0;
+         ret->types = list;
+         ret->others = 0;
+         c_parser_consume_token (parser);
+         pop_scope ();
+         return ret;
+       }
+      else
+       {
+         c_parser_skip_until_found (parser, CPP_CLOSE_PAREN,
+                                    "expected %<)%>");
+         pop_scope ();
+         return NULL;
+       }
+    }
+  else
+    {
+      struct c_arg_info *ret = c_parser_parms_list_declarator (parser, attrs);
+      pop_scope ();
+      return ret;
+    }
+}
+
+/* Parse a parameter list (possibly empty), including the closing
+   parenthesis but not the opening one.  ATTRS are the attributes at
+   the start of the list.  */
+
+static struct c_arg_info *
+c_parser_parms_list_declarator (c_parser *parser, tree attrs)
+{
+  bool good_parm = false;
+  /* ??? Following the old parser, forward parameter declarations may
+     use abstract declarators, and if no real parameter declarations
+     follow the forward declarations then this is not diagnosed.  Also
+     note as above that attributes are ignored as the only contents of
+     the parentheses, or as the only contents after forward
+     declarations.  */
+  if (c_parser_next_token_is (parser, CPP_CLOSE_PAREN))
+    {
+      struct c_arg_info *ret = XOBNEW (&parser_obstack, struct c_arg_info);
+      ret->parms = 0;
+      ret->tags = 0;
+      ret->types = 0;
+      ret->others = 0;
+      c_parser_consume_token (parser);
+      return ret;
+    }
+  if (c_parser_next_token_is (parser, CPP_ELLIPSIS))
+    {
+      struct c_arg_info *ret = XOBNEW (&parser_obstack, struct c_arg_info);
+      ret->parms = 0;
+      ret->tags = 0;
+      ret->others = 0;
+      /* Suppress -Wold-style-definition for this case.  */
+      ret->types = error_mark_node;
+      error ("ISO C requires a named argument before %<...%>");
+      c_parser_consume_token (parser);
+      if (c_parser_next_token_is (parser, CPP_CLOSE_PAREN))
+       {
+         c_parser_consume_token (parser);
+         return ret;
+       }
+      else
+       {
+         c_parser_skip_until_found (parser, CPP_CLOSE_PAREN,
+                                    "expected %<)%>");
+         return NULL;
+       }
+    }
+  /* Nonempty list of parameters, either terminated with semicolon
+     (forward declarations; recurse) or with close parenthesis (normal
+     function) or with ", ... )" (variadic function).  */
+  while (true)
+    {
+      /* Parse a parameter.  */
+      struct c_parm *parm = c_parser_parameter_declaration (parser, attrs);
+      attrs = NULL_TREE;
+      if (parm != NULL)
+       {
+         good_parm = true;
+         push_parm_decl (parm);
+       }
+      if (c_parser_next_token_is (parser, CPP_SEMICOLON))
+       {
+         tree new_attrs;
+         c_parser_consume_token (parser);
+         new_attrs = c_parser_attributes (parser);
+         return c_parser_parms_list_declarator (parser, new_attrs);
+       }
+      if (c_parser_next_token_is (parser, CPP_CLOSE_PAREN))
+       {
+         c_parser_consume_token (parser);
+         if (good_parm)
+           return get_parm_info (false);
+         else
+           {
+             struct c_arg_info *ret
+               = XOBNEW (&parser_obstack, struct c_arg_info);
+             ret->parms = 0;
+             ret->tags = 0;
+             ret->types = 0;
+             ret->others = 0;
+             return ret;
+           }
+       }
+      if (!c_parser_require (parser, CPP_COMMA,
+                            "expected %<;%>, %<,%> or %<)%>"))
+       {
+         c_parser_skip_until_found (parser, CPP_CLOSE_PAREN, NULL);
+         return NULL;
+       }
+      if (c_parser_next_token_is (parser, CPP_ELLIPSIS))
+       {
+         c_parser_consume_token (parser);
+         if (c_parser_next_token_is (parser, CPP_CLOSE_PAREN))
+           {
+             c_parser_consume_token (parser);
+             if (good_parm)
+               return get_parm_info (true);
+             else
+               {
+                 struct c_arg_info *ret
+                   = XOBNEW (&parser_obstack, struct c_arg_info);
+                 ret->parms = 0;
+                 ret->tags = 0;
+                 ret->types = 0;
+                 ret->others = 0;
+                 return ret;
+               }
+           }
+         else
+           {
+             c_parser_skip_until_found (parser, CPP_CLOSE_PAREN,
+                                        "expected %<)%>");
+             return NULL;
+           }
+       }
+    }
+}
+
+/* Parse a parameter declaration.  ATTRS are the attributes at the
+   start of the declaration if it is the first parameter.  */
+
+static struct c_parm *
+c_parser_parameter_declaration (c_parser *parser, tree attrs)
+{
+  struct c_declspecs *specs;
+  struct c_declarator *declarator;
+  tree prefix_attrs;
+  tree postfix_attrs = NULL_TREE;
+  bool dummy = false;
+  if (!c_parser_next_token_starts_declspecs (parser))
+    {
+      /* ??? In some Objective-C cases '...' isn't applicable so there
+        should be a different message.  */
+      c_parser_error (parser,
+                     "expected declaration specifiers or %<...%>");
+      c_parser_skip_to_end_of_parameter (parser);
+      return NULL;
+    }
+  specs = build_null_declspecs ();
+  if (attrs)
+    {
+      declspecs_add_attrs (specs, attrs);
+      attrs = NULL_TREE;
+    }
+  c_parser_declspecs (parser, specs, true, true, true);
+  finish_declspecs (specs);
+  pending_xref_error ();
+  prefix_attrs = specs->attrs;
+  specs->attrs = NULL_TREE;
+  declarator = c_parser_declarator (parser, specs->type_seen_p,
+                                   C_DTR_PARM, &dummy);
+  if (declarator == NULL)
+    {
+      c_parser_skip_until_found (parser, CPP_COMMA, NULL);
+      return NULL;
+    }
+  if (c_parser_next_token_is_keyword (parser, RID_ATTRIBUTE))
+    postfix_attrs = c_parser_attributes (parser);
+  return build_c_parm (specs, chainon (postfix_attrs, prefix_attrs),
+                      declarator);
+}
+
+/* Parse a string literal in an asm expression.  It should not be
+   translated, and wide string literals are an error although
+   permitted by the syntax.  This is a GNU extension.
+
+   asm-string-literal:
+     string-literal
+
+   ??? At present, following the old parser, the caller needs to have
+   set c_lex_string_translate to 0.  It would be better to follow the
+   C++ parser rather than using the c_lex_string_translate kludge.  */
+
+static tree
+c_parser_asm_string_literal (c_parser *parser)
+{
+  tree str;
+  if (c_parser_next_token_is (parser, CPP_STRING))
+    {
+      str = c_parser_peek_token (parser)->value;
+      c_parser_consume_token (parser);
+    }
+  else if (c_parser_next_token_is (parser, CPP_WSTRING))
+    {
+      error ("wide string literal in %<asm%>");
+      str = build_string (1, "");
+      c_parser_consume_token (parser);
+    }
+  else
+    {
+      c_parser_error (parser, "expected string literal");
+      str = NULL_TREE;
+    }
+  return str;
+}
+
+/* Parse a simple asm expression.  This is used in restricted
+   contexts, where a full expression with inputs and outputs does not
+   make sense.  This is a GNU extension.
+
+   simple-asm-expr:
+     asm ( asm-string-literal )
+*/
+
+static tree
+c_parser_simple_asm_expr (c_parser *parser)
+{
+  tree str;
+  gcc_assert (c_parser_next_token_is_keyword (parser, RID_ASM));
+  /* ??? Follow the C++ parser rather than using the
+     c_lex_string_translate kludge.  */
+  c_lex_string_translate = 0;
+  c_parser_consume_token (parser);
+  if (!c_parser_require (parser, CPP_OPEN_PAREN, "expected %<(%>"))
+    {
+      c_lex_string_translate = 1;
+      return NULL_TREE;
+    }
+  str = c_parser_asm_string_literal (parser);
+  c_lex_string_translate = 1;
+  if (!c_parser_require (parser, CPP_CLOSE_PAREN, "expected %<)%>"))
+    {
+      c_parser_skip_until_found (parser, CPP_CLOSE_PAREN, NULL);
+      return NULL_TREE;
+    }
+  return str;
+}
+
+/* Parse (possibly empty) attributes.  This is a GNU extension.
+
+   attributes:
+     empty
+     attributes attribute
+
+   attribute:
+     __attribute__ ( ( attribute-list ) )
+
+   attribute-list:
+     attrib
+     attribute_list , attrib
+
+   attrib:
+     empty
+     any-word
+     any-word ( identifier )
+     any-word ( identifier , nonempty-expr-list )
+     any-word ( expr-list )
+
+   where the "identifier" must not be declared as a type, and
+   "any-word" may be any identifier (including one declared as a
+   type), a reserved word storage class specifier, type specifier or
+   type qualifier.  ??? This still leaves out most reserved keywords
+   (following the old parser), shouldn't we include them, and why not
+   allow identifiers declared as types to start the arguments?  */
+
+static tree
+c_parser_attributes (c_parser *parser)
+{
+  tree attrs = NULL_TREE;
+  while (c_parser_next_token_is_keyword (parser, RID_ATTRIBUTE))
+    {
+      /* ??? Follow the C++ parser rather than using the
+        c_lex_string_translate kludge.  */
+      c_lex_string_translate = 0;
+      c_parser_consume_token (parser);
+      if (!c_parser_require (parser, CPP_OPEN_PAREN, "expected %<(%>"))
+       {
+         c_lex_string_translate = 1;
+         return attrs;
+       }
+      if (!c_parser_require (parser, CPP_OPEN_PAREN, "expected %<(%>"))
+       {
+         c_lex_string_translate = 1;
+         c_parser_skip_until_found (parser, CPP_CLOSE_PAREN, NULL);
+         return attrs;
+       }
+      /* Parse the attribute list.  */
+      while (c_parser_next_token_is (parser, CPP_COMMA)
+            || c_parser_next_token_is (parser, CPP_NAME)
+            || c_parser_next_token_is (parser, CPP_KEYWORD))
+       {
+         tree attr, attr_name, attr_args;
+         if (c_parser_next_token_is (parser, CPP_COMMA))
+           {
+             c_parser_consume_token (parser);
+             continue;
+           }
+         if (c_parser_next_token_is (parser, CPP_KEYWORD))
+           {
+             /* ??? See comment above about what keywords are
+                accepted here.  */
+             bool ok;
+             switch (c_parser_peek_token (parser)->keyword)
+               {
+               case RID_STATIC:
+               case RID_UNSIGNED:
+               case RID_LONG:
+               case RID_CONST:
+               case RID_EXTERN:
+               case RID_REGISTER:
+               case RID_TYPEDEF:
+               case RID_SHORT:
+               case RID_INLINE:
+               case RID_VOLATILE:
+               case RID_SIGNED:
+               case RID_AUTO:
+               case RID_RESTRICT:
+               case RID_COMPLEX:
+               case RID_THREAD:
+               case RID_INT:
+               case RID_CHAR:
+               case RID_FLOAT:
+               case RID_DOUBLE:
+               case RID_VOID:
+               case RID_BOOL:
+                 ok = true;
+                 break;
+               default:
+                 ok = false;
+                 break;
+               }
+             if (!ok)
+               break;
+           }
+         attr_name = c_parser_peek_token (parser)->value;
+         c_parser_consume_token (parser);
+         if (c_parser_next_token_is_not (parser, CPP_OPEN_PAREN))
+           {
+             attr = build_tree_list (attr_name, NULL_TREE);
+             attrs = chainon (attrs, attr);
+             continue;
+           }
+         c_parser_consume_token (parser);
+         /* Parse the attribute contents.  If they start with an
+            identifier which is followed by a comma or close
+            parenthesis, then the arguments start with that
+            identifier; otherwise they are an expression list.  */
+         if (c_parser_next_token_is (parser, CPP_NAME)
+             && c_parser_peek_token (parser)->id_kind == C_ID_ID
+             && ((c_parser_peek_2nd_token (parser)->type == CPP_COMMA)
+                 || (c_parser_peek_2nd_token (parser)->type
+                     == CPP_CLOSE_PAREN)))
+           {
+             tree arg1 = c_parser_peek_token (parser)->value;
+             c_parser_consume_token (parser);
+             if (c_parser_next_token_is (parser, CPP_CLOSE_PAREN))
+               attr_args = build_tree_list (NULL_TREE, arg1);
+             else
+               {
+                 c_parser_consume_token (parser);
+                 attr_args = tree_cons (NULL_TREE, arg1,
+                                        c_parser_expr_list (parser));
+               }
+           }
+         else
+           {
+             if (c_parser_next_token_is (parser, CPP_CLOSE_PAREN))
+               attr_args = NULL_TREE;
+             else
+               attr_args = c_parser_expr_list (parser);
+           }
+         attr = build_tree_list (attr_name, attr_args);
+         if (c_parser_next_token_is (parser, CPP_CLOSE_PAREN))
+           c_parser_consume_token (parser);
+         else
+           {
+             c_lex_string_translate = 1;
+             c_parser_skip_until_found (parser, CPP_CLOSE_PAREN,
+                                        "expected %<)%>");
+             return attrs;
+           }
+         attrs = chainon (attrs, attr);
+       }
+      if (c_parser_next_token_is (parser, CPP_CLOSE_PAREN))
+       c_parser_consume_token (parser);
+      else
+       {
+         c_lex_string_translate = 1;
+         c_parser_skip_until_found (parser, CPP_CLOSE_PAREN,
+                                    "expected %<)%>");
+         return attrs;
+       }
+      if (c_parser_next_token_is (parser, CPP_CLOSE_PAREN))
+       c_parser_consume_token (parser);
+      else
+       {
+         c_lex_string_translate = 1;
+         c_parser_skip_until_found (parser, CPP_CLOSE_PAREN,
+                                    "expected %<)%>");
+         return attrs;
+       }
+      c_lex_string_translate = 1;
+    }
+  return attrs;
+}
+
+/* Parse a type name (C90 6.5.5, C99 6.7.6).
+
+   type-name:
+     specifier-qualifier-list abstract-declarator[opt]
+*/
+
+static struct c_type_name *
+c_parser_type_name (c_parser *parser)
+{
+  struct c_declspecs *specs = build_null_declspecs ();
+  struct c_declarator *declarator;
+  struct c_type_name *ret;
+  bool dummy = false;
+  c_parser_declspecs (parser, specs, false, true, true);
+  if (!specs->declspecs_seen_p)
+    {
+      c_parser_error (parser, "expected specifier-qualifier-list");
+      return NULL;
+    }
+  pending_xref_error ();
+  finish_declspecs (specs);
+  declarator = c_parser_declarator (parser, specs->type_seen_p,
+                                   C_DTR_ABSTRACT, &dummy);
+  if (declarator == NULL)
+    return NULL;
+  ret = XOBNEW (&parser_obstack, struct c_type_name);
+  ret->specs = specs;
+  ret->declarator = declarator;
+  return ret;
+}
+
+/* Parse an initializer (C90 6.5.7, C99 6.7.8).
+
+   initializer:
+     assignment-expression
+     { initializer-list }
+     { initializer-list , }
+
+   initializer-list:
+     designation[opt] initializer
+     initializer-list , designation[opt] initializer
+
+   designation:
+     designator-list =
+
+   designator-list:
+     designator
+     designator-list designator
+
+   designator:
+     array-designator
+     . identifier
+
+   array-designator:
+     [ constant-expression ]
+
+   GNU extensions:
+
+   initializer:
+     { }
+
+   designation:
+     array-designator
+     identifier :
+
+   array-designator:
+     [ constant-expression ... constant-expression ]
+
+   Any expression without commas is accepted in the syntax for the
+   constant-expressions, with non-constant expressions rejected later.
+
+   This function is only used for top-level initializers; for nested
+   ones, see c_parser_initval.  */
+
+static struct c_expr
+c_parser_initializer (c_parser *parser)
+{
+  if (c_parser_next_token_is (parser, CPP_OPEN_BRACE))
+    return c_parser_braced_init (parser, NULL_TREE, false);
+  else
+    return c_parser_expr_no_commas (parser, NULL);
+}
+
+/* Parse a braced initializer list.  TYPE is the type specified for a
+   compound literal, and NULL_TREE for other initializers and for
+   nested braced lists.  NESTED_P is true for nested braced lists,
+   false for the list of a compound literal or the list that is the
+   top-level initializer in a declaration.  */
+
+static struct c_expr
+c_parser_braced_init (c_parser *parser, tree type, bool nested_p)
+{
+  gcc_assert (c_parser_next_token_is (parser, CPP_OPEN_BRACE));
+  c_parser_consume_token (parser);
+  if (nested_p)
+    push_init_level (0);
+  else
+    really_start_incremental_init (type);
+  if (c_parser_next_token_is (parser, CPP_CLOSE_BRACE))
+    {
+      if (pedantic)
+       pedwarn ("ISO C forbids empty initializer braces");
+    }
+  else
+    {
+      /* Parse a non-empty initializer list, possibly with a trailing
+        comma.  */
+      while (true)
+       {
+         c_parser_initelt (parser);
+         if (parser->error)
+           break;
+         if (c_parser_next_token_is (parser, CPP_COMMA))
+           c_parser_consume_token (parser);
+         else
+           break;
+         if (c_parser_next_token_is (parser, CPP_CLOSE_BRACE))
+           break;
+       }
+    }
+  if (c_parser_next_token_is_not (parser, CPP_CLOSE_BRACE))
+    {
+      struct c_expr ret;
+      ret.value = error_mark_node;
+      ret.original_code = ERROR_MARK;
+      c_parser_skip_until_found (parser, CPP_CLOSE_BRACE, "expected %<}%>");
+      return ret;
+    }
+  c_parser_consume_token (parser);
+  return pop_init_level (0);
+}
+
+/* Parse a nested initializer, including designators.  */
+
+static void
+c_parser_initelt (c_parser *parser)
+{
+  /* Parse any designator or designator list.  A single array
+     designator may have the subsequent "=" omitted in GNU C, but a
+     longer list or a structure member designator may not.  */
+  if (c_parser_next_token_is (parser, CPP_NAME)
+      && c_parser_peek_2nd_token (parser)->type == CPP_COLON)
+    {
+      /* Old-style structure member designator.  */
+      set_init_label (c_parser_peek_token (parser)->value);
+      if (pedantic)
+       pedwarn ("obsolete use of designated initializer with %<:%>");
+      c_parser_consume_token (parser);
+      c_parser_consume_token (parser);
+    }
+  else
+    {
+      /* des_seen is 0 if there have been no designators, 1 if there
+        has been a single array designator and 2 otherwise.  */
+      int des_seen = 0;
+      while (c_parser_next_token_is (parser, CPP_OPEN_SQUARE)
+            || c_parser_next_token_is (parser, CPP_DOT))
+       {
+         int des_prev = des_seen;
+         if (des_seen < 2)
+           des_seen++;
+         if (c_parser_next_token_is (parser, CPP_DOT))
+           {
+             des_seen = 2;
+             c_parser_consume_token (parser);
+             if (c_parser_next_token_is (parser, CPP_NAME))
+               {
+                 set_init_label (c_parser_peek_token (parser)->value);
+                 c_parser_consume_token (parser);
+               }
+             else
+               {
+                 struct c_expr init;
+                 init.value = error_mark_node;
+                 init.original_code = ERROR_MARK;
+                 c_parser_error (parser, "expected identifier");
+                 c_parser_skip_until_found (parser, CPP_COMMA, NULL);
+                 process_init_element (init);
+                 return;
+               }
+           }
+         else
+           {
+             tree first, second;
+             /* ??? Following the old parser, [ objc-receiver
+                objc-message-args ] is accepted as an initializer,
+                being distinguished from a designator by what follows
+                the first assignment expression inside the square
+                brackets, but after a first array designator a
+                subsequent square bracket is for Objective-C taken to
+                start an expression, using the obsolete form of
+                designated initializer without '=', rather than
+                possibly being a second level of designation: in LALR
+                terms, the '[' is shifted rather than reducing
+                designator to designator-list.  */
+             if (des_prev == 1 && c_dialect_objc ())
+               {
+                 des_seen = des_prev;
+                 break;
+               }
+             if (des_prev == 0 && c_dialect_objc ())
+               {
+                 /* This might be an array designator or an
+                    Objective-C message expression.  If the former,
+                    continue parsing here; if the latter, parse the
+                    remainder of the initializer given the starting
+                    primary-expression.  ??? It might make sense to
+                    distinguish when des_prev == 1 as well; see
+                    previous comment.  */
+                 tree rec, args;
+                 struct c_expr mexpr;
+                 c_parser_consume_token (parser);
+                 if (c_parser_peek_token (parser)->type == CPP_NAME
+                     && ((c_parser_peek_token (parser)->id_kind
+                          == C_ID_TYPENAME)
+                         || (c_parser_peek_token (parser)->id_kind
+                             == C_ID_CLASSNAME)))
+                   {
+                     /* Type name receiver.  */
+                     tree id = c_parser_peek_token (parser)->value;
+                     c_parser_consume_token (parser);
+                     rec = objc_get_class_reference (id);
+                     goto parse_message_args;
+                   }
+                 first = c_parser_expr_no_commas (parser, NULL).value;
+                 if (c_parser_next_token_is (parser, CPP_ELLIPSIS)
+                     || c_parser_next_token_is (parser, CPP_CLOSE_SQUARE))
+                   goto array_desig_after_first;
+                 /* Expression receiver.  So far only one part
+                    without commas has been parsed; there might be
+                    more of the expression.  */
+                 rec = first;
+                 while (c_parser_next_token_is (parser, CPP_COMMA))
+                   {
+                     tree next;
+                     c_parser_consume_token (parser);
+                     next = c_parser_expr_no_commas (parser, NULL).value;
+                     rec = build_compound_expr (rec, next);
+                   }
+               parse_message_args:
+                 /* Now parse the objc-message-args.  */
+                 args = c_parser_objc_message_args (parser);
+                 c_parser_skip_until_found (parser, CPP_CLOSE_SQUARE,
+                                            "expected %<]%>");
+                 mexpr.value
+                   = objc_build_message_expr (build_tree_list (rec, args));
+                 mexpr.original_code = ERROR_MARK;
+                 /* Now parse and process the remainder of the
+                    initializer, starting with this message
+                    expression as a primary-expression.  */
+                 c_parser_initval (parser, &mexpr);
+                 return;
+               }
+             c_parser_consume_token (parser);
+             first = c_parser_expr_no_commas (parser, NULL).value;
+           array_desig_after_first:
+             if (c_parser_next_token_is (parser, CPP_ELLIPSIS))
+               {
+                 c_parser_consume_token (parser);
+                 second = c_parser_expr_no_commas (parser, NULL).value;
+               }
+             else
+               second = NULL_TREE;
+             if (c_parser_next_token_is (parser, CPP_CLOSE_SQUARE))
+               {
+                 c_parser_consume_token (parser);
+                 set_init_index (first, second);
+                 if (pedantic && second)
+                   pedwarn ("ISO C forbids specifying range of "
+                            "elements to initialize");
+               }
+             else
+               c_parser_skip_until_found (parser, CPP_CLOSE_SQUARE,
+                                          "expected %<]%>");
+           }
+       }
+      if (des_seen >= 1)
+       {
+         if (c_parser_next_token_is (parser, CPP_EQ))
+           {
+             if (pedantic && !flag_isoc99)
+               pedwarn ("ISO C90 forbids specifying subobject to initialize");
+             c_parser_consume_token (parser);
+           }
+         else
+           {
+             if (des_seen == 1)
+               {
+                 if (pedantic)
+                   pedwarn ("obsolete use of designated initializer "
+                            "without %<=%>");
+               }
+             else
+               {
+                 struct c_expr init;
+                 init.value = error_mark_node;
+                 init.original_code = ERROR_MARK;
+                 c_parser_error (parser, "expected %<=%>");
+                 c_parser_skip_until_found (parser, CPP_COMMA, NULL);
+                 process_init_element (init);
+                 return;
+               }
+           }
+       }
+    }
+  c_parser_initval (parser, NULL);
+}
+
+/* Parse a nested initializer; as c_parser_initializer but parses
+   initializers within braced lists, after any designators have been
+   applied.  If AFTER is not NULL then it is an Objective-C message
+   expression which is the primary-expression starting the
+   initializer.  */
+
+static void
+c_parser_initval (c_parser *parser, struct c_expr *after)
+{
+  struct c_expr init;
+  gcc_assert (!after || c_dialect_objc ());
+  if (c_parser_next_token_is (parser, CPP_OPEN_BRACE) && !after)
+    init = c_parser_braced_init (parser, NULL_TREE, true);
+  else
+    init = c_parser_expr_no_commas (parser, after);
+  process_init_element (init);
+}
+
+/* Parse a compound statement (possibly a function body) (C90 6.6.2,
+   C99 6.8.2).
+
+   compound-statement:
+     { block-item-list[opt] }
+     { label-declarations block-item-list }
+
+   block-item-list:
+     block-item
+     block-item-list block-item
+
+   block-item:
+     nested-declaration
+     statement
+
+   nested-declaration:
+     declaration
+
+   GNU extensions:
+
+   compound-statement:
+     { label-declarations block-item-list }
+
+   nested-declaration:
+     __extension__ nested-declaration
+     nested-function-definition
+
+   label-declarations:
+     label-declaration
+     label-declarations label-declaration
+
+   label-declaration:
+     __label__ identifier-list ;
+
+   Allowing the mixing of declarations and code is new in C99.  The
+   GNU syntax also permits (not shown above) labels at the end of
+   compound statements, which yield an error.  We don't allow labels
+   on declarations; this might seem like a natural extension, but
+   there would be a conflict between attributes on the label and
+   prefix attributes on the declaration.  ??? The syntax follows the
+   old parser in requiring something after label declarations.
+   Although they are erroneous if the labels declared aren't defined,
+   is it useful for the syntax to be this way?  */
+
+static tree
+c_parser_compound_statement (c_parser *parser)
+{
+  tree stmt;
+  if (!c_parser_require (parser, CPP_OPEN_BRACE, "expected %<{%>"))
+    return NULL_TREE;
+  stmt = c_begin_compound_stmt (true);
+  c_parser_compound_statement_nostart (parser);
+  return c_end_compound_stmt (stmt, true);
+}
+
+/* Parse a compound statement except for the opening brace.  This is
+   used for parsing both compound statements and statement expressions
+   (which follow different paths to handling the opening).  */
+
+static void
+c_parser_compound_statement_nostart (c_parser *parser)
+{
+  bool last_stmt = false;
+  bool last_label = false;
+  if (c_parser_next_token_is (parser, CPP_CLOSE_BRACE))
+    {
+      c_parser_consume_token (parser);
+      return;
+    }
+  if (c_parser_next_token_is_keyword (parser, RID_LABEL))
+    {
+      /* Read zero or more forward-declarations for labels that nested
+        functions can jump to.  */
+      while (c_parser_next_token_is_keyword (parser, RID_LABEL))
+       {
+         c_parser_consume_token (parser);
+         /* Any identifiers, including those declared as type names,
+            are OK here.  */
+         while (true)
+           {
+             tree label;
+             if (c_parser_next_token_is_not (parser, CPP_NAME))
+               {
+                 c_parser_error (parser, "expected identifier");
+                 break;
+               }
+             label
+               = declare_label (c_parser_peek_token (parser)->value);
+             C_DECLARED_LABEL_FLAG (label) = 1;
+             add_stmt (build_stmt (DECL_EXPR, label));
+             c_parser_consume_token (parser);
+             if (c_parser_next_token_is (parser, CPP_COMMA))
+               c_parser_consume_token (parser);
+             else
+               break;
+           }
+         c_parser_skip_until_found (parser, CPP_SEMICOLON, "expected %<;%>");
+       }
+      /* ??? Locating this diagnostic on the token after the
+        declarations end follows the old parser, but it might be
+        better to locate it where the declarations start instead.  */
+      if (pedantic)
+       pedwarn ("ISO C forbids label declarations");
+    }
+  /* We must now have at least one statement, label or declaration.  */
+  if (c_parser_next_token_is (parser, CPP_CLOSE_BRACE))
+    {
+      c_parser_error (parser, "expected declaration or statement");
+      c_parser_consume_token (parser);
+      return;
+    }
+  while (c_parser_next_token_is_not (parser, CPP_CLOSE_BRACE))
+    {
+      location_t loc = c_parser_peek_token (parser)->location;
+      if (c_parser_next_token_is (parser, CPP_EOF))
+       {
+         parser->error = true;
+         return;
+       }
+      if (c_parser_next_token_is_keyword (parser, RID_CASE)
+         || c_parser_next_token_is_keyword (parser, RID_DEFAULT)
+         || (c_parser_next_token_is (parser, CPP_NAME)
+             && c_parser_peek_2nd_token (parser)->type == CPP_COLON))
+       {
+         last_label = true;
+         last_stmt = false;
+         c_parser_label (parser);
+       }
+      else if (!last_label
+              && c_parser_next_token_starts_declspecs (parser))
+       {
+         last_label = false;
+         c_parser_declaration_or_fndef (parser, true, true, true, true);
+         if (last_stmt
+             && ((pedantic && !flag_isoc99)
+                 || warn_declaration_after_statement))
+           pedwarn_c90 ("%HISO C90 forbids mixed declarations and code",
+                        &loc);
+         last_stmt = false;
+       }
+      else if (!last_label
+              && c_parser_next_token_is_keyword (parser, RID_EXTENSION))
+       {
+         /* __extension__ can start a declaration, but is also an
+            unary operator that can start an expression.  Consume all
+            but the last of a possible series of __extension__ to
+            determine which.  */
+         while (c_parser_peek_2nd_token (parser)->type == CPP_KEYWORD
+                && (c_parser_peek_2nd_token (parser)->keyword
+                    == RID_EXTENSION))
+           c_parser_consume_token (parser);
+         if (c_token_starts_declspecs (c_parser_peek_2nd_token (parser)))
+           {
+             int ext;
+             ext = disable_extension_diagnostics ();
+             c_parser_consume_token (parser);
+             last_label = false;
+             c_parser_declaration_or_fndef (parser, true, true, true, true);
+             /* Following the old parser, __extension__ does not
+                disable this diagnostic.  */
+             restore_extension_diagnostics (ext);
+             if (last_stmt
+                 && ((pedantic && !flag_isoc99)
+                     || warn_declaration_after_statement))
+               pedwarn_c90 ("%HISO C90 forbids mixed declarations and code",
+                            &loc);
+             last_stmt = false;
+           }
+         else
+           goto statement;
+       }
+      else
+       {
+       statement:
+         last_label = false;
+         last_stmt = true;
+         c_parser_statement_after_labels (parser);
+       }
+    }
+  if (last_label)
+    error ("label at end of compound statement");
+  c_parser_consume_token (parser);
+}
+
+/* Parse a label (C90 6.6.1, C99 6.8.1).
+
+   label:
+     identifier : attributes[opt]
+     case constant-expression :
+     default :
+
+   GNU extensions:
+
+   label:
+     case constant-expression ... constant-expression :
+
+   The use of attributes on labels is a GNU extension.  The syntax in
+   GNU C accepts any expressions without commas, non-constant
+   expressions being rejected later.  */
+
+static void
+c_parser_label (c_parser *parser)
+{
+  location_t loc1 = c_parser_peek_token (parser)->location;
+  tree label = NULL_TREE;
+  if (c_parser_next_token_is_keyword (parser, RID_CASE))
+    {
+      tree exp1, exp2;
+      c_parser_consume_token (parser);
+      exp1 = c_parser_expr_no_commas (parser, NULL).value;
+      if (c_parser_next_token_is (parser, CPP_COLON))
+       {
+         c_parser_consume_token (parser);
+         label = do_case (exp1, NULL_TREE);
+       }
+      else if (c_parser_next_token_is (parser, CPP_ELLIPSIS))
+       {
+         c_parser_consume_token (parser);
+         exp2 = c_parser_expr_no_commas (parser, NULL).value;
+         if (c_parser_require (parser, CPP_COLON, "expected %<:%>"))
+           label = do_case (exp1, exp2);
+       }
+      else
+       c_parser_error (parser, "expected %<:%> or %<...%>");
+    }
+  else if (c_parser_next_token_is_keyword (parser, RID_DEFAULT))
+    {
+      c_parser_consume_token (parser);
+      if (c_parser_require (parser, CPP_COLON, "expected %<:%>"))
+       label = do_case (NULL_TREE, NULL_TREE);
+    }
+  else
+    {
+      tree name = c_parser_peek_token (parser)->value;
+      tree tlab;
+      location_t loc2;
+      tree attrs;
+      gcc_assert (c_parser_next_token_is (parser, CPP_NAME));
+      c_parser_consume_token (parser);
+      gcc_assert (c_parser_next_token_is (parser, CPP_COLON));
+      loc2 = c_parser_peek_token (parser)->location;
+      c_parser_consume_token (parser);
+      attrs = c_parser_attributes (parser);
+      tlab = define_label (loc2, name);
+      if (tlab)
+       {
+         decl_attributes (&tlab, attrs, 0);
+         label = add_stmt (build_stmt (LABEL_EXPR, tlab));
+       }
+    }
+  if (label)
+    SET_EXPR_LOCATION (label, loc1);
+}
+
+/* Parse a statement (C90 6.6, C99 6.8).
+
+   statement:
+     labeled-statement
+     compound-statement
+     expression-statement
+     selection-statement
+     iteration-statement
+     jump-statement
+
+   labeled-statement:
+     label statement
+
+   expression-statement:
+     expression[opt] ;
+
+   selection-statement:
+     if-statement
+     switch-statement
+
+   iteration-statement:
+     while-statement
+     do-statement
+     for-statement
+
+   jump-statement:
+     goto identifier ;
+     continue ;
+     break ;
+     return expression[opt] ;
+
+   GNU extensions:
+
+   statement:
+     asm-statement
+
+   jump-statement:
+     goto * expression ;
+
+   Objective-C:
+
+   statement:
+     objc-throw-statement
+     objc-try-catch-statement
+     objc-synchronized-statement
+
+   objc-throw-statement:
+     @throw expression ;
+     @throw ;
+*/
+
+static void
+c_parser_statement (c_parser *parser)
+{
+  while (c_parser_next_token_is_keyword (parser, RID_CASE)
+        || c_parser_next_token_is_keyword (parser, RID_DEFAULT)
+        || (c_parser_next_token_is (parser, CPP_NAME)
+            && c_parser_peek_2nd_token (parser)->type == CPP_COLON))
+    c_parser_label (parser);
+  c_parser_statement_after_labels (parser);
+}
+
+/* Parse a statement, other than a labeled statement.  */
+
+static void
+c_parser_statement_after_labels (c_parser *parser)
+{
+  location_t loc = c_parser_peek_token (parser)->location;
+  tree stmt = NULL_TREE;
+  switch (c_parser_peek_token (parser)->type)
+    {
+    case CPP_OPEN_BRACE:
+      add_stmt (c_parser_compound_statement (parser));
+      break;
+    case CPP_KEYWORD:
+      switch (c_parser_peek_token (parser)->keyword)
+       {
+       case RID_IF:
+         c_parser_if_statement (parser);
+         break;
+       case RID_SWITCH:
+         c_parser_switch_statement (parser);
+         break;
+       case RID_WHILE:
+         c_parser_while_statement (parser);
+         break;
+       case RID_DO:
+         c_parser_do_statement (parser);
+         break;
+       case RID_FOR:
+         c_parser_for_statement (parser);
+         break;
+       case RID_GOTO:
+         c_parser_consume_token (parser);
+         if (c_parser_next_token_is (parser, CPP_NAME))
+           {
+             stmt = c_finish_goto_label (c_parser_peek_token (parser)->value);
+             c_parser_consume_token (parser);
+           }
+         else if (c_parser_next_token_is (parser, CPP_MULT))
+           {
+             c_parser_consume_token (parser);
+             stmt = c_finish_goto_ptr (c_parser_expression (parser).value);
+           }
+         else
+           c_parser_error (parser, "expected identifier or %<*%>");
+         goto expect_semicolon;
+       case RID_CONTINUE:
+         c_parser_consume_token (parser);
+         stmt = c_finish_bc_stmt (&c_cont_label, false);
+         goto expect_semicolon;
+       case RID_BREAK:
+         c_parser_consume_token (parser);
+         stmt = c_finish_bc_stmt (&c_break_label, true);
+         goto expect_semicolon;
+       case RID_RETURN:
+         c_parser_consume_token (parser);
+         if (c_parser_next_token_is (parser, CPP_SEMICOLON))
+           {
+             stmt = c_finish_return (NULL_TREE);
+             c_parser_consume_token (parser);
+           }
+         else
+           {
+             stmt = c_finish_return (c_parser_expression (parser).value);
+             goto expect_semicolon;
+           }
+         break;
+       case RID_ASM:
+         stmt = c_parser_asm_statement (parser);
+         break;
+       case RID_AT_THROW:
+         gcc_assert (c_dialect_objc ());
+         c_parser_consume_token (parser);
+         if (c_parser_next_token_is (parser, CPP_SEMICOLON))
+           {
+             stmt = objc_build_throw_stmt (NULL_TREE);
+             c_parser_consume_token (parser);
+           }
+         else
+           {
+             stmt
+               = objc_build_throw_stmt (c_parser_expression (parser).value);
+             goto expect_semicolon;
+           }
+         break;
+       case RID_AT_TRY:
+         gcc_assert (c_dialect_objc ());
+         c_parser_objc_try_catch_statement (parser);
+         break;
+       case RID_AT_SYNCHRONIZED:
+         gcc_assert (c_dialect_objc ());
+         c_parser_objc_synchronized_statement (parser);
+         break;
+       default:
+         goto expr_stmt;
+       }
+      break;
+    case CPP_SEMICOLON:
+      c_parser_consume_token (parser);
+      break;
+    case CPP_CLOSE_PAREN:
+    case CPP_CLOSE_SQUARE:
+      /* Avoid infinite loop in error recovery:
+        c_parser_skip_until_found stops at a closing nesting
+        delimiter without consuming it, but here we need to consume
+        it to proceed further.  */
+      c_parser_error (parser, "expected statement");
+      c_parser_consume_token (parser);
+      break;
+    default:
+    expr_stmt:
+      stmt = c_finish_expr_stmt (c_parser_expression (parser).value);
+    expect_semicolon:
+      c_parser_skip_until_found (parser, CPP_SEMICOLON, "expected %<;%>");
+      break;
+    }
+  /* 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 statements should already have
+     line numbers assigned.  ??? Can we discard no-op statements
+     earlier?  */
+  if (stmt && EXPR_P (stmt))
+    SET_EXPR_LOCATION (stmt, loc);
+}
+
+/* Parse a parenthesized condition from an if, do or while statement.
+
+   condition:
+     ( expression )
+*/
+static tree
+c_parser_paren_condition (c_parser *parser)
+{
+  location_t loc;
+  tree cond;
+  if (!c_parser_require (parser, CPP_OPEN_PAREN, "expected %<(%>"))
+    return error_mark_node;
+  loc = c_parser_peek_token (parser)->location;
+  cond = lang_hooks.truthvalue_conversion (c_parser_expression (parser).value);
+  if (EXPR_P (cond))
+    SET_EXPR_LOCATION (cond, loc);
+  c_parser_skip_until_found (parser, CPP_CLOSE_PAREN, "expected %<)%>");
+  return cond;
+}
+
+/* Parse a statement which is a block in C99.  */
+
+static tree
+c_parser_c99_block_statement (c_parser *parser)
+{
+  tree block = c_begin_compound_stmt (flag_isoc99);
+  c_parser_statement (parser);
+  return c_end_compound_stmt (block, flag_isoc99);
+}
+
+/* Parse the body of an if statement or the else half thereof.  This
+   is just parsing a statement but (a) it is a block in C99, (b) we
+   track whether the body is an if statement for the sake of
+   -Wparentheses warnings, (c) we handle an empty body specially for
+   the sake of -Wextra warnings.  */
+
+static tree
+c_parser_if_body (c_parser *parser, bool *if_p)
+{
+  tree block = c_begin_compound_stmt (flag_isoc99);
+  while (c_parser_next_token_is_keyword (parser, RID_CASE)
+        || c_parser_next_token_is_keyword (parser, RID_DEFAULT)
+        || (c_parser_next_token_is (parser, CPP_NAME)
+            && c_parser_peek_2nd_token (parser)->type == CPP_COLON))
+    c_parser_label (parser);
+  *if_p = c_parser_next_token_is_keyword (parser, RID_IF);
+  if (extra_warnings && c_parser_next_token_is (parser, CPP_SEMICOLON))
+    add_stmt (build (NOP_EXPR, NULL_TREE, NULL_TREE));
+  c_parser_statement_after_labels (parser);
+  return c_end_compound_stmt (block, flag_isoc99);
+}
+
+/* Parse an if statement (C90 6.6.4, C99 6.8.4).
+
+   if-statement:
+     if ( expression ) statement
+     if ( expression ) statement else statement
+*/
+
+static void
+c_parser_if_statement (c_parser *parser)
+{
+  tree block;
+  location_t loc;
+  tree cond;
+  bool first_if = false, second_if = false;
+  tree first_body, second_body;
+  gcc_assert (c_parser_next_token_is_keyword (parser, RID_IF));
+  c_parser_consume_token (parser);
+  block = c_begin_compound_stmt (flag_isoc99);
+  loc = c_parser_peek_token (parser)->location;
+  cond = c_parser_paren_condition (parser);
+  first_body = c_parser_if_body (parser, &first_if);
+  if (c_parser_next_token_is_keyword (parser, RID_ELSE))
+    {
+      c_parser_consume_token (parser);
+      second_body = c_parser_if_body (parser, &second_if);
+    }
+  else
+    second_body = NULL_TREE;
+  c_finish_if_stmt (loc, cond, first_body, second_body, first_if);
+  add_stmt (c_end_compound_stmt (block, flag_isoc99));
+}
+
+/* Parse a switch statement (C90 6.6.4, C99 6.8.4).
+
+   switch-statement:
+     switch (expression) statement
+*/
+
+static void
+c_parser_switch_statement (c_parser *parser)
+{
+  tree block, expr, body, save_break;
+  gcc_assert (c_parser_next_token_is_keyword (parser, RID_SWITCH));
+  c_parser_consume_token (parser);
+  block = c_begin_compound_stmt (flag_isoc99);
+  if (c_parser_require (parser, CPP_OPEN_PAREN, "expected %<(%>"))
+    {
+      expr = c_parser_expression (parser).value;
+      c_parser_skip_until_found (parser, CPP_CLOSE_PAREN, "expected %<)%>");
+    }
+  else
+    expr = error_mark_node;
+  c_start_case (expr);
+  save_break = c_break_label;
+  c_break_label = NULL_TREE;
+  body = c_parser_c99_block_statement (parser);
+  c_finish_case (body);
+  if (c_break_label)
+    add_stmt (build (LABEL_EXPR, void_type_node, c_break_label));
+  c_break_label = save_break;
+  add_stmt (c_end_compound_stmt (block, flag_isoc99));
+}
+
+/* Parse a while statement (C90 6.6.5, C99 6.8.5).
+
+   while-statement:
+      while (expression) statement
+*/
+
+static void
+c_parser_while_statement (c_parser *parser)
+{
+  tree block, cond, body, save_break, save_cont;
+  location_t loc;
+  gcc_assert (c_parser_next_token_is_keyword (parser, RID_WHILE));
+  c_parser_consume_token (parser);
+  block = c_begin_compound_stmt (flag_isoc99);
+  loc = c_parser_peek_token (parser)->location;
+  cond = c_parser_paren_condition (parser);
+  save_break = c_break_label;
+  c_break_label = NULL_TREE;
+  save_cont = c_cont_label;
+  c_cont_label = NULL_TREE;
+  body = c_parser_c99_block_statement (parser);
+  c_finish_loop (loc, cond, NULL, body, c_break_label, c_cont_label, true);
+  add_stmt (c_end_compound_stmt (block, flag_isoc99));
+  c_break_label = save_break;
+  c_cont_label = save_cont;
+}
+
+/* Parse a do statement (C90 6.6.5, C99 6.8.5).
+
+   do-statement:
+     do statement while ( expression ) ;
+*/
+
+static void
+c_parser_do_statement (c_parser *parser)
+{
+  tree block, cond, body, save_break, save_cont, new_break, new_cont;
+  location_t loc;
+  gcc_assert (c_parser_next_token_is_keyword (parser, RID_DO));
+  c_parser_consume_token (parser);
+  block = c_begin_compound_stmt (flag_isoc99);
+  loc = c_parser_peek_token (parser)->location;
+  save_break = c_break_label;
+  c_break_label = NULL_TREE;
+  save_cont = c_cont_label;
+  c_cont_label = NULL_TREE;
+  body = c_parser_c99_block_statement (parser);
+  c_parser_require_keyword (parser, RID_WHILE, "expected %<while%>");
+  new_break = c_break_label;
+  c_break_label = save_break;
+  new_cont = c_cont_label;
+  c_cont_label = save_cont;
+  cond = c_parser_paren_condition (parser);
+  if (!c_parser_require (parser, CPP_SEMICOLON, "expected %<;%>"))
+    c_parser_skip_to_end_of_block_or_statement (parser);
+  c_finish_loop (loc, cond, NULL, body, new_break, new_cont, false);
+  add_stmt (c_end_compound_stmt (block, flag_isoc99));
+}
+
+/* Parse a for statement (C90 6.6.5, C99 6.8.5).
+
+   for-statement:
+     for ( expression[opt] ; expression[opt] ; expression[opt] ) statement
+     for ( nested-declaration expression[opt] ; expression[opt] ) statement
+
+   The form with a declaration is new in C99.
+
+   ??? In accordance with the old parser, the declaration may be a
+   nested function, which is then rejected in check_for_loop_decls,
+   but does it make any sense for this to be included in the grammar?
+   Note in particular that the nested function does not include a
+   trailing ';', whereas the "declaration" production includes one.
+   Also, can we reject bad declarations earlier and cheaper than
+   check_for_loop_decls?  */
+
+static void
+c_parser_for_statement (c_parser *parser)
+{
+  tree block, cond, incr, save_break, save_cont, body;
+  location_t loc;
+  gcc_assert (c_parser_next_token_is_keyword (parser, RID_FOR));
+  c_parser_consume_token (parser);
+  block = c_begin_compound_stmt (flag_isoc99);
+  if (c_parser_require (parser, CPP_OPEN_PAREN, "expected %<(%>"))
+    {
+      /* Parse the initialization declaration or expression.  */
+      if (c_parser_next_token_is (parser, CPP_SEMICOLON))
+       {
+         c_parser_consume_token (parser);
+         c_finish_expr_stmt (NULL_TREE);
+       }
+      else if (c_parser_next_token_starts_declspecs (parser))
+       {
+         c_parser_declaration_or_fndef (parser, true, true, true, true);
+         check_for_loop_decls ();
+       }
+      else if (c_parser_next_token_is_keyword (parser, RID_EXTENSION))
+       {
+         /* __extension__ can start a declaration, but is also an
+            unary operator that can start an expression.  Consume all
+            but the last of a possible series of __extension__ to
+            determine which.  */
+         while (c_parser_peek_2nd_token (parser)->type == CPP_KEYWORD
+                && (c_parser_peek_2nd_token (parser)->keyword
+                    == RID_EXTENSION))
+           c_parser_consume_token (parser);
+         if (c_token_starts_declspecs (c_parser_peek_2nd_token (parser)))
+           {
+             int ext;
+             ext = disable_extension_diagnostics ();
+             c_parser_consume_token (parser);
+             c_parser_declaration_or_fndef (parser, true, true, true, true);
+             restore_extension_diagnostics (ext);
+             check_for_loop_decls ();
+           }
+         else
+           goto init_expr;
+       }
+      else
+       {
+       init_expr:
+         c_finish_expr_stmt (c_parser_expression (parser).value);
+         c_parser_skip_until_found (parser, CPP_SEMICOLON, "expected %<;%>");
+       }
+      /* Parse the loop condition.  */
+      loc = c_parser_peek_token (parser)->location;
+      if (c_parser_next_token_is (parser, CPP_SEMICOLON))
+       {
+         c_parser_consume_token (parser);
+         cond = NULL_TREE;
+       }
+      else
+       {
+         tree ocond = c_parser_expression (parser).value;
+         cond = lang_hooks.truthvalue_conversion (ocond);
+         if (EXPR_P (cond))
+           SET_EXPR_LOCATION (cond, loc);
+         c_parser_skip_until_found (parser, CPP_SEMICOLON, "expected %<;%>");
+       }
+      /* Parse the increment expression.  */
+      if (c_parser_next_token_is (parser, CPP_CLOSE_PAREN))
+       incr = c_process_expr_stmt (NULL_TREE);
+      else
+       incr = c_process_expr_stmt (c_parser_expression (parser).value);
+      c_parser_skip_until_found (parser, CPP_CLOSE_PAREN, "expected %<)%>");
+    }
+  else
+    {
+      cond = error_mark_node;
+      incr = error_mark_node;
+    }
+  save_break = c_break_label;
+  c_break_label = NULL_TREE;
+  save_cont = c_cont_label;
+  c_cont_label = NULL_TREE;
+  body = c_parser_c99_block_statement (parser);
+  c_finish_loop (loc, cond, incr, body, c_break_label, c_cont_label, true);
+  add_stmt (c_end_compound_stmt (block, flag_isoc99));
+  c_break_label = save_break;
+  c_cont_label = save_cont;
+}
+
+/* Parse an asm statement, a GNU extension.  This is a full-blown asm
+   statement with inputs, outputs, clobbers, and volatile tag
+   allowed.
+
+   asm-statement:
+     asm type-qualifier[opt] ( asm-argument ) ;
+
+   asm-argument:
+     asm-string-literal
+     asm-string-literal : asm-operands[opt]
+     asm-string-literal : asm-operands[opt] : asm-operands[opt]
+     asm-string-literal : asm-operands[opt] : asm-operands[opt] : asm-clobbers
+
+   Qualifiers other than volatile are accepted in the syntax but
+   warned for.  */
+
+static tree
+c_parser_asm_statement (c_parser *parser)
+{
+  tree quals, str, outputs, inputs, clobbers, ret;
+  bool simple;
+  gcc_assert (c_parser_next_token_is_keyword (parser, RID_ASM));
+  c_parser_consume_token (parser);
+  if (c_parser_next_token_is_keyword (parser, RID_VOLATILE))
+    {
+      quals = c_parser_peek_token (parser)->value;
+      c_parser_consume_token (parser);
+    }
+  else if (c_parser_next_token_is_keyword (parser, RID_CONST)
+          || c_parser_next_token_is_keyword (parser, RID_RESTRICT))
+    {
+      warning ("%E qualifier ignored on asm",
+              c_parser_peek_token (parser)->value);
+      quals = NULL_TREE;
+      c_parser_consume_token (parser);
+    }
+  else
+    quals = NULL_TREE;
+  /* ??? Follow the C++ parser rather than using the
+     c_lex_string_translate kludge.  */
+  c_lex_string_translate = 0;
+  if (!c_parser_require (parser, CPP_OPEN_PAREN, "expected %<(%>"))
+    {
+      c_lex_string_translate = 1;
+      return NULL_TREE;
+    }
+  str = c_parser_asm_string_literal (parser);
+  if (c_parser_next_token_is (parser, CPP_CLOSE_PAREN))
+    {
+      simple = true;
+      outputs = NULL_TREE;
+      inputs = NULL_TREE;
+      clobbers = NULL_TREE;
+      goto done_asm;
+    }
+  if (!c_parser_require (parser, CPP_COLON, "expected %<:%> or %<)%>"))
+    {
+      c_lex_string_translate = 1;
+      c_parser_skip_until_found (parser, CPP_CLOSE_PAREN, NULL);
+      return NULL_TREE;
+    }
+  simple = false;
+  /* Parse outputs.  */
+  if (c_parser_next_token_is (parser, CPP_COLON)
+      || c_parser_next_token_is (parser, CPP_CLOSE_PAREN))
+    outputs = NULL_TREE;
+  else
+    outputs = c_parser_asm_operands (parser);
+  if (c_parser_next_token_is (parser, CPP_CLOSE_PAREN))
+    {
+      inputs = NULL_TREE;
+      clobbers = NULL_TREE;
+      goto done_asm;
+    }
+  if (!c_parser_require (parser, CPP_COLON, "expected %<:%> or %<)%>"))
+    {
+      c_lex_string_translate = 1;
+      c_parser_skip_until_found (parser, CPP_CLOSE_PAREN, NULL);
+      return NULL_TREE;
+    }
+  /* Parse inputs.  */
+  if (c_parser_next_token_is (parser, CPP_COLON)
+      || c_parser_next_token_is (parser, CPP_CLOSE_PAREN))
+    inputs = NULL_TREE;
+  else
+    inputs = c_parser_asm_operands (parser);
+  if (c_parser_next_token_is (parser, CPP_CLOSE_PAREN))
+    {
+      clobbers = NULL_TREE;
+      goto done_asm;
+    }
+  if (!c_parser_require (parser, CPP_COLON, "expected %<:%> or %<)%>"))
+    {
+      c_lex_string_translate = 1;
+      c_parser_skip_until_found (parser, CPP_CLOSE_PAREN, NULL);
+      return NULL_TREE;
+    }
+  /* Parse clobbers.  */
+  clobbers = c_parser_asm_clobbers (parser);
+ done_asm:
+  c_lex_string_translate = 1;
+  if (!c_parser_require (parser, CPP_CLOSE_PAREN, "expected %<)%>"))
+    {
+      c_parser_skip_until_found (parser, CPP_CLOSE_PAREN, NULL);
+      return NULL_TREE;
+    }
+  if (!c_parser_require (parser, CPP_SEMICOLON, "expected %<;%>"))
+    c_parser_skip_to_end_of_block_or_statement (parser);
+  ret = build_asm_stmt (quals, build_asm_expr (str, outputs, inputs,
+                                              clobbers, simple));
+  return ret;
+}
+
+/* Parse asm operands, a GNU extension.
+
+   asm-operands:
+     asm-operand
+     asm-operands , asm-operand
+
+   asm-operand:
+     asm-string-literal ( expression )
+     [ identifier ] asm-string-literal ( expression )
+*/
+
+static tree
+c_parser_asm_operands (c_parser *parser)
+{
+  tree list = NULL_TREE;
+  while (true)
+    {
+      tree name, str, expr;
+      if (c_parser_next_token_is (parser, CPP_OPEN_SQUARE))
+       {
+         c_parser_consume_token (parser);
+         if (c_parser_next_token_is (parser, CPP_NAME))
+           {
+             tree id = c_parser_peek_token (parser)->value;
+             c_parser_consume_token (parser);
+             name = build_string (IDENTIFIER_LENGTH (id),
+                                  IDENTIFIER_POINTER (id));
+           }
+         else
+           {
+             c_parser_error (parser, "expected identifier");
+             c_parser_skip_until_found (parser, CPP_CLOSE_SQUARE, NULL);
+             return NULL_TREE;
+           }
+         c_parser_skip_until_found (parser, CPP_CLOSE_SQUARE,
+                                    "expected %<]%>");
+       }
+      else
+       name = NULL_TREE;
+      str = c_parser_asm_string_literal (parser);
+      if (str == NULL_TREE)
+       return NULL_TREE;
+      c_lex_string_translate = 1;
+      if (!c_parser_require (parser, CPP_OPEN_PAREN, "expected %<(%>"))
+       {
+         c_lex_string_translate = 0;
+         return NULL_TREE;
+       }
+      expr = c_parser_expression (parser).value;
+      c_lex_string_translate = 0;
+      if (!c_parser_require (parser, CPP_CLOSE_PAREN, "expected %<)%>"))
+       {
+         c_parser_skip_until_found (parser, CPP_CLOSE_PAREN, NULL);
+         return NULL_TREE;
+       }
+      list = chainon (list, build_tree_list (build_tree_list (name, str),
+                                            expr));
+      if (c_parser_next_token_is (parser, CPP_COMMA))
+       c_parser_consume_token (parser);
+      else
+       break;
+    }
+  return list;
+}
+
+/* Parse asm clobbers, a GNU extension.
+
+   asm-clobbers:
+     asm-string-literal
+     asm-clobbers , asm-string-literal
+*/
+
+static tree
+c_parser_asm_clobbers (c_parser *parser)
+{
+  tree list = NULL_TREE;
+  while (true)
+    {
+      tree str = c_parser_asm_string_literal (parser);
+      if (str)
+       list = tree_cons (NULL_TREE, str, list);
+      else
+       return NULL_TREE;
+      if (c_parser_next_token_is (parser, CPP_COMMA))
+       c_parser_consume_token (parser);
+      else
+       break;
+    }
+  return list;
+}
+
+/* Parse an expression other than a compound expression; that is, an
+   assignment expression (C90 6.3.16, C99 6.5.16).  If AFTER is not
+   NULL then it is an Objective-C message expression which is the
+   primary-expression starting the expression as an initializer.
+
+   assignment-expression:
+     conditional-expression
+     unary-expression assignment-operator assignment-expression
+
+   assignment-operator: one of
+     = *= /= %= += -= <<= >>= &= ^= |=
+
+   In GNU C we accept any conditional expression on the LHS and
+   diagnose the invalid lvalue rather than producing a syntax
+   error.  */
+
+static struct c_expr
+c_parser_expr_no_commas (c_parser *parser, struct c_expr *after)
+{
+  struct c_expr lhs, rhs, ret;
+  enum tree_code code;
+  gcc_assert (!after || c_dialect_objc ());
+  lhs = c_parser_conditional_expression (parser, after);
+  switch (c_parser_peek_token (parser)->type)
+    {
+    case CPP_EQ:
+      code = NOP_EXPR;
+      break;
+    case CPP_MULT_EQ:
+      code = MULT_EXPR;
+      break;
+    case CPP_DIV_EQ:
+      code = TRUNC_DIV_EXPR;
+      break;
+    case CPP_MOD_EQ:
+      code = TRUNC_MOD_EXPR;
+      break;
+    case CPP_PLUS_EQ:
+      code = PLUS_EXPR;
+      break;
+    case CPP_MINUS_EQ:
+      code = MINUS_EXPR;
+      break;
+    case CPP_LSHIFT_EQ:
+      code = LSHIFT_EXPR;
+      break;
+    case CPP_RSHIFT_EQ:
+      code = RSHIFT_EXPR;
+      break;
+    case CPP_AND_EQ:
+      code = BIT_AND_EXPR;
+      break;
+    case CPP_XOR_EQ:
+      code = BIT_XOR_EXPR;
+      break;
+    case CPP_OR_EQ:
+      code = BIT_IOR_EXPR;
+      break;
+    default:
+      return lhs;
+    }
+  c_parser_consume_token (parser);
+  rhs = c_parser_expr_no_commas (parser, NULL);
+  ret.value = build_modify_expr (lhs.value, code, rhs.value);
+  if (code == NOP_EXPR)
+    ret.original_code = MODIFY_EXPR;
+  else
+    {
+      TREE_NO_WARNING (ret.value) = 1;
+      ret.original_code = ERROR_MARK;
+    }
+  return ret;
+}
+
+/* Parse a conditional expression (C90 6.3.15, C99 6.5.15).  If AFTER
+   is not NULL then it is an Objective-C message expression which is
+   the primary-expression starting the expression as an initializer.
+
+   conditional-expression:
+     logical-OR-expression
+     logical-OR-expression ? expression : conditional-expression
+
+   GNU extensions:
+
+   conditional-expression:
+     logical-OR-expression ? : conditional-expression
+*/
+
+static struct c_expr
+c_parser_conditional_expression (c_parser *parser, struct c_expr *after)
+{
+  struct c_expr cond, exp1, exp2, ret;
+  gcc_assert (!after || c_dialect_objc ());
+  cond = c_parser_binary_expression (parser, after);
+  if (c_parser_next_token_is_not (parser, CPP_QUERY))
+    return cond;
+  c_parser_consume_token (parser);
+  if (c_parser_next_token_is (parser, CPP_COLON))
+    {
+      if (pedantic)
+       pedwarn ("ISO C forbids omitting the middle term of a ?: expression");
+      /* Make sure first operand is calculated only once.  */
+      exp1.value = save_expr (default_conversion (cond.value));
+      cond.value = lang_hooks.truthvalue_conversion (exp1.value);
+      skip_evaluation += cond.value == truthvalue_true_node;
+    }
+  else
+    {
+      cond.value
+       = lang_hooks.truthvalue_conversion (default_conversion (cond.value));
+      skip_evaluation += cond.value == truthvalue_false_node;
+      exp1 = c_parser_expression (parser);
+      skip_evaluation += ((cond.value == truthvalue_true_node)
+                         - (cond.value == truthvalue_false_node));
+    }
+  if (!c_parser_require (parser, CPP_COLON, "expected %<:%>"))
+    {
+      skip_evaluation -= cond.value == truthvalue_true_node;
+      ret.value = error_mark_node;
+      ret.original_code = ERROR_MARK;
+      return ret;
+    }
+  exp2 = c_parser_conditional_expression (parser, NULL);
+  skip_evaluation -= cond.value == truthvalue_true_node;
+  ret.value = build_conditional_expr (cond.value, exp1.value, exp2.value);
+  ret.original_code = ERROR_MARK;
+  return ret;
+}
+
+/* Parse a binary expression; that is, a logical-OR-expression (C90
+   6.3.5-6.3.14, C99 6.5.5-6.5.14).  If AFTER is not NULL then it is
+   an Objective-C message expression which is the primary-expression
+   starting the expression as an initializer.
+
+   multiplicative-expression:
+     cast-expression
+     multiplicative-expression * cast-expression
+     multiplicative-expression / cast-expression
+     multiplicative-expression % cast-expression
+
+   additive-expression:
+     multiplicative-expression
+     additive-expression + multiplicative-expression
+     additive-expression - multiplicative-expression
+
+   shift-expression:
+     additive-expression
+     shift-expression << additive-expression
+     shift-expression >> additive-expression
+
+   relational-expression:
+     shift-expression
+     relational-expression < shift-expression
+     relational-expression > shift-expression
+     relational-expression <= shift-expression
+     relational-expression >= shift-expression
+
+   equality-expression:
+     relational-expression
+     equality-expression == relational-expression
+     equality-expression != relational-expression
+
+   AND-expression:
+     equality-expression
+     AND-expression & equality-expression
+
+   exclusive-OR-expression:
+     AND-expression
+     exclusive-OR-expression ^ AND-expression
+
+   inclusive-OR-expression:
+     exclusive-OR-expression
+     inclusive-OR-expression | exclusive-OR-expression
+
+   logical-AND-expression:
+     inclusive-OR-expression
+     logical-AND-expression && inclusive-OR-expression
+
+   logical-OR-expression:
+     logical-AND-expression
+     logical-OR-expression || logical-AND-expression
+*/
+
+static struct c_expr
+c_parser_binary_expression (c_parser *parser, struct c_expr *after)
+{
+  /* A binary expression is parsed using operator-precedence parsing,
+     with the operands being cast expressions.  All the binary
+     operators are left-associative.  Thus a binary expression is of
+     form:
+
+     E0 op1 E1 op2 E2 ...
+
+     which we represent on a stack.  On the stack, the precedence
+     levels are strictly increasing.  When a new operator is
+     encountered of higher precedence than that at the top of the
+     stack, it is pushed; its LHS is the top expression, and its RHS
+     is everything parsed until it is popped.  When a new operator is
+     encountered with precedence less than or equal to that at the top
+     of the stack, triples E[i-1] op[i] E[i] are popped and replaced
+     by the result of the operation until the operator at the top of
+     the stack has lower precedence than the new operator or there is
+     only one element on the stack; then the top expression is the LHS
+     of the new operator.  In the case of logical AND and OR
+     expressions, we also need to adjust skip_evaluation as
+     appropriate when the operators are pushed and popped.  */
+
+  /* The precedence levels, where 0 is a dummy lowest level used for
+     the bottom of the stack.  */
+  enum prec {
+    PREC_NONE,
+    PREC_LOGOR,
+    PREC_LOGAND,
+    PREC_BITOR,
+    PREC_BITXOR,
+    PREC_BITAND,
+    PREC_EQ,
+    PREC_REL,
+    PREC_SHIFT,
+    PREC_ADD,
+    PREC_MULT,
+    NUM_PRECS
+  };
+  struct {
+    /* The expression at this stack level.  */
+    struct c_expr expr;
+    /* The precedence of the operator on its left, PREC_NONE at the
+       bottom of the stack.  */
+    enum prec prec;
+    /* The operation on its left.  */
+    enum tree_code op;
+  } stack[NUM_PRECS];
+  int sp;
+#define POP                                                                  \
+  do {                                                                       \
+    switch (stack[sp].op)                                                    \
+      {                                                                              \
+      case TRUTH_ANDIF_EXPR:                                                 \
+       skip_evaluation -= stack[sp - 1].expr.value == truthvalue_false_node; \
+       break;                                                                \
+      case TRUTH_ORIF_EXPR:                                                  \
+       skip_evaluation -= stack[sp - 1].expr.value == truthvalue_true_node;  \
+       break;                                                                \
+      default:                                                               \
+       break;                                                                \
+      }                                                                              \
+    stack[sp - 1].expr = parser_build_binary_op (stack[sp].op,               \
+                                                stack[sp - 1].expr,          \
+                                                stack[sp].expr);             \
+    sp--;                                                                    \
+  } while (0)
+  gcc_assert (!after || c_dialect_objc ());
+  stack[0].expr = c_parser_cast_expression (parser, after);
+  stack[0].prec = PREC_NONE;
+  sp = 0;
+  while (true)
+    {
+      enum prec oprec;
+      enum tree_code ocode;
+      if (parser->error)
+       goto out;
+      switch (c_parser_peek_token (parser)->type)
+       {
+       case CPP_MULT:
+         oprec = PREC_MULT;
+         ocode = MULT_EXPR;
+         break;
+       case CPP_DIV:
+         oprec = PREC_MULT;
+         ocode = TRUNC_DIV_EXPR;
+         break;
+       case CPP_MOD:
+         oprec = PREC_MULT;
+         ocode = TRUNC_MOD_EXPR;
+         break;
+       case CPP_PLUS:
+         oprec = PREC_ADD;
+         ocode = PLUS_EXPR;
+         break;
+       case CPP_MINUS:
+         oprec = PREC_ADD;
+         ocode = MINUS_EXPR;
+         break;
+       case CPP_LSHIFT:
+         oprec = PREC_SHIFT;
+         ocode = LSHIFT_EXPR;
+         break;
+       case CPP_RSHIFT:
+         oprec = PREC_SHIFT;
+         ocode = RSHIFT_EXPR;
+         break;
+       case CPP_LESS:
+         oprec = PREC_REL;
+         ocode = LT_EXPR;
+         break;
+       case CPP_GREATER:
+         oprec = PREC_REL;
+         ocode = GT_EXPR;
+         break;
+       case CPP_LESS_EQ:
+         oprec = PREC_REL;
+         ocode = LE_EXPR;
+         break;
+       case CPP_GREATER_EQ:
+         oprec = PREC_REL;
+         ocode = GE_EXPR;
+         break;
+       case CPP_EQ_EQ:
+         oprec = PREC_EQ;
+         ocode = EQ_EXPR;
+         break;
+       case CPP_NOT_EQ:
+         oprec = PREC_EQ;
+         ocode = NE_EXPR;
+         break;
+       case CPP_AND:
+         oprec = PREC_BITAND;
+         ocode = BIT_AND_EXPR;
+         break;
+       case CPP_XOR:
+         oprec = PREC_BITXOR;
+         ocode = BIT_XOR_EXPR;
+         break;
+       case CPP_OR:
+         oprec = PREC_BITOR;
+         ocode = BIT_IOR_EXPR;
+         break;
+       case CPP_AND_AND:
+         oprec = PREC_LOGAND;
+         ocode = TRUTH_ANDIF_EXPR;
+         break;
+       case CPP_OR_OR:
+         oprec = PREC_LOGOR;
+         ocode = TRUTH_ORIF_EXPR;
+         break;
+       default:
+         /* Not a binary operator, so end of the binary
+            expression.  */
+         goto out;
+       }
+      c_parser_consume_token (parser);
+      while (oprec <= stack[sp].prec)
+       POP;
+      switch (ocode)
+       {
+       case TRUTH_ANDIF_EXPR:
+         stack[sp].expr.value = lang_hooks.truthvalue_conversion
+           (default_conversion (stack[sp].expr.value));
+         skip_evaluation += stack[sp].expr.value == truthvalue_false_node;
+         break;
+       case TRUTH_ORIF_EXPR:
+         stack[sp].expr.value = lang_hooks.truthvalue_conversion
+           (default_conversion (stack[sp].expr.value));
+         skip_evaluation += stack[sp].expr.value == truthvalue_true_node;
+         break;
+       default:
+         break;
+       }
+      sp++;
+      stack[sp].expr = c_parser_cast_expression (parser, NULL);
+      stack[sp].prec = oprec;
+      stack[sp].op = ocode;
+    }
+ out:
+  while (sp > 0)
+    POP;
+  return stack[0].expr;
+#undef POP
+}
+
+/* Parse a cast expression (C90 6.3.4, C99 6.5.4).  If AFTER is not
+   NULL then it is an Objective-C message expression which is the
+   primary-expression starting the expression as an initializer.
+
+   cast-expression:
+     unary-expression
+     ( type-name ) unary-expression
+*/
+
+static struct c_expr
+c_parser_cast_expression (c_parser *parser, struct c_expr *after)
+{
+  gcc_assert (!after || c_dialect_objc ());
+  if (after)
+    return c_parser_postfix_expression_after_primary (parser, *after);
+  /* If the expression begins with a parenthesized type name, it may
+     be either a cast or a compound literal; we need to see whether
+     the next character is '{' to tell the difference.  If not, it is
+     an unary expression.  */
+  if (c_parser_next_token_is (parser, CPP_OPEN_PAREN)
+      && c_token_starts_typename (c_parser_peek_2nd_token (parser)))
+    {
+      struct c_type_name *type_name;
+      struct c_expr ret;
+      tree expr;
+      c_parser_consume_token (parser);
+      type_name = c_parser_type_name (parser);
+      c_parser_skip_until_found (parser, CPP_CLOSE_PAREN, "expected %<)%>");
+      if (type_name == NULL)
+       {
+         ret.value = error_mark_node;
+         ret.original_code = ERROR_MARK;
+         return ret;
+       }
+      if (c_parser_next_token_is (parser, CPP_OPEN_BRACE))
+       return c_parser_postfix_expression_after_paren_type (parser,
+                                                            type_name);
+      expr = c_parser_cast_expression (parser, NULL).value;
+      ret.value = c_cast_expr (type_name, expr);
+      ret.original_code = ERROR_MARK;
+      return ret;
+    }
+  else
+    return c_parser_unary_expression (parser);
+}
+
+/* Parse an unary expression (C90 6.3.3, C99 6.5.3).
+
+   unary-expression:
+     postfix-expression
+     ++ unary-expression
+     -- unary-expression
+     unary-operator cast-expression
+     sizeof unary-expression
+     sizeof ( type-name )
+
+   unary-operator: one of
+     & * + - ~ !
+
+   GNU extensions:
+
+   unary-expression:
+     __alignof__ unary-expression
+     __alignof__ ( type-name )
+     && identifier
+
+   unary-operator: one of
+     __extension__ __real__ __imag__
+
+   In addition, the GNU syntax treats ++ and -- as unary operators, so
+   they may be applied to cast expressions with errors for non-lvalues
+   given later.  */
+
+static struct c_expr
+c_parser_unary_expression (c_parser *parser)
+{
+  int ext;
+  struct c_expr ret;
+  ret.original_code = ERROR_MARK;
+  switch (c_parser_peek_token (parser)->type)
+    {
+    case CPP_PLUS_PLUS:
+      c_parser_consume_token (parser);
+      ret.value
+       = build_unary_op (PREINCREMENT_EXPR,
+                         c_parser_cast_expression (parser, NULL).value, 0);
+      overflow_warning (ret.value);
+      return ret;
+    case CPP_MINUS_MINUS:
+      c_parser_consume_token (parser);
+      ret.value
+       = build_unary_op (PREDECREMENT_EXPR,
+                         c_parser_cast_expression (parser, NULL).value, 0);
+      overflow_warning (ret.value);
+      return ret;
+    case CPP_AND:
+      c_parser_consume_token (parser);
+      ret.value
+       = build_unary_op (ADDR_EXPR,
+                         c_parser_cast_expression (parser, NULL).value, 0);
+      overflow_warning (ret.value);
+      return ret;
+    case CPP_MULT:
+      c_parser_consume_token (parser);
+      ret.value
+       = build_indirect_ref (c_parser_cast_expression (parser, NULL).value,
+                             "unary *");
+      return ret;
+    case CPP_PLUS:
+      c_parser_consume_token (parser);
+      if (!c_dialect_objc () && warn_traditional && !in_system_header)
+       warning ("traditional C rejects the unary plus operator");
+      ret.value
+       = build_unary_op (CONVERT_EXPR,
+                         c_parser_cast_expression (parser, NULL).value, 0);
+      overflow_warning (ret.value);
+      return ret;
+    case CPP_MINUS:
+      c_parser_consume_token (parser);
+      ret.value
+       = build_unary_op (NEGATE_EXPR,
+                         c_parser_cast_expression (parser, NULL).value, 0);
+      overflow_warning (ret.value);
+      return ret;
+    case CPP_COMPL:
+      c_parser_consume_token (parser);
+      ret.value
+       = build_unary_op (BIT_NOT_EXPR,
+                         c_parser_cast_expression (parser, NULL).value, 0);
+      overflow_warning (ret.value);
+      return ret;
+    case CPP_NOT:
+      c_parser_consume_token (parser);
+      ret.value
+       = build_unary_op (TRUTH_NOT_EXPR,
+                         c_parser_cast_expression (parser, NULL).value, 0);
+      overflow_warning (ret.value);
+      return ret;
+    case CPP_AND_AND:
+      /* Refer to the address of a label as a pointer.  */
+      c_parser_consume_token (parser);
+      if (c_parser_next_token_is (parser, CPP_NAME))
+       {
+         ret.value = finish_label_address_expr
+           (c_parser_peek_token (parser)->value);
+         c_parser_consume_token (parser);
+         return ret;
+       }
+      else
+       {
+         c_parser_error (parser, "expected identifier");
+         ret.value = error_mark_node;
+         return ret;
+       }
+    case CPP_KEYWORD:
+      switch (c_parser_peek_token (parser)->keyword)
+       {
+       case RID_SIZEOF:
+         return c_parser_sizeof_expression (parser);
+       case RID_ALIGNOF:
+         return c_parser_alignof_expression (parser);
+       case RID_EXTENSION:
+         c_parser_consume_token (parser);
+         ext = disable_extension_diagnostics ();
+         ret = c_parser_cast_expression (parser, NULL);
+         restore_extension_diagnostics (ext);
+         return ret;
+       case RID_REALPART:
+         c_parser_consume_token (parser);
+         ret.value
+           = build_unary_op (REALPART_EXPR,
+                             c_parser_cast_expression (parser, NULL).value,
+                             0);
+         return ret;
+       case RID_IMAGPART:
+         c_parser_consume_token (parser);
+         ret.value
+           = build_unary_op (IMAGPART_EXPR,
+                             c_parser_cast_expression (parser, NULL).value,
+                             0);
+         return ret;
+       default:
+         return c_parser_postfix_expression (parser);
+       }
+    default:
+      return c_parser_postfix_expression (parser);
+    }
+}
+
+/* Parse a sizeof expression.  */
+
+static struct c_expr
+c_parser_sizeof_expression (c_parser *parser)
+{
+  struct c_expr expr;
+  gcc_assert (c_parser_next_token_is_keyword (parser, RID_SIZEOF));
+  c_parser_consume_token (parser);
+  skip_evaluation++;
+  in_sizeof++;
+  if (c_parser_next_token_is (parser, CPP_OPEN_PAREN)
+      && c_token_starts_typename (c_parser_peek_2nd_token (parser)))
+    {
+      /* Either sizeof ( type-name ) or sizeof unary-expression
+        starting with a compound literal.  */
+      struct c_type_name *type_name;
+      c_parser_consume_token (parser);
+      type_name = c_parser_type_name (parser);
+      c_parser_skip_until_found (parser, CPP_CLOSE_PAREN, "expected %<)%>");
+      if (type_name == NULL)
+       {
+         struct c_expr ret;
+         skip_evaluation--;
+         in_sizeof--;
+         ret.value = error_mark_node;
+         ret.original_code = ERROR_MARK;
+         return ret;
+       }
+      if (c_parser_next_token_is (parser, CPP_OPEN_BRACE))
+       {
+         expr = c_parser_postfix_expression_after_paren_type (parser,
+                                                              type_name);
+         goto sizeof_expr;
+       }
+      /* sizeof ( type-name ).  */
+      skip_evaluation--;
+      in_sizeof--;
+      return c_expr_sizeof_type (type_name);
+    }
+  else
+    {
+      expr = c_parser_unary_expression (parser);
+    sizeof_expr:
+      skip_evaluation--;
+      in_sizeof--;
+      if (TREE_CODE (expr.value) == COMPONENT_REF
+         && DECL_C_BIT_FIELD (TREE_OPERAND (expr.value, 1)))
+       error ("%<sizeof%> applied to a bit-field");
+      return c_expr_sizeof_expr (expr);
+    }
+}
+
+/* Parse an alignof expression.  */
+
+static struct c_expr
+c_parser_alignof_expression (c_parser *parser)
+{
+  struct c_expr expr;
+  gcc_assert (c_parser_next_token_is_keyword (parser, RID_ALIGNOF));
+  c_parser_consume_token (parser);
+  skip_evaluation++;
+  in_alignof++;
+  if (c_parser_next_token_is (parser, CPP_OPEN_PAREN)
+      && c_token_starts_typename (c_parser_peek_2nd_token (parser)))
+    {
+      /* Either __alignof__ ( type-name ) or __alignof__
+        unary-expression starting with a compound literal.  */
+      struct c_type_name *type_name;
+      struct c_expr ret;
+      c_parser_consume_token (parser);
+      type_name = c_parser_type_name (parser);
+      c_parser_skip_until_found (parser, CPP_CLOSE_PAREN, "expected %<)%>");
+      if (type_name == NULL)
+       {
+         struct c_expr ret;
+         skip_evaluation--;
+         in_alignof--;
+         ret.value = error_mark_node;
+         ret.original_code = ERROR_MARK;
+         return ret;
+       }
+      if (c_parser_next_token_is (parser, CPP_OPEN_BRACE))
+       {
+         expr = c_parser_postfix_expression_after_paren_type (parser,
+                                                              type_name);
+         goto alignof_expr;
+       }
+      /* alignof ( type-name ).  */
+      skip_evaluation--;
+      in_alignof--;
+      ret.value = c_alignof (groktypename (type_name));
+      ret.original_code = ERROR_MARK;
+      return ret;
+    }
+  else
+    {
+      struct c_expr ret;
+      expr = c_parser_unary_expression (parser);
+    alignof_expr:
+      skip_evaluation--;
+      in_alignof--;
+      ret.value = c_alignof_expr (expr.value);
+      ret.original_code = ERROR_MARK;
+      return ret;
+    }
+}
+
+/* Parse a postfix expression (C90 6.3.1-6.3.2, C99 6.5.1-6.5.2).
+
+   postfix-expression:
+     primary-expression
+     postfix-expression [ expression ]
+     postfix-expression ( argument-expression-list[opt] )
+     postfix-expression . identifier
+     postfix-expression -> identifier
+     postfix-expression ++
+     postfix-expression --
+     ( type-name ) { initializer-list }
+     ( type-name ) { initializer-list , }
+
+   argument-expression-list:
+     argument-expression
+     argument-expression-list , argument-expression
+
+   primary-expression:
+     identifier
+     constant
+     string-literal
+     ( expression )
+
+   GNU extensions:
+
+   primary-expression:
+     __func__
+       (treated as a keyword in GNU C)
+     __FUNCTION__
+     __PRETTY_FUNCTION__
+     ( compound-statement )
+     __builtin_va_arg ( assignment-expression , type-name )
+     __builtin_offsetof ( type-name , offsetof-member-designator )
+     __builtin_choose_expr ( assignment-expression ,
+                            assignment-expression ,
+                            assignment-expression )
+     __builtin_types_compatible_p ( type-name , type-name )
+
+   offsetof-member-designator:
+     identifier
+     offsetof-member-designator . identifier
+     offsetof-member-designator [ expression ]
+
+   Objective-C:
+
+   primary-expression:
+     [ objc-receiver objc-message-args ]
+     @selector ( objc-selector-arg )
+     @protocol ( identifier )
+     @encode ( type-name )
+     objc-string-literal
+*/
+
+static struct c_expr
+c_parser_postfix_expression (c_parser *parser)
+{
+  struct c_expr expr, e1, e2, e3;
+  struct c_type_name *t1, *t2;
+  switch (c_parser_peek_token (parser)->type)
+    {
+    case CPP_NUMBER:
+    case CPP_CHAR:
+    case CPP_WCHAR:
+      expr.value = c_parser_peek_token (parser)->value;
+      expr.original_code = ERROR_MARK;
+      c_parser_consume_token (parser);
+      break;
+    case CPP_STRING:
+    case CPP_WSTRING:
+      expr.value = c_parser_peek_token (parser)->value;
+      expr.original_code = STRING_CST;
+      c_parser_consume_token (parser);
+      break;
+    case CPP_OBJC_STRING:
+      gcc_assert (c_dialect_objc ());
+      expr.value
+       = objc_build_string_object (c_parser_peek_token (parser)->value);
+      expr.original_code = ERROR_MARK;
+      c_parser_consume_token (parser);
+      break;
+    case CPP_NAME:
+      if (c_parser_peek_token (parser)->id_kind != C_ID_ID)
+       {
+         c_parser_error (parser, "expected expression");
+         expr.value = error_mark_node;
+         expr.original_code = ERROR_MARK;
+         break;
+       }
+      {
+       tree id = c_parser_peek_token (parser)->value;
+       c_parser_consume_token (parser);
+       expr.value = build_external_ref (id,
+                                        (c_parser_peek_token (parser)->type
+                                         == CPP_OPEN_PAREN));
+       expr.original_code = ERROR_MARK;
+      }
+      break;
+    case CPP_OPEN_PAREN:
+      /* A parenthesized expression, statement expression or compound
+        literal.  */
+      if (c_parser_peek_2nd_token (parser)->type == CPP_OPEN_BRACE)
+       {
+         /* A statement expression.  */
+         tree stmt;
+         c_parser_consume_token (parser);
+         c_parser_consume_token (parser);
+         if (cur_stmt_list == NULL)
+           {
+             error ("braced-group within expression allowed "
+                    "only inside a function");
+             parser->error = true;
+             c_parser_skip_until_found (parser, CPP_CLOSE_BRACE, NULL);
+             c_parser_skip_until_found (parser, CPP_CLOSE_PAREN, NULL);
+             expr.value = error_mark_node;
+             expr.original_code = ERROR_MARK;
+             break;
+           }
+         stmt = c_begin_stmt_expr ();
+         c_parser_compound_statement_nostart (parser);
+         c_parser_skip_until_found (parser, CPP_CLOSE_PAREN,
+                                    "expected %<)%>");
+         if (pedantic)
+           pedwarn ("ISO C forbids braced-groups within expressions");
+         expr.value = c_finish_stmt_expr (stmt);
+         expr.original_code = ERROR_MARK;
+       }
+      else if (c_token_starts_typename (c_parser_peek_2nd_token (parser)))
+       {
+         /* A compound literal.  ??? Can we actually get here rather
+            than going directly to
+            c_parser_postfix_expression_after_paren_type from
+            elsewhere?  */
+         struct c_type_name *type_name;
+         c_parser_consume_token (parser);
+         type_name = c_parser_type_name (parser);
+         c_parser_skip_until_found (parser, CPP_CLOSE_PAREN,
+                                    "expected %<)%>");
+         if (type_name == NULL)
+           {
+             expr.value = error_mark_node;
+             expr.original_code = ERROR_MARK;
+           }
+         else
+           expr = c_parser_postfix_expression_after_paren_type (parser,
+                                                                type_name);
+       }
+      else
+       {
+         /* A parenthesized expression.  */
+         c_parser_consume_token (parser);
+         expr = c_parser_expression (parser);
+         if (TREE_CODE (expr.value) == MODIFY_EXPR)
+           TREE_NO_WARNING (expr.value) = 1;
+         expr.original_code = ERROR_MARK;
+         c_parser_skip_until_found (parser, CPP_CLOSE_PAREN,
+                                    "expected %<)%>");
+       }
+      break;
+    case CPP_KEYWORD:
+      switch (c_parser_peek_token (parser)->keyword)
+       {
+       case RID_FUNCTION_NAME:
+       case RID_PRETTY_FUNCTION_NAME:
+       case RID_C99_FUNCTION_NAME:
+         expr.value = fname_decl (c_parser_peek_token (parser)->keyword,
+                                  c_parser_peek_token (parser)->value);
+         expr.original_code = ERROR_MARK;
+         c_parser_consume_token (parser);
+         break;
+       case RID_VA_ARG:
+         c_parser_consume_token (parser);
+         if (!c_parser_require (parser, CPP_OPEN_PAREN, "expected %<(%>"))
+           {
+             expr.value = error_mark_node;
+             expr.original_code = ERROR_MARK;
+             break;
+           }
+         e1 = c_parser_expr_no_commas (parser, NULL);
+         if (!c_parser_require (parser, CPP_COMMA, "expected %<,%>"))
+           {
+             c_parser_skip_until_found (parser, CPP_CLOSE_PAREN, NULL);
+             expr.value = error_mark_node;
+             expr.original_code = ERROR_MARK;
+             break;
+           }
+         t1 = c_parser_type_name (parser);
+         c_parser_skip_until_found (parser, CPP_CLOSE_PAREN,
+                                    "expected %<)%>");
+         if (t1 == NULL)
+           {
+             expr.value = error_mark_node;
+             expr.original_code = ERROR_MARK;
+           }
+         else
+           {
+             expr.value = build_va_arg (e1.value, groktypename (t1));
+             expr.original_code = ERROR_MARK;
+           }
+         break;
+       case RID_OFFSETOF:
+         c_parser_consume_token (parser);
+         if (!c_parser_require (parser, CPP_OPEN_PAREN, "expected %<(%>"))
+           {
+             expr.value = error_mark_node;
+             expr.original_code = ERROR_MARK;
+             break;
+           }
+         t1 = c_parser_type_name (parser);
+         if (t1 == NULL)
+           {
+             expr.value = error_mark_node;
+             expr.original_code = ERROR_MARK;
+             break;
+           }
+         if (!c_parser_require (parser, CPP_COMMA, "expected %<,%>"))
+           {
+             c_parser_skip_until_found (parser, CPP_CLOSE_PAREN, NULL);
+             expr.value = error_mark_node;
+             expr.original_code = ERROR_MARK;
+             break;
+           }
+         {
+           tree type = groktypename (t1);
+           tree offsetof_ref;
+           if (type == error_mark_node)
+             offsetof_ref = error_mark_node;
+           else
+             offsetof_ref = build1 (INDIRECT_REF, type, NULL);
+           /* Parse the second argument to __builtin_offsetof.  We
+              must have one identifier, and beyond that we want to
+              accept sub structure and sub array references.  */
+           if (c_parser_next_token_is (parser, CPP_NAME))
+             {
+               offsetof_ref = build_component_ref
+                 (offsetof_ref, c_parser_peek_token (parser)->value);
+               c_parser_consume_token (parser);
+               while (c_parser_next_token_is (parser, CPP_DOT)
+                      || c_parser_next_token_is (parser,
+                                                 CPP_OPEN_SQUARE))
+                 {
+                   if (c_parser_next_token_is (parser, CPP_DOT))
+                     {
+                       c_parser_consume_token (parser);
+                       if (c_parser_next_token_is_not (parser,
+                                                       CPP_NAME))
+                         {
+                           c_parser_error (parser, "expected identifier");
+                           break;
+                         }
+                       offsetof_ref = build_component_ref
+                         (offsetof_ref,
+                          c_parser_peek_token (parser)->value);
+                       c_parser_consume_token (parser);
+                     }
+                   else
+                     {
+                       tree idx;
+                       c_parser_consume_token (parser);
+                       idx = c_parser_expression (parser).value;
+                       c_parser_skip_until_found (parser, CPP_CLOSE_SQUARE,
+                                                  "expected %<]%>");
+                       offsetof_ref = build_array_ref (offsetof_ref, idx);
+                     }
+                 }
+             }
+           else
+             c_parser_error (parser, "expected identifier");
+           c_parser_skip_until_found (parser, CPP_CLOSE_PAREN,
+                                      "expected %<)%>");
+           expr.value = fold_offsetof (offsetof_ref);
+           expr.original_code = ERROR_MARK;
+         }
+         break;
+       case RID_CHOOSE_EXPR:
+         c_parser_consume_token (parser);
+         if (!c_parser_require (parser, CPP_OPEN_PAREN, "expected %<(%>"))
+           {
+             expr.value = error_mark_node;
+             expr.original_code = ERROR_MARK;
+             break;
+           }
+         e1 = c_parser_expr_no_commas (parser, NULL);
+         if (!c_parser_require (parser, CPP_COMMA, "expected %<,%>"))
+           {
+             c_parser_skip_until_found (parser, CPP_CLOSE_PAREN, NULL);
+             expr.value = error_mark_node;
+             expr.original_code = ERROR_MARK;
+             break;
+           }
+         e2 = c_parser_expr_no_commas (parser, NULL);
+         if (!c_parser_require (parser, CPP_COMMA, "expected %<,%>"))
+           {
+             c_parser_skip_until_found (parser, CPP_CLOSE_PAREN, NULL);
+             expr.value = error_mark_node;
+             expr.original_code = ERROR_MARK;
+             break;
+           }
+         e3 = c_parser_expr_no_commas (parser, NULL);
+         c_parser_skip_until_found (parser, CPP_CLOSE_PAREN,
+                                    "expected %<)%>");
+         {
+           tree c;
+
+           c = fold (e1.value);
+           STRIP_NOPS (c);
+           if (TREE_CODE (c) != INTEGER_CST)
+             error ("first argument to %<__builtin_choose_expr%> not"
+                    " a constant");
+           expr = integer_zerop (c) ? e3 : e2;
+         }
+         break;
+       case RID_TYPES_COMPATIBLE_P:
+         c_parser_consume_token (parser);
+         if (!c_parser_require (parser, CPP_OPEN_PAREN, "expected %<(%>"))
+           {
+             expr.value = error_mark_node;
+             expr.original_code = ERROR_MARK;
+             break;
+           }
+         t1 = c_parser_type_name (parser);
+         if (t1 == NULL)
+           {
+             expr.value = error_mark_node;
+             expr.original_code = ERROR_MARK;
+             break;
+           }
+         if (!c_parser_require (parser, CPP_COMMA, "expected %<,%>"))
+           {
+             c_parser_skip_until_found (parser, CPP_CLOSE_PAREN, NULL);
+             expr.value = error_mark_node;
+             expr.original_code = ERROR_MARK;
+             break;
+           }
+         t2 = c_parser_type_name (parser);
+         if (t2 == NULL)
+           {
+             expr.value = error_mark_node;
+             expr.original_code = ERROR_MARK;
+             break;
+           }
+         c_parser_skip_until_found (parser, CPP_CLOSE_PAREN,
+                                    "expected %<)%>");
+         {
+           tree e1, e2;
+
+           e1 = TYPE_MAIN_VARIANT (groktypename (t1));
+           e2 = TYPE_MAIN_VARIANT (groktypename (t2));
+
+           expr.value = comptypes (e1, e2)
+             ? build_int_cst (NULL_TREE, 1)
+             : build_int_cst (NULL_TREE, 0);
+           expr.original_code = ERROR_MARK;
+         }
+         break;
+       case RID_AT_SELECTOR:
+         gcc_assert (c_dialect_objc ());
+         c_parser_consume_token (parser);
+         if (!c_parser_require (parser, CPP_OPEN_PAREN, "expected %<(%>"))
+           {
+             expr.value = error_mark_node;
+             expr.original_code = ERROR_MARK;
+             break;
+           }
+         {
+           tree sel = c_parser_objc_selector_arg (parser);
+           c_parser_skip_until_found (parser, CPP_CLOSE_PAREN,
+                                      "expected %<)%>");
+           expr.value = objc_build_selector_expr (sel);
+           expr.original_code = ERROR_MARK;
+         }
+         break;
+       case RID_AT_PROTOCOL:
+         gcc_assert (c_dialect_objc ());
+         c_parser_consume_token (parser);
+         if (!c_parser_require (parser, CPP_OPEN_PAREN, "expected %<(%>"))
+           {
+             expr.value = error_mark_node;
+             expr.original_code = ERROR_MARK;
+             break;
+           }
+         if (c_parser_next_token_is_not (parser, CPP_NAME))
+           {
+             c_parser_error (parser, "expected identifier");
+             c_parser_skip_until_found (parser, CPP_CLOSE_PAREN, NULL);
+             expr.value = error_mark_node;
+             expr.original_code = ERROR_MARK;
+             break;
+           }
+         {
+           tree id = c_parser_peek_token (parser)->value;
+           c_parser_consume_token (parser);
+           c_parser_skip_until_found (parser, CPP_CLOSE_PAREN,
+                                      "expected %<)%>");
+           expr.value = objc_build_protocol_expr (id);
+           expr.original_code = ERROR_MARK;
+         }
+         break;
+       case RID_AT_ENCODE:
+         /* Extension to support C-structures in the archiver.  */
+         gcc_assert (c_dialect_objc ());
+         c_parser_consume_token (parser);
+         if (!c_parser_require (parser, CPP_OPEN_PAREN, "expected %<(%>"))
+           {
+             expr.value = error_mark_node;
+             expr.original_code = ERROR_MARK;
+             break;
+           }
+         t1 = c_parser_type_name (parser);
+         if (t1 == NULL)
+           {
+             expr.value = error_mark_node;
+             expr.original_code = ERROR_MARK;
+             c_parser_skip_until_found (parser, CPP_CLOSE_PAREN, NULL);
+             break;
+           }
+         c_parser_skip_until_found (parser, CPP_CLOSE_PAREN,
+                                    "expected %<)%>");
+         {
+           tree type = groktypename (t1);
+           expr.value = objc_build_encode_expr (type);
+           expr.original_code = ERROR_MARK;
+         }
+         break;
+       default:
+         c_parser_error (parser, "expected expression");
+         expr.value = error_mark_node;
+         expr.original_code = ERROR_MARK;
+         break;
+       }
+      break;
+    case CPP_OPEN_SQUARE:
+      if (c_dialect_objc ())
+       {
+         tree receiver, args;
+         c_parser_consume_token (parser);
+         receiver = c_parser_objc_receiver (parser);
+         args = c_parser_objc_message_args (parser);
+         c_parser_skip_until_found (parser, CPP_CLOSE_SQUARE,
+                                    "expected %<]%>");
+         expr.value = objc_build_message_expr (build_tree_list (receiver,
+                                                                args));
+         expr.original_code = ERROR_MARK;
+         break;
+       }
+      /* Else fall through to report error.  */
+    default:
+      c_parser_error (parser, "expected expression");
+      expr.value = error_mark_node;
+      expr.original_code = ERROR_MARK;
+      break;
+    }
+  return c_parser_postfix_expression_after_primary (parser, expr);
+}
+
+/* Parse a postfix expression after a parenthesized type name: the
+   brace-enclosed initializer of a compound literal, possibly followed
+   by some postfix operators.  This is separate because it is not
+   possible to tell until after the type name whether a cast
+   expression has a cast or a compound literal, or whether the operand
+   of sizeof is a parenthesized type name or starts with a compound
+   literal.  */
+
+static struct c_expr
+c_parser_postfix_expression_after_paren_type (c_parser *parser,
+                                             struct c_type_name *type_name)
+{
+  tree type;
+  struct c_expr init;
+  struct c_expr expr;
+  start_init (NULL_TREE, NULL, 0);
+  type = groktypename (type_name);
+  if (C_TYPE_VARIABLE_SIZE (type))
+    {
+      error ("compound literal has variable size");
+      type = error_mark_node;
+    }
+  init = c_parser_braced_init (parser, type, false);
+  finish_init ();
+  maybe_warn_string_init (type, init);
+
+  if (pedantic && !flag_isoc99)
+    pedwarn ("ISO C90 forbids compound literals");
+  expr.value = build_compound_literal (type, init.value);
+  expr.original_code = ERROR_MARK;
+  return c_parser_postfix_expression_after_primary (parser, expr);
+}
+
+/* Parse a postfix expression after the initial primary or compound
+   literal; that is, parse a series of postfix operators.  */
+
+static struct c_expr
+c_parser_postfix_expression_after_primary (c_parser *parser,
+                                          struct c_expr expr)
+{
+  tree ident, idx, exprlist;
+  while (true)
+    {
+      switch (c_parser_peek_token (parser)->type)
+       {
+       case CPP_OPEN_SQUARE:
+         /* Array reference.  */
+         c_parser_consume_token (parser);
+         idx = c_parser_expression (parser).value;
+         c_parser_skip_until_found (parser, CPP_CLOSE_SQUARE,
+                                    "expected %<]%>");
+         expr.value = build_array_ref (expr.value, idx);
+         expr.original_code = ERROR_MARK;
+         break;
+       case CPP_OPEN_PAREN:
+         /* Function call.  */
+         c_parser_consume_token (parser);
+         if (c_parser_next_token_is (parser, CPP_CLOSE_PAREN))
+           exprlist = NULL_TREE;
+         else
+           exprlist = c_parser_expr_list (parser);
+         c_parser_skip_until_found (parser, CPP_CLOSE_PAREN,
+                                    "expected %<)%>");
+         expr.value = build_function_call (expr.value, exprlist);
+         expr.original_code = ERROR_MARK;
+         break;
+       case CPP_DOT:
+         /* Structure element reference.  */
+         c_parser_consume_token (parser);
+         if (c_parser_next_token_is (parser, CPP_NAME))
+           ident = c_parser_peek_token (parser)->value;
+         else
+           {
+             c_parser_error (parser, "expected identifier");
+             expr.value = error_mark_node;
+             expr.original_code = ERROR_MARK;
+             return expr;
+           }
+         c_parser_consume_token (parser);
+         expr.value = build_component_ref (expr.value, ident);
+         expr.original_code = ERROR_MARK;
+         break;
+       case CPP_DEREF:
+         /* Structure element reference.  */
+         c_parser_consume_token (parser);
+         if (c_parser_next_token_is (parser, CPP_NAME))
+           ident = c_parser_peek_token (parser)->value;
+         else
+           {
+             c_parser_error (parser, "expected identifier");
+             expr.value = error_mark_node;
+             expr.original_code = ERROR_MARK;
+             return expr;
+           }
+         c_parser_consume_token (parser);
+         expr.value = build_component_ref (build_indirect_ref (expr.value,
+                                                               "->"), ident);
+         expr.original_code = ERROR_MARK;
+         break;
+       case CPP_PLUS_PLUS:
+         /* Postincrement.  */
+         c_parser_consume_token (parser);
+         expr.value = build_unary_op (POSTINCREMENT_EXPR, expr.value, 0);
+         expr.original_code = ERROR_MARK;
+         break;
+       case CPP_MINUS_MINUS:
+         /* Postdecrement.  */
+         c_parser_consume_token (parser);
+         expr.value = build_unary_op (POSTDECREMENT_EXPR, expr.value, 0);
+         expr.original_code = ERROR_MARK;
+         break;
+       default:
+         return expr;
+       }
+    }
+}
+
+/* Parse an expression (C90 6.3.17, C99 6.5.17).
+
+   expression:
+     assignment-expression
+     expression , assignment-expression
+*/
+
+static struct c_expr
+c_parser_expression (c_parser *parser)
+{
+  struct c_expr expr;
+  expr = c_parser_expr_no_commas (parser, NULL);
+  while (c_parser_next_token_is (parser, CPP_COMMA))
+    {
+      struct c_expr next;
+      c_parser_consume_token (parser);
+      next = c_parser_expr_no_commas (parser, NULL);
+      expr.value = build_compound_expr (expr.value, next.value);
+      expr.original_code = COMPOUND_EXPR;
+    }
+  return expr;
+}
+
+/* Parse a non-empty list of expressions.
+
+   nonempty-expr-list:
+     assignment-expression
+     nonempty-expr-list , assignment-expression
+*/
+
+static tree
+c_parser_expr_list (c_parser *parser)
+{
+  struct c_expr expr;
+  tree ret;
+  expr = c_parser_expr_no_commas (parser, NULL);
+  ret = build_tree_list (NULL_TREE, expr.value);
+  while (c_parser_next_token_is (parser, CPP_COMMA))
+    {
+      c_parser_consume_token (parser);
+      expr = c_parser_expr_no_commas (parser, NULL);
+      ret = chainon (ret, build_tree_list (NULL_TREE, expr.value));
+    }
+  return ret;
+}
+
+\f
+/* Parse Objective-C-specific constructs.  */
+
+/* Parse an objc-class-definition.
+
+   objc-class-definition:
+     @interface identifier objc-superclass[opt] objc-protocol-refs[opt]
+       objc-class-instance-variables[opt] objc-methodprotolist @end
+     @implementation identifier objc-superclass[opt]
+       objc-class-instance-variables[opt]
+     @interface identifier ( identifier ) objc-protocol-refs[opt]
+       objc-methodprotolist @end
+     @implementation identifier ( identifier )
+
+   objc-superclass:
+     : identifier
+
+   "@interface identifier (" must start "@interface identifier (
+   identifier ) ...": objc-methodprotolist in the first production may
+   not start with a parenthesised identifier as a declarator of a data
+   definition with no declaration specifiers if the objc-superclass,
+   objc-protocol-refs and objc-class-instance-variables are omitted.  */
+
+static void
+c_parser_objc_class_definition (c_parser *parser)
+{
+  bool iface_p;
+  tree id1;
+  tree superclass;
+  if (c_parser_next_token_is_keyword (parser, RID_AT_INTERFACE))
+    iface_p = true;
+  else if (c_parser_next_token_is_keyword (parser, RID_AT_IMPLEMENTATION))
+    iface_p = false;
+  else
+    gcc_unreachable ();
+  c_parser_consume_token (parser);
+  if (c_parser_next_token_is_not (parser, CPP_NAME))
+    {
+      c_parser_error (parser, "expected identifier");
+      return;
+    }
+  id1 = c_parser_peek_token (parser)->value;
+  c_parser_consume_token (parser);
+  if (c_parser_next_token_is (parser, CPP_OPEN_PAREN))
+    {
+      tree id2;
+      tree proto = NULL_TREE;
+      c_parser_consume_token (parser);
+      if (c_parser_next_token_is_not (parser, CPP_NAME))
+       {
+         c_parser_error (parser, "expected identifier");
+         c_parser_skip_until_found (parser, CPP_CLOSE_PAREN, NULL);
+         return;
+       }
+      id2 = c_parser_peek_token (parser)->value;
+      c_parser_consume_token (parser);
+      c_parser_skip_until_found (parser, CPP_CLOSE_PAREN, "expected %<)%>");
+      if (!iface_p)
+       {
+         objc_start_category_implementation (id1, id2);
+         return;
+       }
+      if (c_parser_next_token_is (parser, CPP_LESS))
+       proto = c_parser_objc_protocol_refs (parser);
+      objc_start_category_interface (id1, id2, proto);
+      c_parser_objc_methodprotolist (parser);
+      c_parser_require_keyword (parser, RID_AT_END, "expected %<@end%>");
+      objc_finish_interface ();
+      return;
+    }
+  if (c_parser_next_token_is (parser, CPP_COLON))
+    {
+      c_parser_consume_token (parser);
+      if (c_parser_next_token_is_not (parser, CPP_NAME))
+       {
+         c_parser_error (parser, "expected identifier");
+         return;
+       }
+      superclass = c_parser_peek_token (parser)->value;
+      c_parser_consume_token (parser);
+    }
+  else
+    superclass = NULL_TREE;
+  if (iface_p)
+    {
+      tree proto = NULL_TREE;
+      if (c_parser_next_token_is (parser, CPP_LESS))
+       proto = c_parser_objc_protocol_refs (parser);
+      objc_start_class_interface (id1, superclass, proto);
+    }
+  else
+    objc_start_class_implementation (id1, superclass);
+  if (c_parser_next_token_is (parser, CPP_OPEN_BRACE))
+    c_parser_objc_class_instance_variables (parser);
+  if (iface_p)
+    {
+      objc_continue_interface ();
+      c_parser_objc_methodprotolist (parser);
+      c_parser_require_keyword (parser, RID_AT_END, "expected %<@end%>");
+      objc_finish_interface ();
+    }
+  else
+    {
+      objc_continue_implementation ();
+      return;
+    }
+}
+
+/* Parse objc-class-instance-variables.
+
+   objc-class-instance-variables:
+     { objc-instance-variable-decl-list[opt] }
+
+   objc-instance-variable-decl-list:
+     objc-visibility-spec
+     objc-instance-variable-decl ;
+     ;
+     objc-instance-variable-decl-list objc-visibility-spec
+     objc-instance-variable-decl-list objc-instance-variable-decl ;
+     objc-instance-variable-decl-list ;
+
+   objc-visibility-spec:
+     @private
+     @protected
+     @public
+
+   objc-instance-variable-decl:
+     struct-declaration
+*/
+
+static void
+c_parser_objc_class_instance_variables (c_parser *parser)
+{
+  gcc_assert (c_parser_next_token_is (parser, CPP_OPEN_BRACE));
+  c_parser_consume_token (parser);
+  while (c_parser_next_token_is_not (parser, CPP_EOF))
+    {
+      tree decls;
+      /* Parse any stray semicolon.  */
+      if (c_parser_next_token_is (parser, CPP_SEMICOLON))
+       {
+         if (pedantic)
+           pedwarn ("extra semicolon in struct or union specified");
+         c_parser_consume_token (parser);
+         continue;
+       }
+      /* Stop if at the end of the instance variables.  */
+      if (c_parser_next_token_is (parser, CPP_CLOSE_BRACE))
+       {
+         c_parser_consume_token (parser);
+         break;
+       }
+      /* Parse any objc-visibility-spec.  */
+      if (c_parser_next_token_is_keyword (parser, RID_AT_PRIVATE))
+       {
+         c_parser_consume_token (parser);
+         objc_set_visibility (2);
+         continue;
+       }
+      else if (c_parser_next_token_is_keyword (parser, RID_AT_PROTECTED))
+       {
+         c_parser_consume_token (parser);
+         objc_set_visibility (0);
+         continue;
+       }
+      else if (c_parser_next_token_is_keyword (parser, RID_AT_PUBLIC))
+       {
+         c_parser_consume_token (parser);
+         objc_set_visibility (1);
+         continue;
+       }
+      /* Parse some comma-separated declarations.  */
+      decls = c_parser_struct_declaration (parser);
+      {
+       /* Comma-separated instance variables are chained together in
+          reverse order; add them one by one.  */
+       tree ivar = nreverse (decls);
+       for (; ivar; ivar = TREE_CHAIN (ivar))
+         objc_add_instance_variable (copy_node (ivar));
+      }
+      c_parser_skip_until_found (parser, CPP_SEMICOLON, "expected %<;%>");
+    }
+}
+
+/* Parse an objc-class-declaration.
+
+   objc-class-declaration:
+     @class identifier-list ;
+*/
+
+static void
+c_parser_objc_class_declaration (c_parser *parser)
+{
+  tree list = NULL_TREE;
+  gcc_assert (c_parser_next_token_is_keyword (parser, RID_AT_CLASS));
+  c_parser_consume_token (parser);
+  /* Any identifiers, including those declared as type names, are OK
+     here.  */
+  while (true)
+    {
+      tree id;
+      if (c_parser_next_token_is_not (parser, CPP_NAME))
+       {
+         c_parser_error (parser, "expected identifier");
+         break;
+       }
+      id = c_parser_peek_token (parser)->value;
+      list = chainon (list, build_tree_list (NULL_TREE, id));
+      c_parser_consume_token (parser);
+      if (c_parser_next_token_is (parser, CPP_COMMA))
+       c_parser_consume_token (parser);
+      else
+       break;
+    }
+  c_parser_skip_until_found (parser, CPP_SEMICOLON, "expected %<;%>");
+  objc_declare_class (list);
+}
+
+/* Parse an objc-alias-declaration.
+
+   objc-alias-declaration:
+     @compatibility_alias identifier identifier ;
+*/
+
+static void
+c_parser_objc_alias_declaration (c_parser *parser)
+{
+  tree id1, id2;
+  gcc_assert (c_parser_next_token_is_keyword (parser, RID_AT_ALIAS));
+  c_parser_consume_token (parser);
+  if (c_parser_next_token_is_not (parser, CPP_NAME))
+    {
+      c_parser_error (parser, "expected identifier");
+      c_parser_skip_until_found (parser, CPP_SEMICOLON, NULL);
+      return;
+    }
+  id1 = c_parser_peek_token (parser)->value;
+  c_parser_consume_token (parser);
+  if (c_parser_next_token_is_not (parser, CPP_NAME))
+    {
+      c_parser_error (parser, "expected identifier");
+      c_parser_skip_until_found (parser, CPP_SEMICOLON, NULL);
+      return;
+    }
+  id2 = c_parser_peek_token (parser)->value;
+  c_parser_consume_token (parser);
+  c_parser_skip_until_found (parser, CPP_SEMICOLON, "expected %<;%>");
+  objc_declare_alias (id1, id2);
+}
+
+/* Parse an objc-protocol-definition.
+
+   objc-protocol-definition:
+     @protocol identifier objc-protocol-refs[opt] objc-methodprotolist @end
+     @protocol identifier-list ;
+
+   "@protocol identifier ;" should be resolved as "@protocol
+   identifier-list ;": objc-methodprotolist may not start with a
+   semicolon in the first alternative if objc-protocol-refs are
+   omitted.  */
+
+static void
+c_parser_objc_protocol_definition (c_parser *parser)
+{
+  gcc_assert (c_parser_next_token_is_keyword (parser, RID_AT_PROTOCOL));
+  c_parser_consume_token (parser);
+  if (c_parser_next_token_is_not (parser, CPP_NAME))
+    {
+      c_parser_error (parser, "expected identifier");
+      return;
+    }
+  if (c_parser_peek_2nd_token (parser)->type == CPP_COMMA
+      || c_parser_peek_2nd_token (parser)->type == CPP_SEMICOLON)
+    {
+      tree list = NULL_TREE;
+      /* Any identifiers, including those declared as type names, are
+        OK here.  */
+      while (true)
+       {
+         tree id;
+         if (c_parser_next_token_is_not (parser, CPP_NAME))
+           {
+             c_parser_error (parser, "expected identifier");
+             break;
+           }
+         id = c_parser_peek_token (parser)->value;
+         list = chainon (list, build_tree_list (NULL_TREE, id));
+         c_parser_consume_token (parser);
+         if (c_parser_next_token_is (parser, CPP_COMMA))
+           c_parser_consume_token (parser);
+         else
+           break;
+       }
+      c_parser_skip_until_found (parser, CPP_SEMICOLON, "expected %<;%>");
+      objc_declare_protocols (list);
+    }
+  else
+    {
+      tree id = c_parser_peek_token (parser)->value;
+      tree proto = NULL_TREE;
+      c_parser_consume_token (parser);
+      if (c_parser_next_token_is (parser, CPP_LESS))
+       proto = c_parser_objc_protocol_refs (parser);
+      objc_pq_context = 1;
+      objc_start_protocol (id, proto);
+      c_parser_objc_methodprotolist (parser);
+      c_parser_require_keyword (parser, RID_AT_END, "expected %<@end%>");
+      objc_pq_context = 0;
+      objc_finish_interface ();
+    }
+}
+
+/* Parse an objc-method-type.
+
+   objc-method-type:
+     +
+     -
+*/
+
+static enum tree_code
+c_parser_objc_method_type (c_parser *parser)
+{
+  switch (c_parser_peek_token (parser)->type)
+    {
+    case CPP_PLUS:
+      c_parser_consume_token (parser);
+      return PLUS_EXPR;
+    case CPP_MINUS:
+      c_parser_consume_token (parser);
+      return MINUS_EXPR;
+    default:
+      gcc_unreachable ();
+    }
+}
+
+/* Parse an objc-method-definition.
+
+   objc-method-definition:
+     objc-method-type objc-method-decl ;[opt] compound-statement
+*/
+
+static void
+c_parser_objc_method_definition (c_parser *parser)
+{
+  enum tree_code type = c_parser_objc_method_type (parser);
+  tree decl;
+  objc_set_method_type (type);
+  objc_pq_context = 1;
+  decl = c_parser_objc_method_decl (parser);
+  if (c_parser_next_token_is (parser, CPP_SEMICOLON))
+    {
+      c_parser_consume_token (parser);
+      if (pedantic)
+       pedwarn ("extra semicolon in method definition specified");
+    }
+  objc_pq_context = 0;
+  objc_start_method_definition (decl);
+  add_stmt (c_parser_compound_statement (parser));
+  objc_finish_method_definition (current_function_decl);
+}
+
+/* Parse an objc-methodprotolist.
+
+   objc-methodprotolist:
+     empty
+     objc-methodprotolist objc-methodproto
+     objc-methodprotolist declaration
+     objc-methodprotolist ;
+
+   The declaration is a data definition, which may be missing
+   declaration specifiers under the same rules and diagnostics as
+   other data definitions outside functions, and the stray semicolon
+   is diagnosed the same way as a stray semicolon outside a
+   function.  */
+
+static void
+c_parser_objc_methodprotolist (c_parser *parser)
+{
+  while (true)
+    {
+      /* The list is terminated by @end.  */
+      switch (c_parser_peek_token (parser)->type)
+       {
+       case CPP_SEMICOLON:
+         if (pedantic)
+           pedwarn ("ISO C does not allow extra %<;%> outside of a function");
+         c_parser_consume_token (parser);
+         break;
+       case CPP_PLUS:
+       case CPP_MINUS:
+         c_parser_objc_methodproto (parser);
+         break;
+       case CPP_EOF:
+         return;
+       default:
+         if (c_parser_next_token_is_keyword (parser, RID_AT_END))
+           return;
+         c_parser_declaration_or_fndef (parser, false, true, false, true);
+         break;
+       }
+    }
+}
+
+/* Parse an objc-methodproto.
+
+   objc-methodproto:
+     objc-method-type objc-method-decl ;
+*/
+
+static void
+c_parser_objc_methodproto (c_parser *parser)
+{
+  enum tree_code type = c_parser_objc_method_type (parser);
+  tree decl;
+  objc_set_method_type (type);
+  /* Remember protocol qualifiers in prototypes.  */
+  objc_pq_context = 1;
+  decl = c_parser_objc_method_decl (parser);
+  /* Forget protocol qualifiers here.  */
+  objc_pq_context = 0;
+  objc_add_method_declaration (decl);
+  c_parser_skip_until_found (parser, CPP_SEMICOLON, "expected %<;%>");
+}
+
+/* Parse an objc-method-decl.
+
+   objc-method-decl:
+     ( objc-type-name ) objc-selector
+     objc-selector
+     ( objc-type-name ) objc-keyword-selector objc-optparmlist
+     objc-keyword-selector objc-optparmlist
+
+   objc-keyword-selector:
+     objc-keyword-decl
+     objc-keyword-selector objc-keyword-decl
+
+   objc-keyword-decl:
+     objc-selector : ( objc-type-name ) identifier
+     objc-selector : identifier
+     : ( objc-type-name ) identifier
+     : identifier
+
+   objc-optparmlist:
+     objc-optparms objc-optellipsis
+
+   objc-optparms:
+     empty
+     objc-opt-parms , parameter-declaration
+
+   objc-optellipsis:
+     empty
+     , ...
+*/
+
+static tree
+c_parser_objc_method_decl (c_parser *parser)
+{
+  tree type = NULL_TREE;
+  tree sel;
+  tree parms = NULL_TREE;
+  if (c_parser_next_token_is (parser, CPP_OPEN_PAREN))
+    {
+      c_parser_consume_token (parser);
+      type = c_parser_objc_type_name (parser);
+      c_parser_skip_until_found (parser, CPP_CLOSE_PAREN, "expected %<)%>");
+    }
+  sel = c_parser_objc_selector (parser);
+  /* If there is no selector, or a colon follows, we have an
+     objc-keyword-selector.  If there is a selector, and a colon does
+     not follow, that selector ends the objc-method-decl.  */
+  if (!sel || c_parser_next_token_is (parser, CPP_COLON))
+    {
+      tree tsel = sel;
+      tree list = NULL_TREE;
+      bool ellipsis;
+      while (true)
+       {
+         tree atype = NULL_TREE, id, keyworddecl;
+         if (!c_parser_require (parser, CPP_COLON, "expected %<:%>"))
+           break;
+         if (c_parser_next_token_is (parser, CPP_OPEN_PAREN))
+           {
+             c_parser_consume_token (parser);
+             atype = c_parser_objc_type_name (parser);
+             c_parser_skip_until_found (parser, CPP_CLOSE_PAREN,
+                                        "expected %<)%>");
+           }
+         if (c_parser_next_token_is_not (parser, CPP_NAME))
+           {
+             c_parser_error (parser, "expected identifier");
+             return error_mark_node;
+           }
+         id = c_parser_peek_token (parser)->value;
+         c_parser_consume_token (parser);
+         keyworddecl = objc_build_keyword_decl (tsel, atype, id);
+         list = chainon (list, keyworddecl);
+         tsel = c_parser_objc_selector (parser);
+         if (!tsel && c_parser_next_token_is_not (parser, CPP_COLON))
+           break;
+       }
+      /* Parse the optional parameter list.  Optional Objective-C
+        method parameters follow the C syntax, and may include '...'
+        to denote a variable number of arguments.  */
+      parms = make_node (TREE_LIST);
+      ellipsis = false;
+      while (c_parser_next_token_is (parser, CPP_COMMA))
+       {
+         struct c_parm *parm;
+         c_parser_consume_token (parser);
+         if (c_parser_next_token_is (parser, CPP_ELLIPSIS))
+           {
+             ellipsis = true;
+             c_parser_consume_token (parser);
+             break;
+           }
+         parm = c_parser_parameter_declaration (parser, NULL_TREE);
+         if (parm == NULL)
+           break;
+         parms = chainon (parms,
+                          build_tree_list (NULL_TREE, grokparm (parm)));
+       }
+      TREE_OVERFLOW (parms) = ellipsis;
+      sel = list;
+    }
+  return objc_build_method_signature (type, sel, parms);
+}
+
+/* Parse an objc-type-name.
+
+   objc-type-name:
+     objc-type-qualifiers[opt] type-name
+     objc-type-qualifiers[opt]
+
+   objc-type-qualifiers:
+     objc-type-qualifier
+     objc-type-qualifiers objc-type-qualifier
+
+   objc-type-qualifier: one of
+     in out inout bycopy byref oneway
+*/
+
+static tree
+c_parser_objc_type_name (c_parser *parser)
+{
+  tree quals = NULL_TREE;
+  struct c_type_name *typename = NULL;
+  tree type = NULL_TREE;
+  while (true)
+    {
+      c_token *token = c_parser_peek_token (parser);
+      if (token->type == CPP_KEYWORD
+         && (token->keyword == RID_IN
+             || token->keyword == RID_OUT
+             || token->keyword == RID_INOUT
+             || token->keyword == RID_BYCOPY
+             || token->keyword == RID_BYREF
+             || token->keyword == RID_ONEWAY))
+       {
+         quals = chainon (quals, build_tree_list (NULL_TREE, token->value));
+         c_parser_consume_token (parser);
+       }
+      else
+       break;
+    }
+  if (c_parser_next_token_starts_typename (parser))
+    typename = c_parser_type_name (parser);
+  if (typename)
+    type = groktypename (typename);
+  return build_tree_list (quals, type);
+}
+
+/* Parse objc-protocol-refs.
+
+   objc-protocol-refs:
+     < identifier-list >
+*/
+
+static tree
+c_parser_objc_protocol_refs (c_parser *parser)
+{
+  tree list = NULL_TREE;
+  gcc_assert (c_parser_next_token_is (parser, CPP_LESS));
+  c_parser_consume_token (parser);
+  /* Any identifiers, including those declared as type names, are OK
+     here.  */
+  while (true)
+    {
+      tree id;
+      if (c_parser_next_token_is_not (parser, CPP_NAME))
+       {
+         c_parser_error (parser, "expected identifier");
+         break;
+       }
+      id = c_parser_peek_token (parser)->value;
+      list = chainon (list, build_tree_list (NULL_TREE, id));
+      c_parser_consume_token (parser);
+      if (c_parser_next_token_is (parser, CPP_COMMA))
+       c_parser_consume_token (parser);
+      else
+       break;
+    }
+  c_parser_require (parser, CPP_GREATER, "expected %<>%>");
+  return list;
+}
+
+/* Parse an objc-try-catch-statement.
+
+   objc-try-catch-statement:
+     @try compound-statement objc-catch-list[opt]
+     @try compound-statement objc-catch-list[opt] @finally compound-statement
+
+   objc-catch-list:
+     @catch ( parameter-declaration ) compound-statement
+     objc-catch-list @catch ( parameter-declaration ) compound-statement
+*/
+
+static void
+c_parser_objc_try_catch_statement (c_parser *parser)
+{
+  location_t loc;
+  tree stmt;
+  gcc_assert (c_parser_next_token_is_keyword (parser, RID_AT_TRY));
+  c_parser_consume_token (parser);
+  loc = c_parser_peek_token (parser)->location;
+  stmt = c_parser_compound_statement (parser);
+  objc_begin_try_stmt (loc, stmt);
+  while (c_parser_next_token_is_keyword (parser, RID_AT_CATCH))
+    {
+      struct c_parm *parm;
+      c_parser_consume_token (parser);
+      if (!c_parser_require (parser, CPP_OPEN_PAREN, "expected %<(%>"))
+       break;
+      parm = c_parser_parameter_declaration (parser, NULL_TREE);
+      if (parm == NULL)
+       {
+         c_parser_skip_until_found (parser, CPP_CLOSE_PAREN, NULL);
+         break;
+       }
+      c_parser_skip_until_found (parser, CPP_CLOSE_PAREN, "expected %<)%>");
+      objc_begin_catch_clause (grokparm (parm));
+      if (c_parser_require (parser, CPP_OPEN_BRACE, "expected %<{%>"))
+       c_parser_compound_statement_nostart (parser);
+      objc_finish_catch_clause ();
+    }
+  if (c_parser_next_token_is_keyword (parser, RID_AT_FINALLY))
+    {
+      location_t finloc;
+      tree finstmt;
+      c_parser_consume_token (parser);
+      finloc = c_parser_peek_token (parser)->location;
+      finstmt = c_parser_compound_statement (parser);
+      objc_build_finally_clause (finloc, finstmt);
+    }
+  objc_finish_try_stmt ();
+}
+
+/* Parse an objc-synchronized-statement.
+
+   objc-synchronized-statement:
+     @synchronized ( expression ) compound-statement
+*/
+
+static void
+c_parser_objc_synchronized_statement (c_parser *parser)
+{
+  location_t loc;
+  tree expr, stmt;
+  gcc_assert (c_parser_next_token_is_keyword (parser, RID_AT_SYNCHRONIZED));
+  c_parser_consume_token (parser);
+  loc = c_parser_peek_token (parser)->location;
+  if (c_parser_require (parser, CPP_OPEN_PAREN, "expected %<(%>"))
+    {
+      expr = c_parser_expression (parser).value;
+      c_parser_skip_until_found (parser, CPP_CLOSE_PAREN, "expected %<)%>");
+    }
+  else
+    expr = error_mark_node;
+  stmt = c_parser_compound_statement (parser);
+  objc_build_synchronized (loc, expr, stmt);
+}
+
+/* Parse an objc-selector; return NULL_TREE without an error if the
+   next token is not an objc-selector.
+
+   objc-selector:
+     identifier
+     one of
+       enum struct union if else while do for switch case default
+       break continue return goto asm sizeof typeof __alignof
+       unsigned long const short volatile signed restrict _Complex
+       in out inout bycopy byref oneway int char float double void _Bool
+
+   ??? Why this selection of keywords but not, for example, storage
+   class specifiers?  */
+
+static tree
+c_parser_objc_selector (c_parser *parser)
+{
+  c_token *token = c_parser_peek_token (parser);
+  tree value = token->value;
+  if (token->type == CPP_NAME)
+    {
+      c_parser_consume_token (parser);
+      return value;
+    }
+  if (token->type != CPP_KEYWORD)
+    return NULL_TREE;
+  switch (token->keyword)
+    {
+    case RID_ENUM:
+    case RID_STRUCT:
+    case RID_UNION:
+    case RID_IF:
+    case RID_ELSE:
+    case RID_WHILE:
+    case RID_DO:
+    case RID_FOR:
+    case RID_SWITCH:
+    case RID_CASE:
+    case RID_DEFAULT:
+    case RID_BREAK:
+    case RID_CONTINUE:
+    case RID_RETURN:
+    case RID_GOTO:
+    case RID_ASM:
+    case RID_SIZEOF:
+    case RID_TYPEOF:
+    case RID_ALIGNOF:
+    case RID_UNSIGNED:
+    case RID_LONG:
+    case RID_CONST:
+    case RID_SHORT:
+    case RID_VOLATILE:
+    case RID_SIGNED:
+    case RID_RESTRICT:
+    case RID_COMPLEX:
+    case RID_IN:
+    case RID_OUT:
+    case RID_INOUT:
+    case RID_BYCOPY:
+    case RID_BYREF:
+    case RID_ONEWAY:
+    case RID_INT:
+    case RID_CHAR:
+    case RID_FLOAT:
+    case RID_DOUBLE:
+    case RID_VOID:
+    case RID_BOOL:
+      c_parser_consume_token (parser);
+      return value;
+    default:
+      return NULL_TREE;
+    }
+}
+
+/* Parse an objc-selector-arg.
+
+   objc-selector-arg:
+     objc-selector
+     objc-keywordname-list
+
+   objc-keywordname-list:
+     objc-keywordname
+     objc-keywordname-list objc-keywordname
+
+   objc-keywordname:
+     objc-selector :
+     :
+*/
+
+static tree
+c_parser_objc_selector_arg (c_parser *parser)
+{
+  tree sel = c_parser_objc_selector (parser);
+  tree list = NULL_TREE;
+  if (sel && c_parser_next_token_is_not (parser, CPP_COLON))
+    return sel;
+  while (true)
+    {
+      if (!c_parser_require (parser, CPP_COLON, "expected %<:%>"))
+       return list;
+      list = chainon (list, build_tree_list (sel, NULL_TREE));
+      sel = c_parser_objc_selector (parser);
+      if (!sel && c_parser_next_token_is_not (parser, CPP_COLON))
+       break;
+    }
+  return list;
+}
+
+/* Parse an objc-receiver.
+
+   objc-receiver:
+     expression
+     class-name
+     type-name
+*/
+
+static tree
+c_parser_objc_receiver (c_parser *parser)
+{
+  if (c_parser_peek_token (parser)->type == CPP_NAME
+      && (c_parser_peek_token (parser)->id_kind == C_ID_TYPENAME
+         || c_parser_peek_token (parser)->id_kind == C_ID_CLASSNAME))
+    {
+      tree id = c_parser_peek_token (parser)->value;
+      c_parser_consume_token (parser);
+      return objc_get_class_reference (id);
+    }
+  return c_parser_expression (parser).value;
+}
+
+/* Parse objc-message-args.
+
+   objc-message-args:
+     objc-selector
+     objc-keywordarg-list
+
+   objc-keywordarg-list:
+     objc-keywordarg
+     objc-keywordarg-list objc-keywordarg
+
+   objc-keywordarg:
+     objc-selector : objc-keywordexpr
+     : objc-keywordexpr
+*/
+
+static tree
+c_parser_objc_message_args (c_parser *parser)
+{
+  tree sel = c_parser_objc_selector (parser);
+  tree list = NULL_TREE;
+  if (sel && c_parser_next_token_is_not (parser, CPP_COLON))
+    return sel;
+  while (true)
+    {
+      tree keywordexpr;
+      if (!c_parser_require (parser, CPP_COLON, "expected %<:%>"))
+       return list;
+      keywordexpr = c_parser_objc_keywordexpr (parser);
+      list = chainon (list, build_tree_list (sel, keywordexpr));
+      sel = c_parser_objc_selector (parser);
+      if (!sel && c_parser_next_token_is_not (parser, CPP_COLON))
+       break;
+    }
+  return list;
+}
+
+/* Parse an objc-keywordexpr.
+
+   objc-keywordexpr:
+     nonempty-expr-list
+*/
+
+static tree
+c_parser_objc_keywordexpr (c_parser *parser)
+{
+  tree list = c_parser_expr_list (parser);
+  if (TREE_CHAIN (list) == NULL_TREE)
+    {
+      /* Just return the expression, remove a level of
+        indirection.  */
+      return TREE_VALUE (list);
+    }
+  else
+    {
+      /* We have a comma expression, we will collapse later.  */
+      return list;
+    }
+}
+
+\f
+/* The actual parser and external interface.  ??? Does this need to be
+   garbage-collected?  */
+
+static GTY (()) c_parser *the_parser;
+
+/* Parse a single source file.  */
+
+void
+c_parse_file (void)
+{
+  the_parser = c_parser_new ();
+  c_parser_translation_unit (the_parser);
+  the_parser = NULL;
+}
+
+#include "gt-c-parser.h"
index 1cde482..d16d6a6 100644 (file)
@@ -205,6 +205,10 @@ struct c_declspecs {
   enum c_typespec_keyword typespec_word;
   /* The storage class specifier, or csc_none if none.  */
   enum c_storage_class storage_class;
+  /* Whether any declaration specifiers have been seen at all.  */
+  BOOL_BITFIELD declspecs_seen_p : 1;
+  /* Whether a type specifier has been seen.  */
+  BOOL_BITFIELD type_seen_p : 1;
   /* Whether 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
@@ -346,7 +350,7 @@ struct language_function GTY(())
 };
 
 \f
-/* in c-parse.in */
+/* in c-parser.c */
 extern void c_parse_init (void);
 
 /* in c-aux-info.c */
index e2872ee..096af89 100644 (file)
@@ -1,6 +1,6 @@
 /* -*- indented-text -*- */
 /* Process source files and output type information.
-   Copyright (C) 2002, 2003, 2004 Free Software Foundation, Inc.
+   Copyright (C) 2002, 2003, 2004, 2005 Free Software Foundation, Inc.
 
 This file is part of GCC.
 
@@ -272,8 +272,6 @@ ITYPE       {IWORD}({WS}{IWORD})*
 
 ^"%{"                          { BEGIN(in_yacc_escape); } /* } */
 
-^"@@".*                                /* Used for c-parse.in C/ObjC demarcation.  */
-
 {WS}                           { update_lineno (yytext, yyleng); }
 
 "const"/[^[:alnum:]_]          /* don't care */
index 88037f3..49e73af 100644 (file)
@@ -1,3 +1,11 @@
+2005-02-25  Joseph S. Myers  <joseph@codesourcery.com>
+
+       * Make-lang.in (objc/objc-parse.o-warn, objc/objc-parse.o,
+       objc/objc-parse.c, objc/objc-parse.y): Remove
+       (OBJC_OBJS, objc.srcextra, objc.tags, objc.mostlyclean,
+       objc.distclean, objc.maintainer-clean): Update for new parser.
+       * config-lang.in (gtfiles): Update for new parser.
+
 2005-01-29  Kazu Hirata  <kazu@cs.umass.edu>
 
        * lang-specs.h, objc-act.c, objc-act.h, objc-lang.c: Update
index 0890943..56fad72 100644 (file)
@@ -1,5 +1,5 @@
 # Top level -*- makefile -*- fragment for GNU Objective-C
-#   Copyright (C) 1997, 1998, 2000, 2001, 2002, 2003, 2004
+#   Copyright (C) 1997, 1998, 2000, 2001, 2002, 2003, 2004, 2005
 #   Free Software Foundation, Inc.
 
 #This file is part of GCC.
@@ -46,11 +46,9 @@ OBJECTIVE-C objective-c: cc1obj$(exeext)
 
 # Use maximal warnings for this front end.
 objc-warn = $(STRICT_WARN)
-# Bison-1.75 output yields (harmless) -Wtraditional warnings
-objc/objc-parse.o-warn = -Wno-error
 
 # Language-specific object files for Objective C.
-OBJC_OBJS = objc/objc-lang.o objc/objc-parse.o objc/objc-act.o
+OBJC_OBJS = objc/objc-lang.o objc/objc-act.o
 
 cc1obj$(exeext): $(OBJC_OBJS) $(C_AND_OBJC_OBJS) $(BACKEND) $(LIBDEPS)
        $(CC) $(ALL_CFLAGS) $(LDFLAGS) -o $@ \
@@ -64,28 +62,13 @@ objc/objc-lang.o : objc/objc-lang.c \
    $(GGC_H) langhooks.h $(LANGHOOKS_DEF_H) $(C_COMMON_H) gtype-objc.h \
    c-objc-common.h objc/objc-act.h
 
-objc/objc-parse.o : objc/objc-parse.c \
-   $(CONFIG_H) $(SYSTEM_H) coretypes.h $(TM_H) $(TREE_H) $(C_TREE_H) \
-   toplev.h $(GGC_H) input.h flags.h output.h langhooks.h $(C_COMMON_H) \
-   $(C_PRAGMA_H)
-
 objc/objc-act.o : objc/objc-act.c \
    $(CONFIG_H) $(SYSTEM_H) coretypes.h $(TM_H) $(TREE_H) $(RTL_H) $(TM_P_H) \
    $(EXPR_H) $(TARGET_H) $(C_TREE_H) diagnostic.h toplev.h flags.h \
    objc/objc-act.h input.h function.h output.h debug.h langhooks.h \
    $(LANGHOOKS_DEF_H) $(HASHTAB_H) c-pragma.h gt-objc-objc-act.h
 
-objc.srcextra: objc/objc-parse.c objc/objc-parse.y
-       -cp -p $^ $(srcdir)/objc
-
-objc/objc-parse.c : objc/objc-parse.y
-       -$(BISON) $(BISONFLAGS) -o $@ $<
-
-objc/objc-parse.y: c-parse.in
-       echo '/*WARNING: This file is automatically generated!*/' >tmp-objc-prs.y
-       sed -e "/^@@ifc.*/,/^@@end_ifc.*/d" \
-           -e "/^@@ifobjc.*/d" -e "/^@@end_ifobjc.*/d" < $< >>tmp-objc-prs.y
-       $(SHELL) $(srcdir)/../move-if-change tmp-objc-prs.y $@
+objc.srcextra:
 
 gtype-objc.h : s-gtype ; @true
 gt-objc-objc-act.h : s-gtype ; @true
@@ -103,7 +86,7 @@ objc.srcinfo:
 objc.srcman:
 
 objc.tags: force
-       cd $(srcdir)/objc; etags -o TAGS.sub *.y *.c *.h; \
+       cd $(srcdir)/objc; etags -o TAGS.sub *.c *.h; \
        etags --include TAGS.sub --include ../TAGS.sub
 
 lang_checks += check-objc
@@ -124,18 +107,14 @@ objc.uninstall:
 # A lot of the ancillary files are deleted by the main makefile.
 # We just have to delete files specific to us.
 objc.mostlyclean:
-       -rm -f tmp-objc-prs.y
        -rm -f objc/*$(objext) objc/xforward objc/fflags
-       -rm -f objc/objc-parse.y objc/objc-parse.c objc/objc-parse.output
        -rm -f objc/*$(coverageexts)
 objc.clean: objc.mostlyclean
        -rm -rf objc-headers
 objc.distclean:
        -rm -f objc/Makefile objc/Make-host objc/Make-target
        -rm -f objc/config.status objc/config.cache
-       -rm -f objc-parse.output
 objc.maintainer-clean:
-       -rm -f $(srcdir)/objc/objc-parse.y $(srcdir)/objc/objc-parse.c 
 
 #\f
 # Stage hooks:
index 72de2ff..fbb9a6e 100644 (file)
@@ -1,5 +1,5 @@
 # Top level configure fragment for GNU Objective-C
-#   Copyright (C) 1997, 1998, 2000, 2001, 2002, 2003, 2004
+#   Copyright (C) 1997, 1998, 2000, 2001, 2002, 2003, 2004, 2005
 #   Free Software Foundation, Inc.
 
 #This file is part of GCC.
@@ -37,4 +37,4 @@ target_libs=target-libobjc
 # Most of the object files for cc1obj actually come from C.
 lang_requires="c"
 
-gtfiles="\$(srcdir)/objc/objc-act.h \$(srcdir)/c-parse.in \$(srcdir)/c-tree.h \$(srcdir)/c-decl.c \$(srcdir)/c-objc-common.c \$(srcdir)/c-common.c \$(srcdir)/c-common.h \$(srcdir)/c-pragma.c \$(srcdir)/objc/objc-act.c"
+gtfiles="\$(srcdir)/objc/objc-act.h \$(srcdir)/c-parser.c \$(srcdir)/c-tree.h \$(srcdir)/c-decl.c \$(srcdir)/c-objc-common.c \$(srcdir)/c-common.c \$(srcdir)/c-common.h \$(srcdir)/c-pragma.c \$(srcdir)/objc/objc-act.c"
index f01fd9b..8c03da2 100644 (file)
@@ -2,7 +2,7 @@
    that are called from within the C and C++ front-ends,
    respectively.
    Copyright (C) 1991, 1995, 1997, 1998,
-   1999, 2000, 2001, 2002, 2003, 2004 Free Software Foundation, Inc.
+   1999, 2000, 2001, 2002, 2003, 2004, 2005 Free Software Foundation, Inc.
 
 This file is part of GCC.
 
@@ -254,3 +254,47 @@ objc_is_public (tree ARG_UNUSED (expr), tree ARG_UNUSED (identifier))
 {
   return 1;
 }
+
+tree
+objc_get_class_ivars (tree ARG_UNUSED (class_name))
+{
+  return 0;
+}
+
+tree
+objc_build_throw_stmt (tree ARG_UNUSED (throw_expr))
+{
+  return 0;
+}
+
+void
+objc_build_synchronized (location_t ARG_UNUSED (start_locus),
+                        tree ARG_UNUSED (mutex), tree ARG_UNUSED (body))
+{
+}
+
+void
+objc_begin_try_stmt (location_t ARG_UNUSED (try_locus), tree ARG_UNUSED (body))
+{
+}
+   
+void
+objc_begin_catch_clause (tree ARG_UNUSED (decl))
+{
+}
+
+void
+objc_finish_catch_clause (void)
+{
+}
+
+void
+objc_build_finally_clause (location_t ARG_UNUSED (finally_locus),
+                          tree ARG_UNUSED (body))
+{
+}
+
+void
+objc_finish_try_stmt (void)
+{
+}
index 5210413..ffa4977 100644 (file)
@@ -1,3 +1,9 @@
+2005-02-25  Joseph S. Myers  <joseph@codesourcery.com>
+
+       * gcc.dg/cpp/separate-1.c, gcc.dg/noncompile/971104-1.c,
+       gcc.dg/noncompile/990416-1.c: Adjust expected messages for new
+       parser.
+
 2005-02-25  Diego Novillo  <dnovillo@redhat.com>
 
        PR tree-optimization/20204
index 71dcfef..8698147 100644 (file)
@@ -12,4 +12,4 @@ int FOO( /* { dg-error "parse error|syntax error|expected" "error on this line"
        ), bar;
 
 int baz FOO /* { dg-error "parse error|syntax error|expected" "error on this line" } */
-; /* { dg-warning "no type or storage class" "warning on this line" } */
+;
index 4b02d71..722b71c 100644 (file)
@@ -25,5 +25,5 @@ static void up(int sem){
     ({ "MUTEX     ", "BARB_SEM 1", "BARB_SEM 2", "CUST_SEM 1",
        "CUST_SEM 2", "WAIT_SEM 1", "WAIT_SEM 2", "WAIT_SEM 3",
        "WAIT_SEM 4"}    /* { dg-error "parse error|syntax error|expected" } */
-       [( sb.sem_num )]) );
+       [( sb.sem_num )]) ); /* { dg-error "expected" } */
 }
index a0e02e2..49f5569 100644 (file)
@@ -3,7 +3,7 @@ typedef int word_type;
    
 static void
 copy_reg (unsigned int reg, frame_state *udata,        /* { dg-error "parse|syntax|expected" } */
-         frame_state *target_udata)
+         frame_state *target_udata)    /* { dg-error "expected" } */
 {  
   word_type *preg = get_reg_addr (reg, udata, 0);      /* { dg-error "undeclared|function|without a cast" } */
   word_type *ptreg = get_reg_addr (reg, target_udata, 0); /* { dg-error "undeclared|without a cast" } */