diff options
author | jsm28 <jsm28@138bc75d-0d04-0410-961f-82ee72b054a4> | 2005-02-25 23:20:48 +0000 |
---|---|---|
committer | jsm28 <jsm28@138bc75d-0d04-0410-961f-82ee72b054a4> | 2005-02-25 23:20:48 +0000 |
commit | 1576dec74bf91e0130a9a3aefa2656b575e17ec8 (patch) | |
tree | 3583a41269ae0a4769801c5116794c092decdc2a | |
parent | 588f2bd82944fab85be31aa6643e2dac9bbf58e0 (diff) | |
download | gcc-1576dec74bf91e0130a9a3aefa2656b575e17ec8.tar.gz |
* 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.
git-svn-id: svn+ssh://gcc.gnu.org/svn/gcc/trunk@95558 138bc75d-0d04-0410-961f-82ee72b054a4
-rw-r--r-- | gcc/ChangeLog | 23 | ||||
-rw-r--r-- | gcc/Makefile.in | 29 | ||||
-rw-r--r-- | gcc/c-config-lang.in | 4 | ||||
-rw-r--r-- | gcc/c-decl.c | 9 | ||||
-rw-r--r-- | gcc/c-parse.in | 3588 | ||||
-rw-r--r-- | gcc/c-parser.c | 6219 | ||||
-rw-r--r-- | gcc/c-tree.h | 6 | ||||
-rw-r--r-- | gcc/gengtype-lex.l | 4 | ||||
-rw-r--r-- | gcc/objc/ChangeLog | 8 | ||||
-rw-r--r-- | gcc/objc/Make-lang.in | 29 | ||||
-rw-r--r-- | gcc/objc/config-lang.in | 4 | ||||
-rw-r--r-- | gcc/stub-objc.c | 46 | ||||
-rw-r--r-- | gcc/testsuite/ChangeLog | 6 | ||||
-rw-r--r-- | gcc/testsuite/gcc.dg/cpp/separate-1.c | 2 | ||||
-rw-r--r-- | gcc/testsuite/gcc.dg/noncompile/971104-1.c | 2 | ||||
-rw-r--r-- | gcc/testsuite/gcc.dg/noncompile/990416-1.c | 2 |
16 files changed, 6335 insertions, 3646 deletions
diff --git a/gcc/ChangeLog b/gcc/ChangeLog index eebeac487e8..bc843db024d 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -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 diff --git a/gcc/Makefile.in b/gcc/Makefile.in index 93c33992c23..1be15cd8e62 100644 --- a/gcc/Makefile.in +++ b/gcc/Makefile.in @@ -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) # ------------------------------------------------------ diff --git a/gcc/c-config-lang.in b/gcc/c-config-lang.in index c0a786f53fd..6b5edc2a2d3 100644 --- a/gcc/c-config-lang.in +++ b/gcc/c-config-lang.in @@ -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" diff --git a/gcc/c-decl.c b/gcc/c-decl.c index 0b7b97ede23..690d3b3bc80 100644 --- a/gcc/c-decl.c +++ b/gcc/c-decl.c @@ -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 index fe0d51709eb..00000000000 --- a/gcc/c-parse.in +++ /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 - -@@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 - -%{ -/* 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 (); -} - -%} - -%% -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"); } - ; - -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 - ; - -/* 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); } - ; - -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; } - ; - - -/* 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; } - ; - -@@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; - } -} - -/* 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 index 00000000000..adebfd20589 --- /dev/null +++ b/gcc/c-parser.c @@ -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" + + +/* 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; + } +} + +/* 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; +} + + +/* 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; + } +} + + +/* 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" diff --git a/gcc/c-tree.h b/gcc/c-tree.h index 1cde4828348..d16d6a6892d 100644 --- a/gcc/c-tree.h +++ b/gcc/c-tree.h @@ -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(()) }; -/* in c-parse.in */ +/* in c-parser.c */ extern void c_parse_init (void); /* in c-aux-info.c */ diff --git a/gcc/gengtype-lex.l b/gcc/gengtype-lex.l index e2872eeffa4..096af89a8e3 100644 --- a/gcc/gengtype-lex.l +++ b/gcc/gengtype-lex.l @@ -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 */ diff --git a/gcc/objc/ChangeLog b/gcc/objc/ChangeLog index 88037f36bda..49e73af4960 100644 --- a/gcc/objc/ChangeLog +++ b/gcc/objc/ChangeLog @@ -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 diff --git a/gcc/objc/Make-lang.in b/gcc/objc/Make-lang.in index 08909437aa6..56fad72b149 100644 --- a/gcc/objc/Make-lang.in +++ b/gcc/objc/Make-lang.in @@ -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 # # Stage hooks: diff --git a/gcc/objc/config-lang.in b/gcc/objc/config-lang.in index 72de2ffc59d..fbb9a6e9e92 100644 --- a/gcc/objc/config-lang.in +++ b/gcc/objc/config-lang.in @@ -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" diff --git a/gcc/stub-objc.c b/gcc/stub-objc.c index f01fd9b4249..8c03da27545 100644 --- a/gcc/stub-objc.c +++ b/gcc/stub-objc.c @@ -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) +{ +} diff --git a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog index 52104138021..ffa4977f33b 100644 --- a/gcc/testsuite/ChangeLog +++ b/gcc/testsuite/ChangeLog @@ -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 diff --git a/gcc/testsuite/gcc.dg/cpp/separate-1.c b/gcc/testsuite/gcc.dg/cpp/separate-1.c index 71dcfef7f1d..8698147d521 100644 --- a/gcc/testsuite/gcc.dg/cpp/separate-1.c +++ b/gcc/testsuite/gcc.dg/cpp/separate-1.c @@ -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" } */ +; diff --git a/gcc/testsuite/gcc.dg/noncompile/971104-1.c b/gcc/testsuite/gcc.dg/noncompile/971104-1.c index 4b02d7174df..722b71c784f 100644 --- a/gcc/testsuite/gcc.dg/noncompile/971104-1.c +++ b/gcc/testsuite/gcc.dg/noncompile/971104-1.c @@ -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" } */ } diff --git a/gcc/testsuite/gcc.dg/noncompile/990416-1.c b/gcc/testsuite/gcc.dg/noncompile/990416-1.c index a0e02e20638..49f5569394e 100644 --- a/gcc/testsuite/gcc.dg/noncompile/990416-1.c +++ b/gcc/testsuite/gcc.dg/noncompile/990416-1.c @@ -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" } */ |