// cc2.gr            see license.txt for copyright and terms of use
// starting over with a C++ grammar
// working from ISO/IEC 14882:1998(E)

option useGCDefaults;

verbatim [

#include "ptreenode.h"    // PTreeNode

]

context_class CC2 : public UserActions {
public:
  CC2() {}
};


terminals {
  // grab list generated by lexer
  include("c/c.tok")
}


// start symbol
nonterm StartSymbol -> TranslationUnit;


// map from my lexer's names into the Standard's names
nonterm Identifier -> L2_NAME;

nonterm IntegerLiteral -> L2_INT_LITERAL;

nonterm CharacterLiteral -> L2_CHAR_LITERAL;

nonterm FloatingLiteral -> L2_FLOAT_LITERAL;

nonterm StringLiteral -> L2_STRING_LITERAL;

nonterm BooleanLiteral {
  -> "true";
  -> "false";
}


// -------------------- A.1 Keywords --------------------

nonterm TypedefName {
  -> Identifier;
}

nonterm NamespaceName {
  -> OriginalNamespaceName;
  -> NamespaceAlias;
}

nonterm OriginalNamespaceName {
  -> Identifier;
}

nonterm NamespaceAlias {
  -> Identifier;
}

nonterm ClassName {
  -> Identifier;
  -> TemplateId;
}

nonterm EnumName {
  -> Identifier;
}

nonterm TemplateName {
  -> Identifier;
}


// -------------------- A.2 Lexical conventions --------------------

// since I assume the use of a conventional lexical analyzer, I don't
// reproduce all of the rules from the standard here; instead I list
// the tokens I assume will be exported by the lexer:

//   Identifier
//   IntegerLiteral
//   CharacterLiteral
//   FloatingLiteral
//   StringLiteral
//   BooleanLiteral
//   keywords: "this", "if", ...
//   operators: "+", "-", ...
//   punctuators: "(", ")", ";", ...

nonterm Literal {
  -> IntegerLiteral;
  -> CharacterLiteral;
  -> FloatingLiteral;
  -> StringLiteral;
  -> BooleanLiteral;
}


// -------------------- A.3 Basic concepts --------------------

nonterm TranslationUnit {
  -> DeclarationSeqOpt;
}


// -------------------- A.4 Expressions --------------------

nonterm PrimaryExpression {
  -> Literal;
  -> "this";
  -> "(" Expression ")";
  -> IdExpression;
}

nonterm IdExpression {
  -> UnqualifiedId;
  -> QualifiedId;
}

nonterm UnqualifiedId {
  -> Identifier;
  -> OperatorFunctionId;
  -> ConversionFunctionId;
  -> "~" ClassName;
  -> TemplateId;
}

nonterm ColonColonOpt {
  -> empty;
  -> "::";
}

nonterm TemplateOpt {
  -> empty;
  -> "template";
}

nonterm QualifiedId {
  -> ColonColonOpt NestedNameSpecifier TemplateOpt UnqualifiedId;
  -> "::" Identifier;
  -> "::" OperatorFunctionId;
  -> "::" TemplateId;
}

nonterm NestedNameSpecifierOpt {
  -> empty;
  -> NestedNameSpecifier;
}

nonterm NestedNameSpecifier {
  -> ClassOrNamespaceName "::" NestedNameSpecifierOpt;
  -> ClassOrNamespaceName "::" "template" NestedNameSpecifier;
}

nonterm ClassOrNamespaceName {
  -> ClassName;
  -> NamespaceName;
}                                                

nonterm ExpressionListOpt {
  -> empty;
  -> ExpressionList;
}

