/* ckit/cmm.g */

options
{
   /* output file names */

   common_header = cmm_data; // common header (.hpp) (enumerations, class names)
   common_name = cmm_data; // common code (.cpp)

   // public_header  = cmm_public;  // public header (.hpp) (classes)
   // private_header = cmm_private; // private header (.hpp) (private classes)

   // symbol_header = cmm_symbol; // symbol type header (.hpp) (enumeration)

   lexer_name = cmm_lexer; // output file name prefix (.gpp, .hpp, .cpp)
   parser_name = cmm_parser; // output file name prefix (.gpp, .hpp, .cpp)

   product_name = cmm_product; // output file name prefix (.hpp, .cpp)

   /* iput file names */

   // product_input = "ext.h"; // input include file with additional product declarations

   /* classes and namespaces */

   // product_namespace = finch;
   automatic_namespace = true;

   lexer_class = CmmLexer;
   lexer_super_class = TLexerInput;

   parser_class = CmmParser;
   // parser_super_class = TEnvInput;

   product_class = CmmProduct;
   product_super_class = CmmOutput;

   /* options */

   // switchable_literals = true;
   // tree_code = true;
   // open_method = true; // open_parser and close_parser methods

   // notes = true; // store comments and spaces
   // only_start_notes = true;
   // fixed_notes = true; // true .. variables, not array

   locations = true; // store line numbers

   // ignore_locations = true;
   // ignore_notes = true;

   // note_type = CmmNote;
   location_type = CmmLocation;
   mark_type = CmmMark;

   // note_init = "\"\"";
   location_init = "NULL"; // initialization value for locations

   // anonymous_fields = true;
   ignore_send_options = true; // no custom send, ...
   // ignore_output_options = true; // no custom output, internal_output
   // ignore_execute_options = true; // no execute methods
   // ignore_product_constructor = true; // only for gram
  initialize_variables = true;

   // antlr_mode = true;
   // lexer_input = "lex.g";
   // product_namespace = finch;

   symbol_type = CmmSymbol;
   no_symbol = NONE;
   keyword_prefix = LITERAL_ ;

   // subst_type = CmmDefineItem;
   // replace_type = CmmEntry;

   /* identifiers */

   /*
   rule_prefix = rule_ ;
   type_prefix = type_ ;

   field_prefix = field_ ;
   list_prefix = queue_ ;
   internal_prefix = internal_ ;

   send_func_prefix = send_fce_ ;
   send_internal_prefix = original_ ;
   open_func_prefix = open_fce_ ;
   close_func_prefix = close_fce_ ;

   conv_func_prefix = convert_ ;
   util_func_prefix = utility_ ;

   param_prefix = parameter_ ;
   temp_prefix = temporary_ ;
   local_prefix = local_ ;
   variable_prefix = variable_ ;
   literal_prefix = literal_ ;
   */

   /*
   symbol_type = enum_CmmSymbol;
   no_symbol = no_symbol;
   primitive_prefix = simple_ ;
   delimiter_prefix = delimiter_ ;
   keyword_prefix = keyword_ ;
   */

   basic_type = CmmBasic;
   expr_type = CmmExpr;

   binary_expr_type     = CmmBinaryExpr;
   binary_expr_left     = left;
   binary_expr_right    = right;
   binary_expr_selector = kind;

   unary_expr_type     = CmmUnaryExpr;
   unary_expr_param    = param;
   unary_expr_selector = kind;
}

/* --------------------------------------------------------------------- */

/* extension of cmm_data.hpp */

extension common_include
{@@
@@}

extension common_header
{@@
class TInputItem;
typedef TInputItem * CmmMark;
typedef TInputItem * CmmLocation;

class CttItem;
class CttFunctionParams;
class CttTemplateParams;
class CttEval;
@@}

extension common_tail
{@@
@@}

/* extension of CmmBasic class */

extension common_class
{@@
@@}

/* --------------------------------------------------------------------- */

extension lexer_include
{@@
#include "input.h"
#include "ioexception.h"
@@}

extension lexer_header
{@@
@@}

extension lexer_class
{@@
public:
   virtual void translate ();
   void close_parser ();
@@}

/* --------------------------------------------------------------------- */

/* extension of cmm_parser.h and CmmParser class */

extension parser_include
{@@
@@}

extension parser_header
{@@
@@}

extension parser_class
{@@
public:
   bool examine_type_name (CmmName * name);
   bool examine_type_or_declaration (bool decl,
                                     bool parenthesis,
                                     bool common);
@@}

/* --------------------------------------------------------------------- */

/* extension of cmm_product.h and CmmProduct class */

extension product_include
{@@
   #include "output.h"
@@}

extension product_header
{@@
@@}

extension product_class
{@@
@@}

/* --------------------------------------------------------------------- */

