Open Watcom的C++语法

/
*

  •                        Open Watcom Project
    
    *
  • Portions Copyright (c) 1983-2002 Sybase, Inc. All Rights Reserved.
    *
  • ========================================================================
    *
  • This file contains Original Code and/or Modifications of Original
  • Code as defined in and that are subject to the Sybase Open Watcom
  • Public License version 1.0 (the 'License'). You may not use this file
  • except in compliance with the License. BY USING THIS FILE YOU AGREE TO
  • ALL TERMS AND CONDITIONS OF THE LICENSE. A copy of the License is
  • provided with the Original Code and Modifications, and is also
  • available at www.sybase.com/developer/opensource.
    *
  • The Original Code and all software distributed under the License are
  • distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
  • EXPRESS OR IMPLIED, AND SYBASE AND ALL CONTRIBUTORS HEREBY DISCLAIM
  • ALL SUCH WARRANTIES, INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF
  • MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR
  • NON-INFRINGEMENT. Please see the License for the specific language
  • governing rights and limitations under the License.
    *
  • ========================================================================
    *
  • Description: PLUSPLUS.Y : description of C++ syntax

Modified By Reason

92/10/02 Greg Bentz Initial version, shipped as “alpha”

            Jim Randall
            Anthony Scian
            Jim Welch

92/10/02 A.F.Scian changed cast-expression to use MakeNormalCast so

                            we can distinguish programmer specified casts

92/10/15 A.F.Scian added new keywords _stdcall, Syscall, _Packed,

                            and _Seg16

92/10/16 A.F.Scian - added _Packed semantic actions for OS/2

                            - added _Seg16 semantic actions for OS/2
                            - made far16 equivalent to far for 16-bit compiler
                            - made syscall and stdcall equivalent to cdecl
                              for 16-bit compiler

92/10/22 A.F.Scian instead of parsing one global declaration at a

                            time and accepting the tokens, parse all of the
                            global declarations before accepting

92/10/23 A.F.Scian made interrupt a flag instead of a calling convention
92/10/28 A.F.Scian used direct access to standard calling conventions
92/10/29 A.F.Scian - treat exception decls just like arguments

                            - corrected throw to have an optional expr

92/12/01 A.F.Scian added better error messages for missing ';'
92/12/04 A.F.Scian added optional size expression for delete []
93/01/07 A.F.Scian changed precedence of :> operator to just less

                            than a cast

93/01/27 A.F.Scian added support for '::'
93/01/31 A.F.Scian removed kludge to define class template symbols
93/02/08 A.F.Scian fixed problem with “struct T ” followed by id
93/02/09 A.F.Scian added calls to zapTemplateClassDeclSpec

                            (see YYDRIVER.C for explanation)

93/03/11 J.W.Welch New messaging
93/03/16 A.F.Scian streamlined member-declarator to directly call

                            DeclNoInit instead of going through DataInitNoInit

93/03/29 A.F.Scian added semantics for “new (int [x+1])” 5.3.3

                            "The first array dimension can be a general
                             integral expression even when <type-id> is used"

93/04/20 A.F.Scian added rules for y_template_scoped_typename to

                            handle nested types inside of templates

93/04/21 A.F.Scian fixed actions for function-declaration to not

                            pop the GS_DECL_SPEC stack until the function
                            body is processed (this allows any linkage on
                            the function symbol to be retained for the
                            entire processing of the function body)

93/07/13 A.F.Scian - added more than one pointer declarator to

                              conversion function ids
                            - fixed concatenation of strings so that the
                              type of the result is correct

93/07/29 A.F.Scian it was impossible to tell the difference between

                            no parms and ( void ) (both had parms == NULL)
                            so code now calls AddExplicitParms which handles
                            the problem by setting a bit in the DECL_INFO

93/08/11 A.F.Scian allow multiple ;'s in member decl lists

                            e.g., struct S { int a;;;; void foo(){};;; };

93/12/01 A.F.Scian added %ambig directives supported by new YACC
93/12/15 A.F.Scian added operator new []/operator delete [] support
94/03/23 A.F.Scian set up so that class S ; doesn't define the

                            class

94/04/18 A.F.Scian added support for “class export stdcall X”
94/04/19 A.F.Scian push some calls to FreeDeclInfo into functions

                            that are called before

94/06/08 A.F.Scian improved error message location for missing ';'

                            error messages

94/10/14 A.F.Scian added __declspec( )
94/10/18 A.F.Scian added kludge to support:

                            typedef struct S { } S, const *CPS;
                                                    ^^^^^- accept this

94/10/25 A.F.Scian upgrade LHS of assignment-expr so that it

                            accepts casts and pm-exprs

94/11/02 A.F.Scian added support for “class __declspec(dllimport) X”
94/12/07 A.F.Scian added Y_GLOBAL_ID as a valid declarator-id so

                            struct S { friend int ::foo( int ); }; works

95/02/23 A.F.Scian added builtin_isfloat( ) construct
95/04/28 A.F.Scian added
unaligned modifier
95/05/16 A.F.Scian added class template directives
95/06/28 A.F.Scian added more general offsetof field expressions
96/01/10 A.F.Scian adjusted syntax of __unaligned to match 'const'

                            rather than 'far'

96/02/12 A.F.Scian added support for __declspec( pragma-modifier )
96/02/26 A.F.Scian added some namespace syntax
96/03/19 A.F.Scian adjusted ++@/–@ grammar as per ISO C++ mtg in

                            Santa Cruz, CA resolutions

96/05/07 A.F.Scian added “using namespace X;”
96/06/07 A.F.Scian added support for multiple ids in __declspec()
96/07/02 A.F.Scian added sizeof
96/07/25 A.F.Scian accept unsigned : 1; as a bitfield
96/10/28 A.F.Scian fixed 96/07/25 so that : 1; still works
*/
%token Y_IMPOSSIBLE

/ declaration keywords /
%token Y_ASM
%token Y_AUTO
%token Y_BOOL
%token Y_CHAR
%token Y_CLASS
%token Y_CONST
%token Y_CONST_CAST
%token Y_DELETE
%token Y_DOUBLE
%token Y_DYNAMIC_CAST
%token Y_ELSE
%token Y_ENUM
%token Y_EXPLICIT
%token Y_EXPORT
%token Y_EXTERN
%token Y_FALSE
%token Y_FLOAT
%token Y_FOR
%token Y_FRIEND
%token Y_INLINE
%token Y_INT
%token Y_LONG
%token Y_MUTABLE
%token Y_NAMESPACE
%token Y_NEW
%token Y_OPERATOR
%token Y_PRIVATE
%token Y_PROTECTED
%token Y_PUBLIC
%token Y_REGISTER
%token Y_REINTERPRET_CAST
%token Y_SHORT
%token Y_SIGNED
%token Y_SIZEOF
%token Y_STATIC
%token Y_STATIC_ASSERT
%token Y_STATIC_CAST
%token Y_STRUCT
%token Y_TEMPLATE
%token Y_THIS
%token Y_THROW
%token Y_TRUE
%token Y_TYPEDEF
%token Y_TYPEID
%token Y_TYPENAME
%token Y_UNION
%token Y_UNSIGNED
%token Y_USING
%token Y_VIRTUAL
%token Y_VOID
%token Y_VOLATILE
%token Y_WCHAR_T

/ punctuation and operators /
%token Y_COMMA
%token Y_QUESTION
%token Y_COLON
%token Y_SEMI_COLON
%token Y_LEFT_PAREN
%token Y_RIGHT_PAREN
%token Y_LEFT_BRACKET
%token Y_RIGHT_BRACKET
%token Y_LEFT_BRACE
%token Y_RIGHT_BRACE
%token Y_TILDE
%token Y_EQUAL
%token Y_EQ
%token Y_EXCLAMATION
%token Y_NE
%token Y_OR
%token Y_OR_EQUAL
%token Y_OR_OR
%token Y_AND
%token Y_AND_EQUAL
%token Y_AND_AND
%token Y_XOR
%token Y_XOR_EQUAL
%token Y_GT
%token Y_GE
%token Y_LT
%token Y_LE
%token Y_LSHIFT
%token Y_LSHIFT_EQUAL
%token Y_RSHIFT
%token Y_RSHIFT_EQUAL
%token Y_PLUS
%token Y_PLUS_EQUAL
%token Y_PLUS_PLUS
%token Y_MINUS
%token Y_MINUS_EQUAL
%token Y_MINUS_MINUS
%token Y_TIMES
%token Y_TIMES_EQUAL
%token Y_DIV
%token Y_DIV_EQUAL
%token Y_PERCENT
%token Y_PERCENT_EQUAL
%token Y_DOT
%token Y_DOT_DOT_DOT
%token Y_DOT_STAR
%token Y_ARROW
%token Y_ARROW_STAR
%token Y_SEG_OP

/ special lexical tokens /
%token Y_ID
%token Y_UNKNOWN_ID
%token Y_TEMPLATE_ID
%token Y_TYPE_NAME
%token Y_TEMPLATE_NAME
%token Y_NAMESPACE_NAME
%token Y_CONSTANT
%token Y_TRUE
%token Y_FALSE
%token Y_STRING

%token Y_GLOBAL_ID / :: /
%token Y_GLOBAL_UNKNOWN_ID / :: /
%token Y_GLOBAL_TEMPLATE_ID / :: /
%token Y_GLOBAL_TYPE_NAME / :: /
%token Y_GLOBAL_TEMPLATE_NAME / :: /
%token Y_GLOBAL_NAMESPACE_NAME / :: /
%token Y_GLOBAL_OPERATOR / ::operator /
%token Y_GLOBAL_TILDE / ::~ /
%token Y_GLOBAL_NEW / ::new /
%token Y_GLOBAL_DELETE / ::delete /

/ Y_SCOPED_ tokens must stay in line with Y_TEMPLATE_SCOPED_ tokens /
%token Y_SCOPED_ID / C:: /
%token Y_SCOPED_UNKNOWN_ID / C:: /
%token Y_SCOPED_TEMPLATE_ID / C:: /
%token Y_SCOPED_TYPE_NAME / C:: /
%token Y_SCOPED_TEMPLATE_NAME / C:: /
%token Y_SCOPED_NAMESPACE_NAME / C:: /
%token Y_SCOPED_OPERATOR / C::operator /
%token Y_SCOPED_TILDE / C::~ /
%token Y_SCOPED_TIMES / C:: */

%token Y_TEMPLATE_SCOPED_ID / T<>:: /
%token Y_TEMPLATE_SCOPED_UNKNOWN_ID/ T<>:: /
%token Y_TEMPLATE_SCOPED_TEMPLATE_ID/ T<>:: /
%token Y_TEMPLATE_SCOPED_TYPE_NAME/ T<>:: /
%token Y_TEMPLATE_SCOPED_TEMPLATE_NAME/ T<>:: /
%token Y_TEMPLATE_SCOPED_NAMESPACE_NAME/ T<>:: /
%token Y_TEMPLATE_SCOPED_OPERATOR/ T<>::operator /
%token Y_TEMPLATE_SCOPED_TILDE / T<>::~ /
%token Y_TEMPLATE_SCOPED_TIMES / T<>:: */

/ leader token for “special” parsing /
%token Y_EXPRESSION_SPECIAL
%token Y_EXPR_DECL_SPECIAL
%token Y_FUNCTION_DECL_SPECIAL
%token Y_EXCEPTION_SPECIAL
%token Y_MEM_INIT_SPECIAL
%token Y_DEFARG_SPECIAL
%token Y_TEMPLATE_INT_DEFARG_SPECIAL
%token Y_TEMPLATE_TYPE_DEFARG_SPECIAL
%token Y_CLASS_INST_SPECIAL

/ terminator tokens for “special” parsing /
%token Y_DEFARG_END
%token Y_GT_SPECIAL

/ tokens that are never generated by yylex() /
%token Y_REDUCE_SPECIAL
%token Y_SHIFT_SPECIAL
%token Y_DEFARG_GONE_SPECIAL
%token Y_TEMPLATE_DEFARG_GONE_SPECIAL
%token Y_PURE_FUNCTION_SPECIAL

/ special function names /
%token Y_DECLTYPE
%token YOFFSETOF
%token Y
TYPEOF
%token Y___BUILTIN_ISFLOAT

/ PC-specific keywords /
%token YASM
%token Y
BASED
%token YCDECL
%token Y
CDECL
%token Y
DECLSPEC
%token Y
EXPORT
%token YEXPORT
%token Y
FAR
%token YFAR16
%token Y
FAR16
%token Y
FASTCALL
%token Y
FASTCALL
%token Y
FORTRAN
%token Y
HUGE
%token Y
INLINE
%token Y
INT8
%token Y
INT16
%token Y
INT32
%token Y
INT64
%token Y
INTERRUPT
%token Y
LOADDS
%token Y
NEAR
%token Y
OPTLINK
%token YPACKED
%token Y
PASCAL
%token YPASCAL
%token Y
PRAGMA
%token YSAVEREGS
%token Y
SEG16
%token Y
SEGMENT
%token YSEGNAME
%token Y
SELF
%token YSTDCALL
%token Y
SYSCALL
%token Y
SYSCALL
%token YSYSTEM
%token Y
WATCALL
%token Y
__UNALIGNED

%type segment-cast-opt

%type modifier
%type access-specifier
%type cv-qualifier-seq-opt
%type base-qualifiers-opt
%type packed-class-opt

%type class-key
%type template-typename-key
%type operator

%type class-mod-opt
%type class-mod-seq
%type class-mod

%type ptr-operator
%type pragma-modifier
%type based-expression
%type ptr-mod

%type base-specifier base-specifier-list

%type ctor-initializer
%type defarg-check

%type type-specifier-seq
%type type-specifier
%type typeof-specifier
%type arg-decl-specifier-seq
%type decl-specifier-seq
%type non-type-decl-specifier-seq
%type non-type-decl-specifier
%type no-declarator-declaration
%type basic-type-specifier
%type simple-type-specifier
%type maybe-type-decl-specifier-seq
%type storage-class-specifier
%type ms-specific-declspec
%type ms-declspec-seq
%type function-specifier
%type cv-qualifier
%type class-specifier
%type enum-specifier
%type elaborated-type-specifier
%type class-substance
%type class-body
%type qualified-type-specifier
%type qualified-class-specifier
%type qualified-class-type
%type typename-specifier

%type function-declaration
%type declarator
%type comma-declarator
%type init-declarator
%type comma-init-declarator
%type ctor-declarator
%type declaring-declarator
%type comma-declaring-declarator
%type direct-declarator
%type ptr-mod-init-declarator
%type ptr-mod-declarator
%type conversion-declarator
%type special-new-abstract-ptr-mod-declarator
%type abstract-ptr-mod-declarator
%type special-new-abstract-declarator
%type abstract-declarator
%type special-new-direct-abstract-declarator
%type direct-abstract-declarator
%type parameter-declaration-clause
%type simple-parameter-declaration
%type parameter-declaration
%type template-parameter
%type type-parameter
%type type-parameter-no-defarg
%type parameter-declaration-list
%type actual-exception-declaration
%type exception-declaration
%type member-declaring-declarator
%type member-declarator
%type direct-new-declarator
%type partial-ptr-declarator
%type new-declarator
%type dynamic-type-id
%type new-type-id
%type special-new-type-id
%type simple-arg-no-id