nonterm PostfixExpression {
  fun merge(l,r) [ return l; ]

  -> PrimaryExpression;
  -> PostfixExpression "[" Expression "]";
  -> PostfixExpression "(" ExpressionListOpt ")";
  -> SimpleTypeSpecifier "(" ExpressionListOpt ")";
  -> "typename" ColonColonOpt NestedNameSpecifier Identifier "(" ExpressionListOpt ")";
  -> "typename" ColonColonOpt NestedNameSpecifier TemplateOpt TemplateId "(" ExpressionListOpt ")";
  -> PostfixExpression "." TemplateOpt IdExpression;
  -> PostfixExpression "->" TemplateOpt IdExpression;
  -> PostfixExpression "." PseudoDestructorName;
  -> PostfixExpression "->" PseudoDestructorName;
  -> PostfixExpression "++";
  -> PostfixExpression "--";
  -> "dynamic_cast"     "<" TypeId ">" "(" Expression ")";
  -> "static_cast"      "<" TypeId ">" "(" Expression ")";
  -> "reinterpret_cast" "<" TypeId ">" "(" Expression ")";
  -> "const_cast"       "<" TypeId ">" "(" Expression ")";
  -> "typeid" "(" Expression ")";
  -> "typeid" "(" TypeId ")";
}

nonterm ExpressionList {
  -> AssignmentExpression;
  -> ExpressionList "," AssignmentExpression;
}

nonterm PseudoDestructorName {
  -> ColonColonOpt NestedNameSpecifierOpt TypeName "::" "~" TypeName;
  -> ColonColonOpt NestedNameSpecifier "template" TemplateId "::" "~" TypeName;
  -> ColonColonOpt NestedNameSpecifierOpt "~" TypeName;
}

nonterm UnaryExpression {
  fun merge(l,r) [ return l; ]

  -> PostfixExpression;
  -> "++" CastExpression;
  -> "--" CastExpression;
  -> UnaryOperator CastExpression;
  -> "sizeof" UnaryExpression;
  -> "sizeof" "(" TypeId ")";
  -> NewExpression;
  -> DeleteExpression;
}

nonterm UnaryOperator {
  -> "*";
  -> "&";
  -> "+";
  -> "-";
  -> "!";
  -> "~";
}
  
nonterm NewPlacementOpt {
  -> empty;
  -> NewPlacement;
}

nonterm NewInitializerOpt {
  -> empty;
  -> NewInitializer;
}

nonterm NewExpression {
  -> ColonColonOpt "new" NewPlacementOpt NewTypeId NewInitializerOpt;
  -> ColonColonOpt "new" NewPlacementOpt "(" TypeId ")" NewInitializerOpt;
}

nonterm NewPlacement {
  -> "(" ExpressionList ")";
}                           

nonterm NewDeclaratorOpt {
  -> empty;
  -> NewDeclarator;
}

nonterm NewTypeId {
  -> TypeSpecifierSeq NewDeclaratorOpt;
}

nonterm NewDeclarator {
  -> PtrOperator NewDeclaratorOpt;
  -> DirectNewDeclarator;
}

nonterm DirectNewDeclarator {
  -> "[" Expression "]";
  -> DirectNewDeclarator "[" ConstantExpression "]";
}

nonterm NewInitializer {
  -> "(" ExpressionListOpt ")";
}

nonterm DeleteExpression {
  -> ColonColonOpt "delete" CastExpression;
  -> ColonColonOpt "delete" "[" "]" CastExpression;
}

nonterm CastExpression {
  fun merge(l,r) [ return l; ]

  -> UnaryExpression;
  -> "(" TypeId ")" CastExpression;
}

nonterm PmExpression {
  -> CastExpression;
  -> PmExpression ".*" CastExpression;
  -> PmExpression "->*" CastExpression;
}

nonterm MultiplicativeExpression {
  -> PmExpression;
  -> MultiplicativeExpression "*" PmExpression;
  -> MultiplicativeExpression "/" PmExpression;
  -> MultiplicativeExpression "%" PmExpression;
}

nonterm AdditiveExpression {
  fun merge(l,r) [ return l; ]

  -> MultiplicativeExpression;
  -> AdditiveExpression "+" MultiplicativeExpression;
  -> AdditiveExpression "-" MultiplicativeExpression;
}

