----------------------------------------------------------------------------------
-- Copyright (c) 2006, 2010 IBM Corporation and others.
-- All rights reserved. This program and the accompanying materials
-- are made available under the terms of the Eclipse Public License v1.0
-- which accompanies this distribution, and is available at
-- http://www.eclipse.org/legal/epl_v10.html
--
-- Contributors:
--     IBM Corporation - initial API and implementation
----------------------------------------------------------------------------------


$Terminals
	
	-- Keywords

	asm  auto  bool  break  case  catch  char  class  
	const  const_cast  continue  default  delete  do    
	double  dynamic_cast  else  enum  explicit  export  
	extern  false  float  for  friend  goto  if  inline  
	int  long  mutable  namespace  new  operator  private
	protected  public  register  reinterpret_cast  return
	short  signed  sizeof  static  static_cast  struct
	switch  template  this  throw   try  true  typedef
	typeid  typename  union  unsigned  using  virtual
	void  volatile  wchar_t  while
	
	-- Literals
	
	integer  floating  charconst  stringlit
	
	-- Identifiers
	
	identifier 

	-- Special tokens used in content assist
	
	Completion
	EndOfCompletion
	
	-- Unrecognized token, not actually used anywhere in the grammar, always leads to syntax error
	
	Invalid
	
    -- Punctuation (with aliases to make grammar more readable)

	LeftBracket      ::= '['
	LeftParen        ::= '('
	Dot              ::= '.'
	DotStar          ::= '.*'
	Arrow            ::= '->'
	ArrowStar        ::= '->*'
	PlusPlus         ::= '++'
	MinusMinus       ::= '--'
	And              ::= '&'
	Star             ::= '*'
	Plus             ::= '+'
	Minus            ::= '-'
	Tilde            ::= '~'
	Bang             ::= '!'
	Slash            ::= '/'
	Percent          ::= '%'
	RightShift       ::= '>>'
	LeftShift        ::= '<<'
	LT               ::= '<'
	GT               ::= '>'
	LE               ::= '<='
	GE               ::= '>='
	EQ               ::= '=='
	NE               ::= '!='
	Caret            ::= '^'
	Or               ::= '|'
	AndAnd           ::= '&&'
	OrOr             ::= '||'
	Question         ::= '?'
	Colon            ::= ':'
	ColonColon       ::= '::'
	DotDotDot        ::= '...'
	Assign           ::= '='
	StarAssign       ::= '*='
	SlashAssign      ::= '/='
	PercentAssign    ::= '%='
	PlusAssign       ::= '+='
	MinusAssign      ::= '-='
	RightShiftAssign ::= '>>='
	LeftShiftAssign  ::= '<<='
	AndAssign        ::= '&='
	CaretAssign      ::= '^='
	OrAssign         ::= '|='
	Comma            ::= ','

    RightBracket     -- these four have special rules for content assist
    RightParen     
    RightBrace    
    SemiColon
    LeftBrace
    
$End


$Globals
/.	
    import org.eclipse.cdt.core.dom.ast.cpp.*;
	import org.eclipse.cdt.internal.core.dom.parser.cpp.CPPNodeFactory;
	import org.eclipse.cdt.core.dom.lrparser.action.cpp.CPPBuildASTParserAction;
	import org.eclipse.cdt.core.dom.lrparser.action.cpp.CPPSecondaryParserFactory;
./
$End


$Define
	$build_action_class /. CPPBuildASTParserAction ./
	$node_factory_create_expression /. CPPNodeFactory.getDefault() ./
	$parser_factory_create_expression /. CPPSecondaryParserFactory.getDefault() ./
$End


$Rules

------------------------------------------------------------------------------------------
-- AST scoping
------------------------------------------------------------------------------------------


<openscope-ast> 
    ::= $empty
          /. $Build  openASTScope();  $EndBuild ./ 

<empty>
    ::= $empty 
          /. $Build  consumeEmpty();  $EndBuild ./ 
           
------------------------------------------------------------------------------------------
-- Content assist
------------------------------------------------------------------------------------------

-- The EndOfCompletion token is a special token that matches some punctuation.
-- These tokens allow the parse to complete successfully after a Completion token
-- is encountered.


']' ::=? 'RightBracket'
       | 'EndOfCompletion'
      
')' ::=? 'RightParen'
       | 'EndOfCompletion'
      
'}' ::=? 'RightBrace'
       | 'EndOfCompletion'
      
';' ::=? 'SemiColon'
       | 'EndOfCompletion'

'{' ::=? 'LeftBrace'
       | 'EndOfCompletion'



------------------------------------------------------------------------------------------
-- Basic Concepts
------------------------------------------------------------------------------------------

-- The extra external declaration rules are there just so that ERROR_TOKEN can be
-- caught at the top level.

translation_unit
    ::= declaration_seq_opt
          /. $Build  consumeTranslationUnit(); $EndBuild ./
      

------------------------------------------------------------------------------------------
-- Expressions
------------------------------------------------------------------------------------------

identifier_token
    ::= 'identifier'
      | 'Completion'
      

literal
    ::= 'integer'
           /. $Build  consumeExpressionLiteral(ICPPASTLiteralExpression.lk_integer_constant); $EndBuild ./
      | 'floating'
           /. $Build  consumeExpressionLiteral(ICPPASTLiteralExpression.lk_float_constant); $EndBuild ./
      | 'charconst'
           /. $Build  consumeExpressionLiteral(ICPPASTLiteralExpression.lk_char_constant); $EndBuild ./
      | 'stringlit'
           /. $Build  consumeExpressionLiteral(ICPPASTLiteralExpression.lk_string_literal); $EndBuild ./  
      | 'true'
           /. $Build  consumeExpressionLiteral(ICPPASTLiteralExpression.lk_true); $EndBuild ./
      | 'false'
           /. $Build  consumeExpressionLiteral(ICPPASTLiteralExpression.lk_false); $EndBuild ./
      | 'this'
           /. $Build  consumeExpressionLiteral(ICPPASTLiteralExpression.lk_this); $EndBuild ./
           
           
primary_expression
    ::= literal
      | '(' expression ')'
           /. $Build  consumeExpressionBracketed();  $EndBuild ./
      | id_expression
      
      
id_expression 
    ::= qualified_or_unqualified_name
           /. $Build  consumeExpressionName();  $EndBuild ./
      
      
-- Pushes an IASTName on the stack, if you want an id expression then wrap the name
qualified_or_unqualified_name
    ::= unqualified_id_name
      | qualified_id_name


unqualified_id_name
    ::= identifier_name
      | operator_function_id_name
      | conversion_function_id_name
      | template_id_name
      | '~' identifier_token
          /. $Build  consumeDestructorName();  $EndBuild ./
      | '~' template_id_name
          /. $Build  consumeDestructorNameTemplateId();  $EndBuild ./
     -- | '~' class_name
    


-- wrap an identifier in a name node
identifier_name
    ::= identifier_token
           /. $Build  consumeIdentifierName();  $EndBuild ./
           

template_opt
    ::= 'template'
          /. $Build  consumePlaceHolder();  $EndBuild ./
      | $empty
          /. $Build  consumeEmpty();  $EndBuild ./


-- the ::=? is necessary for example 8.2.1 in the C++ spec to parse correctly
dcolon_opt
    ::=? '::'
          /. $Build  consumeToken();  $EndBuild ./  -- need the actual token to compute offsets
      | $empty
          /. $Build  consumeEmpty();  $EndBuild ./



qualified_id_name
    ::= dcolon_opt nested_name_specifier template_opt unqualified_id_name
          /. $Build  consumeQualifiedId(true);  $EndBuild ./
      | '::' unqualified_id_name
          /. $Build  consumeGlobalQualifiedId();  $EndBuild ./
      
      --| '::' identifier_name
      --    /. $Build  consumeGlobalQualifiedId();  $EndBuild ./
      --| '::' operator_function_id_name
      --    /. $Build  consumeGlobalQualifiedId();  $EndBuild ./
      --| '::' template_id_name
      --    /. $Build  consumeGlobalQualifiedId();  $EndBuild ./



--unqualified_id_with_template_name
--    ::= template_opt unqualified_id_name
--          /. $Build  consumeNameWithTemplateKeyword();  $EndBuild ./
    
    
-- puts a list of names in reverse order on the stack
-- always ends with ::
-- this is the part of a qualified id that comes before the last ::
-- but does not include a :: at the front
nested_name_specifier
    ::= class_or_namespace_name '::' nested_name_specifier_with_template
          /. $Build  consumeNestedNameSpecifier(true);  $EndBuild ./
      | class_or_namespace_name '::' 
          /. $Build  consumeNestedNameSpecifier(false);  $EndBuild ./
      