%type identifier
%type boolean-literal
%type new-keyword
%type delete-keyword
%type declarator-id
%type conversion-type-id
%type operator-function-id
%type scoped-operator-function-id
%type template-scoped-operator-function-id
%type conversion-function-id
%type scoped-conversion-function-id
%type template-scoped-conversion-function-id
%type pseudo-destructor-name
%type exception-specification-opt
%type exception-specification
%type expression
%type expression-before-semicolon
%type expression-list
%type expression-list-opt
%type assignment-operator
%type assignment-expression
%type assignment-expression-opt
%type conditional-expression
%type logical-or-expression
%type logical-and-expression
%type inclusive-or-expression
%type exclusive-or-expression
%type and-expression
%type equality-expression
%type relational-expression
%type shift-expression
%type additive-expression
%type multiplicative-expression
%type pm-expression
%type cast-expression
%type unary-operator
%type unary-expression
%type offsetof-field
%type offsetof-index
%type new-expression
%type delete-expression
%type postfix-expression
%type primary-expression
%type id-expression
%type unqualified-id
%type template-scoped-unqualified-id
%type qualified-id
%type nested-name-specifier
%type scoped-nested-name-specifier
%type segment-expression
%type postfix-expression-before-dot
%type postfix-expression-before-arrow
%type new-placement
%type make-id
%type class-name-id
%type invalid-class-name-id
%type enumerator
%type elaborated-type-name
%type literal
%type string-literal pragma-id
%type type-id-list
%type type-id
%type new-initializer
%type new-initializer-opt
%type constant-expression
%type constant-initializer
%type mem-initializer-list
%type mem-initializer
%type template-id
%type scoped-template-id
%type template-type
%type template-type-instantiation
%type scoped-template-type
%type scoped-template-type-instantiation
%type template-scoped-template-type
%type template-scoped-template-type-instantiation
%type template-argument
%type template-argument-list-opt
%type template-argument-list
%type qualified-namespace-specifier

%type expr-decl-stmt
%type goal-symbol

%nonassoc Y_LEFT_PAREN
%nonassoc Y_FAVOUR_REDUCE_SPECIAL

%start goal-symbol

%%

/ these actions change the token to EOF to force acceptance /
goal-symbol

: Y_EXPRESSION_SPECIAL expression
{
    $$ = $2;
    t = YYEOFTOKEN;
}
| Y_EXPRESSION_SPECIAL type-specifier-seq declaring-declarator initializer
{
    CheckDeclarationDSpec( state->gstack->u.dspec, GetCurrScope() );
    GStackPop( &(state->gstack) );
    $$ = $3->id;
    $3->id = NULL;
    FreeDeclInfo( $3 );
    t = YYEOFTOKEN;
}
| Y_EXPR_DECL_SPECIAL expr-decl-stmt
{
    $$ = $2;
    t = YYEOFTOKEN;
}
| Y_FUNCTION_DECL_SPECIAL decl-specifier-seq declarator
{
    GStackPop( &(state->gstack) );      /* decl-spec */
    $$ = (PTREE) $3;
    t = YYEOFTOKEN;
}
| Y_FUNCTION_DECL_SPECIAL                    declarator
{
    $$ = (PTREE) $2;
    t = YYEOFTOKEN;
}
| Y_FUNCTION_DECL_SPECIAL decl-specifier-seq ctor-declarator
{
    GStackPop( &(state->gstack) );      /* decl-spec */
    $$ = (PTREE) $3;
    t = YYEOFTOKEN;
}
| might-restart-declarations
{
    t = YYEOFTOKEN;
}
| Y_EXCEPTION_SPECIAL exception-declaration
{
    /* treat exception decl like an argument */
    $$ = (PTREE) AddArgument( NULL, $2 );
    t = YYEOFTOKEN;
}
| Y_MEM_INIT_SPECIAL mem-initializer-list Y_LEFT_BRACE
{
    $$ = $2;
    t = YYEOFTOKEN;
}
| Y_DEFARG_SPECIAL assignment-expression Y_DEFARG_END
{
    $$ = $2;
    t = YYEOFTOKEN;
}
| Y_TEMPLATE_INT_DEFARG_SPECIAL logical-or-expression Y_DEFARG_END
{
    $$ = $2;
    t = YYEOFTOKEN;
}
| Y_TEMPLATE_TYPE_DEFARG_SPECIAL expect-type-id type-id Y_DEFARG_END
{
    $$ = $3;
    t = YYEOFTOKEN;
}
| Y_CLASS_INST_SPECIAL class-specifier
{
    $$ = (PTREE) $2;
    t = YYEOFTOKEN;
}
/* I have included this as a stack reset leaves us open to abuse
 * now we fixed bug 218. All linkage gets reset when we have a
 * syntax error earlier in the file which screws up closing of the
 * parser. We only issue an error if we have not reported any
 * earlier errors as this error comes out badly at the end of a
 * file
 */
| Y_RIGHT_BRACE
{
    error_state_t save;
    CErrCheckpoint( &save );
    if( 0 == save ) {
        SetErrLoc( &yylp[1] );
        CErr1( ERR_MISPLACED_RIGHT_BRACE );
        what = P_DIAGNOSED;
    }
}
| /* nothing */
{
    if( CurToken != T_EOF ) {
        CErr1( ERR_SYNTAX );
    }
    what = P_DIAGNOSED;
}
;

/ error reporting hints /
expect-string-literal

: /* nothing */
{ state->expect = "string-literal"; }
;

expect-identifier

: /* nothing */
{ state->expect = "identifier"; }
;

expect-id-expression

: /* nothing */
{ state->expect = "id-expression"; }
;

expect-type-name

: /* nothing */
{ state->expect = "type-name"; }
;

expect-type-id

: /* nothing */
{ state->expect = "type-id"; }
;

expect-qualified-namespace-specifier

: /* nothing */
{ state->expect = "qualified-namespace-specifier"; }
;

lt-special-init

: /* nothing */
{
    angle_bracket_stack *angle_state;

    angle_state = VstkPush( &(state->angle_stack) );
    angle_state->paren_depth = 0;
}
;

lt-special

: lt-special-init Y_LT
;

expr-decl-stmt

: expression-before-semicolon Y_SEMI_COLON
{ $$ = $1; }
| local-declaration
{ $$ = NULL; }
;

expression-before-semicolon

: expression
{
    $$ = $1;
    if( t != Y_SEMI_COLON ) {
        SetErrLoc( &yylocation );
        CErr1( ERR_SYNTAX_MISSING_SEMICOLON );
        what = P_DIAGNOSED;
    }
}
;

/* r/r conflict:

  • id-expression <- qualified-id (unit production)
  • access-declaration <- qualified-id
    */
    access-declaration
    : qualified-id
    { ClassAccessDeclaration( $1, &yylocation ); }
    | qualified-type-specifier
    { ClassAccessTypeDeclaration( $1, &yylocation ); }
    | Y_SCOPED_UNKNOWN_ID
    { ClassAccessDeclaration( MakeScopedId( $1 ), &yylocation ); }
    | nested-name-specifier Y_TEMPLATE_SCOPED_UNKNOWN_ID
    {
    PTreeFreeSubtrees( $1 );
    ClassAccessDeclaration( MakeScopedId( $2 ), &yylocation );
    
    }
    ;

/ A.2 Lexical conventions [gram.lex] /

identifier

: Y_ID
| Y_UNKNOWN_ID
| Y_TEMPLATE_ID
;

literal

: Y_CONSTANT /* integer-literal character-literal floating-literal */
| string-literal
| boolean-literal
;

string-literal

: Y_STRING
| string-literal Y_STRING
{ $$ = PTreeStringLiteralConcat( $1, $2 ); }
;

boolean-literal

: Y_TRUE
| Y_FALSE
;

/ A.4 Expressions [gram.expr] /

primary-expression

: literal
| Y_THIS
{ $$ = setLocation( PTreeThis(), &yylp[1] ); }
| Y_LEFT_PAREN expression Y_RIGHT_PAREN
{ $$ = $2; }
| id-expression
;

id-expression

: unqualified-id
| qualified-id
;

unqualified-id

: identifier
| operator-function-id
| conversion-function-id
| Y_TILDE expect-type-name Y_TYPE_NAME /* ~ class-name */
{ $$ = setLocation( MakeDestructorId( $3 ), &yylp[1] ); }
| Y_TILDE expect-type-name Y_UNKNOWN_ID /* ~ id (non-stanard, diagnostics only) */
{ $$ = setLocation( MakeDestructorId( $3 ), &yylp[1] ); }
| Y_TILDE expect-type-name template-type /* ~ class-name */
{ $$ = setLocation( MakeDestructorIdFromType( PTypeClassInstantiation( state->class_colon, $3 ) ), &yylp[1] ); }
| template-id
;

qualified-id

: nested-name-specifier template-scoped-unqualified-id
{ PTreeFreeSubtrees( $1 ); $$ = $2; }
| Y_GLOBAL_ID /* :: identifier */
{ $$ = MakeGlobalId( $1 ); }
| Y_GLOBAL_TEMPLATE_ID /* :: identifier */
{ $$ = MakeGlobalId( $1 ); }
| Y_SCOPED_ID
{ $$ = MakeScopedId( $1 ); }
| Y_SCOPED_TEMPLATE_ID
{ $$ = MakeScopedId( $1 ); }
| scoped-operator-function-id
| scoped-conversion-function-id
| scoped-template-id
| pseudo-destructor-name
;

/ differs from standard /
nested-name-specifier

: template-type
| scoped-template-type
| template-type scoped-nested-name-specifier
{ PTreeFreeSubtrees( $1 ); $$ = $2; }
| scoped-template-type scoped-nested-name-specifier
{ PTreeFreeSubtrees( $1 ); $$ = $2; }
;

/ non-standard /
scoped-nested-name-specifier

: template-scoped-template-type
| template-scoped-template-type scoped-nested-name-specifier
{
    PTreeFreeSubtrees( $1 );
    $$ = $2;
}
;

/ non-standard /
template-scoped-unqualified-id

: Y_TEMPLATE_SCOPED_ID
{ $$ = MakeScopedId( $1 ); }
| Y_TEMPLATE_SCOPED_TEMPLATE_ID
{ $$ = MakeScopedId( $1 ); }
| Y_TEMPLATE_SCOPED_TEMPLATE_ID lt-special template-argument-list-opt Y_GT_SPECIAL
| Y_TEMPLATE_SCOPED_TEMPLATE_NAME lt-special template-argument-list-opt Y_GT_SPECIAL
| template-scoped-operator-function-id
| template-scoped-conversion-function-id
;

postfix-expression

: primary-expression
| postfix-expression Y_LEFT_BRACKET expression Y_RIGHT_BRACKET
{ $$ = setLocation( PTreeBinary( CO_INDEX, $1, $3 ), &yylp[2] ); }
| postfix-expression Y_LEFT_PAREN expression-list-opt Y_RIGHT_PAREN
{ $$ = setLocation( PTreeBinary( CO_CALL, $1, $3 ), &yylp[2] ); }
| simple-type-specifier Y_LEFT_PAREN expression-list-opt Y_RIGHT_PAREN %ambig 0 Y_LEFT_PAREN
{ $$ = setLocation( MakeFunctionLikeCast( $1, $3 ), &yylp[2] ); }
| typename-specifier Y_LEFT_PAREN expression-list-opt Y_RIGHT_PAREN
{
    $$ = setLocation( MakeFunctionLikeCast( $1, $3 ), &yylp[2] );
}
| postfix-expression-before-dot Y_DOT expect-id-expression id-expression
{ $$ = PTreeReplaceRight( setLocation( $1, &yylp[3] ), $4 ); }
| postfix-expression-before-arrow Y_ARROW expect-id-expression id-expression
{ $$ = PTreeReplaceRight( setLocation( $1, &yylp[3] ), $4 ); }

/* id-expression includes pseudo-destructor-name

| postfix-expression-before-dot Y_DOT pseudo-destructor-name
| postfix-expression-before-arrow Y_ARROW pseudo-destructor-name

*/

| postfix-expression Y_PLUS_PLUS
{ $$ = setLocation( PTreeUnary( CO_POST_PLUS_PLUS, $1 ), &yylp[2] ); }
| postfix-expression Y_MINUS_MINUS
{ $$ = setLocation( PTreeUnary( CO_POST_MINUS_MINUS, $1 ), &yylp[2] ); }
| Y_DYNAMIC_CAST lt-special expect-type-id type-id Y_GT_SPECIAL Y_LEFT_PAREN expression Y_RIGHT_PAREN
{ $$ = setLocation( PTreeBinary( CO_DYNAMIC_CAST, $4, $7 ), &yylp[1] ); }
| Y_STATIC_CAST lt-special expect-type-id type-id Y_GT_SPECIAL Y_LEFT_PAREN expression Y_RIGHT_PAREN
{ $$ = setLocation( PTreeBinary( CO_STATIC_CAST, $4, $7 ), &yylp[1] ); }
| Y_REINTERPRET_CAST lt-special expect-type-id type-id Y_GT_SPECIAL Y_LEFT_PAREN expression Y_RIGHT_PAREN
{ $$ = setLocation( PTreeBinary( CO_REINTERPRET_CAST, $4, $7 ), &yylp[1] ); }
| Y_CONST_CAST lt-special expect-type-id type-id Y_GT_SPECIAL Y_LEFT_PAREN expression Y_RIGHT_PAREN
{ $$ = setLocation( PTreeBinary( CO_CONST_CAST, $4, $7 ), &yylp[1] ); }
| Y_TYPEID Y_LEFT_PAREN expression Y_RIGHT_PAREN
{ $$ = setLocation( PTreeUnary( CO_TYPEID_EXPR, $3 ), &yylp[1] ); }
| Y_TYPEID Y_LEFT_PAREN type-id Y_RIGHT_PAREN
{ $$ = setLocation( PTreeUnary( CO_TYPEID_TYPE, $3 ), &yylp[1] ); }
/* extension */
| Y___SEGNAME Y_LEFT_PAREN expect-string-literal string-literal Y_RIGHT_PAREN
{ $$ = setLocation( PTreeUnary( CO_SEGNAME, $4 ), &yylp[1] ); }
;

/ non-standard /
postfix-expression-before-dot