nonterm ShiftExpression {
  -> AdditiveExpression;
  -> ShiftExpression "<<" AdditiveExpression;
  -> ShiftExpression ">>" AdditiveExpression;
}

nonterm RelationalExpression {
  fun merge(l,r) { return l; }

  -> ShiftExpression;
  -> RelationalExpression "<" ShiftExpression;
  -> RelationalExpression ">" ShiftExpression;
  -> RelationalExpression "<=" ShiftExpression;
  -> RelationalExpression ">=" ShiftExpression;
}

nonterm EqualityExpression {
  -> RelationalExpression;
  -> EqualityExpression "==" RelationalExpression;
  -> EqualityExpression "!=" RelationalExpression;
}

nonterm AndExpression {
  fun merge(l,r) [ return l; ]

  -> EqualityExpression;
  -> AndExpression "&" EqualityExpression;
}

nonterm ExclusiveOrExpression {
  -> AndExpression;
  -> ExclusiveOrExpression "^" AndExpression;
}

nonterm InclusiveOrExpression {
  -> ExclusiveOrExpression;
  -> InclusiveOrExpression "|" ExclusiveOrExpression;
}

nonterm LogicalAndExpression {
  -> InclusiveOrExpression;
  -> LogicalAndExpression "&&" InclusiveOrExpression;
}

nonterm LogicalOrExpression {
  -> LogicalAndExpression;
  -> LogicalOrExpression "||" LogicalAndExpression;
}

nonterm ConditionalExpression {
  -> LogicalOrExpression;
  -> LogicalOrExpression "?" Expression ":" AssignmentExpression;
}

nonterm AssignmentExpression {
  -> ConditionalExpression;
  -> LogicalOrExpression AssignmentOperator AssignmentExpression;
  -> ThrowExpression;
}

nonterm AssignmentOperator {
  -> "=";
  -> "*=";
  -> "/=";
  -> "%=";
  -> "+=";
  -> "-=";
  -> ">>=";
  -> "<<=";
  -> "&=";
  -> "^=";
  -> "|=";
}

nonterm Expression {
  -> AssignmentExpression;
  -> Expression "," AssignmentExpression;
}

nonterm ConstantExpression {
  -> ConditionalExpression;
}


// -------------------- A.5 Statements --------------------

nonterm Statement {
  fun merge(l,r) [ return l; ]

  -> LabeledStatement;
  -> ExpressionStatement;
  -> CompoundStatement;
  -> SelectionStatement;
  -> IterationStatement;
  -> JumpStatement;
  -> DeclarationStatement;
  -> TryBlock;
}

nonterm LabeledStatement {
  -> Identifier ":" Statement;
  -> "case" ConstantExpression ":" Statement;
  -> "default" ":" Statement;      // note: linux kernel contains "switch (..) { ... default: }" ..
}

nonterm ExpressionOpt {
  -> empty;
  -> Expression;
}

nonterm ExpressionStatement {
  -> ExpressionOpt ";";
}

nonterm StatementSeqOpt {
  -> empty;
  -> StatementSeq;
}

nonterm CompoundStatement {
  -> "{" StatementSeqOpt "}";
}

nonterm StatementSeq {
  -> Statement;
  -> StatementSeq Statement;
}

nonterm SelectionStatement {
  -> "if" "(" Condition ")" Statement;
  -> "if" "(" Condition ")" Statement "else" Statement;
  -> "switch" "(" Condition ")" Statement;
}

nonterm Condition {
  -> Expression;
  -> TypeSpecifierSeq Declarator "=" AssignmentExpression;     // ?
}
  
nonterm ConditionOpt {
  -> empty;
  -> Condition;
}

nonterm IterationStatement {
  -> "while" "(" Condition ")" Statement;
  -> "do" Statement "while" "(" Expression ")" ";";
  -> "for" "(" ForInitStatement ConditionOpt ";" ExpressionOpt ")" Statement;
}