nested_name_specifier_with_template
    ::= class_or_namespace_name_with_template '::' nested_name_specifier_with_template
          /. $Build  consumeNestedNameSpecifier(true);  $EndBuild ./
      | class_or_namespace_name_with_template '::' 
          /. $Build  consumeNestedNameSpecifier(false);  $EndBuild ./

      
class_or_namespace_name_with_template
    ::= template_opt class_or_namespace_name
          /. $Build  consumeNameWithTemplateKeyword();  $EndBuild ./
      
      
      
nested_name_specifier_opt
    ::= nested_name_specifier
      | $empty
           /. $Build  consumeNestedNameSpecifierEmpty();  $EndBuild ./

      
class_or_namespace_name -- just identifiers
    ::= class_name
      --| namespace_name -- namespace_name name can only be an identifier token, which is already accepted by class_name


postfix_expression
    ::= primary_expression
      | postfix_expression '[' expression ']'
          /. $Build  consumeExpressionArraySubscript();  $EndBuild ./
      | postfix_expression '(' expression_list_opt ')'    
          /. $Build  consumeExpressionFunctionCall();  $EndBuild ./
      | simple_type_specifier '(' expression_list_opt ')' -- explicit type conversion operator
          /. $Build  consumeExpressionSimpleTypeConstructor(); $EndBuild ./
      | 'typename' dcolon_opt nested_name_specifier <empty>  identifier_name '(' expression_list_opt ')'
          /. $Build  consumeExpressionTypeName(); $EndBuild ./
      | 'typename' dcolon_opt nested_name_specifier template_opt template_id_name '(' expression_list_opt ')'
          /. $Build  consumeExpressionTypeName(); $EndBuild ./
      | postfix_expression '.' qualified_or_unqualified_name
          /. $Build  consumeExpressionFieldReference(false, false);  $EndBuild ./
      | postfix_expression '->' qualified_or_unqualified_name
          /. $Build  consumeExpressionFieldReference(true, false);  $EndBuild ./
      | postfix_expression '.' 'template' qualified_or_unqualified_name
          /. $Build  consumeExpressionFieldReference(false, true);  $EndBuild ./
      | postfix_expression '->' 'template' qualified_or_unqualified_name
          /. $Build  consumeExpressionFieldReference(true, true);  $EndBuild ./
      | postfix_expression '.' pseudo_destructor_name
          /. $Build  consumeExpressionFieldReference(false, false);  $EndBuild ./
      | postfix_expression '->' pseudo_destructor_name
          /. $Build  consumeExpressionFieldReference(true, false);  $EndBuild ./
      | postfix_expression '++'
          /. $Build  consumeExpressionUnaryOperator(IASTUnaryExpression.op_postFixIncr);  $EndBuild ./
      | postfix_expression '--'
          /. $Build  consumeExpressionUnaryOperator(IASTUnaryExpression.op_postFixDecr);  $EndBuild ./
      | 'dynamic_cast' '<' type_id '>' '(' expression ')'
          /. $Build  consumeExpressionCast(ICPPASTCastExpression.op_dynamic_cast);  $EndBuild ./
      | 'static_cast' '<' type_id '>' '(' expression ')'
          /. $Build  consumeExpressionCast(ICPPASTCastExpression.op_static_cast);  $EndBuild ./
      | 'reinterpret_cast' '<' type_id '>' '(' expression ')'
          /. $Build  consumeExpressionCast(ICPPASTCastExpression.op_reinterpret_cast);  $EndBuild ./
      | 'const_cast' '<' type_id '>' '(' expression ')'
          /. $Build  consumeExpressionCast(ICPPASTCastExpression.op_const_cast);  $EndBuild ./
      | 'typeid' '(' expression ')'
          /. $Build  consumeExpressionUnaryOperator(ICPPASTUnaryExpression.op_typeid);  $EndBuild ./
      | 'typeid' '(' type_id ')'
          /. $Build  consumeExpressionTypeId(ICPPASTTypeIdExpression.op_typeid); $EndBuild ./

      
      
-- just names
-- Don't even know if I really need this rule, the DOM parser just parses qualified_or_unqualified_name
-- instead of pseudo_destructor_name. But the difference is I have different
-- token types, so maybe I do need this rule.
pseudo_destructor_name
    ::= dcolon_opt nested_name_specifier_opt type_name '::' destructor_type_name
          /. $Build  consumePsudoDestructorName(true);  $EndBuild ./
      | dcolon_opt nested_name_specifier 'template' template_id_name '::' destructor_type_name
          /. $Build  consumePsudoDestructorName(true);  $EndBuild ./
      | dcolon_opt nested_name_specifier_opt destructor_type_name
          /. $Build  consumePsudoDestructorName(false);  $EndBuild ./


destructor_type_name
    ::= '~' identifier_token
          /. $Build  consumeDestructorName();  $EndBuild ./
      | '~' template_id_name
          /. $Build  consumeDestructorNameTemplateId();  $EndBuild ./
          
          
--destructor_type_name
--    ::= '~' type_name
--          /. $Build  consumeDestructorName();  $EndBuild ./
     
          

unary_expression
    ::= postfix_expression
      | new_expression
      | delete_expression
      | '++' cast_expression
          /. $Build  consumeExpressionUnaryOperator(IASTUnaryExpression.op_prefixIncr);  $EndBuild ./
      | '--' cast_expression
          /. $Build  consumeExpressionUnaryOperator(IASTUnaryExpression.op_prefixDecr);  $EndBuild ./
      | '&' cast_expression
          /. $Build  consumeExpressionUnaryOperator(IASTUnaryExpression.op_amper);  $EndBuild ./
      | '*' cast_expression
          /. $Build  consumeExpressionUnaryOperator(IASTUnaryExpression.op_star);  $EndBuild ./
      | '+' cast_expression
          /. $Build  consumeExpressionUnaryOperator(IASTUnaryExpression.op_plus);  $EndBuild ./
      | '-' cast_expression
          /. $Build  consumeExpressionUnaryOperator(IASTUnaryExpression.op_minus);  $EndBuild ./
      | '~' cast_expression
          /. $Build  consumeExpressionUnaryOperator(IASTUnaryExpression.op_tilde);  $EndBuild ./
      | '!' cast_expression
          /. $Build  consumeExpressionUnaryOperator(IASTUnaryExpression.op_not);  $EndBuild ./
      | 'sizeof' unary_expression
          /. $Build  consumeExpressionUnaryOperator(IASTUnaryExpression.op_sizeof);  $EndBuild ./
      | 'sizeof' '(' type_id ')'
          /. $Build  consumeExpressionTypeId(ICPPASTTypeIdExpression.op_sizeof); $EndBuild ./


new_expression
    ::= dcolon_opt 'new' new_placement_opt new_type_id <openscope-ast> new_array_expressions_opt new_initializer_opt
          /. $Build  consumeExpressionNew(true);  $EndBuild ./
      | dcolon_opt 'new' new_placement_opt '(' type_id ')' <openscope-ast> new_array_expressions_opt new_initializer_opt
          /. $Build  consumeExpressionNew(false);  $EndBuild ./


new_placement_opt
    ::= '(' expression_list ')'
      | $empty
          /. $Build  consumeEmpty();  $EndBuild ./


new_type_id
    ::= type_specifier_seq
          /. $Build  consumeTypeId(false);  $EndBuild ./
      | type_specifier_seq new_declarator
          /. $Build  consumeTypeId(true);  $EndBuild ./


new_declarator -- pointer operators are part of the type id, held in an empty declarator
    ::= <openscope-ast> new_pointer_operators
          /. $Build  consumeNewDeclarator(); $EndBuild ./


new_pointer_operators  -- presumably this will not need an action as ptr_operator will have one
    ::= ptr_operator 
      | ptr_operator new_pointer_operators
      

new_array_expressions 
    ::= '[' expression ']'
      | new_array_expressions '[' constant_expression ']'


new_array_expressions_opt
    ::= new_array_expressions
      | $empty


new_initializer
    ::= '(' expression_list_opt ')'  -- even if the parens are there we get null in the AST
          /. $Build  consumeNewInitializer();  $EndBuild ./
    
    
new_initializer_opt
    ::= new_initializer
      | $empty
           /. $Build  consumeEmpty();  $EndBuild ./


delete_expression
    ::= dcolon_opt 'delete' cast_expression
          /. $Build  consumeExpressionDelete(false);  $EndBuild ./
      | dcolon_opt 'delete' '[' ']' cast_expression
          /. $Build  consumeExpressionDelete(true);  $EndBuild ./