: postfix-expression
{
    $1 = PTreeTraversePostfix( $1, &AnalyseNode );
    if( ! ( $1->flags & PTF_LV_CHECKED ) ) {
        AnalyseLvalue( &$1 );
    }
    $1 = PTreeTraversePostfix( $1, &setAnalysedFlag );
    if( $1->type ) {
        TYPE cls;

        cls = TypedefModifierRemoveOnly( $1->type );
        if( ( cls != NULL )
         && ( cls->id == TYP_POINTER )
         && ( cls->flag & TF1_REFERENCE ) ) {
            cls = cls->of;
        }

        if( cls != NULL ) {
            cls = BindTemplateClass( cls, &$1->locn, FALSE );
            $1->type = BoundTemplateClass( $1->type );
            cls = TypedefModifierRemoveOnly( cls );

            if( cls->id == TYP_CLASS ) {
                setTypeMember( state, cls->u.c.scope );
            }
        }
    }
    $$ = PTreeBinary( CO_DOT, $1, NULL );
}
;

/ non-standard /
postfix-expression-before-arrow

: postfix-expression
{
    $1 = PTreeTraversePostfix( $1, &AnalyseNode );
    if( ! ( $1->flags & PTF_LV_CHECKED ) ) {
        AnalyseLvalue( &$1 );
    }
    $$ = PTreeBinary( CO_ARROW, $1, NULL );
    $$ = OverloadOperator( $$ );
    $$->u.subtree[0] = PTreeTraversePostfix( $$->u.subtree[0], &setAnalysedFlag );
    if( $$->u.subtree[0] ) {
        TYPE cls;

        cls = TypedefModifierRemoveOnly( $$->u.subtree[0]->type );
        if( ( cls != NULL )
         && ( cls->id == TYP_POINTER )
         && ( cls->flag & TF1_REFERENCE ) ) {
            cls = TypedefModifierRemoveOnly( cls->of );
        }

        if( ( cls != NULL ) && cls->id == TYP_POINTER ) {
            cls = BindTemplateClass( cls->of, &$1->locn, FALSE );
            $1->type = BoundTemplateClass( $1->type );
            cls = TypedefModifierRemoveOnly( cls );

            if( cls->id == TYP_CLASS ) {
                setTypeMember( state, cls->u.c.scope );
            }
        }
    }
}
;

expression-list-opt

: /* nothing */
{ $$ = NULL; }
| expression-list
;

expression-list

: assignment-expression
{ $$ = PTreeBinary( CO_LIST, NULL, $1 ); }
| expression-list Y_COMMA assignment-expression
{ $$ = setLocation( PTreeBinary( CO_LIST,   $1, $3 ), &yylp[2] ); }
;

pseudo-destructor-name

: Y_SCOPED_TILDE expect-type-name identifier
{ $$ = setLocation( MakeScopedDestructorId( $1, $3 ), &yylp[1] ); }
| Y_SCOPED_TILDE expect-type-name Y_TYPE_NAME
{ $$ = setLocation( MakeScopedDestructorId( $1, $3 ), &yylp[1] ); }
| nested-name-specifier Y_TEMPLATE_SCOPED_TILDE expect-type-name Y_ID
{
    PTreeFreeSubtrees( $1 );
    $$ = setLocation( MakeScopedDestructorId( $2, $4 ), &yylp[2] );
}
| nested-name-specifier Y_TEMPLATE_SCOPED_TILDE expect-type-name Y_UNKNOWN_ID
{
    PTreeFreeSubtrees( $1 );
    $$ = setLocation( MakeScopedDestructorId( $2, $4 ), &yylp[2] );
}
| nested-name-specifier Y_TEMPLATE_SCOPED_TILDE expect-type-name Y_TEMPLATE_NAME
{
    PTreeFreeSubtrees( $1 );
    $$ = setLocation( MakeScopedDestructorId( $2, $4 ), &yylp[2] );
}
| nested-name-specifier Y_TEMPLATE_SCOPED_TILDE expect-type-name Y_TYPE_NAME
{ $$ = setLocation( MakeScopedDestructorId( $2, $4 ), &yylp[1] ); }
;

unary-expression

: postfix-expression
| Y_PLUS_PLUS cast-expression
{ $$ = setLocation( PTreeUnary( CO_PRE_PLUS_PLUS, $2 ), &yylp[1] ); }
| Y_MINUS_MINUS cast-expression
{ $$ = setLocation( PTreeUnary( CO_PRE_MINUS_MINUS, $2 ), &yylp[1] ); }
| unary-operator cast-expression
{ $$ = PTreeReplaceLeft( $1, $2 ); }
| Y_SIZEOF unary-expression
{ $$ = setLocation( PTreeUnary( CO_SIZEOF_EXPR, $2 ), &yylp[1] ); }
| Y_SIZEOF Y_LEFT_PAREN type-id Y_RIGHT_PAREN
{ $$ = setLocation( PTreeUnary( CO_SIZEOF_TYPE, $3 ), &yylp[1] ); }
| new-expression
| delete-expression
/* extension */
| Y_SIZEOF Y_TYPE_NAME
{ $$ = setLocation( PTreeUnary( CO_SIZEOF_TYPE, PTreeMSSizeofKludge( $2 ) ), &yylp[1] ); }
| Y___BUILTIN_ISFLOAT Y_LEFT_PAREN expect-type-id type-id Y_RIGHT_PAREN
{ $$ = setLocation( MakeBuiltinIsFloat( $4 ), &yylp[1] ); }
| Y___OFFSETOF Y_LEFT_PAREN expect-type-id type-id Y_COMMA offsetof-field Y_RIGHT_PAREN
{ $$ = setLocation( PTreeOffsetof( $4, $6 ), &yylp[5] ); }
;

unary-operator

: Y_TIMES
{ $$ = setLocation( PTreeUnary( CO_INDIRECT, NULL ), &yylp[1] ); }
| Y_AND
{ $$ = setLocation( PTreeUnary( CO_ADDR_OF, NULL ), &yylp[1] ); }
| Y_PLUS
{ $$ = setLocation( PTreeUnary( CO_UPLUS, NULL ), &yylp[1] ); }
| Y_MINUS
{ $$ = setLocation( PTreeUnary( CO_UMINUS, NULL ), &yylp[1] ); }
| Y_EXCLAMATION
{ $$ = setLocation( PTreeUnary( CO_EXCLAMATION, NULL ), &yylp[1] ); }
| Y_TILDE
{ $$ = setLocation( PTreeUnary( CO_TILDE, NULL ), &yylp[1] ); }
;

new-expression

: new-keyword new-modifier-opt new-placement new-type-id new-initializer-opt
{
    $$ = setLocation( MakeNewExpr( $1, $3, $4, $5 ), &$1->locn );
    PTreeFreeSubtrees( $1 );
}
| new-keyword new-modifier-opt               new-type-id new-initializer-opt
{
    $$ = setLocation( MakeNewExpr( $1, NULL, $3, $4 ), &$1->locn );
    PTreeFreeSubtrees( $1 );
}
| new-keyword new-modifier-opt new-placement Y_LEFT_PAREN special-new-type-id Y_RIGHT_PAREN new-initializer-opt /* TODO */
{
    $$ = setLocation( MakeNewExpr( $1, $3, $5, $7 ), &$1->locn );
    PTreeFreeSubtrees( $1 );
}
| new-keyword new-modifier-opt               Y_LEFT_PAREN special-new-type-id Y_RIGHT_PAREN new-initializer-opt /* TODO */
{
    $$ = setLocation( MakeNewExpr( $1, NULL, $4, $6 ), &$1->locn );
    PTreeFreeSubtrees( $1 );
}
;

/ non-standard /
new-keyword

: Y_NEW
{ $$ = makeUnary( CO_NEW, NULL); }
| Y_GLOBAL_NEW
;

new-modifier-opt

: /* nothing */
| modifier
{ CheckNewModifier( $1 ); }
;

new-placement

: Y_LEFT_PAREN expression-list Y_RIGHT_PAREN
{ $$ = $2; }
;

new-type-id

: dynamic-type-id
| Y_LEFT_PAREN special-new-type-id Y_RIGHT_PAREN
{ $$ = $2; }
;

new-initializer-opt

: /* nothing */
{ $$ = NULL; }
| new-initializer
;

new-initializer

: Y_LEFT_PAREN Y_RIGHT_PAREN
{ $$ = NULL; } /* ARM p.61 '()' is syntactic convenience */
| Y_LEFT_PAREN expression-list Y_RIGHT_PAREN
{ $$ = $2; }
;

dynamic-type-id

: type-specifier-seq
{
    $$ = MakeNewTypeId( DoDeclSpec( state->gstack->u.dspec ) );
    GStackPop( &(state->gstack) );
}
| type-specifier-seq new-declarator
{
    $$ = $2;
    GStackPop( &(state->gstack) );
}
;

/ TODO /
new-declarator

: partial-ptr-declarator direct-new-declarator
{ $$ = MakeNewDeclarator( state->gstack->u.dspec, $1, $2 ); }
| partial-ptr-declarator
{ $$ = MakeNewDeclarator( state->gstack->u.dspec, $1, NULL ); }
| direct-new-declarator
{ $$ = MakeNewDeclarator( state->gstack->u.dspec, NULL, $1 ); }
;

delete-expression

: delete-keyword cast-expression
{ $$ = setLocation( MakeDeleteExpr( $1, ( $1 == NULL ) ? CO_DELETE : CO_DELETE_G, $2 ), &yylp[1] ); }
| delete-keyword Y_LEFT_BRACKET delete-size-expression-opt Y_RIGHT_BRACKET cast-expression
{ $$ = setLocation( MakeDeleteExpr( $1, ( $1 == NULL ) ? CO_DELETE_ARRAY : CO_DELETE_G_ARRAY, $5 ), &yylp[1] ); }
;

/ non-standard /
delete-keyword

: Y_DELETE
{ $$ = NULL; }
| Y_GLOBAL_DELETE
;

/ non-standard /
delete-size-expression-opt

: /* nothing */
| expression
{
    PTreeDeleteSizeExpr( $1 );
}
;

cast-expression

: unary-expression
| Y_LEFT_PAREN type-id Y_RIGHT_PAREN cast-expression
{ $$ = setLocation( MakeNormalCast( $2, $4 ), &yylp[3] ); }
;

/ extension /
segment-expression

: cast-expression
| segment-expression Y_SEG_OP cast-expression
{ $$ = setLocation( PTreeBinary( CO_SEG_OP, $1, $3 ), &yylp[2] ); }
;

pm-expression

: segment-expression
| pm-expression Y_DOT_STAR segment-expression
{ $$ = setLocation( PTreeBinary( CO_DOT_STAR, $1, $3 ), &yylp[2] ); }
| pm-expression Y_ARROW_STAR segment-expression
{ $$ = setLocation( PTreeBinary( CO_ARROW_STAR, $1, $3 ), &yylp[2] ); }
;

multiplicative-expression

: pm-expression
| multiplicative-expression Y_TIMES pm-expression
{ $$ = setLocation( PTreeBinary( CO_TIMES, $1, $3 ), &yylp[2] ); }
| multiplicative-expression Y_DIV pm-expression
{ $$ = setLocation( PTreeBinary( CO_DIVIDE, $1, $3 ), &yylp[2] ); }
| multiplicative-expression Y_PERCENT pm-expression
{ $$ = setLocation( PTreeBinary( CO_PERCENT, $1, $3 ), &yylp[2] ); }
;

additive-expression

: multiplicative-expression
| additive-expression Y_PLUS multiplicative-expression
{ $$ = setLocation( PTreeBinary( CO_PLUS, $1, $3 ), &yylp[2] ); }
| additive-expression Y_MINUS multiplicative-expression
{ $$ = setLocation( PTreeBinary( CO_MINUS, $1, $3 ), &yylp[2] ); }
;

shift-expression

: additive-expression
| shift-expression Y_RSHIFT additive-expression
{ $$ = setLocation( PTreeBinary( CO_RSHIFT, $1, $3 ), &yylp[2] ); }
| shift-expression Y_LSHIFT additive-expression
{ $$ = setLocation( PTreeBinary( CO_LSHIFT, $1, $3 ), &yylp[2] ); }
;

relational-expression

: shift-expression
| relational-expression Y_LT shift-expression
{ $$ = setLocation( PTreeBinary( CO_LT, $1, $3 ), &yylp[2] ); }
| relational-expression Y_LE shift-expression
{ $$ = setLocation( PTreeBinary( CO_LE, $1, $3 ), &yylp[2] ); }
| relational-expression Y_GT shift-expression
{ $$ = setLocation( PTreeBinary( CO_GT, $1, $3 ), &yylp[2] ); }
| relational-expression Y_GE shift-expression
{ $$ = setLocation( PTreeBinary( CO_GE, $1, $3 ), &yylp[2] ); }
;

equality-expression

: relational-expression
| equality-expression Y_EQ relational-expression
{ $$ = setLocation( PTreeBinary( CO_EQ, $1, $3 ), &yylp[2] ); }
| equality-expression Y_NE relational-expression
{ $$ = setLocation( PTreeBinary( CO_NE, $1, $3 ), &yylp[2] ); }
;

and-expression

: equality-expression
| and-expression Y_AND equality-expression
{ $$ = setLocation( PTreeBinary( CO_AND, $1, $3 ), &yylp[2] ); }
;

exclusive-or-expression

: and-expression
| exclusive-or-expression Y_XOR and-expression
{ $$ = setLocation( PTreeBinary( CO_XOR, $1, $3 ), &yylp[2] ); }
;

inclusive-or-expression

: exclusive-or-expression
| inclusive-or-expression Y_OR exclusive-or-expression
{ $$ = setLocation( PTreeBinary( CO_OR, $1, $3 ), &yylp[2] ); }
;

logical-and-expression

: inclusive-or-expression
| logical-and-expression Y_AND_AND inclusive-or-expression
{ $$ = setLocation( PTreeBinary( CO_AND_AND, $1, $3 ), &yylp[2] ); }
;

logical-or-expression

: logical-and-expression
| logical-or-expression Y_OR_OR logical-and-expression
{ $$ = setLocation( PTreeBinary( CO_OR_OR, $1, $3 ), &yylp[2] ); }
;

conditional-expression

: logical-or-expression
| logical-or-expression Y_QUESTION expression Y_COLON assignment-expression
{
    $3 = setLocation( PTreeBinary( CO_COLON, $3, $5 ), &yylp[4] );
    $$ = setLocation( PTreeBinary( CO_QUESTION, $1, $3 ), &yylp[2] );
}
;

assignment-expression

: conditional-expression
| logical-or-expression assignment-operator assignment-expression
{
    $$ = PTreeReplaceLeft( $2, $1 );
    $$ = PTreeReplaceRight( $$, $3 );
}
| Y_THROW assignment-expression-opt
{ $$ = setLocation( PTreeUnary( CO_THROW, $2 ), &yylp[1] ); }
;

assignment-expression-opt

: /* nothing */
{ $$ = NULL; }
| assignment-expression
;

assignment-operator