nonterm ForInitStatement {
  fun merge(l,r) [ return l; ]

  -> ExpressionStatement;
  -> SimpleDeclaration;
}

nonterm JumpStatement {
  -> "break" ";";
  -> "continue" ";";
  -> "return" ExpressionOpt ";";
  -> "goto" Identifier ";";
}

nonterm DeclarationStatement {
  -> BlockDeclaration;
}


// -------------------- A.6 Declarations --------------------

nonterm DeclarationSeq {
  -> Declaration;
  -> DeclarationSeq Declaration;
}

nonterm Declaration {
  -> BlockDeclaration;
  -> FunctionDefinition;
  -> TemplateDeclaration;
  -> ExplicitInstantiation;
  -> ExplicitSpecialization;
  -> LinkageSpecification;
  -> NamespaceDefinition;
}

nonterm BlockDeclaration {
  -> SimpleDeclaration;
  -> AsmDefinition;
  -> NamespaceAliasDefinition;
  -> UsingDeclaration;
  -> UsingDirective;
}

nonterm DeclSpecifierSeqOpt {
  -> empty;
  -> DeclSpecifierSeq;
}

nonterm InitDeclaratorListOpt {
  -> empty;
  -> InitDeclaratorList;
}

// Q: why is the InitDeclaratorList optional?  "int ;" is not valid
// A: because we can say "class C { ... };"
//
// Q: for that matter, why is the DeclSpecifierSeq optional?  ";" is
// not a valid declaration (it's a statement)
// A: the declspecifierseq is missing for constructors
nonterm SimpleDeclaration {
  fun merge(l,r) [ return l; ]

  -> DeclSpecifierSeqOpt InitDeclaratorListOpt ";";
}

nonterm DeclSpecifier {
  -> StorageClassSpecifier;
  -> TypeSpecifier;
  -> FunctionSpecifier;
  -> "friend";
  -> "typedef";
}

nonterm DeclSpecifierSeq {
  -> DeclSpecifierSeqOpt DeclSpecifier;
}

nonterm StorageClassSpecifier {
  -> "auto";
  -> "register";
  -> "static";
  -> "extern";
  -> "mutable";
}

nonterm FunctionSpecifier {
  -> "inline";
  -> "virtual";
  -> "explicit";
}

// repeated in spec
//nonterm TypedefName {
//  -> Identifier;
//} 

nonterm TypeSpecifier {
  -> SimpleTypeSpecifier;
  -> ClassSpecifier;
  -> EnumSpecifier;
  -> ElaboratedTypeSpecifier;
  -> CvQualifier;
}

nonterm SimpleTypeSpecifier {
  -> ColonColonOpt NestedNameSpecifierOpt TypeName;
  -> ColonColonOpt NestedNameSpecifier "template" TemplateId;
  -> "char";
  -> "wchar_t";
  -> "bool";
  -> "short";
  -> "int";
  -> "long";
  -> "signed";
  -> "unsigned";
  -> "float";
  -> "double";
  -> "void";
}

nonterm TypeName {
  fun merge(l,r) [ return l; ]

  -> ClassName;
  -> EnumName;
  -> TypedefName;
}

nonterm ElaboratedTypeSpecifier {
  -> ClassKey ColonColonOpt NestedNameSpecifierOpt Identifier;
  -> "enum" ColonColonOpt NestedNameSpecifierOpt Identifier;
  -> "typename" ColonColonOpt NestedNameSpecifier Identifier;
  -> "typename" ColonColonOpt NestedNameSpecifier TemplateOpt TemplateId;
}

// this is repeated in the spec
//nonterm EnumName {
//  -> Identifier;
//}

nonterm IdentifierOpt {
  -> empty;
  -> Identifier;
}
        
nonterm EnumeratorListOpt {
  -> empty;
  -> EnumeratorList;
}