literals // identifiers for C++ literals
{
   LPAREN     : '(' ;
   RPAREN     : ')' ;
   LBRACKET   : '[' ;
   RBRACKET   : ']' ;
   LBRACE     : '{' ;
   RBRACE     : '}' ;

   DOT        : '.'  ;
   ARROW      : "->" ;
   SCOPE      : "::" ;

   LOG_NOT    : '!' ;
   BIT_NOT    : '~' ;

   INC        : "++"  ;
   DEC        : "--"  ;

   DOT_STAR   : ".*"  ;
   ARROW_STAR : "->*" ;

   STAR       : '*' ;
   SLASH      : '/' ;
   MOD        : '%' ;

   PLUS       : '+' ;
   MINUS      : '-' ;

   SHL        : "<<" ;
   SHR        : ">>" ;

   LESS             : '<'  ;
   GREATER          : '>'  ;
   LESS_OR_EQUAL    : "<=" ;
   GREATER_OR_EQUAL : ">=" ;

   EQUAL            : "==" ;
   UNEQUAL          : "!=" ;

   BIT_AND    : '&' ;
   BIT_XOR    : '^' ;
   BIT_OR     : '|' ;

   LOG_AND    : "&&" ;
   LOG_OR     : "||" ;

   ASSIGN         : '='   ;
   MUL_ASSIGN     : "*="  ;
   DIV_ASSIGN     : "/="  ;
   MOD_ASSIGN     : "%="  ;
   PLUS_ASSIGN    : "+="  ;
   MINUS_ASSIGN   : "-="  ;
   SHL_ASSIGN     : "<<=" ;
   SHR_ASSIGN     : ">>=" ;
   BIT_AND_ASSIGN : "&="  ;
   BIT_XOR_ASSIGN : "^="  ;
   BIT_OR_ASSIGN  : "|="  ;

   QUESTION   : '?' ;
   COMMA      : ',' ;

   COLON      : ':' ;
   SEMICOLON  : ';' ;
   DOTS       : "..." ;
}

/* --------------------------------------------------------------------- */

// CmmAccess type shared by CmmMemberSect and CmmBaseItem

enum CmmAccess
{
   NoAccess, // default value
   PrivateAccess,
   ProtectedAccess,
   PublicAccess
};

struct CmmMemberVisibility
{
   CmmAccess access;
};

struct CmmBaseItem
{
   CmmAccess access;
};

// data used during declaration processig

struct CmmBasic
{
   CmmBasic * next_usage;
};

struct CmmName
{
   CttItem * name_ref;
   CttItem * base_ref;
   string replace; // anonymous types !?
};

struct CmmContName
{
   CttItem * cont_ref;
};

struct CmmDeclarator
{
   CmmDeclarator * save; // used by inner declarator

   // data used by declaraton processing

   CmmAccess access_val;

   bool separate_decl; // declaration outside of class
   CmmSimpleDecl * actual_decl; // corresponding declaration

   string short_name; // identifier !?
   CmmName * long_name; // qualified name !?

   CttFunctionParams * function_param_ref; // function parameters
};

struct CmmFunctionSpecifier
{
   CttFunctionParams * param_ref;
};

/* --------------------------------------------------------------------- */

parser ;

/* --------------------------------------------------------------------- */

identifier <primitive> <identifier> <custom send, output>:
  IDENT ;

numeric_literal <primitive> <custom output>:
  NUMBER ;

char_literal <primitive> <custom output>:
  CHAR_LITERAL ;

string_literal <primitive> <custom output>:
  STRING_LITERAL ;

/* --------------------------------------------------------------------- */

/* compound name */

base_subst <modify CmmName> <custom subst, output>:
  id: identifier;

base_name <modify CmmName>:
  (
     spec: special_function
  |
     <call> base_subst // !? last - important
  );

base_args <modify CmmName>:
  (
    { is_template_arg }? // %%
    template_args:template_arg_list
  )? ;

cont_item <CmmContName>:
  <no_space> "::" <no_space>
  <call> cont_name
  <execute add_name>
  <call> cont_args ;

cont_subst <modify CmmContName> <custom subst, output>:
  id: identifier;

cont_name <modify CmmContName>:
  (
     '~' <no_space> <set a_destructor = true>
  |
     "template" <set a_template = true>
  )?
  (
     spec: special_function
  |
     <call> cont_subst // !? last - important
  );

cont_args <modify CmmContName>:
  (
     { is_cont_template_arg }? // %%
     template_args:template_arg_list
  )? ;

compound_name <modify CmmName> <custom list_subst, output, internal_output>:
  <execute open_name>
  <call> base_name
  <execute start_name>
  <call> base_args
  ( <add> cont_item )*
  <execute close_name> ;

simple_name <modify CmmName> <custom output, internal_output>:
  <execute open_name>
  <call> base_name
  <execute start_name>
  <execute close_name> ;

global_mark <modify CmmName>:
  ( "::" <set a_global = true> )? ;

/* --------------------------------------------------------------------- */

/* qualified name */

qualified_name <CmmName>:
  // identifer used in simple expression
  <call> compound_name ;

/* global name */

global_name <CmmName>:
  // namespaces, using declarations and class member initialization
  <call> global_mark
  <call> compound_name ;

/* declaring name */

global_declaring_name <CmmName>:
  // type used in declaration specifiers
  <call> global_mark
  <call> compound_name
  <execute check_type> ;

/* type name */

global_type_name <CmmName>:
  // after typename keyword or in base class specification
  <execute open_type_name>
  <call> global_mark
  <call> compound_name
  <execute close_type_name>
  <execute check_type> ;

/* new name */

simple_new_name <CmmName>:
  // namespace definition, enumeration item, template type parameter
  <execute open_new_name>
  <call> simple_name
  <execute close_new_name> ;

global_new_name <CmmName>:
  // identifier in declarator, class or enumeration type
  <execute open_new_name>
  <call> global_mark
  <call> compound_name
  <execute close_new_name> ;

/* --------------------------------------------------------------------- */

/* id expr */

id_expr <return CmmName:CmmExpr>:
   <result> qualified_name;

/* primary expression */

primary_expr <select CmmExpr>:
    numeric_literal_expr
  | char_literal_expr
  | string_literal_expr
  | this_expr
  | subexpr_expr
  | id_expr // !? last - important
  ;

numeric_literal_expr <CmmNumValue:CmmExpr>:
  value:numeric_literal;

char_literal_expr <CmmCharValue:CmmExpr>:
  value:char_literal;

string_literal_cont <CmmStringCont>:
  value:string_literal;

string_literal_expr <CmmStringValue:CmmExpr>:
  value:string_literal
  ( <add> string_literal_cont )*; // !?