cast_expression
     ::= unary_expression
       | '(' type_id ')' cast_expression
           /. $Build  consumeExpressionCast(ICPPASTCastExpression.op_cast);  $EndBuild ./


pm_expression
    ::= cast_expression
      | pm_expression '.*' cast_expression
          /. $Build  consumeExpressionBinaryOperator(ICPPASTBinaryExpression.op_pmdot);  $EndBuild ./
      | pm_expression '->*' cast_expression
          /. $Build  consumeExpressionBinaryOperator(ICPPASTBinaryExpression.op_pmarrow);  $EndBuild ./
          

multiplicative_expression
    ::= pm_expression
      | multiplicative_expression '*' pm_expression
         /. $Build  consumeExpressionBinaryOperator(ICPPASTBinaryExpression.op_multiply);  $EndBuild ./
      | multiplicative_expression '/' pm_expression
         /. $Build  consumeExpressionBinaryOperator(ICPPASTBinaryExpression.op_divide);  $EndBuild ./
      | multiplicative_expression '%' pm_expression
         /. $Build  consumeExpressionBinaryOperator(ICPPASTBinaryExpression.op_modulo);  $EndBuild ./


additive_expression
    ::= multiplicative_expression
      | additive_expression '+' multiplicative_expression
          /. $Build  consumeExpressionBinaryOperator(ICPPASTBinaryExpression.op_plus);  $EndBuild ./
      | additive_expression '-' multiplicative_expression
          /. $Build  consumeExpressionBinaryOperator(ICPPASTBinaryExpression.op_minus);  $EndBuild ./
      
      
shift_expression
    ::= additive_expression
      | shift_expression '<<' additive_expression
          /. $Build  consumeExpressionBinaryOperator(ICPPASTBinaryExpression.op_shiftLeft);  $EndBuild ./
      | shift_expression '>>' additive_expression
          /. $Build  consumeExpressionBinaryOperator(ICPPASTBinaryExpression.op_shiftRight);  $EndBuild ./
      
      
relational_expression
    ::= shift_expression
      | relational_expression '<' shift_expression
          /. $Build  consumeExpressionBinaryOperator(ICPPASTBinaryExpression.op_lessThan);  $EndBuild ./
      | relational_expression '>' shift_expression
          /. $Build  consumeExpressionBinaryOperator(ICPPASTBinaryExpression.op_greaterThan);  $EndBuild ./
      | relational_expression '<=' shift_expression
          /. $Build  consumeExpressionBinaryOperator(ICPPASTBinaryExpression.op_lessEqual);  $EndBuild ./
      | relational_expression '>=' shift_expression
          /. $Build  consumeExpressionBinaryOperator(ICPPASTBinaryExpression.op_greaterEqual);  $EndBuild ./


equality_expression
    ::= relational_expression
      | equality_expression '==' relational_expression
          /. $Build  consumeExpressionBinaryOperator(ICPPASTBinaryExpression.op_equals);  $EndBuild ./
      | equality_expression '!=' relational_expression
          /. $Build  consumeExpressionBinaryOperator(ICPPASTBinaryExpression.op_notequals);  $EndBuild ./


and_expression
    ::= equality_expression
      | and_expression '&' equality_expression
          /. $Build  consumeExpressionBinaryOperator(ICPPASTBinaryExpression.op_binaryAnd);  $EndBuild ./


exclusive_or_expression
    ::= and_expression
      | exclusive_or_expression '^' and_expression
          /. $Build  consumeExpressionBinaryOperator(ICPPASTBinaryExpression.op_binaryXor);  $EndBuild ./


inclusive_or_expression
    ::= exclusive_or_expression
      | inclusive_or_expression '|' exclusive_or_expression
          /. $Build  consumeExpressionBinaryOperator(ICPPASTBinaryExpression.op_binaryOr);  $EndBuild ./


logical_and_expression
    ::= inclusive_or_expression
      | logical_and_expression '&&' inclusive_or_expression
          /. $Build  consumeExpressionBinaryOperator(ICPPASTBinaryExpression.op_logicalAnd);  $EndBuild ./


logical_or_expression
    ::= logical_and_expression
      | logical_or_expression '||' logical_and_expression
          /. $Build  consumeExpressionBinaryOperator(ICPPASTBinaryExpression.op_logicalOr);  $EndBuild ./
      

conditional_expression
    ::= logical_or_expression
      | logical_or_expression '?' expression ':' assignment_expression
           /. $Build  consumeExpressionConditional();  $EndBuild ./


--rules for template arguments, relational_expression needs brackets when it contains >

relational_expression_inTemplate
    ::= shift_expression
      | relational_expression_inTemplate '<' shift_expression 
          /. $Build  consumeExpressionBinaryOperator(ICPPASTBinaryExpression.op_lessThan);  $EndBuild ./
      | '(' relational_expression_inTemplate '>' shift_expression ')'
          /. $Build  consumeExpressionBinaryOperator(ICPPASTBinaryExpression.op_greaterThan);  $EndBuild ./
      | relational_expression_inTemplate '<=' shift_expression
          /. $Build  consumeExpressionBinaryOperator(ICPPASTBinaryExpression.op_lessEqual);  $EndBuild ./
      | relational_expression_inTemplate '>=' shift_expression
          /. $Build  consumeExpressionBinaryOperator(ICPPASTBinaryExpression.op_greaterEqual);  $EndBuild ./

equality_expression_inTemplate
    ::= relational_expression_inTemplate
      | equality_expression_inTemplate '==' relational_expression_inTemplate
          /. $Build  consumeExpressionBinaryOperator(ICPPASTBinaryExpression.op_equals);  $EndBuild ./
      | equality_expression_inTemplate '!=' relational_expression_inTemplate
          /. $Build  consumeExpressionBinaryOperator(ICPPASTBinaryExpression.op_notequals);  $EndBuild ./


and_expression_inTemplate
    ::= equality_expression_inTemplate
      | and_expression_inTemplate '&' equality_expression_inTemplate
          /. $Build  consumeExpressionBinaryOperator(ICPPASTBinaryExpression.op_binaryAnd);  $EndBuild ./
exclusive_or_expression_inTemplate
    ::= and_expression_inTemplate
      | exclusive_or_expression_inTemplate '^' and_expression_inTemplate
          /. $Build  consumeExpressionBinaryOperator(ICPPASTBinaryExpression.op_binaryXor);  $EndBuild ./


inclusive_or_expression_inTemplate
    ::= exclusive_or_expression_inTemplate
      | inclusive_or_expression_inTemplate '|' exclusive_or_expression_inTemplate
          /. $Build  consumeExpressionBinaryOperator(ICPPASTBinaryExpression.op_binaryOr);  $EndBuild ./


logical_and_expression_inTemplate
    ::= inclusive_or_expression_inTemplate
      | logical_and_expression_inTemplate '&&' inclusive_or_expression_inTemplate
          /. $Build  consumeExpressionBinaryOperator(ICPPASTBinaryExpression.op_logicalAnd);  $EndBuild ./


logical_or_expression_inTemplate
    ::= logical_and_expression_inTemplate
      | logical_or_expression_inTemplate '||' logical_and_expression_inTemplate
          /. $Build  consumeExpressionBinaryOperator(ICPPASTBinaryExpression.op_logicalOr);  $EndBuild ./
      

conditional_expression_inTemplate
    ::= logical_or_expression_inTemplate
      | logical_or_expression_inTemplate '?' expression ':' assignment_expression_inTemplate
           /. $Build  consumeExpressionConditional();  $EndBuild ./