nonterm EnumSpecifier {
  -> "enum" IdentifierOpt "{" EnumeratorListOpt "}";
}

nonterm EnumeratorList {
  -> EnumeratorDefinition;
  -> EnumeratorList "," EnumeratorDefinition;
}

nonterm EnumeratorDefinition {
  -> Enumerator;
  -> Enumerator "=" ConstantExpression;
}

nonterm Enumerator {
  -> Identifier;
}

// repeated in spec
//nonterm NamespaceName {
//  -> OriginalNamespaceName;
//  -> NamespaceAlias;
//} 

// repeated in spec
//nonterm OriginalNamespaceName {
//  -> Identifier;
//} 

nonterm NamespaceDefinition {
  -> NamedNamespaceDefinition;
  -> UnnamedNamespaceDefinition;
}

nonterm NamedNamespaceDefinition {
  -> OriginalNamespaceDefinition;
  -> ExtensionNamespaceDefinition;
}

nonterm OriginalNamespaceDefinition {
  -> "namespace" Identifier "{" NamespaceBody "}";
}

nonterm ExtensionNamespaceDefinition {
  -> "namespace" OriginalNamespaceName "{" NamespaceBody "}";
}

nonterm UnnamedNamespaceDefinition {
  -> "namespace" "{" NamespaceBody "}";
}

nonterm DeclarationSeqOpt {
  -> empty;
  -> DeclarationSeq;
}

nonterm NamespaceBody {
  -> DeclarationSeqOpt;
}

// repeated in spec
//nonterm NamespaceAlias {
//  -> Identifier;
//} 

nonterm NamespaceAliasDefinition {
  -> "namespace" Identifier "=" QualifiedNamespaceSpecifier ";";
}

nonterm QualifiedNamespaceSpecifier {
  -> ColonColonOpt NestedNameSpecifierOpt NamespaceName;
}

nonterm TypenameOpt {
  -> empty;
  -> "typename";
}

nonterm UsingDeclaration {
  -> "using" TypenameOpt ColonColonOpt NestedNameSpecifier UnqualifiedId ";";
  -> "using" "::" UnqualifiedId ";";
}

nonterm UsingDirective {
  -> "using" "namespace" ColonColonOpt NestedNameSpecifierOpt NamespaceName ";";
}

nonterm AsmDefinition {
  -> "asm" "(" StringLiteral ")" ";";
}

nonterm LinkageSpecification {
  -> "extern" StringLiteral "{" DeclarationSeqOpt "}";
  -> "extern" StringLiteral Declaration;
}


// -------------------- A.7 Declarators --------------------

nonterm InitDeclaratorList {
  -> InitDeclarator;
  -> InitDeclaratorList "," InitDeclarator;
}

nonterm InitializerOpt {
  -> empty;
  -> Initializer;
}

nonterm InitDeclarator {
  fun merge(l,r) [ return l; ]

  -> Declarator InitializerOpt;
}

nonterm Declarator {
  -> DirectDeclarator;
  -> PtrOperator Declarator;
}

nonterm CvQualifierSeqOpt {
  -> empty;
  -> CvQualifierSeq;
}

nonterm ExceptionSpecificationOpt {
  -> empty;
  -> ExceptionSpecification;
}

nonterm ConstantExpressionOpt {
  -> empty;
  -> ConstantExpression;
}

nonterm DirectDeclarator {
  -> DeclaratorId;
  -> DirectDeclarator "(" ParameterDeclarationClause ")" CvQualifierSeqOpt ExceptionSpecificationOpt;
  -> DirectDeclarator "[" ConstantExpressionOpt "]";
  -> "(" Declarator ")";
}

nonterm PtrOperator {
  -> "*" CvQualifierSeqOpt;
  -> "&";
  -> ColonColonOpt NestedNameSpecifier "*" CvQualifierSeqOpt;     // pointer to member
}