this_expr <CmmThisExpr:CmmExpr>:
  "this";

subexpr_expr <CmmSubexprExpr:CmmExpr>:
  '(' param:expr ')';

/* postfix expression */

postfix_start <select CmmExpr>:
    modern_cast_expr
  | typeid_expr
  | typename_expr // !?
  | type_change_expr // !?
  | primary_expr ; // !? last - important

modern_cast_expr <CmmModernCastExpr:CmmExpr>:
  ( "dynamic_cast"       <set kind = DynamicCast>
  | "static_cast"        <set kind = StaticCast>
  | "const_cast"         <set kind = ConstCast>
  | "reinterpret_cast"   <set kind = ReinterpreterCast> )
  '<' <no_space> type:type_id <no_space> '>'
  '(' param:expr ')'
  ;

typeid_expr <CmmTypeidExpr:CmmExpr>:
  "typeid"
  '('
  (
     { is_type () }? // %%
     param1:type_id
  |
     param2:expr
  )
  ')'
  ;

typename_expr <CmmTypenameExpr:CmmExpr>:
  "typename"
  name:global_type_name
  '(' list:expr_list ')' ;

type_change_expr <CmmTypechangeExpr:CmmExpr>: // !?
  (
    "signed"   <set a_signed = true>   |
    "unsigned" <set a_unsigned = true> |

    "short"    <set a_short = true>    |

    "long"     <set a_long = true>
       ( "long"   <set a_long_long = true> )? |
       // !? @@ long long

    "bool"     <set a_bool = true>     |
    "char"     <set a_char = true>     |
    "wchar_t"  <set a_wchar = true>    |
    "int"      <set a_int = true>      |
    "float"    <set a_float = true>    |
    "double"   <set a_double = true>   |
    "void"     <set a_void = true>
  )
  '(' list:expr_list ')' ;

postfix_expr <choose CmmExpr>:
  postfix_start
  (
    index_expr |
    call_expr |
    field_expr |
    ptr_field_expr |
    post_inc_expr |
    post_dec_expr
  )* ;

index_expr <CmmIndexExpr:CmmExpr>:
  <store left:CmmExpr>
  '[' right:expr ']' ;

call_expr <CmmCallExpr:CmmExpr>:
  <store param:CmmExpr>
  '(' list:expr_list ')' ;

field_expr <CmmFieldExpr:CmmExpr>:
  <store param:CmmExpr>
  <no_space> '.' <no_space>
  (
     '~' <no_space> <set destructor_name = true>
  |
     "template" <set template_name = true>
  )?
  <execute open_field_template>
  name:id_expr
  <execute close_field_template> ;

ptr_field_expr <CmmPtrFieldExpr:CmmExpr>:
  <store param:CmmExpr>
  <no_space> "->" <no_space>
  (
     '~' <no_space> <set destructor_name = true>
  |
     "template" <set template_name = true>
  )?
  <execute open_ptr_field_template>
  name:id_expr
  <execute close_ptr_field_template> ;

post_inc_expr <CmmPostIncExpr:CmmExpr>:
  <store param:CmmExpr>
  "++" ;

post_dec_expr <CmmPostDecExpr:CmmExpr>:
  <store param:CmmExpr>
  "--" ;

expr_list <CmmExprList> <custom subst>:
  ( <add> assignment_expr (',' <add> assignment_expr)* )? ;

/* unary expression */

unary_expr <select CmmExpr>:
    inc_expr
  | dec_expr
  | deref_expr
  | addr_expr
  | plus_expr
  | minus_expr
  | bit_not_expr
  | log_not_expr
  | scope_expr // !?
  | sizeof_expr
  | allocation_expr
  | deallocation_expr
  | postfix_expr ; // !? last - important

inc_expr <unary>:
  "++" IncExp cast_expr;

dec_expr <unary>:
  "--" DecExp cast_expr;

deref_expr <unary>:
  '*' DerexExp cast_expr;

addr_expr <unary>:
  '&' AddrExp cast_expr;

plus_expr <unary>:
  '+' PlusExp cast_expr;

minus_expr <unary>:
  '-' MinusExp cast_expr;

bit_not_expr <unary>:
  '~' BitNotExp cast_expr;

log_not_expr <unary>:
  '!' LogNotExp cast_expr;

scope_expr <unary>: // !?
   "::" ScopeExp cast_expr ;

sizeof_expr <CmmSizeofExp:CmmExpr>:
  "sizeof"
  (
     { is_type_in_parenthesis () }? // %%
     '(' param1:type_id ')'
  |
     param2:unary_expr
  );

/* new */

allocation_expr <CmmNewExpr:CmmExpr>:
  // ( "::" <set a_global = true> )?
  "new"
  (
     { is_parenthesis_and_expression () }? // %%
     placement:new_placement
  )?
  (
     type1:new_type_id
  |
    '(' type2:type_id ')'
  )
  (
    '(' init:expr_list ')'
  )? ;

new_placement <CmmNewPlacement>:
  '(' list:expr_list ')' ;

new_type_id <CmmNewTypeId>:
  spec:type_specifiers
  ptr:ptr_specifier_list
  ( <add> allocation_array_limit )* ;

allocation_array_limit <CmmNewArrayLimit>:
  '[' value:expr ']'  ;

/* delete */

deallocation_expr <CmmDeleteExpr:CmmExpr>:
  // ( "::" <set a_global = true> )?
  "delete"
  ( '[' ']' <set a_array = true> )?
  param:cast_expr ;

/* cast expression */

cast_expr <select CmmExpr>:
    { is_type_in_parenthesis () }? // %%
    // ( cast_formula ) =>
    cast_formula
  |
    unary_expr ;