assignment_expression_inTemplate
    ::= conditional_expression_inTemplate
      | throw_expression
      | logical_or_expression_inTemplate '=' assignment_expression_inTemplate
          /. $Build  consumeExpressionBinaryOperator(ICPPASTBinaryExpression.op_assign);  $EndBuild ./
      | logical_or_expression_inTemplate '*=' assignment_expression_inTemplate
          /. $Build  consumeExpressionBinaryOperator(ICPPASTBinaryExpression.op_multiplyAssign);  $EndBuild ./
      | logical_or_expression_inTemplate '/=' assignment_expression_inTemplate
          /. $Build  consumeExpressionBinaryOperator(ICPPASTBinaryExpression.op_divideAssign);  $EndBuild ./
      | logical_or_expression_inTemplate '%=' assignment_expression_inTemplate
          /. $Build  consumeExpressionBinaryOperator(ICPPASTBinaryExpression.op_moduloAssign);  $EndBuild ./
      | logical_or_expression_inTemplate '+=' assignment_expression_inTemplate
          /. $Build  consumeExpressionBinaryOperator(ICPPASTBinaryExpression.op_plusAssign);  $EndBuild ./
      | logical_or_expression_inTemplate '-=' assignment_expression_inTemplate
          /. $Build  consumeExpressionBinaryOperator(ICPPASTBinaryExpression.op_minusAssign);  $EndBuild ./
      | logical_or_expression_inTemplate '>>=' assignment_expression_inTemplate
          /. $Build  consumeExpressionBinaryOperator(ICPPASTBinaryExpression.op_shiftRightAssign);  $EndBuild ./
      | logical_or_expression_inTemplate '<<=' assignment_expression_inTemplate
          /. $Build  consumeExpressionBinaryOperator(ICPPASTBinaryExpression.op_shiftLeftAssign);  $EndBuild ./
      | logical_or_expression_inTemplate '&=' assignment_expression_inTemplate
          /. $Build  consumeExpressionBinaryOperator(ICPPASTBinaryExpression.op_binaryAndAssign);  $EndBuild ./
      | logical_or_expression_inTemplate '^=' assignment_expression_inTemplate
          /. $Build  consumeExpressionBinaryOperator(ICPPASTBinaryExpression.op_binaryXorAssign);  $EndBuild ./
      | logical_or_expression_inTemplate '|=' assignment_expression_inTemplate
          /. $Build  consumeExpressionBinaryOperator(ICPPASTBinaryExpression.op_binaryOrAssign);  $EndBuild ./




--end of rules for template arguments
throw_expression
    ::= 'throw'
          /. $Build  consumeExpressionThrow(false);  $EndBuild ./
      | 'throw' assignment_expression
          /. $Build  consumeExpressionThrow(true);  $EndBuild ./


assignment_expression
    ::= conditional_expression
      | throw_expression
      | logical_or_expression '=' assignment_expression
          /. $Build  consumeExpressionBinaryOperator(ICPPASTBinaryExpression.op_assign);  $EndBuild ./
      | logical_or_expression '*=' assignment_expression
          /. $Build  consumeExpressionBinaryOperator(ICPPASTBinaryExpression.op_multiplyAssign);  $EndBuild ./
      | logical_or_expression '/=' assignment_expression
          /. $Build  consumeExpressionBinaryOperator(ICPPASTBinaryExpression.op_divideAssign);  $EndBuild ./
      | logical_or_expression '%=' assignment_expression
          /. $Build  consumeExpressionBinaryOperator(ICPPASTBinaryExpression.op_moduloAssign);  $EndBuild ./
      | logical_or_expression '+=' assignment_expression
          /. $Build  consumeExpressionBinaryOperator(ICPPASTBinaryExpression.op_plusAssign);  $EndBuild ./
      | logical_or_expression '-=' assignment_expression
          /. $Build  consumeExpressionBinaryOperator(ICPPASTBinaryExpression.op_minusAssign);  $EndBuild ./
      | logical_or_expression '>>=' assignment_expression
          /. $Build  consumeExpressionBinaryOperator(ICPPASTBinaryExpression.op_shiftRightAssign);  $EndBuild ./
      | logical_or_expression '<<=' assignment_expression
          /. $Build  consumeExpressionBinaryOperator(ICPPASTBinaryExpression.op_shiftLeftAssign);  $EndBuild ./
      | logical_or_expression '&=' assignment_expression
          /. $Build  consumeExpressionBinaryOperator(ICPPASTBinaryExpression.op_binaryAndAssign);  $EndBuild ./
      | logical_or_expression '^=' assignment_expression
          /. $Build  consumeExpressionBinaryOperator(ICPPASTBinaryExpression.op_binaryXorAssign);  $EndBuild ./
      | logical_or_expression '|=' assignment_expression
          /. $Build  consumeExpressionBinaryOperator(ICPPASTBinaryExpression.op_binaryOrAssign);  $EndBuild ./


expression
    ::= expression_list
     -- | ERROR_TOKEN
     --     /. $Build  consumeExpressionProblem(); $EndBuild ./
      
-- expression_list and expression_list_opt always result in a single element on the stack
-- the element might be an expression, an expression list or null

expression_list
    ::= <openscope-ast> expression_list_actual
           /. $Build  consumeExpressionList();  $EndBuild ./


expression_list_actual
    ::= assignment_expression
      | expression_list_actual ',' assignment_expression

      
expression_list_opt
   ::= expression_list
     | $empty
          /. $Build  consumeEmpty();  $EndBuild ./
          
          
expression_opt
    ::= expression
      | $empty
          /. $Build  consumeEmpty();  $EndBuild ./
      
      
constant_expression
    ::= conditional_expression


constant_expression_opt
    ::= constant_expression
      | $empty
          /. $Build  consumeEmpty();  $EndBuild ./
      

------------------------------------------------------------------------------------------
-- Statements
------------------------------------------------------------------------------------------

statement
    ::= labeled_statement
      | expression_statement
      | compound_statement
      | selection_statement
      | iteration_statement
      | jump_statement
      | declaration_statement
      | try_block
      | ERROR_TOKEN
          /. $Build  consumeStatementProblem();  $EndBuild ./


labeled_statement
    ::= 'identifier' ':' statement
          /. $Build  consumeStatementLabeled();  $EndBuild ./
      | 'case' constant_expression ':' statement
          /. $Build  consumeStatementCase();  $EndBuild ./
      | 'default' ':' statement
          /. $Build  consumeStatementDefault();  $EndBuild ./
      
      
expression_statement
    ::= expression ';'
           /. $Build  consumeStatementExpression();  $EndBuild ./
      | ';'
           /. $Build  consumeStatementNull();  $EndBuild ./
    
    
compound_statement
    ::= '{' <openscope-ast> statement_seq '}'
          /. $Build  consumeStatementCompoundStatement(true);  $EndBuild ./
      | '{' '}'
          /. $Build  consumeStatementCompoundStatement(false);  $EndBuild ./
    
    
statement_seq
    ::= statement
      | statement_seq statement


selection_statement
    ::= 'if' '(' condition ')' statement
          /. $Build  consumeStatementIf(false);  $EndBuild ./
      | 'if' '(' condition ')' statement 'else' statement
          /. $Build  consumeStatementIf(true);  $EndBuild ./
      | 'switch' '(' condition ')' statement
          /. $Build  consumeStatementSwitch();  $EndBuild ./
      


condition
    ::= expression
      | type_specifier_seq declarator '=' assignment_expression
          /. $Build  consumeConditionDeclaration();  $EndBuild ./

condition_opt
    ::= condition
      | $empty
          /. $Build  consumeEmpty(); $EndBuild ./


iteration_statement
    ::= 'while' '(' condition ')' statement
          /. $Build  consumeStatementWhileLoop();  $EndBuild ./
      | 'do' statement 'while' '(' expression ')' ';'
          /. $Build  consumeStatementDoLoop(true);  $EndBuild ./
      | 'do' statement
          /. $Build  consumeStatementDoLoop(false);  $EndBuild ./
      | 'for' '(' for_init_statement condition_opt ';' expression_opt ')' statement
          /. $Build consumeStatementForLoop(); $EndBuild ./


-- I'm sure there are ambiguities here but we won't worry about it
for_init_statement
    ::= expression_statement
      | simple_declaration_with_declspec
          /. $Build  consumeStatementDeclaration();  $EndBuild ./


jump_statement
    ::= 'break' ';'
          /. $Build  consumeStatementBreak();  $EndBuild ./
      | 'continue' ';'
          /. $Build  consumeStatementContinue();  $EndBuild ./
      | 'return' expression ';'
          /. $Build  consumeStatementReturn(true);  $EndBuild ./
      | 'return' ';'
          /. $Build  consumeStatementReturn(false);  $EndBuild ./
      | 'goto' identifier_token ';'
          /. $Build  consumeStatementGoto();  $EndBuild ./


-- Nested functions are not part of the C++ spec, but several
-- of the parser test cases expect them to work.
declaration_statement
    ::= block_declaration
          /. $Build  consumeStatementDeclarationWithDisambiguation();  $EndBuild ./
      | function_definition  -- not spec
          /. $Build  consumeStatementDeclaration();  $EndBuild ./



------------------------------------------------------------------------------------------
-- Declarations
------------------------------------------------------------------------------------------


declaration
    ::= block_declaration
      | function_definition
      | template_declaration
      | explicit_instantiation
      | explicit_specialization
      | linkage_specification
      | namespace_definition
      | ERROR_TOKEN
          /. $Build  consumeDeclarationProblem();  $EndBuild ./