: Y_EQUAL
{ $$ = setLocation( PTreeBinary( CO_EQUAL, NULL, NULL ), &yylp[1] ); }
| Y_TIMES_EQUAL
{ $$ = setLocation( PTreeBinary( CO_TIMES_EQUAL, NULL, NULL ), &yylp[1] ); }
| Y_DIV_EQUAL
{ $$ = setLocation( PTreeBinary( CO_DIVIDE_EQUAL, NULL, NULL ), &yylp[1] ); }
| Y_PERCENT_EQUAL
{ $$ = setLocation( PTreeBinary( CO_PERCENT_EQUAL, NULL, NULL ), &yylp[1] ); }
| Y_PLUS_EQUAL
{ $$ = setLocation( PTreeBinary( CO_PLUS_EQUAL, NULL, NULL ), &yylp[1] ); }
| Y_MINUS_EQUAL
{ $$ = setLocation( PTreeBinary( CO_MINUS_EQUAL, NULL, NULL ), &yylp[1] ); }
| Y_LSHIFT_EQUAL
{ $$ = setLocation( PTreeBinary( CO_LSHIFT_EQUAL, NULL, NULL ), &yylp[1] ); }
| Y_RSHIFT_EQUAL
{ $$ = setLocation( PTreeBinary( CO_RSHIFT_EQUAL, NULL, NULL ), &yylp[1] ); }
| Y_OR_EQUAL
{ $$ = setLocation( PTreeBinary( CO_OR_EQUAL, NULL, NULL ), &yylp[1] ); }
| Y_AND_EQUAL
{ $$ = setLocation( PTreeBinary( CO_AND_EQUAL, NULL, NULL ), &yylp[1] ); }
| Y_XOR_EQUAL
{ $$ = setLocation( PTreeBinary( CO_XOR_EQUAL, NULL, NULL ), &yylp[1] ); }
;

expression

: assignment-expression
| expression Y_COMMA assignment-expression
{ $$ = setLocation( PTreeBinary( CO_COMMA, $1, $3 ), &yylp[2] ); }
;

constant-expression

: conditional-expression
{ $$ = PTreeNonZeroConstantExpr( $1 ); }
;

offsetof-field

: make-id
{
    $$ = PTreeBinary( CO_DOT, $1, NULL );
    $$ = PTreeBinary( CO_DOT, NULL, $$ );
}
| make-id offsetof-index
{
    $$ = PTreeBinary( CO_DOT, $1, $2 );
    $$ = PTreeBinary( CO_DOT, NULL, $$ );
}
| offsetof-field Y_DOT make-id
{
    $$ = setLocation( PTreeBinary( CO_DOT, $3, NULL ), &yylp[2] );
    $$ = setLocation( PTreeBinary( CO_DOT, $1, $$ ), &yylp[2] );
}
| offsetof-field Y_DOT make-id offsetof-index
{
    $$ = setLocation( PTreeBinary( CO_DOT, $3, $4 ), &yylp[2] );
    $$ = setLocation( PTreeBinary( CO_DOT, $1, $$ ), &yylp[2] );
}
;

offsetof-index

: Y_LEFT_BRACKET constant-expression Y_RIGHT_BRACKET
{ $$ = setLocation( PTreeBinary( CO_INDEX, NULL, $2 ), &yylp[1] ); }
| offsetof-index Y_LEFT_BRACKET constant-expression Y_RIGHT_BRACKET
{ $$ = setLocation( PTreeBinary( CO_INDEX, $1, $3 ), &yylp[2] ); }
;

partial-ptr-declarator

: Y_TIMES cv-qualifier-seq-opt partial-ptr-declarator
{ $$ = MakeNewPointer( $2, $3, NULL ); }
| Y_TIMES cv-qualifier-seq-opt
{ $$ = MakeNewPointer( $2, NULL, NULL ); }
| Y_SCOPED_TIMES cv-qualifier-seq-opt partial-ptr-declarator
{ $$ = MakeNewPointer( $2, $3, $1 ); }
| Y_SCOPED_TIMES cv-qualifier-seq-opt
{ $$ = MakeNewPointer( $2, NULL, $1 ); }
| nested-name-specifier Y_TEMPLATE_SCOPED_TIMES cv-qualifier-seq-opt partial-ptr-declarator
{ $$ = MakeNewPointer( $3, $4, $2 ); PTreeFreeSubtrees( $1 ); }
| nested-name-specifier Y_TEMPLATE_SCOPED_TIMES cv-qualifier-seq-opt
{ $$ = MakeNewPointer( $3, NULL, $2 ); PTreeFreeSubtrees( $1 ); }
;

direct-new-declarator

: Y_LEFT_BRACKET expression Y_RIGHT_BRACKET
{ $$ = MakeNewDynamicArray( $2 ); }
| direct-new-declarator Y_LEFT_BRACKET constant-expression Y_RIGHT_BRACKET
{ $$ = AddArrayDeclarator( $1, $3 ); }
;

make-id

: Y_ID
| Y_UNKNOWN_ID
| Y_TEMPLATE_ID
| Y_TYPE_NAME
| Y_TEMPLATE_NAME
| Y_NAMESPACE_NAME
;

/ A.5 Statements [gram.stmt] /

/ A.6 Declarations [gram.dcl] /

/ should only be referenced by might-restart-declarations /
declaration-seq

: declaration
| declaration-seq declaration
;

/ slightly differs from standard /
declaration

: block-declaration-before-semicolon Y_SEMI_COLON
| function-definition
| template-declaration /* | explicit-specialization */
| explicit-instantiation
| linkage-specification
| namespace-definition
| Y_SEMI_COLON /* extension */
;

block-declaration-before-semicolon

: block-declaration
{
    if( t != Y_SEMI_COLON ) {
        SetErrLoc( &yylocation );
        CErr1( ERR_SYNTAX_MISSING_SEMICOLON );
        what = P_DIAGNOSED;
    }
}
;

block-declaration

: simple-declaration
| asm-definition
| namespace-alias-definition
| using-declaration
| using-directive
| static_assert-declaration
;

simple-declaration

: decl-specifier-seq init-declarator-list
{
    CheckDeclarationDSpec( state->gstack->u.dspec, GetCurrScope() );
    GStackPop( &(state->gstack) );
}
| no-declarator-declaration
{
    CheckDeclarationDSpec( state->gstack->u.dspec, GetCurrScope() );
    GStackPop( &(state->gstack) );
}
;

static_assert-declaration

: Y_STATIC_ASSERT Y_LEFT_PAREN constant-expression Y_COMMA expect-string-literal string-literal Y_RIGHT_PAREN
{
    /* see N1720 -- Proposal to Add Static Assertions to the Core
     * Language (Revision 3) */
    DbgAssert( $3->op == PT_INT_CONSTANT );
    DbgAssert( $6->op == PT_STRING_CONSTANT );

    if( $3->u.int_constant == 0 ) {
        CErr2p( ERR_STATIC_ASSERTION_FAILURE, StringBytes( $6->u.string ) );
    }

    PTreeFreeSubtrees( $3 );
    PTreeFreeSubtrees( $6 );
}
;

/ TODO /
decl-specifier-seq

: non-type-decl-specifier-seq type-specifier maybe-type-decl-specifier-seq
{
    $1 = PTypeCombine( $1, $2 );
    $$ = PTypeCombine( $1, $3 );
    $$ = PTypeDone( $$, t == Y_SEMI_COLON );
    pushUserDeclSpec( state, $$ );
}
| non-type-decl-specifier-seq type-specifier
{
    $$ = PTypeCombine( $1, $2 );
    $$ = PTypeDone( $$, t == Y_SEMI_COLON );
    pushUserDeclSpec( state, $$ );
}
| type-specifier maybe-type-decl-specifier-seq
{
    $$ = PTypeCombine( $1, $2 );
    $$ = PTypeDone( $$, t == Y_SEMI_COLON );
    pushUserDeclSpec( state, $$ );
}
| type-specifier
{
    $$ = PTypeDone( $1, t == Y_SEMI_COLON );
    pushUserDeclSpec( state, $$ );
}
| non-type-decl-specifier-seq
{
    $$ = PTypeDone( $1, t == Y_SEMI_COLON );
    pushUserDeclSpec( state, $$ );
}
;

/ non-standard /
non-type-decl-specifier-seq

: non-type-decl-specifier
| non-type-decl-specifier-seq non-type-decl-specifier
{ $$ = PTypeCombine( $1, $2 ); }
;

/ non-standard /
maybe-type-decl-specifier-seq

: non-type-decl-specifier
| basic-type-specifier
| maybe-type-decl-specifier-seq non-type-decl-specifier
{ $$ = PTypeCombine( $1, $2 ); }
| maybe-type-decl-specifier-seq basic-type-specifier
{ $$ = PTypeCombine( $1, $2 ); }
;

/ non-standard /
non-type-decl-specifier

: storage-class-specifier
| function-specifier
| cv-qualifier
| ms-specific-declspec
| Y_FRIEND
{ $$ = PTypeSpecifier( STY_FRIEND ); }
;

/ non-standard /
ms-specific-declspec

: Y___DECLSPEC Y_LEFT_PAREN                 Y_RIGHT_PAREN
{ $$ = PTypeMSDeclSpec( NULL, NULL ); }
| Y___DECLSPEC Y_LEFT_PAREN ms-declspec-seq Y_RIGHT_PAREN
{ $$ = $3; }
;

/ non-standard /
ms-declspec-seq

: make-id
{ $$ = PTypeMSDeclSpec( NULL, $1 ); }
| pragma-modifier
{ $$ = PTypeMSDeclSpecModifier( NULL, $1 ); }
| ms-declspec-seq make-id
{ $$ = PTypeMSDeclSpec( $1, $2 ); }
| ms-declspec-seq pragma-modifier
{ $$ = PTypeMSDeclSpecModifier( $1, $2 ); }
;

storage-class-specifier

: Y_AUTO
{ $$ = PTypeStgClass( STG_AUTO ); }
| Y_REGISTER
{ $$ = PTypeStgClass( STG_REGISTER ); }
| Y_STATIC
{ $$ = PTypeStgClass( STG_STATIC ); }
| Y_EXTERN
{ $$ = PTypeStgClass( STG_EXTERN ); }
| Y_MUTABLE
{ $$ = PTypeStgClass( STG_MUTABLE ); }
/* extension */
| Y_EXTERN linkage-id
{ $$ = PTypeLinkage(); }
| Y_TYPEDEF
{ $$ = PTypeStgClass( STG_TYPEDEF ); }
;

function-specifier

: Y_INLINE
{ $$ = PTypeSpecifier( STY_INLINE ); }
| Y_VIRTUAL
{ $$ = PTypeSpecifier( STY_VIRTUAL ); }
| Y_EXPLICIT
{ $$ = PTypeSpecifier( STY_EXPLICIT ); }
/* extension */
| Y___INLINE
{ $$ = PTypeSpecifier( STY_INLINE ); }
;

type-specifier

: simple-type-specifier %prec Y_FAVOUR_REDUCE_SPECIAL %ambig 0 Y_LEFT_PAREN
| class-specifier
| enum-specifier
| elaborated-type-specifier
| typename-specifier
/* cv-qualifier */
;

simple-type-specifier

: Y_TYPE_NAME
{ $$ = sendType( $1 ); }
| qualified-type-specifier
| basic-type-specifier
/* see N1978 -- Decltype (Revision 5) */
| Y_DECLTYPE Y_LEFT_PAREN expression Y_RIGHT_PAREN
{ $$ = PTypeExpr( $3 ); }
/* extension */
| typeof-specifier
;

/ non-standard /
qualified-type-specifier

: Y_GLOBAL_TYPE_NAME
{ $$ = sendType( $1 ); }
| Y_SCOPED_TYPE_NAME
{ $$ = sendType( $1 ); }
| nested-name-specifier
{
    $$ = PTypeClassInstantiation( state->class_colon, $1 );
}
| nested-name-specifier Y_TEMPLATE_SCOPED_TYPE_NAME
{
    PTreeFreeSubtrees( $1 );
    $$ = sendType( $2 );
}
;

enum-specifier

: enum-key enum-start enumerator-list Y_COMMA Y_RIGHT_BRACE
{
    $$ = MakeEnumType( &(state->gstack->u.enumdata) );
    GStackPop( &(state->gstack) );
    // TODO: warning non-standard
}
| enum-key enum-start enumerator-list         Y_RIGHT_BRACE
{
    $$ = MakeEnumType( &(state->gstack->u.enumdata) );
    GStackPop( &(state->gstack) );
}
| enum-key enum-start                         Y_RIGHT_BRACE
{
    $$ = MakeEnumType( &(state->gstack->u.enumdata) );
    GStackPop( &(state->gstack) );
}
;

/ non-standard /
enum-start

: Y_LEFT_BRACE
{ EnumDefine( &(state->gstack->u.enumdata) ); }
;

/ non-standard /
enum-key

: Y_ENUM make-id
{
    GStackPush( &(state->gstack), GS_ENUM_DATA );
    InitEnumState( &(state->gstack->u.enumdata), $2 );
}
| Y_ENUM
{
    GStackPush( &(state->gstack), GS_ENUM_DATA );
    InitEnumState( &(state->gstack->u.enumdata), NULL );
}
;

enumerator-list

: enumerator-definition
| enumerator-list Y_COMMA enumerator-definition
;

/ TODO /
enumerator-definition

: enumerator
{
    MakeEnumMember( &(state->gstack->u.enumdata), $1, NULL );
}
| enumerator Y_EQUAL constant-expression
{
    MakeEnumMember( &(state->gstack->u.enumdata), $1, $3 );
}
;

enumerator

: make-id /* identifier */
;

elaborated-type-specifier

: Y_ENUM make-id
{
    ENUM_DATA edata;
    InitEnumState( &edata, $2 );
    $$ = EnumReference( &edata );
}
| Y_ENUM elaborated-type-name
{
    ENUM_DATA edata;
    InitEnumState( &edata, $2 );
    $$ = EnumReference( &edata );
}
;

namespace-definition

/* named-namespace-definition | unnamed-namespace-definition */
: namespace-key Y_LEFT_BRACE namespace-body Y_RIGHT_BRACE
;

/ non-standard /
namespace-key

: Y_NAMESPACE
{ NameSpaceUnnamed( &yylp[1] ); }
| Y_NAMESPACE expect-identifier make-id
{ NameSpaceNamed( $3 ); }
;

namespace-body

: /* nothing */
{ NameSpaceClose(); }
| might-restart-declarations
{ NameSpaceClose(); }
;

namespace-alias-definition

: Y_NAMESPACE expect-identifier make-id Y_EQUAL expect-qualified-namespace-specifier qualified-namespace-specifier
{ NameSpaceAlias( $3, $6 ); }
;

qualified-namespace-specifier

: Y_NAMESPACE_NAME
| Y_GLOBAL_NAMESPACE_NAME
| Y_SCOPED_NAMESPACE_NAME
;

using-declaration

: Y_USING qualified-id
{ NameSpaceUsingDeclId( $2 ); }
| Y_USING qualified-type-specifier
{ NameSpaceUsingDeclType( $2 ); }
| Y_USING Y_GLOBAL_TEMPLATE_NAME
{ NameSpaceUsingDeclTemplateName( $2 ); }
| Y_USING Y_SCOPED_TEMPLATE_NAME
{ NameSpaceUsingDeclTemplateName( $2 ); }
| Y_USING qualified-namespace-specifier
{
    CErr2p( ERR_NAMESPACE_NOT_ALLOWED_IN_USING_DECL, $2 );
    PTreeFreeSubtrees( $2 );
}
;