cast_formula <CmmCastFormula: CmmExpr>:
  '(' type:type_id ')' param:cast_expr ;

/* pm expression */

pm_expr <binary>:
  cast_expr
  ".*"  DotMemberExp
  "->*" ArrowMemverExp ;

/* arithmetic and logical expressions */

multiplicative_expr <binary>:
  pm_expr
  '*' MulExp
  '/' DivExp
  '%' ModExp ;

additive_expr <binary>:
  multiplicative_expr
  '+' AddExp
  '-' SubExp ;

shift_expr <binary>:
  additive_expr
  "<<" ShlExp
  ">>" ShrExp ;

relational_expr <binary>:
  shift_expr
  '<' LtExp
  '>' GtExp
  "<=" LeExp
  ">=" GeExp ;

equality_expr <binary>:
  relational_expr
  "==" EqExp
  "!=" NeExp ;

and_expr <binary>:
  equality_expr
  '&' BitAndExp ;

exclusive_or_expr <binary>:
  and_expr
  '^' BitXorExp ;

inclusive_or_expr <binary>:
  exclusive_or_expr
  '|' BitOrExp ;

logical_and_expr <binary>:
  inclusive_or_expr
  "&&" LogAndExp ;

logical_or_expr <binary>:
  logical_and_expr
  "||" LogOrExp ;

/* conditional expression */

conditional_expr <choose CmmExpr>:
  logical_or_expr
  ( conditional_cont_expr )? ;

conditional_cont_expr <new CmmCondExpr:CmmExpr>:
  <store cond_expr:CmmExpr>
  '?' then_expr:expr
  ':' else_expr:conditional_expr ; // !? @@
  // ':' else_expr:assignment_expr ; // !? @@

/* assignment expression */

assignment_expr <select CmmExpr>:
   throw_expr |
   simple_assignment_expr; // !? last - important

simple_assignment_expr <binary>:
  conditional_expr // !?
  '='   AssignExp
  "+="  AddAssignExp
  "-="  SubAssignExp
  "*="  MulAssignExp
  "/="  DivAssignExp
  "%="  ModAssignExp
  "<<=" ShlAssignExp
  ">>=" ShrAssignExp
  "&="  AndAssignExp
  "^="  XorAssignExp
  "|="  OrAssignExp ;

/* expression */

expr <binary> <custom replace, list_replace>:
  assignment_expr
  ',' CommaExp ;

/* constant expression */

const_expr <return CmmExpr>:
  conditional_expr ;

/* --------------------------------------------------------------------- */

/* statement */

stat <select CmmStat> <custom list_subst, replace, list_replace>:

     ( identifier ':' ) => labeled_stat |

     { is_declaration () }? declaration_stat | // %%

     expression_stat |

     compound_stat |
     case_stat |
     default_stat |
     if_stat |
     switch_stat |
     while_stat |
     do_stat |
     for_stat |
     break_stat |
     continue_stat |
     return_stat |
     goto_stat |
     try_stat |
     empty_stat ;

/* inner_stat and tail_stat - statements with different output indentation */

inner_stat <return CmmStat> <custom send>:
   <indent> stat <unindent>;

tail_stat <return CmmStat> <custom send>:
   <indent> stat <unindent>;

/* list of statements */

stat_list <CmmStatSect>:
   (  <new_line> <add> stat )* ;

inner_stat_list <return CmmStatSect> <custom send>:
   <indent>
   stat_list
   <unindent> ;

/* concrete statements */

declaration_stat <CmmDeclStat:CmmStat>:
  decl:block_declaration ;

labeled_stat <CmmLabeledStat:CmmStat>:
  lab:identifier ':'
  <new_line>
  body:stat ;

case_stat <CmmCaseStat:CmmStat>:
  "case" case_expr:expr ':'
  <new_line>
  body:stat;

default_stat <CmmDefaultStat:CmmStat>:
  "default" ':'
  <new_line>
  body:stat;

expression_stat <CmmExprStat:CmmStat> <custom subst>:
  inner_expr:expr ';';

empty_stat <CmmEmptyStat:CmmStat>:
  ';' ;

compound_stat <CmmCompoundStat:CmmStat> <custom open_close_send>:
  <execute open_block () >
  '{'
  <execute read_block () >
  body:inner_stat_list
  '}'
  <execute close_block () > ;

condition <CmmCondition>:
     { is_declaration () }?  // %%
     cond_decl:simple_declaration_content
  |
     cond_expr:expr
  ;

for_condition <CmmCondition>:
     ( simple_declaration_content ';' ) =>
     // { is_declaration () }?
     cond_decl:simple_declaration_content
  |
     cond_expr:expr
  ;

if_stat <CmmIfStat:CmmStat>:
  <execute open_block () >
  "if" '(' cond:condition ')' then_stat:inner_stat
  (
    <silent>
    <new_line>
    "else" else_stat:tail_stat
  )?
  <execute close_block () > ;

switch_stat <CmmSwitchStat:CmmStat>:
  <execute open_block () >
  "switch" '(' cond:condition ')' body:inner_stat
  <execute close_block () > ;

while_stat <CmmWhileStat:CmmStat>:
  <execute open_block () >
  "while" '(' cond:condition ')' body:inner_stat
  <execute close_block () > ;

do_stat <CmmDoStat:CmmStat>:
  <execute open_block () >
  "do" body:inner_stat "while" '(' cond_expr:expr ')' ';'
  <execute close_block () > ;

for_stat <CmmForStat:CmmStat>:
  <execute open_block () >
  "for"
  '('
  ( from_expr:for_condition )?
  ';'
  (to_expr:expr)?
  ';'
  (cond_expr:expr)?
  ')'
  body:inner_stat
  <execute close_block () > ;

