Skip to main content
aboutsummaryrefslogblamecommitdiffstats
blob: c306206738f311ebdca8ec7a30b63f5c324b52ee (plain) (tree)
1
2
3
4
5
6
7
8
9
10
11
12
13
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885












                                                                                  
                                     








































                                                                                   
                                                                                                                






                                                                                                              
                      





















































































                                                                                                   
                                                                          

























                                                                                     
                                            


                                  








                                                    

                                               








                                                                                                     
                                          








                                                        






                                                    














                                                                                    
                                      






                                            







                                                                                                                    










                                                                                                             


                                                                                                        









































































































                                                                                                          




                                     






























































































































































































































































































































































































































































































































                                                                                                                    
                                           







                                           
                                           















































                                                                               
                    










































































                                                                              





                                                                                                                       

























































































































































































                                                                                            
                                                                          


          


                                                                      
















                                                                                                                                                                     

                                                                                   


                                              
                                                                                 
                                              
                                                                                 






















                                                                                      


                          






























                                                             


                                           

 


                                                  

 
 







                                                                       
                          



                                           
 



                                                                      
 













                                                                                                                                                                               

      
                                                             












                                                             
 



                                  
 





                                                  
                     



















                                                                                  


                   
                                                                                                                     
                                                                     
                                                                                                                                                       
                                                                    
 
    












































































                                                                                            

                                                                             
                                      


                                                                   
                                                                             

                                                                          
                            


                                 


















                                                    
                                                                             
                                       





                                                                            
 



                                                                       
 

                                             



















































                                                                                                        



                                                        


                     


                                                                       

 


                               

      
                     


                                

                             








                                                

                                                                        

 
                    
                                                       

                                                             






















                                                                           
                                                                                         




















                                                                











                                                                                                                









































                                                                              
 













                                                                       
                                                                    
                     



                                                                  
                          
                                                                   















                                    
----------------------------------------------------------------------------------
-- Copyright (c) 2006, 2008 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
----------------------------------------------------------------------------------

%options la=2
%options package=org.eclipse.cdt.internal.core.dom.lrparser.cpp
%options template=btParserTemplateD.g



$Notice
-- Copied into all files generated by LPG
/./*******************************************************************************
 * Copyright (c) 2006, 2008 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
 *********************************************************************************/
 
 // This file was generated by LPG
./
$End



$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 (also true and false are considered literals)
	
	integer  floating  charconst  stringlit
	
	-- zero  -- this is a special token used to disambiguate the the grammar rule for pure virtual functions
	      -- TODO is this really necessary? because it adds overhead in getKind()
	
	-- identifiers
	-- Special token that represents identifiers that have been declared as typedefs (lexer feedback hack)
	-- there's going to be more of these
	
	identifier 
	-- TypedefName

	-- Special tokens used in content assist
	
	Completion
	EndOfCompletion
	
	-- Unrecognized token
	
	Invalid
	
    -- Punctuation (with aliases to make grammar more readable)

	LeftBracket      ::= '['
	LeftParen        ::= '('
	LeftBrace        ::= '{'
	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            ::= ','
	zero             ::= '0'

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


$Globals
/.	
	import java.util.*;
	
	import org.eclipse.cdt.core.dom.ast.*;
	import org.eclipse.cdt.core.dom.ast.cpp.*;
	import org.eclipse.cdt.core.dom.lrparser.action.cpp.CPPASTNodeFactory;
	import org.eclipse.cdt.core.dom.lrparser.action.cpp.CPPBuildASTParserAction;
	import org.eclipse.cdt.core.dom.lrparser.IParser;
	import org.eclipse.cdt.core.dom.lrparser.IParserActionTokenProvider;
	import org.eclipse.cdt.core.dom.lrparser.util.DebugUtil;
./
$End

-- TODO move as much code and macros as possible into a common file

$Define
	-- These macros allow the template and header code to be customized by an extending parser.
	$ast_class /.Object./
	$additional_interfaces /. , IParserActionTokenProvider, IParser ./
	
	$build_action_class /. CPPBuildASTParserAction ./
	$resolve_action_class /. C99TypedefTrackerParserAction ./
	$node_factory_create_expression /. CPPASTNodeFactory.DEFAULT_INSTANCE ./
	
	$action_class /. CPPParserAction ./
	$data_class /. Object ./ -- allow anything to be passed between actions
	
	$UndoResolver /.$Undo action.resolver.undo(); $EndUndo./
	
	$Resolve /. $BeginTrial $resolve.
	./
	$EndResolve /. $EndTrial 
		$UndoResolver
	./ -- undo actions are automatically generated for binding resolution actions
	
	$Builder /. $BeginFinal  $builder.
	./ 
	$EndBuilder /. $EndFinal ./

	$Build /. $Action $Builder ./
	$EndBuild /. $EndBuilder $EndAction ./
	
	$resolve /. action.resolver./
	$builder /. action.builder./
	
	-- comment out when using trial/undo
	$Action /. $BeginAction ./
	$BeginFinal /. ./
	$EndFinal /. ./