nonterm CvQualifierSeq {
  -> CvQualifier CvQualifierSeqOpt;
}

nonterm CvQualifier {
  -> "const";
  -> "volatile";
}

nonterm DeclaratorId {
  fun merge(l,r) [ return l; ]

  -> IdExpression;
  -> ColonColonOpt NestedNameSpecifierOpt TypeName;
}

nonterm AbstractDeclaratorOpt {
  -> empty;
  -> AbstractDeclarator;
}

nonterm TypeId {
  -> TypeSpecifierSeq AbstractDeclaratorOpt;
}

nonterm TypeSpecifierSeqOpt {
  -> empty;
  -> TypeSpecifierSeq;
}

nonterm TypeSpecifierSeq {
  -> TypeSpecifier TypeSpecifierSeqOpt;
}

nonterm AbstractDeclarator {
  -> PtrOperator AbstractDeclaratorOpt;
  -> DirectAbstractDeclarator;
}
     
nonterm DirectAbstractDeclaratorOpt {
  -> empty;
  -> DirectAbstractDeclarator;
}

nonterm DirectAbstractDeclarator {
  -> DirectAbstractDeclaratorOpt "(" ParameterDeclarationClause ")" CvQualifierSeqOpt ExceptionSpecificationOpt;
  -> DirectAbstractDeclaratorOpt "[" ConstantExpressionOpt "]";
  -> "(" AbstractDeclarator ")";
}

nonterm ParameterDeclarationListOpt {
  -> empty;
  -> ParameterDeclarationList;
}

nonterm EllipsisOpt {
  -> empty;
  -> "...";
}

nonterm ParameterDeclarationClause {
  -> ParameterDeclarationListOpt EllipsisOpt;
  -> ParameterDeclarationList "," "...";
}

nonterm ParameterDeclarationList {
  -> ParameterDeclaration;
  -> ParameterDeclarationList "," ParameterDeclaration;
}

nonterm ParameterDeclaration {
  fun merge(l,r) [ return l; ]

  -> DeclSpecifierSeq Declarator;
  -> DeclSpecifierSeq Declarator "=" AssignmentExpression;
  -> DeclSpecifierSeq AbstractDeclaratorOpt;
  -> DeclSpecifierSeq AbstractDeclaratorOpt "=" AssignmentExpression;
}

nonterm CtorInitializerOpt {
  -> empty;
  -> CtorInitializer;
}

nonterm FunctionDefinition {
  -> DeclSpecifierSeqOpt Declarator CtorInitializerOpt FunctionBody;
  -> DeclSpecifierSeqOpt Declarator FunctionTryBlock;
}

nonterm FunctionBody {
  -> CompoundStatement;
}

nonterm Initializer {
  -> "=" InitializerClause;
  -> "(" ExpressionList ")";
}

nonterm CommaOpt {
  -> empty;
  -> ",";
}

nonterm InitializerClause {
  -> AssignmentExpression;
  -> "{" InitializerList CommaOpt "}";
  -> "{" "}";
}

nonterm InitializerList {
  -> InitializerClause;
  -> InitializerList "," InitializerClause;
}


// -------------------- A.8 Classes --------------------

// repeated in spec
//nonterm ClassName {
//  -> Identifier;
//  -> TemplateId;
//} 

nonterm MemberSpecificationOpt {
  -> empty;
  -> MemberSpecification;
}

nonterm ClassSpecifier {
  -> ClassHead "{" MemberSpecificationOpt "}";
}

nonterm BaseClauseOpt {
  -> empty;
  -> BaseClause;
}

nonterm ClassHead {
  -> ClassKey IdentifierOpt BaseClauseOpt;
  -> ClassKey NestedNameSpecifier Identifier BaseClauseOpt;
  -> ClassKey NestedNameSpecifierOpt TemplateId BaseClauseOpt;
}

nonterm ClassKey {
  -> "class";
  -> "struct";
  -> "union";
}
  