block_declaration
    ::= simple_declaration
      | asm_definition
      | namespace_alias_definition
      | using_declaration
      | using_directive


declaration_seq
    ::= declaration
      | declaration_seq declaration



declaration_seq_opt
    ::= declaration_seq
      | $empty
      
    
    
simple_declaration
    ::= declaration_specifiers_opt <openscope-ast> init_declarator_list_opt ';'
          /. $Build  consumeDeclarationSimple(true);  $EndBuild ./


simple_declaration_with_declspec 
    ::= declaration_specifiers <openscope-ast> init_declarator_list_opt ';'
          /. $Build  consumeDeclarationSimple(true);  $EndBuild ./


-- declaration specifier nodes not created here, they are created by sub-rules 
-- these rules add IToken modifiers to the declspec nodes
declaration_specifiers
    ::= <openscope-ast> simple_declaration_specifiers
          /. $Build  consumeDeclarationSpecifiersSimple();  $EndBuild ./
      | <openscope-ast> class_declaration_specifiers
          /. $Build  consumeDeclarationSpecifiersComposite();  $EndBuild ./
      | <openscope-ast> elaborated_declaration_specifiers
          /. $Build  consumeDeclarationSpecifiersComposite();  $EndBuild ./
      | <openscope-ast> enum_declaration_specifiers
          /. $Build  consumeDeclarationSpecifiersComposite();  $EndBuild ./
      | <openscope-ast> type_name_declaration_specifiers
          /. $Build  consumeDeclarationSpecifiersTypeName();  $EndBuild ./


declaration_specifiers_opt
    ::= declaration_specifiers
      | $empty 
          /. $Build  consumeEmpty();  $EndBuild ./

          

-- what about type qualifiers... cv_qualifier
no_type_declaration_specifier
    ::= storage_class_specifier
      | function_specifier
      | cv_qualifier
      | 'friend'
          /. $Build  consumeToken(); $EndBuild ./
      | 'typedef'
          /. $Build  consumeToken(); $EndBuild ./
      
      
no_type_declaration_specifiers
    ::= no_type_declaration_specifier
      | no_type_declaration_specifiers no_type_declaration_specifier
  
      
-- now also includes qualified names
-- if there is no long long then this may be simplified
simple_declaration_specifiers
    ::= simple_type_specifier
      | no_type_declaration_specifiers simple_type_specifier
      | simple_declaration_specifiers simple_type_specifier
      | simple_declaration_specifiers no_type_declaration_specifier
      | no_type_declaration_specifiers
      
      
-- struct, union or class!
class_declaration_specifiers
    ::= class_specifier
      | no_type_declaration_specifiers class_specifier
      | class_declaration_specifiers no_type_declaration_specifier
      

-- elaborated means something different, but how different?
elaborated_declaration_specifiers
    ::= elaborated_type_specifier
      | no_type_declaration_specifiers elaborated_type_specifier
      | elaborated_declaration_specifiers no_type_declaration_specifier


-- Think this is the same
enum_declaration_specifiers
    ::= enum_specifier
      | no_type_declaration_specifiers  enum_specifier
      | enum_declaration_specifiers no_type_declaration_specifier


-- just typedefs in C99, but expanded to type names in C++ (no tagging needed)
type_name_declaration_specifiers
    ::= type_name_specifier
      | no_type_declaration_specifiers  type_name_specifier
      | type_name_declaration_specifiers no_type_declaration_specifier
    
    
  -- TODO comment this out    
--decl_specifier
--    ::= storage_class_specifier -- just keywords
--      | type_specifier  -- this is where the fun is
 --     | function_specifier -- just keywords
 --     | 'friend'
 --     | 'typedef'


storage_class_specifier
    ::= 'auto'
          /. $Build  consumeToken(); $EndBuild ./
      | 'register'
          /. $Build  consumeToken(); $EndBuild ./
      | 'static'
          /. $Build  consumeToken(); $EndBuild ./
      | 'extern'
          /. $Build  consumeToken(); $EndBuild ./
      | 'mutable'
          /. $Build  consumeToken(); $EndBuild ./


function_specifier
    ::= 'inline'
          /. $Build  consumeToken(); $EndBuild ./
      | 'virtual'
          /. $Build  consumeToken(); $EndBuild ./
      | 'explicit'
          /. $Build  consumeToken(); $EndBuild ./


-- We have no way to disambiguate token types
--typedef_name
--    ::= identifier_token


--type_specifier
--    ::= simple_type_specifier  -- int, void etc...
--      | class_specifier  -- structs, unions, classes
--      | enum_specifier   -- enums
--      | elaborated_type_specifier  -- its elaborated, but this is different than c, includes typename
--      | cv_qualifier  -- the const and volatile keywords (separated because they can be applied to pointer modifiers)


--simple_type_specifier
--    ::= dcolon_opt nested_name_specifier_opt type_name
--          /. $Build  consumeQualifiedId(false);  $EndBuild ./
--      | dcolon_opt nested_name_specifier 'template' template_id_name
--          /. $Build  consumeQualifiedId(false);  $EndBuild ./
--      | simple_type_primitive_specifier
      
   

simple_type_specifier
    ::= simple_type_specifier_token
          /. $Build  consumeToken(); $EndBuild ./

simple_type_specifier_token
    ::= 'char'
      | 'wchar_t'
      | 'bool'
      | 'short'
      | 'int'
      | 'long'
      | 'signed'
      | 'unsigned'
      | 'float'
      | 'double'
      | 'void'


-- last two rules moved here from simple_type_specifier
type_name  -- all identifiers of some kind
    ::= class_name
     -- | enum_name 
     -- | typedef_name


-- last two rules moved here from simple_type_specifier
type_name_specifier  -- all identifiers of some kind
    ::= type_name
      | dcolon_opt nested_name_specifier_opt type_name
          /. $Build  consumeQualifiedId(false);  $EndBuild ./
      | dcolon_opt nested_name_specifier 'template' template_id_name
          /. $Build  consumeQualifiedId(false);  $EndBuild ./
      | 'typename' dcolon_opt nested_name_specifier identifier_name
          /. $Build  consumeQualifiedId(false);  $EndBuild ./
      | 'typename' dcolon_opt nested_name_specifier template_opt template_id_name
          /. $Build  consumeQualifiedId(true);  $EndBuild ./
      | 'typename' identifier_name


-- used for forward declaration and incomplete types
elaborated_type_specifier
    ::= class_keyword elaborated_specifier_hook dcolon_opt nested_name_specifier_opt identifier_name
          /. $Build  consumeTypeSpecifierElaborated(false);  $EndBuild ./
      | class_keyword elaborated_specifier_hook dcolon_opt nested_name_specifier_opt template_opt template_id_name
          /. $Build  consumeTypeSpecifierElaborated(true);   $EndBuild ./
      | 'enum' elaborated_specifier_hook dcolon_opt nested_name_specifier_opt identifier_name      
          /. $Build  consumeTypeSpecifierElaborated(false);  $EndBuild ./


elaborated_specifier_hook
    ::= $empty
    

-- there is currently no way to disambiguate identifier tokens
--enum_name
--   ::= identifier_token


comma_opt
    ::= ',' | $empty
    
    
enum_specifier
    ::= 'enum' enum_specifier_hook '{' <openscope-ast> enumerator_list_opt comma_opt '}'
          /. $Build  consumeTypeSpecifierEnumeration(false); $EndBuild ./
      | 'enum' enum_specifier_hook identifier_token '{' <openscope-ast> enumerator_list_opt comma_opt '}'
          /. $Build  consumeTypeSpecifierEnumeration(true); $EndBuild ./

enum_specifier_hook
    ::= $empty
    
enumerator_list
    ::= enumerator_definition
      | enumerator_list ',' enumerator_definition


enumerator_list_opt
    ::= enumerator_list
      | $empty


enumerator_definition
    ::= identifier_token
          /. $Build  consumeEnumerator(false); $EndBuild ./
      | identifier_token '=' constant_expression
          /. $Build  consumeEnumerator(true); $EndBuild ./


namespace_name
    ::= identifier_name
    
    
-- In the spec grammar this is broken down into original_namespace_definition and extension_namespace_definition.
-- But since we are not tracking identifiers it becomes the same thing, so its simplified here.
namespace_definition
    ::= 'namespace' namespace_name namespace_definition_hook '{' <openscope-ast> declaration_seq_opt '}'
          /. $Build  consumeNamespaceDefinition(true);  $EndBuild ./
      | 'namespace' namespace_definition_hook '{' <openscope-ast> declaration_seq_opt '}'
           /. $Build  consumeNamespaceDefinition(false);  $EndBuild ./