using-directive

: Y_USING Y_NAMESPACE expect-qualified-namespace-specifier qualified-namespace-specifier
{ NameSpaceUsingDirective( $4 ); }
;

asm-definition

: Y_ASM Y_LEFT_PAREN expect-string-literal string-literal Y_RIGHT_PAREN
{
    StringTrash( $4->u.string );
    PTreeFree( $4 );
    CErr1( WARN_ASM_IGNORED );
}
;

linkage-specification

: Y_EXTERN linkage-id start-linkage-block linkage-body Y_RIGHT_BRACE
{ LinkagePop(); }
;

linkage-id

: string-literal
{
    LinkagePush( $1->u.string->string );
    StringTrash( $1->u.string );
    PTreeFree( $1 );
    if( ! ScopeType( GetCurrScope(), SCOPE_FILE ) ) {
        CErr1( ERR_ONLY_GLOBAL_LINKAGES );
    }
}
;

start-linkage-block

: Y_LEFT_BRACE
{ LinkageBlock(); }
;

linkage-body

: /* nothing */
| might-restart-declarations
;

/ A.7 Declarators [gram.decl] /

init-declarator-list

: init-declarator
{
    tryCtorStyleInit( state, $1 );
}
| init-declarator-list Y_COMMA comma-init-declarator
{
    tryCtorStyleInit( state, $3 );
}
;

init-declarator

: declarator
{
    $$ = InsertDeclInfo( GetCurrScope(), $1 );
    GStackPush( &(state->gstack), GS_INIT_DATA );
    $$ = DataInitNoInit( &(state->gstack->u.initdata), $$ );
    GStackPop( &(state->gstack) );
}
| declaring-declarator initializer
{ $$ = $1; }
| ptr-mod-init-declarator
{
    $1 = FinishDeclarator( state->gstack->u.dspec, $1 );
    $$ = InsertDeclInfo( GetCurrScope(), $1 );
}
| direct-declarator Y_LEFT_PAREN expression-list Y_RIGHT_PAREN
{
    $1 = FinishDeclarator( state->gstack->u.dspec, $1 );
    $$ = InsertDeclInfo( GetCurrScope(), $1 );
    setInitWithLocn( $$, $3, &yylp[2] );
}
;

declarator

: ptr-mod-declarator
{
    $$ = FinishDeclarator( state->gstack->u.dspec, $1 );
}
| direct-declarator
{
    $$ = FinishDeclarator( state->gstack->u.dspec, $1 );
}
;

comma-init-declarator

: comma-declarator
{
    $$ = InsertDeclInfo( GetCurrScope(), $1 );
    GStackPush( &(state->gstack), GS_INIT_DATA );
    $$ = DataInitNoInit( &(state->gstack->u.initdata), $$ );
    GStackPop( &(state->gstack) );
}
| comma-declaring-declarator initializer
{ $$ = $1; }
| cv-qualifier-seq-opt ptr-mod-init-declarator
{
    $2 = AddMSCVQualifierKludge( $1, $2 );
    $2 = FinishDeclarator( state->gstack->u.dspec, $2 );
    $$ = InsertDeclInfo( GetCurrScope(), $2 );
}
| cv-qualifier-seq-opt direct-declarator Y_LEFT_PAREN expression-list Y_RIGHT_PAREN
{
    $2 = AddMSCVQualifierKludge( $1, $2 );
    $2 = FinishDeclarator( state->gstack->u.dspec, $2 );
    $$ = InsertDeclInfo( GetCurrScope(), $2 );
    setInitWithLocn( $$, $4, &yylp[3] );
}
;

declaring-declarator

: declarator
{
    $$ = InsertDeclInfo( GetCurrScope(), $1 );
    GStackPush( &(state->gstack), GS_DECL_INFO );
    state->gstack->u.dinfo = $$;
}
;

comma-declaring-declarator

: comma-declarator
{
    $$ = InsertDeclInfo( GetCurrScope(), $1 );
    GStackPush( &(state->gstack), GS_DECL_INFO );
    state->gstack->u.dinfo = $$;
}
;

comma-declarator

: cv-qualifier-seq-opt ptr-mod-declarator
{
    $2 = AddMSCVQualifierKludge( $1, $2 );
    $$ = FinishDeclarator( state->gstack->u.dspec, $2 );
}
| cv-qualifier-seq-opt direct-declarator
{
    $2 = AddMSCVQualifierKludge( $1, $2 );
    $$ = FinishDeclarator( state->gstack->u.dspec, $2 );
}
;

ptr-mod

: modifier
{ $$ = MakeFlagModifier( $1 ); }
| Y___BASED Y_LEFT_PAREN based-expression Y_RIGHT_PAREN
{ $$ = $3; }
| pragma-modifier
| ptr-operator
;

ptr-mod-init-declarator

: ptr-mod ptr-mod-init-declarator
{ $$ = AddDeclarator( $2, $1 ); }
| ptr-mod direct-declarator Y_LEFT_PAREN expression-list Y_RIGHT_PAREN
{
    $$ = AddDeclarator( $2, $1 );
    setInitWithLocn( $$, $4, &yylp[3] );
}
;

ptr-mod-declarator

: ptr-mod ptr-mod-declarator
{ $$ = AddDeclarator( $2, $1 ); }
| ptr-mod direct-declarator
{ $$ = AddDeclarator( $2, $1 ); }
;

direct-declarator

: declarator-id
{
    $$ = MakeDeclarator( state->gstack->u.dspec, $1 );
    if( $$ == NULL ) {
        what = P_SYNTAX;
    } else {
        if( $$->template_member ) {
            what = P_CLASS_TEMPLATE;
        }
    }
}
| direct-declarator Y_LEFT_PAREN parameter-declaration-clause Y_RIGHT_PAREN cv-qualifier-seq-opt exception-specification-opt
{
    $$ = AddDeclarator( $1, MakeFnType( &($3), $5, $6 ) );
    $$ = AddExplicitParms( $$, $3 );
}
| direct-declarator Y_LEFT_BRACKET constant-expression Y_RIGHT_BRACKET
{ $$ = AddArrayDeclarator( $1, $3 ); }
| direct-declarator Y_LEFT_BRACKET                     Y_RIGHT_BRACKET
{ $$ = AddArrayDeclarator( $1, NULL ); }
| Y_LEFT_PAREN ptr-mod-declarator Y_RIGHT_PAREN
{ $$ = $2; }
| Y_LEFT_PAREN direct-declarator Y_RIGHT_PAREN
{ $$ = $2; }
;

modifier

: Y___NEAR
{ $$ = TF1_NEAR; }
| Y___FAR
{ $$ = TF1_FAR; }
| Y__FAR16
{ $$ = TF1_SET_FAR16;       /* equals TF1_FAR on the 8086 */ }
| Y___FAR16
{ $$ = TF1_SET_FAR16;       /* equals TF1_FAR on the 8086 */ }
| Y___HUGE
{ $$ = TF1_SET_HUGE;        /* equals TF1_FAR on the 386 */ }
| Y__EXPORT
{ $$ = TF1_DLLEXPORT | TF1_HUG_FUNCTION; }
| Y___EXPORT
{ $$ = TF1_DLLEXPORT | TF1_HUG_FUNCTION; }
| Y___LOADDS
{ $$ = TF1_LOADDS | TF1_TYP_FUNCTION; }
| Y___SAVEREGS
{ $$ = TF1_SAVEREGS | TF1_TYP_FUNCTION; }
| Y___INTERRUPT
{ $$ = TF1_INTERRUPT | TF1_TYP_FUNCTION; }
;

based-expression

: segment-cast-opt Y___SEGNAME Y_LEFT_PAREN expect-string-literal string-literal Y_RIGHT_PAREN
{ $$ = MakeBasedModifier( TF1_BASED_STRING, $1, $5 ); }
| segment-cast-opt identifier
{ $$ = MakeBasedModifier( TF1_NULL, $1, $2 ); }
| segment-cast-opt Y_VOID
{ $$ = MakeBasedModifier( TF1_BASED_VOID, $1, NULL ); }
| segment-cast-opt Y___SELF
{ $$ = MakeBasedModifier( TF1_BASED_SELF, $1, NULL ); }
;

segment-cast-opt

: /* nothing */
{ $$ = FALSE; }
| Y_LEFT_PAREN Y___SEGMENT Y_RIGHT_PAREN
{ $$ = TRUE; }
;

pragma-modifier

: Y___PRAGMA Y_LEFT_PAREN pragma-id Y_RIGHT_PAREN
{
    $$ = MakePragma( $3->u.string->string );
    StringTrash( $3->u.string );
    PTreeFree( $3 );
}
| Y__CDECL
{ $$ = MakeIndexPragma( M_CDECL ); }
| Y___CDECL
{ $$ = MakeIndexPragma( M_CDECL ); }
| Y__FASTCALL
{ $$ = MakeIndexPragma( M_FASTCALL ); }
| Y___FASTCALL
{ $$ = MakeIndexPragma( M_FASTCALL ); }
| Y___FORTRAN
{ $$ = MakeIndexPragma( M_FORTRAN ); }
| Y__OPTLINK
{ $$ = MakeIndexPragma( M_OPTLINK ); }
| Y__PASCAL
{ $$ = MakeIndexPragma( M_PASCAL ); }
| Y___PASCAL
{ $$ = MakeIndexPragma( M_PASCAL ); }
| Y___STDCALL
{ $$ = MakeIndexPragma( M_STDCALL ); }
| Y__SYSCALL
{ $$ = MakeIndexPragma( M_SYSCALL ); }
| Y___SYSCALL
{ $$ = MakeIndexPragma( M_SYSCALL ); }
| Y__SYSTEM
{ $$ = MakeIndexPragma( M_SYSTEM ); }
| Y___WATCALL
{ $$ = MakeIndexPragma( M_WATCALL ); }
;

pragma-id

: string-literal
;

ptr-operator

: Y_TIMES cv-qualifier-seq-opt
{ $$ = MakePointerType( TF1_NULL, $2 ); }
| Y_AND cv-qualifier-seq-opt
{ $$ = MakePointerType( TF1_REFERENCE, $2 ); }
| Y_SCOPED_TIMES cv-qualifier-seq-opt
{ $$ = MakeMemberPointer( $1, $2 ); }
| nested-name-specifier Y_TEMPLATE_SCOPED_TIMES cv-qualifier-seq-opt
{ $$ = MakeMemberPointer( $2, $3 ); PTreeFreeSubtrees( $1 ); }
/* extension */
| Y_TIMES Y__SEG16 cv-qualifier-seq-opt
{ $$ = MakeSeg16Pointer( $3 ); }
;

cv-qualifier-seq-opt

: /* nothing */
{ $$ = STY_NULL; }
| Y_CONST
{ $$ = STY_CONST; }
| Y_VOLATILE
{ $$ = STY_VOLATILE; }
| Y___UNALIGNED
{ $$ = STY_UNALIGNED; }
| Y_CONST Y_VOLATILE
{ $$ = STY_CONST | STY_VOLATILE; }
| Y_VOLATILE Y_CONST
{ $$ = STY_CONST | STY_VOLATILE; }
| Y_CONST Y___UNALIGNED
{ $$ = STY_CONST | STY_UNALIGNED; }
| Y___UNALIGNED Y_CONST
{ $$ = STY_CONST | STY_UNALIGNED; }
| Y_VOLATILE Y___UNALIGNED
{ $$ = STY_VOLATILE | STY_UNALIGNED; }
| Y___UNALIGNED Y_VOLATILE
{ $$ = STY_VOLATILE | STY_UNALIGNED; }
| Y___UNALIGNED Y_CONST Y_VOLATILE
{ $$ = STY_CONST | STY_VOLATILE | STY_UNALIGNED; }
| Y___UNALIGNED Y_VOLATILE Y_CONST
{ $$ = STY_CONST | STY_VOLATILE | STY_UNALIGNED; }
| Y_VOLATILE Y_CONST Y___UNALIGNED
{ $$ = STY_CONST | STY_VOLATILE | STY_UNALIGNED; }
| Y_VOLATILE Y___UNALIGNED Y_CONST
{ $$ = STY_CONST | STY_VOLATILE | STY_UNALIGNED; }
| Y_CONST Y_VOLATILE Y___UNALIGNED
{ $$ = STY_CONST | STY_VOLATILE | STY_UNALIGNED; }
| Y_CONST Y___UNALIGNED Y_VOLATILE
{ $$ = STY_CONST | STY_VOLATILE | STY_UNALIGNED; }
;

declarator-id

: id-expression
| Y_TEMPLATE_NAME /* non-standard */
| Y_NAMESPACE_NAME /* non-standard */
| Y_TYPE_NAME /* non-standard */
| Y_GLOBAL_UNKNOWN_ID /* :: identifier */
{ $$ = MakeGlobalId( $1 ); }
| Y_SCOPED_UNKNOWN_ID
{ $$ = MakeScopedId( $1 ); }
| nested-name-specifier Y_TEMPLATE_SCOPED_UNKNOWN_ID
{ PTreeFreeSubtrees( $1 ); $$ = MakeScopedId( $2 ); }
/*
 * these Y_TEMPLATE_SCOPED_ cases are needed because of the odd way
 * template class constructors are parsed. Essentially, a constructor
 * of the form A<T>::A() gets parsed as a function with A<T> being the
 * return type and ::A being the declarator-id. zapTemplateClassDeclSpec
 * then cleans things up by converting it into a constructor.
 */
| Y_TEMPLATE_SCOPED_ID
{ $$ = MakeScopedId( $1 ); zapTemplateClassDeclSpec( state ); }
| Y_TEMPLATE_SCOPED_UNKNOWN_ID
{ $$ = MakeScopedId( $1 ); zapTemplateClassDeclSpec( state ); }
| Y_TEMPLATE_SCOPED_TILDE make-id
{ $$ = MakeScopedDestructorId( $1, $2 ); zapTemplateClassDeclSpec( state ); }
| template-scoped-conversion-function-id
{
    zapTemplateClassDeclSpec( state );
}
| template-scoped-operator-function-id
{
    zapTemplateClassDeclSpec( state );
}
;

type-id

: type-specifier-seq abstract-declarator
{
    $$ = TypeDeclarator( $2 );
    GStackPop( &(state->gstack) );
}
| type-specifier-seq
{
    $$ = DoDeclSpec( state->gstack->u.dspec );
    GStackPop( &(state->gstack) );
}
;

type-specifier-seq

: decl-specifier-seq
{
    $$ = CheckTypeSpecifier( $1 );
    if( $$ == NULL ) {
        what = P_SYNTAX;
    }
}
;

abstract-declarator

: abstract-ptr-mod-declarator
{
    $$ = FinishDeclarator( state->gstack->u.dspec, $1 );
}
| direct-abstract-declarator
{
    $$ = FinishDeclarator( state->gstack->u.dspec, $1 );
}
;