break_stat <CmmBreakStat:CmmStat>:
  "break" ';';

continue_stat <CmmContinueStat:CmmStat>:
  "continue" ';';

return_stat <CmmReturnStat:CmmStat>:
  "return" (return_expr:expr)? ';';

goto_stat <CmmGotoStat:CmmStat>:
  "goto" goto_lab:identifier ';';

/* ---------------------------------------------------------------------- */

/* declaration */

declaration_list <CmmDeclSect> <custom internal_send>:
  ( <add> declaration <new_line> )* ;

declaration <select CmmDecl> <custom list_subst, replace, list_replace, open_close_send>:

    ( "extern" string_literal ) => linkage_specification

  | ( "extern" "template" ) => extern_template_declaration // !? GNU extension

  | { is_constructor () }? constructor_declaration // %%

  | complex_declaration
  | empty_declaration

  | namespace_definition
  | using_declaration
  | asm_declaration

  | template_declaration

  <: additional member_visibility :>
  <: additional class_declaration :>
  <: additional enum_declaration :>
  <: additional simple_declaration :>
  ;

block_declaration <select CmmDecl>:

    simple_declaration
  | empty_declaration

  | namespace_definition
  | using_declaration
  | asm_declaration ;

/* ---------------------------------------------------------------------- */

/* simple declaration */

// !? @@

simple_declaration <return CmmSimpleDecl:CmmDecl>: // <custom internal_send>:
  simple_declaration_content ';' ;

simple_declaration_content <CmmSimpleDecl> <custom subst>:
  spec:decl_specifiers
  <execute open_simple_declaration>
  (
     <add> init_declarator
     ( ',' <add> init_declarator )*
  )
  <execute close_simple_declaration> ;

/* complex declaration */

// !? @@

complex_declaration <CmmComplexDecl:CmmSimpleDecl> <custom internal_send>:
  spec:decl_specifiers
  <execute open_complex_declaration>
  (
      /* (':') => */ ':' empty_width:conditional_expr ';' // !?
  |
     ';' <set empty=true> // !?
  |
     <add> init_declarator
     (
        func_body:function_body
     |
        ( ',' <add> init_declarator )*
        ';'
     )
  )
  <execute close_complex_declaration> ;

/* constructor head */

// !? @@

constructor_head <CmmCtorHead:CmmCtorDecl> <custom no_send>:
  spec:constructor_decl_specifiers
  ( '~' <set destructor=true> )?
  <add> constructor_head_declarator
  (
     ':' <set init_values = true>
  |
     '{' <set body=true>
  |
     "try" <set try_block = true>
  |
     ';' // no empty = true
  ) ;

constructor_head_declarator <CmmDeclarator>:
  <execute open_declarator>
  name:global_new_name
  cont:constructor_head_specifier_list
  <execute close_declarator> ;

constructor_head_specifier_list <CmmContSpecifierSect>:
  <add> constructor_head_specifier;

constructor_head_specifier <return CmmContSpecifier>:
  function_specifier ;

/* constructor declaration */

constructor_declaration <CmmCtorDecl:CmmComplexDecl> <custom internal_send>:
  <execute open_constructor_declaration>
  spec:constructor_decl_specifiers
  ( '~' <set destructor=true> )?
  <add> init_declarator
  (
     func_body:function_body
  |
     ';' // no empty = true
  )
  <execute close_constructor_declaration> ;

/* function body */

function_body <CmmFunctionBody> <custom output, internal_output>:
  <execute open_function>
  (
     // <new_line>
     ( ':' ctor_init: ctor_initializer )?
     <new_line>
     statements:compound_stat
  |
     <new_line>
     "try"
     ( ':' ctor_init:ctor_initializer )?
     statements:compound_stat
     handlers:handler_list
  )
  <execute close_function> ;

/* ---------------------------------------------------------------------- */

/* elaborated type specifiers */

elaborated_enum_specifier <CmmEnumDecl>:
  "enum"
  name:global_new_name ; // !?

elaborated_class_specifier <CmmClassDecl>:
  (
    "class"  <set style = ClassStyle> |
    "struct" <set style = StructStyle> |
    "union"  <set style = UnionStyle>
  )
  name:global_new_name; // !?

/* enum and class declarations */

class_declaration <return CmmClassDecl> :
  class_specifier ';' ;

enum_declaration <return CmmEnumDecl>:
  enum_specifier  ';' ;

/* ---------------------------------------------------------------------- */

/* namespace definition */

namespace_definition <CmmNamespaceDecl:CmmDecl> :
  "namespace"
  (
     name:simple_new_name
     (
        '=' value:global_name ';'
        <execute add_namespace_alias>
     |
        <call> namespace_body
        // <set with_body = true>
     )
  |
     <call> namespace_body
     // <set anonymous = true>
  );

namespace_body <modify CmmNamespaceDecl> :
   <new_line>
   <execute open_namespace> // before brace, important for include(s) on lexical level
   '{'
      <indent>
      body:declaration_list
      <unindent>
   <execute close_namespace> // before brace, important for include(s)
   '}'
   ;

/* using declaration */

using_declaration <CmmUsingDecl:CmmDecl>:
  "using"
  (
     "namespace" <set a_namespace = true>
  |
     "typename"  <set a_typename  = true>
  )?
  <execute open_using>
  name: global_name
  <execute close_using>
  ';' ;

/* extern declaration */

linkage_specification <CmmExternDecl:CmmDecl>:
  "extern"
  (
     language:string_literal
     (
        '{' decl_list:declaration_list '}'
     |
        inner_decl:declaration
     )
  |
     inner_decl:declaration
  ) ;

/* asm declaration */

