The Perl Toolchain Summit needs more sponsors. If your company depends on Perl, please support this very important event.
####################################################
#                                                  #
#                *** 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('',<DATA>);
	$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
	;

%%