flitter/lang_cpp/parsing/parser_cpp.mly
Joey Yakimowich-Payne fa600b98f7 Add poc files
2018-05-26 10:55:38 +09:00

1975 lines
68 KiB
OCaml

%{
(* Yoann Padioleau
*
* Copyright (C) 2010-2014 Facebook
* Copyright (C) 2008-2009 University of Urbana Champaign
* Copyright (C) 2006-2007 Ecole des Mines de Nantes
* Copyright (C) 2002 Yoann Padioleau
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License (GPL)
* version 2 as published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* file license.txt for more details.
*)
open Common
open Ast_cpp
open Parser_cpp_mly_helper
(* see todo_mly for stuff temporarily commented out *)
%}
/*(*************************************************************************)*/
/*(*1 Tokens *)*/
/*(*************************************************************************)*/
/*
(* Some tokens below are not even used in this file because they are filtered
* in some intermediate phases (e.g. the comment tokens). Some tokens
* also appear only here and are not in the lexer because they are
* created in some intermediate phases. They are called "fresh" tokens
* and always contain a '_' in their name.
*)*/
/*(* unrecognized token, will generate parse error *)*/
%token <Parse_info.info> TUnknown
%token <Parse_info.info> EOF
/*(*-----------------------------------------*)*/
/*(*2 The space/comment tokens *)*/
/*(*-----------------------------------------*)*/
/*
(* coupling: Token_helpers.is_real_comment and other related functions.
* disappear in parse_cpp.ml via TH.is_comment in lexer_function
*)*/
%token <Parse_info.info> TCommentSpace TCommentNewline TComment
/*(* fresh_token: cppext: appears after parsing_hack_pp and disappear *)*/
%token <(Token_cpp.cppcommentkind * Parse_info.info)> TComment_Pp
/*(* fresh_token: c++ext: appears after parsing_hack_pp and disappear *)*/
%token <(Token_cpp.cpluspluscommentkind * Parse_info.info)> TComment_Cpp
/*(*-----------------------------------------*)*/
/*(*2 The C tokens *)*/
/*(*-----------------------------------------*)*/
%token <string * Parse_info.info> TInt
%token <(string * Ast_cpp.floatType) * Parse_info.info> TFloat
%token <(string * Ast_cpp.isWchar) * Parse_info.info> TChar TString
%token <string * Parse_info.info> TIdent
/*(* fresh_token: appear after some fix_tokens in parsing_hack.ml *)*/
%token <string * Parse_info.info> TIdent_Typedef
/*
(* coupling: some tokens like TOPar and TCPar are used as synchronisation point
* in parsing_hack.ml. So if you define a special token like TOParDefine and
* TCParEOL, then you must take care to also modify token_helpers.ml
*)*/
%token <Parse_info.info> TOPar TCPar TOBrace TCBrace TOCro TCCro
%token <Parse_info.info> TDot TComma TPtrOp TInc TDec
%token <Ast_cpp.assignOp * Parse_info.info> TAssign
%token <Parse_info.info> TEq TWhy TTilde TBang TEllipsis TCol TPtVirg
%token <Parse_info.info>
TOrLog TAndLog TOr TXor TAnd TEqEq TNotEq TInfEq TSupEq
TShl TShr
TPlus TMinus TMul TDiv TMod
/*(*c++ext: see also TInf2 and TSup2 *)*/
%token <Parse_info.info> TInf TSup
%token <Parse_info.info>
Tchar Tshort Tint Tdouble Tfloat Tlong Tunsigned Tsigned Tvoid
Tauto Tregister Textern Tstatic
Ttypedef
Tconst Tvolatile
Tstruct Tunion Tenum
Tbreak Telse Tswitch Tcase Tcontinue Tfor Tdo Tif Twhile Treturn
Tgoto Tdefault
Tsizeof
/*(* C99 *)*/
%token <Parse_info.info> Trestrict
/*(*-----------------------------------------*)*/
/*(*2 gccext: extra tokens *)*/
/*(*-----------------------------------------*)*/
%token <Parse_info.info> Tasm Ttypeof
/*(* less: disappear in parsing_hacks_pp, not present in AST for now *)*/
%token <Parse_info.info> Tattribute
/*(* also c++ext: *)*/
%token <Parse_info.info> Tinline
/*(*-----------------------------------------*)*/
/*(*2 cppext: extra tokens *)*/
/*(*-----------------------------------------*)*/
/*(* cppext: #define *)*/
%token <Parse_info.info> TDefine
%token <(string * Parse_info.info)> TDefParamVariadic
/*(* transformed in TCommentSpace and disappear in parsing_hack.ml *)*/
%token <Parse_info.info> TCppEscapedNewline
/*(* fresh_token: appear after fix_tokens_define in parsing_hack_define.ml *)*/
%token <(string * Parse_info.info)> TIdent_Define
%token <Parse_info.info> TOPar_Define
%token <Parse_info.info> TCommentNewline_DefineEndOfMacro
%token <Parse_info.info> TOBrace_DefineInit
/*(* cppext: #include *)*/
%token <(string * string * Parse_info.info)> TInclude
/*(* cppext: #ifdef *)*/
/*(* coupling: Token_helpers.is_cpp_instruction *)*/
%token <Parse_info.info> TIfdef TIfdefelse TIfdefelif TEndif
%token <(bool * Parse_info.info)> TIfdefBool TIfdefMisc TIfdefVersion
/*(* cppext: other *)*/
%token <string * Parse_info.info> TUndef
%token <Parse_info.info> TCppDirectiveOther
/*(* cppext: special macros *)*/
/*(* fresh_token: appear after fix_tokens in parsing_hacks_pp.ml *)*/
%token <Parse_info.info> TIdent_MacroStmt
%token <Parse_info.info> TIdent_MacroString
%token <(string * Parse_info.info)> TIdent_MacroIterator
%token <(string * Parse_info.info)> TIdent_MacroDecl
%token <Parse_info.info> Tconst_MacroDeclConst
/*(* fresh_token: appear after parsing_hack_pp.ml, alt to TIdent_MacroTop *)*/
%token <Parse_info.info> TCPar_EOL
/*(* fresh_token: appear after parsing_hack_pp.ml *)*/
%token <Parse_info.info> TAny_Action
/*(*-----------------------------------------*)*/
/*(*2 c++ext: extra tokens *)*/
/*(*-----------------------------------------*)*/
%token <Parse_info.info>
Tclass Tthis
Tnew Tdelete
Ttemplate Ttypeid Ttypename
Tcatch Ttry Tthrow
Toperator
Tpublic Tprivate Tprotected Tfriend
Tvirtual
Tnamespace Tusing
Tbool Tfalse Ttrue
Twchar_t
Tconst_cast Tdynamic_cast Tstatic_cast Treinterpret_cast
Texplicit Tmutable
Texport
%token <Parse_info.info> TPtrOpStar TDotStar
%token <Parse_info.info> TColCol
/*(* fresh_token: for constructed object, in parsing_hacks_cpp.ml *)*/
%token <Parse_info.info> TOPar_CplusplusInit
/*(* fresh_token: for template *)*/
%token <Parse_info.info> TInf_Template TSup_Template
/*(* fresh_token: for new[] delete[] *)*/
%token <Parse_info.info> TOCro_new TCCro_new
/*(* fresh_token: for pure virtual method. TODO add stuff in parsing_hack *)*/
%token <Parse_info.info> TInt_ZeroVirtual
/*(* fresh_token: why can't use TypedefIdent? conflict? *)*/
%token <string * Parse_info.info> TIdent_ClassnameInQualifier
/*(* fresh_token: appears after solved if next token is a typedef *)*/
%token <string * Parse_info.info> TIdent_ClassnameInQualifier_BeforeTypedef
/*(* fresh_token: just before <> *)*/
%token <string * Parse_info.info> TIdent_Templatename
/*(* for templatename as qualifier, before a '::' TODO write heuristic! *)*/
%token <string * Parse_info.info> TIdent_TemplatenameInQualifier
/*(* fresh_token: appears after solved if next token is a typedef *)*/
%token <string * Parse_info.info> TIdent_TemplatenameInQualifier_BeforeTypedef
/*(* fresh_token: for methods with same name as classname *)*/
%token <string * Parse_info.info> TIdent_Constructor
/*(* for cast_constructor, before a '(', unused for now *)*/
%token <string * Parse_info.info> TIdent_TypedefConstr
/*(* fresh_token: for constructed (basic) objects *)*/
%token <Parse_info.info>
Tchar_Constr Tint_Constr Tfloat_Constr Tdouble_Constr Twchar_t_Constr
Tshort_Constr Tlong_Constr Tbool_Constr
Tsigned_Constr Tunsigned_Constr
/*(* fresh_token: appears after solved if next token is a typedef *)*/
%token <Parse_info.info> TColCol_BeforeTypedef
/*(*************************************************************************)*/
/*(*1 Priorities *)*/
/*(*************************************************************************)*/
/*(* must be at the top so that it has the lowest priority *)*/
%nonassoc LOW_PRIORITY_RULE
/*(* see conflicts.txt *)*/
%nonassoc Telse
%left TOrLog
%left TAndLog
%left TOr
%left TXor
%left TAnd
%left TEqEq TNotEq
%left TInf TSup TInfEq TSupEq
%left TShl TShr
%left TPlus TMinus
%left TMul TDiv TMod
/*(*************************************************************************)*/
/*(*1 Rules type declaration *)*/
/*(*************************************************************************)*/
%start main toplevel statement expr type_id
%type <Ast_cpp.program> main
%type <Ast_cpp.toplevel option> toplevel
%type <Ast_cpp.statement> statement
%type <Ast_cpp.expression> expr
%type <Ast_cpp.fullType> type_id
%type <(Ast_cpp.name) * (Ast_cpp.fullType -> Ast_cpp.fullType)> declarator
%type <(Ast_cpp.name)> type_cplusplus_id
%%
/*(*************************************************************************)*/
/*(*1 TOC *)*/
/*(*************************************************************************)*/
/*
(* translation_unit (obsolete)
*
* ident
* expression
* statement
* types with
* - left part (type_spec, qualif, template and its arguments),
* - right part (declarator, abstract declarator)
* - aux part (parameters)
* class/struct
* enum
* declaration, storage, initializers
* block_declaration
* cpp directives
* toplevel (= start grammar rule)
*
* generic workarounds (obrace, cbrace for context setting)
* xxx_list, xxx_opt
*)*/
/*(*************************************************************************)*/
/*(*1 translation_unit (unused) *)*/
/*(*************************************************************************)*/
/*(* no more used now that use error recovery, but good to keep *)*/
main:
| translation_unit EOF { $1 }
translation_unit:
| external_declaration { [DeclElem $1] }
| translation_unit external_declaration { $1 @ [DeclElem $2] }
external_declaration:
| function_definition { Func (FunctionOrMethod $1) }
| block_declaration { BlockDecl $1 }
/*(*************************************************************************)*/
/*(*1 Ident, scope *)*/
/*(*************************************************************************)*/
id_expression:
| unqualified_id { noQscope, $1 }
| qualified_id { $1 }
/*
(* todo:
* ~id class_name, conflict IdDestructor TODO
* template-id, conflict
*)*/
unqualified_id:
| TIdent { IdIdent $1 }
| operator_function_id { $1 }
| conversion_function_id { $1 }
operator_function_id:
| Toperator operator_kind
{ IdOperator ($1, $2) }
conversion_function_id:
| Toperator conversion_type_id
{ IdConverter ($1, $2) }
/*
(* no deref getref operator (cos ambiguity with Mul and And),
* no unaryplus/minus op either
*)*/
operator_kind:
/*(* != == *)*/
| TEqEq { BinaryOp (Logical Eq), [$1] }
| TNotEq { BinaryOp (Logical NotEq), [$1] }
/*(* = += -= *= /= %= ^= &= |= >>= <<= *)*/
| TEq { AssignOp SimpleAssign, [$1] }
| TAssign { AssignOp (fst $1), [snd $1] }
/*(* ! ~ *)*/
| TTilde { UnaryTildeOp, [$1] }
| TBang { UnaryNotOp, [$1] }
/*(* , *)*/
| TComma { CommaOp, [$1] }
/*(* + - * / % *)*/
| TPlus { BinaryOp (Arith Plus), [$1] }
| TMinus { BinaryOp (Arith Minus), [$1] }
| TMul { BinaryOp (Arith Mul), [$1] }
| TDiv { BinaryOp (Arith Div), [$1] }
| TMod { BinaryOp (Arith Mod), [$1] }
/*(* ^ & | << >> *)*/
| TOr { BinaryOp (Arith Or), [$1] }
| TXor { BinaryOp (Arith Xor), [$1] }
| TAnd { BinaryOp (Arith And), [$1] }
| TShl { BinaryOp (Arith DecLeft), [$1] }
| TShr { BinaryOp (Arith DecRight), [$1] }
/*(* && || *)*/
| TOrLog { BinaryOp (Logical OrLog), [$1] }
| TAndLog { BinaryOp (Logical AndLog), [$1] }
/*(* < > <= >= *)*/
| TInf { BinaryOp (Logical Inf), [$1] }
| TSup { BinaryOp (Logical Sup), [$1] }
| TInfEq { BinaryOp (Logical InfEq), [$1] }
| TSupEq { BinaryOp (Logical SupEq), [$1] }
/*(* ++ -- *)*/
| TInc { FixOp Inc, [$1] }
| TDec { FixOp Dec, [$1] }
/*(* ->* -> *) */
| TPtrOpStar { PtrOpOp PtrStarOp, [$1] }
| TPtrOp { PtrOpOp PtrOp, [$1] }
/*(* () [] (double tokens) *)*/
| TOPar TCPar { AccessOp ParenOp, [$1;$2] }
| TOCro TCCro { AccessOp ArrayOp, [$1;$2] }
/*(* new delete *)*/
| Tnew { AllocOp NewOp, [$1] }
| Tdelete { AllocOp DeleteOp, [$1] }
/*(*new[] delete[] (tripple tokens) *)*/
| Tnew TOCro_new TCCro_new { AllocOp NewArrayOp, [$1;$2;$3] }
| Tdelete TOCro_new TCCro_new { AllocOp DeleteArrayOp, [$1;$2;$3] }
qualified_id:
| nested_name_specifier /*(*templateopt*)*/ unqualified_id
{ $1, $2 }
nested_name_specifier:
| class_or_namespace_name_for_qualifier TColCol nested_name_specifier_opt
{ ($1, $2)::$3 }
/*(* context dependent *)*/
class_or_namespace_name_for_qualifier:
| TIdent_ClassnameInQualifier
{ QClassname $1 }
| TIdent_TemplatenameInQualifier
TInf_Template template_argument_list TSup_Template
{ QTemplateId ($1, ($2, $3, $4)) }
/*
(* context dependent: in the original grammar there was one rule
* for each names (e.g. typedef_name:, enum_name:, class_name:) but
* we don't have such contextual information and we can merge
* those rules anyway without introducing conflicts.
*)*/
enum_name_or_typedef_name_or_simple_class_name:
| TIdent_Typedef { $1 }
/*(* used only with namespace/using rules. We use Tclassname for stuff
* like std::... todo? or just TIdent_Typedef? *)*/
namespace_name:
| TIdent { $1 }
/*(*----------------------------*)*/
/*(*2 workarounds *)*/
/*(*----------------------------*)*/
nested_name_specifier2:
| class_or_namespace_name_for_qualifier2
TColCol_BeforeTypedef nested_name_specifier_opt2
{ ($1, $2)::$3 }
class_or_namespace_name_for_qualifier2:
| TIdent_ClassnameInQualifier_BeforeTypedef
{ QClassname $1 }
| TIdent_TemplatenameInQualifier_BeforeTypedef
TInf_Template template_argument_list TSup_Template
{ QTemplateId ($1, ($2, $3, $4)) }
/*
(* Why this ? Why not s/ident/TIdent ? cos there is multiple namespaces in C,
* so a label can have the same name that a typedef, same for field and tags
* hence sometimes the use of ident instead of TIdent.
*)*/
ident:
| TIdent { $1 }
| TIdent_Typedef { $1 }
/*(*************************************************************************)*/
/*(*1 Expressions *)*/
/*(*************************************************************************)*/
expr:
| assign_expr { $1 }
| expr TComma assign_expr { mk_e (Sequence ($1,$3)) [$2] }
/*(* bugfix: in C grammar they put 'unary_expr', but in fact it must be
* 'cast_expr', otherwise (int * ) xxx = &yy; is not allowed
*)*/
assign_expr:
| cond_expr { $1 }
| cast_expr TAssign assign_expr { mk_e(Assignment ($1,fst $2,$3)) [snd $2]}
| cast_expr TEq assign_expr { mk_e(Assignment ($1,SimpleAssign,$3)) [$2]}
/*(*c++ext: *)*/
| Tthrow assign_expr_opt { mk_e (Throw $2) [$1] }
/*(* gccext: allow optional then part hence opt_expr
* bugfix: in C grammar they put 'TCol cond_expr', but in fact it must be
* 'assign_expr', otherwise pnp ? x : x = 0x388 is not allowed
*)*/
cond_expr:
| arith_expr { $1 }
| arith_expr TWhy expr_opt TCol assign_expr
{ mk_e (CondExpr ($1,$3,$5)) [$2;$4] }
arith_expr:
| pm_expr { $1 }
| arith_expr TMul arith_expr { mk_e(Binary ($1, Arith Mul, $3)) [$2] }
| arith_expr TDiv arith_expr { mk_e(Binary ($1, Arith Div, $3)) [$2] }
| arith_expr TMod arith_expr { mk_e(Binary ($1, Arith Mod, $3)) [$2] }
| arith_expr TPlus arith_expr { mk_e(Binary ($1, Arith Plus, $3)) [$2] }
| arith_expr TMinus arith_expr { mk_e(Binary ($1, Arith Minus, $3)) [$2] }
| arith_expr TShl arith_expr { mk_e(Binary ($1, Arith DecLeft, $3)) [$2] }
| arith_expr TShr arith_expr { mk_e(Binary ($1, Arith DecRight, $3)) [$2] }
| arith_expr TInf arith_expr { mk_e(Binary ($1, Logical Inf, $3)) [$2] }
| arith_expr TSup arith_expr { mk_e(Binary ($1, Logical Sup, $3)) [$2] }
| arith_expr TInfEq arith_expr { mk_e(Binary ($1, Logical InfEq, $3)) [$2] }
| arith_expr TSupEq arith_expr { mk_e(Binary ($1, Logical SupEq, $3)) [$2] }
| arith_expr TEqEq arith_expr { mk_e(Binary ($1, Logical Eq, $3)) [$2] }
| arith_expr TNotEq arith_expr { mk_e(Binary ($1, Logical NotEq, $3)) [$2] }
| arith_expr TAnd arith_expr { mk_e(Binary ($1, Arith And, $3)) [$2] }
| arith_expr TOr arith_expr { mk_e(Binary ($1, Arith Or, $3)) [$2] }
| arith_expr TXor arith_expr { mk_e(Binary ($1, Arith Xor, $3)) [$2] }
| arith_expr TAndLog arith_expr { mk_e(Binary ($1, Logical AndLog, $3)) [$2] }
| arith_expr TOrLog arith_expr { mk_e(Binary ($1, Logical OrLog, $3)) [$2] }
pm_expr:
| cast_expr { $1 }
/*(*c++ext: .* and ->*, note that not next to . and -> and take expr *)*/
| pm_expr TDotStar cast_expr
{ mk_e(RecordStarAccess ($1,$3)) [$2]}
| pm_expr TPtrOpStar cast_expr
{ mk_e(RecordPtStarAccess ($1,$3)) [$2]}
cast_expr:
| unary_expr { $1 }
| TOPar type_id TCPar cast_expr { mk_e(Cast (($1, $2, $3), $4)) noii }
unary_expr:
| postfix_expr { $1 }
| TInc unary_expr { mk_e(Infix ($2, Inc)) [$1] }
| TDec unary_expr { mk_e(Infix ($2, Dec)) [$1] }
| unary_op cast_expr { mk_e(Unary ($2, fst $1)) [snd $1] }
| Tsizeof unary_expr { mk_e(SizeOfExpr ($1, $2)) noii }
| Tsizeof TOPar type_id TCPar { mk_e(SizeOfType ($1, ($2, $3, $4))) noii }
/*(*c++ext: *)*/
| new_expr { $1 }
| delete_expr { $1 }
unary_op:
| TAnd { GetRef, $1 }
| TMul { DeRef, $1 }
| TPlus { UnPlus, $1 }
| TMinus { UnMinus, $1 }
| TTilde { Tilde, $1 }
| TBang { Not, $1 }
/*(* gccext: have that a lot in old kernel to get address of local label.
* cf gcc manual "local labels as values".
*)*/
| TAndLog { GetRefLabel, $1 }
postfix_expr:
| primary_expr { $1 }
| postfix_expr TOCro expr TCCro
{ mk_e(ArrayAccess ($1, ($2, $3, $4))) noii }
| postfix_expr TOPar argument_list_opt TCPar
{ mk_e(mk_funcall $1 ($2, $3, $4)) noii }
/*(*c++ext: ident is now a id_expression *)*/
| postfix_expr TDot template_opt tcolcol_opt id_expression
{ let name = ($4, fst $5, snd $5) in mk_e(RecordAccess ($1,name)) [$2] }
| postfix_expr TPtrOp template_opt tcolcol_opt id_expression
{ let name = ($4, fst $5, snd $5) in mk_e(RecordPtAccess($1,name)) [$2] }
| postfix_expr TInc { mk_e(Postfix ($1, Inc)) [$2] }
| postfix_expr TDec { mk_e(Postfix ($1, Dec)) [$2] }
/*(* gccext: also called compound literals *)*/
| compound_literal_expr { $1 }
/*(* c++ext: *)*/
| cast_operator_expr { $1 }
| Ttypeid TOPar unary_expr TCPar { mk_e(TypeId ($1, ($2, Right $3, $4))) noii }
| Ttypeid TOPar type_id TCPar { mk_e(TypeId ($1, ($2, Left $3, $4))) noii }
| cast_constructor_expr { $1 }
primary_expr:
/*(*c++ext: cf below now. old: TIdent { mk_e(Ident (fst $1)) [snd $1] } *)*/
/*(* constants a.k.a literal *)*/
| TInt { mk_e(C (Int (fst $1))) [snd $1] }
| TFloat { mk_e(C (Float (fst $1))) [snd $1] }
| TString { mk_e(C (String (fst $1))) [snd $1] }
| TChar { mk_e(C (Char (fst $1))) [snd $1] }
/*(*c++ext: *)*/
| Ttrue { mk_e(C (Bool false)) [$1] }
| Tfalse { mk_e(C (Bool false)) [$1] }
/*(* forunparser: *)*/
| TOPar expr TCPar { mk_e(ParenExpr ($1, $2, $3)) noii }
/*(* gccext: cppext: *)*/
| string_elem string_list { mk_e(C (MultiString)) ($1 @ $2) }
/*(* gccext: allow statement as expressions via ({ statement }) *)*/
| TOPar compound TCPar { mk_e(StatementExpr ($1, $2, $3)) noii }
/*(* c++ext: *)*/
| Tthis { mk_e(This $1) [] }
/*(* contains identifier rule *)*/
| primary_cplusplus_id { $1 }
/*(*----------------------------*)*/
/*(*2 c++ext: *)*/
/*(*----------------------------*)*/
/*(* can't factorize with following rule :(
* | tcolcol_opt nested_name_specifier_opt TIdent
*)*/
primary_cplusplus_id:
| id_expression
{ let name = (None, fst $1, snd $1) in
mk_e (Id (name, noIdInfo())) [] }
| TColCol TIdent
{ let name = Some $1, noQscope, IdIdent $2 in
mk_e (Id (name, noIdInfo())) [] }
| TColCol operator_function_id
{ let qop = $2 in
let name = (Some $1, noQscope, qop) in
mk_e (Id (name, noIdInfo())) [] }
| TColCol qualified_id
{ let name = (Some $1, fst $2, snd $2) in
mk_e (Id (name, noIdInfo())) [] }
/*(*could use TInf here *)*/
cast_operator_expr:
| cpp_cast_operator TInf_Template type_id TSup_Template TOPar expr TCPar
{ mk_e (CplusplusCast ($1, ($2, $3, $4), ($5, $6, $7))) noii }
/*(* TODO: remove once we don't skip template arguments *)*/
| cpp_cast_operator TOPar expr TCPar
{ mk_e ExprTodo noii }
/*(*c++ext:*)*/
cpp_cast_operator:
| Tstatic_cast { Static_cast, $1 }
| Tdynamic_cast { Dynamic_cast, $1 }
| Tconst_cast { Const_cast, $1 }
| Treinterpret_cast { Reinterpret_cast, $1 }
/*
(* c++ext: cast with function syntax, and also constructor, but conflict
* hence the TIdent_TypedefConstr. But it's simpler to just consider
* this as a function call. A semantic analysis could infer it was
* actually a ConstructedObject.
*
* TODO: can have nested specifier before the typedefident ... so
* need a classname3?
*)*/
cast_constructor_expr:
| TIdent_TypedefConstr TOPar argument_list_opt TCPar
{ let name = None, noQscope, IdIdent $1 in
let ft = nQ, (TypeName name, noii) in
mk_e(ConstructedObject (ft, ($2, $3, $4))) noii
}
| basic_type_2 TOPar argument_list_opt TCPar
{ let ft = nQ, $1 in
mk_e(ConstructedObject (ft, ($2, $3, $4))) noii
}
/*(* c++ext: * simple case: new A(x1, x2); *)*/
new_expr:
| tcolcol_opt Tnew new_placement_opt new_type_id new_initializer_opt
{ mk_e (New ($1, $2, $3, $4, $5)) noii }
/*(* ambiguity then on the TOPar
tcolcol_opt Tnew new_placement_opt TOPar type_id TCPar new_initializer_opt
*)*/
delete_expr:
| tcolcol_opt Tdelete cast_expr
{ mk_e (Delete ($1, $3)) [$2] }
| tcolcol_opt Tdelete TOCro_new TCCro_new cast_expr
{ mk_e (DeleteArray ($1, $5)) [$2;$3;$4] }
new_placement:
| TOPar argument_list TCPar { ($1, $2, $3) }
new_initializer:
| TOPar argument_list_opt TCPar { ($1, $2, $3) }
/*(*----------------------------*)*/
/*(*2 gccext: *)*/
/*(*----------------------------*)*/
compound_literal_expr:
| TOPar type_id TCPar TOBrace TCBrace
{ mk_e(GccConstructor (($1, $2, $3), ($4, [], $5))) noii }
| TOPar type_id TCPar TOBrace initialize_list gcc_comma_opt TCBrace
{ mk_e(GccConstructor (($1, $2, $3), ($4, List.rev $5, $7))) noii }
string_elem:
| TString { [snd $1] }
/*(* cppext: ex= printk (KERN_INFO "xxx" UTS_RELEASE) *)*/
| TIdent_MacroString { [$1] }
/*(*----------------------------*)*/
/*(*2 cppext: *)*/
/*(*----------------------------*)*/
argument:
| assign_expr { Left $1 }
/*(* cppext: *)*/
/*(* actually this can happen also when have a wrong typedef inference ...*)*/
| type_id { Right (ArgType $1) }
/* see todo_mly */
/*(*----------------------------*)*/
/*(*2 workarounds *)*/
/*(*----------------------------*)*/
/*(* would like evalInt $1 but require too much info *)*/
const_expr: cond_expr { $1 }
basic_type_2:
| Tchar_Constr { (BaseType (IntType CChar)), [$1]}
| Tint_Constr { (BaseType (IntType (Si (Signed,CInt)))), [$1]}
| Tfloat_Constr { (BaseType (FloatType CFloat)), [$1]}
| Tdouble_Constr { (BaseType (FloatType CDouble)), [$1] }
| Twchar_t_Constr { (BaseType (IntType WChar_t)), [$1] }
| Tshort_Constr { (BaseType (IntType (Si (Signed, CShort)))), [$1] }
| Tlong_Constr { (BaseType (IntType (Si (Signed, CLong)))), [$1] }
| Tbool_Constr { (BaseType (IntType CBool)), [$1] }
/*(*************************************************************************)*/
/*(*1 Statements *)*/
/*(*************************************************************************)*/
statement:
| compound { Compound $1, noii }
| expr_statement { ExprStatement(fst $1), snd $1 }
| labeled { Labeled (fst $1), snd $1 }
| selection { Selection (fst $1), snd $1 }
| iteration { Iteration (fst $1), snd $1 }
| jump TPtVirg { Jump (fst $1), snd $1 @ [$2] }
/*(* cppext: *)*/
| TIdent_MacroStmt { MacroStmt, [$1] }
/*
(* cppext: c++ext: because of cpp, some stuff looks like declaration but are in
* fact statement but too hard to figure out, and if parse them as
* expression, then we force to have first decls and then exprs, then
* will have a parse error. So easier to let mix decl/statement.
* Moreover it helps to not make such a difference between decl and
* statement for further coccinelle phases to factorize code.
*
* update: now a c++ext and handle slightly differently. It's inlined
* in statement instead of going through a stat_or_decl.
*)*/
| declaration_statement { $1 }
/*(* gccext: if move in statement then can have r/r conflict with define *)*/
| function_definition { NestedFunc $1, noii }
/*(* c++ext: *)*/
| try_block { $1 }
compound:
| TOBrace statement_list_opt TCBrace { ($1, $2, $3) }
expr_statement:
| expr_opt TPtVirg { $1, [$2] }
/*(* note that case 1: case 2: i++; would be correctly parsed, but with
* a Case (1, (Case (2, i++))) :(
*)*/
labeled:
| ident TCol statement { Label (fst $1, $3), [snd $1; $2] }
| Tcase const_expr TCol statement { Case ($2, $4), [$1; $3] }
| Tcase const_expr TEllipsis const_expr TCol statement
{ CaseRange ($2, $4, $6), [$1;$3;$5] } /*(* gccext: allow range *)*/
| Tdefault TCol statement { Default $3, [$1; $2] }
/*(* classic else ambiguity resolved by a %prec, see conflicts.txt *)*/
selection:
| Tif TOPar expr TCPar statement %prec LOW_PRIORITY_RULE
{ If ($1, ($2, $3, $4), $5, None, (ExprStatement None, [])), noii }
| Tif TOPar expr TCPar statement Telse statement
{ If ($1, ($2, $3, $4), $5, Some $6, $7), noii }
| Tswitch TOPar expr TCPar statement
{ Switch ($1, ($2, $3, $4), $5), noii }
iteration:
| Twhile TOPar expr TCPar statement
{ While ($1, ($2, $3, $4), $5), noii }
| Tdo statement Twhile TOPar expr TCPar TPtVirg
{ DoWhile ($1, $2, $3, ($4, $5, $6), $7), noii }
| Tfor TOPar expr_statement expr_statement expr_opt TCPar statement
{ For ($1, ($2, ($3,$4, ($5, [])), $6), $7), noii }
/*(* cppext: *)*/
| TIdent_MacroIterator TOPar argument_list_opt TCPar statement
{ MacroIteration ($1, ($2, $3, $4), $5), noii }
/*(* the ';' in the caller grammar rule will be appended to the infos *)*/
jump:
| Tgoto ident { Goto (fst $2), [$1;snd $2] }
| Tcontinue { Continue, [$1] }
| Tbreak { Break, [$1] }
| Treturn { Return, [$1] }
| Treturn expr { ReturnExpr $2, [$1] }
| Tgoto TMul expr { GotoComputed $3, [$1;$2] }
/*(*----------------------------*)*/
/*(*2 cppext: *)*/
/*(*----------------------------*)*/
statement_list_opt:
| /*(*empty*)*/ { [] }
| statement_list { $1 }
statement_list:
| statement_seq { [$1] }
| statement_list statement_seq { $1 @ [$2] }
statement_seq:
| statement { StmtElem $1 }
/*(* cppext: *)*/
| cpp_directive
{ CppDirectiveStmt $1 }
| cpp_ifdef_directive/*(* stat_or_decl_list ...*)*/
{ IfdefStmt $1 }
/*(*----------------------------*)*/
/*(*2 c++ext: *)*/
/*(*----------------------------*)*/
declaration_statement:
| block_declaration { DeclStmt $1, noii }
try_block:
| Ttry compound handler_list { Try ($1, $2, $3), noii }
handler:
| Tcatch TOPar exception_decl TCPar compound { ($1, ($2, $3, $4), $5) }
exception_decl:
| parameter_decl { ExnDecl $1 }
| TEllipsis { ExnDeclEllipsis $1 }
/*(*************************************************************************)*/
/*(*1 Types *)*/
/*(*************************************************************************)*/
/*(*-----------------------------------------------------------------------*)*/
/*(*2 Type spec, left part of a type *)*/
/*(*-----------------------------------------------------------------------*)*/
/*(* in c++ grammar they put 'cv_qualifier' here but I prefer keep as before *)*/
type_spec:
| simple_type_specifier { $1 }
| elaborated_type_specifier { $1 }
| enum_specifier { Right3 $1, noii }
| class_specifier { Right3 (StructDef $1), noii }
simple_type_specifier:
| Tvoid { Right3 (BaseType Void), [$1] }
| Tchar { Right3 (BaseType (IntType CChar)), [$1]}
| Tint { Right3 (BaseType (IntType (Si (Signed,CInt)))), [$1]}
| Tfloat { Right3 (BaseType (FloatType CFloat)), [$1]}
| Tdouble { Right3 (BaseType (FloatType CDouble)), [$1] }
| Tshort { Middle3 Short, [$1]}
| Tlong { Middle3 Long, [$1]}
| Tsigned { Left3 Signed, [$1]}
| Tunsigned { Left3 UnSigned, [$1]}
/*(*c++ext: *)*/
| Tbool { Right3 (BaseType (IntType CBool)), [$1] }
| Twchar_t { Right3 (BaseType (IntType WChar_t)), [$1] }
/*(* gccext: *)*/
| Ttypeof TOPar assign_expr TCPar { Right3 (TypeOf ($1,($2,Right $3,$4))),noii}
| Ttypeof TOPar type_id TCPar { Right3 (TypeOf ($1,($2,Left $3,$4))),noii}
/*
(* history: cant put TIdent {} cos it makes the grammar ambiguous and
* generates lots of conflicts => we must use some tricks.
* See parsing_hacks_typedef.ml. See also conflicts.txt
*)*/
| type_cplusplus_id { Right3 (TypeName $1), noii }
/*(*todo: can have a ::opt nested_name_specifier_opt before ident*)*/
elaborated_type_specifier:
| Tenum ident
{ Right3 (EnumName ($1, $2)), noii }
| class_key ident
{ Right3 (StructUnionName ($1, $2)), noii }
/*(* c++ext: *)*/
| Ttypename type_cplusplus_id
{ Right3 (TypenameKwd ($1, $2)), noii }
/*(*----------------------------*)*/
/*(*2 c++ext: *)*/
/*(*----------------------------*)*/
/*(* cant factorize with a tcolcol_opt2 *)*/
type_cplusplus_id:
| type_name { None, noQscope, $1 }
| nested_name_specifier2 type_name { None, $1, $2 }
| TColCol_BeforeTypedef type_name { Some $1, noQscope, $2 }
| TColCol_BeforeTypedef nested_name_specifier2 type_name
{ Some $1, $2, $3 }
/*
(* in c++ grammar they put
* typename: enum-name | typedef-name | class-name
* class-name: identifier | template-id
* template-id: template-name < template-argument-list >
*
* But in my case I don't have the contextual info so when I see an ident
* it can be a typedef-name, enum-name, or class-name (but not template-name
* because I detect them as they have a '<' just after),
* so here type_name is simplified in consequence.
*)*/
type_name:
| enum_name_or_typedef_name_or_simple_class_name { IdIdent $1 }
| template_id { $1 }
template_id:
| TIdent_Templatename TInf_Template template_argument_list TSup_Template
{ IdTemplateId ($1, ($2, $3, $4)) }
/*
(*c++ext: in the c++ grammar they have also 'template-name' but this is catched
* in my case by type_id and its generic TypedefIdent, or will be parsed
* as an Ident and so assign_expr. In this later case may need a ast post
* disambiguation analysis for some false positive.
*)*/
template_argument:
| type_id { Left $1 }
| assign_expr { Right $1 }
/*(*-----------------------------------------------------------------------*)*/
/*(*2 Qualifiers *)*/
/*(*-----------------------------------------------------------------------*)*/
/*(* was called type_qualif before *)*/
cv_qualif:
| Tconst { {const=Some $1; volatile=None} }
| Tvolatile { {const=None ; volatile=Some $1} }
/*(* C99 *)*/
| Trestrict { (* TODO *) {const=None ; volatile=None} }
/*(*-----------------------------------------------------------------------*)*/
/*(*2 Declarator, right part of a type + second part of decl (the ident) *)*/
/*(*-----------------------------------------------------------------------*)*/
/*
(* declarator return a couple:
* (name, partial type (a function to be applied to return type))
*
* note that with 'int* f(int)' we must return Func(Pointer int,int) and not
* Pointer (Func(int,int)).
*)*/
declarator:
| pointer direct_d { (fst $2, fun x -> x +> $1 +> (snd $2) ) }
| direct_d { $1 }
/*(* so must do int * const p; if the pointer is constant, not the pointee *)*/
pointer:
| TMul { fun x ->(nQ, (Pointer x, [$1]))}
| TMul cv_qualif_list { fun x ->($2.qualifD, (Pointer x, [$1]))}
| TMul pointer { fun x ->(nQ, (Pointer ($2 x),[$1]))}
| TMul cv_qualif_list pointer { fun x ->($2.qualifD, (Pointer ($3 x),[$1]))}
/*(*c++ext: no qualif for ref *)*/
| TAnd { fun x ->(nQ, (Reference x, [$1]))}
| TAnd pointer { fun x ->(nQ, (Reference ($2 x),[$1]))}
direct_d:
| declarator_id
{ ($1, fun x -> x) }
| TOPar declarator TCPar /*(* forunparser: old: $2 *)*/
{ (fst $2, fun x -> (nQ, (ParenType ($1, (snd $2) x, $3), noii))) }
| direct_d TOCro TCCro
{ (fst $1, fun x->(snd $1) (nQ,(Array (($2,None,$3),x), noii))) }
| direct_d TOCro const_expr TCCro
{ (fst $1, fun x->(snd $1) (nQ,(Array (($2, Some $3, $4),x),noii))) }
| direct_d TOPar TCPar const_opt exn_spec_opt
{ (fst $1, fun x-> (snd $1)
(nQ, (FunctionType {
ft_ret= x; ft_params = ($2, [], $3);
ft_dots = None; ft_const = $4; ft_throw = $5; }, noii)))
}
| direct_d TOPar parameter_type_list TCPar const_opt exn_spec_opt
{ (fst $1, fun x-> (snd $1)
(nQ,(FunctionType {
ft_ret = x; ft_params = ($2,fst $3,$4);
ft_dots = snd $3; ft_const = $5; ft_throw = $6; }, noii)))
}
/*(*----------------------------*)*/
/*(*2 c++ext: *)*/
/*(*----------------------------*)*/
declarator_id:
| tcolcol_opt id_expression
{ ($1, fst $2, snd $2) }
/*(* TODO ::opt nested-name-specifieropt type-name*) */
/*(*-----------------------------------------------------------------------*)*/
/*(*2 Abstract Declarator (right part of a type, no ident) *)*/
/*(*-----------------------------------------------------------------------*)*/
abstract_declarator:
| pointer { $1 }
| direct_abstract_declarator { $1 }
| pointer direct_abstract_declarator { fun x -> x +> $2 +> $1 }
direct_abstract_declarator:
| TOPar abstract_declarator TCPar /*(* forunparser: old: $2 *)*/
{ (fun x -> (nQ, (ParenType ($1, $2 x, $3), noii))) }
| TOCro TCCro
{ fun x -> (nQ, (Array (($1,None, $2), x), noii))}
| TOCro const_expr TCCro
{ fun x -> (nQ, (Array (($1, Some $2, $3), x), noii))}
| direct_abstract_declarator TOCro TCCro
{ fun x ->$1 (nQ, (Array (($2, None, $3), x), noii)) }
| direct_abstract_declarator TOCro const_expr TCCro
{ fun x ->$1 (nQ, (Array (($2, Some $3, $4), x), noii)) }
| TOPar TCPar
{ fun x -> (nQ, (FunctionType {
ft_ret = x; ft_params = ($1,[],$2);
ft_dots = None; ft_const = None; ft_throw = None;}, noii)) }
| TOPar parameter_type_list TCPar
{ fun x -> (nQ, (FunctionType {
ft_ret = x; ft_params = ($1,fst $2,$3);
ft_dots = snd $2; ft_const = None; ft_throw = None; }, noii)) }
| direct_abstract_declarator TOPar TCPar const_opt exn_spec_opt
{ fun x -> $1 (nQ, (FunctionType {
ft_ret = x; ft_params = ($2,[],$3);
ft_dots = None; ft_const = $4; ft_throw = $5; }, noii)) }
| direct_abstract_declarator TOPar parameter_type_list TCPar const_opt
exn_spec_opt
{ fun x -> $1 (nQ, (FunctionType {
ft_ret = x; ft_params = ($2,fst $3,$4);
ft_dots = snd $3; ft_const = $5; ft_throw = $6; }, noii)) }
/*(*-----------------------------------------------------------------------*)*/
/*(*2 Parameters (use decl_spec not type_spec just for 'register') *)*/
/*(*-----------------------------------------------------------------------*)*/
parameter_type_list:
| parameter_list { $1, None }
| parameter_list TComma TEllipsis { $1, Some ($2,$3) }
parameter_decl:
| decl_spec declarator
{ let (t_ret,reg) = type_and_register_from_decl $1 in
let (name, ftyp) = fixNameForParam $2 in
{ p_name = Some name; p_type = ftyp t_ret;
p_register = reg; p_val = None } }
| decl_spec abstract_declarator
{ let (t_ret, reg) = type_and_register_from_decl $1 in
{ p_name = None; p_type = $2 t_ret;
p_register = reg; p_val = None } }
| decl_spec
{ let (t_ret, reg) = type_and_register_from_decl $1 in
{ p_name = None; p_type = t_ret; p_register = reg; p_val = None } }
/*(*c++ext: default parameter value, copy paste *)*/
| decl_spec declarator TEq assign_expr
{ let (t_ret, reg) = type_and_register_from_decl $1 in
let (name, ftyp) = fixNameForParam $2 in
{ p_name = Some name; p_type = ftyp t_ret;
p_register = reg; p_val = Some ($3, $4) } }
| decl_spec abstract_declarator TEq assign_expr
{ let (t_ret, reg) = type_and_register_from_decl $1 in
{ p_name = None; p_type = $2 t_ret;
p_register = reg; p_val = Some ($3, $4) } }
| decl_spec TEq assign_expr
{ let (t_ret, reg) = type_and_register_from_decl $1 in
{ p_name = None; p_type = t_ret;
p_register = reg; p_val = Some($2,$3) } }
/*(*----------------------------*)*/
/*(*2 workarounds *)*/
/*(*----------------------------*)*/
parameter_list:
| parameter_decl2 { [$1, []] }
| parameter_list TComma parameter_decl2 { $1 @ [$3, [$2]] }
parameter_decl2:
| parameter_decl { $1 }
/*(* when the typedef inference didn't work *)*/
| TIdent
{
let t = nQ, (TypeName (None, [], IdIdent $1), noii) in
{ p_name = None; p_type = t; p_val = None; p_register = None; }
}
/*(*----------------------------*)*/
/*(*2 c++ext: *)*/
/*(*----------------------------*)*/
/*
(*c++ext: specialisation
* TODO should be type-id-listopt. Also they can have qualifiers!
* need typedef heuristic for throw() but can be also an expression ...
*)*/
exception_specification:
| Tthrow TOPar TCPar { ($1, ($2, [], $3)) }
| Tthrow TOPar exn_name TCPar { ($1, ($2, [Left $3], $4)) }
| Tthrow TOPar exn_name TComma exn_name TCPar
{ ($1, ($2, [Left $3; Right $4; Left $5], $6)) }
exn_name: ident
{ None, [], IdIdent $1 }
/*(*c++ext: in orig they put cv-qualifier-seqopt but it's never volatile so*)*/
const_opt:
| Tconst { Some $1 }
| /*(*empty*)*/ { None }
/*(*-----------------------------------------------------------------------*)*/
/*(*2 helper type rules *)*/
/*(*-----------------------------------------------------------------------*)*/
/*(* For type_id. No storage here. Was used before for field but
* now structure fields can have storage so fields now use decl_spec. *)*/
spec_qualif_list:
| type_spec { addTypeD $1 nullDecl }
| cv_qualif { {nullDecl with qualifD = $1} }
| type_spec spec_qualif_list { addTypeD $1 $2 }
| cv_qualif spec_qualif_list { addQualifD $1 $2 }
/*(* for pointers in direct_declarator and abstract_declarator *)*/
cv_qualif_list:
| cv_qualif { {nullDecl with qualifD = $1 } }
| cv_qualif_list cv_qualif { addQualifD $2 $1 }
/*(*-----------------------------------------------------------------------*)*/
/*(*2 xxx_type_id *)*/
/*(*-----------------------------------------------------------------------*)*/
/*(* For cast, sizeof, throw. Was called type_name in old C grammar. *)*/
type_id:
| spec_qualif_list
{ let (t_ret, _, _) = type_and_storage_from_decl $1 in t_ret }
| spec_qualif_list abstract_declarator
{ let (t_ret, _, _) = type_and_storage_from_decl $1 in $2 t_ret }
/*
(* used for the type passed to new().
* There is ambiguity with '*' and '&' cos when have new int *2, it can
* be parsed as (new int) * 2 or (new int * ) 2.
* cf p62 of Ellis. So when see a TMul or TAnd don't reduce here,
* shift, hence the prec when are to decide wether or not to enter
* in new_declarator and its leading ptr_operator
*)*/
new_type_id:
| spec_qualif_list %prec LOW_PRIORITY_RULE
{ let (t_ret, _, _) = type_and_storage_from_decl $1 in t_ret }
| spec_qualif_list new_declarator
{ let (t_ret, _, _) = type_and_storage_from_decl $1 in (* TODOAST *) t_ret }
new_declarator:
| ptr_operator new_declarator
{ () }
| ptr_operator %prec LOW_PRIORITY_RULE
{ () }
| direct_new_declarator
{ () }
ptr_operator:
| TMul { () }
| TAnd { () }
direct_new_declarator:
| TOCro expr TCCro { () }
| direct_new_declarator TOCro expr TCCro { () }
/*
(* in c++ grammar they do 'type_spec_seq conversion_declaratoropt'. We
* can not replace with a simple 'type_id' cos here we must not allow
* functionType otherwise there is conflicts on TOPar.
* TODO: right now do simple_type_specifier because conflict
* when do full type_spec.
* type_spec conversion_declaratoropt
*
*)*/
conversion_type_id:
| simple_type_specifier conversion_declarator
{ let tx = addTypeD $1 nullDecl in
let (t_ret, _, _) = type_and_storage_from_decl tx in t_ret
}
| simple_type_specifier %prec LOW_PRIORITY_RULE
{ let tx = addTypeD $1 nullDecl in
let (t_ret, _, _) = type_and_storage_from_decl tx in t_ret
}
conversion_declarator:
| ptr_operator conversion_declarator
{ () }
| ptr_operator %prec LOW_PRIORITY_RULE
{ () }
/*(*************************************************************************)*/
/*(*1 Class and struct definitions *)*/
/*(*************************************************************************)*/
/*(* this can come from a simple_declaration/decl_spec *)*/
class_specifier:
| class_head TOBrace member_specification_opt TCBrace
{ let (kind, nameopt, baseopt) = $1 in
{ c_kind = kind; c_name = nameopt;
c_inherit = baseopt; c_members = ($2, $3, $4) } }
/*
(* todo in grammar they allow anon class with base_clause, weird.
* bugfix_c++: in c++ grammar they put identifier but when we do template
* specialization then we can get some template_id. Note that can
* not introduce a class_key_name intermediate cos they get a
* r/r conflict as there is another place with a 'class_key ident'
* in elaborated specifier. So need to duplicate the rule for
* the template_id case.
*)*/
class_head:
| class_key
{ $1, None, None }
| class_key ident base_clause_opt
{ let name = None, noQscope, IdIdent $2 in
$1, Some name, $3 }
| class_key nested_name_specifier ident base_clause_opt
{ let name = None, $2, IdIdent $3 in
$1, Some name, $4 }
/*(* was called struct_union before *)*/
class_key:
| Tstruct { Struct, $1 }
| Tunion { Union, $1 }
/*(*c++ext: *)*/
| Tclass { Class, $1 }
/*(*----------------------------*)*/
/*(*2 c++ext: inheritance rules *)*/
/*(*----------------------------*)*/
base_clause:
| TCol base_specifier_list { $1, $2 }
/*(* base-specifier:
* ::opt nested-name-specifieropt class-name
* virtual access-specifieropt ::opt nested-name-specifieropt class-name
* access-specifier virtualopt ::opt nested-name-specifieropt class-name
* specialisation
*)*/
base_specifier:
| class_name
{ { i_name = $1; i_virtual = None; i_access = None } }
| access_specifier class_name
{ { i_name = $2; i_virtual = None; i_access = Some $1 } }
| Tvirtual access_specifier class_name
{ { i_name = $3; i_virtual = Some $1; i_access = Some $2 } }
/*(* TODO? specialisation | ident { $1 }, do heuristic so can remove rule2 *)*/
class_name:
| type_cplusplus_id { $1 }
| TIdent { None, noQscope, IdIdent $1 }
/*(*----------------------------*)*/
/*(*2 c++ext: members *)*/
/*(*----------------------------*)*/
/*(* todo? add cpp_directive possibility here too *)*/
member_specification:
| member_declaration member_specification_opt
{ ClassElem $1::$2 }
| access_specifier TCol member_specification_opt
{ ClassElem (Access ($1, $2))::$3 }
access_specifier:
| Tpublic { Public, $1 }
| Tprivate { Private, $1 }
| Tprotected { Protected, $1 }
/*(* in c++ grammar there is a ;opt after function_definition but
* there is a conflict as it can also be an EmptyField *)*/
member_declaration:
| field_declaration { fixFieldOrMethodDecl $1 }
| function_definition { MemberFunc (FunctionOrMethod $1) }
| qualified_id TPtVirg
{ let name = (None, fst $1, snd $1) in
QualifiedIdInClass (name, $2)
}
| using_declaration { UsingDeclInClass $1 }
| template_declaration { TemplateDeclInClass $1 }
/*(* not in c++ grammar as merged with function_definition, but I can't *)*/
| ctor_dtor_member { $1 }
/*(* cppext: as some macro sometimes have a trailing ';' we must allow
* them here. Generates conflicts if keep the opt_ptvirg mentionned
* before.
* c++ext: in c++ grammar they put a double optional but I prefer
* to force the presence of a decl_spec. I don't know what means
* 'x;' in a structure, maybe default to int but not practical for my way of
* parsing
*)*/
| TPtVirg { EmptyField $1 }
/*(*-----------------------------------------------------------------------*)*/
/*(*2 field declaration *)*/
/*(*-----------------------------------------------------------------------*)*/
field_declaration:
| decl_spec TPtVirg
{ (* gccext: allow empty elements if it is a structdef or enumdef *)
let (t_ret, sto, _inline) = type_and_storage_from_decl $1 in
let onedecl = { v_namei = None; v_type = t_ret; v_storage = sto } in
([(FieldDecl onedecl),noii], $2)
}
| decl_spec member_declarator_list TPtVirg
{ let (t_ret, sto, _inline) = type_and_storage_from_decl $1 in
($2 +> (List.map (fun (f, iivirg) -> f t_ret sto, iivirg)), $3)
}
/*(* was called struct_declarator before *)*/
member_declarator:
| declarator
{ let (name, partialt) = $1 in (fun t_ret sto ->
FieldDecl {
v_namei = Some (name, None);
v_type = partialt t_ret; v_storage = sto; })
}
/*(* can also be an abstract when it's =0 on a function type *)*/
| declarator TEq const_expr
{ let (name, partialt) = $1 in (fun t_ret sto ->
FieldDecl {
v_namei = Some (name, Some (EqInit ($2, InitExpr $3)));
v_type = partialt t_ret; v_storage = sto;
})
}
/*(* normally just ident, but ambiguity so solve by inspetcing declarator *)*/
| declarator TCol const_expr
{ let (name, _partialt) = fixNameForParam $1 in (fun t_ret _stoTODO ->
BitField (Some name, $2, t_ret, $3))
}
| TCol const_expr
{ (fun t_ret _stoTODO -> BitField (None, $1, t_ret, $2)) }
/*(*-----------------------------------------------------------------------*)*/
/*(*2 c++ext: constructor special case *)*/
/*(*-----------------------------------------------------------------------*)*/
/*(* special case for ctor/dtor because they don't have a return type.
* TODOAST on the ctor_spec and chain of calls
*)*/
ctor_dtor_member:
| ctor_spec TIdent_Constructor TOPar parameter_type_list_opt TCPar
ctor_mem_initializer_list_opt
compound
{ MemberFunc (Constructor (mk_constructor $2 ($3, $4, $5) $7)) }
| ctor_spec TIdent_Constructor TOPar parameter_type_list_opt TCPar TPtVirg
{ MemberDecl (ConstructorDecl ($2, ($3, opt_to_list_params $4, $5), $6)) }
| dtor_spec TTilde ident TOPar void_opt TCPar exn_spec_opt compound
{ MemberFunc (Destructor (mk_destructor $2 $3 ($4, $5, $6) $7 $8)) }
| dtor_spec TTilde ident TOPar void_opt TCPar exn_spec_opt TPtVirg
{ MemberDecl (DestructorDecl ($2, $3, ($4, $5, $6), $7, $8)) }
ctor_spec:
| Texplicit { }
| Tinline { }
| /*(*empty*)*/ { }
dtor_spec:
| Tvirtual { }
| Tinline { }
| /*(*empty*)*/ { }
ctor_mem_initializer_list_opt:
| TCol mem_initializer_list { () }
| /*(* empty *)*/ { () }
mem_initializer:
| mem_initializer_id TOPar argument_list_opt TCPar { () }
/*(* factorize with declarator_id ? specialisation *)*/
mem_initializer_id:
/* specialsiation | TIdent { () } */
| primary_cplusplus_id { () }
/*(*************************************************************************)*/
/*(*1 Enum definition *)*/
/*(*************************************************************************)*/
enum_specifier:
| Tenum TOBrace enumerator_list gcc_comma_opt TCBrace
{ EnumDef ($1, None, ($2, $3, $5)) (*$4*) }
| Tenum ident TOBrace enumerator_list gcc_comma_opt TCBrace
{ EnumDef ($1, Some $2, ($3, $4, $6)) (*$5*) }
enumerator:
| ident { { e_name = $1; e_val = None; } }
| ident TEq const_expr { { e_name = $1; e_val = Some ($2, $3); } }
/*(*************************************************************************)*/
/*(*1 Simple declaration, initializers *)*/
/*(*************************************************************************)*/
simple_declaration:
| decl_spec TPtVirg
{ let (t_ret, sto, _inline) = type_and_storage_from_decl $1 in
DeclList ([{v_namei = None; v_type = t_ret; v_storage = sto},noii],$2)
}
| decl_spec init_declarator_list TPtVirg
{ let (t_ret, sto, _inline) = type_and_storage_from_decl $1 in
DeclList (
($2 +> List.map (fun (((name, f), iniopt), iivirg) ->
(* old: if fst (unwrap storage)=StoTypedef then LP.add_typedef s; *)
{ v_namei = Some (name, iniopt);
v_type = f t_ret; v_storage = sto
},
iivirg
)), $3)
}
/*(* cppext: *)*/
| TIdent_MacroDecl TOPar argument_list TCPar TPtVirg
{ MacroDecl ([], $1, ($2, $3, $4), $5) }
| Tstatic TIdent_MacroDecl TOPar argument_list TCPar TPtVirg
{ MacroDecl ([$1], $2, ($3, $4, $5), $6) }
| Tstatic Tconst_MacroDeclConst
TIdent_MacroDecl TOPar argument_list TCPar TPtVirg
{ MacroDecl ([$1;$2], $3, ($4, $5, $6), $7) }
/*(*-----------------------------------------------------------------------*)*/
/*
(* In c++ grammar they put 'explicit' in function_spec, 'typedef' and 'friend'
* in decl_spec. But it's just estethic as no other rules directly
* mention function_spec or storage_spec. They just want to say that
* 'virtual' applies only to functions, but they have no way to check that
* syntaxically. I could keep as before, as in the C grammar.
* For 'explicit' I prefer to put it directly
* with the ctor as I already have a special heuristic for constructor.
* They also don't put the cv_qualif here but instead inline it in
* type_spec. I prefer to keep as before but I take care when
* they speak about type_spec to translate instead in type+qualif_spec
* (which is spec_qualif_list)
*
* todo? can simplify by putting all in _opt ? must have at least one otherwise
* decl_list is ambiguous ? (no cos have ';' between decl)
*)*/
decl_spec:
| storage_class_spec { {nullDecl with storageD = $1 } }
| type_spec { addTypeD $1 nullDecl }
| cv_qualif { {nullDecl with qualifD = $1 } }
| function_spec { {nullDecl with inlineD = (true, [snd $1]) } (*TODO*) }
| Ttypedef { {nullDecl with storageD = StoTypedef $1 } }
| Tfriend { {nullDecl with inlineD = (true, [$1]) } (*TODO*) }
| storage_class_spec decl_spec { addStorageD $1 $2 }
| type_spec decl_spec { addTypeD $1 $2 }
| cv_qualif decl_spec { addQualifD $1 $2 }
| function_spec decl_spec { addInlineD (snd $1) $2 (*TODO*) }
| Ttypedef decl_spec { addStorageD (StoTypedef $1) $2 }
| Tfriend decl_spec { addInlineD $1 $2 (*TODO*)}
function_spec:
/*(*gccext: and c++ext: *)*/
| Tinline { Inline, $1 }
/*(*c++ext: *)*/
| Tvirtual { Virtual, $1 }
storage_class_spec:
| Tstatic { Sto (Static, $1) }
| Textern { Sto (Extern, $1) }
| Tauto { Sto (Auto, $1) }
| Tregister { Sto (Register,$1) }
/*(* c++ext: *)*/
| Tmutable { Sto (Register,$1) (*TODO*) }
/*(*-----------------------------------------------------------------------*)*/
/*(*2 declarators (right part of type and variable) *)*/
/*(*-----------------------------------------------------------------------*)*/
init_declarator:
| declaratori { ($1, None) }
| declaratori TEq initialize { ($1, Some (EqInit ($2, $3))) }
/*
(* c++ext: c++ initializer via call to constructor. Note that this
* is different from TypedefIdent2, here the declaratori is an ident,
* not the constructorname hence the need for a TOPar_CplusplusInit
*)*/
| declaratori TOPar_CplusplusInit argument_list_opt TCPar
{ ($1, Some (ObjInit ($2, $3, $4))) }
/*(*----------------------------*)*/
/*(*2 gccext: *)*/
/*(*----------------------------*)*/
declaratori:
| declarator { $1 }
/*(* gccext: *)*/
| declarator gcc_asm_decl { $1 }
gcc_asm_decl:
| Tasm volatile_opt TOPar asmbody TCPar { }
/*(*-----------------------------------------------------------------------*)*/
/*(*2 initializers *)*/
/*(*-----------------------------------------------------------------------*)*/
initialize:
| assign_expr
{ InitExpr $1 }
| TOBrace initialize_list gcc_comma_opt_struct TCBrace
{ InitList ($1, List.rev $2, $4) (*$3*) }
/*(* gccext: *)*/
| TOBrace TCBrace
{ InitList ($1, [], $2) }
/*
(* opti: This time we use the weird order of non-terminal which requires in
* the "caller" to do a List.rev cos quite critical. With this wierd order it
* allows yacc to use a constant stack space instead of exploding if we would
* do a 'initialize2 Tcomma initialize_list'.
*)
*/
initialize_list:
| initialize2 { [$1, []] }
| initialize_list TComma initialize2 { ($3, [$2])::$1 }
/*(* gccext: condexpr and no assign_expr cos can have ambiguity with comma *)*/
initialize2:
| cond_expr
{ InitExpr $1 }
| TOBrace initialize_list gcc_comma_opt_struct TCBrace
{ InitList ($1, List.rev $2, $4) (*$3*) }
| TOBrace TCBrace
{ InitList ($1, [], $2) }
/*(* gccext: labeled elements, a.k.a designators *)*/
| designator_list TEq initialize2
{ InitDesignators ($1, $2, $3) }
/*(* gccext: old format, in old kernel for instance *)*/
| ident TCol initialize2
{ InitFieldOld ($1, $2, $3) }
/*(* kenccext: c++ext:, but conflcit with array designators *)*/
| TOCro const_expr TCCro initialize2
{ InitIndexOld (($1, $2, $3), $4) }
| TOCro const_expr TCCro TEq initialize2
{ InitDesignators ([DesignatorIndex($1, $2, $3)], $4, $5) }
/*(* they can be nested, can have a .x.[3].y *)*/
designator:
| TDot ident
{ DesignatorField ($1, $2) }
/* conflict with kenccext
| TOCro const_expr TCCro %prec LOW_PRIORITY_RULE
{ DesignatorIndex ($1, $2, $3) }
| TOCro const_expr TEllipsis const_expr TCCro
{ DesignatorRange ($1, ($2, $3, $4), $5) }
*/
/*(*----------------------------*)*/
/*(*2 workarounds *)*/
/*(*----------------------------*)*/
gcc_comma_opt_struct:
| TComma { Some $1 }
| /*(* empty *)*/ { None }
/*(*************************************************************************)*/
/*(*1 Block declaration (namespace and asm) *)*/
/*(*************************************************************************)*/
block_declaration:
| simple_declaration { $1 }
/*(*gccext: *)*/
| asm_definition { $1 }
/*(*c++ext: *)*/
| namespace_alias_definition { $1 }
| using_declaration { UsingDecl $1 }
| using_directive { $1 }
/*(*----------------------------*)*/
/*(*2 c++ext: *)*/
/*(*----------------------------*)*/
namespace_alias_definition:
| Tnamespace TIdent TEq tcolcol_opt nested_name_specifier_opt namespace_name
TPtVirg
{ let name = $4, $5, IdIdent $6 in NameSpaceAlias ($1, $2, $3, name, $7) }
using_directive:
| Tusing Tnamespace tcolcol_opt nested_name_specifier_opt namespace_name
TPtVirg
{ let name = $3, $4, IdIdent $5 in UsingDirective ($1, $2, name, $6) }
/*(* conflict on TColCol in 'Tusing TColCol unqualified_id TPtVirg'
* need LALR(2) to see if after tcol have a nested_name_specifier
* or put opt on nested_name_specifier too
*)*/
using_declaration:
| Tusing typename_opt tcolcol_opt nested_name_specifier unqualified_id TPtVirg
{ let name = ($3, $4, $5) in $1, name, $6 (*$2*) }
/*(* TODO: remove once we don't skip qualifier ? *)*/
| Tusing typename_opt tcolcol_opt unqualified_id TPtVirg
{ let name = ($3, [], $4) in $1, name, $5 (*$2*) }
/*(*----------------------------*)*/
/*(*2 gccext: c++ext: *)*/
/*(*----------------------------*)*/
/*(* gccext: c++ext: also apparently *)*/
asm_definition:
| Tasm volatile_opt TOPar asmbody TCPar TPtVirg
{ Asm($1, $2, ($3, $4, $5), $6) }
asmbody:
| string_list colon_asm_list { $1, $2 }
| string_list { $1, [] } /*(* in old kernel *)*/
colon_asm:
| TCol colon_option_list { Colon $2, [$1] }
colon_option:
| TString { ColonMisc, [snd $1] }
| TString TOPar asm_expr TCPar { ColonExpr ($2, $3, $4), [snd $1] }
/*(* cppext: certainly a macro *)*/
| TOCro TIdent TCCro TString TOPar asm_expr TCPar
{ ColonExpr ($5, $6, $7), [$1;snd $2;$3;snd $4] }
| TIdent { ColonMisc, [snd $1] }
| /*(* empty *)*/ { ColonMisc, [] }
asm_expr: assign_expr { $1 }
/*(*************************************************************************)*/
/*(*1 Declaration, in c++ sense *)*/
/*(*************************************************************************)*/
/*
(* in grammar they have 'explicit_instantiation' but it is equal to
* to template_declaration and so is ambiguous.
*
* declaration > block_declaration > simple_declaration, hmmm
* could be renamed declaration_or_definition
*)*/
declaration:
| block_declaration { BlockDecl $1 }
| function_definition { Func (FunctionOrMethod $1) }
/*(* not in c++ grammar as merged with function_definition, but I can't *)*/
| ctor_dtor { $1 }
| template_declaration { let (a,b,c) = $1 in TemplateDecl (a,b,c)}
| explicit_specialization { $1 }
| linkage_specification { $1 }
| namespace_definition { $1 }
/*(* sometimes the function ends with }; instead of just } *)*/
| TPtVirg { EmptyDef $1 }
/*(*----------------------------*)*/
/*(*2 cppext: *)*/
/*(*----------------------------*)*/
declaration_list_opt:
| /*(*empty*)*/ { [] }
| declaration_list { $1 }
declaration_list:
| declaration_seq { [$1] }
| declaration_list declaration_seq { $1 @ [$2] }
declaration_seq:
| declaration { DeclElem $1 }
/* (* cppext: *)*/
| cpp_directive
{ CppDirectiveDecl $1 }
| cpp_ifdef_directive/*(* stat_or_decl_list ...*)*/
{ IfdefDecl $1 }
/*(*----------------------------*)*/
/*(*2 c++ext: *)*/
/*(*----------------------------*)*/
/*(*todo: export_opt, but generates lots of conflicts *)*/
template_declaration:
| Ttemplate TInf_Template template_parameter_list TSup_Template declaration
{ ($1, ($2, $3, $4), $5) }
explicit_specialization:
| Ttemplate TInf_Template TSup_Template declaration
{ TemplateSpecialization ($1, ($2, (), $3), $4) }
/*(*todo: '| type_paramter'
* ambiguity with parameter_decl cos a type can also be 'class X'
| Tclass ident { raise Todo }
*)*/
template_parameter:
| parameter_decl { $1 }
/*(* c++ext: could also do a extern_string_opt to factorize stuff *)*/
linkage_specification:
| Textern TString declaration
{ ExternC ($1, (snd $2), $3) }
| Textern TString TOBrace declaration_list_opt TCBrace
{ ExternCList ($1, (snd $2), ($3, $4, $5)) }
namespace_definition:
| named_namespace_definition { $1 }
| unnamed_namespace_definition { $1 }
/*
(* in c++ grammar they make diff between 'original' and 'extension' namespace
* definition but they require some contextual information to know if
* an identifier was already a namespace. So here I have just a single rule.
*)*/
named_namespace_definition:
| Tnamespace TIdent TOBrace declaration_list_opt TCBrace
{ NameSpace ($1, $2, ($3, $4, $5)) }
unnamed_namespace_definition:
| Tnamespace TOBrace declaration_list_opt TCBrace
{ NameSpaceAnon ($1, ($2, $3, $4)) }
/*
(* Special case cos ctor/dtor do not have return type.
* TODO scope ? do a start_constructor ?
*)*/
ctor_dtor:
| nested_name_specifier TIdent_Constructor TOPar parameter_type_list_opt TCPar
ctor_mem_initializer_list_opt
compound
{ DeclTodo }
/*(* new_type_id, could also introduce a Tdestructorname or forbidy the
TypedefIdent2 transfo by putting a guard in the lalr(k) rule by
checking if have a ~ before
*)*/
| nested_name_specifier TTilde ident TOPar void_opt TCPar compound
{ DeclTodo }
/*(* TODO: remove once we don't skip qualifiers *)*/
| inline_opt TIdent_Constructor TOPar parameter_type_list_opt TCPar
ctor_mem_initializer_list_opt
compound
{ DeclTodo }
| TTilde ident TOPar void_opt TCPar exn_spec_opt compound
{ DeclTodo }
/*(*************************************************************************)*/
/*(*1 Function definition *)*/
/*(*************************************************************************)*/
function_definition: start_fun compound
{ fixFunc ($1, $2) }
start_fun: decl_spec declarator
{ let (t_ret, sto) = type_and_storage_for_funcdef_from_decl $1 in
(fst $2, fixOldCDecl ((snd $2) t_ret), sto)
}
/*(*************************************************************************)*/
/*(*1 Cpp directives *)*/
/*(*************************************************************************)*/
/*(* cppext: *)*/
cpp_directive:
| TInclude
{ let (_include_str, filename, tok) = $1 in
(* redo some lexing work :( *)
let inc_kind, path =
match () with
| _ when filename =~ "^\"\\(.*\\)\"$" -> Local, matched1 filename
| _ when filename =~ "^\\<\\(.*\\)\\>$" -> Standard, matched1 filename
| _ -> Weird, filename
in
Include (tok, inc_kind, path)
}
| TDefine TIdent_Define define_val TCommentNewline_DefineEndOfMacro
{ Define ($1, $2, DefineVar, $3) (*$4??*) }
/*
(* The TOPar_Define is introduced to avoid ambiguity with previous rules.
* A TOPar_Define is a TOPar that was just next to the ident (no space).
* See parsing_hacks_define.ml
*)*/
| TDefine TIdent_Define TOPar_Define param_define_list_opt TCPar
define_val TCommentNewline_DefineEndOfMacro
{ Define ($1, $2, (DefineFunc ($3, $4, $5)), $6) (*$7*) }
| TUndef { Undef $1 }
| TCppDirectiveOther { PragmaAndCo $1 }
define_val:
/*(* perhaps better to use assign_expr? but in that case need
* do a assign_expr_of_string'in parse_c.
* c++ext: update, now statement include simple declarations
* so maybe can parse $1 and generate the previous DefineDecl
* and DefineFunction? cos nested_func is also now inside statement.
*)*/
| expr { DefineExpr $1 }
| statement { DefineStmt $1 }
/*(* for statement-like macro with fixed number of arguments *)*/
| Tdo statement Twhile TOPar expr TCPar
{ match $5 with
| (C (Int ("0"))), [tok] -> DefineDoWhileZero ($2, [$1;$3;$4;tok;$6])
| _ -> raise Parsing.Parse_error
}
/*(* for statement-like macro with varargs *)*/
| Tif TOPar expr TCPar id_expression
{ let name = (None, fst $5, snd $5) in
DefinePrintWrapper ($1, ($2, $3, $4), name)
}
| TOBrace_DefineInit initialize_list TCBrace comma_opt
{ DefineInit (InitList ($1, List.rev $2, $3) (*$4*)) }
| /*(* empty *)*/ { DefineEmpty }
param_define:
| ident { fst $1, [snd $1] }
| TDefParamVariadic { fst $1, [snd $1] }
| TEllipsis { "...", [$1] }
/*(* they reuse keywords :( *)*/
| Tregister { "register", [$1] }
| Tnew { "new", [$1] }
cpp_ifdef_directive:
| TIfdef { Ifdef, $1 }
| TIfdefelse { IfdefElse, $1 }
| TIfdefelif { IfdefElseif, $1 }
| TEndif { IfdefEndif, $1 }
| TIfdefBool { Ifdef, snd $1 }
| TIfdefMisc { Ifdef, snd $1 }
| TIfdefVersion { Ifdef, snd $1 }
cpp_other:
/*(* cppext: *)*/
| TIdent TOPar argument_list TCPar TPtVirg
{ MacroTop ($1, ($2, $3, $4), Some $5) }
/*(* TCPar_EOL to fix the end-of-stream bug of ocamlyacc *)*/
| TIdent TOPar argument_list TCPar_EOL
{ MacroTop ($1, ($2, $3, $4), None) }
/*(* ex: EXPORT_NO_SYMBOLS; *)*/
| TIdent TPtVirg { MacroVarTop ($1, $2) }
/*(*************************************************************************)*/
/*(*1 toplevel *)*/
/*(*************************************************************************)*/
toplevel:
| toplevel_aux { Some $1 }
| EOF { None }
toplevel_aux:
| declaration { DeclElem $1 }
| cpp_directive { CppDirectiveDecl $1 }
| cpp_ifdef_directive /*(*external_declaration_list ...*)*/ { IfdefDecl $1 }
| cpp_other { $1 }
/*
(* when have error recovery, we can end up skipping the
* beginning of the file, and so get trailing unclose } at
* end
*)*/
| TCBrace { DeclElem (EmptyDef $1) }
/*(*************************************************************************)*/
/*(*1 xxx_list, xxx_opt *)*/
/*(*************************************************************************)*/
string_list:
| string_elem { $1 }
| string_list string_elem { $1 @ $2 }
colon_asm_list:
| colon_asm { [$1] }
| colon_asm_list colon_asm { $1 @ [$2] }
colon_option_list:
| colon_option { [$1, []] }
| colon_option_list TComma colon_option { $1 @ [$3, [$2]] }
argument_list:
| argument { [$1, []] }
| argument_list TComma argument { $1 @ [$3, [$2]] }
enumerator_list:
| enumerator { [$1, []] }
| enumerator_list TComma enumerator { $1 @ [$3, [$2]] }
init_declarator_list:
| init_declarator { [$1, []] }
| init_declarator_list TComma init_declarator { $1 @ [$3, [$2]] }
member_declarator_list:
| member_declarator { [$1, []] }
| member_declarator_list TComma member_declarator { $1 @ [$3, [$2]] }
param_define_list_opt:
| /*(* empty *)*/ { [] }
| param_define { [$1, []] }
| param_define_list_opt TComma param_define { $1 @ [$3, [$2]] }
designator_list:
| designator { [$1] }
| designator_list designator { $1 @ [$2] }
handler_list:
| handler { [$1] }
| handler_list handler { $1 @ [$2] }
mem_initializer_list:
| mem_initializer { [$1, []] }
| mem_initializer_list TComma mem_initializer { $1 @ [$3, [$2]] }
template_argument_list:
| template_argument { [$1, []] }
| template_argument_list TComma template_argument { $1 @ [$3, [$2]] }
template_parameter_list:
| template_parameter { [$1, []] }
| template_parameter_list TComma template_parameter { $1 @ [$3, [$2]] }
base_specifier_list:
| base_specifier { [$1, []] }
| base_specifier_list TComma base_specifier { $1 @ [$3, [$2]] }
/*(*-----------------------------------------------------------------------*)*/
/*(* gccext: which allow a trailing ',' in enum, as in perl *)*/
gcc_comma_opt:
| TComma { [$1] }
| /*(* empty *)*/ { [] }
comma_opt:
| TComma { [$1] }
| { [] }
assign_expr_opt:
| assign_expr { Some $1 }
| /*(* empty *)*/ { None }
expr_opt:
| expr { Some $1 }
| /*(* empty *)*/ { None }
argument_list_opt:
| argument_list { $1 }
| /*(*empty*)*/ { [] }
parameter_type_list_opt:
| parameter_type_list { Some $1 }
| /*(*empty*)*/ { None }
member_specification_opt:
| member_specification { $1 }
| /*(*empty*)*/ { [] }
nested_name_specifier_opt:
| nested_name_specifier { $1 }
| /*(* empty *)*/ { [] }
nested_name_specifier_opt2:
| nested_name_specifier2 { $1 }
| /*(* empty *)*/ { [] }
exn_spec_opt:
| exception_specification { Some $1 }
| /*(*empty*)*/ { None }
/*(*c++ext: ??? *)*/
new_placement_opt:
| new_placement { Some $1 }
| /*(*empty*)*/ { None }
new_initializer_opt:
| new_initializer { Some $1 }
| /*(*empty*)*/ { None }
base_clause_opt:
| base_clause { Some $1 }
| /*(*empty*)*/ { None }
typename_opt:
| Ttypename { [$1] }
| /*(*empty*)*/ { [] }
template_opt:
| Ttemplate { [$1] }
| /*(*empty*)*/ { [] }
/*
export_opt:
| Texport { Some $1 }
| (*empty*) { None }
ptvirg_opt:
| TPtVirg { [$1] }
| { [] }
*/
void_opt:
| Tvoid { Some $1 }
| /*(*empty*)*/ { None }
inline_opt:
| Tinline { Some $1 }
| /*(*empty*)*/ { None }
volatile_opt:
| Tvolatile { Some $1 }
| /*(*empty*)*/ { None }
tcolcol_opt:
| TColCol { Some $1 }
| /*(* empty *)*/ { None }