asm_declaration <CmmAsmDecl:CmmDecl>:
  "asm" '(' instruction:string_literal ')' ';' ;

/* empty declaration */

empty_declaration <CmmEmptyDecl:CmmDecl> <custom send>:
  ';' ;

/* ---------------------------------------------------------------------- */

/* declaration specifiers */

decl_specifiers <CmmDeclSpec>:
  <execute open_decl_specifiers >
  <call> simple_decl_specifiers
  (
     basic_name:global_declaring_name
  |
     class_spec:class_specifier
  |
     enum_spec:enum_specifier
  |
     typename_spec:typename_specifier
  |
     <call> simple_type_specifiers
  )
  <redudant> <call> simple_decl_specifiers // !?
  <execute close_decl_specifiers>
  ;

type_specifiers <CmmDeclSpec>:
  <call> simple_cv_specifiers
  (
    "register" <set a_register = true> // !? @@ root/cint/inc/C__ci.h
  )?
  (
     basic_name:global_declaring_name // !?
  |
     class_spec:elaborated_class_specifier
  |
     enum_spec:elaborated_enum_specifier
  |
     typename_spec:typename_specifier
  |
     <call> simple_type_specifiers
  )
  <redudant> <call> simple_decl_specifiers // !?
  ;

typename_specifier <CmmTypenameSpec>:
  "typename"
  name:global_type_name ;

simple_decl_specifiers <modify CmmDeclSpec>:
  (
    "typedef"  <set a_typedef = true>  |
    "friend"   <set a_friend = true>   |

    "inline"   <set a_inline = true>   |
    "virtual"  <set a_virtual = true>  |
    "explicit" <set a_explicit = true> |

    "mutable"  <set a_mutable = true>  |
    "extern"   <set a_extern = true>   |
    "static"   <set a_static = true>   |
    "auto"     <set a_auto = true>     |
    "register" <set a_register = true> |

    "const"    <set a_const = true>    |
    "volatile" <set a_volatile = true>
  )* ;

constructor_decl_specifiers <CmmDeclSpec>:
  ( "inline"   <set a_inline = true>   |
    "virtual"  <set a_virtual = true>  |
    "explicit" <set a_explicit = true>
  )* ;

simple_cv_specifiers <modify CmmDeclSpec>:
  (
    "const" <set a_const = true> |
    "volatile" <set a_volatile = true>
  )* ;

simple_type_specifiers <modify CmmDeclSpec>:
  ( "signed"   <set a_signed = true>   |
    "unsigned" <set a_unsigned = true> |

    "short"    <set a_short = true>    |

    "long"     <set a_long = true>
       ( "long"   <set a_long_long = true> )? |
       // !? @@ long long

    "bool"     <set a_bool = true>     |
    "char"     <set a_char = true>     |
    "wchar_t"  <set a_wchar = true>    |
    "int"      <set a_int = true>      |
    "float"    <set a_float = true>    |
    "double"   <set a_double = true>   |
    "void"     <set a_void = true>
  )@ ;

/* ---------------------------------------------------------------------- */

/* enum */

enum_specifier <CmmEnumDecl:CmmDecl>:
  "enum"
  (
     name:global_new_name
     (
        <call> enum_body
        <set with_body = true>
     |
        <execute add_enum_forw>
        // NO <set forward = true>
     )
  |
     <call> enum_body
     // NO <set anonymous = true>
  );

enum_body <modify CmmEnumDecl>:
  <execute open_enum_type>
  <new_line>
  '{'
     <indent>
     items:enum_list
     <unindent>
  '}'
  <execute close_enum_type> ;

enum_list <CmmEnumSect>:
  (
    <add> enumerator
    ( ',' <add> flexible_enumerator )*
  )? ;

enumerator <CmmEnumItem>:
  <new_line>
  name:simple_new_name
  <execute add_enum_item>
  // <execute read_enum_init () >
  ( '=' init:const_expr )? ;

flexible_enumerator <CmmEnumItem>:
  <new_line>
  (
     name:simple_new_name
     <execute add_enum_item>
     // <execute read_enum_init () >
     ( '=' init:const_expr )?
  |
     // <set empty=true> // !? @@
  );

/* ---------------------------------------------------------------------- */

/* type id */

type_id <CmmTypeId>: /* abstract_type_id */
  spec:type_specifiers
  decl:abstract_declarator ;

common_type_id <CmmTypeId>:
  spec:type_specifiers
  decl:common_declarator ;

/* declarator */

declarator <CmmDeclarator>:
  <execute open_declarator>
  ptr:ptr_specifier_list
  (
     name:global_new_name
  |
     '(' inner:declarator ')'
  )
  cont:cont_specifier_list
  <execute close_declarator>
  ;

abstract_declarator <CmmDeclarator>:
  <execute open_declarator>
  ptr:ptr_specifier_list
  (
     // ( '(' ) => // !?
     { is_inner_abstract_declarator () }?
       '(' inner:abstract_declarator ')'
  )?
  cont:cont_specifier_list
  <execute close_declarator>
  ;

common_declarator_name <modify CmmDeclarator> <custom internal_output>:
  name:global_new_name
  ;

common_declarator <CmmDeclarator>:
  <execute open_declarator>
  ptr:ptr_specifier_list
  (
     // ( '(' ) => // !? @@
     { is_inner_common_declarator () }?
       '(' inner:common_declarator ')'
  |
     <call> common_declarator_name
     <set empty_branch = true>
  )?
  cont:cont_specifier_list
  <execute close_declarator>
  ;

/* pointer specifiers */

ptr_specifier_list <CmmPtrSpecifierSect> <custom output, internal_output>:
  ( <silent> <add> ptr_specifier )*
  <execute member_pointer_list> ; // !? @@