nonterm MemberSpecification {
  -> MemberDeclaration MemberSpecificationOpt;
  -> AccessSpecifier ":" MemberSpecificationOpt;
}

nonterm MemberDeclaratorListOpt {
  -> empty;
  -> MemberDeclaratorList;
}
  
nonterm SemicolonOpt {
  -> empty;
  -> ";";
}

nonterm MemberDeclaration {
  fun merge(l,r) [ return l; ]

  -> DeclSpecifierSeqOpt MemberDeclaratorListOpt ";";
  -> FunctionDefinition SemicolonOpt;
  -> ColonColonOpt NestedNameSpecifier TemplateOpt UnqualifiedId ";";
  -> UsingDeclaration;
  -> TemplateDeclaration;
}

nonterm MemberDeclaratorList {
  -> MemberDeclarator;
  -> MemberDeclaratorList "," MemberDeclarator;
}

nonterm PureSpecifierOpt {
  -> empty;
  -> PureSpecifier;
}

nonterm ConstantInitializerOpt {
  -> empty;
  -> ConstantInitializer;
}

nonterm MemberDeclarator {
  fun merge(l,r) [ return l; ]

  -> Declarator PureSpecifierOpt;           // for when declarator is a function type
  -> Declarator ConstantInitializerOpt;     // for when it is any other type
  -> IdentifierOpt ":" ConstantExpression;  // bitfield with optional name
}

nonterm PureSpecifier {
  -> "=" IntegerLiteral;         // standard says "0" here but that's not one of my tokens..
}

nonterm ConstantInitializer{ 
  -> "=" ConstantExpression;
}


// -------------------- A.9 Derived classes --------------------

nonterm BaseClause {
  -> ":" BaseSpecifierList;
}

nonterm BaseSpecifierList {
  -> BaseSpecifier;
  -> BaseSpecifierList "," BaseSpecifier;
}
 
// Q: is there a nonterminal called "virtual"?
// A: no.  the standard uses the wrong font for "virtual" in the base-specifier rules
nonterm VirtualOpt {
  -> empty;
  -> "virtual";
}

nonterm AccessSpecifierOpt {
  -> empty;
  -> AccessSpecifier;
}

nonterm BaseSpecifier {
  -> ColonColonOpt NestedNameSpecifierOpt ClassName;
  -> "virtual" AccessSpecifierOpt ColonColonOpt NestedNameSpecifierOpt ClassName;
  -> AccessSpecifier VirtualOpt   ColonColonOpt NestedNameSpecifierOpt ClassName;
}

nonterm AccessSpecifier {
  -> "private";
  -> "protected";
  -> "public";
}


// -------------------- A.10 Special member functions --------------------

nonterm ConversionFunctionId {
  -> "operator" ConversionTypeId;
}

nonterm ConversionDeclaratorOpt {
  -> empty;
  -> ConversionDeclarator;
}

nonterm ConversionTypeId {
  -> TypeSpecifierSeq ConversionDeclaratorOpt;
}

nonterm ConversionDeclarator {
  -> PtrOperator ConversionDeclaratorOpt;
}

nonterm CtorInitializer {
  -> ":" MemInitializerList;
}

// Q: why right recursion?
nonterm MemInitializerList {
  -> MemInitializer;
  -> MemInitializer "," MemInitializerList;
}                                          

// Q: what is a mem-initializer?
// A: "member initializer", in constructors after the ":" but before "{"
nonterm MemInitializer {
  -> MemInitializerId "(" ExpressionListOpt ")";
}

nonterm MemInitializerId {
  fun merge(l,r) { return l; }

  -> ColonColonOpt NestedNameSpecifierOpt ClassName;
  -> Identifier;
}


// -------------------- A.11 Overloading --------------------

nonterm OperatorFunctionId {
  -> "operator" Operator;
}

