X-Git-Url: http://git.sourceforge.jp/view?a=blobdiff_plain;f=gcc%2Fc-parse.in;h=3a1c17eb70872cec0de3efb7bdee5fe77136f950;hb=0f92db9e6158b1d5fd2576f269f51b57339c35c6;hp=646183cc340ce4efbba1b31c731d2396acdf0271;hpb=389acd0a1c55fa82c7702b22cd1644d4450dfa63;p=pf3gnuchains%2Fgcc-fork.git diff --git a/gcc/c-parse.in b/gcc/c-parse.in index 646183cc340..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 %{ @@ -41,8 +41,12 @@ end ifc #include #include "tree.h" #include "input.h" +#include "cpplib.h" +#include "intl.h" +#include "timevar.h" #include "c-lex.h" #include "c-tree.h" +#include "c-pragma.h" #include "flags.h" #include "output.h" #include "toplev.h" @@ -59,7 +63,7 @@ end ifobjc /* Since parsers are distinct for each language, put the language string definition here. */ ifobjc -const char * const language_string = "GNU Obj-C"; +const char * const language_string = "GNU Objective-C"; end ifobjc ifc const char * const language_string = "GNU C"; @@ -68,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 */ @@ -117,8 +124,8 @@ end ifc %token REALPART IMAGPART VA_ARG %token PTR_VALUE PTR_BASE PTR_EXTENT -/* Used in c-lex.c for parsing pragmas. */ -%token END_OF_LINE +/* 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 @@ -150,46 +157,63 @@ end ifc %token CLASSNAME PUBLIC PRIVATE PROTECTED PROTOCOL OBJECTNAME CLASS ALIAS /* Objective-C string constants in raw form. - yylval is an OBJC_STRING_CST node. */ + yylval is an STRING_CST node. */ %token OBJC_STRING %type unop +%type ENUM STRUCT UNION IF ELSE WHILE DO FOR SWITCH CASE DEFAULT +%type BREAK CONTINUE RETURN GOTO ASM_KEYWORD SIZEOF TYPEOF ALIGNOF %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_nostart compstmt_primary_start +%type compstmt compstmt_start compstmt_nostart compstmt_primary_start +%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 @@ -248,13 +272,20 @@ tree objc_ivar_context; enum tree_code objc_inherit_code; int objc_receiver_context; int objc_public_flag; +int objc_pq_context; end ifobjc /* Tell yyparse how to print a token's value, if yydebug is set. */ #define YYPRINT(FILE,YYCHAR,YYLVAL) yyprint(FILE,YYCHAR,YYLVAL) -extern void yyprint PARAMS ((FILE *, int, YYSTYPE)); + +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)); /* Add GC roots for variables local to this file. */ void @@ -277,7 +308,7 @@ end ifobjc %% program: /* empty */ { if (pedantic) - pedwarn ("ANSI C forbids an empty source file"); + pedwarn ("ISO C forbids an empty source file"); finish_file (); } | extdefs @@ -286,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 (); } ; @@ -296,7 +330,7 @@ program: /* empty */ extdefs: {$$ = NULL_TREE; } extdef - | extdefs {$$ = NULL_TREE; } extdef + | extdefs {$$ = NULL_TREE; ggc_collect(); } extdef ; extdef: @@ -320,62 +354,64 @@ end ifobjc datadef: setspecs notype_initdecls ';' { if (pedantic) - error ("ANSI C forbids data definition with no type or storage class"); + error ("ISO C forbids data definition with no type or storage class"); else if (!flag_traditional) warning ("data definition has no type or storage class"); 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 '}' | ';' { if (pedantic) - pedwarn ("ANSI C does not allow extra `;' outside of a function"); } + pedwarn ("ISO C does not allow extra `;' outside of a function"); } ; fndef: - typed_declspecs setspecs declarator + declspecs_ts setspecs declarator { if (! start_function (current_declspecs, $3, prefix_attributes, NULL_TREE)) YYERROR1; - reinit_parse_for_function (); } + } 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; - reinit_parse_for_function (); } + } 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); } @@ -383,11 +419,13 @@ fndef: { if (! start_function (NULL_TREE, $2, prefix_attributes, NULL_TREE)) YYERROR1; - reinit_parse_for_function (); } + } 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); } @@ -411,7 +449,12 @@ unop: '&' | '-' { $$ = NEGATE_EXPR; } | '+' - { $$ = CONVERT_EXPR; } + { $$ = CONVERT_EXPR; +ifc + if (warn_traditional && !in_system_header) + warning ("traditional C rejects the unary plus operator"); +end ifc + } | PLUSPLUS { $$ = PREINCREMENT_EXPR; } | MINUSMINUS @@ -452,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 ("ANSI 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 @@ -474,7 +506,7 @@ unary_expr: else { if (pedantic) - pedwarn ("ANSI C forbids `&...'"); + pedwarn ("ISO C forbids `&...'"); $$ = tree_last (DECL_ARGUMENTS (current_function_decl)); $$ = build_unary_op (ADDR_EXPR, $$, 0); } } @@ -498,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: @@ -513,37 +543,7 @@ alignof: cast_expr: unary_expr | '(' typename ')' cast_expr %prec UNARY - { tree type = groktypename ($2); - $$ = 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 ("ANSI C 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: @@ -595,7 +595,7 @@ expr_no_commas: $$ = build_conditional_expr ($1, $4, $7); } | expr_no_commas '?' { if (pedantic) - pedwarn ("ANSI C forbids omitting the middle term of a ?: expression"); + pedwarn ("ISO C forbids omitting the middle term of a ?: expression"); /* Make sure first operand is calculated only once. */ $2 = save_expr ($1); $1 = truthvalue_conversion (default_conversion ($2)); @@ -632,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' @@ -641,70 +672,53 @@ primary: | '(' error ')' { $$ = error_mark_node; } | compstmt_primary_start compstmt_nostart ')' - { tree rtl_exp; - if (pedantic) - pedwarn ("ANSI C forbids braced-groups within expressions"); - pop_iterator_stack (); + { tree saved_last_tree; + + if (pedantic) + pedwarn ("ISO C forbids braced-groups within expressions"); pop_label_level (); - rtl_exp = expand_end_stmt_expr ($1); - /* The statements have side effects, so the group does. */ - TREE_SIDE_EFFECTS (rtl_exp) = 1; - if (TREE_CODE ($2) == BLOCK) - { - /* Make a BIND_EXPR for the BLOCK already made. */ - $$ = build (BIND_EXPR, TREE_TYPE (rtl_exp), - NULL_TREE, rtl_exp, $2); - /* Remove the block from the tree at this point. - It gets put back at the proper place - when the BIND_EXPR is expanded. */ - delete_block ($2); - } - else - $$ = $2; + saved_last_tree = COMPOUND_BODY ($1); + RECHAIN_STMTS ($1, COMPOUND_BODY ($1)); + last_tree = saved_last_tree; + TREE_CHAIN (last_tree) = NULL_TREE; + if (!last_expr_type) + last_expr_type = void_type_node; + $$ = build1 (STMT_EXPR, last_expr_type, $1); + TREE_SIDE_EFFECTS ($$) = 1; } | compstmt_primary_start error ')' { - /* Make sure we call expand_end_stmt_expr. Otherwise - we are likely to lose sequences and crash later. */ - pop_iterator_stack (); pop_label_level (); - expand_end_stmt_expr ($1); + last_tree = COMPOUND_BODY ($1); + TREE_CHAIN (last_tree) = NULL_TREE; $$ = error_mark_node; } | 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); } @@ -728,17 +742,28 @@ end ifobjc string: STRING | string STRING - { $$ = chainon ($1, $2); + { +ifc + static int last_lineno = 0; + static const char *last_input_filename = 0; +end ifc + $$ = chainon ($1, $2); ifc - if (warn_traditional && !in_system_header) - warning ("Use of ANSI string concatenation"); + if (warn_traditional && !in_system_header + && (lineno != last_lineno || !last_input_filename || + strcmp (last_input_filename, input_filename))) + { + warning ("traditional C rejects string concatenation"); + last_lineno = lineno; + last_input_filename = input_filename; + } end ifc } ; ifobjc -/* Produces an OBJC_STRING_CST with perhaps more OBJC_STRING_CSTs chained - onto it. */ +/* Produces an STRING_CST with perhaps more STRING_CSTs chained + onto it, which is to be read as an ObjC string object. */ objc_string: OBJC_STRING | objc_string OBJC_STRING @@ -753,7 +778,7 @@ old_style_parm_decls: /* ... is used here to indicate a varargs function. */ { c_mark_varargs (); if (pedantic) - pedwarn ("ANSI C does not permit use of `varargs.h'"); } + pedwarn ("ISO C does not permit use of `varargs.h'"); } ; /* The following are analogous to lineno_decl, decls and decl @@ -776,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"); } ; @@ -800,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, @@ -820,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_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_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; } + | 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; } - | declmods_no_prefix_attr SCSPEC + | 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)); @@ -927,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); } @@ -972,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: @@ -1096,7 +1533,7 @@ init: initlist_maybe_comma: /* empty */ { if (pedantic) - pedwarn ("ANSI C forbids empty initializer braces"); } + pedwarn ("ISO C forbids empty initializer braces"); } | initlist1 maybecomma ; @@ -1109,9 +1546,15 @@ initlist1: It may use braces. */ initelt: designator_list '=' initval + { if (pedantic && ! flag_isoc99) + pedwarn ("ISO C89 forbids specifying subobject to initialize"); } | designator initval + { if (pedantic) + pedwarn ("obsolete use of designated initializer without `='"); } | identifier ':' - { set_init_label ($1); } + { set_init_label ($1); + if (pedantic) + pedwarn ("obsolete use of designated initializer with `:'"); } initval | initval ; @@ -1139,7 +1582,9 @@ designator: so don't include these productions in the Objective-C grammar. */ ifc | '[' expr_no_commas ELLIPSIS expr_no_commas ']' - { set_init_index ($2, $4); } + { set_init_index ($2, $4); + if (pedantic) + pedwarn ("ISO C forbids specifying range of elements to initialize"); } | '[' expr_no_commas ']' { set_init_index ($2, NULL_TREE); } end ifc @@ -1148,7 +1593,7 @@ end ifc nested_function: declarator { if (pedantic) - pedwarn ("ANSI C forbids nested functions"); + pedwarn ("ISO C forbids nested functions"); push_function_context (); if (! start_function (current_declspecs, $1, @@ -1157,7 +1602,7 @@ nested_function: pop_function_context (); YYERROR1; } - reinit_parse_for_function (); } + } old_style_parm_decls { store_parm_decls (); } /* This used to use compstmt_or_error. @@ -1166,15 +1611,19 @@ 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 - { finish_function (1); - pop_function_context (); } + 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); } ; notype_nested_function: notype_declarator { if (pedantic) - pedwarn ("ANSI C forbids nested functions"); + pedwarn ("ISO C forbids nested functions"); push_function_context (); if (! start_function (current_declspecs, $1, @@ -1183,7 +1632,7 @@ notype_nested_function: pop_function_context (); YYERROR1; } - reinit_parse_for_function (); } + } old_style_parm_decls { store_parm_decls (); } /* This used to use compstmt_or_error. @@ -1192,9 +1641,13 @@ 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 - { finish_function (1); - pop_function_context (); } + 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); } ; /* Any kind of declarator (thus, all declarators allowed @@ -1208,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 '.' @@ -1219,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 @@ -1238,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 '(' error ')' %prec '.' +/* | parm_declarator_starttypename '(' error ')' %prec '.' { $$ = build_nt (CALL_EXPR, $1, NULL_TREE, NULL_TREE); poplevel (0, 0, 0); } */ ifc - | parm_declarator '[' '*' ']' %prec '.' + | 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 '[' expr ']' %prec '.' + | parm_declarator_starttypename '[' expr ']' %prec '.' { $$ = build_nt (ARRAY_REF, $1, $3); } - | parm_declarator '[' ']' %prec '.' + | parm_declarator_starttypename '[' ']' %prec '.' { $$ = build_nt (ARRAY_REF, $1, NULL_TREE); } - | '*' type_quals parm_declarator %prec UNARY + | TYPENAME + ; + +parm_declarator_nostarttypename: + parm_declarator_nostarttypename '(' parmlist_or_identifiers %prec '.' + { $$ = build_nt (CALL_EXPR, $1, $3, NULL_TREE); } +/* | parm_declarator_nostarttypename '(' error ')' %prec '.' + { $$ = build_nt (CALL_EXPR, $1, NULL_TREE, NULL_TREE); + poplevel (0, 0, 0); } */ +ifc + | 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_nostarttypename '[' expr ']' %prec '.' + { $$ = build_nt (ARRAY_REF, $1, $3); } + | parm_declarator_nostarttypename '[' ']' %prec '.' + { $$ = build_nt (ARRAY_REF, $1, NULL_TREE); } + | '*' 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 @@ -1277,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 '.' @@ -1292,13 +1758,6 @@ end ifc { $$ = 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; } | IDENTIFIER ; @@ -1323,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. */ @@ -1334,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 @@ -1344,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 @@ -1356,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: @@ -1405,42 +1877,33 @@ 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 MS P-SDK). */ if (pedantic) - pedwarn ("ANSI C doesn't support unnamed structs/unions"); + pedwarn ("ISO C doesn't support unnamed structs/unions"); $$ = grokfield($3, $4, NULL, current_declspecs, NULL_TREE); current_declspecs = TREE_VALUE (declspec_stack); 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 ("ANSI C forbids member declarations with no members"); + pedwarn ("ISO C forbids member declarations with no members"); shadow_tag($1); $$ = NULL_TREE; } | error @@ -1452,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: @@ -1469,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. @@ -1494,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 */ @@ -1506,79 +1994,118 @@ 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; } + +/* 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 + { + pedwarn ("deprecated use of 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 ; -/* 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. */ +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 + ; -stmts: - lineno_stmt_or_labels - { - if (pedantic && $1) - pedwarn ("ANSI C forbids label at end of compound statement"); - } +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_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_error: + errstmt + | lineno_stmt_decl_or_labels errstmt ; -xstmts: - /* empty */ - | stmts +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 ';' ; pushlevel: /* empty */ - { emit_line_note (input_filename, lineno); - pushlevel (0); + { pushlevel (0); clear_last_expr (); - expand_start_bindings (0); + add_scope_stmt (/*begin_p=*/1, /*partial_p=*/0); ifobjc if (objc_method_context) add_objc_decls (); @@ -1586,13 +2113,50 @@ end ifobjc } ; +poplevel: /* empty */ + { $$ = add_scope_stmt (/*begin_p=*/0, /*partial_p=*/0); } + +/* Start and end blocks created for the new scopes of C99. */ +c99_block_start: /* empty */ + { if (flag_isoc99) + { + $$ = c_begin_compound_stmt (); + pushlevel (0); + clear_last_expr (); + add_scope_stmt (/*begin_p=*/1, /*partial_p=*/0); +ifobjc + if (objc_method_context) + add_objc_decls (); +end ifobjc + } + else + $$ = NULL_TREE; + } + ; + +/* Productions using c99_block_start and c99_block_end will need to do what's + in compstmt: RECHAIN_STMTS ($1, COMPOUND_BODY ($1)); $$ = $2; where + $1 is the value of c99_block_start and $2 of c99_block_end. */ +c99_block_end: /* empty */ + { if (flag_isoc99) + { + tree scope_stmt = add_scope_stmt (/*begin_p=*/0, /*partial_p=*/0); + $$ = poplevel (kept_level_p (), 0, 0); + SCOPE_STMT_BLOCK (TREE_PURPOSE (scope_stmt)) + = SCOPE_STMT_BLOCK (TREE_VALUE (scope_stmt)) + = $$; + } + else + $$ = NULL_TREE; } + ; + /* Read zero or more forward-declarations for labels that nested functions can jump to. */ maybe_label_decls: /* empty */ | label_decls { if (pedantic) - pedwarn ("ANSI C forbids label declarations"); } + pedwarn ("ISO C forbids label declarations"); } ; label_decls: @@ -1607,7 +2171,7 @@ label_decl: { tree label = shadow_label (TREE_VALUE (link)); C_DECLARED_LABEL_FLAG (label) = 1; - declare_nonlocal_label (label); + add_decl_stmt (label); } } ; @@ -1620,22 +2184,21 @@ compstmt_or_error: | error compstmt ; -compstmt_start: '{' { compstmt_count++; } +compstmt_start: '{' { compstmt_count++; + $$ = c_begin_compound_stmt (); } compstmt_nostart: '}' { $$ = convert (void_type_node, integer_zero_node); } - | pushlevel maybe_label_decls decls xstmts '}' - { emit_line_note (input_filename, lineno); - expand_end_bindings (getdecls (), 1, 0); - $$ = poplevel (1, 1, 0); } - | pushlevel maybe_label_decls error '}' - { emit_line_note (input_filename, lineno); - expand_end_bindings (getdecls (), kept_level_p (), 0); - $$ = poplevel (kept_level_p (), 0, 0); } - | pushlevel maybe_label_decls stmts '}' - { emit_line_note (input_filename, lineno); - expand_end_bindings (getdecls (), kept_level_p (), 0); - $$ = 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: @@ -1650,19 +2213,20 @@ compstmt_primary_start: there is a way to turn off the entire subtree of blocks that are contained in it. */ keep_next_level (); - push_iterator_stack (); push_label_level (); - $$ = expand_start_stmt_expr (); compstmt_count++; + $$ = add_stmt (build_stmt (COMPOUND_STMT, last_tree)); } compstmt: compstmt_start compstmt_nostart - { $$ = $2; } + { RECHAIN_STMTS ($1, COMPOUND_BODY ($1)); + $$ = $1; } ; /* Value is number of statements counted as of the closeparen. */ simple_if: - if_prefix lineno_labeled_stmt + if_prefix c99_block_lineno_labeled_stmt + { c_finish_then (); } /* Make sure c_expand_end_cond is run once for each call to c_expand_start_cond. Otherwise a crash is likely. */ @@ -1671,13 +2235,11 @@ simple_if: if_prefix: IF '(' expr ')' - { emit_line_note ($-1, $0); - c_expand_start_cond (truthvalue_conversion ($3), 0, + { c_expand_start_cond (truthvalue_conversion ($3), compstmt_count); $$ = stmt_count; - if_stmt_file = $-1; - if_stmt_line = $0; - position_after_white_space (); } + if_stmt_file = $-2; + if_stmt_line = $-1; } ; /* This is a subroutine of stmt. @@ -1687,72 +2249,76 @@ do_stmt_start: DO { stmt_count++; compstmt_count++; - emit_line_note ($-1, $0); - /* See comment in `while' alternative, above. */ - emit_nop (); - expand_start_loop_continue_elsewhere (1); - position_after_white_space (); } - lineno_labeled_stmt WHILE - { expand_loop_continue_here (); } - ; - + $$ + = add_stmt (build_stmt (DO_STMT, NULL_TREE, + NULL_TREE)); + /* In the event that a parse error prevents + parsing the complete do-statement, set the + condition now. Otherwise, we can get crashes at + RTL-generation time. */ + DO_COND ($$) = error_mark_node; } + c99_block_lineno_labeled_stmt WHILE + { $$ = $2; + RECHAIN_STMTS ($$, DO_BODY ($$)); } + ; + +/* 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_filename: - { $$ = input_filename; } + { if (yychar == YYEMPTY) + yychar = YYLEX; + $$ = input_filename; } ; save_lineno: - { $$ = lineno; } + { if (yychar == YYEMPTY) + yychar = YYLEX; + $$ = 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 ; -lineno_stmt_or_label: - save_filename save_lineno stmt_or_label - { $$ = $3; } +/* Like lineno_labeled_stmt, but a block in C99. */ +c99_block_lineno_labeled_stmt: + c99_block_start lineno_labeled_stmt c99_block_end + { if (flag_isoc99) + RECHAIN_STMTS ($1, COMPOUND_BODY ($1)); } ; -stmt_or_label: - stmt - { $$ = 0; } - | label - { $$ = 1; } +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. */ + } + } ; -/* Parse a single real statement, not including any labels. */ -stmt: - compstmt - { stmt_count++; } - | all_iter_stmt - | expr ';' - { stmt_count++; - emit_line_note ($-1, $0); -/* It appears that this should not be done--that a non-lvalue array - shouldn't get an error if the value isn't used. - Section 3.2.2.1 says that an array lvalue gets converted to a pointer - if it appears as a top-level expression, - but says nothing about non-lvalue arrays. */ -#if 0 - /* Call default_conversion to get an error - on referring to a register array if pedantic. */ - if (TREE_CODE (TREE_TYPE ($1)) == ARRAY_TYPE - || TREE_CODE (TREE_TYPE ($1)) == FUNCTION_TYPE) - $1 = default_conversion ($1); -#endif - iterator_expand ($1); } - | simple_if ELSE +lineno_label: + save_filename save_lineno label + { if ($3) + { + STMT_LINENO ($3) = $2; + } + } + ; + +select_or_iter_stmt: + simple_if ELSE { c_expand_start_else (); - $1 = stmt_count; - position_after_white_space (); } - lineno_labeled_stmt - { c_expand_end_cond (); + $1 = stmt_count; } + c99_block_lineno_labeled_stmt + { c_finish_else (); + c_expand_end_cond (); if (extra_warnings && stmt_count == $1) warning ("empty body in an else-statement"); } | simple_if %prec IF @@ -1770,232 +2336,132 @@ stmt: | simple_if ELSE error { c_expand_end_cond (); } | WHILE - { stmt_count++; - emit_line_note ($-1, $0); - /* The emit_nop used to come before emit_line_note, - but that made the nop seem like part of the preceding line. - And that was confusing when the preceding line was - inside of an if statement and was not really executed. - I think it ought to work to put the nop after the line number. - We will see. --rms, July 15, 1991. */ - emit_nop (); } + { stmt_count++; } '(' expr ')' - { /* Don't start the loop till we have succeeded - in parsing the end test. This is to make sure - that we end every loop we start. */ - expand_start_loop (1); - emit_line_note (input_filename, lineno); - expand_exit_loop_if_false (NULL_PTR, - truthvalue_conversion ($4)); - position_after_white_space (); } - lineno_labeled_stmt - { expand_end_loop (); } + { $4 = truthvalue_conversion ($4); + $$ + = add_stmt (build_stmt (WHILE_STMT, $4, NULL_TREE)); } + c99_block_lineno_labeled_stmt + { RECHAIN_STMTS ($6, WHILE_BODY ($6)); } | do_stmt_start '(' expr ')' ';' - { emit_line_note (input_filename, lineno); - expand_exit_loop_if_false (NULL_PTR, - truthvalue_conversion ($3)); - expand_end_loop (); } -/* This rule is needed to make sure we end every loop we start. */ + { DO_COND ($1) = truthvalue_conversion ($3); } | do_stmt_start error - { expand_end_loop (); } + { } | FOR - '(' xexpr ';' + { $$ = build_stmt (FOR_STMT, NULL_TREE, NULL_TREE, + NULL_TREE, NULL_TREE); + add_stmt ($$); } + '(' for_init_stmt { stmt_count++; - emit_line_note ($-1, $0); - /* See comment in `while' alternative, above. */ - emit_nop (); - if ($3) c_expand_expr_stmt ($3); - /* Next step is to call expand_start_loop_continue_elsewhere, - but wait till after we parse the entire for (...). - Otherwise, invalid input might cause us to call that - fn without calling expand_end_loop. */ - } + RECHAIN_STMTS ($2, FOR_INIT_STMT ($2)); } xexpr ';' - /* Can't emit now; wait till after expand_start_loop... */ - { $7 = lineno; - $$ = input_filename; } + { if ($6) + FOR_COND ($2) = truthvalue_conversion ($6); } xexpr ')' - { - /* Start the loop. Doing this after parsing - all the expressions ensures we will end the loop. */ - expand_start_loop_continue_elsewhere (1); - /* Emit the end-test, with a line number. */ - emit_line_note ($8, $7); - if ($6) - expand_exit_loop_if_false (NULL_PTR, - truthvalue_conversion ($6)); - $7 = lineno; - $8 = input_filename; - position_after_white_space (); } - lineno_labeled_stmt - { /* Emit the increment expression, with a line number. */ - emit_line_note ($8, $7); - expand_loop_continue_here (); - if ($9) - c_expand_expr_stmt ($9); - expand_end_loop (); } + { FOR_EXPR ($2) = $9; } + c99_block_lineno_labeled_stmt + { RECHAIN_STMTS ($2, FOR_BODY ($2)); } | SWITCH '(' expr ')' { stmt_count++; - emit_line_note ($-1, $0); - c_expand_start_case ($3); - position_after_white_space (); } - lineno_labeled_stmt - { expand_end_case ($3); } + $$ = c_start_case ($3); } + c99_block_lineno_labeled_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++; $$ = $1; } + | expr ';' + { stmt_count++; + $$ = c_expand_expr_stmt ($1); } + | c99_block_start select_or_iter_stmt c99_block_end + { if (flag_isoc99) + RECHAIN_STMTS ($1, COMPOUND_BODY ($1)); + $$ = NULL_TREE; } | BREAK ';' - { tree break_stmt = build_break_stmt (); - stmt_count++; - genrtl_break_stmt (); } + { stmt_count++; + $$ = add_stmt (build_break_stmt ()); } | CONTINUE ';' - { tree continue_stmt = build_continue_stmt (); - stmt_count++; - genrtl_continue_stmt (); } + { stmt_count++; + $$ = add_stmt (build_continue_stmt ()); } | RETURN ';' - { tree return_stmt = build_return_stmt (NULL_TREE); - stmt_count++; - genrtl_return_stmt (RETURN_EXPR(return_stmt)); } + { stmt_count++; + $$ = c_expand_return (NULL_TREE); } | RETURN expr ';' - { tree return_stmt = build_return_stmt ($2); - stmt_count++; - genrtl_return_stmt (RETURN_EXPR(return_stmt)); } + { stmt_count++; + $$ = c_expand_return ($2); } | ASM_KEYWORD maybe_type_qual '(' expr ')' ';' { stmt_count++; - emit_line_note ($-1, $0); - STRIP_NOPS ($4); - if ((TREE_CODE ($4) == ADDR_EXPR - && TREE_CODE (TREE_OPERAND ($4, 0)) == STRING_CST) - || TREE_CODE ($4) == STRING_CST) - expand_asm ($4); - 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++; - emit_line_note ($-1, $0); - 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++; - emit_line_note ($-1, $0); - 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++; - emit_line_note ($-1, $0); - 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++; - emit_line_note ($-1, $0); decl = lookup_label ($2); if (decl != 0) { TREE_USED (decl) = 1; - expand_goto (decl); + $$ = add_stmt (build_stmt (GOTO_STMT, decl)); } + else + $$ = NULL_TREE; } | GOTO '*' expr ';' { if (pedantic) - pedwarn ("ANSI C forbids `goto *expr;'"); + pedwarn ("ISO C forbids `goto *expr;'"); stmt_count++; - emit_line_note ($-1, $0); - expand_computed_goto (convert (ptr_type_node, $3)); } + $3 = convert (ptr_type_node, $3); + $$ = add_stmt (build_stmt (GOTO_STMT, $3)); } | ';' + { $$ = NULL_TREE; } ; -all_iter_stmt: - all_iter_stmt_simple -/* | all_iter_stmt_with_decl */ - ; - -all_iter_stmt_simple: - FOR '(' primary ')' - { - /* The value returned by this action is */ - /* 1 if everything is OK */ - /* 0 in case of error or already bound iterator */ - - $$ = 0; - if (TREE_CODE ($3) != VAR_DECL) - error ("invalid `for (ITERATOR)' syntax"); - else if (! ITERATOR_P ($3)) - error ("`%s' is not an iterator", - IDENTIFIER_POINTER (DECL_NAME ($3))); - else if (ITERATOR_BOUND_P ($3)) - error ("`for (%s)' inside expansion of same iterator", - IDENTIFIER_POINTER (DECL_NAME ($3))); - else - { - $$ = 1; - iterator_for_loop_start ($3); - } - } - lineno_labeled_stmt - { - if ($5) - iterator_for_loop_end ($3); - } - -/* This really should allow any kind of declaration, - for generality. Fix it before turning it back on. - -all_iter_stmt_with_decl: - FOR '(' ITERATOR pushlevel setspecs iterator_spec ')' - { -*/ /* The value returned by this action is */ - /* 1 if everything is OK */ - /* 0 in case of error or already bound iterator */ -/* - iterator_for_loop_start ($6); - } - lineno_labeled_stmt - { - iterator_for_loop_end ($6); - emit_line_note (input_filename, lineno); - expand_end_bindings (getdecls (), 1, 0); - $$ = poplevel (1, 1, 0); - } -*/ - /* 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 ':' - { tree case_label_tree = build_case_label ($2, NULL_TREE); - stmt_count++; - genrtl_case_label(CASE_LOW(case_label_tree), CASE_HIGH(case_label_tree)); - position_after_white_space (); - } + { stmt_count++; + $$ = do_case ($2, NULL_TREE); } | CASE expr_no_commas ELLIPSIS expr_no_commas ':' - { tree case_label_tree = build_case_label ($2, $4); - stmt_count++; - genrtl_case_label(CASE_LOW(case_label_tree), CASE_HIGH(case_label_tree)); - position_after_white_space (); - } + { stmt_count++; + $$ = do_case ($2, $4); } | DEFAULT ':' - { tree case_label_tree = build_case_label (NULL_TREE, NULL_TREE); - stmt_count++; - genrtl_case_label(CASE_LOW(case_label_tree), CASE_HIGH(case_label_tree)); - position_after_white_space (); - } - | identifier ':' maybe_attribute - { tree label = define_label (input_filename, lineno, $1); + { stmt_count++; + $$ = do_case (NULL_TREE, NULL_TREE); } + | identifier save_filename save_lineno ':' maybe_attribute + { tree label = define_label ($2, $3, $1); stmt_count++; - emit_nop (); if (label) { - expand_label (label); - decl_attributes (label, $3, NULL_TREE); + decl_attributes (label, $5, NULL_TREE); + $$ = add_stmt (build_stmt (LABEL_STMT, label)); } - position_after_white_space (); } + else + $$ = NULL_TREE; + } ; /* Either a type-qualifier or nothing. First thing in an `asm' statement. */ @@ -2040,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); } ; @@ -2056,13 +2526,16 @@ parmlist_1: | parms ';' { tree parm; if (pedantic) - pedwarn ("ANSI C forbids forward parameter declarations"); + pedwarn ("ISO C forbids forward parameter declarations"); /* Mark the forward decls as such. */ 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); } ; @@ -2079,7 +2552,7 @@ parmlist_2: /* empty */ it caused problems with the code in expand_builtin which tries to verify that BUILT_IN_NEXT_ARG is being used correctly. */ - error ("ANSI C requires a named argument before `...'"); + error ("ISO C requires a named argument before `...'"); } | parms { $$ = get_parm_info (1); } @@ -2088,7 +2561,7 @@ parmlist_2: /* empty */ ; parms: - parm + firstparm { push_parm_decl ($1); } | parms ',' parm { push_parm_decl ($3); } @@ -2097,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, @@ -2105,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, @@ -2113,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, @@ -2121,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, @@ -2129,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, @@ -2138,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 @@ -2354,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; } @@ -2419,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); @@ -2437,7 +2949,7 @@ ivars: /* empty */ { $$ = NULL_TREE; } | ivar_declarator - | ivars ',' ivar_declarator + | ivars ',' maybe_setattrs ivar_declarator ; ivar_declarator: @@ -2463,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; } @@ -2537,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 ; @@ -2612,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"); } ; @@ -2643,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: @@ -2693,25 +3173,9 @@ selector: ; reservedwords: - ENUM { $$ = get_identifier (token_buffer); } - | STRUCT { $$ = get_identifier (token_buffer); } - | UNION { $$ = get_identifier (token_buffer); } - | IF { $$ = get_identifier (token_buffer); } - | ELSE { $$ = get_identifier (token_buffer); } - | WHILE { $$ = get_identifier (token_buffer); } - | DO { $$ = get_identifier (token_buffer); } - | FOR { $$ = get_identifier (token_buffer); } - | SWITCH { $$ = get_identifier (token_buffer); } - | CASE { $$ = get_identifier (token_buffer); } - | DEFAULT { $$ = get_identifier (token_buffer); } - | BREAK { $$ = get_identifier (token_buffer); } - | CONTINUE { $$ = get_identifier (token_buffer); } - | RETURN { $$ = get_identifier (token_buffer); } - | GOTO { $$ = get_identifier (token_buffer); } - | ASM_KEYWORD { $$ = get_identifier (token_buffer); } - | SIZEOF { $$ = get_identifier (token_buffer); } - | TYPEOF { $$ = get_identifier (token_buffer); } - | ALIGNOF { $$ = get_identifier (token_buffer); } + ENUM | STRUCT | UNION | IF | ELSE | WHILE | DO | FOR + | SWITCH | CASE | DEFAULT | BREAK | CONTINUE | RETURN + | GOTO | ASM_KEYWORD | SIZEOF | TYPEOF | ALIGNOF | TYPESPEC | TYPE_QUAL ; @@ -2842,3 +3306,638 @@ objcencodeexpr: 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_TRAD 0x01 /* not in traditional C */ +#define D_C89 0x02 /* not in C89 */ +#define D_EXT 0x04 /* GCC extension */ +#define D_EXT89 0x08 /* GCC extension incorporated in C99 */ +#define D_OBJC 0x10 /* 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 }, + { "__bounded", RID_BOUNDED, 0 }, + { "__bounded__", RID_BOUNDED, 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 }, + { "__ptrbase", RID_PTRBASE, 0 }, + { "__ptrbase__", RID_PTRBASE, 0 }, + { "__ptrextent", RID_PTREXTENT, 0 }, + { "__ptrextent__", RID_PTREXTENT, 0 }, + { "__ptrvalue", RID_PTRVALUE, 0 }, + { "__ptrvalue__", RID_PTRVALUE, 0 }, + { "__real", RID_REALPART, 0 }, + { "__real__", RID_REALPART, 0 }, + { "__restrict", RID_RESTRICT, 0 }, + { "__restrict__", RID_RESTRICT, 0 }, + { "__signed", RID_SIGNED, 0 }, + { "__signed__", RID_SIGNED, 0 }, + { "__typeof", RID_TYPEOF, 0 }, + { "__typeof__", RID_TYPEOF, 0 }, + { "__unbounded", RID_UNBOUNDED, 0 }, + { "__unbounded__", RID_UNBOUNDED, 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, D_TRAD }, + { "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_TRAD|D_EXT89 }, + { "int", RID_INT, 0 }, + { "long", RID_LONG, 0 }, + { "register", RID_REGISTER, 0 }, + { "restrict", RID_RESTRICT, D_TRAD|D_C89 }, + { "return", RID_RETURN, 0 }, + { "short", RID_SHORT, 0 }, + { "signed", RID_SIGNED, D_TRAD }, + { "sizeof", RID_SIZEOF, 0 }, + { "static", RID_STATIC, 0 }, + { "struct", RID_STRUCT, 0 }, + { "switch", RID_SWITCH, 0 }, + { "typedef", RID_TYPEDEF, 0 }, + { "typeof", RID_TYPEOF, D_TRAD|D_EXT }, + { "union", RID_UNION, 0 }, + { "unsigned", RID_UNSIGNED, 0 }, + { "void", RID_VOID, 0 }, + { "volatile", RID_VOLATILE, D_TRAD }, + { "while", RID_WHILE, 0 }, +ifobjc + { "@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 }, + { "id", RID_ID, D_OBJC }, + { "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 */ SCSPEC, + /* 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_BOUNDED */ TYPE_QUAL, + /* RID_UNBOUNDED */ TYPE_QUAL, + /* RID_COMPLEX */ TYPESPEC, + + /* C++ */ + /* RID_FRIEND */ 0, + /* RID_VIRTUAL */ 0, + /* RID_EXPLICIT */ 0, + /* RID_EXPORT */ 0, + /* RID_MUTABLE */ 0, + + /* ObjC */ + /* RID_IN */ TYPE_QUAL, + /* RID_OUT */ TYPE_QUAL, + /* RID_INOUT */ TYPE_QUAL, + /* RID_BYCOPY */ TYPE_QUAL, + /* RID_BYREF */ TYPE_QUAL, + /* RID_ONEWAY */ TYPE_QUAL, + + /* 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_PTRBASE */ PTR_BASE, + /* 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, + /* 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_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, + + /* alternate spellings */ + /* RID_AND */ 0, + /* RID_AND_EQ */ 0, + /* RID_NOT */ 0, + /* RID_NOT_EQ */ 0, + /* RID_OR */ 0, + /* RID_OR_EQ */ 0, + /* RID_XOR */ 0, + /* RID_XOR_EQ */ 0, + /* RID_BITAND */ 0, + /* RID_BITOR */ 0, + /* RID_COMPL */ 0, + + /* Objective C */ + /* RID_ID */ OBJECTNAME, + /* RID_AT_ENCODE */ ENCODE, + /* RID_AT_END */ END, + /* RID_AT_CLASS */ CLASS, + /* RID_AT_ALIAS */ ALIAS, + /* RID_AT_DEFS */ DEFS, + /* RID_AT_PRIVATE */ PRIVATE, + /* RID_AT_PROTECTED */ PROTECTED, + /* RID_AT_PUBLIC */ PUBLIC, + /* RID_AT_PROTOCOL */ PROTOCOL, + /* RID_AT_SELECTOR */ SELECTOR, + /* RID_AT_INTERFACE */ INTERFACE, + /* 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 = (flag_isoc99 ? 0 : D_C89) + | (flag_traditional ? D_TRAD : 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 + get_identifier hash anyway. */ + ridpointers = (tree *) xcalloc ((int) RID_MAX, sizeof (tree)); + 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; + +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 + } +} + +const char * +init_parse (filename) + const char *filename; +{ + add_c_tree_codes (); + + /* Make identifier nodes long enough for the language-specific slots. */ + set_identifier_size (sizeof (struct lang_identifier)); + + init_reswords (); + init_pragma (); + + return init_c_lex (filename); +} + +void +finish_parse () +{ + cpp_finish (parse_in); + /* Call to cpp_destroy () omitted for performance reasons. */ + errorcount += cpp_errors (parse_in); +} + +#define NAME(type) cpp_type2name (type) + +static void +yyerror (msgid) + const char *msgid; +{ + const char *string = _(msgid); + + if (last_token == CPP_EOF) + error ("%s at end of input", string); + else if (last_token == CPP_CHAR || last_token == CPP_WCHAR) + { + unsigned int val = TREE_INT_CST_LOW (yylval.ttype); + const char *ell = (last_token == CPP_CHAR) ? "" : "L"; + if (val <= UCHAR_MAX && ISGRAPH (val)) + error ("%s before %s'%c'", string, ell, val); + else + error ("%s before %s'\\x%x'", string, ell, val); + } + else if (last_token == CPP_STRING + || last_token == CPP_WSTRING) + error ("%s before string constant", string); + else if (last_token == CPP_NUMBER + || last_token == CPP_INT + || last_token == CPP_FLOAT) + error ("%s before numeric constant", string); + else if (last_token == CPP_NAME) + error ("%s before \"%s\"", string, IDENTIFIER_POINTER (yylval.ttype)); + else + 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 () +{ + get_next: + last_token = c_lex (&yylval.ttype); +ifobjc + reconsider: +end ifobjc + 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_COLON: return ':'; + case CPP_COMMA: return ','; + case CPP_OPEN_PAREN: return '('; + case CPP_CLOSE_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_SEMICOLON: 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 '.'; + + case CPP_EOF: + if (cpp_pop_buffer (parse_in) == 0) + return 0; + goto get_next; + + case CPP_NAME: + return yylexname (); + + case CPP_INT: + case CPP_FLOAT: + case CPP_NUMBER: + case CPP_CHAR: + case CPP_WCHAR: + return CONSTANT; + + case CPP_STRING: + case CPP_WSTRING: + return 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: + 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 '%s' token", NAME(last_token)); + goto get_next; + + default: + abort (); + } + /* NOTREACHED */ +} + +static int +yylex() +{ + int r; + timevar_push (TV_LEX); + r = _yylex(); + timevar_pop (TV_LEX); + return r; +} + +/* Sets the value of the 'yydebug' variable to VALUE. + This is a function so we don't have to have YYDEBUG defined + in order to build the compiler. */ + +void +set_yydebug (value) + int value; +{ +#if YYDEBUG != 0 + yydebug = value; +#else + warning ("YYDEBUG not defined."); +#endif +} + +/* Function used when yydebug is set, to print a token in more detail. */ + +static void +yyprint (file, yychar, yyl) + FILE *file; + int yychar; + YYSTYPE yyl; +{ + tree t = yyl.ttype; + + fprintf (file, " [%s]", NAME(last_token)); + + switch (yychar) + { + case IDENTIFIER: + case TYPENAME: + case OBJECTNAME: + case TYPESPEC: + case TYPE_QUAL: + case SCSPEC: + 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) + fprintf (file, +#if HOST_BITS_PER_WIDE_INT == 64 +#if HOST_BITS_PER_WIDE_INT == HOST_BITS_PER_INT + " 0x%x%016x", +#else +#if HOST_BITS_PER_WIDE_INT == HOST_BITS_PER_LONG + " 0x%lx%016lx", +#else + " 0x%llx%016llx", +#endif +#endif +#else +#if HOST_BITS_PER_WIDE_INT != HOST_BITS_PER_INT + " 0x%lx%08lx", +#else + " 0x%x%08x", +#endif +#endif + TREE_INT_CST_HIGH (t), TREE_INT_CST_LOW (t)); + break; + } +} + +/* This is not the ideal place to put these, but we have to get them out + of c-lex.c because cp/lex.c has its own versions. */ + +/* Return something to represent absolute declarators containing a *. + TARGET is the absolute declarator that the * contains. + TYPE_QUALS is a list of modifiers such as const or volatile + to apply to the pointer type, represented as identifiers. + + We return an INDIRECT_REF whose "contents" are TARGET + and whose type is the modifier list. */ + +tree +make_pointer_declarator (type_quals, target) + tree type_quals, target; +{ + return build1 (INDIRECT_REF, type_quals, target); +}