namespace_definition_hook
    ::= $empty
    
              
namespace_alias_definition
    ::= 'namespace' identifier_token '=' dcolon_opt nested_name_specifier_opt namespace_name ';'
           /. $Build  consumeNamespaceAliasDefinition(); $EndBuild ./
           

-- make more lenient!
-- using_declaration
--     ::= 'using' typename_opt dcolon_opt nested_name_specifier unqualified_id_name ';'
--       | 'using' '::' unqualified_id_name ';'
      
      
-- TODO why not just check if the second token is 'typename'?
using_declaration
    ::= 'using' typename_opt dcolon_opt nested_name_specifier_opt unqualified_id_name ';'
          /. $Build  consumeUsingDeclaration();  $EndBuild ./


typename_opt
    ::= 'typename'
          /. $Build  consumePlaceHolder();  $EndBuild ./
      | $empty
          /. $Build  consumeEmpty();  $EndBuild ./


using_directive
    ::= 'using' 'namespace' dcolon_opt nested_name_specifier_opt namespace_name ';'
           /. $Build  consumeUsingDirective();  $EndBuild ./


asm_definition
    ::= 'asm' '(' 'stringlit' ')' ';'
          /. $Build  consumeDeclarationASM(); $EndBuild ./


linkage_specification
    ::= 'extern' 'stringlit' '{' <openscope-ast> declaration_seq_opt '}'
           /. $Build  consumeLinkageSpecification();  $EndBuild ./
      | 'extern' 'stringlit' <openscope-ast> declaration
           /. $Build  consumeLinkageSpecification();  $EndBuild ./


init_declarator_list
    ::= init_declarator_complete
      | init_declarator_list ',' init_declarator_complete


init_declarator_list_opt
    ::= init_declarator_list
      | $empty
      
      
init_declarator_complete
    ::= init_declarator
          /. $Build  consumeInitDeclaratorComplete();  $EndBuild ./ 
      
      
init_declarator
    ::= complete_declarator 
      | complete_declarator initializer
          /. $Build  consumeDeclaratorWithInitializer(true);  $EndBuild ./

complete_declarator
    ::= declarator

declarator
    ::= direct_declarator 
      | <openscope-ast> ptr_operator_seq direct_declarator
          /. $Build  consumeDeclaratorWithPointer(true);  $EndBuild ./

function_declarator
    ::= function_direct_declarator
      | <openscope-ast> ptr_operator_seq direct_declarator
          /. $Build  consumeDeclaratorWithPointer(true);  $EndBuild ./
      

direct_declarator
    ::= basic_direct_declarator
      | function_direct_declarator
      | array_direct_declarator


basic_direct_declarator
    ::= declarator_id_name
         /. $Build  consumeDirectDeclaratorIdentifier();  $EndBuild ./
      | '(' declarator ')'
         /. $Build  consumeDirectDeclaratorBracketed();  $EndBuild ./


function_direct_declarator
    ::= basic_direct_declarator '(' <openscope-ast> parameter_declaration_clause ')' <openscope-ast> cv_qualifier_seq_opt <openscope-ast> exception_specification_opt
          /. $Build  consumeDirectDeclaratorFunctionDeclarator(true);  $EndBuild ./


array_direct_declarator
    ::= array_direct_declarator array_modifier
           /. $Build  consumeDirectDeclaratorArrayDeclarator(true);  $EndBuild ./
      | basic_direct_declarator array_modifier
           /. $Build  consumeDirectDeclaratorArrayDeclarator(true);  $EndBuild ./


array_modifier
    ::= '[' constant_expression ']'
           /. $Build  consumeDirectDeclaratorArrayModifier(true);  $EndBuild ./
      | '[' ']'
           /. $Build  consumeDirectDeclaratorArrayModifier(false);  $EndBuild ./      
      

ptr_operator
    ::= pointer_hook '*' pointer_hook <openscope-ast> cv_qualifier_seq_opt
          /. $Build  consumePointer();  $EndBuild ./
      | pointer_hook '&' pointer_hook
          /. $Build  consumeReferenceOperator();  $EndBuild ./
      | dcolon_opt nested_name_specifier pointer_hook '*' pointer_hook <openscope-ast> cv_qualifier_seq_opt
          /. $Build  consumePointerToMember();  $EndBuild ./

pointer_hook
    ::= $empty
    
ptr_operator_seq
    ::= ptr_operator
      | ptr_operator_seq ptr_operator


--ptr_operator_seq_opt
--    ::= ptr_operator_seq
--      | $empty


cv_qualifier_seq
    ::= cv_qualifier cv_qualifier_seq_opt


cv_qualifier_seq_opt
    ::= cv_qualifier_seq
      | $empty


cv_qualifier
    ::= 'const'
          /. $Build  consumeToken(); $EndBuild ./
      | 'volatile'
          /. $Build  consumeToken(); $EndBuild ./


declarator_id_name
   ::= qualified_or_unqualified_name
     | dcolon_opt nested_name_specifier_opt type_name
          /. $Build  consumeQualifiedId(false);  $EndBuild ./
      
--declarator_id_name
--   ::= unqualified_id_name
--     | <empty> nested_name_specifier template_opt unqualified_id_name
--         /. $Build  consumeQualifiedId(true);  $EndBuild ./
  

type_id
    ::= type_specifier_seq
          /. $Build  consumeTypeId(false);  $EndBuild ./
      | type_specifier_seq abstract_declarator
          /. $Build  consumeTypeId(true);  $EndBuild ./


--type_specifier_seq
--    ::= type_specifier
--      | type_specifier_seq type_specifier


-- more lenient than spec, but easier to deal with
-- TODO are conflicts resolved by using the more strict rule? 
type_specifier_seq
    ::= declaration_specifiers


abstract_declarator
    ::= direct_abstract_declarator 
      | <openscope-ast> ptr_operator_seq 
          /. $Build  consumeDeclaratorWithPointer(false);  $EndBuild ./
      | <openscope-ast> ptr_operator_seq direct_abstract_declarator
          /. $Build  consumeDeclaratorWithPointer(true);  $EndBuild ./
      
      
direct_abstract_declarator
    ::= basic_direct_abstract_declarator
      | array_direct_abstract_declarator
      | function_direct_abstract_declarator
      

basic_direct_abstract_declarator
    ::= '(' abstract_declarator ')'
          /. $Build  consumeDirectDeclaratorBracketed();  $EndBuild ./
      | '(' ')'
          /. $Build  consumeAbstractDeclaratorEmpty();  $EndBuild ./
          

array_direct_abstract_declarator
    ::= array_modifier
          /. $Build  consumeDirectDeclaratorArrayDeclarator(false);  $EndBuild ./
      | array_direct_abstract_declarator array_modifier
          /. $Build  consumeDirectDeclaratorArrayDeclarator(true);  $EndBuild ./
      | basic_direct_abstract_declarator array_modifier
          /. $Build  consumeDirectDeclaratorArrayDeclarator(true);  $EndBuild ./    
       

function_direct_abstract_declarator                 
     ::= basic_direct_abstract_declarator '(' <openscope-ast> parameter_declaration_clause ')' <openscope-ast> cv_qualifier_seq_opt <openscope-ast> exception_specification_opt
           /. $Build  consumeDirectDeclaratorFunctionDeclarator(true);  $EndBuild ./
       | '(' <openscope-ast> parameter_declaration_clause ')' <openscope-ast> cv_qualifier_seq_opt <openscope-ast> exception_specification_opt
           /. $Build  consumeDirectDeclaratorFunctionDeclarator(false);  $EndBuild ./
      

-- actions just place a marker indicating if '...' was parsed
parameter_declaration_clause
    ::= parameter_declaration_list_opt '...'
          /. $Build  consumePlaceHolder();  $EndBuild ./
      | parameter_declaration_list_opt
          /. $Build  consumeEmpty();  $EndBuild ./
      | parameter_declaration_list ',' '...'
          /. $Build  consumePlaceHolder();  $EndBuild ./


parameter_declaration_list
     ::= parameter_declaration
       | parameter_declaration_list ',' parameter_declaration


parameter_declaration_list_opt
    ::= parameter_declaration_list
      | $empty


abstract_declarator_opt
    ::= abstract_declarator
      | $empty
          /. $Build  consumeEmpty();  $EndBuild ./
          
          