nonterm Operator {
  -> "new";
  -> "delete";
  -> "new" "[" "]";
  -> "delete" "[" "]";
  -> "+";
  -> "-";
  -> "*";
  -> "/";
  -> "%";
  -> "^";
  -> "&";
  -> "|";
  -> "~";
  -> "!";
  -> "=";
  -> "<";
  -> ">";
  -> "+=";
  -> "-=";
  -> "*=";
  -> "/=";
  -> "%=";
  -> "^=";
  -> "&=";
  -> "|=";
  -> "<<";
  -> ">>";
  -> ">>=";
  -> "<<=";
  -> "==";
  -> "!=";
  -> "<=";
  -> ">=";
  -> "&&";
  -> "||";
  -> "++";
  -> "--";
  -> ",";
  -> "->*";
  -> "->";
  -> "(" ")";
  -> "[" "]";
}


// -------------------- A.12 Templates --------------------

nonterm ExportOpt {
  -> empty;
  -> "export";
}

nonterm TemplateDeclaration {
  -> ExportOpt "template" "<" TemplateParameterList ">" Declaration;
}

nonterm TemplateParameterList {
  -> TemplateParameter;
  -> TemplateParameterList "," TemplateParameter;
}

nonterm TemplateParameter {
  fun merge(l,r) { return l; }

  -> TypeParameter;
  -> ParameterDeclaration;
}

nonterm TypeParameter {
  -> "class" IdentifierOpt;
  -> "class" IdentifierOpt "=" TypeId;
  -> "typename" IdentifierOpt;
  -> "typename" IdentifierOpt "=" TypeId;
  -> "template" "<" TemplateParameterList ">" "class" IdentifierOpt;
  -> "template" "<" TemplateParameterList ">" "class" IdentifierOpt "=" IdExpression;
}

nonterm TemplateArgumentListOpt {
  -> empty;
  -> TemplateArgumentList;
}

nonterm TemplateId {
  -> TemplateName "<" TemplateArgumentListOpt ">";
}

// repeated in spec
//nonterm TemplateName {
//  -> Identifier;
//} 

nonterm TemplateArgumentList {
  -> TemplateArgument;
  -> TemplateArgumentList "," TemplateArgument;
}

nonterm TemplateArgument {
  fun merge(l,r) [ return l; ]

  -> AssignmentExpression;
  -> TypeId;
  -> IdExpression;
}

nonterm ExplicitInstantiation {
  -> "template" Declaration;
}

nonterm ExplicitSpecialization {
  -> "template" "<" ">" Declaration;
}


// -------------------- A.13 Exception handling --------------------

nonterm TryBlock {
  -> "try" CompoundStatement HandlerSeq;
}

nonterm FunctionTryBlock {
  -> "try" CtorInitializerOpt FunctionBody HandlerSeq;
}

nonterm HandlerSeqOpt {
  -> empty;
  -> HandlerSeq;
}

// Q: why did they choose to use right recursion for this one?  all of
// the other sequences use left recursion..
nonterm HandlerSeq {
  -> Handler HandlerSeqOpt;
}

nonterm Handler {
  -> "catch" "(" ExceptionDeclaration ")" CompoundStatement;
}

nonterm ExceptionDeclaration {
  -> TypeSpecifierSeq Declarator;
  -> TypeSpecifierSeq AbstractDeclarator;
  -> TypeSpecifierSeq;
  -> "...";
}

nonterm AssignmentExpressionOpt {
  -> empty;
  -> AssignmentExpression;
}

nonterm ThrowExpression {
  -> "throw" AssignmentExpressionOpt;
}

nonterm TypeIdListOpt {
  -> empty;
  -> TypeIdList;
}

nonterm ExceptionSpecification {
  -> "throw" "(" TypeIdListOpt ")";
}

nonterm TypeIdList {
  -> TypeId;
  -> TypeIdList "," TypeId;
}


// A.14 Preprocessing directives: deferring to separate preprocessor


