ptr_specifier <CmmPtrSpecifier>:
    '*' <set pointer=true>
    <call> ptr_cv_specifier_list
  |
    '&' <set reference=true>
    <call> ptr_cv_specifier_list
  ;

member_specifier <CmmPtrSpecifier>: // !? @@ only for output
  area:global_name
  <call> member_specifier_tail ;

member_specifier_tail <modify CmmPtrSpecifier>:
  "::" '*'
  <set member_pointer=true>
  <call> ptr_cv_specifier_list ;

ptr_cv_specifier_list <modify CmmPtrSpecifier>:
  (
    "const" <set cv_const = true>
  |
    "volatile" <set cv_volatile = true>
  )* ;

/* function and array specifiers */

cont_specifier_list <CmmContSpecifierSect>:
  ( <add> cont_specifier )* ;

cont_specifier <select CmmContSpecifier>:
    function_specifier
  |
    array_specifier ;

function_specifier <CmmFunctionSpecifier:CmmContSpecifier>:
  <execute open_parameters>
  '('
  parameters:parameter_declaration_list
  ')'
  (
    "const" <set cv_const = true>
  |
    "volatile" <set cv_volatile = true>
  )*
  ( exception_spec:exception_specification )?
  <execute close_parameters> ;

array_specifier <CmmArraySpecifier:CmmContSpecifier>:
  '[' (lim:expr)? ']' ;

/* parameter declarations */

parameter_declaration_list <CmmParamSect>:
  (
     <add> parameter_declaration
     ( ',' <add> parameter_declaration )*
  )? ;

parameter_declaration <CmmParamItem> <custom subst, list_subst, list_replace>:
 (
     { is_parameter () }? // %%
       type:common_type_id
       <execute read_param_init () >
       <call> parameter_initialization
       ( "..." <set following_dots=true> )? // !?
  |
     { is_initializer_acceptable () }? // %%
        value:expr
  |
     "..." <set dots=true> // !?
  )
  <execute add_parameter> ;

parameter_initialization <modify CmmParamItem> <custom internal_output>:
  ( '=' init:assignment_expr )? ;

/* init declarator */

init_declarator <return CmmDeclarator>:
  <result> declarator
  <execute add_declarator>
  ( { is_width_acceptable }?  ':' width:conditional_expr )? // !? @@
  <execute read_initializer () >
  (  init:initializer  )? ;

/* initializer */

initializer <CmmInitializer> <custom internal_send>:
   '=' value:initializer_item
   // | "(" value2:expr ")" // !? @@
   ;

initializer_item <select CmmInitItem> <custom internal_send, replace>:
     simple_initializer
   | initializer_list ;

flexible_initializer_item <select CmmInitItem>: // <custom internal_send, replace>:
     initializer_list
   | simple_initializer
   | empty_initializer; // !? last - important

empty_initializer <CmmInitEmpty:CmmInitItem>:
   ;

simple_initializer <CmmInitSimple:CmmInitItem> <custom subst>:
  expr:assignment_expr ;

initializer_list <CmmInitList:CmmInitItem> <custom subst, internal_send>:
  '{'
  <indent>
  (
    <add> initializer_item
    (
      ','
      <new_line>
      <add> flexible_initializer_item
    )*
  )?
  <unindent>
  '}';

/* ---------------------------------------------------------------------- */

/* class */

class_specifier <CmmClassDecl:CmmDecl>:
  (
    "class"  <set style = ClassStyle> |
    "struct" <set style = StructStyle> |
    "union"  <set style = UnionStyle>
  )
  (
    name:global_new_name
    (
      <silent>
      <call> class_body
      <set with_body = true>
    |
      // NO <set forward = true>
      <execute add_class_forw>
    )
  |
    <call> class_body
    // NO <set anonymous = true>
  );

class_body <modify CmmClassDecl>:
  <execute open_class>
  ( ':' base_list:base_specifier_list )?
  <new_line>
 '{'
     <indent>
     members:member_list
     <unindent>
 '}'
  <execute close_class> ;

/* members */

member_visibility <CmmMemberVisibility:CmmDecl> <custom internal_send>:
  ( "private"   <set access = PrivateAccess>
  | "protected" <set access = ProtectedAccess>
  | "public"    <set access = PublicAccess> )
  <no_space> ':'
  <execute add_visibility> ;

member_item <select CmmDecl> <custom internal_send>:
    member_visibility
  | { is_constructor () }? constructor_declaration // %%
  | complex_declaration // !?
  | empty_declaration
  | using_declaration
  | template_declaration
  ;

member_list <CmmDeclSect> <custom internal_send>:
  ( <add> member_item <new_line> )* ;

/* base specification */

base_specifier_list <CmmBaseSect>:
  <add> base_specifier
  ( ',' <add> base_specifier )* ;

base_specifier <CmmBaseItem>:
  (
    "virtual" <set a_virtual = true>

    ( "private"   <set access = PrivateAccess>
    | "protected" <set access = ProtectedAccess>
    | "public"    <set access = PublicAccess>
    |             <set access = NoAccess> )
  |
    "private"     <set access = PrivateAccess>
    ( "virtual"   <set a_virtual = true> )?
  |
    "protected"   <set access = ProtectedAccess>
    ( "virtual"   <set a_virtual = true> )?
  |
    "public"      <set access = PublicAccess>
    ( "virtual"   <set a_virtual = true> )?
  |
                  <set access = NoAccess>
  )

  from:global_type_name
  <execute add_base> ;

/* constructor initializer */

ctor_initializer <CmmCtorInitializer> <custom internal_send>:
  <indent>
  <add> member_initializer
  ( ',' <new_line> <add> member_initializer )*
  <unindent> ;

