#################################################### # # # *** WARNING *** # # # # This test will try to parse a full C++ grammar, # # so it will use a huge ammount of CPU and memory. # # # # So, be patient, specially for test #2... # # # #################################################### $^W=0; # Before `make install' is performed this script should be runnable with # `make test'. After `make install' it should work as `perl test.pl' ######################### We start with some black magic to print on failure. # Change 1..1 below to 1..last_test_to_print . # (It may become useful if the test is moved to ./t subdirectory.) BEGIN { $| = 1; print "1..10\n"; } END {print "not ok 1\n" unless $loaded;} use Parse::Yapp; $loaded = 1; print "ok 1\n"; ######################### End of black magic. # Insert your test code below (better if it prints "ok 13" # (correspondingly "not ok 13") depending on the success of chunk 13 # of the test code): use Parse::Yapp; my($testnum)=2; my($parser,$grammar); my($yapptxt); #Test 2 eval { $grammar=join('',); $parser=new Parse::Yapp(input => $grammar); }; $@ and do { print "not ok $testnum\n"; print "Object not created. Cannot continue test suite: aborting\n"; exit(1); }; print "ok ", $testnum++, "\n"; #Test 3 keys(%{$parser->{GRAMMAR}{NULLABLE}}) == 43 or print "not "; print "ok ", $testnum++, "\n"; #Test 4 keys(%{$parser->{GRAMMAR}{NTERM}}) == 233 or print "not "; print "ok ", $testnum++, "\n"; #Test 5 @{$parser->{GRAMMAR}{UUTERM}} == 3 or print "not "; print "ok ", $testnum++, "\n"; #Test 6 keys(%{$parser->{GRAMMAR}{TERM}}) == 108 or print "not "; print "ok ", $testnum++, "\n"; #Test 7 @{$parser->{GRAMMAR}{RULES}} == 825 or print "not "; print "ok ", $testnum++, "\n"; #Test 8 @{$parser->{STATES}} == 1611 or print "not "; print "ok ", $testnum++, "\n"; #Test 9 keys(%{$parser->{CONFLICTS}{SOLVED}}) == 115 or print "not "; print "ok ", $testnum++, "\n"; #Test 10 ( $parser->{CONFLICTS}{FORCED}{TOTAL}[0] == 30 and $parser->{CONFLICTS}{FORCED}{TOTAL}[1] == 42 ) or print "not "; print "ok ", $testnum++, "\n"; __DATA__ /* This grammar is a stripped form of the original C++ grammar from the GNU CC compiler : YACC parser for C++ syntax. Copyright (C) 1988, 89, 93-98, 1999 Free Software Foundation, Inc. Hacked by Michael Tiemann (tiemann@cygnus.com) The full gcc compiler an the original grammar file are freely available under the GPL license at : ftp://ftp.gnu.org/gnu/gcc/ */ %{ $language_string = "GNU C++"; %} %start program /* 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 AGGR %token 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 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 ':' %right ASSIGN '=' %right '?' %left OROR %left ANDAND %left '|' %left '^' %left '&' %left MIN_MAX %left EQCOMPARE %left ARITHCOMPARE '<' '>' %left LSHIFT RSHIFT %left '+' '-' %left '*' '/' '%' %left POINTSAT_STAR DOT_STAR %right UNARY PLUSPLUS MINUSMINUS '~' %left HYPERUNARY %left PAREN_STAR_PAREN LEFT_RIGHT %left POINTSAT '.' '(' '[' %right SCOPE /* C++ extension */ %nonassoc NEW DELETE TRY CATCH /* C++ extensions */ /* Not needed by yapp : already defined in the first %left directive */ /* %token PTYPENAME */ %token PRE_PARSED_FUNCTION_DECL EXTERN_LANG_STRING ALL %token PRE_PARSED_CLASS_DECL DEFARG DEFARG_MARKER /* in order to recognize aggr tags as defining and thus shadowing. */ %token TYPENAME_DEFN IDENTIFIER_DEFN PTYPENAME_DEFN /* Not needed by yapp : already defined in the first %left directive */ /* %token 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 %{ /* Deleted everything */ %} %% program: /* empty */ | extdefs ; /* 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: lang_extdef | extdefs lang_extdef ; extdefs_opt: extdefs | /* empty */ ; dot_hush_warning: ; dot_warning_ok: ; extension: EXTENSION ; asm_keyword: ASM_KEYWORD ; lang_extdef: extdef ; extdef: fndef eat_saved_input | datadef | template_def | asm_keyword '(' string ')' ';' | extern_lang_string '{' extdefs_opt '}' | extern_lang_string dot_hush_warning fndef dot_warning_ok eat_saved_input | extern_lang_string dot_hush_warning datadef dot_warning_ok | NAMESPACE identifier '{' extdefs_opt '}' | NAMESPACE '{' extdefs_opt '}' | namespace_alias | using_decl ';' | using_directive | extension extdef ; namespace_alias: NAMESPACE identifier '=' any_id ';' ; using_decl: USING qualified_id | USING global_scope qualified_id | USING global_scope unqualified_id ; namespace_using_decl: USING namespace_qualifier identifier | USING global_scope identifier | USING global_scope namespace_qualifier identifier ; using_directive: USING NAMESPACE any_id ';' ; namespace_qualifier: NSNAME SCOPE | namespace_qualifier NSNAME SCOPE ; any_id: unqualified_id | qualified_id | global_scope qualified_id | global_scope unqualified_id ; extern_lang_string: EXTERN_LANG_STRING | extern_lang_string EXTERN_LANG_STRING ; template_header: TEMPLATE '<' template_parm_list '>' | TEMPLATE '<' '>' ; template_parm_list: template_parm | template_parm_list ',' template_parm ; maybe_identifier: identifier | /* empty */ ; template_type_parm: aggr maybe_identifier | TYPENAME_KEYWORD maybe_identifier ; template_template_parm: template_header aggr maybe_identifier ; 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 | template_type_parm '=' type_id | parm | parm '=' expr_no_commas %prec ARITHCOMPARE | template_template_parm | template_template_parm '=' template_arg ; template_def: template_header template_extdef | template_header error %prec EMPTY ; template_extdef: fndef eat_saved_input | template_datadef | template_def | extern_lang_string dot_hush_warning fndef dot_warning_ok eat_saved_input | extern_lang_string dot_hush_warning template_datadef dot_warning_ok | extension template_extdef ; template_datadef: nomods_initdecls ';' | declmods notype_initdecls ';' | typed_declspecs initdecls ';' | structsp ';' ; datadef: nomods_initdecls ';' | declmods notype_initdecls ';' | typed_declspecs initdecls ';' | declmods ';' | explicit_instantiation ';' | typed_declspecs ';' | error ';' | error '}' | ';' ; ctor_initializer_opt: nodecls | base_init ; maybe_return_init: /* empty */ | return_init | return_init ';' ; eat_saved_input: /* empty */ | END_OF_SAVED_INPUT ; fndef: fn_dot_def1 maybe_return_init ctor_initializer_opt compstmt_or_error | fn_dot_def1 maybe_return_init function_try_block | fn_dot_def1 maybe_return_init error ; constructor_declarator: nested_name_specifier SELFNAME '(' parmlist ')' cv_qualifiers exception_specification_opt | nested_name_specifier SELFNAME LEFT_RIGHT cv_qualifiers exception_specification_opt | global_scope nested_name_specifier SELFNAME '(' parmlist ')' cv_qualifiers exception_specification_opt | global_scope nested_name_specifier SELFNAME LEFT_RIGHT cv_qualifiers exception_specification_opt | nested_name_specifier self_template_type '(' parmlist ')' cv_qualifiers exception_specification_opt | nested_name_specifier self_template_type LEFT_RIGHT cv_qualifiers exception_specification_opt | global_scope nested_name_specifier self_template_type '(' parmlist ')' cv_qualifiers exception_specification_opt | global_scope nested_name_specifier self_template_type LEFT_RIGHT cv_qualifiers exception_specification_opt ; fn_dot_def1: typed_declspecs declarator | declmods notype_declarator | notype_declarator | declmods constructor_declarator | constructor_declarator ; component_constructor_declarator: SELFNAME '(' parmlist ')' cv_qualifiers exception_specification_opt | SELFNAME LEFT_RIGHT cv_qualifiers exception_specification_opt | self_template_type '(' parmlist ')' cv_qualifiers exception_specification_opt | self_template_type LEFT_RIGHT cv_qualifiers exception_specification_opt ; /* more C++ complexity. See component_decl for a comment on the reduce/reduce conflict introduced by these rules. */ fn_dot_def2: declmods component_constructor_declarator | component_constructor_declarator | typed_declspecs declarator | declmods notype_declarator | notype_declarator | declmods constructor_declarator | constructor_declarator ; return_id: RETURN_KEYWORD IDENTIFIER ; return_init: return_id maybe_init | return_id '(' nonnull_exprlist ')' | return_id LEFT_RIGHT ; base_init: ':' dot_set_base_init member_init_list ; dot_set_base_init: /* empty */ ; member_init_list: /* empty */ | member_init | member_init_list ',' member_init | member_init_list error ; member_init: '(' nonnull_exprlist ')' | LEFT_RIGHT | notype_identifier '(' nonnull_exprlist ')' | notype_identifier LEFT_RIGHT | nonnested_type '(' nonnull_exprlist ')' | nonnested_type LEFT_RIGHT | typename_sub '(' nonnull_exprlist ')' | typename_sub LEFT_RIGHT ; 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 ';' end_explicit_instantiation | TEMPLATE begin_explicit_instantiation typed_declspecs declarator end_explicit_instantiation | TEMPLATE begin_explicit_instantiation notype_declarator end_explicit_instantiation | TEMPLATE begin_explicit_instantiation constructor_declarator end_explicit_instantiation | SCSPEC TEMPLATE begin_explicit_instantiation typespec ';' end_explicit_instantiation | SCSPEC TEMPLATE begin_explicit_instantiation typed_declspecs declarator end_explicit_instantiation | SCSPEC TEMPLATE begin_explicit_instantiation notype_declarator end_explicit_instantiation | SCSPEC TEMPLATE begin_explicit_instantiation constructor_declarator end_explicit_instantiation ; begin_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 dot_finish_template_type | TYPENAME '<' template_arg_list_opt template_close_bracket dot_finish_template_type | self_template_type ; apparent_template_type: template_type | identifier '<' template_arg_list_opt '>' dot_finish_template_type ; self_template_type: SELFNAME '<' template_arg_list_opt template_close_bracket dot_finish_template_type ; dot_finish_template_type: ; template_close_bracket: '>' | RSHIFT ; template_arg_list_opt: /* empty */ | template_arg_list ; template_arg_list: template_arg | template_arg_list ',' template_arg ; template_arg: type_id | PTYPENAME | expr_no_commas %prec ARITHCOMPARE ; unop: '-' | '+' | PLUSPLUS | MINUSMINUS | '!' ; expr: nontrivial_exprlist | expr_no_commas ; paren_expr_or_null: LEFT_RIGHT | '(' expr ')' ; paren_cond_or_null: LEFT_RIGHT | '(' condition ')' ; xcond: /* empty */ | condition | error ; condition: type_specifier_seq declarator maybeasm maybe_attribute '=' | expr ; compstmtend: '}' | maybe_label_decls stmts '}' | maybe_label_decls stmts error '}' | maybe_label_decls error '}' ; already_scoped_stmt: '{' compstmtend | simple_stmt ; nontrivial_exprlist: expr_no_commas ',' expr_no_commas | expr_no_commas ',' error | nontrivial_exprlist ',' expr_no_commas | nontrivial_exprlist ',' error ; nonnull_exprlist: expr_no_commas | nontrivial_exprlist ; unary_expr: primary %prec UNARY /* __extension__ turns off -pedantic for following primary. */ | extension cast_expr %prec UNARY | '*' cast_expr %prec UNARY | '&' cast_expr %prec UNARY | '~' cast_expr | unop cast_expr %prec UNARY /* Refer to the address of a label as a pointer. */ | ANDAND identifier | SIZEOF unary_expr %prec UNARY | SIZEOF '(' type_id ')' %prec HYPERUNARY | ALIGNOF unary_expr %prec UNARY | ALIGNOF '(' type_id ')' %prec HYPERUNARY /* The %prec EMPTY's here are required by the = init initializer syntax extension; see below. */ | new new_type_id %prec EMPTY | new new_type_id new_initializer | new new_placement new_type_id %prec EMPTY | new new_placement new_type_id new_initializer /* The dot_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 '(' dot_begin_new_placement type_id dot_finish_new_placement %prec EMPTY | new '(' dot_begin_new_placement type_id dot_finish_new_placement new_initializer | new new_placement '(' dot_begin_new_placement type_id dot_finish_new_placement %prec EMPTY | new new_placement '(' dot_begin_new_placement type_id dot_finish_new_placement new_initializer | delete cast_expr %prec UNARY | delete '[' ']' cast_expr %prec UNARY | delete '[' expr ']' cast_expr %prec UNARY | REALPART cast_expr %prec UNARY | IMAGPART cast_expr %prec UNARY ; /* 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. */ dot_finish_new_placement: ')' ; dot_begin_new_placement: ; new_placement: '(' dot_begin_new_placement nonnull_exprlist ')' | '{' dot_begin_new_placement nonnull_exprlist '}' ; new_initializer: '(' nonnull_exprlist ')' | LEFT_RIGHT | '(' typespec ')' /* 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 ; /* This is necessary to postpone reduction of `int ((int)(int)(int))'. */ regcast_or_absdcl: '(' type_id ')' %prec EMPTY | regcast_or_absdcl '(' type_id ')' %prec EMPTY ; cast_expr: unary_expr | regcast_or_absdcl unary_expr %prec UNARY | regcast_or_absdcl '{' initlist maybecomma '}' %prec UNARY ; expr_no_commas: cast_expr /* Handle general members. */ | expr_no_commas POINTSAT_STAR expr_no_commas | expr_no_commas DOT_STAR expr_no_commas | expr_no_commas '+' expr_no_commas | expr_no_commas '-' expr_no_commas | expr_no_commas '*' expr_no_commas | expr_no_commas '/' expr_no_commas | expr_no_commas '%' expr_no_commas | expr_no_commas LSHIFT expr_no_commas | expr_no_commas RSHIFT expr_no_commas | expr_no_commas ARITHCOMPARE expr_no_commas | expr_no_commas '<' expr_no_commas | expr_no_commas '>' expr_no_commas | expr_no_commas EQCOMPARE expr_no_commas | expr_no_commas MIN_MAX expr_no_commas | expr_no_commas '&' expr_no_commas | expr_no_commas '|' expr_no_commas | expr_no_commas '^' expr_no_commas | expr_no_commas ANDAND expr_no_commas | expr_no_commas OROR expr_no_commas | expr_no_commas '?' xexpr ':' expr_no_commas | expr_no_commas '=' expr_no_commas | expr_no_commas ASSIGN expr_no_commas | THROW | THROW expr_no_commas /* 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 | '~' see_typename template_type | template_id | operator_name | IDENTIFIER | PTYPENAME | NSNAME %prec EMPTY ; do_id: ; template_id: PFUNCNAME '<' do_id template_arg_list_opt template_close_bracket | operator_name '<' do_id template_arg_list_opt template_close_bracket ; object_template_id: TEMPLATE identifier '<' template_arg_list_opt template_close_bracket | TEMPLATE PFUNCNAME '<' template_arg_list_opt template_close_bracket | TEMPLATE operator_name '<' template_arg_list_opt template_close_bracket ; unqualified_id: notype_unqualified_id | TYPENAME | SELFNAME ; expr_or_declarator_intern: expr_or_declarator | attributes expr_or_declarator ; expr_or_declarator: notype_unqualified_id | '*' expr_or_declarator_intern %prec UNARY | '&' expr_or_declarator_intern %prec UNARY | '(' expr_or_declarator_intern ')' ; notype_template_declarator: IDENTIFIER '<' template_arg_list_opt template_close_bracket | NSNAME '<' template_arg_list template_close_bracket ; 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 ')' ; primary: notype_unqualified_id | CONSTANT | boolean_dot_literal | string | '(' expr ')' | '(' expr_or_declarator_intern ')' | '(' error ')' | '(' compstmt ')' /* 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 ')' | notype_unqualified_id LEFT_RIGHT | primary '(' nonnull_exprlist ')' | primary LEFT_RIGHT | primary '[' expr ']' | primary PLUSPLUS | primary MINUSMINUS /* C++ extensions */ | THIS | CV_QUALIFIER '(' nonnull_exprlist ')' | functional_cast | DYNAMIC_CAST '<' type_id '>' '(' expr ')' | STATIC_CAST '<' type_id '>' '(' expr ')' | REINTERPRET_CAST '<' type_id '>' '(' expr ')' | CONST_CAST '<' type_id '>' '(' expr ')' | TYPEID '(' expr ')' | TYPEID '(' type_id ')' | global_scope IDENTIFIER | global_scope template_id | global_scope operator_name | overqualified_id %prec HYPERUNARY | overqualified_id '(' nonnull_exprlist ')' | overqualified_id LEFT_RIGHT | object object_template_id %prec UNARY | object object_template_id '(' nonnull_exprlist ')' | object object_template_id LEFT_RIGHT | object unqualified_id %prec UNARY | object overqualified_id %prec UNARY | object unqualified_id '(' nonnull_exprlist ')' | object unqualified_id LEFT_RIGHT | object overqualified_id '(' nonnull_exprlist ')' | object overqualified_id LEFT_RIGHT /* p->int::~int() is valid -- 12.4 */ | object '~' TYPESPEC LEFT_RIGHT | object TYPESPEC SCOPE '~' TYPESPEC LEFT_RIGHT | object error ; /* Not needed for now. primary_no_id: '(' expr ')' | '(' error ')' | '(' | primary_no_id '(' nonnull_exprlist ')' | primary_no_id LEFT_RIGHT | primary_no_id '[' expr ']' | primary_no_id PLUSPLUS | primary_no_id MINUSMINUS | SCOPE IDENTIFIER | SCOPE operator_name ; */ new: NEW | global_scope NEW ; delete: DELETE | global_scope delete ; boolean_dot_literal: CXX_TRUE | CXX_FALSE ; /* Produces a STRING_CST with perhaps more STRING_CSTs chained onto it. */ string: STRING | string STRING ; nodecls: /* empty */ ; object: primary '.' | primary POINTSAT ; decl: typespec initdecls ';' | typed_declspecs initdecls ';' | declmods notype_initdecls ';' | typed_declspecs ';' | declmods ';' | extension decl ; /* 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 | fcast_or_absdcl LEFT_RIGHT %prec EMPTY ; /* ANSI type-id (8.1) */ type_id: typed_typespecs absdcl | nonempty_cv_qualifiers absdcl | typespec absdcl | typed_typespecs %prec EMPTY | nonempty_cv_qualifiers %prec EMPTY ; /* 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 | typespec reserved_declspecs %prec HYPERUNARY | typespec reserved_typespecquals reserved_declspecs | declmods typespec reserved_declspecs | declmods typespec reserved_typespecquals | declmods typespec reserved_typespecquals reserved_declspecs ; reserved_declspecs: SCSPEC | reserved_declspecs typespecqual_reserved | reserved_declspecs SCSPEC | reserved_declspecs attributes | attributes ; /* 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 | nonempty_cv_qualifiers typespec | typespec reserved_typespecquals | nonempty_cv_qualifiers typespec reserved_typespecquals ; reserved_typespecquals: typespecqual_reserved | reserved_typespecquals typespecqual_reserved ; /* A typespec (but not a type qualifier). Once we have seen one of these in a declaration, if a typedef name appears then it is being redeclared. */ typespec: structsp | TYPESPEC %prec EMPTY | complete_type_name | TYPEOF '(' expr ')' | TYPEOF '(' type_id ')' | SIGOF '(' expr ')' | SIGOF '(' type_id ')' ; /* A typespec that is a reserved word, or a type qualifier. */ typespecqual_reserved: TYPESPEC | CV_QUALIFIER | structsp ; initdecls: initdcl0 | initdecls ',' initdcl ; notype_initdecls: notype_initdcl0 | notype_initdecls ',' initdcl ; nomods_initdecls: nomods_initdcl0 | nomods_initdecls ',' initdcl ; maybeasm: /* empty */ | asm_keyword '(' string ')' ; initdcl: declarator maybeasm maybe_attribute '=' init /* Note how the declaration of the variable is in effect while its init is parsed! */ | declarator maybeasm maybe_attribute ; /* 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_dot_def1 when appropriate. */ initdcl0_innards: maybe_attribute '=' /* Note how the declaration of the variable is in effect while its init is parsed! */ init | maybe_attribute ; initdcl0: declarator maybeasm initdcl0_innards ; notype_initdcl0: notype_declarator maybeasm initdcl0_innards ; nomods_initdcl0: notype_declarator maybeasm initdcl0_innards | constructor_declarator maybeasm maybe_attribute ; /* the * rules are dummies to accept the Apollo extended syntax so that the header files compile. */ maybe_attribute: /* empty */ | attributes ; attributes: attribute | attributes attribute ; attribute: ATTRIBUTE '(' '(' attribute_list ')' ')' ; attribute_list: attrib | attribute_list ',' attrib ; attrib: /* empty */ | any_word | any_word '(' IDENTIFIER ')' | any_word '(' IDENTIFIER ',' nonnull_exprlist ')' | any_word '(' nonnull_exprlist ')' ; /* 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 | identifiers_or_typenames ',' identifier ; maybe_init: /* empty */ %prec EMPTY | '=' init ; /* If we are processing a template, we don't want to expand this initializer yet. */ init: expr_no_commas %prec '=' | '{' '}' | '{' initlist '}' | '{' initlist ',' '}' | error ; /* This chain is built in reverse order, and put in forward order where initlist is used. */ initlist: init | initlist ',' init /* These are for labeled elements. */ | '[' expr_no_commas ']' init | identifier ':' init | initlist ',' identifier ':' init ; fn_dot_defpen: PRE_PARSED_FUNCTION_DECL ; pending_inline: fn_dot_defpen maybe_return_init ctor_initializer_opt compstmt_or_error | fn_dot_defpen maybe_return_init function_try_block | fn_dot_defpen maybe_return_init error ; 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 | DEFARG_MARKER error END_OF_SAVED_INPUT ; pending_defargs: /* empty */ %prec EMPTY | pending_defargs defarg_again | pending_defargs error ; structsp: ENUM identifier '{' enumlist maybecomma_warn '}' | ENUM identifier '{' '}' | ENUM '{' enumlist maybecomma_warn '}' | ENUM '{' '}' | ENUM identifier | ENUM complex_type_name | TYPENAME_KEYWORD typename_sub /* C++ extensions, merged with C to avoid shift/reduce conflicts */ | class_head '{' opt_dot_component_decl_list '}' maybe_attribute pending_defargs pending_inlines | class_head %prec EMPTY ; maybecomma: /* empty */ | ',' ; maybecomma_warn: /* empty */ | ',' ; aggr: AGGR | aggr SCSPEC | aggr TYPESPEC | aggr CV_QUALIFIER | aggr AGGR | aggr attributes ; named_class_head_sans_basetype: aggr identifier ; named_class_head_sans_basetype_defn: aggr identifier_defn %prec EMPTY | named_class_head_sans_basetype '{' | named_class_head_sans_basetype ':' ; named_complex_class_head_sans_basetype: aggr nested_name_specifier identifier | aggr global_scope nested_name_specifier identifier | aggr global_scope identifier | aggr apparent_template_type | aggr nested_name_specifier apparent_template_type ; named_class_head: named_class_head_sans_basetype %prec EMPTY | named_class_head_sans_basetype_defn /* Class name is unqualified, so we look for base classes in the current scope. */ maybe_base_class_list %prec EMPTY | named_complex_class_head_sans_basetype maybe_base_class_list ; unnamed_class_head: aggr '{' ; /* 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 | named_class_head ; maybe_base_class_list: /* empty */ %prec EMPTY | ':' see_typename %prec EMPTY | ':' see_typename base_class_list %prec EMPTY ; base_class_list: base_class | base_class_list ',' see_typename base_class ; base_class: base_class_dot_1 | base_class_access_list see_typename base_class_dot_1 ; base_class_dot_1: typename_sub | nonnested_type | SIGOF '(' expr ')' | SIGOF '(' type_id ')' ; base_class_access_list: VISSPEC see_typename | SCSPEC see_typename | base_class_access_list VISSPEC see_typename | base_class_access_list SCSPEC see_typename ; opt_dot_component_decl_list: | component_decl_list | opt_dot_component_decl_list access_specifier component_decl_list | opt_dot_component_decl_list access_specifier ; access_specifier: VISSPEC ':' ; /* 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 | component_decl_list component_decl ; component_decl: component_decl_1 ';' | component_decl_1 '}' /* C++: handle constructors, destructors and inline functions */ /* note that INLINE is like a TYPESPEC */ | fn_dot_def2 ':' /* base_init compstmt */ | fn_dot_def2 TRY /* base_init compstmt */ | fn_dot_def2 RETURN_KEYWORD /* base_init compstmt */ | fn_dot_def2 '{' /* nodecls compstmt */ | ';' | extension component_decl | template_header component_decl | template_header typed_declspecs ';' ; 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 | declmods notype_components | notype_declarator maybeasm maybe_attribute maybe_init | constructor_declarator maybeasm maybe_attribute maybe_init | ':' expr_no_commas | error /* 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 | component_constructor_declarator maybeasm maybe_attribute maybe_init | using_decl ; /* The case of exactly one component is handled directly by component_decl. */ /* ??? Huh? ^^^ */ components: /* empty: possibly anonymous */ | component_declarator0 | components ',' component_declarator ; notype_components: /* empty: possibly anonymous */ | notype_component_declarator0 | notype_components ',' notype_component_declarator ; 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 | TYPENAME ':' expr_no_commas maybe_attribute ; notype_component_declarator0: notype_declarator maybeasm maybe_attribute maybe_init | constructor_declarator maybeasm maybe_attribute maybe_init | IDENTIFIER ':' expr_no_commas maybe_attribute | ':' expr_no_commas maybe_attribute ; after_type_component_declarator: after_type_declarator maybeasm maybe_attribute maybe_init | TYPENAME ':' expr_no_commas maybe_attribute ; notype_component_declarator: notype_declarator maybeasm maybe_attribute maybe_init | IDENTIFIER ':' expr_no_commas maybe_attribute | ':' expr_no_commas maybe_attribute ; /* 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 ; enumerator: identifier | identifier '=' expr_no_commas ; /* ANSI new-type-id (5.3.4) */ new_type_id: type_specifier_seq new_declarator | type_specifier_seq %prec EMPTY /* 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. */ | '(' dot_begin_new_placement type_id dot_finish_new_placement '[' expr ']' ; cv_qualifiers: /* empty */ %prec EMPTY | cv_qualifiers CV_QUALIFIER ; nonempty_cv_qualifiers: CV_QUALIFIER | nonempty_cv_qualifiers CV_QUALIFIER ; /* These rules must follow the rules for function declarations and component declarations. That way, longer rules are preferred. */ suspend_mom: /* empty */ ; /* An expression which will not live on the momentary obstack. */ nonmomentary_expr: suspend_mom expr ; /* An expression which will not live on the momentary obstack. */ maybe_parmlist: suspend_mom '(' nonnull_exprlist ')' | suspend_mom '(' parmlist ')' | suspend_mom LEFT_RIGHT | suspend_mom '(' error ')' ; /* A declarator that is allowed only after an explicit typespec. */ after_type_declarator_intern: after_type_declarator | attributes after_type_declarator ; /* may all be followed by prec '.' */ after_type_declarator: '*' nonempty_cv_qualifiers after_type_declarator_intern %prec UNARY | '&' nonempty_cv_qualifiers after_type_declarator_intern %prec UNARY | '*' after_type_declarator_intern %prec UNARY | '&' after_type_declarator_intern %prec UNARY | ptr_to_mem cv_qualifiers after_type_declarator_intern | direct_after_type_declarator ; direct_after_type_declarator: direct_after_type_declarator maybe_parmlist cv_qualifiers exception_specification_opt %prec '.' | direct_after_type_declarator '[' nonmomentary_expr ']' | direct_after_type_declarator '[' ']' | '(' after_type_declarator_intern ')' | nested_name_specifier type_name %prec EMPTY | type_name %prec EMPTY ; nonnested_type: type_name %prec EMPTY | global_scope type_name ; complete_type_name: nonnested_type | nested_type | global_scope nested_type ; nested_type: nested_name_specifier type_name %prec EMPTY ; /* 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 ; notype_declarator: '*' nonempty_cv_qualifiers notype_declarator_intern %prec UNARY | '&' nonempty_cv_qualifiers notype_declarator_intern %prec UNARY | '*' notype_declarator_intern %prec UNARY | '&' notype_declarator_intern %prec UNARY | ptr_to_mem cv_qualifiers notype_declarator_intern | direct_notype_declarator ; complex_notype_declarator: '*' nonempty_cv_qualifiers notype_declarator_intern %prec UNARY | '&' nonempty_cv_qualifiers notype_declarator_intern %prec UNARY | '*' complex_notype_declarator %prec UNARY | '&' complex_notype_declarator %prec UNARY | ptr_to_mem cv_qualifiers notype_declarator_intern | complex_direct_notype_declarator ; complex_direct_notype_declarator: direct_notype_declarator maybe_parmlist cv_qualifiers exception_specification_opt %prec '.' | '(' complex_notype_declarator ')' | direct_notype_declarator '[' nonmomentary_expr ']' | direct_notype_declarator '[' ']' | notype_qualified_id | nested_name_specifier notype_template_declarator ; qualified_id: nested_name_specifier unqualified_id | nested_name_specifier object_template_id ; notype_qualified_id: nested_name_specifier notype_unqualified_id | nested_name_specifier object_template_id ; overqualified_id: notype_qualified_id | global_scope notype_qualified_id ; functional_cast: typespec '(' nonnull_exprlist ')' | typespec '(' expr_or_declarator_intern ')' | typespec fcast_or_absdcl %prec EMPTY ; type_name: TYPENAME | SELFNAME | template_type %prec EMPTY ; nested_name_specifier: nested_name_specifier_1 | nested_name_specifier nested_name_specifier_1 | nested_name_specifier TEMPLATE explicit_template_type SCOPE ; /* Why the @#$%^& do type_name and notype_identifier need to be expanded inline here?!? (jason) */ nested_name_specifier_1: TYPENAME SCOPE | SELFNAME SCOPE | NSNAME SCOPE | template_type SCOPE /* 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 ; typename_sub0: typename_sub1 identifier %prec EMPTY | typename_sub1 template_type %prec EMPTY | typename_sub1 explicit_template_type %prec EMPTY | typename_sub1 TEMPLATE explicit_template_type %prec EMPTY ; typename_sub1: typename_sub2 | typename_sub1 typename_sub2 | typename_sub1 explicit_template_type SCOPE | typename_sub1 TEMPLATE explicit_template_type SCOPE ; typename_sub2: TYPENAME SCOPE | SELFNAME SCOPE | template_type SCOPE | PTYPENAME SCOPE | IDENTIFIER SCOPE | NSNAME SCOPE ; explicit_template_type: identifier '<' template_arg_list_opt template_close_bracket ; complex_type_name: global_scope type_name | nested_type | global_scope nested_type ; ptr_to_mem: nested_name_specifier '*' | global_scope nested_name_specifier '*' ; /* 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 ; /* ANSI new-declarator (5.3.4) */ new_declarator: '*' cv_qualifiers new_declarator | '*' cv_qualifiers %prec EMPTY | '&' cv_qualifiers new_declarator %prec EMPTY | '&' cv_qualifiers %prec EMPTY | ptr_to_mem cv_qualifiers %prec EMPTY | ptr_to_mem cv_qualifiers new_declarator | direct_new_declarator %prec EMPTY ; /* ANSI direct-new-declarator (5.3.4) */ direct_new_declarator: '[' expr ']' | direct_new_declarator '[' nonmomentary_expr ']' ; absdcl_intern: absdcl | attributes absdcl ; /* ANSI abstract-declarator (8.1) */ absdcl: '*' nonempty_cv_qualifiers absdcl_intern | '*' absdcl_intern | '*' nonempty_cv_qualifiers %prec EMPTY | '*' %prec EMPTY | '&' nonempty_cv_qualifiers absdcl_intern | '&' absdcl_intern | '&' nonempty_cv_qualifiers %prec EMPTY | '&' %prec EMPTY | ptr_to_mem cv_qualifiers %prec EMPTY | ptr_to_mem cv_qualifiers absdcl_intern | direct_abstract_declarator %prec EMPTY ; /* ANSI direct-abstract-declarator (8.1) */ direct_abstract_declarator: '(' absdcl_intern ')' /* `(typedef)1' is `int'. */ | PAREN_STAR_PAREN | direct_abstract_declarator '(' parmlist ')' cv_qualifiers exception_specification_opt %prec '.' | direct_abstract_declarator LEFT_RIGHT cv_qualifiers exception_specification_opt %prec '.' | direct_abstract_declarator '[' nonmomentary_expr ']' %prec '.' | direct_abstract_declarator '[' ']' %prec '.' | '(' complex_parmlist ')' cv_qualifiers exception_specification_opt %prec '.' | regcast_or_absdcl cv_qualifiers exception_specification_opt %prec '.' | fcast_or_absdcl cv_qualifiers exception_specification_opt %prec '.' | '[' nonmomentary_expr ']' %prec '.' | '[' ']' %prec '.' ; /* 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 ; label_decls: label_decl | label_decls label_decl ; label_decl: LABEL identifiers_or_typenames ';' ; /* 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: '{' compstmtend ; simple_if: IF paren_cond_or_null implicitly_scoped_stmt ; implicitly_scoped_stmt: compstmt | simple_stmt ; stmt: compstmt | simple_stmt ; simple_stmt: decl | expr ';' | simple_if ELSE implicitly_scoped_stmt | simple_if %prec IF | WHILE paren_cond_or_null already_scoped_stmt | DO implicitly_scoped_stmt WHILE paren_expr_or_null ';' | FOR '(' for_dot_init_dot_statement xcond ';' xexpr ')' already_scoped_stmt | SWITCH '(' condition ')' implicitly_scoped_stmt | CASE expr_no_commas ':' stmt | CASE expr_no_commas ELLIPSIS expr_no_commas ':' stmt | DEFAULT ':' stmt | BREAK ';' | CONTINUE ';' | RETURN_KEYWORD ';' | RETURN_KEYWORD expr ';' | asm_keyword maybe_cv_qualifier '(' string ')' ';' /* This is the case with just output operands. */ | asm_keyword maybe_cv_qualifier '(' string ':' asm_operands ')' ';' /* This is the case with input operands as well. */ | asm_keyword maybe_cv_qualifier '(' string ':' asm_operands ':' asm_operands ')' ';' /* This is the case with clobbered registers as well. */ | asm_keyword maybe_cv_qualifier '(' string ':' asm_operands ':' asm_operands ':' asm_clobbers ')' ';' | GOTO '*' expr ';' | GOTO identifier ';' | label_colon stmt | label_colon '}' | ';' | try_block | using_directive | namespace_using_decl | namespace_alias ; function_try_block: TRY ctor_initializer_opt compstmt handler_seq ; try_block: TRY compstmt handler_seq ; handler_seq: handler | handler_seq handler ; handler: CATCH handler_args compstmt ; type_specifier_seq: typed_typespecs %prec EMPTY | nonempty_cv_qualifiers %prec EMPTY ; handler_args: '(' ELLIPSIS ')' /* This doesn't allow reference parameters, the below does. | '(' type_specifier_seq absdcl ')' | '(' type_specifier_seq ')' | '(' type_specifier_seq notype_declarator ')' | '(' typed_typespecs after_type_declarator ')' This allows reference parameters... */ | '(' parm ')' ; label_colon: IDENTIFIER ':' | PTYPENAME ':' | TYPENAME ':' | SELFNAME ':' ; for_dot_init_dot_statement: xexpr ';' | decl | '{' compstmtend ; /* Either a type-qualifier or nothing. First thing in an `asm' statement. */ maybe_cv_qualifier: /* empty */ | CV_QUALIFIER ; xexpr: /* empty */ | expr | error ; /* 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 */ | nonnull_asm_operands ; nonnull_asm_operands: asm_operand | nonnull_asm_operands ',' asm_operand ; asm_operand: STRING '(' expr ')' ; asm_clobbers: STRING | asm_clobbers ',' STRING ; /* 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 */ | complex_parmlist | type_id ; /* This nonterminal does not include the common sequence '(' type_id ')', as it is ambiguous and must be disambiguated elsewhere. */ complex_parmlist: parms | parms_comma ELLIPSIS /* C++ allows an ellipsis without a separating ',' */ | parms ELLIPSIS | type_id ELLIPSIS | ELLIPSIS | parms ':' | type_id ':' ; /* A default argument to a */ defarg: '=' defarg1 ; defarg1: DEFARG | init ; /* A nonempty list of parameter declarations or type names. */ parms: named_parm | parm defarg | parms_comma full_parm | parms_comma bad_parm | parms_comma bad_parm '=' init ; parms_comma: parms ',' | type_id ',' ; /* 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 | typed_typespecs declarator | typespec declarator | typed_declspecs1 absdcl | typed_declspecs1 %prec EMPTY | declmods notype_declarator ; full_parm: parm | parm defarg ; parm: named_parm | type_id ; see_typename: /* empty */ %prec EMPTY ; bad_parm: /* empty */ %prec EMPTY | notype_declarator ; exception_specification_opt: /* empty */ %prec EMPTY | THROW '(' ansi_raise_identifiers ')' %prec EMPTY | THROW LEFT_RIGHT %prec EMPTY ; ansi_raise_identifier: type_id ; ansi_raise_identifiers: ansi_raise_identifier | ansi_raise_identifiers ',' ansi_raise_identifier ; conversion_declarator: /* empty */ %prec EMPTY | '*' cv_qualifiers conversion_declarator | '&' cv_qualifiers conversion_declarator | ptr_to_mem cv_qualifiers conversion_declarator ; operator: OPERATOR ; operator_name: operator '*' | operator '/' | operator '%' | operator '+' | operator '-' | operator '&' | operator '|' | operator '^' | operator '~' | operator ',' | operator ARITHCOMPARE | operator '<' | operator '>' | operator EQCOMPARE | operator ASSIGN | operator '=' | operator LSHIFT | operator RSHIFT | operator PLUSPLUS | operator MINUSMINUS | operator ANDAND | operator OROR | operator '!' | operator '?' ':' | operator MIN_MAX | operator POINTSAT %prec EMPTY | operator POINTSAT_STAR %prec EMPTY | operator LEFT_RIGHT | operator '[' ']' | operator NEW %prec EMPTY | operator DELETE %prec EMPTY | operator NEW '[' ']' | operator DELETE '[' ']' /* Names here should be looked up in class scope ALSO. */ | operator type_specifier_seq conversion_declarator | operator error ; %%