diff options
author | Marc Espie <espie@cvs.openbsd.org> | 1999-05-26 13:38:57 +0000 |
---|---|---|
committer | Marc Espie <espie@cvs.openbsd.org> | 1999-05-26 13:38:57 +0000 |
commit | 0126e157b87f137fc08dc7f46f6c291b9d06ac5d (patch) | |
tree | f8555e3e504eb82b4cd3cba5cec20ae4ce8124ff /gnu/egcs/gcc/cp/parse.y | |
parent | ff8e9a4356e55ed142306c3a375fa280800abc86 (diff) |
egcs projects compiler system
Exact copy of the snapshot, except for the removal of
texinfo/
gcc/ch/
libchill/
Diffstat (limited to 'gnu/egcs/gcc/cp/parse.y')
-rw-r--r-- | gnu/egcs/gcc/cp/parse.y | 3806 |
1 files changed, 3806 insertions, 0 deletions
diff --git a/gnu/egcs/gcc/cp/parse.y b/gnu/egcs/gcc/cp/parse.y new file mode 100644 index 00000000000..677730ca336 --- /dev/null +++ b/gnu/egcs/gcc/cp/parse.y @@ -0,0 +1,3806 @@ +/* YACC parser for C++ syntax. + Copyright (C) 1988, 89, 93-98, 1999 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 "system.h" + +#include "tree.h" +#include "input.h" +#include "flags.h" +#include "lex.h" +#include "cp-tree.h" +#include "output.h" +#include "except.h" +#include "toplev.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; + +extern int end_of_file; + +/* 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 const char *cond_stmt_keyword; + +static tree empty_parms PROTO((void)); +static int parse_decl PROTO((tree, tree, tree, int, tree *)); + +/* Nonzero if we have an `extern "C"' acting as an extern specifier. */ +int have_extern_spec; +int used_extern_spec; + +/* Cons up an empty parameter list. */ +#ifdef __GNUC__ +__inline +#endif +static tree +empty_parms () +{ + tree parms; + + if (strict_prototype + || current_class_type != NULL) + parms = void_list_node; + else + parms = NULL_TREE; + return parms; +} + +%} + +%start program + +%union {long itype; tree ttype; char *strtype; enum tree_code code; flagged_type_tree ftype; } + +/* 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 +%token SELFNAME + +/* A template function. */ +%token PFUNCNAME + +/* 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 CV_QUALIFIER + +/* 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_KEYWORD GOTO ASM_KEYWORD TYPEOF ALIGNOF +%token SIGOF +%token ATTRIBUTE EXTENSION LABEL +%token REALPART IMAGPART + +/* the reserved words... C++ extensions */ +%token <ttype> AGGR +%token <ttype> VISSPEC +%token DELETE NEW 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 <itype> 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 PFUNCNAME TYPENAME SELFNAME PTYPENAME SCSPEC TYPESPEC CV_QUALIFIER ENUM AGGR ELLIPSIS TYPEOF SIGOF OPERATOR NSNAME TYPENAME_KEYWORD + +%left '{' ',' ';' + +%nonassoc THROW +%right <code> ':' +%right <code> ASSIGN '=' +%right <code> '?' +%left <code> OROR +%left <code> ANDAND +%left <code> '|' +%left <code> '^' +%left <code> '&' +%left <code> MIN_MAX +%left <code> EQCOMPARE +%left <code> ARITHCOMPARE '<' '>' +%left <code> LSHIFT RSHIFT +%left <code> '+' '-' +%left <code> '*' '/' '%' +%left <code> POINTSAT_STAR DOT_STAR +%right <code> UNARY PLUSPLUS MINUSMINUS '~' +%left HYPERUNARY +%left <ttype> PAREN_STAR_PAREN LEFT_RIGHT +%left <code> POINTSAT '.' '(' '[' + +%right SCOPE /* C++ extension */ +%nonassoc NEW DELETE TRY CATCH + +%type <code> unop + +%type <ttype> identifier IDENTIFIER TYPENAME CONSTANT expr nonnull_exprlist +%type <ttype> PFUNCNAME maybe_identifier +%type <ttype> paren_expr_or_null nontrivial_exprlist SELFNAME +%type <ttype> expr_no_commas cast_expr unary_expr primary string STRING +%type <ttype> reserved_declspecs boolean.literal +%type <ttype> reserved_typespecquals +%type <ttype> declmods +%type <ttype> SCSPEC TYPESPEC CV_QUALIFIER maybe_cv_qualifier +%type <itype> initdecls notype_initdecls initdcl /* C++ modification */ +%type <ttype> init initlist maybeasm maybe_init defarg defarg1 +%type <ttype> asm_operands nonnull_asm_operands asm_operand asm_clobbers +%type <ttype> maybe_attribute attributes attribute attribute_list attrib +%type <ttype> any_word + +%type <ttype> compstmt implicitly_scoped_stmt + +%type <ttype> declarator notype_declarator after_type_declarator +%type <ttype> notype_declarator_intern absdcl_intern +%type <ttype> after_type_declarator_intern +%type <ttype> direct_notype_declarator direct_after_type_declarator +%type <itype> components notype_components +%type <ttype> component_decl component_decl_1 +%type <ttype> component_declarator component_declarator0 +%type <ttype> notype_component_declarator notype_component_declarator0 +%type <ttype> after_type_component_declarator after_type_component_declarator0 +%type <ttype> enumlist enumerator +%type <ttype> absdcl cv_qualifiers +%type <ttype> direct_abstract_declarator conversion_declarator +%type <ttype> new_declarator direct_new_declarator +%type <ttype> xexpr parmlist parms bad_parm +%type <ttype> identifiers_or_typenames +%type <ttype> fcast_or_absdcl regcast_or_absdcl +%type <ttype> expr_or_declarator expr_or_declarator_intern +%type <ttype> complex_notype_declarator +%type <ttype> notype_unqualified_id unqualified_id qualified_id +%type <ttype> template_id do_id object_template_id notype_template_declarator +%type <ttype> overqualified_id notype_qualified_id any_id +%type <ttype> complex_direct_notype_declarator functional_cast +%type <ttype> complex_parmlist parms_comma +%type <ttype> namespace_qualifier namespace_using_decl + +%type <ftype> type_id new_type_id typed_typespecs typespec typed_declspecs +%type <ftype> typed_declspecs1 type_specifier_seq nonempty_cv_qualifiers +%type <ftype> structsp typespecqual_reserved parm named_parm full_parm + +/* C++ extensions */ +%token <ttype> PTYPENAME +%token <ttype> PRE_PARSED_FUNCTION_DECL EXTERN_LANG_STRING ALL +%token <ttype> PRE_PARSED_CLASS_DECL DEFARG DEFARG_MARKER +%type <ttype> component_constructor_declarator +%type <ttype> fn.def2 return_id fn.defpen constructor_declarator +%type <itype> ctor_initializer_opt function_try_block +%type <ttype> named_class_head_sans_basetype +%type <ftype> class_head named_class_head +%type <ftype> named_complex_class_head_sans_basetype +%type <ttype> unnamed_class_head +%type <ttype> base_class_list +%type <ttype> base_class_access_list +%type <ttype> base_class maybe_base_class_list base_class.1 +%type <ttype> exception_specification_opt ansi_raise_identifier ansi_raise_identifiers +%type <ttype> operator_name +%type <ttype> object aggr +%type <itype> new delete .begin_new_placement +/* %type <ttype> primary_no_id */ +%type <ttype> nonmomentary_expr maybe_parmlist +%type <itype> initdcl0 notype_initdcl0 member_init_list initdcl0_innards +%type <ttype> template_header template_parm_list template_parm +%type <ttype> template_type_parm template_template_parm +%type <code> template_close_bracket +%type <ttype> apparent_template_type +%type <ttype> template_type template_arg_list template_arg_list_opt +%type <ttype> template_arg +%type <ttype> condition xcond paren_cond_or_null +%type <ttype> type_name nested_name_specifier nested_type ptr_to_mem +%type <ttype> complete_type_name notype_identifier nonnested_type +%type <ttype> complex_type_name nested_name_specifier_1 +%type <ttype> new_initializer new_placement +%type <ttype> using_decl +%type <ttype> typename_sub typename_sub0 typename_sub1 typename_sub2 +%type <ttype> explicit_template_type +/* in order to recognize aggr tags as defining and thus shadowing. */ +%token TYPENAME_DEFN IDENTIFIER_DEFN PTYPENAME_DEFN +%type <ttype> named_class_head_sans_basetype_defn +%type <ttype> identifier_defn IDENTIFIER_DEFN TYPENAME_DEFN PTYPENAME_DEFN + +%type <ttype> self_template_type .finish_template_type + +%token NSNAME +%type <ttype> NSNAME + +/* Used in lex.c for parsing pragmas. */ +%token END_OF_LINE + +/* lex.c and pt.c depend 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 kind of the most recent one + being defined. (For example, this might be class_type_node.) */ +static tree current_aggr; + +/* When defining an enumeration, this is the type of the enumeration. */ +static tree current_enum_type; + +/* 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 PROTO((FILE *, int, YYSTYPE)); +extern tree combine_strings PROTO((tree)); + +static int +parse_decl(declarator, specs_attrs, attributes, initialized, decl) + tree declarator; + tree specs_attrs; + tree attributes; + int initialized; + tree* decl; +{ + int sm; + + split_specs_attrs (specs_attrs, ¤t_declspecs, &prefix_attributes); + if (current_declspecs + && TREE_CODE (current_declspecs) != TREE_LIST) + current_declspecs = build_decl_list (NULL_TREE, 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; + } + sm = suspend_momentary (); + *decl = start_decl (declarator, current_declspecs, initialized, + attributes, prefix_attributes); + return sm; +} +%} + +%% +program: + /* empty */ + | extdefs + { finish_translation_unit (); } + ; + +/* 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: + { $<ttype>$ = NULL_TREE; } + lang_extdef + { $<ttype>$ = NULL_TREE; } + | extdefs lang_extdef + { $<ttype>$ = NULL_TREE; } + ; + +extdefs_opt: + extdefs + | /* empty */ + ; + +.hush_warning: + { have_extern_spec = 1; + used_extern_spec = 0; + $<ttype>$ = NULL_TREE; } + ; +.warning_ok: + { have_extern_spec = 0; } + ; + +extension: + EXTENSION + { $<itype>$ = pedantic; + pedantic = 0; } + ; + +asm_keyword: + 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 eat_saved_input + { if (pending_inlines) do_pending_inlines (); } + | datadef + { if (pending_inlines) do_pending_inlines (); } + | template_def + { if (pending_inlines) do_pending_inlines (); } + | 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 eat_saved_input + { 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_alias + | using_decl ';' + { do_toplevel_using_decl ($1); } + | using_directive + | extension extdef + { pedantic = $<itype>1; } + ; + +namespace_alias: + NAMESPACE identifier '=' + { begin_only_namespace_names (); } + any_id ';' + { + end_only_namespace_names (); + if (lastiddecl) + $5 = lastiddecl; + do_namespace_alias ($2, $5); + } + ; + +using_decl: + USING qualified_id + { $$ = $2; } + | USING global_scope qualified_id + { $$ = $3; } + | USING global_scope unqualified_id + { $$ = $3; } + ; + +namespace_using_decl: + USING namespace_qualifier identifier + { $$ = build_parse_node (SCOPE_REF, $2, $3); } + | USING global_scope identifier + { $$ = build_parse_node (SCOPE_REF, global_namespace, $3); } + | USING global_scope namespace_qualifier identifier + { $$ = build_parse_node (SCOPE_REF, $3, $4); } + ; + +using_directive: + USING NAMESPACE + { begin_only_namespace_names (); } + any_id ';' + { + end_only_namespace_names (); + /* If no declaration was found, the using-directive is + invalid. Since that was not reported, we need the + identifier for the error message. */ + if (TREE_CODE ($4) == IDENTIFIER_NODE && lastiddecl) + $4 = lastiddecl; + do_using_directive ($4); + } + ; + +namespace_qualifier: + NSNAME SCOPE + { + if (TREE_CODE ($$) == IDENTIFIER_NODE) + $$ = lastiddecl; + got_scope = $$; + } + | namespace_qualifier NSNAME SCOPE + { + $$ = $2; + if (TREE_CODE ($$) == IDENTIFIER_NODE) + $$ = lastiddecl; + got_scope = $$; + } + +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 '<' '>' + { begin_specialization(); + $$ = NULL_TREE; } + ; + +template_parm_list: + template_parm + { $$ = process_template_parm (NULL_TREE, $1); } + | template_parm_list ',' template_parm + { $$ = process_template_parm ($1, $3); } + ; + +maybe_identifier: + identifier + { $$ = $1; } + | /* empty */ + { $$ = NULL_TREE; } + +template_type_parm: + aggr maybe_identifier + { $$ = finish_template_type_parm ($1, $2); } + | TYPENAME_KEYWORD maybe_identifier + { $$ = finish_template_type_parm (class_type_node, $2); } + ; + +template_template_parm: + template_header aggr maybe_identifier + { $$ = finish_template_template_parm ($2, $3); } + ; + +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, $1); } + | template_type_parm '=' type_id + { $$ = build_tree_list (groktypename ($3.t), $1); } + | parm + { $$ = build_tree_list (NULL_TREE, $1.t); } + | parm '=' expr_no_commas %prec ARITHCOMPARE + { $$ = build_tree_list ($3, $1.t); } + | template_template_parm + { $$ = build_tree_list (NULL_TREE, $1); } + | template_template_parm '=' template_arg + { + if (TREE_CODE ($3) != TEMPLATE_DECL + && TREE_CODE ($3) != TEMPLATE_TEMPLATE_PARM + && TREE_CODE ($3) != TYPE_DECL) + { + error ("invalid default template argument"); + $3 = error_mark_node; + } + $$ = build_tree_list ($3, $1); + } + ; + +template_def: + template_header template_extdef + { finish_template_decl ($1); } + | template_header error %prec EMPTY + { finish_template_decl ($1); } + ; + +template_extdef: + fndef eat_saved_input + { if (pending_inlines) do_pending_inlines (); } + | template_datadef + { if (pending_inlines) do_pending_inlines (); } + | template_def + { if (pending_inlines) do_pending_inlines (); } + | extern_lang_string .hush_warning fndef .warning_ok eat_saved_input + { if (pending_inlines) do_pending_inlines (); + pop_lang_context (); } + | extern_lang_string .hush_warning template_datadef .warning_ok + { if (pending_inlines) do_pending_inlines (); + pop_lang_context (); } + | extension template_extdef + { pedantic = $<itype>1; } + ; + +template_datadef: + nomods_initdecls ';' + | declmods notype_initdecls ';' + {} + | typed_declspecs initdecls ';' + { note_list_got_semicolon ($1.t); } + | structsp ';' + { maybe_process_partial_specialization ($1.t); + note_got_semicolon ($1.t); } + ; + +datadef: + nomods_initdecls ';' + | declmods notype_initdecls ';' + {} + | typed_declspecs initdecls ';' + { note_list_got_semicolon ($1.t); } + | declmods ';' + { pedwarn ("empty declaration"); } + | explicit_instantiation ';' + | typed_declspecs ';' + { + tree t, attrs; + split_specs_attrs ($1.t, &t, &attrs); + shadow_tag (t); + note_list_got_semicolon ($1.t); + } + | 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); } + | fn.def1 maybe_return_init function_try_block + { + int nested = (hack_decl_function_context + (current_function_decl) != NULL_TREE); + finish_function (lineno, (int)$3, nested); + } + | fn.def1 maybe_return_init error + { } + ; + +constructor_declarator: + nested_name_specifier SELFNAME '(' + { $$ = begin_constructor_declarator ($1, $2); } + parmlist ')' cv_qualifiers exception_specification_opt + { $$ = make_call_declarator ($<ttype>4, $5, $7, $8); } + | nested_name_specifier SELFNAME LEFT_RIGHT cv_qualifiers exception_specification_opt + { $$ = begin_constructor_declarator ($1, $2); + $$ = make_call_declarator ($$, empty_parms (), $4, $5); + } + | global_scope nested_name_specifier SELFNAME '(' + { $$ = begin_constructor_declarator ($2, $3); } + parmlist ')' cv_qualifiers exception_specification_opt + { $$ = make_call_declarator ($<ttype>5, $6, $8, $9); } + | global_scope nested_name_specifier SELFNAME LEFT_RIGHT cv_qualifiers exception_specification_opt + { $$ = begin_constructor_declarator ($2, $3); + $$ = make_call_declarator ($$, empty_parms (), $5, $6); + } + | nested_name_specifier self_template_type '(' + { $$ = begin_constructor_declarator ($1, $2); } + parmlist ')' cv_qualifiers exception_specification_opt + { $$ = make_call_declarator ($<ttype>4, $5, $7, $8); } + | nested_name_specifier self_template_type LEFT_RIGHT cv_qualifiers exception_specification_opt + { $$ = begin_constructor_declarator ($1, $2); + $$ = make_call_declarator ($$, empty_parms (), $4, $5); + } + | global_scope nested_name_specifier self_template_type '(' + { $$ = begin_constructor_declarator ($2, $3); } + parmlist ')' cv_qualifiers exception_specification_opt + { $$ = make_call_declarator ($<ttype>5, $6, $8, $9); } + | global_scope nested_name_specifier self_template_type LEFT_RIGHT cv_qualifiers exception_specification_opt + { $$ = begin_constructor_declarator ($2, $3); + $$ = make_call_declarator ($$, empty_parms (), $5, $6); + } + ; + +fn.def1: + typed_declspecs declarator + { if (!begin_function_definition ($1.t, $2)) + YYERROR1; } + | declmods notype_declarator + { if (!begin_function_definition ($1, $2)) + YYERROR1; } + | notype_declarator + { if (!begin_function_definition (NULL_TREE, $1)) + YYERROR1; } + | declmods constructor_declarator + { if (!begin_function_definition ($1, $2)) + YYERROR1; } + | constructor_declarator + { if (!begin_function_definition (NULL_TREE, $1)) + YYERROR1; } + ; + +component_constructor_declarator: + SELFNAME '(' parmlist ')' cv_qualifiers exception_specification_opt + { $$ = make_call_declarator ($1, $3, $5, $6); } + | SELFNAME LEFT_RIGHT cv_qualifiers exception_specification_opt + { $$ = make_call_declarator ($1, empty_parms (), $3, $4); } + | self_template_type '(' parmlist ')' cv_qualifiers exception_specification_opt + { $$ = make_call_declarator ($1, $3, $5, $6); } + | self_template_type LEFT_RIGHT cv_qualifiers exception_specification_opt + { $$ = make_call_declarator ($1, empty_parms (), $3, $4); } + ; + +/* more C++ complexity. See component_decl for a comment on the + reduce/reduce conflict introduced by these rules. */ +fn.def2: + declmods component_constructor_declarator + { tree specs, attrs; + split_specs_attrs ($1, &specs, &attrs); + attrs = build_tree_list (attrs, NULL_TREE); + $$ = start_method (specs, $2, attrs); + rest_of_mdef: + if (! $$) + YYERROR1; + if (yychar == YYEMPTY) + yychar = YYLEX; + reinit_parse_for_method (yychar, $$); } + | component_constructor_declarator + { $$ = start_method (NULL_TREE, $1, NULL_TREE); + goto rest_of_mdef; } + | typed_declspecs declarator + { tree specs, attrs; + split_specs_attrs ($1.t, &specs, &attrs); + attrs = build_tree_list (attrs, NULL_TREE); + $$ = start_method (specs, $2, attrs); goto rest_of_mdef; } + | declmods notype_declarator + { tree specs, attrs; + split_specs_attrs ($1, &specs, &attrs); + attrs = build_tree_list (attrs, NULL_TREE); + $$ = start_method (specs, $2, attrs); goto rest_of_mdef; } + | notype_declarator + { $$ = start_method (NULL_TREE, $$, NULL_TREE); + goto rest_of_mdef; } + | declmods constructor_declarator + { tree specs, attrs; + split_specs_attrs ($1, &specs, &attrs); + attrs = build_tree_list (attrs, NULL_TREE); + $$ = start_method (specs, $2, attrs); goto rest_of_mdef; } + | constructor_declarator + { $$ = start_method (NULL_TREE, $$, NULL_TREE); + goto rest_of_mdef; } + ; + +return_id: + RETURN_KEYWORD IDENTIFIER + { + if (! current_function_parms_stored) + store_parm_decls (); + $$ = $2; + } + ; + +return_init: + return_id maybe_init + { store_return_init ($<ttype>$, $2); } + | return_id '(' nonnull_exprlist ')' + { store_return_init ($<ttype>$, $3); } + | return_id LEFT_RIGHT + { store_return_init ($<ttype>$, 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) + pedwarn ("anachronistic old style base class initializer"); + expand_member_init (current_class_ref, NULL_TREE, $2); + } + | LEFT_RIGHT + { + if (current_class_name) + pedwarn ("anachronistic old style base class initializer"); + expand_member_init (current_class_ref, NULL_TREE, void_type_node); + } + | notype_identifier '(' nonnull_exprlist ')' + { expand_member_init (current_class_ref, $1, $3); } + | notype_identifier LEFT_RIGHT + { expand_member_init (current_class_ref, $1, void_type_node); } + | nonnested_type '(' nonnull_exprlist ')' + { expand_member_init (current_class_ref, $1, $3); } + | nonnested_type LEFT_RIGHT + { expand_member_init (current_class_ref, $1, void_type_node); } + | typename_sub '(' nonnull_exprlist ')' + { expand_member_init (current_class_ref, TYPE_MAIN_DECL ($1), + $3); } + | typename_sub LEFT_RIGHT + { expand_member_init (current_class_ref, TYPE_MAIN_DECL ($1), + void_type_node); } + ; + +identifier: + IDENTIFIER + | TYPENAME + | SELFNAME + | PTYPENAME + | NSNAME + ; + +notype_identifier: + IDENTIFIER + | PTYPENAME + | NSNAME %prec EMPTY + ; + +identifier_defn: + IDENTIFIER_DEFN + | TYPENAME_DEFN + | PTYPENAME_DEFN + ; + +explicit_instantiation: + TEMPLATE begin_explicit_instantiation typespec ';' + { do_type_instantiation ($3.t, NULL_TREE); + yyungetc (';', 1); } + end_explicit_instantiation + | TEMPLATE begin_explicit_instantiation typed_declspecs declarator + { tree specs = strip_attrs ($3.t); + do_decl_instantiation (specs, $4, NULL_TREE); } + end_explicit_instantiation + | TEMPLATE begin_explicit_instantiation notype_declarator + { do_decl_instantiation (NULL_TREE, $3, NULL_TREE); } + end_explicit_instantiation + | TEMPLATE begin_explicit_instantiation constructor_declarator + { do_decl_instantiation (NULL_TREE, $3, NULL_TREE); } + end_explicit_instantiation + | SCSPEC TEMPLATE begin_explicit_instantiation typespec ';' + { do_type_instantiation ($4.t, $1); + yyungetc (';', 1); } + end_explicit_instantiation + | SCSPEC TEMPLATE begin_explicit_instantiation typed_declspecs + declarator + { tree specs = strip_attrs ($4.t); + do_decl_instantiation (specs, $5, $1); } + end_explicit_instantiation + | SCSPEC TEMPLATE begin_explicit_instantiation notype_declarator + { do_decl_instantiation (NULL_TREE, $4, $1); } + end_explicit_instantiation + | SCSPEC TEMPLATE begin_explicit_instantiation constructor_declarator + { do_decl_instantiation (NULL_TREE, $4, $1); } + end_explicit_instantiation + ; + +begin_explicit_instantiation: + { begin_explicit_instantiation(); } + +end_explicit_instantiation: + { end_explicit_instantiation(); } + +/* The TYPENAME expansions are to deal with use of a template class name as + a template within the class itself, where the template decl is hidden by + a type decl. Got all that? */ + +template_type: + PTYPENAME '<' template_arg_list_opt template_close_bracket + .finish_template_type + { $$ = $5; } + | TYPENAME '<' template_arg_list_opt template_close_bracket + .finish_template_type + { $$ = $5; } + | self_template_type + ; + +apparent_template_type: + template_type + | identifier '<' template_arg_list_opt '>' + .finish_template_type + { $$ = $5; } + +self_template_type: + SELFNAME '<' template_arg_list_opt template_close_bracket + .finish_template_type + { $$ = $5; } + ; + +.finish_template_type: + { + if (yychar == YYEMPTY) + yychar = YYLEX; + + $$ = finish_template_type ($<ttype>-3, $<ttype>-1, + yychar == SCOPE); + } + +template_close_bracket: + '>' + | RSHIFT + { + /* Handle `Class<Class<Type>>' without space in the `>>' */ + pedwarn ("`>>' should be `> >' in template class name"); + yyungetc ('>', 1); + } + ; + +template_arg_list_opt: + /* empty */ + { $$ = NULL_TREE; } + | template_arg_list + ; + +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 ($1.t); } + | PTYPENAME + { $$ = lastiddecl; } + | expr_no_commas %prec ARITHCOMPARE + ; + +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 ')' + { $$ = $2; } + ; + +paren_cond_or_null: + LEFT_RIGHT + { error ("ANSI C++ forbids an empty condition for `%s'", + cond_stmt_keyword); + $$ = integer_zero_node; } + | '(' condition ')' + { $$ = $2; } + ; + +xcond: + /* empty */ + { $$ = NULL_TREE; } + | condition + | error + { $$ = NULL_TREE; } + ; + +condition: + type_specifier_seq declarator 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.t; + $<itype>5 = suspend_momentary (); + $<ttype>$ = start_decl ($<ttype>2, current_declspecs, 1, + $4, /*prefix_attributes*/ NULL_TREE); + } + init + { + cp_finish_decl ($<ttype>6, $7, $4, 1, LOOKUP_ONLYCONVERTING); + resume_momentary ($<itype>5); + $$ = convert_from_reference ($<ttype>6); + 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: + '{' + { $<ttype>$ = begin_compound_stmt (1); } + compstmtend + { finish_compound_stmt (1, $<ttype>2); } + | simple_stmt + ; + + +nontrivial_exprlist: + expr_no_commas ',' expr_no_commas + { $$ = expr_tree_cons (NULL_TREE, $$, + build_expr_list (NULL_TREE, $3)); } + | expr_no_commas ',' error + { $$ = expr_tree_cons (NULL_TREE, $$, + build_expr_list (NULL_TREE, error_mark_node)); } + | nontrivial_exprlist ',' expr_no_commas + { chainon ($$, build_expr_list (NULL_TREE, $3)); } + | nontrivial_exprlist ',' error + { chainon ($$, build_expr_list (NULL_TREE, error_mark_node)); } + ; + +nonnull_exprlist: + expr_no_commas + { $$ = build_expr_list (NULL_TREE, $$); } + | nontrivial_exprlist + ; + +unary_expr: + primary %prec UNARY + { $$ = $1; } + /* __extension__ turns off -pedantic for following primary. */ + | extension cast_expr %prec UNARY + { $$ = $2; + pedantic = $<itype>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 + { $$ = finish_unary_op_expr ($1, $2); } + /* Refer to the address of a label as a pointer. */ + | ANDAND identifier + { if (pedantic) + pedwarn ("ANSI C++ forbids `&&'"); + $$ = finish_label_address_expr ($2); } + | SIZEOF unary_expr %prec UNARY + { $$ = expr_sizeof ($2); } + | SIZEOF '(' type_id ')' %prec HYPERUNARY + { $$ = c_sizeof (groktypename ($3.t)); + check_for_new_type ("sizeof", $3); } + | ALIGNOF unary_expr %prec UNARY + { $$ = grok_alignof ($2); } + | ALIGNOF '(' type_id ')' %prec HYPERUNARY + { $$ = c_alignof (groktypename ($3.t)); + check_for_new_type ("alignof", $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.t, NULL_TREE, $1); + check_for_new_type ("new", $2); } + | new new_type_id new_initializer + { $$ = build_new (NULL_TREE, $2.t, $3, $1); + check_for_new_type ("new", $2); } + | new new_placement new_type_id %prec EMPTY + { $$ = build_new ($2, $3.t, NULL_TREE, $1); + check_for_new_type ("new", $3); } + | new new_placement new_type_id new_initializer + { $$ = build_new ($2, $3.t, $4, $1); + check_for_new_type ("new", $3); } + /* The .begin_new_placement in the following rules is + necessary to avoid shift/reduce conflicts that lead to + mis-parsing some expressions. Of course, these constructs + are not really new-placement and it is bogus to call + begin_new_placement. But, the parser cannot always tell at this + point whether the next thing is an expression or a type-id, + so there is nothing we can do. Fortunately, + begin_new_placement does nothing harmful. When we rewrite + the parser, this lossage should be removed, of course. */ + | new '(' .begin_new_placement type_id .finish_new_placement + %prec EMPTY + { $$ = build_new (NULL_TREE, groktypename($4.t), + NULL_TREE, $1); + check_for_new_type ("new", $4); } + | new '(' .begin_new_placement type_id .finish_new_placement + new_initializer + { $$ = build_new (NULL_TREE, groktypename($4.t), $6, $1); + check_for_new_type ("new", $4); } + | new new_placement '(' .begin_new_placement type_id + .finish_new_placement %prec EMPTY + { $$ = build_new ($2, groktypename($5.t), NULL_TREE, $1); + check_for_new_type ("new", $5); } + | new new_placement '(' .begin_new_placement type_id + .finish_new_placement new_initializer + { $$ = build_new ($2, groktypename($5.t), $7, $1); + check_for_new_type ("new", $5); } + + | 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; } + | REALPART cast_expr %prec UNARY + { $$ = build_x_unary_op (REALPART_EXPR, $2); } + | IMAGPART cast_expr %prec UNARY + { $$ = build_x_unary_op (IMAGPART_EXPR, $2); } + ; + + /* Note this rule is not suitable for use in new_placement + since it uses NULL_TREE as the argument to + finish_new_placement. This rule serves only to avoid + reduce/reduce conflicts in unary_expr. See the comments + there on the use of begin/finish_new_placement. */ +.finish_new_placement: + ')' + { finish_new_placement (NULL_TREE, $<itype>-1); } + +.begin_new_placement: + { $$ = begin_new_placement (); } + +new_placement: + '(' .begin_new_placement nonnull_exprlist ')' + { $$ = finish_new_placement ($3, $2); } + | '{' .begin_new_placement nonnull_exprlist '}' + { cp_pedwarn ("old style placement syntax, use () instead"); + $$ = finish_new_placement ($3, $2); } + ; + +new_initializer: + '(' nonnull_exprlist ')' + { $$ = $2; } + | LEFT_RIGHT + { $$ = NULL_TREE; } + | '(' typespec ')' + { + cp_error ("`%T' is not a valid expression", $2.t); + $$ = 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 `='"); + if (TREE_CODE ($2) != TREE_LIST + && TREE_CODE ($2) != CONSTRUCTOR) + $$ = build_expr_list (NULL_TREE, $2); + else + $$ = $2; + } + ; + +/* This is necessary to postpone reduction of `int ((int)(int)(int))'. */ +regcast_or_absdcl: + '(' type_id ')' %prec EMPTY + { $2.t = finish_parmlist (build_tree_list (NULL_TREE, $2.t), 0); + $$ = make_call_declarator (NULL_TREE, $2.t, NULL_TREE, NULL_TREE); + check_for_new_type ("cast", $2); } + | regcast_or_absdcl '(' type_id ')' %prec EMPTY + { $3.t = finish_parmlist (build_tree_list (NULL_TREE, $3.t), 0); + $$ = make_call_declarator ($$, $3.t, NULL_TREE, NULL_TREE); + check_for_new_type ("cast", $3); } + ; + +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_x_modify_expr ($$, NOP_EXPR, $3); + if ($$ != error_mark_node) + C_SET_EXP_ORIGINAL_CODE ($$, MODIFY_EXPR); } + | expr_no_commas ASSIGN expr_no_commas + { $$ = build_x_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.t); + $$ = build_m_component_ref ($$, build_c_cast (type, $5)); } + | object primary_no_id %prec UNARY + { $$ = build_m_component_ref ($$, $2); } +*/ + ; + +notype_unqualified_id: + '~' see_typename identifier + { $$ = build_parse_node (BIT_NOT_EXPR, $3); } + | '~' see_typename template_type + { $$ = build_parse_node (BIT_NOT_EXPR, $3); } + | template_id + | operator_name + | IDENTIFIER + | PTYPENAME + | NSNAME %prec EMPTY + ; + +do_id: + { + /* If lastiddecl is a TREE_LIST, it's a baselink, which + means that we're in an expression like S::f<int>, so + don't do_identifier; we only do that for unqualified + identifiers. */ + if (lastiddecl && TREE_CODE (lastiddecl) != TREE_LIST) + $$ = do_identifier ($<ttype>-1, 1, NULL_TREE); + else + $$ = $<ttype>-1; + } + +template_id: + PFUNCNAME '<' do_id template_arg_list_opt template_close_bracket + { $$ = lookup_template_function ($3, $4); } + | operator_name '<' do_id template_arg_list_opt template_close_bracket + { $$ = lookup_template_function ($3, $4); } + ; + +object_template_id: + TEMPLATE identifier '<' template_arg_list_opt template_close_bracket + { $$ = lookup_template_function ($2, $4); } + | TEMPLATE PFUNCNAME '<' template_arg_list_opt template_close_bracket + { $$ = lookup_template_function ($2, $4); } + | TEMPLATE operator_name '<' template_arg_list_opt + template_close_bracket + { $$ = lookup_template_function ($2, $4); } + ; + +unqualified_id: + notype_unqualified_id + | TYPENAME + | SELFNAME + ; + +expr_or_declarator_intern: + expr_or_declarator + | attributes expr_or_declarator + { + /* Provide support for '(' attributes '*' declarator ')' + etc */ + $$ = decl_tree_cons ($1, $2, NULL_TREE); + } + ; + +expr_or_declarator: + notype_unqualified_id + | '*' expr_or_declarator_intern %prec UNARY + { $$ = build_parse_node (INDIRECT_REF, $2); } + | '&' expr_or_declarator_intern %prec UNARY + { $$ = build_parse_node (ADDR_EXPR, $2); } + | '(' expr_or_declarator_intern ')' + { $$ = $2; } + ; + +notype_template_declarator: + IDENTIFIER '<' template_arg_list_opt template_close_bracket + { $$ = lookup_template_function ($1, $3); } + | NSNAME '<' template_arg_list template_close_bracket + { $$ = lookup_template_function ($1, $3); } + ; + +direct_notype_declarator: + complex_direct_notype_declarator + /* This precedence declaration is to prefer this reduce + to the Koenig lookup shift in primary, below. I hate yacc. */ + | notype_unqualified_id %prec '(' + | notype_template_declarator + | '(' expr_or_declarator_intern ')' + { $$ = finish_decl_parsing ($2); } + ; + +primary: + notype_unqualified_id + { + if (TREE_CODE ($1) == BIT_NOT_EXPR) + $$ = build_x_unary_op (BIT_NOT_EXPR, TREE_OPERAND ($1, 0)); + else + $$ = finish_id_expr ($1); + } + | CONSTANT + | boolean.literal + | string + { + if (processing_template_decl) + push_obstacks (&permanent_obstack, &permanent_obstack); + $$ = combine_strings ($$); + /* combine_strings doesn't set up TYPE_MAIN_VARIANT of + a const array the way we want, so fix it. */ + if (flag_const_strings) + TREE_TYPE ($$) = build_cplus_array_type + (TREE_TYPE (TREE_TYPE ($$)), + TYPE_DOMAIN (TREE_TYPE ($$))); + if (processing_template_decl) + pop_obstacks (); + } + | '(' expr ')' + { $$ = finish_parenthesized_expr ($2); } + | '(' expr_or_declarator_intern ')' + { $2 = reparse_decl_as_expr (NULL_TREE, $2); + $$ = finish_parenthesized_expr ($2); } + | '(' error ')' + { $$ = error_mark_node; } + | '(' + { tree scope = current_scope (); + if (!scope || TREE_CODE (scope) != FUNCTION_DECL) + { + error ("braced-group within expression allowed only inside a function"); + YYERROR; + } + if (pedantic) + pedwarn ("ANSI C++ forbids braced-groups within expressions"); + $<ttype>$ = begin_stmt_expr (); + } + compstmt ')' + { $$ = finish_stmt_expr ($<ttype>2, $3); } + /* Koenig lookup support + We could store lastiddecl in $1 to avoid another lookup, + but that would result in many additional reduce/reduce conflicts. */ + | notype_unqualified_id '(' nonnull_exprlist ')' + { $$ = finish_call_expr ($1, $3, 1); } + | notype_unqualified_id LEFT_RIGHT + { $$ = finish_call_expr ($1, NULL_TREE, 1); } + | primary '(' nonnull_exprlist ')' + { $$ = finish_call_expr ($1, $3, 0); } + | primary LEFT_RIGHT + { $$ = finish_call_expr ($1, NULL_TREE, 0); } + | primary '[' expr ']' + { $$ = grok_array_decl ($$, $3); } + | primary PLUSPLUS + { $$ = finish_increment_expr ($1, POSTINCREMENT_EXPR); } + | primary MINUSMINUS + { $$ = finish_increment_expr ($1, POSTDECREMENT_EXPR); } + /* C++ extensions */ + | THIS + { $$ = finish_this_expr (); } + | CV_QUALIFIER '(' nonnull_exprlist ')' + { + /* This is a C cast in C++'s `functional' notation + using the "implicit int" extension so that: + `const (3)' is equivalent to `const int (3)'. */ + tree type; + + if ($3 == error_mark_node) + { + $$ = error_mark_node; + break; + } + + type = cp_build_qualified_type (integer_type_node, + cp_type_qual_from_rid ($1)); + $$ = build_c_cast (type, build_compound_expr ($3)); + } + | functional_cast + | DYNAMIC_CAST '<' type_id '>' '(' expr ')' + { tree type = groktypename ($3.t); + check_for_new_type ("dynamic_cast", $3); + $$ = build_dynamic_cast (type, $6); } + | STATIC_CAST '<' type_id '>' '(' expr ')' + { tree type = groktypename ($3.t); + check_for_new_type ("static_cast", $3); + $$ = build_static_cast (type, $6); } + | REINTERPRET_CAST '<' type_id '>' '(' expr ')' + { tree type = groktypename ($3.t); + check_for_new_type ("reinterpret_cast", $3); + $$ = build_reinterpret_cast (type, $6); } + | CONST_CAST '<' type_id '>' '(' expr ')' + { tree type = groktypename ($3.t); + check_for_new_type ("const_cast", $3); + $$ = build_const_cast (type, $6); } + | TYPEID '(' expr ')' + { $$ = build_x_typeid ($3); } + | TYPEID '(' type_id ')' + { tree type = groktypename ($3.t); + check_for_new_type ("typeid", $3); + $$ = get_typeid (TYPE_MAIN_VARIANT (type)); } + | global_scope IDENTIFIER + { $$ = do_scoped_id ($2, 1); } + | global_scope template_id + { $$ = $2; } + | global_scope operator_name + { + got_scope = NULL_TREE; + if (TREE_CODE ($2) == IDENTIFIER_NODE) + $$ = do_scoped_id ($2, 1); + else + $$ = $2; + } + | overqualified_id %prec HYPERUNARY + { $$ = build_offset_ref (OP0 ($$), OP1 ($$)); } + | overqualified_id '(' nonnull_exprlist ')' + { $$ = finish_qualified_call_expr ($1, $3); } + | overqualified_id LEFT_RIGHT + { $$ = finish_qualified_call_expr ($1, NULL_TREE); } + | object object_template_id %prec UNARY + { + $$ = build_x_component_ref ($$, $2, NULL_TREE, 1); + } + | object object_template_id '(' nonnull_exprlist ')' + { $$ = finish_object_call_expr ($2, $1, $4); } + | object object_template_id LEFT_RIGHT + { $$ = finish_object_call_expr ($2, $1, NULL_TREE); } + | object unqualified_id %prec UNARY + { $$ = build_x_component_ref ($$, $2, NULL_TREE, 1); } + | object overqualified_id %prec UNARY + { if (processing_template_decl) + $$ = build_min_nt (COMPONENT_REF, $1, copy_to_permanent ($2)); + else + $$ = build_object_ref ($$, OP0 ($2), OP1 ($2)); } + | object unqualified_id '(' nonnull_exprlist ')' + { $$ = finish_object_call_expr ($2, $1, $4); } + | object unqualified_id LEFT_RIGHT + { $$ = finish_object_call_expr ($2, $1, NULL_TREE); } + | object overqualified_id '(' nonnull_exprlist ')' + { $$ = finish_qualified_object_call_expr ($2, $1, $4); } + | object overqualified_id LEFT_RIGHT + { $$ = finish_qualified_object_call_expr ($2, $1, NULL_TREE); } + /* p->int::~int() is valid -- 12.4 */ + | object '~' TYPESPEC LEFT_RIGHT + { $$ = finish_pseudo_destructor_call_expr ($1, NULL_TREE, $3); } + | object TYPESPEC SCOPE '~' TYPESPEC LEFT_RIGHT + { $$ = finish_pseudo_destructor_call_expr ($1, $2, $5); } + | object error + { + $$ = 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; + } + $<ttype>$ = expand_start_stmt_expr (); } + compstmt ')' + { if (pedantic) + pedwarn ("ANSI C++ forbids braced-groups within expressions"); + $$ = expand_end_stmt_expr ($<ttype>2); } + | primary_no_id '(' nonnull_exprlist ')' + { $$ = build_x_function_call ($$, $3, current_class_ref); } + | primary_no_id LEFT_RIGHT + { $$ = build_x_function_call ($$, NULL_TREE, current_class_ref); } + | 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: + typespec initdecls ';' + { + resume_momentary ($2); + if ($1.t && IS_AGGR_TYPE_CODE (TREE_CODE ($1.t))) + note_got_semicolon ($1.t); + } + | typed_declspecs initdecls ';' + { + resume_momentary ($2); + note_list_got_semicolon ($1.t); + } + | declmods notype_initdecls ';' + { resume_momentary ($2); } + | typed_declspecs ';' + { + shadow_tag ($1.t); + note_list_got_semicolon ($1.t); + } + | declmods ';' + { warning ("empty declaration"); } + | extension decl + { pedantic = $<itype>1; } + ; + +/* 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 + { $$ = make_call_declarator (NULL_TREE, empty_parms (), + NULL_TREE, NULL_TREE); } + | fcast_or_absdcl LEFT_RIGHT %prec EMPTY + { $$ = make_call_declarator ($$, empty_parms (), NULL_TREE, + NULL_TREE); } + ; + +/* ANSI type-id (8.1) */ +type_id: + typed_typespecs absdcl + { $$.t = build_decl_list ($1.t, $2); + $$.new_type_flag = $1.new_type_flag; } + | nonempty_cv_qualifiers absdcl + { $$.t = build_decl_list ($1.t, $2); + $$.new_type_flag = $1.new_type_flag; } + | typespec absdcl + { $$.t = build_decl_list (build_decl_list (NULL_TREE, $1.t), + $2); + $$.new_type_flag = $1.new_type_flag; } + | typed_typespecs %prec EMPTY + { $$.t = build_decl_list ($1.t, NULL_TREE); + $$.new_type_flag = $1.new_type_flag; } + | nonempty_cv_qualifiers %prec EMPTY + { $$.t = build_decl_list ($1.t, NULL_TREE); + $$.new_type_flag = $1.new_type_flag; } + ; + +/* 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 + { $$.t = decl_tree_cons (NULL_TREE, $2.t, $1); + $$.new_type_flag = $2.new_type_flag; } + | typespec reserved_declspecs %prec HYPERUNARY + { $$.t = decl_tree_cons (NULL_TREE, $1.t, $2); + $$.new_type_flag = $1.new_type_flag; } + | typespec reserved_typespecquals reserved_declspecs + { $$.t = decl_tree_cons (NULL_TREE, $1.t, chainon ($2, $3)); + $$.new_type_flag = $1.new_type_flag; } + | declmods typespec reserved_declspecs + { $$.t = decl_tree_cons (NULL_TREE, $2.t, chainon ($3, $1)); + $$.new_type_flag = $2.new_type_flag; } + | declmods typespec reserved_typespecquals + { $$.t = decl_tree_cons (NULL_TREE, $2.t, chainon ($3, $1)); + $$.new_type_flag = $2.new_type_flag; } + | declmods typespec reserved_typespecquals reserved_declspecs + { $$.t = decl_tree_cons (NULL_TREE, $2.t, + chainon ($3, chainon ($4, $1))); + $$.new_type_flag = $2.new_type_flag; } + ; + +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.t, $$); } + | 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. */ + +/* We use hash_tree_cons for lists of typeless declspecs so that they end + up on a persistent obstack. Otherwise, they could appear at the + beginning of something like + + static const struct { int foo () { } } b; + + and would be discarded after we finish compiling foo. We don't need to + worry once we see a type. */ + +declmods: + nonempty_cv_qualifiers %prec EMPTY + { $$ = $1.t; TREE_STATIC ($$) = 1; } + | SCSPEC + { $$ = hash_tree_cons (NULL_TREE, $$, NULL_TREE); } + | declmods CV_QUALIFIER + { $$ = hash_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)); + $$ = hash_tree_cons (NULL_TREE, $2, $$); + TREE_STATIC ($$) = TREE_STATIC ($1); } + | declmods attributes + { $$ = hash_tree_cons ($2, NULL_TREE, $1); } + | attributes %prec EMPTY + { $$ = hash_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 + { $$.t = build_decl_list (NULL_TREE, $1.t); + $$.new_type_flag = $1.new_type_flag; } + | nonempty_cv_qualifiers typespec + { $$.t = decl_tree_cons (NULL_TREE, $2.t, $1.t); + $$.new_type_flag = $2.new_type_flag; } + | typespec reserved_typespecquals + { $$.t = decl_tree_cons (NULL_TREE, $1.t, $2); + $$.new_type_flag = $1.new_type_flag; } + | nonempty_cv_qualifiers typespec reserved_typespecquals + { $$.t = decl_tree_cons (NULL_TREE, $2.t, chainon ($3, $1.t)); + $$.new_type_flag = $1.new_type_flag; } + ; + +reserved_typespecquals: + typespecqual_reserved + { $$ = build_decl_list (NULL_TREE, $1.t); } + | reserved_typespecquals typespecqual_reserved + { $$ = decl_tree_cons (NULL_TREE, $2.t, $1); } + ; + +/* 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 + { $$.t = $1; $$.new_type_flag = 0; } + | complete_type_name + { $$.t = $1; $$.new_type_flag = 0; } + | TYPEOF '(' expr ')' + { $$.t = finish_typeof ($3); + $$.new_type_flag = 0; } + | TYPEOF '(' type_id ')' + { $$.t = groktypename ($3.t); + $$.new_type_flag = 0; } + | SIGOF '(' expr ')' + { tree type = TREE_TYPE ($3); + + $$.new_type_flag = 0; + if (IS_AGGR_TYPE (type)) + { + sorry ("sigof type specifier"); + $$.t = type; + } + else + { + error ("`sigof' applied to non-aggregate expression"); + $$.t = error_mark_node; + } + } + | SIGOF '(' type_id ')' + { tree type = groktypename ($3.t); + + $$.new_type_flag = 0; + if (IS_AGGR_TYPE (type)) + { + sorry ("sigof type specifier"); + $$.t = type; + } + else + { + error("`sigof' applied to non-aggregate type"); + $$.t = error_mark_node; + } + } + ; + +/* A typespec that is a reserved word, or a type qualifier. */ + +typespecqual_reserved: + TYPESPEC + { $$.t = $1; $$.new_type_flag = 0; } + | CV_QUALIFIER + { $$.t = $1; $$.new_type_flag = 0; } + | structsp + ; + +initdecls: + initdcl0 + | initdecls ',' initdcl + { check_multiple_declarators (); } + ; + +notype_initdecls: + notype_initdcl0 + | notype_initdecls ',' initdcl + { check_multiple_declarators (); } + ; + +nomods_initdecls: + nomods_initdcl0 + | nomods_initdecls ',' initdcl + { check_multiple_declarators (); } + ; + +maybeasm: + /* empty */ + { $$ = NULL_TREE; } + | asm_keyword '(' string ')' + { if (TREE_CHAIN ($3)) $3 = combine_strings ($3); $$ = $3; } + ; + +initdcl: + declarator maybeasm maybe_attribute '=' + { $<ttype>$ = start_decl ($<ttype>1, current_declspecs, 1, + $3, prefix_attributes); } + init +/* Note how the declaration of the variable is in effect while its init is parsed! */ + { cp_finish_decl ($<ttype>5, $6, $2, 1, LOOKUP_ONLYCONVERTING); } + | declarator maybeasm maybe_attribute + { $<ttype>$ = start_decl ($<ttype>1, current_declspecs, 0, + $3, prefix_attributes); + cp_finish_decl ($<ttype>$, NULL_TREE, $2, 1, 0); } + ; + + /* This rule assumes a certain configuration of the parser stack. + In particular, $0, the element directly before the beginning of + this rule on the stack, must be a maybeasm. $-1 must be a + declarator or notype_declarator. And $-2 must be some declmods + or declspecs. We can't move the maybeasm into this rule because + we need that reduce so we prefer fn.def1 when appropriate. */ +initdcl0_innards: + maybe_attribute '=' + { $<itype>2 = parse_decl ($<ttype>-1, $<ttype>-2, + $1, 1, &$<ttype>$); } + /* Note how the declaration of the variable is in effect + while its init is parsed! */ + init + { cp_finish_decl ($<ttype>3, $4, $<ttype>0, 1, + LOOKUP_ONLYCONVERTING); + $$ = $<itype>2; } + | maybe_attribute + { tree d; + $$ = parse_decl ($<ttype>-1, $<ttype>-2, $1, 0, &d); + cp_finish_decl (d, NULL_TREE, $<ttype>0, 1, 0); } + ; + +initdcl0: + declarator maybeasm initdcl0_innards + { $$ = $3; } + +notype_initdcl0: + notype_declarator maybeasm initdcl0_innards + { $$ = $3; } + ; + +nomods_initdcl0: + notype_declarator maybeasm + { /* Set things up as initdcl0_innards expects. */ + $<ttype>2 = $1; + $1 = NULL_TREE; } + initdcl0_innards + {} + | constructor_declarator maybeasm maybe_attribute + { tree d; + parse_decl($1, NULL_TREE, $3, 0, &d); + cp_finish_decl (d, NULL_TREE, $2, 1, 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 + | CV_QUALIFIER + ; + +/* 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: + /* empty */ %prec EMPTY + { $$ = NULL_TREE; } + | '=' init + { $$ = $2; } + +/* If we are processing a template, we don't want to expand this + initializer yet. */ + +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 + { $$ = expr_tree_cons (NULL_TREE, $3, $$); } + /* These are for labeled elements. */ + | '[' expr_no_commas ']' init + { $$ = build_expr_list ($2, $4); } + | identifier ':' init + { $$ = build_expr_list ($$, $3); } + | initlist ',' identifier ':' init + { $$ = expr_tree_cons ($3, $5, $$); } + ; + +fn.defpen: + PRE_PARSED_FUNCTION_DECL + { start_function (NULL_TREE, TREE_VALUE ($1), + NULL_TREE, 2); + reinit_parse_for_function (); } + +pending_inline: + fn.defpen maybe_return_init ctor_initializer_opt compstmt_or_error + { + int nested = (hack_decl_function_context + (current_function_decl) != NULL_TREE); + finish_function (lineno, (int)$3 | 2, nested); + process_next_inline ($1); + } + | fn.defpen maybe_return_init function_try_block + { + int nested = (hack_decl_function_context + (current_function_decl) != NULL_TREE); + finish_function (lineno, (int)$3 | 2, nested); + process_next_inline ($1); + } + | fn.defpen maybe_return_init error + { process_next_inline ($1); } + ; + +pending_inlines: + /* empty */ + | pending_inlines pending_inline eat_saved_input + ; + +/* A regurgitated default argument. The value of DEFARG_MARKER will be + the TREE_LIST node for the parameter in question. */ +defarg_again: + DEFARG_MARKER expr_no_commas END_OF_SAVED_INPUT + { replace_defarg ($1, $2); } + | DEFARG_MARKER error END_OF_SAVED_INPUT + { replace_defarg ($1, error_mark_node); } + +pending_defargs: + /* empty */ %prec EMPTY + | pending_defargs defarg_again + { do_pending_defargs (); } + | pending_defargs error + { do_pending_defargs (); } + ; + +structsp: + ENUM identifier '{' + { $<itype>3 = suspend_momentary (); + $<ttype>$ = current_enum_type; + current_enum_type = start_enum ($2); } + enumlist maybecomma_warn '}' + { TYPE_VALUES (current_enum_type) = $5; + $$.t = finish_enum (current_enum_type); + $$.new_type_flag = 1; + current_enum_type = $<ttype>4; + resume_momentary ((int) $<itype>3); + check_for_missing_semicolon ($$.t); } + | ENUM identifier '{' '}' + { $$.t = finish_enum (start_enum ($2)); + $$.new_type_flag = 1; + check_for_missing_semicolon ($$.t); } + | ENUM '{' + { $<itype>2 = suspend_momentary (); + $<ttype>$ = current_enum_type; + current_enum_type = start_enum (make_anon_name ()); } + enumlist maybecomma_warn '}' + { TYPE_VALUES (current_enum_type) = $4; + $$.t = finish_enum (current_enum_type); + $$.new_type_flag = 1; + current_enum_type = $<ttype>3; + resume_momentary ((int) $<itype>1); + check_for_missing_semicolon ($$.t); } + | ENUM '{' '}' + { $$.t = finish_enum (start_enum (make_anon_name())); + $$.new_type_flag = 1; + check_for_missing_semicolon ($$.t); } + | ENUM identifier + { $$.t = xref_tag (enum_type_node, $2, 1); + $$.new_type_flag = 0; } + | ENUM complex_type_name + { $$.t = xref_tag (enum_type_node, $2, 1); + $$.new_type_flag = 0; } + | TYPENAME_KEYWORD typename_sub + { $$.t = $2; + $$.new_type_flag = 0; + if (!processing_template_decl) + cp_pedwarn ("using `typename' outside of template"); } + /* C++ extensions, merged with C to avoid shift/reduce conflicts */ + | class_head '{' + { $1.t = begin_class_definition ($1.t); } + opt.component_decl_list '}' maybe_attribute + { + int semi; + + if (yychar == YYEMPTY) + yychar = YYLEX; + semi = yychar == ';'; + + $<ttype>$ = finish_class_definition ($1.t, $6, semi, + $1.new_type_flag); + } + pending_defargs + { + begin_inline_definitions (); + } + pending_inlines + { + finish_inline_definitions (); + $$.t = $<ttype>7; + $$.new_type_flag = 1; + } + | class_head %prec EMPTY + { + if ($1.new_type_flag) + pop_scope (CP_DECL_CONTEXT (TYPE_MAIN_DECL ($1.t))); + $$.new_type_flag = 0; + if (TYPE_BINFO ($1.t) == NULL_TREE) + { + cp_error ("%T is not a class type", $1.t); + $$.t = error_mark_node; + } + else + { + $$.t = $1.t; + /* struct B: public A; is not accepted by the WP grammar. */ + if (TYPE_BINFO_BASETYPES ($$.t) && !TYPE_SIZE ($$.t) + && ! TYPE_BEING_DEFINED ($$.t)) + cp_error ("base clause without member specification for `%#T'", + $$.t); + } + } + ; + +maybecomma: + /* empty */ + | ',' + ; + +maybecomma_warn: + /* empty */ + | ',' + { if (pedantic && !in_system_header) + 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 CV_QUALIFIER + { 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"); } + | aggr attributes + { $$ = build_decl_list ($2, $1); } + ; + +named_class_head_sans_basetype: + aggr identifier + { + current_aggr = $1; + $$ = $2; + } + ; + +named_class_head_sans_basetype_defn: + aggr identifier_defn %prec EMPTY + { current_aggr = $$; $$ = $2; } + | named_class_head_sans_basetype '{' + { yyungetc ('{', 1); } + | named_class_head_sans_basetype ':' + { yyungetc (':', 1); } + ; + +named_complex_class_head_sans_basetype: + aggr nested_name_specifier identifier + { + current_aggr = $1; + $$.t = handle_class_head ($1, $2, $3); + $$.new_type_flag = 1; + } + | aggr global_scope nested_name_specifier identifier + { + current_aggr = $1; + $$.t = handle_class_head ($1, $3, $4); + $$.new_type_flag = 1; + } + | aggr global_scope identifier + { + current_aggr = $1; + $$.t = handle_class_head ($1, NULL_TREE, $3); + $$.new_type_flag = 1; + } + | aggr apparent_template_type + { + current_aggr = $1; + $$.t = $2; + $$.new_type_flag = 0; + } + | aggr nested_name_specifier apparent_template_type + { + current_aggr = $1; + $$.t = $3; + if (CP_DECL_CONTEXT ($$.t)) + push_scope (CP_DECL_CONTEXT ($$.t)); + $$.new_type_flag = 1; + } + ; + +named_class_head: + named_class_head_sans_basetype %prec EMPTY + { + $$.t = xref_tag (current_aggr, $1, 1); + $$.new_type_flag = 0; + } + | named_class_head_sans_basetype_defn + { $<ttype>$ = xref_tag (current_aggr, $1, 0); } + /* Class name is unqualified, so we look for base classes + in the current scope. */ + maybe_base_class_list %prec EMPTY + { + $$.t = $<ttype>2; + $$.new_type_flag = 0; + if ($3) + xref_basetypes (current_aggr, $1, $<ttype>2, $3); + } + | named_complex_class_head_sans_basetype + maybe_base_class_list + { + if ($1.t != error_mark_node) + { + $$.t = TREE_TYPE ($1.t); + $$.new_type_flag = $1.new_type_flag; + if (current_aggr == union_type_node + && TREE_CODE ($$.t) != UNION_TYPE) + cp_pedwarn ("`union' tag used in declaring `%#T'", + $$.t); + else if (TREE_CODE ($$.t) == UNION_TYPE + && current_aggr != union_type_node) + cp_pedwarn ("non-`union' tag used in declaring `%#T'", $$); + else if (TREE_CODE ($$.t) == RECORD_TYPE) + /* We might be specializing a template with a different + class-key; deal. */ + CLASSTYPE_DECLARED_CLASS ($$.t) + = (current_aggr == class_type_node); + if ($2) + { + maybe_process_partial_specialization ($$.t); + xref_basetypes (current_aggr, $1.t, $$.t, $2); + } + } + } + ; + +unnamed_class_head: + aggr '{' + { $$ = xref_tag ($$, make_anon_name (), 0); + yyungetc ('{', 1); } + ; + +/* The tree output of this nonterminal a declarationf or the type + named. If NEW_TYPE_FLAG is set, then the name used in this + class-head was explicitly qualified, e.g.: `struct X::Y'. We have + already called push_scope for X. */ +class_head: + unnamed_class_head + { + $$.t = $1; + $$.new_type_flag = 0; + } + | named_class_head + ; + +maybe_base_class_list: + /* empty */ %prec 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 + { $$ = finish_base_specifier (access_default_node, $1, + current_aggr + == signature_type_node); } + | base_class_access_list see_typename base_class.1 + { $$ = finish_base_specifier ($1, $3, + current_aggr + == signature_type_node); } + ; + +base_class.1: + typename_sub + { if ($$ != error_mark_node) $$ = TYPE_MAIN_DECL ($1); } + | nonnested_type + | SIGOF '(' expr ')' + { + if (current_aggr == signature_type_node) + { + if (IS_AGGR_TYPE (TREE_TYPE ($3))) + { + sorry ("`sigof' as base signature specifier"); + $$ = TREE_TYPE ($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.t))) + { + sorry ("`sigof' as base signature specifier"); + $$ = groktypename ($3.t); + } + 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 ($1 != ridpointers[(int)RID_VIRTUAL]) + cp_error ("`%D' access", $1); + $$ = access_default_virtual_node; } + | base_class_access_list VISSPEC see_typename + { + if ($1 != access_default_virtual_node) + error ("multiple access specifiers"); + else if ($2 == access_public_node) + $$ = access_public_virtual_node; + else if ($2 == access_protected_node) + $$ = access_protected_virtual_node; + else /* $2 == access_private_node */ + $$ = access_private_virtual_node; + } + | base_class_access_list SCSPEC see_typename + { if ($2 != ridpointers[(int)RID_VIRTUAL]) + cp_error ("`%D' access", $2); + else if ($$ == access_public_node) + $$ = access_public_virtual_node; + else if ($$ == access_protected_node) + $$ = access_protected_virtual_node; + else if ($$ == access_private_node) + $$ = access_private_virtual_node; + else + error ("multiple `virtual' specifiers"); + } + ; + +opt.component_decl_list: + | component_decl_list + | opt.component_decl_list access_specifier component_decl_list + | opt.component_decl_list access_specifier + ; + +access_specifier: + VISSPEC ':' + { + if (current_aggr == signature_type_node) + { + error ("access specifier not allowed in signature"); + $1 = access_public_node; + } + + current_access_specifier = $1; + } + ; + +/* 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 + { + finish_member_declaration ($1); + } + | component_decl_list component_decl + { + finish_member_declaration ($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_KEYWORD /* base_init compstmt */ + { $$ = finish_method ($$); } + | fn.def2 '{' /* nodecls compstmt */ + { $$ = finish_method ($$); } + | ';' + { $$ = NULL_TREE; } + | extension component_decl + { $$ = $2; + pedantic = $<itype>1; } + | template_header component_decl + { + if ($2) + $$ = finish_member_template_decl ($2); + else + /* The component was already processed. */ + $$ = NULL_TREE; + + finish_template_decl ($1); + } + | template_header typed_declspecs ';' + { + $$ = finish_member_class_template ($2.t); + finish_template_decl ($1); + } + ; + +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 + { + /* Most of the productions for component_decl only + allow the creation of one new member, so we call + finish_member_declaration in component_decl_list. + For this rule and the next, however, there can be + more than one member, e.g.: + + int i, j; + + and we need the first member to be fully + registered before the second is processed. + Therefore, the rules for components take care of + this processing. To avoid registering the + components more than once, we send NULL_TREE up + here; that lets finish_member_declaration know + that there is nothing to do. */ + if (!$2) + grok_x_components ($1.t); + $$ = NULL_TREE; + } + | declmods notype_components + { + if (!$2) + grok_x_components ($1); + $$ = NULL_TREE; + } + | notype_declarator maybeasm maybe_attribute maybe_init + { $$ = grokfield ($$, NULL_TREE, $4, $2, + build_tree_list ($3, NULL_TREE)); } + | constructor_declarator maybeasm maybe_attribute maybe_init + { $$ = grokfield ($$, NULL_TREE, $4, $2, + build_tree_list ($3, 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? */ + | declmods component_constructor_declarator maybeasm maybe_attribute maybe_init + { tree specs, attrs; + split_specs_attrs ($1, &specs, &attrs); + $$ = grokfield ($2, specs, $5, $3, + build_tree_list ($4, attrs)); } + | component_constructor_declarator maybeasm maybe_attribute maybe_init + { $$ = grokfield ($$, NULL_TREE, $4, $2, + build_tree_list ($3, NULL_TREE)); } + | using_decl + { $$ = do_class_using_decl ($1); } + +/* The case of exactly one component is handled directly by component_decl. */ +/* ??? Huh? ^^^ */ +components: + /* empty: possibly anonymous */ + { $$ = 0; } + | component_declarator0 + { + if (PROCESSING_REAL_TEMPLATE_DECL_P ()) + $1 = finish_member_template_decl ($1); + finish_member_declaration ($1); + $$ = 1; + } + | components ',' component_declarator + { + check_multiple_declarators (); + if (PROCESSING_REAL_TEMPLATE_DECL_P ()) + $3 = finish_member_template_decl ($3); + finish_member_declaration ($3); + $$ = 2; + } + ; + +notype_components: + /* empty: possibly anonymous */ + { $$ = 0; } + | notype_component_declarator0 + { + if (PROCESSING_REAL_TEMPLATE_DECL_P ()) + $1 = finish_member_template_decl ($1); + finish_member_declaration ($1); + $$ = 1; + } + | notype_components ',' notype_component_declarator + { + check_multiple_declarators (); + if (PROCESSING_REAL_TEMPLATE_DECL_P ()) + $3 = finish_member_template_decl ($3); + finish_member_declaration ($3); + $$ = 2; + } + ; + +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 maybeasm maybe_attribute maybe_init + { split_specs_attrs ($<ttype>0, ¤t_declspecs, + &prefix_attributes); + $<ttype>0 = current_declspecs; + $$ = grokfield ($$, current_declspecs, $4, $2, + build_tree_list ($3, prefix_attributes)); } + | TYPENAME ':' expr_no_commas maybe_attribute + { split_specs_attrs ($<ttype>0, ¤t_declspecs, + &prefix_attributes); + $<ttype>0 = current_declspecs; + $$ = grokbitfield ($$, current_declspecs, $3); + cplus_decl_attributes ($$, $4, prefix_attributes); } + ; + +notype_component_declarator0: + notype_declarator maybeasm maybe_attribute maybe_init + { split_specs_attrs ($<ttype>0, ¤t_declspecs, + &prefix_attributes); + $<ttype>0 = current_declspecs; + $$ = grokfield ($$, current_declspecs, $4, $2, + build_tree_list ($3, prefix_attributes)); } + | constructor_declarator maybeasm maybe_attribute maybe_init + { split_specs_attrs ($<ttype>0, ¤t_declspecs, + &prefix_attributes); + $<ttype>0 = current_declspecs; + $$ = grokfield ($$, current_declspecs, $4, $2, + build_tree_list ($3, prefix_attributes)); } + | IDENTIFIER ':' expr_no_commas maybe_attribute + { split_specs_attrs ($<ttype>0, ¤t_declspecs, + &prefix_attributes); + $<ttype>0 = current_declspecs; + $$ = grokbitfield ($$, current_declspecs, $3); + cplus_decl_attributes ($$, $4, prefix_attributes); } + | ':' expr_no_commas maybe_attribute + { split_specs_attrs ($<ttype>0, ¤t_declspecs, + &prefix_attributes); + $<ttype>0 = current_declspecs; + $$ = grokbitfield (NULL_TREE, current_declspecs, $2); + cplus_decl_attributes ($$, $3, prefix_attributes); } + ; + +after_type_component_declarator: + after_type_declarator maybeasm maybe_attribute maybe_init + { $$ = grokfield ($$, current_declspecs, $4, $2, + build_tree_list ($3, prefix_attributes)); } + | TYPENAME ':' expr_no_commas maybe_attribute + { $$ = grokbitfield ($$, current_declspecs, $3); + cplus_decl_attributes ($$, $4, prefix_attributes); } + ; + +notype_component_declarator: + notype_declarator maybeasm maybe_attribute maybe_init + { $$ = grokfield ($$, current_declspecs, $4, $2, + build_tree_list ($3, 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, current_enum_type); } + | identifier '=' expr_no_commas + { $$ = build_enumerator ($$, $3, current_enum_type); } + ; + +/* ANSI new-type-id (5.3.4) */ +new_type_id: + type_specifier_seq new_declarator + { $$.t = build_decl_list ($1.t, $2); + $$.new_type_flag = $1.new_type_flag; } + | type_specifier_seq %prec EMPTY + { $$.t = build_decl_list ($1.t, NULL_TREE); + $$.new_type_flag = $1.new_type_flag; } + /* GNU extension to allow arrays of arbitrary types with + non-constant dimension. For the use of begin_new_placement + here, see the comments in unary_expr above. */ + | '(' .begin_new_placement type_id .finish_new_placement + '[' expr ']' + { + if (pedantic) + pedwarn ("ANSI C++ forbids array dimensions with parenthesized type in new"); + $$.t = build_parse_node (ARRAY_REF, TREE_VALUE ($3.t), $6); + $$.t = build_decl_list (TREE_PURPOSE ($3.t), $$.t); + $$.new_type_flag = $3.new_type_flag; + } + ; + +cv_qualifiers: + /* empty */ %prec EMPTY + { $$ = NULL_TREE; } + | cv_qualifiers CV_QUALIFIER + { $$ = decl_tree_cons (NULL_TREE, $2, $$); } + ; + +nonempty_cv_qualifiers: + CV_QUALIFIER + { $$.t = hash_tree_cons (NULL_TREE, $1, NULL_TREE); + $$.new_type_flag = 0; } + | nonempty_cv_qualifiers CV_QUALIFIER + { $$.t = hash_tree_cons (NULL_TREE, $2, $1.t); + $$.new_type_flag = $1.new_type_flag; } + ; + +/* These rules must follow the rules for function declarations + and component declarations. That way, longer rules are preferred. */ + +suspend_mom: + /* empty */ + { $<itype>$ = suspend_momentary (); } + +/* An expression which will not live on the momentary obstack. */ +nonmomentary_expr: + suspend_mom expr + { resume_momentary ((int) $<itype>1); $$ = $2; } + ; + +/* An expression which will not live on the momentary obstack. */ +maybe_parmlist: + suspend_mom '(' nonnull_exprlist ')' + { resume_momentary ((int) $<itype>1); $$ = $3; } + | suspend_mom '(' parmlist ')' + { resume_momentary ((int) $<itype>1); $$ = $3; } + | suspend_mom LEFT_RIGHT + { resume_momentary ((int) $<itype>1); $$ = empty_parms (); } + | suspend_mom '(' error ')' + { resume_momentary ((int) $<itype>1); $$ = NULL_TREE; } + ; + +/* A declarator that is allowed only after an explicit typespec. */ + +after_type_declarator_intern: + after_type_declarator + | attributes after_type_declarator + { + /* Provide support for '(' attributes '*' declarator ')' + etc */ + $$ = decl_tree_cons ($1, $2, NULL_TREE); + } + ; + +/* may all be followed by prec '.' */ +after_type_declarator: + '*' nonempty_cv_qualifiers after_type_declarator_intern %prec UNARY + { $$ = make_pointer_declarator ($2.t, $3); } + | '&' nonempty_cv_qualifiers after_type_declarator_intern %prec UNARY + { $$ = make_reference_declarator ($2.t, $3); } + | '*' after_type_declarator_intern %prec UNARY + { $$ = make_pointer_declarator (NULL_TREE, $2); } + | '&' after_type_declarator_intern %prec UNARY + { $$ = make_reference_declarator (NULL_TREE, $2); } + | ptr_to_mem cv_qualifiers after_type_declarator_intern + { tree arg = make_pointer_declarator ($2, $3); + $$ = build_parse_node (SCOPE_REF, $1, arg); + } + | direct_after_type_declarator + ; + +direct_after_type_declarator: + direct_after_type_declarator maybe_parmlist cv_qualifiers exception_specification_opt %prec '.' + { $$ = make_call_declarator ($$, $2, $3, $4); } + | 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_intern ')' + { $$ = $2; } + | nested_name_specifier type_name %prec EMPTY + { push_nested_class ($1, 3); + $$ = build_parse_node (SCOPE_REF, $$, $2); + TREE_COMPLEXITY ($$) = current_class_depth; } + | type_name %prec EMPTY + ; + +nonnested_type: + type_name %prec EMPTY + { + if (TREE_CODE ($1) == IDENTIFIER_NODE) + { + $$ = lookup_name ($1, 1); + maybe_note_name_used_in_class ($1, $$); + } + else + $$ = $1; + } + | global_scope type_name + { + if (TREE_CODE ($2) == IDENTIFIER_NODE) + $$ = IDENTIFIER_GLOBAL_VALUE ($2); + else + $$ = $2; + got_scope = NULL_TREE; + } + ; + +complete_type_name: + nonnested_type + | nested_type + | global_scope nested_type + { $$ = $2; } + ; + +nested_type: + nested_name_specifier type_name %prec EMPTY + { $$ = get_type_decl ($2); } + ; + +/* A declarator allowed whether or not there has been + an explicit typespec. These cannot redeclare a typedef-name. */ + +notype_declarator_intern: + notype_declarator + | attributes notype_declarator + { + /* Provide support for '(' attributes '*' declarator ')' + etc */ + $$ = decl_tree_cons ($1, $2, NULL_TREE); + } + ; + +notype_declarator: + '*' nonempty_cv_qualifiers notype_declarator_intern %prec UNARY + { $$ = make_pointer_declarator ($2.t, $3); } + | '&' nonempty_cv_qualifiers notype_declarator_intern %prec UNARY + { $$ = make_reference_declarator ($2.t, $3); } + | '*' notype_declarator_intern %prec UNARY + { $$ = make_pointer_declarator (NULL_TREE, $2); } + | '&' notype_declarator_intern %prec UNARY + { $$ = make_reference_declarator (NULL_TREE, $2); } + | ptr_to_mem cv_qualifiers notype_declarator_intern + { tree arg = make_pointer_declarator ($2, $3); + $$ = build_parse_node (SCOPE_REF, $1, arg); + } + | direct_notype_declarator + ; + +complex_notype_declarator: + '*' nonempty_cv_qualifiers notype_declarator_intern %prec UNARY + { $$ = make_pointer_declarator ($2.t, $3); } + | '&' nonempty_cv_qualifiers notype_declarator_intern %prec UNARY + { $$ = make_reference_declarator ($2.t, $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 cv_qualifiers notype_declarator_intern + { 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 cv_qualifiers exception_specification_opt %prec '.' + { $$ = make_call_declarator ($$, $2, $3, $4); } + | '(' 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 + { enter_scope_of ($1); } + | nested_name_specifier notype_template_declarator + { got_scope = NULL_TREE; + $$ = build_parse_node (SCOPE_REF, $1, $2); + enter_scope_of ($$); + } + ; + +qualified_id: + nested_name_specifier unqualified_id + { got_scope = NULL_TREE; + $$ = build_parse_node (SCOPE_REF, $$, $2); } + | nested_name_specifier object_template_id + { got_scope = NULL_TREE; + $$ = build_parse_node (SCOPE_REF, $1, $2); } + ; + +notype_qualified_id: + nested_name_specifier notype_unqualified_id + { got_scope = NULL_TREE; + $$ = build_parse_node (SCOPE_REF, $$, $2); } + | nested_name_specifier object_template_id + { got_scope = NULL_TREE; + $$ = build_parse_node (SCOPE_REF, $1, $2); } + ; + +overqualified_id: + notype_qualified_id + | global_scope notype_qualified_id + { $$ = $2; } + ; + +functional_cast: + typespec '(' nonnull_exprlist ')' + { $$ = build_functional_cast ($1.t, $3); } + | typespec '(' expr_or_declarator_intern ')' + { $$ = reparse_decl_as_expr ($1.t, $3); } + | typespec fcast_or_absdcl %prec EMPTY + { $$ = reparse_absdcl_as_expr ($1.t, $2); } + ; +type_name: + TYPENAME + | SELFNAME + | template_type %prec EMPTY + ; + +nested_name_specifier: + nested_name_specifier_1 + | nested_name_specifier nested_name_specifier_1 + { $$ = $2; } + | nested_name_specifier TEMPLATE explicit_template_type SCOPE + { got_scope = $$ = make_typename_type ($1, $3); } + ; + +/* Why the @#$%^& do type_name and notype_identifier need to be expanded + inline here?!? (jason) */ +nested_name_specifier_1: + TYPENAME SCOPE + { + if (TREE_CODE ($1) == IDENTIFIER_NODE) + { + $$ = lastiddecl; + maybe_note_name_used_in_class ($1, $$); + } + got_scope = $$ = + complete_type (TYPE_MAIN_VARIANT (TREE_TYPE ($$))); + } + | SELFNAME SCOPE + { + if (TREE_CODE ($1) == IDENTIFIER_NODE) + $$ = lastiddecl; + got_scope = $$ = TREE_TYPE ($$); + } + | NSNAME SCOPE + { + if (TREE_CODE ($$) == IDENTIFIER_NODE) + $$ = lastiddecl; + got_scope = $$; + } + | template_type SCOPE + { got_scope = $$ = complete_type (TREE_TYPE ($1)); } +/* 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; } */ + ; + +typename_sub: + typename_sub0 + | global_scope typename_sub0 + { $$ = $2; } + ; + +typename_sub0: + typename_sub1 identifier %prec EMPTY + { + if (TREE_CODE_CLASS (TREE_CODE ($1)) == 't') + $$ = make_typename_type ($1, $2); + else if (TREE_CODE ($2) == IDENTIFIER_NODE) + cp_error ("`%T' is not a class or namespace", $2); + else + { + $$ = $2; + if (TREE_CODE ($$) == TYPE_DECL) + $$ = TREE_TYPE ($$); + } + } + | typename_sub1 template_type %prec EMPTY + { $$ = TREE_TYPE ($2); } + | typename_sub1 explicit_template_type %prec EMPTY + { $$ = make_typename_type ($1, $2); } + | typename_sub1 TEMPLATE explicit_template_type %prec EMPTY + { $$ = make_typename_type ($1, $3); } + ; + +typename_sub1: + typename_sub2 + { + if (TREE_CODE ($1) == IDENTIFIER_NODE) + cp_error ("`%T' is not a class or namespace", $1); + } + | typename_sub1 typename_sub2 + { + if (TREE_CODE_CLASS (TREE_CODE ($1)) == 't') + $$ = make_typename_type ($1, $2); + else if (TREE_CODE ($2) == IDENTIFIER_NODE) + cp_error ("`%T' is not a class or namespace", $2); + else + { + $$ = $2; + if (TREE_CODE ($$) == TYPE_DECL) + $$ = TREE_TYPE ($$); + } + } + | typename_sub1 explicit_template_type SCOPE + { got_scope = $$ = make_typename_type ($1, $2); } + | typename_sub1 TEMPLATE explicit_template_type SCOPE + { got_scope = $$ = make_typename_type ($1, $3); } + ; + +typename_sub2: + TYPENAME SCOPE + { + if (TREE_CODE ($1) != IDENTIFIER_NODE) + $1 = lastiddecl; + + /* Retrieve the type for the identifier, which might involve + some computation. */ + got_scope = $$ = complete_type (IDENTIFIER_TYPE_VALUE ($1)); + + if ($$ == error_mark_node) + cp_error ("`%T' is not a class or namespace", $1); + } + | SELFNAME SCOPE + { + if (TREE_CODE ($1) != IDENTIFIER_NODE) + $$ = lastiddecl; + got_scope = $$ = complete_type (TREE_TYPE ($$)); + } + | template_type SCOPE + { got_scope = $$ = complete_type (TREE_TYPE ($$)); } + | PTYPENAME SCOPE + | IDENTIFIER SCOPE + | NSNAME SCOPE + { + if (TREE_CODE ($$) == IDENTIFIER_NODE) + $$ = lastiddecl; + got_scope = $$; + } + ; + +explicit_template_type: + identifier '<' template_arg_list_opt template_close_bracket + { $$ = build_min_nt (TEMPLATE_ID_EXPR, $1, $3); } + ; + +complex_type_name: + global_scope type_name + { + if (TREE_CODE ($2) == IDENTIFIER_NODE) + $$ = IDENTIFIER_GLOBAL_VALUE ($2); + else + $$ = $2; + got_scope = NULL_TREE; + } + | nested_type + | global_scope nested_type + { $$ = $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: + '*' cv_qualifiers new_declarator + { $$ = make_pointer_declarator ($2, $3); } + | '*' cv_qualifiers %prec EMPTY + { $$ = make_pointer_declarator ($2, NULL_TREE); } + | '&' cv_qualifiers new_declarator %prec EMPTY + { $$ = make_reference_declarator ($2, $3); } + | '&' cv_qualifiers %prec EMPTY + { $$ = make_reference_declarator ($2, NULL_TREE); } + | ptr_to_mem cv_qualifiers %prec EMPTY + { tree arg = make_pointer_declarator ($2, NULL_TREE); + $$ = build_parse_node (SCOPE_REF, $1, arg); + } + | ptr_to_mem cv_qualifiers 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); } + ; + +absdcl_intern: + absdcl + | attributes absdcl + { + /* Provide support for '(' attributes '*' declarator ')' + etc */ + $$ = decl_tree_cons ($1, $2, NULL_TREE); + } + ; + +/* ANSI abstract-declarator (8.1) */ +absdcl: + '*' nonempty_cv_qualifiers absdcl_intern + { $$ = make_pointer_declarator ($2.t, $3); } + | '*' absdcl_intern + { $$ = make_pointer_declarator (NULL_TREE, $2); } + | '*' nonempty_cv_qualifiers %prec EMPTY + { $$ = make_pointer_declarator ($2.t, NULL_TREE); } + | '*' %prec EMPTY + { $$ = make_pointer_declarator (NULL_TREE, NULL_TREE); } + | '&' nonempty_cv_qualifiers absdcl_intern + { $$ = make_reference_declarator ($2.t, $3); } + | '&' absdcl_intern + { $$ = make_reference_declarator (NULL_TREE, $2); } + | '&' nonempty_cv_qualifiers %prec EMPTY + { $$ = make_reference_declarator ($2.t, NULL_TREE); } + | '&' %prec EMPTY + { $$ = make_reference_declarator (NULL_TREE, NULL_TREE); } + | ptr_to_mem cv_qualifiers %prec EMPTY + { tree arg = make_pointer_declarator ($2, NULL_TREE); + $$ = build_parse_node (SCOPE_REF, $1, arg); + } + | ptr_to_mem cv_qualifiers absdcl_intern + { 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_intern ')' + { $$ = $2; } + /* `(typedef)1' is `int'. */ + | PAREN_STAR_PAREN + | direct_abstract_declarator '(' parmlist ')' cv_qualifiers exception_specification_opt %prec '.' + { $$ = make_call_declarator ($$, $3, $5, $6); } + | direct_abstract_declarator LEFT_RIGHT cv_qualifiers exception_specification_opt %prec '.' + { $$ = make_call_declarator ($$, empty_parms (), $3, $4); } + | 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 ')' cv_qualifiers exception_specification_opt %prec '.' + { $$ = make_call_declarator (NULL_TREE, $2, $4, $5); } + | regcast_or_absdcl cv_qualifiers exception_specification_opt %prec '.' + { set_quals_and_spec ($$, $2, $3); } + | fcast_or_absdcl cv_qualifiers exception_specification_opt %prec '.' + { set_quals_and_spec ($$, $2, $3); } + | '[' 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 ';' + ; + +/* 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: + '{' + { $<ttype>$ = begin_compound_stmt (0); } + compstmtend + { $$ = finish_compound_stmt (0, $<ttype>2); } + ; + +simple_if: + IF + { + $<ttype>$ = begin_if_stmt (); + cond_stmt_keyword = "if"; + } + paren_cond_or_null + { finish_if_stmt_cond ($3, $<ttype>2); } + implicitly_scoped_stmt + { $<ttype>$ = finish_then_clause ($<ttype>2); } + ; + +implicitly_scoped_stmt: + compstmt + | { $<ttype>$ = begin_compound_stmt (0); } + simple_stmt + { $$ = finish_compound_stmt (0, $<ttype>1); } + ; + +stmt: + compstmt + {} + | simple_stmt + ; + +simple_stmt: + decl + { finish_stmt (); } + | expr ';' + { finish_expr_stmt ($1); } + | simple_if ELSE + { begin_else_clause (); } + implicitly_scoped_stmt + { + finish_else_clause ($<ttype>1); + finish_if_stmt (); + } + | simple_if %prec IF + { finish_if_stmt (); } + | WHILE + { + $<ttype>$ = begin_while_stmt (); + cond_stmt_keyword = "while"; + } + paren_cond_or_null + { finish_while_stmt_cond ($3, $<ttype>2); } + already_scoped_stmt + { finish_while_stmt ($<ttype>2); } + | DO + { $<ttype>$ = begin_do_stmt (); } + implicitly_scoped_stmt WHILE + { + finish_do_body ($<ttype>2); + cond_stmt_keyword = "do"; + } + paren_expr_or_null ';' + { finish_do_stmt ($6, $<ttype>2); } + | FOR + { $<ttype>$ = begin_for_stmt (); } + '(' for.init.statement + { finish_for_init_stmt ($<ttype>2); } + xcond ';' + { finish_for_cond ($6, $<ttype>2); } + xexpr ')' + { finish_for_expr ($9, $<ttype>2); } + already_scoped_stmt + { finish_for_stmt ($9, $<ttype>2); } + | SWITCH + { begin_switch_stmt (); } + '(' condition ')' + { $<ttype>$ = finish_switch_cond ($4); } + implicitly_scoped_stmt + { finish_switch_stmt ($4, $<ttype>6); } + | CASE expr_no_commas ':' + { finish_case_label ($2, NULL_TREE); } + stmt + | CASE expr_no_commas ELLIPSIS expr_no_commas ':' + { finish_case_label ($2, $4); } + stmt + | DEFAULT ':' + { finish_case_label (NULL_TREE, NULL_TREE); } + stmt + | BREAK ';' + { finish_break_stmt (); } + | CONTINUE ';' + { finish_continue_stmt (); } + | RETURN_KEYWORD ';' + { finish_return_stmt (NULL_TREE); } + | RETURN_KEYWORD expr ';' + { finish_return_stmt ($2); } + | asm_keyword maybe_cv_qualifier '(' string ')' ';' + { + finish_asm_stmt ($2, $4, NULL_TREE, NULL_TREE, + NULL_TREE); + } + /* This is the case with just output operands. */ + | asm_keyword maybe_cv_qualifier '(' string ':' asm_operands ')' ';' + { + finish_asm_stmt ($2, $4, $6, NULL_TREE, + NULL_TREE); + } + /* This is the case with input operands as well. */ + | asm_keyword maybe_cv_qualifier '(' string ':' asm_operands ':' asm_operands ')' ';' + { finish_asm_stmt ($2, $4, $6, $8, NULL_TREE); } + /* This is the case with clobbered registers as well. */ + | asm_keyword maybe_cv_qualifier '(' string ':' asm_operands ':' + asm_operands ':' asm_clobbers ')' ';' + { finish_asm_stmt ($2, $4, $6, $8, $10); } + | GOTO '*' expr ';' + { + if (pedantic) + pedwarn ("ANSI C++ forbids computed gotos"); + finish_goto_stmt ($3); + } + | GOTO identifier ';' + { finish_goto_stmt ($2); } + | label_colon stmt + { finish_stmt (); } + | label_colon '}' + { error ("label must be followed by statement"); + yyungetc ('}', 0); + finish_stmt (); } + | ';' + { finish_stmt (); } + | try_block + | using_directive + | namespace_using_decl + { do_local_using_decl ($1); } + | namespace_alias + ; + +function_try_block: + TRY + { + if (! current_function_parms_stored) + store_parm_decls (); + expand_start_early_try_stmts (); + } + ctor_initializer_opt compstmt + { + expand_start_all_catch (); + } + handler_seq + { + expand_end_all_catch (); + $$ = $3; + } + ; + +try_block: + TRY + { $<ttype>$ = begin_try_block (); } + compstmt + { finish_try_block ($<ttype>2); } + handler_seq + { finish_handler_sequence ($<ttype>2); } + ; + +handler_seq: + handler + | handler_seq handler + ; + +handler: + CATCH + { $<ttype>$ = begin_handler(); } + handler_args + { finish_handler_parms ($<ttype>2); } + compstmt + { finish_handler ($<ttype>2); } + ; + +type_specifier_seq: + typed_typespecs %prec EMPTY + | nonempty_cv_qualifiers %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 ')' + { check_for_new_type ("inside exception declarations", $2); + expand_start_catch_block ($2.t, $3); } + | '(' type_specifier_seq ')' + { check_for_new_type ("inside exception declarations", $2); + expand_start_catch_block ($2.t, NULL_TREE); } + | '(' type_specifier_seq notype_declarator ')' + { check_for_new_type ("inside exception declarations", $2); + expand_start_catch_block ($2.t, $3); } + | '(' typed_typespecs after_type_declarator ')' + { check_for_new_type ("inside exception declarations", $2); + expand_start_catch_block ($2.t, $3); } + This allows reference parameters... */ + | '(' parm ')' + { check_for_new_type ("inside exception declarations", $2); + expand_start_catch_block (TREE_PURPOSE ($2.t), + TREE_VALUE ($2.t)); } + ; + +label_colon: + IDENTIFIER ':' + { tree label; + do_label: + label = define_label (input_filename, lineno, $1); + if (label && ! minimal_parse_mode) + expand_label (label); + } + | PTYPENAME ':' + { goto do_label; } + | TYPENAME ':' + { goto do_label; } + | SELFNAME ':' + { goto do_label; } + ; + +for.init.statement: + xexpr ';' + { if ($1) cplus_expand_expr_stmt ($1); } + | decl + | '{' compstmtend + { if (pedantic) + pedwarn ("ANSI C++ forbids compound statements inside for initializations"); + } + ; + +/* Either a type-qualifier or nothing. First thing in an `asm' statement. */ + +maybe_cv_qualifier: + /* empty */ + { emit_line_note (input_filename, lineno); + $$ = NULL_TREE; } + | CV_QUALIFIER + { 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 */ + { + $$ = empty_parms(); + } + | complex_parmlist + | type_id + { $$ = finish_parmlist (build_tree_list (NULL_TREE, $1.t), 0); + check_for_new_type ("inside parameter list", $1); } + ; + +/* This nonterminal does not include the common sequence '(' type_id ')', + as it is ambiguous and must be disambiguated elsewhere. */ +complex_parmlist: + parms + { $$ = finish_parmlist ($$, 0); } + | parms_comma ELLIPSIS + { $$ = finish_parmlist ($1, 1); } + /* C++ allows an ellipsis without a separating ',' */ + | parms ELLIPSIS + { $$ = finish_parmlist ($1, 1); } + | type_id ELLIPSIS + { $$ = finish_parmlist (build_tree_list (NULL_TREE, + $1.t), 1); } + | ELLIPSIS + { $$ = finish_parmlist (NULL_TREE, 1); } + | parms ':' + { + /* This helps us recover from really nasty + parse errors, for example, a missing right + parenthesis. */ + yyerror ("possibly missing ')'"); + $$ = finish_parmlist ($1, 0); + yyungetc (':', 0); + yychar = ')'; + } + | type_id ':' + { + /* This helps us recover from really nasty + parse errors, for example, a missing right + parenthesis. */ + yyerror ("possibly missing ')'"); + $$ = finish_parmlist (build_tree_list (NULL_TREE, + $1.t), 0); + yyungetc (':', 0); + yychar = ')'; + } + ; + +/* A default argument to a */ +defarg: + '=' + { maybe_snarf_defarg (); } + defarg1 + { $$ = $3; } + ; + +defarg1: + DEFARG + | init + ; + +/* A nonempty list of parameter declarations or type names. */ +parms: + named_parm + { check_for_new_type ("in a parameter list", $1); + $$ = build_tree_list (NULL_TREE, $1.t); } + | parm defarg + { check_for_new_type ("in a parameter list", $1); + $$ = build_tree_list ($2, $1.t); } + | parms_comma full_parm + { check_for_new_type ("in a parameter list", $2); + $$ = chainon ($$, $2.t); } + | 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 ',' + { check_for_new_type ("in a parameter list", $1); + $$ = build_tree_list (NULL_TREE, $1.t); } + ; + +/* A single parameter declaration or parameter type name, + as found in a parmlist. */ +named_parm: + /* Here we expand typed_declspecs inline to avoid mis-parsing of + TYPESPEC IDENTIFIER. */ + typed_declspecs1 declarator + { tree specs = strip_attrs ($1.t); + $$.new_type_flag = $1.new_type_flag; + $$.t = build_tree_list (specs, $2); } + | typed_typespecs declarator + { $$.t = build_tree_list ($1.t, $2); + $$.new_type_flag = $1.new_type_flag; } + | typespec declarator + { $$.t = build_tree_list (build_decl_list (NULL_TREE, $1.t), + $2); + $$.new_type_flag = $1.new_type_flag; } + | typed_declspecs1 absdcl + { tree specs = strip_attrs ($1.t); + $$.t = build_tree_list (specs, $2); + $$.new_type_flag = $1.new_type_flag; } + | typed_declspecs1 %prec EMPTY + { tree specs = strip_attrs ($1.t); + $$.t = build_tree_list (specs, NULL_TREE); + $$.new_type_flag = $1.new_type_flag; } + | declmods notype_declarator + { tree specs = strip_attrs ($1); + $$.t = build_tree_list (specs, $2); + $$.new_type_flag = 0; } + ; + +full_parm: + parm + { $$.t = build_tree_list (NULL_TREE, $1.t); + $$.new_type_flag = $1.new_type_flag; } + | parm defarg + { $$.t = build_tree_list ($2, $1.t); + $$.new_type_flag = $1.new_type_flag; } + ; + +parm: + named_parm + | type_id + ; + +see_typename: + /* empty */ %prec EMPTY + { see_typename (); } + ; + +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"); + if (TREE_CODE ($$) == SCOPE_REF + && (TREE_CODE (TREE_OPERAND ($$, 0)) == TEMPLATE_TYPE_PARM + || TREE_CODE (TREE_OPERAND ($$, 0)) == TEMPLATE_TEMPLATE_PARM)) + cp_error (" perhaps you want `typename %E' to make it a type", $$); + $$ = build_tree_list (integer_type_node, $$); + } + ; + +exception_specification_opt: + /* empty */ %prec 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($1.t)); } + ; + +ansi_raise_identifiers: + ansi_raise_identifier + | ansi_raise_identifiers ',' ansi_raise_identifier + { + TREE_CHAIN ($3) = $$; + $$ = $3; + } + ; + +conversion_declarator: + /* empty */ %prec EMPTY + { $$ = NULL_TREE; } + | '*' cv_qualifiers conversion_declarator + { $$ = make_pointer_declarator ($2, $3); } + | '&' cv_qualifiers conversion_declarator + { $$ = make_reference_declarator ($2, $3); } + | ptr_to_mem cv_qualifiers 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.t, $3); } + | operator error + { $$ = ansi_opname[ERROR_MARK]; } + ; + +%% + +#ifdef SPEW_DEBUG +const char * +debug_yytranslate (value) + int value; +{ + return yytname[YYTRANSLATE (value)]; +} + +#endif |