parameter_declaration
    ::= declaration_specifiers parameter_init_declarator
          /. $Build  consumeParameterDeclaration();  $EndBuild ./
      | declaration_specifiers
          /. $Build  consumeParameterDeclarationWithoutDeclarator();  $EndBuild ./


parameter_init_declarator
	::= declarator
	  | declarator '=' parameter_initializer
	      /. $Build  consumeDeclaratorWithInitializer(true);  $EndBuild ./
	  | abstract_declarator
	  | abstract_declarator '=' parameter_initializer
	      /. $Build  consumeDeclaratorWithInitializer(true);  $EndBuild ./
	  | '=' parameter_initializer
	      /. $Build  consumeDeclaratorWithInitializer(false);  $EndBuild ./
	  
	  
parameter_initializer
    ::= assignment_expression
          /. $Build  consumeInitializer();  $EndBuild ./


function_definition
    ::= declaration_specifiers_opt function_declarator <openscope-ast> ctor_initializer_list_opt function_body
           /. $Build  consumeFunctionDefinition(false);  $EndBuild ./
      | declaration_specifiers_opt function_declarator 'try' <openscope-ast> ctor_initializer_list_opt function_body <openscope-ast> handler_seq
           /. $Build  consumeFunctionDefinition(true);  $EndBuild ./

    
function_body
    ::= compound_statement


initializer
    ::= '=' initializer_clause
      | '(' expression_list ')'
          /. $Build  consumeInitializerConstructor();  $EndBuild ./


initializer_clause
    ::= assignment_expression
         /. $Build  consumeInitializer();  $EndBuild ./
      | initializer_list
--CDT_70_FIX_FROM_50-#4
          /. $Build  consumeInitializer();  $EndBuild ./
         
initializer_list
    ::= start_initializer_list '{' <openscope-ast> initializer_seq ',' '}' end_initializer_list
         /. $Build  consumeInitializerList();  $EndBuild ./
      | start_initializer_list '{' <openscope-ast> initializer_seq '}' end_initializer_list
         /. $Build  consumeInitializerList();  $EndBuild ./
      | '{' <openscope-ast> '}'
         /. $Build  consumeInitializerList();  $EndBuild ./


start_initializer_list
    ::= $empty
          /. $Build  initializerListStart(); $EndBuild ./
          
end_initializer_list
    ::= $empty
          /. $Build  initializerListEnd(); $EndBuild ./

initializer_seq
    ::= initializer_clause
      | initializer_seq ',' initializer_clause


      
------------------------------------------------------------------------------------------
-- Classes
------------------------------------------------------------------------------------------


class_name
    ::= identifier_name
      | template_id_name


class_specifier
    ::= class_head '{'   <openscope-ast> member_declaration_list_opt '}'
          /.  $Build  consumeClassSpecifier();  $EndBuild ./
       
       
class_head
    ::= class_keyword composite_specifier_hook identifier_name_opt class_name_suffix_hook <openscope-ast> base_clause_opt
          /. $Build  consumeClassHead(false);  $EndBuild ./
      | class_keyword composite_specifier_hook template_id_name class_name_suffix_hook <openscope-ast> base_clause_opt
          /. $Build  consumeClassHead(false);  $EndBuild ./
      | class_keyword composite_specifier_hook nested_name_specifier identifier_name class_name_suffix_hook <openscope-ast> base_clause_opt
          /. $Build  consumeClassHead(true);  $EndBuild ./
      | class_keyword composite_specifier_hook nested_name_specifier template_id_name class_name_suffix_hook <openscope-ast> base_clause_opt
          /. $Build  consumeClassHead(true);  $EndBuild ./

composite_specifier_hook
    ::= $empty
    
class_name_suffix_hook
    ::= $empty

identifier_name_opt
    ::= identifier_name
      | $empty
          /. $Build  consumeEmpty();  $EndBuild./      
      
      
class_keyword
    ::= 'class'
      | 'struct'
      | 'union'


visibility_label
    ::= access_specifier_keyword ':'
          /. $Build  consumeVisibilityLabel();  $EndBuild ./



member_declaration
    ::= declaration_specifiers_opt <openscope-ast> member_declarator_list ';'
          /. $Build  consumeDeclarationSimple(true);  $EndBuild ./
      | declaration_specifiers_opt ';'
          /. $Build  consumeDeclarationSimple(false);  $EndBuild ./
      | function_definition ';' 
      | function_definition      
      | dcolon_opt nested_name_specifier template_opt unqualified_id_name ';'
          /. $Build  consumeMemberDeclarationQualifiedId();  $EndBuild ./ 
      | using_declaration  
      | template_declaration
      | explicit_specialization  -- not spec
      | namespace_definition     -- not spec
      | visibility_label 
      | ERROR_TOKEN
          /. $Build  consumeDeclarationProblem();  $EndBuild ./


member_declaration_list
    ::= member_declaration
      | member_declaration_list member_declaration


member_declaration_list_opt
    ::= member_declaration_list
      | $empty


member_declarator_list
    ::= member_declarator_complete
      | member_declarator_list ',' member_declarator_complete


member_declarator_complete
    ::= member_declarator

member_declarator
    ::= declarator
    -- parse pure specifier as a constant_initializer, reduces conflicts
    -- | declarator pure_specifier  
      | declarator constant_initializer
          /. $Build  consumeMemberDeclaratorWithInitializer();  $EndBuild ./
      | bit_field_declarator ':' constant_expression
          /. $Build  consumeBitField(true);  $EndBuild ./
      | ':' constant_expression
          /. $Build  consumeBitField(false);  $EndBuild ./


bit_field_declarator
    ::= identifier_name
          /. $Build  consumeDirectDeclaratorIdentifier();  $EndBuild ./


constant_initializer
    ::= '=' constant_expression
            /. $Build  consumeInitializer();  $EndBuild ./


base_clause
    ::= ':' base_specifier_list


base_clause_opt
    ::= base_clause
      | $empty 
    

base_specifier_list
    ::= base_specifier
      | base_specifier_list ',' base_specifier



base_specifier
    ::= dcolon_opt nested_name_specifier_opt class_name
          /. $Build  consumeBaseSpecifier(false, false);  $EndBuild ./
      | 'virtual' access_specifier_keyword_opt dcolon_opt nested_name_specifier_opt class_name
          /. $Build  consumeBaseSpecifier(true, true);  $EndBuild ./
      | access_specifier_keyword 'virtual' dcolon_opt nested_name_specifier_opt class_name
          /. $Build  consumeBaseSpecifier(true, true);  $EndBuild ./
      | access_specifier_keyword dcolon_opt nested_name_specifier_opt class_name
          /. $Build  consumeBaseSpecifier(true, false);  $EndBuild ./

      
access_specifier_keyword
    ::= 'private'
          /. $Build  consumeToken();  $EndBuild ./
      | 'protected'
          /. $Build  consumeToken();  $EndBuild ./
      | 'public'
          /. $Build  consumeToken();  $EndBuild ./


access_specifier_keyword_opt
    ::= access_specifier_keyword
      | $empty
          /. $Build  consumeEmpty();  $EndBuild ./


conversion_function_id_name
    ::= conversion_function_id
      | conversion_function_id '<' <openscope-ast> template_argument_list_opt '>'
          /. $Build  consumeTemplateId();  $EndBuild ./
          
conversion_function_id
    ::= 'operator' conversion_type_id
          /. $Build  consumeConversionName(); $EndBuild ./


conversion_type_id
    ::= type_specifier_seq conversion_declarator
          /. $Build  consumeTypeId(true);  $EndBuild ./
      | type_specifier_seq
          /. $Build  consumeTypeId(false);  $EndBuild ./


conversion_declarator
    ::= <openscope-ast> ptr_operator_seq
          /. $Build  consumeDeclaratorWithPointer(false);  $EndBuild ./
      
 
 
--conversion_declarator_opt
--    ::= conversion_declarator
--      | $empty
      
    
ctor_initializer_list
    ::= ':' mem_initializer_list


ctor_initializer_list_opt
    ::= ctor_initializer_list
      | $empty
      

mem_initializer_list
    ::= mem_initializer
      | mem_initializer ',' mem_initializer_list


mem_initializer
    ::= mem_initializer_name '(' expression_list_opt ')'
          /. $Build  consumeConstructorChainInitializer();  $EndBuild ./


mem_initializer_name
    ::= dcolon_opt nested_name_specifier_opt class_name
          /. $Build  consumeQualifiedId(false);  $EndBuild ./
      | identifier_name


operator_function_id_name
    ::= operator_id_name
      | operator_id_name '<' <openscope-ast> template_argument_list_opt '>'
          /. $Build  consumeTemplateId();  $EndBuild ./