$End


$Headers
/.
	private $action_class action;	
	
	// uncomment to use with backtracking parser
	public $action_type() {  // constructor
	}
	
	private void initActions(IASTTranslationUnit tu) {
	    // binding resolution actions need access to IASTName nodes, temporary
	    action = new $action_class();
		//action.resolver = new $resolve_action_class(this);
		action.builder  = new $build_action_class($node_factory_create_expression, this, tu);
		//action.builder.setTokenMap(CPPParsersym.orderedTerminalSymbols);
		
		// comment this line to use with backtracking parser
		//setParserAction(action);
	}
	
	
	public void addToken(IToken token) {
		token.setKind(mapKind(token.getKind()));
		super.addToken(token);
	}
	
	
	public void setTokens(List<IToken> tokens) {
		resetTokenStream();
		for(IToken token : tokens) {
			addToken(token);
		}
	}
	
	public IASTCompletionNode parse(IASTTranslationUnit tu) {
		// this has to be done, or... kaboom!
		setStreamLength(getSize());
		initActions(tu);
		
		final int errorRepairCount = -1;  // _1 means full error handling
		parser(null, errorRepairCount); // do the actual parse
		super.resetTokenStream(); // allow tokens to be garbage collected
	
		// the completion node may be null
		IASTCompletionNode compNode = action.builder.getASTCompletionNode();
	
		action = null;
		
		// Comment this line to use with backtracking parser
		//parserAction = null;
		
		return compNode;
	}


	public int getKind(int i) {
		int kind = super.getKind(i);
		
		// There used to be a special token kind for zero used to parser pure virtual function declarations.
		// But it turned out to be easier to just parse them as an init_declarator and programaticaly check
		// for pure virtual, see consumeMemberDeclaratorWithInitializer().
		
		//if(kind == CPPParsersym.TK_integer && "0".equals(getTokenText(i))) { //$NON-NLS-1$
		//	kind = CPPParsersym.TK_zero;
		//}
		
		// lexer feedback hack!
		//else if(kind == C99Parsersym.TK_identifier && action.resolver.isTypedef(getTokenText(i))) {
		//	kind = C99Parsersym.TK_TypedefName;
		//}
		
		return kind;
	}
	
	
	// uncomment this method to use with backtracking parser
	public List getRuleTokens() {
	    return Collections.unmodifiableList(getTokens().subList(getLeftSpan(), getRightSpan() + 1));
	}


./
$End


$Start
	translation_unit
$End



$Rules

------------------------------------------------------------------------------------------
-- AST  and Symbol Table Scoping
------------------------------------------------------------------------------------------


<openscope-ast> 
    ::= $empty
          /.$Action $Builder  openASTScope();  $EndBuilder $EndAction./ 
  
<openscope-symbol> 
    ::= $empty
       --   /.$Action $Resolve  openSymbolScope();  $EndResolve $EndAction./ 

<openscope-declaration> 
    ::= $empty
       --   /.$Action $Resolve  openDeclarationScope();  $EndResolve $EndAction./ 

<placeholder>
    ::= $empty 
           /.$Action $Builder  consumePlaceHolder();  $EndBuilder $EndAction./ 

<empty>
    ::= $empty 
           /.$Action $Builder  consumeEmpty();  $EndBuilder $EndAction./ 
           
------------------------------------------------------------------------------------------
-- 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'




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


translation_unit
    ::= declaration_seq
          /. $Build  consumeTranslationUnit(); $EndBuild ./
      | $empty
          /. $Build  consumeTranslationUnit(); $EndBuild ./

--expression_as_translation_unit
--    ::= expression
--          /. $Build  consumeExpressionAsTranslationUnit(); $EndBuild ./


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

literal
    ::= 'integer'
           /. $Build  consumeExpressionLiteral(ICPPASTLiteralExpression.lk_integer_constant); $EndBuild ./
      | '0'
           /. $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
      | '~' class_name
          /. $Build  consumeDestructorName();  $EndBuild ./


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

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


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


