/* YACC parser for C++ syntax. Copyright (C) 1988, 1989, 1993, 1994, 1995 Free Software Foundation, Inc. Hacked by Michael Tiemann (tiemann@cygnus.com) This file is part of GNU CC. GNU CC is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2, or (at your option) any later version. GNU CC is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with GNU CC; see the file COPYING. If not, write to the Free Software Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ /* This grammar is based on the GNU CC grammar. */ /* Note: Bison automatically applies a default action of "$$ = $1" for all derivations; this is applied before the explicit action, if one is given. Keep this in mind when reading the actions. */ %{ /* Cause the `yydebug' variable to be defined. */ #define YYDEBUG 1 #include "config.h" #include #include #include "tree.h" #include "input.h" #include "flags.h" #include "lex.h" #include "cp-tree.h" #include "output.h" /* Since parsers are distinct for each language, put the language string definition here. (fnf) */ char *language_string = "GNU C++"; extern tree void_list_node; extern struct obstack permanent_obstack; #ifndef errno extern int errno; #endif extern int end_of_file; extern int current_class_depth; /* FSF LOCAL dje prefix attributes */ extern tree strip_attrs PROTO((tree)); /* END FSF LOCAL */ void yyerror (); /* Like YYERROR but do call yyerror. */ #define YYERROR1 { yyerror ("syntax error"); YYERROR; } #define OP0(NODE) (TREE_OPERAND (NODE, 0)) #define OP1(NODE) (TREE_OPERAND (NODE, 1)) /* Contains the statement keyword (if/while/do) to include in an error message if the user supplies an empty conditional expression. */ static char *cond_stmt_keyword; /* Nonzero if we have an `extern "C"' acting as an extern specifier. */ int have_extern_spec; int used_extern_spec; void yyhook (); /* Cons up an empty parameter list. */ #ifdef __GNUC__ __inline #endif static tree empty_parms () { tree parms; if (strict_prototype) parms = void_list_node; else parms = NULL_TREE; return parms; } %} %start program %union {long itype; tree ttype; char *strtype; enum tree_code code; } /* All identifiers that are not reserved words and are not declared typedefs in the current block */ %token IDENTIFIER /* All identifiers that are declared typedefs in the current block. In some contexts, they are treated just like IDENTIFIER, but they can also serve as typespecs in declarations. */ %token TYPENAME /* Reserved words that specify storage class. yylval contains an IDENTIFIER_NODE which indicates which one. */ %token SCSPEC /* Reserved words that specify type. yylval contains an IDENTIFIER_NODE which indicates which one. */ %token TYPESPEC /* Reserved words that qualify type: "const" or "volatile". yylval contains an IDENTIFIER_NODE which indicates which one. */ %token TYPE_QUAL /* Character or numeric constants. yylval is the node for the constant. */ %token CONSTANT /* String constants in raw form. yylval is a STRING_CST node. */ %token STRING /* "...", used for functions with variable arglists. */ %token ELLIPSIS /* the reserved words */ /* SCO include files test "ASM", so use something else. */ %token SIZEOF ENUM /* STRUCT UNION */ IF ELSE WHILE DO FOR SWITCH CASE DEFAULT %token BREAK CONTINUE RETURN GOTO ASM_KEYWORD GCC_ASM_KEYWORD TYPEOF ALIGNOF %token SIGOF %token ATTRIBUTE EXTENSION LABEL /* the reserved words... C++ extensions */ %token AGGR %token VISSPEC %token DELETE NEW OVERLOAD THIS OPERATOR CXX_TRUE CXX_FALSE %token NAMESPACE TYPENAME_KEYWORD USING %token LEFT_RIGHT TEMPLATE %token TYPEID DYNAMIC_CAST STATIC_CAST REINTERPRET_CAST CONST_CAST %token SCOPE /* Define the operator tokens and their precedences. The value is an integer because, if used, it is the tree code to use in the expression made from the operator. */ %left EMPTY /* used to resolve s/r with epsilon */ %left error /* Add precedence rules to solve dangling else s/r conflict */ %nonassoc IF %nonassoc ELSE %left IDENTIFIER TYPENAME PTYPENAME SCSPEC TYPESPEC TYPE_QUAL ENUM AGGR ELLIPSIS TYPEOF SIGOF OPERATOR NSNAME TYPENAME_KEYWORD %left '{' ',' ';' %nonassoc THROW %right ':' %right ASSIGN '=' %right '?' %left OROR %left ANDAND %left '|' %left '^' %left '&' %left MIN_MAX %left EQCOMPARE %left ARITHCOMPARE '<' '>' %left LSHIFT RSHIFT %left '+' '-' %left '*' '/' '%' %left POINTSAT_STAR DOT_STAR %right UNARY PLUSPLUS MINUSMINUS '~' %left HYPERUNARY %left PAREN_STAR_PAREN LEFT_RIGHT %left POINTSAT '.' '(' '[' %right SCOPE /* C++ extension */ %nonassoc NEW DELETE TRY CATCH %type unop %type identifier IDENTIFIER TYPENAME CONSTANT expr nonnull_exprlist %type paren_expr_or_null nontrivial_exprlist %type expr_no_commas cast_expr unary_expr primary string STRING %type typed_declspecs reserved_declspecs boolean.literal %type typed_typespecs reserved_typespecquals %type declmods typespec typespecqual_reserved %type SCSPEC TYPESPEC TYPE_QUAL nonempty_type_quals maybe_type_qual %type initdecls notype_initdecls initdcl /* C++ modification */ %type init initlist maybeasm maybe_init %type asm_operands nonnull_asm_operands asm_operand asm_clobbers %type maybe_attribute attributes attribute attribute_list attrib %type any_word %type compstmt implicitly_scoped_stmt %type declarator notype_declarator after_type_declarator %type direct_notype_declarator direct_after_type_declarator %type structsp opt.component_decl_list component_decl_list %type component_decl component_decl_1 components notype_components %type component_declarator component_declarator0 %type notype_component_declarator notype_component_declarator0 %type after_type_component_declarator after_type_component_declarator0 %type enumlist enumerator %type type_id absdcl type_quals %type direct_abstract_declarator conversion_declarator %type new_type_id new_declarator direct_new_declarator %type xexpr parmlist parms parm bad_parm full_parm %type identifiers_or_typenames %type fcast_or_absdcl regcast_or_absdcl %type expr_or_declarator complex_notype_declarator %type notype_unqualified_id unqualified_id qualified_id %type overqualified_id notype_qualified_id any_id %type complex_direct_notype_declarator functional_cast %type named_parm complex_parmlist typed_declspecs1 parms_comma /* C++ extensions */ %token TYPENAME_ELLIPSIS PTYPENAME %token PRE_PARSED_FUNCTION_DECL EXTERN_LANG_STRING ALL %token PRE_PARSED_CLASS_DECL %type fn.def1 /* Not really! */ %type fn.def2 return_id %type ctor_initializer_opt %type named_class_head named_class_head_sans_basetype %type named_complex_class_head_sans_basetype %type unnamed_class_head %type class_head base_class_list %type base_class_access_list %type base_class maybe_base_class_list base_class.1 %type exception_specification_opt ansi_raise_identifier ansi_raise_identifiers %type operator_name %type object aggr %type new delete /* %type primary_no_id */ %type nonmomentary_expr maybe_parmlist %type initdcl0 notype_initdcl0 member_init_list %type template_header template_parm_list template_parm %type template_type_parm %type template_type template_arg_list template_arg %type template_instantiation template_type_name tmpl.2 %type template_instantiate_once template_instantiate_some %type fn_tmpl_end /* %type try_for_typename */ %type condition xcond paren_cond_or_null %type type_name nested_name_specifier nested_type ptr_to_mem %type qualified_type_name complete_type_name notype_identifier %type complex_type_name nested_name_specifier_1 %type nomods_initdecls nomods_initdcl0 %type new_initializer new_placement specialization type_specifier_seq %type using_decl .poplevel /* in order to recognize aggr tags as defining and thus shadowing. */ %token TYPENAME_DEFN IDENTIFIER_DEFN PTYPENAME_DEFN %type named_class_head_sans_basetype_defn %type identifier_defn IDENTIFIER_DEFN TYPENAME_DEFN PTYPENAME_DEFN %token NSNAME %type NSNAME /* Used in lex.c for parsing pragmas. */ %token END_OF_LINE /* lex.c and pt.c depends on this being the last token. Define any new tokens before this one! */ %token END_OF_SAVED_INPUT %{ /* List of types and structure classes of the current declaration. */ static tree current_declspecs; /* List of prefix attributes in effect. Prefix attributes are parsed by the reserved_declspecs and declmods rules. They create a list that contains *both* declspecs and attrs. */ /* ??? It is not clear yet that all cases where an attribute can now appear in a declspec list have been updated. */ static tree prefix_attributes; /* When defining an aggregate, this is the most recent one being defined. */ static tree current_aggr; /* 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 (); extern tree combine_strings PROTO((tree)); %} %% program: /* empty */ | extdefs { /* In case there were missing closebraces, get us back to the global binding level. */ while (! global_bindings_p ()) poplevel (0, 0, 0); finish_file (); } ; /* the reason for the strange actions in this rule is so that notype_initdecls when reached via datadef can find a valid list of type and sc specs in $0. */ extdefs: { $$ = NULL_TREE; } lang_extdef { $$ = NULL_TREE; } | extdefs lang_extdef { $$ = NULL_TREE; } ; extdefs_opt: extdefs | /* empty */ ; .hush_warning: { have_extern_spec = 1; used_extern_spec = 0; $$ = NULL_TREE; } ; .warning_ok: { have_extern_spec = 0; } ; asm_keyword: ASM_KEYWORD | GCC_ASM_KEYWORD ; lang_extdef: { if (pending_lang_change) do_pending_lang_change(); } extdef { if (! toplevel_bindings_p () && ! pseudo_global_level_p()) pop_everything (); } ; extdef: fndef { if (pending_inlines) do_pending_inlines (); } | datadef { if (pending_inlines) do_pending_inlines (); } | template_def { if (pending_inlines) do_pending_inlines (); } | overloaddef | asm_keyword '(' string ')' ';' { if (TREE_CHAIN ($3)) $3 = combine_strings ($3); assemble_asm ($3); } | extern_lang_string '{' extdefs_opt '}' { pop_lang_context (); } | extern_lang_string .hush_warning fndef .warning_ok { if (pending_inlines) do_pending_inlines (); pop_lang_context (); } | extern_lang_string .hush_warning datadef .warning_ok { if (pending_inlines) do_pending_inlines (); pop_lang_context (); } | NAMESPACE identifier '{' { push_namespace ($2); } extdefs_opt '}' { pop_namespace (); } | NAMESPACE '{' { push_namespace (NULL_TREE); } extdefs_opt '}' { pop_namespace (); } | NAMESPACE identifier '=' any_id ';' { do_namespace_alias ($2, $4); } | using_decl ';' { do_toplevel_using_decl ($1); } | USING NAMESPACE any_id ';' { do_using_directive ($3); } ; using_decl: USING qualified_id { $$ = $2; } | USING global_scope qualified_id { $$ = $3; } | USING global_scope unqualified_id { $$ = $3; } ; any_id: unqualified_id | qualified_id | global_scope qualified_id { $$ = $2; } | global_scope unqualified_id { $$ = $2; } ; extern_lang_string: EXTERN_LANG_STRING { push_lang_context ($1); } | extern_lang_string EXTERN_LANG_STRING { if (current_lang_name != $2) cp_error ("use of linkage spec `%D' is different from previous spec `%D'", $2, current_lang_name); pop_lang_context (); push_lang_context ($2); } ; template_header: TEMPLATE '<' { begin_template_parm_list (); } template_parm_list '>' { $$ = end_template_parm_list ($4); } ; template_parm_list: template_parm { $$ = process_template_parm (NULL_TREE, $1); } | template_parm_list ',' template_parm { $$ = process_template_parm ($1, $3); } ; template_type_parm: aggr { $$ = build_tree_list ($1, NULL_TREE); ttpa: if (TREE_PURPOSE ($$) == signature_type_node) sorry ("signature as template type parameter"); else if (TREE_PURPOSE ($$) != class_type_node) pedwarn ("template type parameters must use the keyword `class'"); } | aggr identifier { $$ = build_tree_list ($1, $2); goto ttpa; } | TYPENAME_KEYWORD { $$ = build_tree_list (class_type_node, NULL_TREE); } | TYPENAME_KEYWORD identifier { $$ = build_tree_list (class_type_node, $2); } ; template_parm: /* The following rules introduce a new reduce/reduce conflict on the ',' and '>' input tokens: they are valid prefixes for a `structsp', which means they could match a nameless parameter. See 14.6, paragraph 3. By putting them before the `parm' rule, we get their match before considering them nameless parameter declarations. */ template_type_parm { $$ = build_tree_list (NULL_TREE, $$); } | template_type_parm '=' typespec { $$ = build_tree_list ($3, $$); } | full_parm ; overloaddef: OVERLOAD ov_identifiers ';' { warning ("use of `overload' is an anachronism"); } ; ov_identifiers: IDENTIFIER { declare_overloaded ($1); } | ov_identifiers ',' IDENTIFIER { declare_overloaded ($3); } ; template_def: /* Class template declarations go here; they aren't normal class declarations, because we can't process the bodies yet. */ template_header named_class_head_sans_basetype '{' { yychar = '{'; goto template1; } ';' | template_header named_class_head_sans_basetype_defn '{' { yychar = '{'; goto template1; } ';' | template_header named_class_head_sans_basetype ':' { yychar = ':'; goto template1; } ';' | template_header named_class_head_sans_basetype_defn ':' { yychar = ':'; template1: if (current_aggr == signature_type_node) sorry ("template type defining a signature"); /* Maybe pedantic warning for union? How about an enum? :-) */ end_template_decl ($1, $2, current_aggr, 1); reinit_parse_for_template (yychar, $1, $2); yychar = YYEMPTY; } ';' | template_header named_class_head_sans_basetype ';' { end_template_decl ($1, $2, current_aggr, 0); /* declare $2 as template name with $1 parm list */ } | template_header named_class_head_sans_basetype_defn ';' { end_template_decl ($1, $2, current_aggr, 0); /* declare $2 as template name with $1 parm list */ } | template_header /* notype_initdcl0 ';' */ notype_declarator exception_specification_opt maybeasm maybe_attribute fn_tmpl_end { tree d; int momentary; int def = ($6 != ';'); momentary = suspend_momentary (); d = start_decl ($2, /*current_declspecs*/NULL_TREE, 0, $3); cplus_decl_attributes (d, $5, /*prefix_attributes*/NULL_TREE); cp_finish_decl (d, NULL_TREE, $4, 0, 0); end_template_decl ($1, d, 0, def); if (def) reinit_parse_for_template ((int) $6, $1, d); resume_momentary (momentary); } | template_header typed_declspecs /*initdcl0*/ declarator exception_specification_opt maybeasm maybe_attribute fn_tmpl_end { tree d, specs, attrs; int momentary; int def = ($7 != ';'); split_specs_attrs ($2, &specs, &attrs); momentary = suspend_momentary (); d = start_decl ($3, specs, 0, $4); cplus_decl_attributes (d, $6, attrs); cp_finish_decl (d, NULL_TREE, $5, 0, 0); end_template_decl ($1, d, 0, def); if (def) { reinit_parse_for_template ((int) $7, $1, d); yychar = YYEMPTY; } note_list_got_semicolon ($2); resume_momentary (momentary); } | template_header declmods notype_declarator fn_tmpl_end { tree d, specs, attrs; int def = ($4 != ';'); split_specs_attrs ($2, &specs, &attrs); d = start_decl ($3, specs, 0, NULL_TREE); cplus_decl_attributes (d, NULL_TREE, attrs); cp_finish_decl (d, NULL_TREE, NULL_TREE, 0, 0); end_template_decl ($1, d, 0, def); if (def) reinit_parse_for_template ((int) $4, $1, d); } /* Try to recover from syntax errors in templates. */ | template_header error '}' { end_template_decl ($1, 0, 0, 0); } | template_header error ';' { end_template_decl ($1, 0, 0, 0); } ; fn_tmpl_end: '{' { $$ = '{'; } | ':' { $$ = ':'; } | ';' { $$ = ';'; } | '=' { $$ = '='; } | RETURN { $$ = RETURN; } ; datadef: nomods_initdecls ';' {} | declmods notype_initdecls ';' {} /* Normal case to make fast: "const i;". */ | declmods notype_declarator ';' { tree d, specs, attrs; split_specs_attrs ($1, &specs, &attrs); d = start_decl ($2, specs, 0, NULL_TREE); cplus_decl_attributes (d, NULL_TREE, attrs); cp_finish_decl (d, NULL_TREE, NULL_TREE, 0, 0); } | typed_declspecs initdecls ';' { note_list_got_semicolon ($$); } /* Normal case: make this fast. */ | typed_declspecs declarator ';' { tree d, specs, attrs; split_specs_attrs ($1, &specs, &attrs); d = start_decl ($2, specs, 0, NULL_TREE); cplus_decl_attributes (d, NULL_TREE, attrs); cp_finish_decl (d, NULL_TREE, NULL_TREE, 0, 0); note_list_got_semicolon ($$); } | declmods ';' { pedwarn ("empty declaration"); } | explicit_instantiation ';' | typed_declspecs ';' { tree t, attrs; split_specs_attrs ($1, &t, &attrs); shadow_tag (t); if (TREE_CODE (t) == TREE_LIST && TREE_PURPOSE (t) == NULL_TREE) { t = TREE_VALUE (t); if (IS_AGGR_TYPE (t) && IDENTIFIER_TEMPLATE (TYPE_IDENTIFIER (t))) { if (CLASSTYPE_USE_TEMPLATE (t) == 0) SET_CLASSTYPE_TEMPLATE_SPECIALIZATION (t); else if (CLASSTYPE_TEMPLATE_INSTANTIATION (t)) error ("override declaration for already-expanded template"); } } note_list_got_semicolon ($$); } | error ';' | error '}' | ';' ; ctor_initializer_opt: nodecls { $$ = 0; } | base_init { $$ = 1; } ; maybe_return_init: /* empty */ | return_init | return_init ';' ; eat_saved_input: /* empty */ | END_OF_SAVED_INPUT ; fndef: fn.def1 maybe_return_init ctor_initializer_opt compstmt_or_error { finish_function (lineno, (int)$3, 0); if ($$) process_next_inline ($$); } | fn.def1 maybe_return_init function_try_block { if ($$) process_next_inline ($$); } eat_saved_input | typed_declspecs declarator error {} | declmods notype_declarator error {} | notype_declarator error {} ; fn.def1: typed_declspecs declarator exception_specification_opt { tree specs, attrs; split_specs_attrs ($1, &specs, &attrs); if (! start_function (specs, $2, $3, attrs, 0)) YYERROR1; reinit_parse_for_function (); $$ = NULL_TREE; } | declmods notype_declarator exception_specification_opt { tree specs = strip_attrs ($1); if (! start_function (specs, $2, $3, NULL_TREE, 0)) YYERROR1; reinit_parse_for_function (); $$ = NULL_TREE; } | notype_declarator exception_specification_opt { if (! start_function (NULL_TREE, $$, $2, NULL_TREE, 0)) YYERROR1; reinit_parse_for_function (); $$ = NULL_TREE; } | PRE_PARSED_FUNCTION_DECL { start_function (NULL_TREE, TREE_VALUE ($$), NULL_TREE, NULL_TREE, 1); reinit_parse_for_function (); } ; /* more C++ complexity. See component_decl for a comment on the reduce/reduce conflict introduced by these rules. */ fn.def2: typed_declspecs '(' parmlist ')' type_quals exception_specification_opt { tree specs = strip_attrs ($1); $$ = build_parse_node (CALL_EXPR, TREE_VALUE (specs), $3, $5); $$ = start_method (TREE_CHAIN (specs), $$, $6); rest_of_mdef: if (! $$) YYERROR1; if (yychar == YYEMPTY) yychar = YYLEX; reinit_parse_for_method (yychar, $$); } | typed_declspecs LEFT_RIGHT type_quals exception_specification_opt { tree specs = strip_attrs ($1); $$ = build_parse_node (CALL_EXPR, TREE_VALUE (specs), empty_parms (), $3); $$ = start_method (TREE_CHAIN (specs), $$, $4); goto rest_of_mdef; } | typed_declspecs declarator exception_specification_opt { tree specs = strip_attrs ($1); $$ = start_method (specs, $2, $3); goto rest_of_mdef; } | declmods notype_declarator exception_specification_opt { tree specs = strip_attrs ($1); $$ = start_method (specs, $2, $3); goto rest_of_mdef; } | notype_declarator exception_specification_opt { $$ = start_method (NULL_TREE, $$, $2); goto rest_of_mdef; } ; return_id: RETURN IDENTIFIER { if (! current_function_parms_stored) store_parm_decls (); $$ = $2; } ; return_init: return_id maybe_init { store_return_init ($$, $2); } | return_id '(' nonnull_exprlist ')' { store_return_init ($$, $3); } | return_id LEFT_RIGHT { store_return_init ($$, NULL_TREE); } ; base_init: ':' .set_base_init member_init_list { if ($3 == 0) error ("no base initializers given following ':'"); setup_vtbl_ptr (); /* Always keep the BLOCK node associated with the outermost pair of curley braces of a function. These are needed for correct operation of dwarfout.c. */ keep_next_level (); } ; .set_base_init: /* empty */ { if (! current_function_parms_stored) store_parm_decls (); if (DECL_CONSTRUCTOR_P (current_function_decl)) { /* Make a contour for the initializer list. */ pushlevel (0); clear_last_expr (); expand_start_bindings (0); } else if (current_class_type == NULL_TREE) error ("base initializers not allowed for non-member functions"); else if (! DECL_CONSTRUCTOR_P (current_function_decl)) error ("only constructors take base initializers"); } ; member_init_list: /* empty */ { $$ = 0; } | member_init { $$ = 1; } | member_init_list ',' member_init | member_init_list error ; member_init: '(' nonnull_exprlist ')' { if (current_class_name && !flag_traditional) pedwarn ("anachronistic old style base class initializer"); expand_member_init (C_C_D, NULL_TREE, $2); } | LEFT_RIGHT { if (current_class_name && !flag_traditional) pedwarn ("anachronistic old style base class initializer"); expand_member_init (C_C_D, NULL_TREE, void_type_node); } | notype_identifier '(' nonnull_exprlist ')' { expand_member_init (C_C_D, $$, $3); } | notype_identifier LEFT_RIGHT { expand_member_init (C_C_D, $$, void_type_node); } | complete_type_name '(' nonnull_exprlist ')' { expand_member_init (C_C_D, $$, $3); } | complete_type_name LEFT_RIGHT { expand_member_init (C_C_D, $$, void_type_node); } /* GNU extension */ | notype_qualified_id '(' nonnull_exprlist ')' { do_member_init (OP0 ($1), OP1 ($1), $3); } | notype_qualified_id LEFT_RIGHT { do_member_init (OP0 ($1), OP1 ($1), void_type_node); } ; identifier: IDENTIFIER | TYPENAME | PTYPENAME | NSNAME ; notype_identifier: IDENTIFIER | PTYPENAME | NSNAME %prec EMPTY ; identifier_defn: IDENTIFIER_DEFN | TYPENAME_DEFN | PTYPENAME_DEFN ; explicit_instantiation: TEMPLATE specialization template_instantiation { do_type_instantiation ($3 ? $3 : $2, NULL_TREE); } | TEMPLATE typed_declspecs declarator { tree specs = strip_attrs ($2); do_function_instantiation (specs, $3, NULL_TREE); } | TEMPLATE notype_declarator { do_function_instantiation (NULL_TREE, $2, NULL_TREE); } | SCSPEC TEMPLATE specialization template_instantiation { do_type_instantiation ($4 ? $4 : $3, $1); } | SCSPEC TEMPLATE typed_declspecs declarator { tree specs = strip_attrs ($3); do_function_instantiation (specs, $4, $1); } | SCSPEC TEMPLATE notype_declarator { do_function_instantiation (NULL_TREE, $3, $1); } ; template_type: template_type_name tmpl.2 template_instantiation { if ($3) $$ = $3; } ; template_type_name: PTYPENAME '<' template_arg_list '>' { $$ = lookup_template_class ($$, $3, NULL_TREE); } | PTYPENAME '<' '>' { $$ = lookup_template_class ($$, NULL_TREE, NULL_TREE); } | TYPENAME '<' template_arg_list '>' { $$ = lookup_template_class ($$, $3, NULL_TREE); } ; tmpl.2: /* empty */ %prec EMPTY { $$ = instantiate_class_template ($0, 1); } ; template_arg_list: template_arg { $$ = build_tree_list (NULL_TREE, $$); } | template_arg_list ',' template_arg { $$ = chainon ($$, build_tree_list (NULL_TREE, $3)); } ; template_arg: type_id { $$ = groktypename ($$); } | expr_no_commas %prec UNARY ; template_instantiate_once: PRE_PARSED_CLASS_DECL maybe_base_class_list { tree t, decl, tmpl; tmpl = TREE_PURPOSE (IDENTIFIER_TEMPLATE ($1)); t = xref_tag (DECL_TEMPLATE_INFO (tmpl)->aggr, $1, $2, 0); set_current_level_tags_transparency (1); my_friendly_assert (TREE_CODE (t) == RECORD_TYPE || TREE_CODE (t) == UNION_TYPE, 257); $$ = t; /* Now, put a copy of the decl in global scope, to avoid recursive expansion. */ decl = IDENTIFIER_LOCAL_VALUE ($1); if (!decl) decl = IDENTIFIER_CLASS_VALUE ($1); /* Now, put a copy of the decl in global scope, to avoid recursive expansion. */ if (decl) { /* Need to copy it to clear the chain pointer, and need to get it into permanent storage. */ my_friendly_assert (TREE_CODE (decl) == TYPE_DECL, 258); push_obstacks (&permanent_obstack, &permanent_obstack); decl = copy_node (decl); if (DECL_LANG_SPECIFIC (decl)) copy_lang_decl (decl); pop_obstacks (); pushdecl_top_level (decl); } /* Kludge; see instantiate_class_template. */ TYPE_BEING_DEFINED (t) = 0; } left_curly opt.component_decl_list '}' { tree t = finish_struct ($3, $5, 0); pop_obstacks (); end_template_instantiation ($1); repo_template_used (t); /* Now go after the methods & class data. */ instantiate_member_templates ($1); pop_tinst_level(); CLASSTYPE_GOT_SEMICOLON (t) = 1; } ; template_instantiation: /* empty */ { $$ = NULL_TREE; } | template_instantiate_once { $$ = $1; } ; template_instantiate_some: /* empty */ { $$ = NULL_TREE; /* never used from here... */} | template_instantiate_once template_instantiate_some { $$ = $1; /*???*/ } ; unop: '-' { $$ = NEGATE_EXPR; } | '+' { $$ = CONVERT_EXPR; } | PLUSPLUS { $$ = PREINCREMENT_EXPR; } | MINUSMINUS { $$ = PREDECREMENT_EXPR; } | '!' { $$ = TRUTH_NOT_EXPR; } ; expr: nontrivial_exprlist { $$ = build_x_compound_expr ($$); } | expr_no_commas ; paren_expr_or_null: LEFT_RIGHT { error ("ANSI C++ forbids an empty condition for `%s'", cond_stmt_keyword); $$ = integer_zero_node; } | '(' expr ')' { $$ = condition_conversion ($2); } ; paren_cond_or_null: LEFT_RIGHT { error ("ANSI C++ forbids an empty condition for `%s'", cond_stmt_keyword); $$ = integer_zero_node; } | '(' condition ')' { $$ = condition_conversion ($2); } ; xcond: /* empty */ { $$ = NULL_TREE; } | condition { $$ = condition_conversion ($$); } | error { $$ = NULL_TREE; } ; condition: type_specifier_seq declarator exception_specification_opt maybeasm maybe_attribute '=' { { tree d; for (d = getdecls (); d; d = TREE_CHAIN (d)) if (TREE_CODE (d) == TYPE_DECL) { tree s = TREE_TYPE (d); if (TREE_CODE (s) == RECORD_TYPE) cp_error ("definition of class `%T' in condition", s); else if (TREE_CODE (s) == ENUMERAL_TYPE) cp_error ("definition of enum `%T' in condition", s); } } current_declspecs = $1; $6 = suspend_momentary (); $$ = start_decl ($2, current_declspecs, 1, $3); cplus_decl_attributes ($$, $5, /*prefix_attributes*/ NULL_TREE); } init { cp_finish_decl ($7, $8, $5, 0, LOOKUP_ONLYCONVERTING); resume_momentary ($6); $$ = $7; if (TREE_CODE (TREE_TYPE ($$)) == ARRAY_TYPE) cp_error ("definition of array `%#D' in condition", $$); } | expr ; compstmtend: '}' | maybe_label_decls stmts '}' | maybe_label_decls stmts error '}' | maybe_label_decls error '}' ; already_scoped_stmt: '{' compstmtend { finish_stmt (); } | simple_stmt ; nontrivial_exprlist: expr_no_commas ',' expr_no_commas { $$ = tree_cons (NULL_TREE, $$, build_tree_list (NULL_TREE, $3)); } | expr_no_commas ',' error { $$ = tree_cons (NULL_TREE, $$, build_tree_list (NULL_TREE, error_mark_node)); } | nontrivial_exprlist ',' expr_no_commas { chainon ($$, build_tree_list (NULL_TREE, $3)); } | nontrivial_exprlist ',' error { chainon ($$, build_tree_list (NULL_TREE, error_mark_node)); } ; nonnull_exprlist: expr_no_commas { $$ = build_tree_list (NULL_TREE, $$); } | nontrivial_exprlist ; unary_expr: primary %prec UNARY { #if 0 if (TREE_CODE ($$) == TYPE_EXPR) $$ = build_component_type_expr (C_C_D, $$, NULL_TREE, 1); #endif } /* __extension__ turns off -pedantic for following primary. */ | EXTENSION { $1 = pedantic; pedantic = 0; } cast_expr %prec UNARY { $$ = $3; pedantic = $1; } | '*' cast_expr %prec UNARY { $$ = build_x_indirect_ref ($2, "unary *"); } | '&' cast_expr %prec UNARY { $$ = build_x_unary_op (ADDR_EXPR, $2); } | '~' cast_expr { $$ = build_x_unary_op (BIT_NOT_EXPR, $2); } | unop cast_expr %prec UNARY { $$ = build_x_unary_op ($1, $2); if ($1 == NEGATE_EXPR && TREE_CODE ($2) == INTEGER_CST) TREE_NEGATED_INT ($$) = 1; overflow_warning ($$); } /* Refer to the address of a label as a pointer. */ | ANDAND identifier { tree label = lookup_label ($2); if (label == NULL_TREE) $$ = null_pointer_node; else { TREE_USED (label) = 1; $$ = build1 (ADDR_EXPR, ptr_type_node, label); TREE_CONSTANT ($$) = 1; } } | SIZEOF unary_expr %prec UNARY { if (TREE_CODE ($2) == COMPONENT_REF && DECL_BIT_FIELD (TREE_OPERAND ($2, 1))) error ("sizeof applied to a bit-field"); /* ANSI says arrays and functions are converted inside comma. But we can't really convert them in build_compound_expr because that would break commas in lvalues. So do the conversion here if operand was a comma. */ if (TREE_CODE ($2) == COMPOUND_EXPR && (TREE_CODE (TREE_TYPE ($2)) == ARRAY_TYPE || TREE_CODE (TREE_TYPE ($2)) == FUNCTION_TYPE)) $2 = default_conversion ($2); else if (TREE_CODE ($2) == TREE_LIST) { tree t = TREE_VALUE ($2); if (t != NULL_TREE && ((TREE_TYPE (t) && TREE_CODE (TREE_TYPE (t)) == FUNCTION_TYPE) || is_overloaded_fn (t))) pedwarn ("ANSI C++ forbids taking the sizeof a function type"); } $$ = c_sizeof (TREE_TYPE ($2)); } | SIZEOF '(' type_id ')' %prec HYPERUNARY { $$ = c_sizeof (groktypename ($3)); } | ALIGNOF unary_expr %prec UNARY { $$ = grok_alignof ($2); } | ALIGNOF '(' type_id ')' %prec HYPERUNARY { $$ = c_alignof (groktypename ($3)); } /* The %prec EMPTY's here are required by the = init initializer syntax extension; see below. */ | new new_type_id %prec EMPTY { $$ = build_new (NULL_TREE, $2, NULL_TREE, $1); } | new new_type_id new_initializer { $$ = build_new (NULL_TREE, $2, $3, $1); } | new new_placement new_type_id %prec EMPTY { $$ = build_new ($2, $3, NULL_TREE, $1); } | new new_placement new_type_id new_initializer { $$ = build_new ($2, $3, $4, $1); } | new '(' type_id ')' %prec EMPTY { $$ = build_new (NULL_TREE, groktypename($3), NULL_TREE, $1); } | new '(' type_id ')' new_initializer { $$ = build_new (NULL_TREE, groktypename($3), $5, $1); } | new new_placement '(' type_id ')' %prec EMPTY { $$ = build_new ($2, groktypename($4), NULL_TREE, $1); } | new new_placement '(' type_id ')' new_initializer { $$ = build_new ($2, groktypename($4), $6, $1); } | delete cast_expr %prec UNARY { $$ = delete_sanity ($2, NULL_TREE, 0, $1); } | delete '[' ']' cast_expr %prec UNARY { $$ = delete_sanity ($4, NULL_TREE, 1, $1); if (yychar == YYEMPTY) yychar = YYLEX; } | delete '[' expr ']' cast_expr %prec UNARY { $$ = delete_sanity ($5, $3, 2, $1); if (yychar == YYEMPTY) yychar = YYLEX; } ; new_placement: '(' nonnull_exprlist ')' { $$ = $2; } | '{' nonnull_exprlist '}' { $$ = $2; pedwarn ("old style placement syntax, use () instead"); } ; new_initializer: '(' nonnull_exprlist ')' { $$ = $2; } | LEFT_RIGHT { $$ = NULL_TREE; } | '(' typespec ')' { cp_error ("`%T' is not a valid expression", $2); $$ = error_mark_node; } /* GNU extension so people can use initializer lists. Note that this alters the meaning of `new int = 1', which was previously syntactically valid but semantically invalid. */ | '=' init { if (pedantic) pedwarn ("ANSI C++ forbids initialization of new expression with `='"); $$ = $2; } ; /* This is necessary to postpone reduction of `int ((int)(int)(int))'. */ regcast_or_absdcl: '(' type_id ')' %prec EMPTY { $2 = tree_cons (NULL_TREE, $2, void_list_node); TREE_PARMLIST ($2) = 1; $$ = build_parse_node (CALL_EXPR, NULL_TREE, $2, NULL_TREE); } | regcast_or_absdcl '(' type_id ')' %prec EMPTY { $3 = tree_cons (NULL_TREE, $3, void_list_node); TREE_PARMLIST ($3) = 1; $$ = build_parse_node (CALL_EXPR, $$, $3, NULL_TREE); } ; cast_expr: unary_expr | regcast_or_absdcl unary_expr %prec UNARY { $$ = reparse_absdcl_as_casts ($$, $2); } | regcast_or_absdcl '{' initlist maybecomma '}' %prec UNARY { tree init = build_nt (CONSTRUCTOR, NULL_TREE, nreverse ($3)); if (pedantic) pedwarn ("ANSI C++ forbids constructor-expressions"); /* Indicate that this was a GNU C constructor expression. */ TREE_HAS_CONSTRUCTOR (init) = 1; $$ = reparse_absdcl_as_casts ($$, init); } ; expr_no_commas: cast_expr /* Handle general members. */ | expr_no_commas POINTSAT_STAR expr_no_commas { $$ = build_x_binary_op (MEMBER_REF, $$, $3); } | expr_no_commas DOT_STAR expr_no_commas { $$ = build_m_component_ref ($$, $3); } | expr_no_commas '+' expr_no_commas { $$ = build_x_binary_op ($2, $$, $3); } | expr_no_commas '-' expr_no_commas { $$ = build_x_binary_op ($2, $$, $3); } | expr_no_commas '*' expr_no_commas { $$ = build_x_binary_op ($2, $$, $3); } | expr_no_commas '/' expr_no_commas { $$ = build_x_binary_op ($2, $$, $3); } | expr_no_commas '%' expr_no_commas { $$ = build_x_binary_op ($2, $$, $3); } | expr_no_commas LSHIFT expr_no_commas { $$ = build_x_binary_op ($2, $$, $3); } | expr_no_commas RSHIFT expr_no_commas { $$ = build_x_binary_op ($2, $$, $3); } | expr_no_commas ARITHCOMPARE expr_no_commas { $$ = build_x_binary_op ($2, $$, $3); } | expr_no_commas '<' expr_no_commas { $$ = build_x_binary_op (LT_EXPR, $$, $3); } | expr_no_commas '>' expr_no_commas { $$ = build_x_binary_op (GT_EXPR, $$, $3); } | expr_no_commas EQCOMPARE expr_no_commas { $$ = build_x_binary_op ($2, $$, $3); } | expr_no_commas MIN_MAX expr_no_commas { $$ = build_x_binary_op ($2, $$, $3); } | expr_no_commas '&' expr_no_commas { $$ = build_x_binary_op ($2, $$, $3); } | expr_no_commas '|' expr_no_commas { $$ = build_x_binary_op ($2, $$, $3); } | expr_no_commas '^' expr_no_commas { $$ = build_x_binary_op ($2, $$, $3); } | expr_no_commas ANDAND expr_no_commas { $$ = build_x_binary_op (TRUTH_ANDIF_EXPR, $$, $3); } | expr_no_commas OROR expr_no_commas { $$ = build_x_binary_op (TRUTH_ORIF_EXPR, $$, $3); } | expr_no_commas '?' xexpr ':' expr_no_commas { $$ = build_x_conditional_expr ($$, $3, $5); } | expr_no_commas '=' expr_no_commas { $$ = build_modify_expr ($$, NOP_EXPR, $3); C_SET_EXP_ORIGINAL_CODE ($$, MODIFY_EXPR); } | expr_no_commas ASSIGN expr_no_commas { register tree rval; if ((rval = build_opfncall (MODIFY_EXPR, LOOKUP_NORMAL, $$, $3, make_node ($2)))) $$ = rval; else $$ = build_modify_expr ($$, $2, $3); } | THROW { $$ = build_throw (NULL_TREE); } | THROW expr_no_commas { $$ = build_throw ($2); } /* These extensions are not defined. The second arg to build_m_component_ref is old, build_m_component_ref now does an implicit build_indirect_ref (x, NULL_PTR) on the second argument. | object '&' expr_no_commas %prec UNARY { $$ = build_m_component_ref ($$, build_x_unary_op (ADDR_EXPR, $3)); } | object unop expr_no_commas %prec UNARY { $$ = build_m_component_ref ($$, build_x_unary_op ($2, $3)); } | object '(' type_id ')' expr_no_commas %prec UNARY { tree type = groktypename ($3); $$ = build_m_component_ref ($$, build_c_cast (type, $5, 0)); } | object primary_no_id %prec UNARY { $$ = build_m_component_ref ($$, $2); } */ ; notype_unqualified_id: '~' see_typename identifier { $$ = build_parse_node (BIT_NOT_EXPR, $3); } | operator_name | IDENTIFIER | PTYPENAME | NSNAME %prec EMPTY ; unqualified_id: notype_unqualified_id | TYPENAME ; expr_or_declarator: notype_unqualified_id | '*' expr_or_declarator %prec UNARY { $$ = build_parse_node (INDIRECT_REF, $2); } | '&' expr_or_declarator %prec UNARY { $$ = build_parse_node (ADDR_EXPR, $2); } | '(' expr_or_declarator ')' { $$ = $2; } ; direct_notype_declarator: complex_direct_notype_declarator | notype_unqualified_id | '(' expr_or_declarator ')' { $$ = finish_decl_parsing ($2); } ; primary: notype_unqualified_id { if (TREE_CODE ($$) == BIT_NOT_EXPR) $$ = build_x_unary_op (BIT_NOT_EXPR, TREE_OPERAND ($$, 0)); else if (IDENTIFIER_OPNAME_P ($$)) { tree op = $$; $$ = lookup_name (op, 0); if ($$ == NULL_TREE) { if (op != ansi_opname[ERROR_MARK]) error ("operator %s not defined", operator_name_string (op)); $$ = error_mark_node; } } else $$ = do_identifier ($$); } | CONSTANT | boolean.literal | string { $$ = combine_strings ($$); } | '(' expr ')' { char class; $$ = $2; class = TREE_CODE_CLASS (TREE_CODE ($$)); if (class == 'e' || class == '1' || class == '2' || class == '<') /* This inhibits warnings in truthvalue_conversion. */ C_SET_EXP_ORIGINAL_CODE ($$, ERROR_MARK); } | '(' expr_or_declarator ')' { char class; $$ = reparse_decl_as_expr (NULL_TREE, $2); class = TREE_CODE_CLASS (TREE_CODE ($$)); if (class == 'e' || class == '1' || class == '2' || class == '<') /* This inhibits warnings in truthvalue_conversion. */ C_SET_EXP_ORIGINAL_CODE ($$, ERROR_MARK); } | '(' error ')' { $$ = error_mark_node; } | '(' { if (current_function_decl == 0) { error ("braced-group within expression allowed only inside a function"); YYERROR; } keep_next_level (); $$ = expand_start_stmt_expr (); } compstmt ')' { tree rtl_exp; if (pedantic) pedwarn ("ANSI C++ forbids braced-groups within expressions"); rtl_exp = expand_end_stmt_expr ($2); /* The statements have side effects, so the group does. */ TREE_SIDE_EFFECTS (rtl_exp) = 1; if (TREE_CODE ($3) == BLOCK) { /* Make a BIND_EXPR for the BLOCK already made. */ $$ = build (BIND_EXPR, TREE_TYPE (rtl_exp), NULL_TREE, rtl_exp, $3); /* 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 ($3); } else $$ = $3; } | primary '(' nonnull_exprlist ')' { /* [eichin:19911016.1902EST] */ $$ = build_x_function_call ($1, $3, current_class_decl); /* here we instantiate_class_template as needed... */ do_pending_templates (); } template_instantiate_some { if (TREE_CODE ($5) == CALL_EXPR && TREE_TYPE ($5) != void_type_node) $$ = require_complete_type ($5); else $$ = $5; } | primary LEFT_RIGHT { $$ = build_x_function_call ($$, NULL_TREE, current_class_decl); if (TREE_CODE ($$) == CALL_EXPR && TREE_TYPE ($$) != void_type_node) $$ = require_complete_type ($$); } | primary '[' expr ']' { $$ = grok_array_decl ($$, $3); } | primary PLUSPLUS { /* If we get an OFFSET_REF, turn it into what it really means (e.g., a COMPONENT_REF). This way if we've got, say, a reference to a static member that's being operated on, we don't end up trying to find a member operator for the class it's in. */ if (TREE_CODE ($$) == OFFSET_REF) $$ = resolve_offset_ref ($$); $$ = build_x_unary_op (POSTINCREMENT_EXPR, $$); } | primary MINUSMINUS { if (TREE_CODE ($$) == OFFSET_REF) $$ = resolve_offset_ref ($$); $$ = build_x_unary_op (POSTDECREMENT_EXPR, $$); } /* C++ extensions */ | THIS { if (current_class_decl) { #ifdef WARNING_ABOUT_CCD TREE_USED (current_class_decl) = 1; #endif $$ = current_class_decl; } else if (current_function_decl && DECL_STATIC_FUNCTION_P (current_function_decl)) { error ("`this' is unavailable for static member functions"); $$ = error_mark_node; } else { if (current_function_decl) error ("invalid use of `this' in non-member function"); else error ("invalid use of `this' at top level"); $$ = error_mark_node; } } | TYPE_QUAL '(' nonnull_exprlist ')' { tree type; tree id = $$; /* This is a C cast in C++'s `functional' notation. */ if ($3 == error_mark_node) { $$ = error_mark_node; break; } #if 0 if ($3 == NULL_TREE) { error ("cannot cast null list to type `%s'", IDENTIFIER_POINTER (TYPE_NAME (id))); $$ = error_mark_node; break; } #endif #if 0 /* type is not set! (mrs) */ if (type == error_mark_node) $$ = error_mark_node; else #endif { if (id == ridpointers[(int) RID_CONST]) type = build_type_variant (integer_type_node, 1, 0); else if (id == ridpointers[(int) RID_VOLATILE]) type = build_type_variant (integer_type_node, 0, 1); #if 0 /* should not be able to get here (mrs) */ else if (id == ridpointers[(int) RID_FRIEND]) { error ("cannot cast expression to `friend' type"); $$ = error_mark_node; break; } #endif else my_friendly_abort (79); $$ = build_c_cast (type, build_compound_expr ($3), 1); } } | functional_cast | DYNAMIC_CAST '<' { dont_allow_type_definitions = "inside dynamic_cast"; } type_id '>' { dont_allow_type_definitions = 0; } '(' expr ')' { tree type = groktypename ($4); $$ = build_dynamic_cast (type, $8); } | STATIC_CAST '<' { dont_allow_type_definitions = "inside static_cast"; } type_id '>' { dont_allow_type_definitions = 0; } '(' expr ')' { tree type = groktypename ($4); $$ = build_static_cast (type, $8); } | REINTERPRET_CAST '<' { dont_allow_type_definitions = "inside reinterpret_cast"; } type_id '>' { dont_allow_type_definitions = 0; } '(' expr ')' { tree type = groktypename ($4); $$ = build_reinterpret_cast (type, $8); } | CONST_CAST '<' { dont_allow_type_definitions = "inside const_cast"; } type_id '>' { dont_allow_type_definitions = 0; } '(' expr ')' { tree type = groktypename ($4); $$ = build_const_cast (type, $8); } | TYPEID '(' expr ')' { $$ = build_typeid ($3); } | TYPEID '(' type_id ')' { tree type = groktypename ($3); $$ = get_typeid (TYPE_MAIN_VARIANT (type)); } | global_scope IDENTIFIER { do_scoped_id: $$ = IDENTIFIER_GLOBAL_VALUE ($2); if (yychar == YYEMPTY) yychar = YYLEX; if (! $$) { if (yychar == '(' || yychar == LEFT_RIGHT) $$ = implicitly_declare ($2); else { if (IDENTIFIER_GLOBAL_VALUE ($2) != error_mark_node) error ("undeclared variable `%s' (first use here)", IDENTIFIER_POINTER ($2)); $$ = error_mark_node; /* Prevent repeated error messages. */ IDENTIFIER_GLOBAL_VALUE ($2) = error_mark_node; } } else { if (TREE_CODE ($$) == ADDR_EXPR) assemble_external (TREE_OPERAND ($$, 0)); else assemble_external ($$); TREE_USED ($$) = 1; } if (TREE_CODE ($$) == CONST_DECL) { /* XXX CHS - should we set TREE_USED of the constant? */ $$ = DECL_INITIAL ($$); /* This is to prevent an enum whose value is 0 from being considered a null pointer constant. */ $$ = build1 (NOP_EXPR, TREE_TYPE ($$), $$); TREE_CONSTANT ($$) = 1; } } | global_scope operator_name { got_scope = NULL_TREE; if (TREE_CODE ($2) == IDENTIFIER_NODE) goto do_scoped_id; $$ = $2; } | overqualified_id %prec HYPERUNARY { $$ = build_offset_ref (OP0 ($$), OP1 ($$)); } | overqualified_id '(' nonnull_exprlist ')' { $$ = build_member_call (OP0 ($$), OP1 ($$), $3); } | overqualified_id LEFT_RIGHT { $$ = build_member_call (OP0 ($$), OP1 ($$), NULL_TREE); } | object unqualified_id %prec UNARY { got_object = NULL_TREE; $$ = build_component_ref ($$, $2, NULL_TREE, 1); } | object overqualified_id %prec UNARY { got_object = NULL_TREE; $$ = build_object_ref ($$, OP0 ($2), OP1 ($2)); } | object unqualified_id '(' nonnull_exprlist ')' { got_object = NULL_TREE; #if 0 /* This is a future direction of this code, but because build_x_function_call cannot always undo what is done in build_component_ref entirely yet, we cannot do this. */ $$ = build_x_function_call (build_component_ref ($$, $2, NULL_TREE, 1), $4, $$); if (TREE_CODE ($$) == CALL_EXPR && TREE_TYPE ($$) != void_type_node) $$ = require_complete_type ($$); #else $$ = build_method_call ($$, $2, $4, NULL_TREE, (LOOKUP_NORMAL|LOOKUP_AGGR)); #endif } | object unqualified_id LEFT_RIGHT { got_object = NULL_TREE; #if 0 /* This is a future direction of this code, but because build_x_function_call cannot always undo what is done in build_component_ref entirely yet, we cannot do this. */ $$ = build_x_function_call (build_component_ref ($$, $2, NULL_TREE, 1), NULL_TREE, $$); if (TREE_CODE ($$) == CALL_EXPR && TREE_TYPE ($$) != void_type_node) $$ = require_complete_type ($$); #else $$ = build_method_call ($$, $2, NULL_TREE, NULL_TREE, (LOOKUP_NORMAL|LOOKUP_AGGR)); #endif } | object overqualified_id '(' nonnull_exprlist ')' { got_object = NULL_TREE; if (IS_SIGNATURE (IDENTIFIER_TYPE_VALUE (OP0 ($2)))) { warning ("signature name in scope resolution ignored"); $$ = build_method_call ($$, OP1 ($2), $4, NULL_TREE, (LOOKUP_NORMAL|LOOKUP_AGGR)); } else $$ = build_scoped_method_call ($$, OP0 ($2), OP1 ($2), $4); } | object overqualified_id LEFT_RIGHT { got_object = NULL_TREE; if (IS_SIGNATURE (IDENTIFIER_TYPE_VALUE (OP0 ($2)))) { warning ("signature name in scope resolution ignored"); $$ = build_method_call ($$, OP1 ($2), NULL_TREE, NULL_TREE, (LOOKUP_NORMAL|LOOKUP_AGGR)); } else $$ = build_scoped_method_call ($$, OP0 ($2), OP1 ($2), NULL_TREE); } /* p->int::~int() is valid -- 12.4 */ | object '~' TYPESPEC LEFT_RIGHT { got_object = NULL_TREE; if (IDENTIFIER_GLOBAL_VALUE ($3) && (TREE_CODE (TREE_TYPE ($1)) != TREE_CODE (TREE_TYPE (IDENTIFIER_GLOBAL_VALUE ($3))))) cp_error ("`%E' is not of type `%T'", $1, $3); $$ = convert (void_type_node, $1); } | object TYPESPEC SCOPE '~' TYPESPEC LEFT_RIGHT { got_object = NULL_TREE; if ($2 != $5) cp_error ("destructor specifier `%T::~%T()' must have matching names", $2, $5); if (TREE_CODE (TREE_TYPE ($1)) != TREE_CODE (TREE_TYPE (IDENTIFIER_GLOBAL_VALUE ($2)))) cp_error ("`%E' is not of type `%T'", $1, $2); $$ = convert (void_type_node, $1); } | object error { got_object = NULL_TREE; $$ = error_mark_node; } ; /* Not needed for now. primary_no_id: '(' expr ')' { $$ = $2; } | '(' error ')' { $$ = error_mark_node; } | '(' { if (current_function_decl == 0) { error ("braced-group within expression allowed only inside a function"); YYERROR; } $$ = expand_start_stmt_expr (); } compstmt ')' { if (pedantic) pedwarn ("ANSI C++ forbids braced-groups within expressions"); $$ = expand_end_stmt_expr ($2); } | primary_no_id '(' nonnull_exprlist ')' { $$ = build_x_function_call ($$, $3, current_class_decl); } | primary_no_id LEFT_RIGHT { $$ = build_x_function_call ($$, NULL_TREE, current_class_decl); } | primary_no_id '[' expr ']' { goto do_array; } | primary_no_id PLUSPLUS { $$ = build_x_unary_op (POSTINCREMENT_EXPR, $$); } | primary_no_id MINUSMINUS { $$ = build_x_unary_op (POSTDECREMENT_EXPR, $$); } | SCOPE IDENTIFIER { goto do_scoped_id; } | SCOPE operator_name { if (TREE_CODE ($2) == IDENTIFIER_NODE) goto do_scoped_id; goto do_scoped_operator; } ; */ new: NEW { $$ = 0; } | global_scope NEW { got_scope = NULL_TREE; $$ = 1; } ; delete: DELETE { $$ = 0; } | global_scope delete { got_scope = NULL_TREE; $$ = 1; } ; boolean.literal: CXX_TRUE { $$ = boolean_true_node; } | CXX_FALSE { $$ = boolean_false_node; } ; /* Produces a STRING_CST with perhaps more STRING_CSTs chained onto it. */ string: STRING | string STRING { $$ = chainon ($$, $2); } ; nodecls: /* empty */ { if (! current_function_parms_stored) store_parm_decls (); setup_vtbl_ptr (); /* Always keep the BLOCK node associated with the outermost pair of curley braces of a function. These are needed for correct operation of dwarfout.c. */ keep_next_level (); } ; object: primary '.' { got_object = TREE_TYPE ($$); } | primary POINTSAT { $$ = build_x_arrow ($$); got_object = TREE_TYPE ($$); } ; decl: /* Normal case: make this fast. */ typespec declarator ';' { tree d = get_decl_list ($1); int yes = suspend_momentary (); d = start_decl ($2, d, 0, NULL_TREE); cp_finish_decl (d, NULL_TREE, NULL_TREE, 0, 0); resume_momentary (yes); if (IS_AGGR_TYPE_CODE (TREE_CODE ($1))) note_got_semicolon ($1); } | typed_declspecs declarator ';' { tree d, specs, attrs; int yes; split_specs_attrs ($1, &specs, &attrs); yes = suspend_momentary (); d = start_decl ($2, specs, 0, NULL_TREE); cplus_decl_attributes (d, NULL_TREE, attrs); cp_finish_decl (d, NULL_TREE, NULL_TREE, 0, 0); resume_momentary (yes); note_list_got_semicolon ($1); } | typespec initdecls ';' { resume_momentary ($2); if (IS_AGGR_TYPE_CODE (TREE_CODE ($1))) note_got_semicolon ($1); } | typed_declspecs initdecls ';' { resume_momentary ($2); note_list_got_semicolon ($1); } | declmods notype_initdecls ';' { resume_momentary ($2); } | typed_declspecs ';' { shadow_tag ($1); note_list_got_semicolon ($1); } | declmods ';' { warning ("empty declaration"); } ; /* Any kind of declarator (thus, all declarators allowed after an explicit typespec). */ declarator: after_type_declarator %prec EMPTY | notype_declarator %prec EMPTY ; /* This is necessary to postpone reduction of `int()()()()'. */ fcast_or_absdcl: LEFT_RIGHT %prec EMPTY { $$ = build_parse_node (CALL_EXPR, NULL_TREE, empty_parms (), NULL_TREE); } | fcast_or_absdcl LEFT_RIGHT %prec EMPTY { $$ = build_parse_node (CALL_EXPR, $$, empty_parms (), NULL_TREE); } ; /* ANSI type-id (8.1) */ type_id: typed_typespecs absdcl { $$ = build_decl_list ($$, $2); } | nonempty_type_quals absdcl { $$ = build_decl_list ($$, $2); } | typespec absdcl { $$ = build_decl_list (get_decl_list ($$), $2); } | typed_typespecs %prec EMPTY { $$ = build_decl_list ($$, NULL_TREE); } | nonempty_type_quals %prec EMPTY { $$ = build_decl_list ($$, NULL_TREE); } ; /* 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. In the result, declspecs have a non-NULL TREE_VALUE, attributes do not. */ typed_declspecs: typed_typespecs %prec EMPTY | typed_declspecs1 ; typed_declspecs1: declmods typespec { $$ = decl_tree_cons (NULL_TREE, $2, $$); } | typespec reserved_declspecs %prec HYPERUNARY { $$ = decl_tree_cons (NULL_TREE, $$, $2); } | typespec reserved_typespecquals reserved_declspecs { $$ = decl_tree_cons (NULL_TREE, $$, chainon ($2, $3)); } | declmods typespec reserved_declspecs { $$ = decl_tree_cons (NULL_TREE, $2, chainon ($3, $$)); } | declmods typespec reserved_typespecquals { $$ = decl_tree_cons (NULL_TREE, $2, chainon ($3, $$)); } | declmods typespec reserved_typespecquals reserved_declspecs { $$ = decl_tree_cons (NULL_TREE, $2, chainon ($3, chainon ($4, $$))); } ; reserved_declspecs: SCSPEC { if (extra_warnings) warning ("`%s' is not at beginning of declaration", IDENTIFIER_POINTER ($$)); $$ = build_decl_list (NULL_TREE, $$); } | reserved_declspecs typespecqual_reserved { $$ = decl_tree_cons (NULL_TREE, $2, $$); } | reserved_declspecs SCSPEC { if (extra_warnings) warning ("`%s' is not at beginning of declaration", IDENTIFIER_POINTER ($2)); $$ = decl_tree_cons (NULL_TREE, $2, $$); } | reserved_declspecs attributes { $$ = decl_tree_cons ($2, NULL_TREE, $1); } | attributes { $$ = decl_tree_cons ($1, NULL_TREE, NULL_TREE); } ; /* List of just storage classes and type modifiers. A declaration can start with just this, but then it cannot be used to redeclare a typedef-name. In the result, declspecs have a non-NULL TREE_VALUE, attributes do not. */ declmods: nonempty_type_quals %prec EMPTY { TREE_STATIC ($$) = 1; } | SCSPEC { $$ = IDENTIFIER_AS_LIST ($$); } | declmods TYPE_QUAL { $$ = decl_tree_cons (NULL_TREE, $2, $$); TREE_STATIC ($$) = 1; } | declmods SCSPEC { if (extra_warnings && TREE_STATIC ($$)) warning ("`%s' is not at beginning of declaration", IDENTIFIER_POINTER ($2)); $$ = decl_tree_cons (NULL_TREE, $2, $$); TREE_STATIC ($$) = TREE_STATIC ($1); } | declmods attributes { $$ = decl_tree_cons ($2, NULL_TREE, $1); } | attributes { $$ = decl_tree_cons ($1, NULL_TREE, NULL_TREE); } ; /* Used instead of declspecs where storage classes are not allowed (that is, for typenames and structure components). C++ can takes storage classes for structure components. Don't accept a typedef-name if anything but a modifier precedes it. */ typed_typespecs: typespec %prec EMPTY { $$ = get_decl_list ($$); } | nonempty_type_quals typespec { $$ = decl_tree_cons (NULL_TREE, $2, $$); } | typespec reserved_typespecquals { $$ = decl_tree_cons (NULL_TREE, $$, $2); } | nonempty_type_quals typespec reserved_typespecquals { $$ = decl_tree_cons (NULL_TREE, $2, chainon ($3, $$)); } ; reserved_typespecquals: typespecqual_reserved { $$ = build_decl_list (NULL_TREE, $$); } | reserved_typespecquals typespecqual_reserved { $$ = decl_tree_cons (NULL_TREE, $2, $$); } ; /* A typespec (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. */ typespec: structsp | TYPESPEC %prec EMPTY | complete_type_name | TYPEOF '(' expr ')' { $$ = TREE_TYPE ($3); if (pedantic && !in_system_header) pedwarn ("ANSI C++ forbids `typeof'"); } | TYPEOF '(' type_id ')' { $$ = groktypename ($3); if (pedantic && !in_system_header) pedwarn ("ANSI C++ forbids `typeof'"); } | SIGOF '(' expr ')' { tree type = TREE_TYPE ($3); if (IS_AGGR_TYPE (type)) { sorry ("sigof type specifier"); $$ = type; } else { error ("`sigof' applied to non-aggregate expression"); $$ = error_mark_node; } } | SIGOF '(' type_id ')' { tree type = groktypename ($3); if (IS_AGGR_TYPE (type)) { sorry ("sigof type specifier"); $$ = type; } else { error("`sigof' applied to non-aggregate type"); $$ = error_mark_node; } } ; /* A typespec that is a reserved word, or a type qualifier. */ typespecqual_reserved: TYPESPEC | TYPE_QUAL | structsp ; initdecls: initdcl0 | initdecls ',' initdcl ; notype_initdecls: notype_initdcl0 | notype_initdecls ',' initdcl ; nomods_initdecls: nomods_initdcl0 | nomods_initdecls ',' initdcl ; maybeasm: /* empty */ { $$ = NULL_TREE; } | asm_keyword '(' string ')' { if (TREE_CHAIN ($3)) $3 = combine_strings ($3); $$ = $3; } ; initdcl0: declarator exception_specification_opt maybeasm maybe_attribute '=' { split_specs_attrs ($0, ¤t_declspecs, &prefix_attributes); if (TREE_CODE (current_declspecs) != TREE_LIST) current_declspecs = get_decl_list (current_declspecs); if (have_extern_spec && !used_extern_spec) { current_declspecs = decl_tree_cons (NULL_TREE, get_identifier ("extern"), current_declspecs); used_extern_spec = 1; } $5 = suspend_momentary (); $$ = start_decl ($1, current_declspecs, 1, $2); cplus_decl_attributes ($$, $4, prefix_attributes); } init /* Note how the declaration of the variable is in effect while its init is parsed! */ { cp_finish_decl ($6, $7, $3, 0, LOOKUP_ONLYCONVERTING); $$ = $5; } | declarator exception_specification_opt maybeasm maybe_attribute { tree d; split_specs_attrs ($0, ¤t_declspecs, &prefix_attributes); if (TREE_CODE (current_declspecs) != TREE_LIST) current_declspecs = get_decl_list (current_declspecs); if (have_extern_spec && !used_extern_spec) { current_declspecs = decl_tree_cons (NULL_TREE, get_identifier ("extern"), current_declspecs); used_extern_spec = 1; } $$ = suspend_momentary (); d = start_decl ($1, current_declspecs, 0, $2); cplus_decl_attributes (d, $4, prefix_attributes); cp_finish_decl (d, NULL_TREE, $3, 0, 0); } ; initdcl: declarator exception_specification_opt maybeasm maybe_attribute '=' { $$ = start_decl ($1, current_declspecs, 1, $2); cplus_decl_attributes ($$, $4, prefix_attributes); } init /* Note how the declaration of the variable is in effect while its init is parsed! */ { cp_finish_decl ($6, $7, $3, 0, LOOKUP_ONLYCONVERTING); } | declarator exception_specification_opt maybeasm maybe_attribute { $$ = start_decl ($1, current_declspecs, 0, $2); cplus_decl_attributes ($$, $4, prefix_attributes); cp_finish_decl ($$, NULL_TREE, $3, 0, 0); } ; notype_initdcl0: notype_declarator exception_specification_opt maybeasm maybe_attribute '=' { split_specs_attrs ($0, ¤t_declspecs, &prefix_attributes); $5 = suspend_momentary (); $$ = start_decl ($1, current_declspecs, 1, $2); cplus_decl_attributes ($$, $4, prefix_attributes); } init /* Note how the declaration of the variable is in effect while its init is parsed! */ { cp_finish_decl ($6, $7, $3, 0, LOOKUP_ONLYCONVERTING); $$ = $5; } | notype_declarator exception_specification_opt maybeasm maybe_attribute { tree d; split_specs_attrs ($0, ¤t_declspecs, &prefix_attributes); $$ = suspend_momentary (); d = start_decl ($1, current_declspecs, 0, $2); cplus_decl_attributes (d, $4, prefix_attributes); cp_finish_decl (d, NULL_TREE, $3, 0, 0); } ; nomods_initdcl0: notype_declarator exception_specification_opt maybeasm maybe_attribute '=' { current_declspecs = NULL_TREE; prefix_attributes = NULL_TREE; $5 = suspend_momentary (); $$ = start_decl ($1, current_declspecs, 1, $2); cplus_decl_attributes ($$, $4, prefix_attributes); } init /* Note how the declaration of the variable is in effect while its init is parsed! */ { cp_finish_decl ($6, $7, $3, 0, LOOKUP_ONLYCONVERTING); $$ = $5; } | notype_declarator exception_specification_opt maybeasm maybe_attribute { tree d; current_declspecs = NULL_TREE; prefix_attributes = NULL_TREE; $$ = suspend_momentary (); d = start_decl ($1, current_declspecs, 0, $2); cplus_decl_attributes (d, $4, prefix_attributes); cp_finish_decl (d, NULL_TREE, $3, 0, 0); } ; /* the * rules are dummies to accept the Apollo extended syntax so that the header files compile. */ maybe_attribute: /* empty */ { $$ = NULL_TREE; } | attributes { $$ = $1; } ; attributes: attribute { $$ = $1; } | attributes attribute { $$ = chainon ($1, $2); } ; attribute: ATTRIBUTE '(' '(' attribute_list ')' ')' { $$ = $4; } ; attribute_list: attrib { $$ = $1; } | attribute_list ',' attrib { $$ = chainon ($1, $3); } ; attrib: /* empty */ { $$ = NULL_TREE; } | any_word { $$ = build_tree_list ($1, NULL_TREE); } | any_word '(' IDENTIFIER ')' { $$ = build_tree_list ($1, build_tree_list (NULL_TREE, $3)); } | any_word '(' IDENTIFIER ',' nonnull_exprlist ')' { $$ = build_tree_list ($1, tree_cons (NULL_TREE, $3, $5)); } | any_word '(' nonnull_exprlist ')' { $$ = build_tree_list ($1, $3); } ; /* This still leaves out most reserved keywords, shouldn't we include them? */ any_word: identifier | SCSPEC | TYPESPEC | TYPE_QUAL ; /* A nonempty list of identifiers, including typenames. */ identifiers_or_typenames: identifier { $$ = build_tree_list (NULL_TREE, $1); } | identifiers_or_typenames ',' identifier { $$ = chainon ($1, build_tree_list (NULL_TREE, $3)); } ; maybe_init: %prec EMPTY /* empty */ { $$ = NULL_TREE; } | '=' init { $$ = $2; } init: expr_no_commas %prec '=' | '{' '}' { $$ = build_nt (CONSTRUCTOR, NULL_TREE, NULL_TREE); TREE_HAS_CONSTRUCTOR ($$) = 1; } | '{' initlist '}' { $$ = build_nt (CONSTRUCTOR, NULL_TREE, nreverse ($2)); TREE_HAS_CONSTRUCTOR ($$) = 1; } | '{' initlist ',' '}' { $$ = build_nt (CONSTRUCTOR, NULL_TREE, nreverse ($2)); TREE_HAS_CONSTRUCTOR ($$) = 1; } | error { $$ = NULL_TREE; } ; /* This chain is built in reverse order, and put in forward order where initlist is used. */ initlist: init { $$ = build_tree_list (NULL_TREE, $$); } | initlist ',' init { $$ = tree_cons (NULL_TREE, $3, $$); } /* These are for labeled elements. */ | '[' expr_no_commas ']' init { $$ = build_tree_list ($2, $4); } | initlist ',' CASE expr_no_commas ':' init { $$ = tree_cons ($4, $6, $$); } | identifier ':' init { $$ = build_tree_list ($$, $3); } | initlist ',' identifier ':' init { $$ = tree_cons ($3, $5, $$); } ; structsp: ENUM identifier '{' { $3 = suspend_momentary (); $$ = start_enum ($2); } enumlist maybecomma_warn '}' { $$ = finish_enum ($4, $5); resume_momentary ((int) $3); check_for_missing_semicolon ($4); } | ENUM identifier '{' '}' { $$ = finish_enum (start_enum ($2), NULL_TREE); check_for_missing_semicolon ($$); } | ENUM '{' { $2 = suspend_momentary (); $$ = start_enum (make_anon_name ()); } enumlist maybecomma_warn '}' { $$ = finish_enum ($3, $4); resume_momentary ((int) $1); check_for_missing_semicolon ($3); } | ENUM '{' '}' { $$ = finish_enum (start_enum (make_anon_name()), NULL_TREE); check_for_missing_semicolon ($$); } | ENUM identifier { $$ = xref_tag (enum_type_node, $2, NULL_TREE, 1); } | ENUM complex_type_name { $$ = xref_tag (enum_type_node, $2, NULL_TREE, 1); } | TYPENAME_KEYWORD complex_type_name { $$ = $2; } /* C++ extensions, merged with C to avoid shift/reduce conflicts */ | class_head left_curly opt.component_decl_list '}' { int semi; tree id; #if 0 /* Need to rework class nesting in the presence of nested classes, etc. */ shadow_tag (CLASSTYPE_AS_LIST ($$)); */ #endif if (yychar == YYEMPTY) yychar = YYLEX; semi = yychar == ';'; /* finish_struct nukes this anyway; if finish_exception does too, then it can go. */ if (semi) note_got_semicolon ($$); if (TREE_CODE ($$) == ENUMERAL_TYPE) /* $$ = $1 from default rule. */; else { $$ = finish_struct ($$, $3, semi); if (semi) note_got_semicolon ($$); } pop_obstacks (); id = TYPE_IDENTIFIER ($$); if (id && IDENTIFIER_TEMPLATE (id)) { tree decl; /* I don't know if the copying of this TYPE_DECL is * really needed. However, it's such a small per- * formance penalty that the extra safety is a bargain. * - niklas@appli.se */ push_obstacks (&permanent_obstack, &permanent_obstack); decl = copy_node (lookup_name (id, 0)); if (DECL_LANG_SPECIFIC (decl)) copy_lang_decl (decl); pop_obstacks (); undo_template_name_overload (id, 0); pushdecl_top_level (decl); } if (! semi) check_for_missing_semicolon ($$); } | class_head %prec EMPTY { /* struct B: public A; is not accepted by the WP grammar. */ if (TYPE_BINFO_BASETYPES ($$) && !TYPE_SIZE ($$) && ! TYPE_BEING_DEFINED ($$)) cp_error ("base clause without member specification for `%#T'", $$); } ; maybecomma: /* empty */ | ',' ; maybecomma_warn: /* empty */ | ',' { if (pedantic) pedwarn ("comma at end of enumerator list"); } ; aggr: AGGR | aggr SCSPEC { error ("storage class specifier `%s' not allowed after struct or class", IDENTIFIER_POINTER ($2)); } | aggr TYPESPEC { error ("type specifier `%s' not allowed after struct or class", IDENTIFIER_POINTER ($2)); } | aggr TYPE_QUAL { error ("type qualifier `%s' not allowed after struct or class", IDENTIFIER_POINTER ($2)); } | aggr AGGR { error ("no body nor ';' separates two class, struct or union declarations"); } ; specialization: aggr template_type_name ';' { yyungetc (';', 1); current_aggr = $$; $$ = $2; if ($0 == ridpointers[(int) RID_TEMPLATE]) instantiate_class_template ($$, 2); } ; named_class_head_sans_basetype: aggr identifier { current_aggr = $$; $$ = $2; } | specialization ; named_class_head_sans_basetype_defn: aggr identifier_defn %prec EMPTY { current_aggr = $$; $$ = $2; } | aggr template_type_name '{' { yyungetc ('{', 1); aggr2: current_aggr = $$; $$ = $2; overload_template_name ($$, 0); } | aggr template_type_name ':' { yyungetc (':', 1); goto aggr2; } ; named_complex_class_head_sans_basetype: aggr nested_name_specifier identifier { current_aggr = $$; $$ = $3; } | aggr template_type %prec EMPTY { current_aggr = $$; $$ = $2; } ; do_xref_defn: /* empty */ %prec EMPTY { $$ = xref_tag (current_aggr, $0, NULL_TREE, 0); } ; named_class_head: named_class_head_sans_basetype %prec EMPTY { $$ = xref_tag (current_aggr, $1, NULL_TREE, 1); } | named_class_head_sans_basetype_defn do_xref_defn maybe_base_class_list %prec EMPTY { $$ = $2; if ($3) xref_basetypes (current_aggr, $1, $2, $3); } | named_complex_class_head_sans_basetype maybe_base_class_list { $$ = TREE_TYPE ($1); if ($2) xref_basetypes (current_aggr, $1, TREE_TYPE ($1), $2); } ; unnamed_class_head: aggr '{' { $$ = xref_tag ($$, make_anon_name (), NULL_TREE, 0); yyungetc ('{', 1); } ; class_head: unnamed_class_head | named_class_head ; maybe_base_class_list: %prec EMPTY /* empty */ { $$ = NULL_TREE; } | ':' see_typename %prec EMPTY { yyungetc(':', 1); $$ = NULL_TREE; } | ':' see_typename base_class_list %prec EMPTY { $$ = $3; } ; base_class_list: base_class | base_class_list ',' see_typename base_class { $$ = chainon ($$, $4); } ; base_class: base_class.1 { tree type; type = IDENTIFIER_TYPE_VALUE ($$); if (! is_aggr_typedef ($$, 1)) $$ = NULL_TREE; else if (current_aggr == signature_type_node && (! type) && (! IS_SIGNATURE (type))) { error ("class name not allowed as base signature"); $$ = NULL_TREE; } else if (current_aggr == signature_type_node) { sorry ("signature inheritance, base type `%s' ignored", IDENTIFIER_POINTER ($$)); $$ = build_tree_list ((tree)access_public, $$); } else if (type && IS_SIGNATURE (type)) { error ("signature name not allowed as base class"); $$ = NULL_TREE; } else $$ = build_tree_list ((tree)access_default, $$); } | base_class_access_list see_typename base_class.1 { tree type; type = IDENTIFIER_TYPE_VALUE ($3); if (current_aggr == signature_type_node) error ("access and source specifiers not allowed in signature"); if (! is_aggr_typedef ($3, 1)) $$ = NULL_TREE; else if (current_aggr == signature_type_node && (! type) && (! IS_SIGNATURE (type))) { error ("class name not allowed as base signature"); $$ = NULL_TREE; } else if (current_aggr == signature_type_node) { sorry ("signature inheritance, base type `%s' ignored", IDENTIFIER_POINTER ($$)); $$ = build_tree_list ((tree)access_public, $3); } else if (type && IS_SIGNATURE (type)) { error ("signature name not allowed as base class"); $$ = NULL_TREE; } else $$ = build_tree_list ((tree) $$, $3); } ; base_class.1: complete_type_name | SIGOF '(' expr ')' { if (current_aggr == signature_type_node) { if (IS_AGGR_TYPE (TREE_TYPE ($3))) { sorry ("`sigof' as base signature specifier"); /* need to return some dummy signature identifier */ $$ = $3; } else { error ("`sigof' applied to non-aggregate expression"); $$ = error_mark_node; } } else { error ("`sigof' in struct or class declaration"); $$ = error_mark_node; } } | SIGOF '(' type_id ')' { if (current_aggr == signature_type_node) { if (IS_AGGR_TYPE (groktypename ($3))) { sorry ("`sigof' as base signature specifier"); /* need to return some dummy signature identifier */ $$ = $3; } else { error ("`sigof' applied to non-aggregate expression"); $$ = error_mark_node; } } else { error ("`sigof' in struct or class declaration"); $$ = error_mark_node; } } ; base_class_access_list: VISSPEC see_typename | SCSPEC see_typename { if ($$ != ridpointers[(int)RID_VIRTUAL]) sorry ("non-virtual access"); $$ = access_default_virtual; } | base_class_access_list VISSPEC see_typename { int err = 0; if ($2 == access_protected) { warning ("`protected' access not implemented"); $2 = access_public; err++; } else if ($2 == access_public) { if ($1 == access_private) { mixed: error ("base class cannot be public and private"); } else if ($1 == access_default_virtual) $$ = access_public_virtual; } else /* $2 == access_private */ { if ($1 == access_public) goto mixed; else if ($1 == access_default_virtual) $$ = access_private_virtual; } } | base_class_access_list SCSPEC see_typename { if ($2 != ridpointers[(int)RID_VIRTUAL]) sorry ("non-virtual access"); if ($$ == access_public) $$ = access_public_virtual; else if ($$ == access_private) $$ = access_private_virtual; } ; left_curly: '{' { tree t = $0; push_obstacks_nochange (); end_temporary_allocation (); if (! IS_AGGR_TYPE (t)) { t = $0 = make_lang_type (RECORD_TYPE); TYPE_NAME (t) = get_identifier ("erroneous type"); } if (TYPE_SIZE (t)) duplicate_tag_error (t); if (TYPE_SIZE (t) || TYPE_BEING_DEFINED (t)) { t = make_lang_type (TREE_CODE (t)); pushtag (TYPE_IDENTIFIER ($0), t, 0); $0 = t; } pushclass (t, 0); TYPE_BEING_DEFINED (t) = 1; /* Reset the interface data, at the earliest possible moment, as it might have been set via a class foo; before. */ /* Don't change signatures. */ if (! IS_SIGNATURE (t)) { extern tree pending_vtables; int needs_writing; tree name = TYPE_IDENTIFIER (t); if (! ANON_AGGRNAME_P (name)) { CLASSTYPE_INTERFACE_ONLY (t) = interface_only; SET_CLASSTYPE_INTERFACE_UNKNOWN_X (t, interface_unknown); } /* Record how to set the access of this class's virtual functions. If write_virtuals == 2 or 3, then inline virtuals are ``extern inline''. */ switch (write_virtuals) { case 0: case 1: needs_writing = 1; break; case 2: needs_writing = !! value_member (name, pending_vtables); break; case 3: needs_writing = ! CLASSTYPE_INTERFACE_ONLY (t) && CLASSTYPE_INTERFACE_KNOWN (t); break; default: needs_writing = 0; } CLASSTYPE_VTABLE_NEEDS_WRITING (t) = needs_writing; } #if 0 t = TYPE_IDENTIFIER ($0); if (t && IDENTIFIER_TEMPLATE (t)) overload_template_name (t, 1); #endif } ; opt.component_decl_list: /* empty */ { $$ = NULL_TREE; } | component_decl_list { if (current_aggr == signature_type_node) $$ = build_tree_list ((tree) access_public, $$); else $$ = build_tree_list ((tree) access_default, $$); } | opt.component_decl_list VISSPEC ':' component_decl_list { tree visspec = (tree) $2; if (current_aggr == signature_type_node) { error ("access specifier not allowed in signature"); visspec = (tree) access_public; } $$ = chainon ($$, build_tree_list (visspec, $4)); } | opt.component_decl_list VISSPEC ':' { if (current_aggr == signature_type_node) error ("access specifier not allowed in signature"); } ; /* Note: we no longer warn about the semicolon after a component_decl_list. ARM $9.2 says that the semicolon is optional, and therefore allowed. */ component_decl_list: component_decl { if ($$ == void_type_node) $$ = NULL_TREE; } | component_decl_list component_decl { /* In pushdecl, we created a reverse list of names in this binding level. Make sure that the chain of what we're trying to add isn't the item itself (which can happen with what pushdecl's doing). */ if ($2 != NULL_TREE && $2 != void_type_node) { if (TREE_CHAIN ($2) != $$) $$ = chainon ($$, $2); else $$ = $2; } } ; component_decl: component_decl_1 ';' { } | component_decl_1 '}' { error ("missing ';' before right brace"); yyungetc ('}', 0); } /* C++: handle constructors, destructors and inline functions */ /* note that INLINE is like a TYPESPEC */ | fn.def2 ':' /* base_init compstmt */ { $$ = finish_method ($$); } | fn.def2 TRY /* base_init compstmt */ { $$ = finish_method ($$); } | fn.def2 RETURN /* base_init compstmt */ { $$ = finish_method ($$); } | fn.def2 '{' /* nodecls compstmt */ { $$ = finish_method ($$); } | ';' { $$ = NULL_TREE; } ; component_decl_1: /* Do not add a "typed_declspecs declarator" rule here for speed; we need to call grok_x_components for enums, so the speedup would be insignificant. */ typed_declspecs components { $$ = grok_x_components ($1, $2); } | declmods notype_components { $$ = grok_x_components ($1, $2); } | notype_declarator exception_specification_opt maybeasm maybe_attribute maybe_init { $$ = grokfield ($$, NULL_TREE, $2, $5, $3, build_tree_list ($4, NULL_TREE)); } | ':' expr_no_commas { $$ = grokbitfield (NULL_TREE, NULL_TREE, $2); } | error { $$ = NULL_TREE; } /* These rules introduce a reduce/reduce conflict; in typedef int foo, bar; class A { foo (bar); }; should "A::foo" be declared as a function or "A::bar" as a data member? In other words, is "bar" an after_type_declarator or a parmlist? */ | typed_declspecs '(' parmlist ')' type_quals exception_specification_opt maybeasm maybe_attribute maybe_init { tree specs, attrs; split_specs_attrs ($1, &specs, &attrs); $$ = build_parse_node (CALL_EXPR, TREE_VALUE (specs), $3, $5); $$ = grokfield ($$, TREE_CHAIN (specs), $6, $9, $7, build_tree_list ($8, attrs)); } | typed_declspecs LEFT_RIGHT type_quals exception_specification_opt maybeasm maybe_attribute maybe_init { tree specs, attrs; split_specs_attrs ($1, &specs, &attrs); $$ = build_parse_node (CALL_EXPR, TREE_VALUE (specs), empty_parms (), $3); $$ = grokfield ($$, TREE_CHAIN (specs), $4, $7, $5, build_tree_list ($6, attrs)); } | using_decl { $$ = do_class_using_decl ($1); } ; /* The case of exactly one component is handled directly by component_decl. */ /* ??? Huh? ^^^ */ components: /* empty: possibly anonymous */ { $$ = NULL_TREE; } | component_declarator0 | components ',' component_declarator { /* In this context, void_type_node encodes friends. They have been recorded elsewhere. */ if ($$ == void_type_node) $$ = $3; else $$ = chainon ($$, $3); } ; notype_components: /* empty: possibly anonymous */ { $$ = NULL_TREE; } | notype_component_declarator0 | notype_components ',' notype_component_declarator { /* In this context, void_type_node encodes friends. They have been recorded elsewhere. */ if ($$ == void_type_node) $$ = $3; else $$ = chainon ($$, $3); } ; component_declarator0: after_type_component_declarator0 | notype_component_declarator0 ; component_declarator: after_type_component_declarator | notype_component_declarator ; after_type_component_declarator0: after_type_declarator exception_specification_opt maybeasm maybe_attribute maybe_init { split_specs_attrs ($0, ¤t_declspecs, &prefix_attributes); $0 = current_declspecs; $$ = grokfield ($$, current_declspecs, $2, $5, $3, build_tree_list ($4, prefix_attributes)); } | TYPENAME ':' expr_no_commas maybe_attribute { split_specs_attrs ($0, ¤t_declspecs, &prefix_attributes); $0 = current_declspecs; $$ = grokbitfield ($$, current_declspecs, $3); cplus_decl_attributes ($$, $4, prefix_attributes); } ; notype_component_declarator0: notype_declarator exception_specification_opt maybeasm maybe_attribute maybe_init { split_specs_attrs ($0, ¤t_declspecs, &prefix_attributes); $0 = current_declspecs; $$ = grokfield ($$, current_declspecs, $2, $5, $3, build_tree_list ($4, prefix_attributes)); } | IDENTIFIER ':' expr_no_commas maybe_attribute { split_specs_attrs ($0, ¤t_declspecs, &prefix_attributes); $0 = current_declspecs; $$ = grokbitfield ($$, current_declspecs, $3); cplus_decl_attributes ($$, $4, prefix_attributes); } | ':' expr_no_commas maybe_attribute { split_specs_attrs ($0, ¤t_declspecs, &prefix_attributes); $0 = current_declspecs; $$ = grokbitfield (NULL_TREE, current_declspecs, $2); cplus_decl_attributes ($$, $3, prefix_attributes); } ; after_type_component_declarator: after_type_declarator exception_specification_opt maybeasm maybe_attribute maybe_init { $$ = grokfield ($$, current_declspecs, $2, $5, $3, build_tree_list ($4, prefix_attributes)); } | TYPENAME ':' expr_no_commas maybe_attribute { $$ = grokbitfield ($$, current_declspecs, $3); cplus_decl_attributes ($$, $4, prefix_attributes); } ; notype_component_declarator: notype_declarator exception_specification_opt maybeasm maybe_attribute maybe_init { $$ = grokfield ($$, current_declspecs, $2, $5, $3, build_tree_list ($4, prefix_attributes)); } | IDENTIFIER ':' expr_no_commas maybe_attribute { $$ = grokbitfield ($$, current_declspecs, $3); cplus_decl_attributes ($$, $4, prefix_attributes); } | ':' expr_no_commas maybe_attribute { $$ = grokbitfield (NULL_TREE, current_declspecs, $2); cplus_decl_attributes ($$, $3, prefix_attributes); } ; /* We chain the enumerators in reverse order. Because of the way enums are built, the order is insignificant. Take advantage of this fact. */ enumlist: enumerator | enumlist ',' enumerator { TREE_CHAIN ($3) = $$; $$ = $3; } ; enumerator: identifier { $$ = build_enumerator ($$, NULL_TREE); } | identifier '=' expr_no_commas { $$ = build_enumerator ($$, $3); } ; /* ANSI new-type-id (5.3.4) */ new_type_id: type_specifier_seq new_declarator { $$ = build_decl_list ($$, $2); } | type_specifier_seq %prec EMPTY { $$ = build_decl_list ($$, NULL_TREE); } /* GNU extension to allow arrays of arbitrary types with non-constant dimension. */ | '(' type_id ')' '[' expr ']' { if (pedantic) pedwarn ("ANSI C++ forbids array dimensions with parenthesized type in new"); $$ = build_parse_node (ARRAY_REF, TREE_VALUE ($2), $5); $$ = build_decl_list (TREE_PURPOSE ($2), $$); } ; type_quals: /* empty */ %prec EMPTY { $$ = NULL_TREE; } | type_quals TYPE_QUAL { $$ = decl_tree_cons (NULL_TREE, $2, $$); } ; nonempty_type_quals: TYPE_QUAL { $$ = IDENTIFIER_AS_LIST ($$); } | nonempty_type_quals TYPE_QUAL { $$ = decl_tree_cons (NULL_TREE, $2, $$); } ; /* These rules must follow the rules for function declarations and component declarations. That way, longer rules are preferred. */ suspend_mom: { $$ = suspend_momentary (); } /* An expression which will not live on the momentary obstack. */ nonmomentary_expr: suspend_mom expr { resume_momentary ((int) $1); $$ = $2; } ; /* An expression which will not live on the momentary obstack. */ maybe_parmlist: suspend_mom '(' nonnull_exprlist ')' { resume_momentary ((int) $1); $$ = $3; } | suspend_mom '(' parmlist ')' { resume_momentary ((int) $1); $$ = $3; } | suspend_mom LEFT_RIGHT { resume_momentary ((int) $1); $$ = empty_parms (); } | suspend_mom '(' error ')' { resume_momentary ((int) $1); $$ = NULL_TREE; } ; /* A declarator that is allowed only after an explicit typespec. */ /* may all be followed by prec '.' */ after_type_declarator: '*' nonempty_type_quals after_type_declarator %prec UNARY { $$ = make_pointer_declarator ($2, $3); } | '&' nonempty_type_quals after_type_declarator %prec UNARY { $$ = make_reference_declarator ($2, $3); } | '*' after_type_declarator %prec UNARY { $$ = make_pointer_declarator (NULL_TREE, $2); } | '&' after_type_declarator %prec UNARY { $$ = make_reference_declarator (NULL_TREE, $2); } | ptr_to_mem type_quals after_type_declarator { tree arg = make_pointer_declarator ($2, $3); $$ = build_parse_node (SCOPE_REF, $1, arg); } | direct_after_type_declarator ; qualified_type_name: type_name %prec EMPTY { /* Remember that this name has been used in the class definition, as per [class.scope0] */ if (current_class_type && TYPE_BEING_DEFINED (current_class_type) && ! IDENTIFIER_CLASS_VALUE ($$)) { tree t = lookup_name ($$, -2); if (t) pushdecl_class_level (t); } } | nested_type ; nested_type: nested_name_specifier type_name %prec EMPTY { $$ = $2; } ; direct_after_type_declarator: direct_after_type_declarator maybe_parmlist type_quals %prec '.' { $$ = build_parse_node (CALL_EXPR, $$, $2, $3); } | direct_after_type_declarator '[' nonmomentary_expr ']' { $$ = build_parse_node (ARRAY_REF, $$, $3); } | direct_after_type_declarator '[' ']' { $$ = build_parse_node (ARRAY_REF, $$, NULL_TREE); } | '(' after_type_declarator ')' { $$ = $2; } | nested_name_specifier type_name %prec EMPTY { push_nested_class (TREE_TYPE ($$), 3); $$ = build_parse_node (SCOPE_REF, $$, $2); TREE_COMPLEXITY ($$) = current_class_depth; } | type_name %prec EMPTY ; /* A declarator allowed whether or not there has been an explicit typespec. These cannot redeclare a typedef-name. */ notype_declarator: '*' nonempty_type_quals notype_declarator %prec UNARY { $$ = make_pointer_declarator ($2, $3); } | '&' nonempty_type_quals notype_declarator %prec UNARY { $$ = make_reference_declarator ($2, $3); } | '*' notype_declarator %prec UNARY { $$ = make_pointer_declarator (NULL_TREE, $2); } | '&' notype_declarator %prec UNARY { $$ = make_reference_declarator (NULL_TREE, $2); } | ptr_to_mem type_quals notype_declarator { tree arg = make_pointer_declarator ($2, $3); $$ = build_parse_node (SCOPE_REF, $1, arg); } | direct_notype_declarator ; complex_notype_declarator: '*' nonempty_type_quals notype_declarator %prec UNARY { $$ = make_pointer_declarator ($2, $3); } | '&' nonempty_type_quals notype_declarator %prec UNARY { $$ = make_reference_declarator ($2, $3); } | '*' complex_notype_declarator %prec UNARY { $$ = make_pointer_declarator (NULL_TREE, $2); } | '&' complex_notype_declarator %prec UNARY { $$ = make_reference_declarator (NULL_TREE, $2); } | ptr_to_mem type_quals notype_declarator { tree arg = make_pointer_declarator ($2, $3); $$ = build_parse_node (SCOPE_REF, $1, arg); } | complex_direct_notype_declarator ; complex_direct_notype_declarator: direct_notype_declarator maybe_parmlist type_quals %prec '.' { $$ = build_parse_node (CALL_EXPR, $$, $2, $3); } | '(' complex_notype_declarator ')' { $$ = $2; } | direct_notype_declarator '[' nonmomentary_expr ']' { $$ = build_parse_node (ARRAY_REF, $$, $3); } | direct_notype_declarator '[' ']' { $$ = build_parse_node (ARRAY_REF, $$, NULL_TREE); } | notype_qualified_id { if (TREE_TYPE (OP0 ($$)) != current_class_type) { push_nested_class (TREE_TYPE (OP0 ($$)), 3); TREE_COMPLEXITY ($$) = current_class_depth; } } ; qualified_id: nested_name_specifier unqualified_id { got_scope = NULL_TREE; $$ = build_parse_node (SCOPE_REF, $$, $2); } ; notype_qualified_id: nested_name_specifier notype_unqualified_id { got_scope = NULL_TREE; $$ = build_parse_node (SCOPE_REF, $$, $2); } ; overqualified_id: notype_qualified_id | global_scope notype_qualified_id { $$ = $2; } ; functional_cast: typespec '(' nonnull_exprlist ')' { $$ = build_functional_cast ($$, $3); } | typespec '(' expr_or_declarator ')' { $$ = reparse_decl_as_expr ($$, $3); } | typespec fcast_or_absdcl %prec EMPTY { $$ = reparse_absdcl_as_expr ($$, $2); } ; type_name: TYPENAME | template_type %prec EMPTY ; nested_name_specifier: nested_name_specifier_1 | nested_name_specifier nested_name_specifier_1 { $$ = $2; } ; /* Why the @#$%^& do type_name and notype_identifier need to be expanded inline here?!? (jason) */ nested_name_specifier_1: TYPENAME SCOPE { got_scope = TREE_TYPE ($$); } | NSNAME SCOPE { got_scope = $$; } | template_type SCOPE { got_scope = TREE_TYPE ($$); } /* These break 'const i;' | IDENTIFIER SCOPE { failed_scope: cp_error ("`%D' is not an aggregate typedef", lastiddecl ? lastiddecl : $$); $$ = error_mark_node; } | PTYPENAME SCOPE { goto failed_scope; } */ ; complete_type_name: qualified_type_name | global_scope qualified_type_name { $$ = $2; } ; complex_type_name: nested_type | global_scope qualified_type_name { $$ = $2; } ; ptr_to_mem: nested_name_specifier '*' { got_scope = NULL_TREE; } | global_scope nested_name_specifier '*' { $$ = $2; got_scope = NULL_TREE; } ; /* All uses of explicit global scope must go through this nonterminal so that got_scope will be set before yylex is called to get the next token. */ global_scope: SCOPE { got_scope = void_type_node; } ; /* ANSI new-declarator (5.3.4) */ new_declarator: '*' type_quals new_declarator { $$ = make_pointer_declarator ($2, $3); } | '*' type_quals %prec EMPTY { $$ = make_pointer_declarator ($2, NULL_TREE); } | '&' type_quals new_declarator %prec EMPTY { $$ = make_reference_declarator ($2, $3); } | '&' type_quals %prec EMPTY { $$ = make_reference_declarator ($2, NULL_TREE); } | ptr_to_mem type_quals %prec EMPTY { tree arg = make_pointer_declarator ($2, NULL_TREE); $$ = build_parse_node (SCOPE_REF, $1, arg); } | ptr_to_mem type_quals new_declarator { tree arg = make_pointer_declarator ($2, $3); $$ = build_parse_node (SCOPE_REF, $1, arg); } | direct_new_declarator %prec EMPTY ; /* ANSI direct-new-declarator (5.3.4) */ direct_new_declarator: '[' expr ']' { $$ = build_parse_node (ARRAY_REF, NULL_TREE, $2); } | direct_new_declarator '[' nonmomentary_expr ']' { $$ = build_parse_node (ARRAY_REF, $$, $3); } ; /* ANSI abstract-declarator (8.1) */ absdcl: '*' nonempty_type_quals absdcl { $$ = make_pointer_declarator ($2, $3); } | '*' absdcl { $$ = make_pointer_declarator (NULL_TREE, $2); } | '*' nonempty_type_quals %prec EMPTY { $$ = make_pointer_declarator ($2, NULL_TREE); } | '*' %prec EMPTY { $$ = make_pointer_declarator (NULL_TREE, NULL_TREE); } | '&' nonempty_type_quals absdcl { $$ = make_reference_declarator ($2, $3); } | '&' absdcl { $$ = make_reference_declarator (NULL_TREE, $2); } | '&' nonempty_type_quals %prec EMPTY { $$ = make_reference_declarator ($2, NULL_TREE); } | '&' %prec EMPTY { $$ = make_reference_declarator (NULL_TREE, NULL_TREE); } | ptr_to_mem type_quals %prec EMPTY { tree arg = make_pointer_declarator ($2, NULL_TREE); $$ = build_parse_node (SCOPE_REF, $1, arg); } | ptr_to_mem type_quals absdcl { tree arg = make_pointer_declarator ($2, $3); $$ = build_parse_node (SCOPE_REF, $1, arg); } | direct_abstract_declarator %prec EMPTY ; /* ANSI direct-abstract-declarator (8.1) */ direct_abstract_declarator: '(' absdcl ')' { $$ = $2; } /* `(typedef)1' is `int'. */ | PAREN_STAR_PAREN | direct_abstract_declarator '(' parmlist ')' type_quals %prec '.' { $$ = build_parse_node (CALL_EXPR, $$, $3, $5); } | direct_abstract_declarator LEFT_RIGHT type_quals %prec '.' { $$ = build_parse_node (CALL_EXPR, $$, empty_parms (), $3); } | direct_abstract_declarator '[' nonmomentary_expr ']' %prec '.' { $$ = build_parse_node (ARRAY_REF, $$, $3); } | direct_abstract_declarator '[' ']' %prec '.' { $$ = build_parse_node (ARRAY_REF, $$, NULL_TREE); } | '(' complex_parmlist ')' type_quals %prec '.' { $$ = build_parse_node (CALL_EXPR, NULL_TREE, $2, $4); } | regcast_or_absdcl type_quals %prec '.' { TREE_OPERAND ($$, 2) = $2; } | fcast_or_absdcl type_quals %prec '.' { TREE_OPERAND ($$, 2) = $2; } | '[' nonmomentary_expr ']' %prec '.' { $$ = build_parse_node (ARRAY_REF, NULL_TREE, $2); } | '[' ']' %prec '.' { $$ = build_parse_node (ARRAY_REF, NULL_TREE, NULL_TREE); } ; /* For C++, decls and stmts can be intermixed, so we don't need to have a special rule that won't start parsing the stmt section until we have a stmt that parses without errors. */ stmts: stmt | errstmt | stmts stmt | stmts errstmt ; errstmt: error ';' ; /* build the LET_STMT node before parsing its contents, so that any LET_STMTs within the context can have their display pointers set up to point at this one. */ .pushlevel: /* empty */ { emit_line_note (input_filename, lineno); pushlevel (0); clear_last_expr (); push_momentary (); expand_start_bindings (0); } ; .poplevel: /* empty */ { expand_end_bindings (getdecls (), kept_level_p (), 1); $$ = poplevel (kept_level_p (), 1, 0); pop_momentary (); } ; /* 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"); } ; label_decls: label_decl | label_decls label_decl ; label_decl: LABEL identifiers_or_typenames ';' { tree link; for (link = $2; link; link = TREE_CHAIN (link)) { tree label = shadow_label (TREE_VALUE (link)); C_DECLARED_LABEL_FLAG (label) = 1; declare_nonlocal_label (label); } } ; /* This is the body of a function definition. It causes syntax errors to ignore to the next openbrace. */ compstmt_or_error: compstmt {} | error compstmt ; compstmt: '{' .pushlevel compstmtend .poplevel { $$ = $4; } ; simple_if: IF { cond_stmt_keyword = "if"; } .pushlevel paren_cond_or_null { emit_line_note (input_filename, lineno); expand_start_cond ($4, 0); } implicitly_scoped_stmt ; implicitly_scoped_stmt: compstmt { finish_stmt (); } | .pushlevel simple_stmt .poplevel { $$ = $3; } ; stmt: compstmt { finish_stmt (); } | simple_stmt ; simple_stmt: decl { finish_stmt (); } | expr ';' { tree expr = $1; emit_line_note (input_filename, lineno); /* Do default conversion if safe and possibly important, in case within ({...}). */ if ((TREE_CODE (TREE_TYPE (expr)) == ARRAY_TYPE && lvalue_p (expr)) || TREE_CODE (TREE_TYPE (expr)) == FUNCTION_TYPE) expr = default_conversion (expr); cplus_expand_expr_stmt (expr); clear_momentary (); finish_stmt (); } | simple_if ELSE { expand_start_else (); } implicitly_scoped_stmt { expand_end_cond (); } .poplevel { finish_stmt (); } | simple_if %prec IF { expand_end_cond (); expand_end_bindings (getdecls (), kept_level_p (), 1); poplevel (kept_level_p (), 1, 0); pop_momentary (); finish_stmt (); } | WHILE { emit_nop (); emit_line_note (input_filename, lineno); expand_start_loop (1); cond_stmt_keyword = "while"; } .pushlevel paren_cond_or_null { expand_exit_loop_if_false (0, $4); } already_scoped_stmt .poplevel { expand_end_loop (); finish_stmt (); } | DO { emit_nop (); emit_line_note (input_filename, lineno); expand_start_loop_continue_elsewhere (1); } implicitly_scoped_stmt WHILE { expand_loop_continue_here (); cond_stmt_keyword = "do"; } paren_expr_or_null ';' { emit_line_note (input_filename, lineno); expand_exit_loop_if_false (0, $6); expand_end_loop (); clear_momentary (); finish_stmt (); } | FOR { emit_line_note (input_filename, lineno); if (flag_new_for_scope > 0) { /* Conditionalize .pushlevel */ pushlevel (0); note_level_for_for (); clear_last_expr (); push_momentary (); expand_start_bindings (0); } } '(' for.init.statement { emit_nop (); emit_line_note (input_filename, lineno); expand_start_loop_continue_elsewhere (1); } .pushlevel xcond ';' { emit_line_note (input_filename, lineno); if ($7) expand_exit_loop_if_false (0, $7); } xexpr ')' /* Don't let the tree nodes for $10 be discarded by clear_momentary during the parsing of the next stmt. */ { push_momentary (); } already_scoped_stmt .poplevel { emit_line_note (input_filename, lineno); expand_loop_continue_here (); if ($10) cplus_expand_expr_stmt ($10); pop_momentary (); expand_end_loop (); if (flag_new_for_scope > 0) { expand_end_bindings (getdecls (), kept_level_p (), 1); poplevel (kept_level_p (), 1, 0); pop_momentary (); } finish_stmt (); } | SWITCH .pushlevel '(' condition ')' { emit_line_note (input_filename, lineno); c_expand_start_case ($4); push_switch (); /* Don't let the tree nodes for $4 be discarded by clear_momentary during the parsing of the next stmt. */ push_momentary (); } implicitly_scoped_stmt { expand_end_case ($4); pop_momentary (); pop_switch (); } .poplevel { finish_stmt (); } | CASE expr_no_commas ':' { register tree value = check_cp_case_value ($2); register tree label = build_decl (LABEL_DECL, NULL_TREE, NULL_TREE); if (value != error_mark_node) { tree duplicate; int success = pushcase (value, convert_and_check, label, &duplicate); if (success == 1) cp_error ("case label `%E' not within a switch statement", $2); else if (success == 2) { cp_error ("duplicate case value `%E'", $2); cp_error_at ("previously used here", duplicate); } else if (success == 3) warning ("case value out of range"); else if (success == 5) cp_error ("case label `%E' within scope of cleanup or variable array", $2); } define_case_label (label); } stmt | CASE expr_no_commas ELLIPSIS expr_no_commas ':' { register tree value1 = check_cp_case_value ($2); register tree value2 = check_cp_case_value ($4); register tree label = build_decl (LABEL_DECL, NULL_TREE, NULL_TREE); if (pedantic) pedwarn ("ANSI C++ forbids range expressions in switch statement"); if (value1 != error_mark_node && value2 != error_mark_node) { tree duplicate; int success = pushcase_range (value1, value2, convert_and_check, label, &duplicate); if (success == 1) error ("case label not within a switch statement"); else if (success == 2) { error ("duplicate (or overlapping) case value"); error_with_decl (duplicate, "this is the first entry overlapping that value"); } else if (success == 3) warning ("case value out of range"); else if (success == 4) warning ("empty range specified"); else if (success == 5) error ("case label within scope of cleanup or variable array"); } define_case_label (label); } stmt | DEFAULT ':' { tree duplicate; register tree label = build_decl (LABEL_DECL, NULL_TREE, NULL_TREE); int success = pushcase (NULL_TREE, 0, label, &duplicate); if (success == 1) error ("default label not within a switch statement"); else if (success == 2) { error ("multiple default labels in one switch"); error_with_decl (duplicate, "this is the first default label"); } define_case_label (NULL_TREE); } stmt | BREAK ';' { emit_line_note (input_filename, lineno); if ( ! expand_exit_something ()) error ("break statement not within loop or switch"); } | CONTINUE ';' { emit_line_note (input_filename, lineno); if (! expand_continue_loop (0)) error ("continue statement not within a loop"); } | RETURN ';' { emit_line_note (input_filename, lineno); c_expand_return (NULL_TREE); } | RETURN expr ';' { emit_line_note (input_filename, lineno); c_expand_return ($2); finish_stmt (); } | asm_keyword maybe_type_qual '(' string ')' ';' { if (TREE_CHAIN ($4)) $4 = combine_strings ($4); emit_line_note (input_filename, lineno); expand_asm ($4); finish_stmt (); } /* This is the case with just output operands. */ | asm_keyword maybe_type_qual '(' string ':' asm_operands ')' ';' { if (TREE_CHAIN ($4)) $4 = combine_strings ($4); emit_line_note (input_filename, lineno); c_expand_asm_operands ($4, $6, NULL_TREE, NULL_TREE, $2 == ridpointers[(int)RID_VOLATILE], input_filename, lineno); finish_stmt (); } /* This is the case with input operands as well. */ | asm_keyword maybe_type_qual '(' string ':' asm_operands ':' asm_operands ')' ';' { if (TREE_CHAIN ($4)) $4 = combine_strings ($4); emit_line_note (input_filename, lineno); c_expand_asm_operands ($4, $6, $8, NULL_TREE, $2 == ridpointers[(int)RID_VOLATILE], input_filename, lineno); finish_stmt (); } /* This is the case with clobbered registers as well. */ | asm_keyword maybe_type_qual '(' string ':' asm_operands ':' asm_operands ':' asm_clobbers ')' ';' { if (TREE_CHAIN ($4)) $4 = combine_strings ($4); emit_line_note (input_filename, lineno); c_expand_asm_operands ($4, $6, $8, $10, $2 == ridpointers[(int)RID_VOLATILE], input_filename, lineno); finish_stmt (); } | GOTO '*' expr ';' { emit_line_note (input_filename, lineno); expand_computed_goto ($3); } | GOTO identifier ';' { tree decl; emit_line_note (input_filename, lineno); decl = lookup_label ($2); TREE_USED (decl) = 1; expand_goto (decl); } | label_colon stmt { finish_stmt (); } | label_colon '}' { error ("label must be followed by statement"); yyungetc ('}', 0); finish_stmt (); } | ';' { finish_stmt (); } | try_block ; function_try_block: TRY { if (! current_function_parms_stored) store_parm_decls (); expand_start_early_try_stmts (); } ctor_initializer_opt compstmt_or_error { expand_end_try_stmts (); expand_start_all_catch (); } handler_seq { expand_end_all_catch (); finish_function (lineno, (int)$3, 0); } ; try_block: TRY { expand_start_try_stmts (); } compstmt { expand_end_try_stmts (); expand_start_all_catch (); } handler_seq { expand_end_all_catch (); } ; handler_seq: /* empty */ | handler_seq CATCH .pushlevel { dont_allow_type_definitions = "inside exception declarations"; } handler_args { dont_allow_type_definitions = 0; } compstmt { expand_end_catch_block (); } .poplevel ; type_specifier_seq: typed_typespecs %prec EMPTY | nonempty_type_quals %prec EMPTY ; handler_args: '(' ELLIPSIS ')' { expand_start_catch_block (NULL_TREE, NULL_TREE); } /* This doesn't allow reference parameters, the below does. | '(' type_specifier_seq absdcl ')' { expand_start_catch_block ($2, $3); } | '(' type_specifier_seq ')' { expand_start_catch_block ($2, NULL_TREE); } | '(' type_specifier_seq notype_declarator ')' { expand_start_catch_block ($2, $3); } | '(' typed_typespecs after_type_declarator ')' { expand_start_catch_block ($2, $3); } This allows reference parameters... */ | '(' parm ')' { expand_start_catch_block (TREE_PURPOSE ($2), TREE_VALUE ($2)); } ; label_colon: IDENTIFIER ':' { tree label; do_label: label = define_label (input_filename, lineno, $1); if (label) expand_label (label); } | PTYPENAME ':' { goto do_label; } | TYPENAME ':' { goto do_label; } ; for.init.statement: xexpr ';' { if ($1) cplus_expand_expr_stmt ($1); } | decl | '{' compstmtend ; /* Either a type-qualifier or nothing. First thing in an `asm' statement. */ maybe_type_qual: /* empty */ { emit_line_note (input_filename, lineno); $$ = NULL_TREE; } | TYPE_QUAL { emit_line_note (input_filename, lineno); } ; xexpr: /* empty */ { $$ = NULL_TREE; } | expr | error { $$ = NULL_TREE; } ; /* These are the operands other than the first string and colon in asm ("addextend %2,%1": "=dm" (x), "0" (y), "g" (*x)) */ asm_operands: /* empty */ { $$ = NULL_TREE; } | nonnull_asm_operands ; nonnull_asm_operands: asm_operand | nonnull_asm_operands ',' asm_operand { $$ = chainon ($$, $3); } ; asm_operand: STRING '(' expr ')' { $$ = build_tree_list ($$, $3); } ; asm_clobbers: STRING { $$ = tree_cons (NULL_TREE, $$, NULL_TREE); } | asm_clobbers ',' STRING { $$ = tree_cons (NULL_TREE, $3, $$); } ; /* This is what appears inside the parens in a function declarator. Its value is represented in the format that grokdeclarator expects. In C++, declaring a function with no parameters means that that function takes *no* parameters. */ parmlist: /* empty */ { if (strict_prototype) $$ = void_list_node; else $$ = NULL_TREE; } | complex_parmlist | type_id { $$ = tree_cons (NULL_TREE, $$, void_list_node); TREE_PARMLIST ($$) = 1; } ; /* This nonterminal does not include the common sequence '(' type_id ')', as it is ambiguous and must be disambiguated elsewhere. */ complex_parmlist: parms { $$ = chainon ($$, void_list_node); TREE_PARMLIST ($$) = 1; } | parms_comma ELLIPSIS { TREE_PARMLIST ($$) = 1; } /* C++ allows an ellipsis without a separating ',' */ | parms ELLIPSIS { TREE_PARMLIST ($$) = 1; } | type_id ELLIPSIS { $$ = build_tree_list (NULL_TREE, $$); TREE_PARMLIST ($$) = 1; } | ELLIPSIS { /* ARM $8.2.5 has this as a boxed-off comment. */ if (pedantic) warning ("use of `...' without a first argument is non-portable"); $$ = NULL_TREE; } | TYPENAME_ELLIPSIS { TREE_PARMLIST ($$) = 1; } | parms TYPENAME_ELLIPSIS { TREE_PARMLIST ($$) = 1; } | type_id TYPENAME_ELLIPSIS { $$ = build_tree_list (NULL_TREE, $$); TREE_PARMLIST ($$) = 1; } | parms ':' { /* This helps us recover from really nasty parse errors, for example, a missing right parenthesis. */ yyerror ("possibly missing ')'"); $$ = chainon ($$, void_list_node); TREE_PARMLIST ($$) = 1; yyungetc (':', 0); yychar = ')'; } | type_id ':' { /* This helps us recover from really nasty parse errors, for example, a missing right parenthesis. */ yyerror ("possibly missing ')'"); $$ = tree_cons (NULL_TREE, $$, void_list_node); TREE_PARMLIST ($$) = 1; yyungetc (':', 0); yychar = ')'; } ; /* A nonempty list of parameter declarations or type names. */ parms: named_parm { $$ = build_tree_list (NULL_TREE, $$); } | parm '=' init { $$ = build_tree_list ($3, $$); } | parms_comma full_parm { $$ = chainon ($$, $2); } | parms_comma bad_parm { $$ = chainon ($$, build_tree_list (NULL_TREE, $2)); } | parms_comma bad_parm '=' init { $$ = chainon ($$, build_tree_list ($4, $2)); } ; parms_comma: parms ',' | type_id ',' { $$ = build_tree_list (NULL_TREE, $$); } ; /* A single parameter declaration or parameter type name, as found in a parmlist. The first four cases make up for 10% of the time spent parsing C++. We cannot use them because of `int id[]' which won't get parsed properly. */ named_parm: /* typed_declspecs dont_see_typename '*' IDENTIFIER { tree specs = strip_attrs ($1); $$ = build_tree_list (specs, build_parse_node (INDIRECT_REF, $4)); see_typename (); } | typed_declspecs dont_see_typename '&' IDENTIFIER { tree specs = strip_attrs ($1); $$ = build_tree_list (specs, build_parse_node (ADDR_EXPR, $4)); see_typename (); } | TYPENAME IDENTIFIER { $$ = build_tree_list (get_decl_list ($$), $2); } | TYPESPEC IDENTIFIER { $$ = build_tree_list (get_decl_list ($$), $2); } | */ /* Here we expand typed_declspecs inline to avoid mis-parsing of TYPESPEC IDENTIFIER. */ typed_declspecs1 declarator { tree specs = strip_attrs ($1); $$ = build_tree_list (specs, $2); } | typed_typespecs declarator { $$ = build_tree_list ($$, $2); } | typespec declarator { $$ = build_tree_list (get_decl_list ($$), $2); } | typed_declspecs1 absdcl { tree specs = strip_attrs ($1); $$ = build_tree_list (specs, $2); } | typed_declspecs1 %prec EMPTY { tree specs = strip_attrs ($1); $$ = build_tree_list (specs, NULL_TREE); } | declmods notype_declarator { tree specs = strip_attrs ($1); $$ = build_tree_list (specs, $2); } ; full_parm: parm maybe_init { $$ = build_tree_list ($2, $$); } ; parm: named_parm | type_id ; see_typename: %prec EMPTY { see_typename (); } ; /* dont_see_typename: %prec EMPTY { dont_see_typename (); } ; try_for_typename: { if ($-1 == error_mark_node) $$ = 0; else { $$ = 1; pushclass ($-1, 1); } } ; */ bad_parm: /* empty */ %prec EMPTY { error ("type specifier omitted for parameter"); $$ = build_tree_list (integer_type_node, NULL_TREE); } | notype_declarator { error ("type specifier omitted for parameter"); $$ = build_tree_list (integer_type_node, $$); } ; exception_specification_opt: %prec EMPTY /* empty */ { $$ = NULL_TREE; } | THROW '(' ansi_raise_identifiers ')' %prec EMPTY { $$ = $3; } | THROW LEFT_RIGHT %prec EMPTY { $$ = build_decl_list (NULL_TREE, NULL_TREE); } ; ansi_raise_identifier: type_id { $$ = build_decl_list (NULL_TREE, groktypename($$)); } ; ansi_raise_identifiers: ansi_raise_identifier | ansi_raise_identifiers ',' ansi_raise_identifier { TREE_CHAIN ($3) = $$; $$ = $3; } ; conversion_declarator: /* empty */ %prec EMPTY { $$ = NULL_TREE; } | '*' type_quals conversion_declarator { $$ = make_pointer_declarator ($2, $3); } | '&' type_quals conversion_declarator { $$ = make_reference_declarator ($2, $3); } | ptr_to_mem type_quals conversion_declarator { tree arg = make_pointer_declarator ($2, $3); $$ = build_parse_node (SCOPE_REF, $1, arg); } ; operator: OPERATOR { got_scope = NULL_TREE; } ; operator_name: operator '*' { $$ = ansi_opname[MULT_EXPR]; } | operator '/' { $$ = ansi_opname[TRUNC_DIV_EXPR]; } | operator '%' { $$ = ansi_opname[TRUNC_MOD_EXPR]; } | operator '+' { $$ = ansi_opname[PLUS_EXPR]; } | operator '-' { $$ = ansi_opname[MINUS_EXPR]; } | operator '&' { $$ = ansi_opname[BIT_AND_EXPR]; } | operator '|' { $$ = ansi_opname[BIT_IOR_EXPR]; } | operator '^' { $$ = ansi_opname[BIT_XOR_EXPR]; } | operator '~' { $$ = ansi_opname[BIT_NOT_EXPR]; } | operator ',' { $$ = ansi_opname[COMPOUND_EXPR]; } | operator ARITHCOMPARE { $$ = ansi_opname[$2]; } | operator '<' { $$ = ansi_opname[LT_EXPR]; } | operator '>' { $$ = ansi_opname[GT_EXPR]; } | operator EQCOMPARE { $$ = ansi_opname[$2]; } | operator ASSIGN { $$ = ansi_assopname[$2]; } | operator '=' { $$ = ansi_opname [MODIFY_EXPR]; } | operator LSHIFT { $$ = ansi_opname[$2]; } | operator RSHIFT { $$ = ansi_opname[$2]; } | operator PLUSPLUS { $$ = ansi_opname[POSTINCREMENT_EXPR]; } | operator MINUSMINUS { $$ = ansi_opname[PREDECREMENT_EXPR]; } | operator ANDAND { $$ = ansi_opname[TRUTH_ANDIF_EXPR]; } | operator OROR { $$ = ansi_opname[TRUTH_ORIF_EXPR]; } | operator '!' { $$ = ansi_opname[TRUTH_NOT_EXPR]; } | operator '?' ':' { $$ = ansi_opname[COND_EXPR]; } | operator MIN_MAX { $$ = ansi_opname[$2]; } | operator POINTSAT %prec EMPTY { $$ = ansi_opname[COMPONENT_REF]; } | operator POINTSAT_STAR %prec EMPTY { $$ = ansi_opname[MEMBER_REF]; } | operator LEFT_RIGHT { $$ = ansi_opname[CALL_EXPR]; } | operator '[' ']' { $$ = ansi_opname[ARRAY_REF]; } | operator NEW %prec EMPTY { $$ = ansi_opname[NEW_EXPR]; } | operator DELETE %prec EMPTY { $$ = ansi_opname[DELETE_EXPR]; } | operator NEW '[' ']' { $$ = ansi_opname[VEC_NEW_EXPR]; } | operator DELETE '[' ']' { $$ = ansi_opname[VEC_DELETE_EXPR]; } /* Names here should be looked up in class scope ALSO. */ | operator type_specifier_seq conversion_declarator { $$ = grokoptypename ($2, $3); } | operator error { $$ = ansi_opname[ERROR_MARK]; } ; %% #ifdef SPEW_DEBUG const char * debug_yytranslate (value) int value; { return yytname[YYTRANSLATE (value)]; } #endif