operator_id_name
    ::= 'operator' overloadable_operator
          /. $Build  consumeOperatorName();  $EndBuild ./


overloadable_operator
    ::= 'new' | 'delete' | 'new' '[' ']' | 'delete' '[' ']'
      | '+' | '-' | '*' | '/' | '%' | '^' | '&' | '|' | '~'
      | '!' | '=' | '<' | '>' | '+=' | '-=' | '*=' | '/=' | '%='
      | '^=' | '&=' | '|=' | '<<' | '>>' | '>>=' | '<<=' | '==' | '!='
      | '<=' | '>=' | '&&' | '||' | '++' | '--' | ',' | '->*' | '->'
      | '(' ')' | '[' ']'


template_declaration
    ::= export_opt 'template' '<' <openscope-ast> template_parameter_list '>' declaration
          /. $Build  consumeTemplateDeclaration();  $EndBuild ./


export_opt
    ::= 'export'
          /. $Build  consumePlaceHolder();  $EndBuild ./
      | $empty
          /. $Build  consumeEmpty();  $EndBuild ./


template_parameter_list
    ::= template_parameter
      | template_parameter_list ',' template_parameter


-- TODO There is an ambiguity in the spec grammar here, 
-- "class X" should be parsed as a type_parameter
-- and not as a parameter_declaration. Here precedence is used to disambiguate
-- but it would be better to refactor the grammar to remove the conflict.

template_parameter
    ::= type_parameter
      | parameter_declaration
          /. $Build  consumeTemplateParamterDeclaration();  $EndBuild ./ 


type_parameter
    ::= 'class' identifier_name_opt 
          /. $Build  consumeSimpleTypeTemplateParameter(false);  $EndBuild ./
      | 'class' identifier_name_opt '=' type_id
          /. $Build  consumeSimpleTypeTemplateParameter(true);  $EndBuild ./
      | 'typename' identifier_name_opt
          /. $Build  consumeSimpleTypeTemplateParameter(false);  $EndBuild ./
      | 'typename' identifier_name_opt '=' type_id
          /. $Build  consumeSimpleTypeTemplateParameter(true);  $EndBuild ./
      | 'template' '<' <openscope-ast> template_parameter_list '>' 'class' identifier_name_opt
          /. $Build  consumeTemplatedTypeTemplateParameter(false);  $EndBuild ./
      | 'template' '<' <openscope-ast> template_parameter_list '>' 'class' identifier_name_opt '=' id_expression
          /. $Build  consumeTemplatedTypeTemplateParameter(true);  $EndBuild ./


template_id_name
    ::= identifier_name '<' <openscope-ast> template_argument_list_opt '>'
          /. $Build  consumeTemplateId();  $EndBuild ./
--        | ERROR_TOKEN
--          /. $Build consumeTemplateIDError(); $EndBuild ./  


template_argument_list
    ::= template_argument
       | template_argument_list ',' template_argument


template_argument_list_opt
    ::= template_argument_list
      | $empty
      
--type_id in template

class_name_inTemplate
    ::= identifier_name

class_or_namespace_name_inTemplate -- just identifiers
    ::= class_name_inTemplate
      --| namespace_name -- namespace_name name can only be an identifier token, which is already accepted by 

nested_name_specifier_inTemplate
    ::= class_or_namespace_name_inTemplate '::' nested_name_specifier_with_template_inTemplate
          /. $Build  consumeNestedNameSpecifier(true);  $EndBuild ./
      | class_or_namespace_name_inTemplate '::' 
          /. $Build  consumeNestedNameSpecifier(false);  $EndBuild ./
      

nested_name_specifier_with_template_inTemplate
    ::= class_or_namespace_name_with_template_inTemplate '::' nested_name_specifier_with_template_inTemplate
          /. $Build  consumeNestedNameSpecifier(true);  $EndBuild ./
      | class_or_namespace_name_with_template_inTemplate '::' 
          /. $Build  consumeNestedNameSpecifier(false);  $EndBuild ./

      
class_or_namespace_name_with_template_inTemplate
    ::= template_opt class_or_namespace_name_inTemplate
          /. $Build  consumeNameWithTemplateKeyword();  $EndBuild ./
    
nested_name_specifier_opt_inTemplate
    ::= nested_name_specifier_inTemplate
      | $empty
           /. $Build  consumeNestedNameSpecifierEmpty();  $EndBuild ./


type_name_inTemplate  -- all identifiers of some kind
    ::= class_name_inTemplate

-- last two rules moved here from simple_type_specifier
type_name_specifier_inTemplate  -- all identifiers of some kind
    ::= type_name_inTemplate
--      | dcolon_opt nested_name_specifier_opt_inTemplate type_name_inTemplate
--          /. $Build  consumeQualifiedId(false);  $EndBuild ./
--      | dcolon_opt nested_name_specifier_inTemplate 'template' template_id_name
--          /. $Build  consumeQualifiedId(false);  $EndBuild ./
      | 'typename' dcolon_opt nested_name_specifier identifier_name
          /. $Build  consumeQualifiedId(false);  $EndBuild ./
      | 'typename' dcolon_opt nested_name_specifier template_opt template_id_name
          /. $Build  consumeQualifiedId(true);  $EndBuild ./
      | 'typename' identifier_name

type_name_declaration_specifiers_inTemplate
    ::= type_name_specifier_inTemplate
      | no_type_declaration_specifiers  type_name_specifier_inTemplate
      | type_name_declaration_specifiers_inTemplate no_type_declaration_specifier


          
declaration_specifiers_inTemplate
    ::= <openscope-ast> simple_declaration_specifiers
          /. $Build  consumeDeclarationSpecifiersSimple();  $EndBuild ./
      | <openscope-ast> class_declaration_specifiers
          /. $Build  consumeDeclarationSpecifiersComposite();  $EndBuild ./
      | <openscope-ast> elaborated_declaration_specifiers
          /. $Build  consumeDeclarationSpecifiersComposite();  $EndBuild ./
      | <openscope-ast> enum_declaration_specifiers
          /. $Build  consumeDeclarationSpecifiersComposite();  $EndBuild ./
      | <openscope-ast> type_name_declaration_specifiers_inTemplate
          /. $Build  consumeDeclarationSpecifiersTypeName();  $EndBuild ./          
          

type_specifier_seq_inTemplate
      ::= declaration_specifiers_inTemplate


type_id_inTemplate
    ::= type_specifier_seq_inTemplate
          /. $Build  consumeTypeId(false);  $EndBuild ./
      | type_specifier_seq_inTemplate abstract_declarator
          /. $Build  consumeTypeId(true);  $EndBuild ./
          
--end type_id in template


template_argument
    ::= assignment_expression_inTemplate
          /. $Build  consumeTemplateArgumentExpression();  $EndBuild ./  
    | type_id_inTemplate
          /. $Build  consumeTemplateArgumentTypeId();  $EndBuild ./


explicit_instantiation
    ::= 'template' declaration
          /. $Build  consumeTemplateExplicitInstantiation();  $EndBuild ./


explicit_specialization
    ::= 'template' '<' '>' declaration
           /. $Build  consumeTemplateExplicitSpecialization();  $EndBuild ./


try_block
    ::= 'try' compound_statement <openscope-ast> handler_seq
          /. $Build  consumeStatementTryBlock(true);  $EndBuild ./
	  | 'try' compound_statement
          /. $Build  consumeStatementTryBlock(false);  $EndBuild ./





handler_seq
    ::= handler
      | handler_seq handler


handler
    ::= 'catch' '(' exception_declaration ')' compound_statement
          /. $Build  consumeStatementCatchHandler(false);  $EndBuild ./
      | 'catch' '(' '...' ')' compound_statement
          /. $Build  consumeStatementCatchHandler(true);  $EndBuild ./


-- open a scope just so that we can reuse consumeDeclarationSimple()
exception_declaration
    ::= type_specifier_seq <openscope-ast> declarator
          /. $Build  consumeDeclarationSimple(true);  $EndBuild ./
      | type_specifier_seq <openscope-ast> abstract_declarator
          /. $Build  consumeDeclarationSimple(true);  $EndBuild ./
      | type_specifier_seq
          /. $Build  consumeDeclarationSimple(false);  $EndBuild ./


-- puts type ids on the stack
exception_specification
    ::= 'throw' '(' type_id_list ')'
      | 'throw' '('  ')'
          /. $Build  consumePlaceHolder();  $EndBuild ./


exception_specification_opt
    ::= exception_specification
      | $empty


type_id_list
    ::= type_id
      | type_id_list ',' type_id