-- this is a compound name
qualified_id_name
    ::= dcolon_opt nested_name_specifier template_opt unqualified_id_name
          /. $Build  consumeQualifiedId(true);  $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


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 '::' '~' type_name
          /. $Build  consumePsudoDestructorName(true);  $EndBuild ./
      | dcolon_opt nested_name_specifier 'template' template_id_name '::' '~' type_name
          /. $Build  consumePsudoDestructorName(true);  $EndBuild ./
      | dcolon_opt nested_name_specifier_opt '~' type_name
          /. $Build  consumePsudoDestructorName(false);  $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 -- done
    ::= dcolon_opt 'new' new_placement_opt new_type_id <openscope-ast> new_array_expressions_opt new_initializer_opt
          /. $Build  consumeExpressionNew(false);  $EndBuild ./
      | dcolon_opt 'new' new_placement_opt '(' type_id ')' new_initializer_opt
          /. $Build  consumeExpressionNew(true);  $EndBuild ./


new_placement -- done
    ::= '(' expression_list ')'


new_placement_opt -- done
    ::= new_placement
      | $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 -- done
    ::= '(' expression_list_opt ')'  -- even if the parens are there we get null in the AST
    
    
new_initializer_opt -- done
    ::= 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 ./


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
------------------------------------------------------------------------------------------

-- TODO: declarations in conditions

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 ':' 
          /. $Build  consumeStatementCase();  $EndBuild ./
      | default ':'
          /. $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 ./


-- where did this come from?
--condition_opt
--    ::= condition
--      | $empty
--          /. $Build  consumeEmpty(); $EndBuild ./


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

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


declaration_statement
    ::= block_declaration
          /. $Build  consumeStatementDeclaration();  $EndBuild ./



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


declaration
    ::= block_declaration
      | function_definition         -- done
      | template_declaration        -- done
      | explicit_instantiation      -- done
      | explicit_specialization     -- done
      | linkage_specification       -- done
      | namespace_definition        -- done


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


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 ./
    

-- 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  consumeDeclSpecToken(); $EndBuild ./
      | 'typedef'
          /. $Build  consumeDeclSpecToken(); $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
      
      
-- 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'
      | 'register'
      | 'static'
      | 'extern'
      | 'mutable'


function_specifier
    ::= 'inline'
      | 'virtual'
      | 'explicit'


typedef_name
    ::= 'identifier'


--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  consumeDeclSpecToken(); $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      -- identifier
      | 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 ./


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


enum_name
    ::= 'identifier'


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


enumerator_list
    ::= enumerator_definition
      | enumerator_list ',' enumerator_definition


enumerator_list_opt
    ::= enumerator_list
      | $empty


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


enumerator
    ::= 'identifier'


namespace_name
    ::= original_namespace_name
      | namespace_alias


original_namespace_name
    ::= 'identifier'


namespace_definition
    ::= named_namespace_definition
      | unnamed_namespace_definition


named_namespace_definition
    ::= original_namespace_definition
      | extension_namespace_definition


original_namespace_definition
    ::= 'namespace' identifier_name '{' <openscope-ast> declaration_seq_opt '}'
          /. $Build  consumeNamespaceDefinition(true);  $EndBuild ./


extension_namespace_definition
    ::= 'namespace' original_namespace_name '{' <openscope-ast> declaration_seq_opt '}'
          /. $Build  consumeNamespaceDefinition(true);  $EndBuild ./


unnamed_namespace_definition
    ::= 'namespace' '{' <openscope-ast> declaration_seq_opt '}'
           /. $Build  consumeNamespaceDefinition(false);  $EndBuild ./


namespace_alias
    ::= 'identifier'


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

--qualified_namespace_specifier
--    ::= dcolon_opt nested_name_specifier_opt namespace_name


-- make more lenient!
-- using_declaration
--     ::= 'using' typename_opt dcolon_opt nested_name_specifier unqualified_id_name ';'
--       | 'using' '::' unqualified_id_name ';'
      
      
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
      | init_declarator_list ',' init_declarator


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


declarator
    ::= 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
    ::= '*' <openscope-ast> cv_qualifier_seq_opt
          /. $Build  consumePointer();  $EndBuild ./
      | '&'
          /. $Build  consumeReferenceOperator();  $EndBuild ./
      | dcolon_opt nested_name_specifier '*' <openscope-ast> cv_qualifier_seq_opt
          /. $Build  consumePointerToMember();  $EndBuild ./


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  consumeDeclSpecToken(); $EndBuild ./
      | 'volatile'
          /. $Build  consumeDeclSpecToken(); $EndBuild ./