abstract-ptr-mod-declarator

: ptr-mod abstract-ptr-mod-declarator
{ $$ = AddDeclarator( $2, $1 ); }
| ptr-mod direct-abstract-declarator
{ $$ = AddDeclarator( $2, $1 ); }
| ptr-mod
{ $$ = MakeAbstractDeclarator( $1 ); }
;

direct-abstract-declarator

: direct-abstract-declarator Y_LEFT_PAREN parameter-declaration-clause Y_RIGHT_PAREN cv-qualifier-seq-opt exception-specification-opt
{
    $$ = AddDeclarator( $1, MakeFnType( &($3), $5, $6 ) );
    FreeArgs( $3 );
}
| Y_LEFT_PAREN parameter-declaration-clause Y_RIGHT_PAREN cv-qualifier-seq-opt exception-specification-opt
{
    $$ = MakeAbstractDeclarator( MakeFnType( &($2), $4, $5 ) );
    FreeArgs( $2 );
}
| direct-abstract-declarator Y_LEFT_BRACKET constant-expression Y_RIGHT_BRACKET
{ $$ = AddArrayDeclarator( $1, $3 ); }
| Y_LEFT_BRACKET constant-expression Y_RIGHT_BRACKET
{
    $$ = MakeAbstractDeclarator( NULL );
    $$ = AddArrayDeclarator( $$, $2 );
}
| direct-abstract-declarator Y_LEFT_BRACKET Y_RIGHT_BRACKET
{ $$ = AddArrayDeclarator( $1, NULL ); }
| Y_LEFT_BRACKET Y_RIGHT_BRACKET
{
    $$ = MakeAbstractDeclarator( NULL );
    $$ = AddArrayDeclarator( $$, NULL );
}
| Y_LEFT_PAREN direct-abstract-declarator Y_RIGHT_PAREN
{ $$ = $2; }
| Y_LEFT_PAREN abstract-ptr-mod-declarator Y_RIGHT_PAREN
{ $$ = $2; }
;

parameter-declaration-clause

: /* nothing */
{ $$ = NULL; }
| parameter-declaration-list
| parameter-declaration-list Y_COMMA Y_DOT_DOT_DOT
{ $$ = AddEllipseArg( $1 ); }
| parameter-declaration-list         Y_DOT_DOT_DOT
{ $$ = AddEllipseArg( $1 ); }
| Y_DOT_DOT_DOT
{ $$ = AddEllipseArg( NULL ); }
;

parameter-declaration-list

: parameter-declaration
{ $$ = AddArgument( NULL, $1 ); }
| parameter-declaration-list Y_COMMA parameter-declaration
{ $$ = AddArgument( $1, $3 ); }
;

arg-decl-specifier-seq

: decl-specifier-seq
{
    $$ = CheckArgDSpec( $1 );
    if( $$ == NULL ) {
        what = P_SYNTAX;
    }
}
;

parameter-declaration

: simple-parameter-declaration
{ GStackPop( &(state->gstack) ); }
;

/ non standard /
simple-parameter-declaration

: arg-decl-specifier-seq
{ $$ = DeclSpecDeclarator( $1 ); }
| arg-decl-specifier-seq simple-arg-no-id defarg-parse-or-copy
{ $$ = $2; }
| arg-decl-specifier-seq declarator
{ $$ = $2; }
| arg-decl-specifier-seq declarator defarg-parse-or-copy
{ $$ = $2; }
| arg-decl-specifier-seq abstract-declarator
{ $$ = $2; }
| arg-decl-specifier-seq abstract-declarator defarg-parse-or-copy
{ $$ = $2; }
;

simple-arg-no-id

: /* nothing */
{ $$ = DeclSpecDeclarator( $<dspec>0 ); }
;

defarg-parse-or-copy

: defarg-check Y_EQUAL assignment-expression
{
    DECL_INFO *dinfo;

    DbgAssert( $1 == NULL );
    dinfo = $<dinfo>0;
    dinfo->defarg_expr = $3;
    dinfo->has_defarg = TRUE;
    TokenLocnAssign( dinfo->init_locn, yylp[2] );
}
| defarg-check Y_DEFARG_GONE_SPECIAL
{
    DECL_INFO *dinfo;

    dinfo = $<dinfo>0;
    dinfo->defarg_rewrite = $1;
    dinfo->has_defarg = TRUE;
    TokenLocnAssign( dinfo->init_locn, yylp[2] );
}
;

type-defarg-parse-or-copy

: defarg-check Y_EQUAL type-id
{
    DECL_INFO *dinfo;

    DbgAssert( $1 == NULL );
    dinfo = $<dinfo>0;
    dinfo->defarg_expr = $3;
    dinfo->has_defarg = TRUE;
    TokenLocnAssign( dinfo->init_locn, yylp[2] );
}
| defarg-check Y_DEFARG_GONE_SPECIAL
{
    DECL_INFO *dinfo;

    dinfo = $<dinfo>0;
    dinfo->defarg_rewrite = $1;
    dinfo->has_defarg = TRUE;
    TokenLocnAssign( dinfo->init_locn, yylp[2] );
}
;

defarg-check

: /* nothing */
{
    if( t != Y_EQUAL ) {
        what = P_SYNTAX;
        $$ = NULL;
    } else {
        angle_bracket_stack *angle_state;

        angle_state = VstkTop( &(state->angle_stack) );
        if( state->template_decl && ( angle_state != NULL )
         && ( angle_state->paren_depth == 0 ) ) {
            $$ = RewritePackageTemplateDefArg();
            t = Y_DEFARG_GONE_SPECIAL;
        } else if( state->template_decl ) {
            $$ = RewritePackagePassThrough( currParseStack->template_record_tokens );
            t = Y_DEFARG_GONE_SPECIAL;
        } else if( ClassOKToRewrite() ) {
            $$ = RewritePackageDefArg( NULL );
            t = Y_DEFARG_GONE_SPECIAL;
        } else {
            $$ = NULL;
        }
    }
}
;

ctor-declarator

: Y_LEFT_PAREN parameter-declaration-clause Y_RIGHT_PAREN cv-qualifier-seq-opt exception-specification-opt
{
    DECL_SPEC *dspec;
    PTREE id;

    dspec = state->gstack->u.dspec;
    id = MakeConstructorId( dspec );
    if( id == NULL ) {
        what = P_SYNTAX;
    }
    $$ = MakeDeclarator( dspec, id );
    AddDeclarator( $$, MakeFnType( &($2), $4, $5 ) );
    $$ = AddExplicitParms( $$, $2 );
    if( $$->template_member ) {
        what = P_CLASS_TEMPLATE;
    } else {
        $$ = FinishDeclarator( dspec, $$ );
    }
}
;

function-declaration

: decl-specifier-seq declarator ctor-initializer
{
    $2->mem_init = $3;
    $$ = DeclFunction( state->gstack->u.dspec, $2 );
    GStackPush( &(state->gstack), GS_DECL_INFO );
    state->gstack->u.dinfo = $$;
}
| decl-specifier-seq declarator
{
    $$ = DeclFunction( state->gstack->u.dspec, $2 );
    GStackPush( &(state->gstack), GS_DECL_INFO );
    state->gstack->u.dinfo = $$;
}
| declarator ctor-initializer
{
    $1->mem_init = $2;
    $$ = DeclFunction( NULL, $1 );
    GStackPush( &(state->gstack), GS_DECL_INFO );
    state->gstack->u.dinfo = $$;
}
| declarator
{
    $$ = DeclFunction( NULL, $1 );
    GStackPush( &(state->gstack), GS_DECL_INFO );
    state->gstack->u.dinfo = $$;
}
| decl-specifier-seq ctor-declarator ctor-initializer
{
    $2->mem_init = $3;
    $$ = DeclFunction( state->gstack->u.dspec, $2 );
    GStackPush( &(state->gstack), GS_DECL_INFO );
    state->gstack->u.dinfo = $$;
}
| decl-specifier-seq ctor-declarator
{
    $$ = DeclFunction( state->gstack->u.dspec, $2 );
    GStackPush( &(state->gstack), GS_DECL_INFO );
    state->gstack->u.dinfo = $$;
}
;

function-definition

: function-declaration function-body
{
    GStackPop( &(state->gstack) );  /* decl-info */
    if( $1->has_dspec ) {
        GStackPop( &(state->gstack) );      /* decl-spec */
    }
    if( $1->body != NULL ) {
        if( ScopeType( GetCurrScope(), SCOPE_TEMPLATE_DECL ) ) {
            TemplateFunctionAttachDefn( $1 );
        } else if( ( ScopeType( GetCurrScope(), SCOPE_TEMPLATE_INST )
                && ! $1->friend_fn ) ) {
            TemplateMemberAttachDefn( $1, FALSE );
        } else if( ( ( ScopeType( GetCurrScope(), SCOPE_CLASS )
                    && ScopeType( GetCurrScope()->enclosing,
                                  SCOPE_TEMPLATE_INST ) )
                && ! $1->friend_fn ) ) {
            if( GetCurrScope()->owner.type->flag & TF1_SPECIFIC ) {
                ClassStoreInlineFunc( $1 );
            } else {
                TemplateMemberAttachDefn( $1, TRUE );
            }
        } else {
            ClassStoreInlineFunc( $1 );
        }
    } else {
        FreeDeclInfo( $1 );
    }
}
;

function-body

: check-for-rewrite Y_LEFT_BRACE absorb-body Y_RIGHT_BRACE
;

check-for-rewrite

: /* nothing */
{
    /* guards against errors from Q during rewriting:
        void foo( void )
        {
            Q::blah
        }
    */
    setNoSuperTokens( state );
}
;

absorb-body

: /* nothing */
{
    /* token will be thrown away (see check-for-rewrite) */
    ParseFlush();
    if( doFnbodyRewrite() ) {
        REWRITE *rewrite;
        rewrite = RewritePackageFunction( getMultiToken() );
        state->gstack->u.dinfo->body = rewrite;
    } else {
        FunctionBody( state->gstack->u.dinfo );
    }
    what = P_RELEX;
}
;

initializer

: init-start assignment-expression
{
    DataInitSimple( $2 );
    GStackPop( &(state->gstack) );
}
| init-start braced-initializer
{
    GStackPop( &(state->gstack) );
}
;

init-start

: Y_EQUAL
{
    DECL_INFO *dinfo;

    dinfo = state->gstack->u.dinfo;
    reuseGStack( state, GS_INIT_DATA );
    DataInitStart( &(state->gstack->u.initdata), dinfo );
    DataInitSimpleLocn( &yylp[1] );
}
;

initializer-list

: assignment-expression
{ DataInitExpr( $1 ); }
| initializer-list Y_COMMA assignment-expression
{ DataInitExpr( $3 ); }
| braced-initializer
| initializer-list Y_COMMA braced-initializer
;

/ A.8 Classes [gram.class] /

/* r/r conflict:

  • class-specifier <- class-key class-name
  • start-class <-
    /
    start-class
    : /
    nothing */
    {
    ClassStart();
    pushDefaultDeclSpec( state );
    
    }
    ;

invalid-class-name-id

: Y_GLOBAL_UNKNOWN_ID
| Y_SCOPED_UNKNOWN_ID
;

class-name-id

: Y_ID
| Y_UNKNOWN_ID
| Y_TEMPLATE_ID
| Y_TYPE_NAME
| Y_TEMPLATE_NAME
| Y_NAMESPACE_NAME
| Y_GLOBAL_ID
| Y_GLOBAL_TYPE_NAME
| Y_SCOPED_ID
| Y_SCOPED_TYPE_NAME
| invalid-class-name-id
{
    CErr2p( ERR_QUALIFIED_NAME_NOT_CLASS, $1 );
    $$ = PTreeErrorNode( $1 );
}
;

class-name

: class-name-id
{
    CLASS_DECL decl_type;
    CLNAME_STATE after_name;

    decl_type = CLASS_REFERENCE;
    switch( t ) {
    case Y_LEFT_BRACE:
    case Y_COLON:
        decl_type = CLASS_DEFINITION;
        break;
    case Y_SEMI_COLON:
        decl_type = CLASS_DECLARATION;
        break;
    }
    after_name = ClassName( $1, decl_type );
    switch( after_name ) {
    case CLNAME_CONTINUE:
        what = P_RELEX;
        break;
    case CLNAME_PROBLEM:
        what = P_DIAGNOSED;
        break;
    }
}
| nested-name-specifier
{
    CLASS_DECL decl_type;
    tc_directive tcd_control;

    tcd_control = TCD_NULL;
    decl_type = CLASS_REFERENCE;

    switch( t ) {
    case Y_LEFT_BRACE:
    case Y_COLON:
        decl_type = CLASS_DEFINITION;
        break;
    case Y_SEMI_COLON:
        if( state->template_extern ) {
            tcd_control |= TCD_EXTERN;
        } else if( state->template_instantiate ) {
            tcd_control |= TCD_INSTANTIATE;
        }
        decl_type = CLASS_DECLARATION;
        break;
    }
    ClassSpecificInstantiation( $1, decl_type, tcd_control );
    what = P_RELEX;
}
;

class-specifier

: class-key class-name
{
    $$ = ClassRefDef();
    GStackPop( &(state->gstack) );
}
| class-key class-name base-clause class-body
{ $$ = $4; }
| class-key class-name             class-body
{ $$ = $3; }
| class-key no-class-name base-clause class-body
{ $$ = $4; }
| class-key no-class-name             class-body
{ $$ = $3; }
;

class-key

: packed-class-opt Y_CLASS class-mod-opt
{
    pushClassData( state, TF1_NULL, $1, $3 );
}
| packed-class-opt Y_STRUCT class-mod-opt
{
    pushClassData( state, TF1_STRUCT, $1, $3 );
}
| packed-class-opt Y_UNION class-mod-opt
{
    pushClassData( state, TF1_UNION, $1, $3 );
}
;

class-body

: class-substance Y_RIGHT_BRACE
{
    GStackPop( &(state->gstack) );
    GStackPop( &(state->gstack) );
    $$ = $1;
}
;

class-substance

: start-class Y_LEFT_BRACE member-specification-opt
{ $$ = ClassEnd(); what = P_RELEX; }
;

no-class-name

: /* nothing */
{ ClassName( NULL, CLASS_DEFINITION ); }
;

packed-class-opt

: /* nothing */
{ $$ = CLINIT_NULL; }
| Y__PACKED
{ $$ = CLINIT_PACKED; }
;

class-mod-opt

: /* nothing */
{ $$ = NULL; }
| class-mod-seq
;

class-mod

: pragma-modifier
| modifier
{ $$ = MakeFlagModifier( $1 ); }
| ms-specific-declspec
{ $$ = MakeClassModDeclSpec( $1 ); }
;

class-mod-seq

: class-mod
| class-mod-seq class-mod
{ $$ = TypeClassModCombine( $1, $2 ); }
;

member-specification-opt

: /* nothing */
| member-specification
;

member-specification

: member-specification-opt member-declaration
| member-specification-opt access-specifier Y_COLON
{ ClassPermission( $2 ); }
;