member_initializer <CmmMemberInitializer> <custom internal_send>:
   name:global_name
   '('
   <execute read_member_initializer () >
   params:expr_list
   ')'; // !? global_name

/* ---------------------------------------------------------------------- */

/* special member functions */

conversion_specifiers <return CmmDeclSpec>: // !? @@
  <execute open_conversion () >
  <result> type_specifiers
  ptr:ptr_specifier_list
  <execute close_conversion () > ;

special_function <CmmSpecialFuction>:
   "operator"
   (
     conv:conversion_specifiers // !? @@

   | "new"    <set spec_new=true>    ( ('[' ']') => '[' ']' <set spec_new_array=true> )? // !?
   | "delete" <set spec_delete=true> ( ('[' ']') => '[' ']' <set spec_delete_array=true> )?

   | "+" <set spec_add=true>
   | "-" <set spec_sub=true>
   | "*" <set spec_mul=true>
   | "/" <set spec_div=true>
   | "%" <set spec_mod=true>
   | "^" <set spec_xor=true>
   | "&" <set spec_and=true>
   | "|" <set spec_or=true>
   | "~" <set spec_not=true>

   | "!"  <set spec_log_not=true>
   | "="  <set spec_assign=true>
   | "<"  <set spec_lt=true>
   | ">"  <set spec_gt=true>
   | "+=" <set spec_add_assign=true>
   | "-=" <set spec_sub_assign=true>
   | "*=" <set spec_mul_assign=true>
   | "/=" <set spec_div_assign=true>
   | "%=" <set spec_mod_assign=true>

   | "^="  <set spec_xor_assign=true>
   | "&="  <set spec_and_assign=true>
   | "|="  <set spec_or_assign=true>
   | "<<"  <set spec_shl=true>
   | ">>"  <set spec_shr=true>
   | ">>=" <set spec_shl_assign=true>
   | "<<=" <set spec_shr_assign=true>
   | "=="  <set spec_eq=true>
   | "!="  <set spec_ne=true>

   | "<="  <set spec_le=true>
   | ">="  <set spec_ge=true>
   | "&&"  <set spec_log_and=true>
   | "||"  <set spec_log_or=true>
   | "++"  <set spec_inc=true>
   | "--"  <set spec_dec=true>
   | ","   <set spec_comma=true>
   | "->*" <set spec_member_deref=true>
   | "->"  <set spec_deref=true>

   | "(" ")" <set spec_call=true>
   | "[" "]" <set spec_index=true>
   ) ;

/* ---------------------------------------------------------------------- */

/* template declaration */

template_declaration <CmmTemplateDecl:CmmDecl>:
  <call> common_template_declaration ;

extern_template_declaration <CmmExxternTemplateDecl:CmmTemplateDecl>:
  // GNU extension
  "extern"
  <call> common_template_declaration ;

common_template_declaration <modify CmmTemplateDecl:CmmDecl>:
  <execute open_template>
  <call> template_specification
  <execute add_template>
  inner_decl:declaration
  <execute close_template> ;

template_specification <modify CmmTemplateDecl>:
  (
    "export"
    <set export_template = true>
  )?
  "template"
  (
    '<'
    (
      params:template_param_list
    |
      <set explicit_specialization = true>
    )
    '>'
    <set parameter_block = true> // !?
  |
    <set explicit_instatiation = true>
  );

template_param_list <CmmTemplateParamSect>:
  <add> template_param
  ( ',' <add> template_param )* ;

template_param <select CmmTemplateParam>:
    ( "template" | "class" | "typename" ) => template_type_param
  | template_value_param ;

template_type_param <CmmTemplateTypeParam:CmmTemplateParam>:
  (
    "template" '<' params:template_param_list '>'
  )?
  (
    "class" <set a_class = true>
  |
    "typename" <set a_typename = true>
  )
  ( name:simple_new_name )?
  // <execute read_type_init>
  ( '=' value:type_id )?
  <execute add_template_type_param>
  ;

template_value_param <CmmTemplateValueParam:CmmTemplateParam>:
  type:common_type_id
  <execute add_template_value_param>
  // <execute read_value_init>
  ( '=' init:shift_expr )? ; // !?

/* template arguments */

template_arg_list <CmmTemplateArgSect>:
  <execute open_template_arguments>
  '<'
  (
    <add> template_arg
    ( ',' <add> template_arg )*
  )?
  '>'
  <execute close_template_arguments> ;

template_arg <select CmmTemplateArg>:
     { is_type () }? // %%
     template_type_arg
  |
     template_value_arg;

template_type_arg <CmmTemplateTypeArg:CmmTemplateArg>:
  type:type_id; // !?

template_value_arg <CmmTemplateValueArg:CmmTemplateArg>:
   value:shift_expr; // !?

/* ---------------------------------------------------------------------- */

/* try statement */

try_stat <CmmTryStat:CmmStat>:
  "try"
  <new_line>
  body:compound_stat
  handlers:handler_list ;

handler_list <CmmHandlerSect>:
  <add> handler (<add> handler)* ;

handler <CmmHandlerItem>:
  <new_line>
  "catch"
  '('
  (
    type:common_type_id
  |
    "..." <set dots=true>
  )
  ')'
  <new_line>
  body:compound_stat ;

/* throw expression */

throw_expr <CmmThrowExpr:CmmExpr>:
  "throw" (expr:assignment_expr)? ;

/* exception specification */

exception_specification <CmmExceptionSect>:
  "throw"
  '('
  (
    <add> exception_specification_item
    (',' <add> exception_specification_item)*
  )?
  ')' ;

exception_specification_item <CmmExceptionItem: CmmTypeDecl>:
  type:type_id ;

/* ---------------------------------------------------------------------- */