declarator_id_name
    ::= qualified_or_unqualified_name
      | dcolon_opt nested_name_specifier_opt type_name
          /. $Build  consumeQualifiedId(false);  $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
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 ./
          

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_direct_declarator <openscope-ast> ctor_initializer_list_opt function_body
           /. $Build  consumeFunctionDefinition(false);  $EndBuild ./
      | declaration_specifiers_opt function_direct_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 ./
      | '{' <openscope-ast> initializer_list ',' '}'
         /. $Build  consumeInitializerList();  $EndBuild ./
      | '{' <openscope-ast> initializer_list '}'
         /. $Build  consumeInitializerList();  $EndBuild ./
      | '{' <openscope-ast> '}'
         /. $Build  consumeInitializerList();  $EndBuild ./


initializer_list
    ::= initializer_clause
      | initializer_list ',' initializer_clause


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


class_name
    ::= identifier_name
      | template_id_name


class_specifier -- done
    ::= class_head '{' <openscope-ast> member_declaration_list_opt '}'
          /.  $Build  consumeClassSpecifier();  $EndBuild ./


class_head -- done
    ::= class_keyword identifier_name_opt <openscope-ast> base_clause_opt
          /. $Build  consumeClassHead(false);  $EndBuild ./
      | class_keyword template_id_name <openscope-ast> base_clause_opt
          /. $Build  consumeClassHead(false);  $EndBuild ./
      | class_keyword nested_name_specifier identifier_name <openscope-ast> base_clause_opt
          /. $Build  consumeClassHead(true);  $EndBuild ./
      | class_keyword nested_name_specifier template_id_name <openscope-ast> base_clause_opt
          /. $Build  consumeClassHead(true);  $EndBuild ./


identifier_opt
    ::= 'identifier'
      | $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 ';'  -- done
      | function_definition      -- done
      | dcolon_opt nested_name_specifier template_opt unqualified_id_name ';'
          /. $Build  consumeMemberDeclarationQualifiedId();  $EndBuild ./ 
      | using_declaration  -- done
      | template_declaration
      | visibility_label  -- done




member_declaration_list
    ::= member_declaration
      | member_declaration_list member_declaration


member_declaration_list_opt
    ::= member_declaration_list
      | $empty


member_declarator_list
    ::= member_declarator
      | member_declarator_list ',' member_declarator


member_declarator
    ::= declarator
      -- | declarator pure_specifier  -- parse this as a constant initializer
      | 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 ./
          

--pure_specifier -- this leads to ambiguities
--    ::= '=' '0'


constant_initializer
    ::= '=' constant_expression


base_clause
    ::= ':' base_specifier_list


base_clause_opt
    ::= base_clause
      | $empty 
    

base_specifier_list
    ::= base_specifier
      | base_specifier_list ',' base_specifier


-- make this more lenient, allow virtual both before and after
base_specifier
    ::= dcolon_opt nested_name_specifier_opt class_name
          /. $Build  consumeBaseSpecifier(false);  $EndBuild ./
      | virtual_opt access_specifier_keyword virtual_opt dcolon_opt nested_name_specifier_opt class_name
          /. $Build  consumeBaseSpecifier(true);  $EndBuild ./


virtual_opt
    ::= 'virtual' 
          /. $Build  consumePlaceHolder();  $EndBuild ./
      | $empty
          /. $Build  consumeEmpty();  $EndBuild ./
      

access_specifier_keyword
    ::= 'private'
      | 'protected'
      | 'public'


access_specifier_keyword_opt
    ::= access_specifier_keyword
      | $empty


conversion_function_id_name
    ::= '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


template_parameter
    ::= type_parameter
      | parameter_declaration


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 ./


-- pushes name node on stack
template_id_name
    ::= template_identifier '<' <openscope-ast> template_argument_list_opt '>'
          /. $Build  consumeTemplateId();  $EndBuild ./

template_identifier
    ::= 'identifier'


template_argument_list
    ::= template_argument
      | template_argument_list ',' template_argument


template_argument_list_opt
    ::= template_argument_list
      | $empty
      

template_argument
    ::= assignment_expression
      | type_id
      | qualified_or_unqualified_name


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();  $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' '('  ')'


exception_specification_opt
    ::= exception_specification
      | $empty


type_id_list
    ::= type_id
      | type_id_list ',' type_id

Back to the top