member-declaration

: simple-member-declaration-before-semicolon Y_SEMI_COLON
| function-definition
| access-declaration Y_SEMI_COLON
| static_assert-declaration Y_SEMI_COLON
| template-declaration
| Y_SEMI_COLON
{
    SetErrLoc( &yylp[1] );
    CErr1( WARN_EMPTY_MEMBER_DECL );
}
;

simple-member-declaration-before-semicolon

: simple-member-declaration
{
    if( t != Y_SEMI_COLON ) {
        SetErrLoc( &yylocation );
        CErr1( ERR_SYNTAX_MISSING_SEMICOLON );
        what = P_DIAGNOSED;
    }
}
;

simple-member-declaration

: decl-specifier-seq member-declarator-list
{
    GStackPop( &(state->gstack) );
}
| member-declarator-list
{
}
| decl-specifier-seq
{
    $1 = CheckNoDeclarator( $1 );
    if( $1 == NULL ) {
        what = P_SYNTAX;
    }
    GStackPop( &(state->gstack) );
}
| decl-specifier-seq ctor-declarator
{
    InsertDeclInfo( GetCurrScope(), $2 );
    FreeDeclInfo( $2 );
    GStackPop( &(state->gstack) );
}
| using-declaration
;

member-declarator-list

: member-declarator
{
    VerifyMemberFunction( state->gstack->u.dspec, $1 );
}
| member-declarator-list Y_COMMA member-declarator
{
    VerifyMemberFunction( state->gstack->u.dspec, $3 );
}
;

member-declarator

: member-declaring-declarator constant-initializer
{
    $$ = $1;
    $$->sym->flag |= SF_IN_CLASS_INIT;
    DataInitSimple( $2 );
    GStackPop( &(state->gstack) );
}
| member-declaring-declarator Y_PURE_FUNCTION_SPECIAL Y_CONSTANT
{
    if( $3->op != PT_INT_CONSTANT || $3->u.int_constant != 0 ) {
        CErr1( ERR_MUST_BE_ZERO );
    }
    PTreeFree( $3 );
    $$ = $1;
}
| member-declaring-declarator
{
    $$ = $1;
    DeclNoInit( $$ );
}
| Y_COLON constant-expression
{
    ClassBitfield( state->gstack->u.dspec, NULL, $2 );
    $$ = NULL;
}
| declarator-id Y_COLON constant-expression
{
    ClassBitfield( state->gstack->u.dspec, $1, $3 );
    $$ = NULL;
}
;

member-declaring-declarator

: declarator
{
    if( t == Y_EQUAL ) {
        if( VerifyPureFunction( $1 ) ) {
            t = Y_PURE_FUNCTION_SPECIAL;
        }
    }

    $$ = InsertDeclInfo( GetCurrScope(), $1 );

    if( t == Y_EQUAL ) {
        if( ! SymIsStaticMember( $$->sym ) || ! SymIsConstant( $$->sym ) ) {
            CErr1( ERR_MUST_BE_CONST_STATIC_INTEGRAL );
        }

        GStackPush( &(state->gstack), GS_DECL_INFO );
        state->gstack->u.dinfo = $$;

        reuseGStack( state, GS_INIT_DATA );
        DataInitStart( &(state->gstack->u.initdata), $$ );
        DataInitSimpleLocn( &yylp[1] );
    }
}
;

constant-initializer

: Y_EQUAL constant-expression
{ $$ = $2; }
;

/ A.9 Derived classes [gram.derived] /

base-clause

: Y_COLON base-specifier-list
{ ClassBaseClause( $2 ); }
;

base-specifier-list

: base-specifier
{ $$ = ClassBaseList( NULL, $1 ); }
| base-specifier-list Y_COMMA base-specifier
{ $$ = ClassBaseList( $1, $3 ); }
;

base-specifier

: base-qualifiers-opt qualified-class-specifier
{ $$ = ClassBaseSpecifier( $1, $2 ); }
;

base-qualifiers-opt

: /* nothing */
{ $$ = IN_NULL; }
| base-qualifiers-opt Y_PRIVATE
{ $$ = ClassBaseQualifiers( $1, IN_PRIVATE ); }
| base-qualifiers-opt Y_PUBLIC
{ $$ = ClassBaseQualifiers( $1, IN_PUBLIC ); }
| base-qualifiers-opt Y_PROTECTED
{ $$ = ClassBaseQualifiers( $1, IN_PROTECTED ); }
| base-qualifiers-opt Y_VIRTUAL
{ $$ = ClassBaseQualifiers( $1, IN_VIRTUAL ); }
;

access-specifier

: Y_PRIVATE
{ $$ = SF_PRIVATE; }
| Y_PROTECTED
{ $$ = SF_PROTECTED; }
| Y_PUBLIC
{ $$ = SF_NULL; }
;

/ A.10 Special member functions [gram.special] /

conversion-function-id

: Y_OPERATOR conversion-type-id
{ $$ = setLocation( $2, &yylp[1] ); }
;

scoped-conversion-function-id

: Y_SCOPED_OPERATOR conversion-type-id
{
    $$ = setLocation( MakeScopedUserConversionId( $1, $2 ), &yylp[1] );
    ScopeQualifyPop();
}
| Y_GLOBAL_OPERATOR conversion-type-id
{ $$ = setLocation( $2, &yylp[1] ); }
;

template-scoped-conversion-function-id

: Y_TEMPLATE_SCOPED_OPERATOR conversion-type-id
{
    $$ = setLocation( MakeScopedUserConversionId( $1, $2 ), &yylp[1] );
    ScopeQualifyPop();
}
;

conversion-type-id

: type-specifier-seq
{
    $$ = MakeUserConversionId( $1, NULL );
    GStackPop( &(state->gstack) );
}
| type-specifier-seq conversion-declarator
{
    $$ = MakeUserConversionId( $1, $2 );
    GStackPop( &(state->gstack) );
}
;

conversion-declarator

: ptr-operator
{ $$ = MakeAbstractDeclarator( $1 ); }
| ptr-operator conversion-declarator
{ $$ = AddDeclarator( $2, $1 ); }
;

ctor-initializer

: Y_COLON
{
    if( state->template_record_tokens != NULL ) {
        PTreeFreeSubtrees( getMultiToken() );
        recordTemplateCtorInitializer( state );
        $$ = NULL;
    } else {
        $$ = RewritePackageMemInit( getMultiToken() );
    }
    what = P_RELEX;
}
;

mem-initializer-list

: mem-initializer
{ $$ = PTreeBinary( CO_LIST, NULL, $1 ); }
| mem-initializer-list Y_COMMA mem-initializer
{ $$ = PTreeBinary( CO_LIST,   $1, $3 ); }
;

mem-initializer

: qualified-class-specifier Y_LEFT_PAREN expression-list-opt Y_RIGHT_PAREN
{ $$ = MakeMemInitItem( $1, NULL, $3, &yylp[2] ); }
| identifier Y_LEFT_PAREN expression-list-opt Y_RIGHT_PAREN
{ $$ = MakeMemInitItem( NULL, $1, $3, &yylp[2] ); }
;

/ non-standard /
qualified-class-specifier

: qualified-class-type
{
    if( $$ == NULL ) {
        what = P_DIAGNOSED;
    }
}
;

/ non-standard /
qualified-class-type

: Y_TYPE_NAME
{ $$ = sendClass( $1 ); }
| Y_GLOBAL_TYPE_NAME
{ $$ = sendClass( $1 ); }
| Y_SCOPED_TYPE_NAME
{ $$ = sendClass( $1 ); }
| nested-name-specifier
{
    $$ = PTypeClassInstantiation( state->class_colon, $1 );
    if( StructType( $$->partial ) == NULL ) {
        CErr2p( ERR_EXPECTED_CLASS_TYPE, $$->partial );
        PTypeRelease( $$ );
        $$ = NULL;
    }
}
| nested-name-specifier Y_TEMPLATE_SCOPED_TYPE_NAME
{
    PTreeFreeSubtrees( $1 );
    $$ = sendClass( $2 );
}
;

/ A.11 Overloading [gram.over] /

/ TODO /
operator-function-id

: Y_OPERATOR operator
{ $$ = setLocation( MakeOperatorId( $2 ), &yylp[1] ); }
;

scoped-operator-function-id

: Y_SCOPED_OPERATOR operator
{
    $$ = setLocation( MakeScopedOperatorId( $1, $2 ), &yylp[1] );
    ScopeQualifyPop();
}
| Y_GLOBAL_OPERATOR operator
{
    $$ = setLocation( MakeGlobalOperatorId( $1, $2 ), &yylp[1] );
    ScopeQualifyPop();
}
;

template-scoped-operator-function-id

: Y_TEMPLATE_SCOPED_OPERATOR operator
{
    $$ = setLocation( MakeScopedOperatorId( $1, $2 ), &yylp[1] );
    ScopeQualifyPop();
}
;

operator

: Y_NEW
{ $$ = CO_NEW; }
| Y_DELETE
{ $$ = CO_DELETE; }
| Y_NEW Y_LEFT_BRACKET Y_RIGHT_BRACKET
{ $$ = CO_NEW_ARRAY; }
| Y_DELETE Y_LEFT_BRACKET Y_RIGHT_BRACKET
{ $$ = CO_DELETE_ARRAY; }
| Y_PLUS
{ $$ = CO_PLUS; }
| Y_MINUS
{ $$ = CO_MINUS; }
| Y_TIMES
{ $$ = CO_TIMES; }
| Y_DIV
{ $$ = CO_DIVIDE; }
| Y_PERCENT
{ $$ = CO_PERCENT; }
| Y_XOR
{ $$ = CO_XOR; }
| Y_AND
{ $$ = CO_AND; }
| Y_OR
{ $$ = CO_OR; }
| Y_TILDE
{ $$ = CO_TILDE; }
| Y_EXCLAMATION
{ $$ = CO_EXCLAMATION; }
| Y_EQUAL
{ $$ = CO_EQUAL; }
| Y_TIMES_EQUAL
{ $$ = CO_TIMES_EQUAL; }
| Y_DIV_EQUAL
{ $$ = CO_DIVIDE_EQUAL; }
| Y_PERCENT_EQUAL
{ $$ = CO_PERCENT_EQUAL; }
| Y_PLUS_EQUAL
{ $$ = CO_PLUS_EQUAL; }
| Y_MINUS_EQUAL
{ $$ = CO_MINUS_EQUAL; }
| Y_LSHIFT_EQUAL
{ $$ = CO_LSHIFT_EQUAL; }
| Y_RSHIFT_EQUAL
{ $$ = CO_RSHIFT_EQUAL; }
| Y_OR_EQUAL
{ $$ = CO_OR_EQUAL; }
| Y_AND_EQUAL
{ $$ = CO_AND_EQUAL; }
| Y_XOR_EQUAL
{ $$ = CO_XOR_EQUAL; }
| Y_LSHIFT
{ $$ = CO_LSHIFT; }
| Y_RSHIFT
{ $$ = CO_RSHIFT; }
| Y_EQ
{ $$ = CO_EQ; }
| Y_NE
{ $$ = CO_NE; }
| Y_LE
{ $$ = CO_LE; }
| Y_GE
{ $$ = CO_GE; }
| Y_LT
{ $$ = CO_LT; }
| Y_GT
{ $$ = CO_GT; }
| Y_AND_AND
{ $$ = CO_AND_AND; }
| Y_OR_OR
{ $$ = CO_OR_OR; }
| Y_PLUS_PLUS
{ $$ = CO_PRE_PLUS_PLUS; }
| Y_MINUS_MINUS
{ $$ = CO_PRE_MINUS_MINUS; }
| Y_COMMA
{ $$ = CO_COMMA; }
| Y_ARROW_STAR
{ $$ = CO_ARROW_STAR; }
| Y_ARROW
{ $$ = CO_ARROW; }
| Y_LEFT_PAREN Y_RIGHT_PAREN
{ $$ = CO_CALL; }
| Y_LEFT_BRACKET Y_RIGHT_BRACKET
{ $$ = CO_INDEX; }
| Y_SEG_OP
{ $$ = CO_SEG_OP; }
;

/ A.12 Templates [gram.temp] /

/ differs from standard /
template-declaration

: template-declaration-before-semicolon Y_SEMI_COLON
| template-function-declaration
;

/ differs from standard /
template-declaration-start

: template-key template-declaration-init lt-special template-parameter-list-opt Y_GT_SPECIAL
;

/ differs from standard /
simple-template-declaration-before-semicolon

: block-declaration-before-semicolon
| simple-member-declaration-before-semicolon
;

template-declaration-before-semicolon

: template-declaration-start simple-template-declaration-before-semicolon
{
    RewriteFree( ParseGetRecordingInProgress( NULL ) );
    state->template_decl = FALSE;
    GStackPop( &(state->gstack) ); /* GS_DECL_SPEC */
    GStackPop( &(state->gstack) ); /* GS_TEMPLATE_DATA */
}
| Y_EXPORT template-declaration-start simple-template-declaration-before-semicolon
{
    CErr1( WARN_UNSUPPORTED_TEMPLATE_EXPORT );
    RewriteFree( ParseGetRecordingInProgress( NULL ) );
    state->template_decl = FALSE;
    GStackPop( &(state->gstack) ); /* GS_DECL_SPEC */
    GStackPop( &(state->gstack) ); /* GS_TEMPLATE_DATA */
}
;

template-function-declaration

: template-declaration-start function-definition
{
    RewriteFree( ParseGetRecordingInProgress( NULL ) );
    state->template_decl = FALSE;
    GStackPop( &(state->gstack) ); /* GS_DECL_SPEC */
    GStackPop( &(state->gstack) ); /* GS_TEMPLATE_DATA */
}
| Y_EXPORT template-declaration-start function-definition
{
    CErr1( WARN_UNSUPPORTED_TEMPLATE_EXPORT );
    RewriteFree( ParseGetRecordingInProgress( NULL ) );
    state->template_decl = FALSE;
    GStackPop( &(state->gstack) ); /* GS_DECL_SPEC */
    GStackPop( &(state->gstack) ); /* GS_TEMPLATE_DATA */
}
;

/ non standard /
template-declaration-init

: /* nothing */
{
    GStackPush( &(state->gstack), GS_TEMPLATE_DATA );
    TemplateDeclInit( &(state->gstack->u.templatedata) );
}
;

/ non standard /
template-parameter-list-opt

: /* nothing */
{
    pushDefaultDeclSpec( state );
    state->template_record_tokens = RewriteRecordInit( &(state->template_record_locn) );
}
| template-parameter-list
{
    pushDefaultDeclSpec( state );
    state->template_record_tokens = RewriteRecordInit( &(state->template_record_locn) );
}
;

template-parameter-list

: template-parameter
{
    TemplateDeclAddArgument( $1 );
}
| template-parameter-list Y_COMMA template-parameter
{
    TemplateDeclAddArgument( $3 );
}
;

template-parameter

: type-parameter
| parameter-declaration
;

type-parameter

