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