: type-parameter-no-defarg
| type-parameter-no-defarg type-defarg-parse-or-copy
;

/ non standard /
type-parameter-no-defarg

: template-typename-key
{
    DECL_SPEC *dspec;

    pushClassData( state, TF1_NULL, CLINIT_NULL, NULL );
    ClassName( NULL, CLASS_GENERIC );
    dspec = ClassRefDef();
    GStackPop( &(state->gstack) );
    $$ = DeclSpecDeclarator( dspec );
    PTypeRelease( dspec );
}
| template-typename-key make-id
{
    DECL_SPEC *dspec;

    pushClassData( state, TF1_NULL, CLINIT_NULL, NULL );
    ClassName( $2, CLASS_GENERIC );
    dspec = ClassRefDef();
    GStackPop( &(state->gstack) );
    $$ = DeclSpecDeclarator( dspec );
    PTypeRelease( dspec );
}
;

/ non standard /
template-typename-key

: Y_TYPENAME
{ }
| Y_CLASS
{ }
;

template-id

: Y_TEMPLATE_ID lt-special template-argument-list-opt Y_GT_SPECIAL
{
    $3 = NodeReverseArgs( NULL, $3 );
    $3->flags |= PTF_ALREADY_ANALYSED;
    $$ = PTreeBinary( CO_TEMPLATE, $1, $3 );
}
;

scoped-template-id

: Y_SCOPED_TEMPLATE_ID lt-special template-argument-list-opt Y_GT_SPECIAL
{
    $3 = NodeReverseArgs( NULL, $3 );
    $3->flags |= PTF_ALREADY_ANALYSED;
    $$ = PTreeBinary( CO_TEMPLATE, MakeScopedId( $1 ), $3 );
}
| Y_GLOBAL_TEMPLATE_ID lt-special template-argument-list-opt Y_GT_SPECIAL
{
    $3 = NodeReverseArgs( NULL, $3 );
    $3->flags |= PTF_ALREADY_ANALYSED;
    $$ = PTreeBinary( CO_TEMPLATE, MakeScopedId( $1 ), $3 );
}
;

template-argument-list

: template-argument
{ $$ = PTreeBinary( CO_LIST, NULL, $1 ); }
| template-argument-list Y_COMMA template-argument
{ $$ = setLocation( PTreeBinary( CO_LIST, $1, $3 ), &yylp[2] ); }
;

template-argument

: assignment-expression
{
    $1 = AnalyseRawExpr( $1 );
    if( $1->op == PT_SYMBOL ) {
        SYMBOL sym = $1->u.symcg.symbol;
        if( SymIsConstantInt( sym ) ) {
            PTreeFreeSubtrees( $1 );
            $1 = PTreeIntConstant( sym->u.sval, TYP_SINT );
        }
    }
    $$ = $1;
}
| type-id
;

/ TODO /
typename-specifier

: typename-special nested-name-specifier Y_TEMPLATE_SCOPED_TYPE_NAME
{
    $$ = sendType( $3 );
    PTreeFreeSubtrees( $2 );
}
| typename-special nested-name-specifier
{
    $$ = sendType( $2 );
}
| typename-special Y_SCOPED_TYPE_NAME
{
    $$ = sendType( $2 );
}
;

/ non-standard /
explicit-instantiation-special

: Y_TEMPLATE
{
    state->template_instantiate = TRUE;
}
| Y_EXTERN Y_TEMPLATE
{
    state->template_extern = TRUE;
}
;

explicit-instantiation

: Y_EXTERN Y_TEMPLATE template-class-directive-extern Y_SEMI_COLON
{
    CErr1( WARN_MISSING_KEYWORD_IN_EXPLICT_INSTANTIATION );
}
| Y_TEMPLATE template-class-directive-instantiate Y_SEMI_COLON
{
    CErr1( WARN_MISSING_KEYWORD_IN_EXPLICT_INSTANTIATION );
}
| explicit-instantiation-special block-declaration-before-semicolon Y_SEMI_COLON
{
    state->template_instantiate = FALSE;
    state->template_extern = FALSE;
}
;

template-key

: Y_TEMPLATE
{
    if( state->template_decl ) {
        CErr1( ERR_NO_NESTED_TEMPLATES );
    } else if( ! ScopeType( GetCurrScope(), SCOPE_FILE )
            && ! ScopeType( GetCurrScope(), SCOPE_CLASS ) ) {
        CErr1( ERR_ONLY_GLOBAL_TEMPLATES );
    }
    state->template_decl = TRUE;
}
;

template-argument-list-opt

: /* nothing */
{ $$ = PTreeBinary( CO_LIST, NULL, NULL ); }
| template-argument-list
{ $$ = $1; }
;

template-class-directive-extern

: nested-name-specifier
{
    TYPE type = NodeIsBinaryOp( $1, CO_STORAGE ) ?
        $1->u.subtree[1]->type : $1->type;

    TemplateClassDirective( type, &($1->locn), TCD_EXTERN ); 
    NodeFreeDupedExpr( $1 );
}
;

template-class-directive-instantiate

: nested-name-specifier
{
    TYPE type = NodeIsBinaryOp( $1, CO_STORAGE ) ?
        $1->u.subtree[1]->type : $1->type;

    TemplateClassDirective( type, &($1->locn), TCD_INSTANTIATE ); 
    NodeFreeDupedExpr( $1 );
}
;

template-type

: template-type-instantiation Y_GT_SPECIAL
;

template-type-instantiation

: Y_TEMPLATE_NAME lt-special template-argument-list-opt
{
    TYPE inst_type;

    inst_type = TemplateClassReference( $1, $3 );
    setWatchColonColon( state, $1, inst_type );
    $$ = $1;

    if( inst_type != NULL ) {
        $$->type = inst_type;
    }
}
;

scoped-template-type

: scoped-template-type-instantiation Y_GT_SPECIAL
;

scoped-template-type-instantiation

: Y_SCOPED_TEMPLATE_NAME lt-special template-argument-list-opt
{
    TYPE inst_type;

    inst_type = TemplateClassReference( $1, $3 );
    setWatchColonColon( state, $1, inst_type );
    $$ = $1;

    if( inst_type == NULL ) {
        DbgAssert( ( $$->op == PT_BINARY )
                && ( $$->cgop == CO_STORAGE ) );
        $$->u.subtree[1] =
            PTreeBinary( CO_TEMPLATE, $$->u.subtree[1], $3 );
    } else {
        $$->u.subtree[1]->type = inst_type;
    }
}
| Y_GLOBAL_TEMPLATE_NAME lt-special template-argument-list-opt
{
    TYPE inst_type;

    inst_type = TemplateClassReference( $1, $3 );
    setWatchColonColon( state, $1, inst_type );
    $$ = $1;

    if( inst_type == NULL ) {
        DbgAssert( ( $$->op == PT_BINARY )
                && ( $$->cgop == CO_STORAGE ) );
        $$->u.subtree[1] =
            PTreeBinary( CO_TEMPLATE, $$->u.subtree[1], $3 );
    } else {
        $$->u.subtree[1]->type = inst_type;
    }
}
;

template-scoped-template-type

: template-scoped-template-type-instantiation Y_GT_SPECIAL
;

template-scoped-template-type-instantiation

: Y_TEMPLATE_SCOPED_TEMPLATE_NAME lt-special template-argument-list-opt
{
    TYPE inst_type;

    inst_type = TemplateClassReference( $1, $3 );
    setWatchColonColon( state, $1, inst_type );
    $$ = $1;

    if( inst_type == NULL ) {
        DbgAssert( ( $$->op == PT_BINARY )
                && ( $$->cgop == CO_STORAGE ) );
        $$->u.subtree[1] =
            PTreeBinary( CO_TEMPLATE, $$->u.subtree[1], $3 );
    } else {
        $$->u.subtree[1]->type = inst_type;
    }
}
;

/ A.13 Exception handling [gram.except] /

exception-declaration

: actual-exception-declaration
{
    $$ = $1;
    GStackPop( &(state->gstack) );
}
;

actual-exception-declaration

: type-specifier-seq declarator
{ $$ = $2; }
| type-specifier-seq abstract-declarator
{ $$ = $2; }
| type-specifier-seq
{ $$ = DeclSpecDeclarator( state->gstack->u.dspec ); }
;

exception-specification-opt

: /* nothing */
{ $$ = ThrowsAnything(); }
| exception-specification
;

exception-specification

: Y_THROW Y_LEFT_PAREN type-id-list Y_RIGHT_PAREN
{ $$ = $3; }
| Y_THROW Y_LEFT_PAREN              Y_RIGHT_PAREN
{ $$ = NULL; }
;

type-id-list

: expect-type-id type-id
{ $$ = $2; }
| type-id-list Y_COMMA expect-type-id type-id
{ $$ = PTreeTListAppend( $1, $4 ); }
;

/ declaration syntax /
might-restart-declarations

: start-restart-declarations
{ popRestartDecl( state ); }
| start-restart-declarations declaration-seq
{ popRestartDecl( state ); }
;

start-restart-declarations

: /* nothing */
{ pushRestartDecl( state ); }
;

local-declaration

: block-declaration-before-semicolon Y_SEMI_COLON
;

no-declarator-declaration

: decl-specifier-seq
{
    $$ = CheckNoDeclarator( $1 );
    if( $$ == NULL ) {
        what = P_SYNTAX;
    }
}
;

/ extension /
typeof-specifier

: Y___TYPEOF Y_LEFT_PAREN expression Y_RIGHT_PAREN
{ $$ = PTypeExpr( $3 ); }
| Y___TYPEOF Y_LEFT_PAREN type-id Y_RIGHT_PAREN
{ $$ = PTypeTypeid( $3 ); }
;

cv-qualifier

: Y_CONST
{ $$ = PTypeSpecifier( STY_CONST ); }
| Y_VOLATILE
{ $$ = PTypeSpecifier( STY_VOLATILE ); }
| Y___UNALIGNED
{ $$ = PTypeSpecifier( STY_UNALIGNED ); }
;

/ non-standard /
basic-type-specifier

: Y_CHAR
{ $$ = PTypeScalar( STM_CHAR ); }
| Y_WCHAR_T
{ $$ = PTypeScalar( STM_WCHAR ); }
| Y_BOOL
{ $$ = PTypeScalar( STM_BOOL ); }
| Y_SHORT
{ $$ = PTypeScalar( STM_SHORT ); }
| Y_INT
{ $$ = PTypeScalar( STM_INT ); }
| Y_LONG
{ $$ = PTypeScalar( STM_LONG ); }
| Y_SIGNED
{ $$ = PTypeScalar( STM_SIGNED ); }
| Y_UNSIGNED
{ $$ = PTypeScalar( STM_UNSIGNED ); }
| Y_FLOAT
{ $$ = PTypeScalar( STM_FLOAT ); }
| Y_DOUBLE
{ $$ = PTypeScalar( STM_DOUBLE ); }
| Y_VOID
{ $$ = PTypeScalar( STM_VOID ); }
/* extension */
| Y___SEGMENT
{ $$ = PTypeScalar( STM_SEGMENT ); }
| Y___INT8
{ $$ = PTypeScalar( STM_CHAR ); }
| Y___INT16
{ $$ = PTypeScalar( STM_SHORT ); }
| Y___INT32
{ $$ = PTypeScalar( STM_INT32 ); }
| Y___INT64
{ $$ = PTypeScalar( STM_INT64 ); }
;

elaborated-type-name

: Y_GLOBAL_ID
| Y_GLOBAL_TEMPLATE_ID
| Y_GLOBAL_TYPE_NAME
| Y_SCOPED_ID
| Y_SCOPED_TEMPLATE_ID
| Y_SCOPED_TYPE_NAME
;

braced-initializer

: brace-start initializer-list Y_COMMA Y_RIGHT_BRACE
{ DataInitPop(); }
| brace-start initializer-list         Y_RIGHT_BRACE
{ DataInitPop(); }
;

brace-start

: Y_LEFT_BRACE
{ DataInitPush(); }
;

typename-special

: typename-special-init Y_TYPENAME
{
    if( ! ScopeType( GetCurrScope(), SCOPE_TEMPLATE_DECL )
     && ! IsTemplateInstantiationActive() ) {
        SetErrLoc( &yylp[2] );
        CErr1( ERR_TYPENAME_OUTSIDE_TEMPLATE );
    }
}
;

typename-special-init

: /* nothing */
{
    state->special_typename = TRUE;
}
;

special-new-type-id

: type-specifier-seq special-new-abstract-declarator
{
    $$ = $2;
    GStackPop( &(state->gstack) );
}
| type-specifier-seq
{
    $$ = MakeNewTypeId( DoDeclSpec( state->gstack->u.dspec ) );
    GStackPop( &(state->gstack) );
}
;

special-new-abstract-declarator

: special-new-abstract-ptr-mod-declarator
{
    $$ = FinishDeclarator( state->gstack->u.dspec, $1 );
}
| special-new-direct-abstract-declarator
{
    $$ = FinishDeclarator( state->gstack->u.dspec, $1 );
}
;

special-new-abstract-ptr-mod-declarator

: ptr-mod special-new-abstract-ptr-mod-declarator
{ $$ = AddDeclarator( $2, $1 ); }
| ptr-mod special-new-direct-abstract-declarator
{ $$ = AddDeclarator( $2, $1 ); }
| ptr-mod
{ $$ = MakeAbstractDeclarator( $1 ); }
;

special-new-direct-abstract-declarator

: special-new-direct-abstract-declarator Y_LEFT_PAREN parameter-declaration-clause Y_RIGHT_PAREN cv-qualifier-seq-opt exception-specification-opt
{
    $$ = AddDeclarator( $1, MakeFnType( &($3), $5, $6 ) );
    FreeArgs( $3 );
}
| Y_LEFT_PAREN parameter-declaration-clause Y_RIGHT_PAREN cv-qualifier-seq-opt exception-specification-opt
{
    $$ = MakeAbstractDeclarator( MakeFnType( &($2), $4, $5 ) );
    FreeArgs( $2 );
}
| special-new-direct-abstract-declarator Y_LEFT_BRACKET constant-expression Y_RIGHT_BRACKET
{ $$ = AddArrayDeclarator( $1, $3 ); }
| Y_LEFT_BRACKET expression Y_RIGHT_BRACKET
{ $$ = MakeNewDynamicArray( $2 ); }
| special-new-direct-abstract-declarator Y_LEFT_BRACKET Y_RIGHT_BRACKET
{ $$ = AddArrayDeclarator( $1, NULL ); }
| Y_LEFT_BRACKET Y_RIGHT_BRACKET
{
    $$ = MakeAbstractDeclarator( NULL );
    $$ = AddArrayDeclarator( $$, NULL );
}
| Y_LEFT_PAREN special-new-direct-abstract-declarator Y_RIGHT_PAREN
{ $$ = $2; }
| Y_LEFT_PAREN special-new-abstract-ptr-mod-declarator Y_RIGHT_PAREN
{ $$ = $2; }
;

%%

你可能感兴趣的:(Open Watcom的C++语法)