/*
-* Copyright 2005-2008, Ecole des Mines de Nantes, University of Copenhagen
-* Yoann Padioleau, Julia Lawall, Rene Rydhof Hansen, Henrik Stuart, Gilles Muller
-* This file is part of Coccinelle.
-*
-* Coccinelle is free software: you can redistribute it and/or modify
-* it under the terms of the GNU General Public License as published by
-* the Free Software Foundation, according to version 2 of the License.
-*
-* Coccinelle 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
-* GNU General Public License for more details.
-*
-* You should have received a copy of the GNU General Public License
-* along with Coccinelle. If not, see <http://www.gnu.org/licenses/>.
-*
-* The authors reserve the right to distribute this or future versions of
-* Coccinelle under other licenses.
-*/
+ * Copyright 2010, INRIA, University of Copenhagen
+ * Julia Lawall, Rene Rydhof Hansen, Gilles Muller, Nicolas Palix
+ * Copyright 2005-2009, Ecole des Mines de Nantes, University of Copenhagen
+ * Yoann Padioleau, Julia Lawall, Rene Rydhof Hansen, Henrik Stuart, Gilles Muller, Nicolas Palix
+ * This file is part of Coccinelle.
+ *
+ * Coccinelle is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, according to version 2 of the License.
+ *
+ * Coccinelle 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
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Coccinelle. If not, see <http://www.gnu.org/licenses/>.
+ *
+ * The authors reserve the right to distribute this or future versions of
+ * Coccinelle under other licenses.
+ */
%{
module Ast0 = Ast0_cocci
module Ast = Ast_cocci
module P = Parse_aux
+
+(* ---------------------------------------------------------------------- *)
+(* support for TMeta *)
+
+let print_meta (r,n) = r^"."^n
+
+let meta_metatable = Hashtbl.create(101)
+
+let coerce_tmeta newty name builder matcher =
+ try
+ let x = Hashtbl.find meta_metatable name in
+ if not (matcher x)
+ then
+ failwith
+ (Printf.sprintf "Metavariable %s is used as %s"
+ (print_meta name) newty)
+ with Not_found ->
+ (if !Flag_parsing_cocci.show_SP
+ then
+ Common.pr2
+ (Printf.sprintf
+ "Metavariable %s is assumed to be %s metavariable"
+ (print_meta name) newty));
+ Hashtbl.add meta_metatable name builder
+
+let tmeta_to_type (name,pure,clt) =
+ (coerce_tmeta "a type" name (TMetaType(name,pure,clt))
+ (function TMetaType(_,_,_) -> true | _ -> false));
+ Ast0.wrap(Ast0.MetaType(P.clt2mcode name clt,pure))
+
+let tmeta_to_field (name,pure,clt) =
+ (coerce_tmeta "a field" name (TMetaField(name,pure,clt))
+ (function TMetaField(_,_,_) -> true | _ -> false));
+ P.meta_field (name,pure,clt)
+
+let tmeta_to_exp (name,pure,clt) =
+ (coerce_tmeta "an expression" name
+ (TMetaExp(name,Ast0.NoConstraint,pure,None,clt))
+ (function TMetaExp(_,_,_,_,_) -> true | _ -> false));
+ Ast0.wrap
+ (Ast0.MetaExpr(P.clt2mcode name clt,Ast0.NoConstraint,None,Ast.ANY,pure))
+
+let tmeta_to_param (name,pure,clt) =
+ (coerce_tmeta "a parameter" name (TMetaParam(name,pure,clt))
+ (function TMetaParam(_,_,_) -> true | _ -> false));
+ Ast0.wrap(Ast0.MetaParam(P.clt2mcode name clt,pure))
+
+let tmeta_to_statement (name,pure,clt) =
+ (coerce_tmeta "a statement" name (TMetaType(name,pure,clt))
+ (function TMetaType(_,_,_) -> true | _ -> false));
+ P.meta_stm (name,pure,clt)
+
+let tmeta_to_seed_id (name,pure,clt) =
+ (coerce_tmeta "an identifier" name
+ (TMetaId(name,Ast.IdNoConstraint,pure,clt))
+ (function TMetaId(_,_,_,_) -> true | _ -> false));
+ Ast.SeedId name
+
+let tmeta_to_ident (name,pure,clt) =
+ (coerce_tmeta "an identifier" name
+ (TMetaId(name,Ast.IdNoConstraint,pure,clt))
+ (function TMetaId(_,_,_,_) -> true | _ -> false));
+ Ast0.wrap(Ast0.MetaId(P.clt2mcode name clt,Ast.IdNoConstraint,pure))
%}
%token EOF
%token TIdentifier TExpression TStatement TFunction TLocal TType TParameter
-%token TIdExpression
+%token TIdExpression TInitialiser TDeclaration TField TMetavariable
%token Tlist TFresh TConstant TError TWords TWhy0 TPlus0 TBang0
-%token TPure TContext
+%token TPure TContext TGenerated
%token TTypedef TDeclarer TIterator TName TPosition TPosAny
-%token TUsing TDisable TExtends TDepends TOn TEver TNever TExists TForall TScript
-%token TReverse TNothing
+%token TUsing TDisable TExtends TDepends TOn TEver TNever TExists TForall
+%token TScript TInitialize TFinalize TNothing TVirtual
%token<string> TRuleName
%token<Data.clt> Tchar Tshort Tint Tdouble Tfloat Tlong
-%token<Data.clt> Tvoid Tstruct Tunion
+%token<Data.clt> Tsize_t Tssize_t Tptrdiff_t
+%token<Data.clt> Tvoid Tstruct Tunion Tenum
%token<Data.clt> Tunsigned Tsigned
%token<Data.clt> Tstatic Tauto Tregister Textern Tinline Ttypedef
%token <Data.clt> TIf TElse TWhile TFor TDo TSwitch TCase TDefault TReturn
%token <Data.clt> TBreak TContinue TGoto TSizeof TFunDecl
%token <string * Data.clt> TIdent TTypeId TDeclarerId TIteratorId
-
-%token <Parse_aux.idinfo> TMetaId TMetaFunc TMetaLocalFunc
-%token <Parse_aux.idinfo> TMetaIterator TMetaDeclarer
-%token <Parse_aux.expinfo> TMetaErr
-%token <Parse_aux.info> TMetaParam TMetaStm TMetaStmList TMetaType
-%token <Parse_aux.list_info> TMetaParamList TMetaExpList
-%token <Parse_aux.typed_info> TMetaExp TMetaIdExp TMetaLocalIdExp TMetaConst
-%token <Parse_aux.pos_info> TMetaPos
+%token <Ast_cocci.added_string * Data.clt> TPragma
+
+%token <Parse_aux.idinfo> TMetaId TMetaFunc TMetaLocalFunc
+%token <Parse_aux.idinfo> TMetaIterator TMetaDeclarer
+%token <Parse_aux.expinfo> TMetaErr
+%token <Parse_aux.info> TMetaParam TMetaStm TMetaStmList TMetaType
+%token <Parse_aux.info> TMetaInit TMetaDecl TMetaField TMeta
+%token <Parse_aux.list_info> TMetaParamList TMetaExpList
+%token <Parse_aux.list_info> TMetaFieldList
+%token <Parse_aux.typed_expinfo> TMetaExp TMetaIdExp TMetaLocalIdExp TMetaConst
+%token <Parse_aux.pos_info> TMetaPos
%token TArob TArobArob TPArob
%token <string> TScriptData
%token <Data.clt> TWhy TDotDot TBang TOPar TOPar0
%token <Data.clt> TMid0 TCPar TCPar0
-%token <string> TPragma TPathIsoFile
+%token <string> TPathIsoFile
%token <string * Data.clt> TIncludeL TIncludeNL
-%token <Data.clt * token> TDefine
-%token <Data.clt * token * int> TDefineParam
+%token <Data.clt * token> TDefine TUndef
+%token <Data.clt * token * int * int> TDefineParam
%token <string * Data.clt> TMinusFile TPlusFile
%token <Data.clt> TInc TDec
%token <Data.clt> TAndLog
%token <Data.clt> TOr
%token <Data.clt> TXor
-%token <Data.clt> TAnd
-%token <Data.clt> TEqEq TNotEq
+%token <Data.clt> TAnd
+%token <Data.clt> TEqEq TNotEq TTildeEq TTildeExclEq TSub
%token <Ast_cocci.logicalOp * Data.clt> TLogOp /* TInf TSup TInfEq TSupEq */
-%token <Ast_cocci.arithOp * Data.clt> TShOp /* TShl TShr */
+%token <Ast_cocci.arithOp * Data.clt> TShLOp TShROp /* TShl TShr */
%token <Ast_cocci.arithOp * Data.clt> TDmOp /* TDiv TMod */
%token <Data.clt> TPlus TMinus
%token <Data.clt> TMul TTilde
%token <Data.clt> TPtrOp
-%token TMPtVirg
+%token TMPtVirg TCppConcatOp
%token <Data.clt> TEq TDot TComma TPtVirg
%token <Ast_cocci.assignOp * Data.clt> TAssign
%token TIso TRightIso TIsoExpression TIsoStatement TIsoDeclaration TIsoType
-%token TIsoTopLevel TIsoArgExpression TIsoTestExpression
+%token TIsoTopLevel TIsoArgExpression TIsoTestExpression TIsoToTestExpression
+
+%token TUnderscore
%token TInvalid
%left TAndLog
%left TOr
%left TXor
-%left TAnd
+%left TAnd
%left TEqEq TNotEq
%left TLogOp /* TInf TSup TInfEq TSupEq */
-%left TShOp /* TShl TShr */
+%left TShLOp TShROp /* TShl TShr */
%left TPlus TMinus
%left TMul TDmOp /* TDiv TMod */
%type <Ast0_cocci.rule> plus_exp_main
%start include_main
-%type <(string,string) Common.either list> include_main
+%type <Data.incl_iso list> include_main
%start iso_rule_name
%type <Ast_cocci.rulename>
%start meta_main
%type <(Ast_cocci.metavar,Ast_cocci.metavar) Common.either list> meta_main
-%start <string * (string * string)> script_meta_main
+%start <(string option (*string*) * string option (*ast*)) * (Ast_cocci.meta_name * Ast_cocci.metavar) option> script_meta_main
%start iso_main
%type <Ast0_cocci.anything list list> iso_main
nm=ioption(pure_ident) extends d=depends i=loption(choose_iso)
a=loption(disable) e=exists ee=is_expression TArob
{ P.make_cocci_rule_name_result nm d i a e ee }
- | TScript TDotDot lang=pure_ident d=depends TArob
- { P.make_script_rule_name_result lang d }
+ | TGenerated extends d=depends i=loption(choose_iso)
+ a=loption(disable) e=exists ee=is_expression TArob
+ /* these rules have no name as a cheap way to ensure that no normal
+ rule inherits their metavariables or depends on them */
+ { P.make_generated_rule_name_result None d i a e ee }
+ | TScript TDotDot lang=pure_ident nm=ioption(pure_ident) d=depends TArob
+ { P.make_script_rule_name_result lang nm d }
+ | TInitialize TDotDot lang=pure_ident d=depends TArob
+ { P.make_initial_script_rule_name_result lang d }
+ | TFinalize TDotDot lang=pure_ident d=depends TArob
+ { P.make_final_script_rule_name_result lang d }
extends:
/* empty */ { () }
exists:
TExists { Ast.Exists }
| TForall { Ast.Forall }
-| TReverse TForall { Ast.ReverseForall }
| { Ast.Undetermined }
is_expression: // for more flexible parsing of top level expressions
| list(incl) TArobArob { $1 }
incl:
- TUsing TString { Common.Left(P.id2name $2) }
-| TUsing TPathIsoFile { Common.Right $2 }
+ TIncludeL { let (x,_) = $1 in Data.Include(x) }
+| TUsing TString { Data.Iso(Common.Left(P.id2name $2)) }
+| TUsing TPathIsoFile { Data.Iso(Common.Right $2) }
+| TVirtual comma_list(pure_ident)
+ { let names = List.map P.id2name $2 in
+ Iteration.parsed_virtual_rules :=
+ Common.union_set names !Iteration.parsed_virtual_rules;
+ (* ensure that the names of virtual and real rules don't overlap *)
+ List.iter
+ (function name -> Hashtbl.add Data.all_metadecls name [])
+ names;
+ Data.Virt(names) }
metadec:
ar=arity ispure=pure
kindfn=metakind ids=comma_list(pure_ident_or_meta_ident) TMPtVirg
{ P.create_metadec ar ispure kindfn ids }
+| kindfn=metakind_fresh ids=comma_list(pure_ident_or_meta_ident_with_seed)
+ TMPtVirg
+ { P.create_fresh_metadec kindfn ids }
+| ar=arity ispure=pure
+ kindfn=metakind_atomic_maybe_virt
+ ids=
+ comma_list(pure_ident_or_meta_ident_with_idconstraint_virt(re_or_not_eqid))
+ TMPtVirg
+ { let (normal,virt) = Common.partition_either (fun x -> x) ids in
+ let (idfn,virtfn) = kindfn in
+ function cr ->
+ (P.create_metadec_with_constraints ar ispure idfn normal cr) @
+ (P.create_metadec_virt ar ispure virtfn virt cr) }
| ar=arity ispure=pure
kindfn=metakind_atomic
- ids=comma_list(pure_ident_or_meta_ident_with_not_eq(not_eq)) TMPtVirg
- { P.create_metadec_ne ar ispure kindfn ids }
+ ids=comma_list(pure_ident_or_meta_ident_with_idconstraint(re_or_not_eqid))
+ TMPtVirg
+ { P.create_metadec_with_constraints ar ispure kindfn ids }
| ar=arity ispure=pure
kindfn=metakind_atomic_expi
- ids=comma_list(pure_ident_or_meta_ident_with_not_eq(not_eqe)) TMPtVirg
- { P.create_metadec_ne ar ispure kindfn ids }
+ ids=comma_list(pure_ident_or_meta_ident_with_econstraint(re_or_not_eqe_or_sub))
+ TMPtVirg
+ { P.create_metadec_with_constraints ar ispure kindfn ids }
| ar=arity ispure=pure
kindfn=metakind_atomic_expe
- ids=comma_list(pure_ident_or_meta_ident_with_not_eq(not_ceq)) TMPtVirg
- { P.create_metadec_ne ar ispure kindfn ids }
+ ids=comma_list(pure_ident_or_meta_ident_with_econstraint(not_ceq_or_sub))
+ TMPtVirg
+ { P.create_metadec_with_constraints ar ispure kindfn ids }
| ar=arity TPosition a=option(TPosAny)
- ids=comma_list(pure_ident_or_meta_ident_with_not_eq(not_pos)) TMPtVirg
- { let kindfn arity name pure check_meta constraints =
+ ids=comma_list(pure_ident_or_meta_ident_with_x_eq(not_pos)) TMPtVirg
+ (* pb: position variables can't be inherited from normal rules, and then
+ there is no way to inherit from a generated rule, so there is no point
+ to have a position variable *)
+ { (if !Data.in_generating
+ then failwith "position variables not allowed in a generated rule file");
+ let kindfn arity name pure check_meta constraints =
let tok = check_meta(Ast.MetaPosDecl(arity,name)) in
let any = match a with None -> Ast.PER | Some _ -> Ast.ALL in
!Data.add_pos_meta name constraints any; tok in
- P.create_metadec_ne ar false kindfn ids }
+ P.create_metadec_with_constraints ar false kindfn ids }
+| ar=arity ispure=pure
+ TParameter Tlist TOCro len=list_len TCCro
+ ids=comma_list(pure_ident_or_meta_ident) TMPtVirg
+ { P.create_len_metadec ar ispure
+ (fun lenname arity name pure check_meta ->
+ let tok = check_meta(Ast.MetaParamListDecl(arity,name,lenname)) in
+ !Data.add_paramlist_meta name lenname pure; tok)
+ len ids }
| ar=arity ispure=pure
- TParameter Tlist TOCro id=pure_ident_or_meta_ident TCCro
+ TExpression Tlist TOCro len=list_len TCCro
ids=comma_list(pure_ident_or_meta_ident) TMPtVirg
{ P.create_len_metadec ar ispure
(fun lenname arity name pure check_meta ->
- let tok =
- check_meta(Ast.MetaParamListDecl(arity,name,Some lenname)) in
- !Data.add_paramlist_meta name (Some lenname) pure; tok)
- id ids }
+ let tok = check_meta(Ast.MetaExpListDecl(arity,name,lenname)) in
+ !Data.add_explist_meta name lenname pure; tok)
+ len ids }
| ar=arity ispure=pure
- TExpression Tlist TOCro id=pure_ident_or_meta_ident TCCro
+ TField Tlist TOCro len=list_len TCCro
ids=comma_list(pure_ident_or_meta_ident) TMPtVirg
{ P.create_len_metadec ar ispure
(fun lenname arity name pure check_meta ->
- let tok =
- check_meta(Ast.MetaExpListDecl(arity,name,Some lenname)) in
- !Data.add_explist_meta name (Some lenname) pure; tok)
- id ids }
+ let tok = check_meta(Ast.MetaFieldListDecl(arity,name,lenname)) in
+ !Data.add_field_list_meta name lenname pure; tok)
+ len ids }
-%inline metakind:
+list_len:
+ pure_ident_or_meta_ident { Common.Left $1 }
+| TInt { let (x,clt) = $1 in Common.Right (int_of_string x) }
+
+%inline metakind_fresh:
TFresh TIdentifier
+ { (fun name check_meta seed ->
+ let tok = check_meta(Ast.MetaFreshIdDecl(name,seed)) in
+ !Data.add_fresh_id_meta name; tok) }
+
+/* metavariable kinds with no constraints, etc */
+%inline metakind:
+ TMetavariable
{ (fun arity name pure check_meta ->
- let tok = check_meta(Ast.MetaFreshIdDecl(arity,name)) in
- !Data.add_id_meta name [] pure; tok) }
+ let tok = check_meta(Ast.MetaMetaDecl(arity,name)) in
+ !Data.add_meta_meta name pure; tok) }
| TParameter
{ (fun arity name pure check_meta ->
let tok = check_meta(Ast.MetaParamDecl(arity,name)) in
!Data.add_param_meta name pure; tok) }
| TParameter Tlist
{ (fun arity name pure check_meta ->
- let tok = check_meta(Ast.MetaParamListDecl(arity,name,None)) in
- !Data.add_paramlist_meta name None pure; tok) }
+ let len = Ast.AnyLen in
+ let tok = check_meta(Ast.MetaParamListDecl(arity,name,len)) in
+ !Data.add_paramlist_meta name len pure; tok) }
| TExpression Tlist
{ (fun arity name pure check_meta ->
- let tok = check_meta(Ast.MetaExpListDecl(arity,name,None)) in
- !Data.add_explist_meta name None pure; tok) }
+ let len = Ast.AnyLen in
+ let tok = check_meta(Ast.MetaExpListDecl(arity,name,len)) in
+ !Data.add_explist_meta name len pure; tok) }
| TType
{ (fun arity name pure check_meta ->
let tok = check_meta(Ast.MetaTypeDecl(arity,name)) in
- !Data.add_type_meta name pure; tok) }
+ !Data.add_type_meta name pure; tok) }
+| TInitialiser
+ { (fun arity name pure check_meta ->
+ let tok = check_meta(Ast.MetaInitDecl(arity,name)) in
+ !Data.add_init_meta name pure; tok) }
| TStatement
{ (fun arity name pure check_meta ->
let tok = check_meta(Ast.MetaStmDecl(arity,name)) in
!Data.add_stm_meta name pure; tok) }
+| TDeclaration
+ { (fun arity name pure check_meta ->
+ let tok = check_meta(Ast.MetaDeclDecl(arity,name)) in
+ !Data.add_decl_meta name pure; tok) }
+| TField
+ { (fun arity name pure check_meta ->
+ let tok = check_meta(Ast.MetaFieldDecl(arity,name)) in
+ !Data.add_field_meta name pure; tok) }
+| TField Tlist
+ { (fun arity name pure check_meta ->
+ let len = Ast.AnyLen in
+ let tok = check_meta(Ast.MetaFieldListDecl(arity,name,len)) in
+ !Data.add_field_list_meta name len pure; tok) }
| TStatement Tlist
{ (fun arity name pure check_meta ->
let tok = check_meta(Ast.MetaStmListDecl(arity,name)) in
then (!Data.add_iterator_name name; [])
else raise (Semantic_cocci.Semantic "bad iterator")) }
+%inline metakind_atomic_maybe_virt:
+ TIdentifier
+ {
+ let idfn arity name pure check_meta constraints =
+ let tok = check_meta(Ast.MetaIdDecl(arity,name)) in
+ !Data.add_id_meta name constraints pure; tok in
+ let virtfn arity name pure check_meta virtual_env =
+ try
+ let vl = List.assoc name virtual_env in
+ !Data.add_virt_id_meta_found name vl; []
+ with Not_found ->
+ Iteration.parsed_virtual_identifiers :=
+ Common.union_set [name]
+ !Iteration.parsed_virtual_identifiers;
+ let name = ("virtual",name) in
+ let tok = check_meta(Ast.MetaIdDecl(arity,name)) in
+ !Data.add_virt_id_meta_not_found name pure; tok in
+ (idfn,virtfn) }
%inline metakind_atomic:
- TIdentifier
- { (fun arity name pure check_meta constraints ->
- let tok = check_meta(Ast.MetaIdDecl(arity,name)) in
- !Data.add_id_meta name constraints pure; tok) }
-| TFunction
+ TFunction
{ (fun arity name pure check_meta constraints ->
let tok = check_meta(Ast.MetaFuncDecl(arity,name)) in
!Data.add_func_meta name constraints pure; tok) }
| Some _ ->
!Data.add_local_idexp_meta ty name constraints pure;
check_meta(Ast.MetaLocalIdExpDecl(arity,name,ty))) }
-| TExpression m=nonempty_list(TMul)
- { (fun arity name pure check_meta constraints ->
- let ty = Some [P.ty_pointerify Type_cocci.Unknown m] in
- let tok = check_meta(Ast.MetaExpDecl(arity,name,ty)) in
- !Data.add_exp_meta ty name constraints pure; tok) }
-| vl=meta_exp_type TOCro TCCro
+| TExpression ty=expression_type
{ (fun arity name pure check_meta constraints ->
- let ty = Some (List.map (function x -> Type_cocci.Array x) vl) in
+ let ty = Some [ty] in
let tok = check_meta(Ast.MetaExpDecl(arity,name,ty)) in
!Data.add_exp_meta ty name constraints pure; tok) }
| TConstant ty=ioption(meta_exp_type)
let tok = check_meta(Ast.MetaConstDecl(arity,name,ty)) in
!Data.add_const_meta ty name constraints pure; tok) }
+expression_type:
+ m=nonempty_list(TMul) { P.ty_pointerify Type_cocci.Unknown m }
+| Tenum m=list(TMul)
+ { P.ty_pointerify (Type_cocci.EnumName Type_cocci.NoName) m }
+| Tstruct m=list(TMul)
+ { P.ty_pointerify
+ (Type_cocci.StructUnionName (Type_cocci.Struct,Type_cocci.NoName)) m }
+| Tunion m=list(TMul)
+ { P.ty_pointerify
+ (Type_cocci.StructUnionName (Type_cocci.Union,Type_cocci.NoName)) m }
+
%inline metakind_atomic_expe:
TExpression
{ (fun arity name pure check_meta constraints ->
| vl=meta_exp_type // no error if use $1 but doesn't type check
{ (fun arity name pure check_meta constraints ->
let ty = Some vl in
- List.iter
- (function c ->
- match Ast0.unwrap c with
- Ast0.Constant(_) ->
- if not
- (List.exists
- (function
- Type_cocci.BaseType(Type_cocci.IntType,_) -> true
- | Type_cocci.BaseType(Type_cocci.ShortType,_) -> true
- | Type_cocci.BaseType(Type_cocci.LongType,_) -> true
- | _ -> false)
- vl)
- then failwith "metavariable with int constraint must be an int"
- | _ -> ())
- constraints;
+ (match constraints with
+ Ast0.NotExpCstrt constraints ->
+ List.iter
+ (function c ->
+ match Ast0.unwrap c with
+ Ast0.Constant(_) ->
+ if not
+ (List.exists
+ (function
+ Type_cocci.BaseType(Type_cocci.IntType) -> true
+ | Type_cocci.BaseType(Type_cocci.ShortType) -> true
+ | Type_cocci.BaseType(Type_cocci.LongType) -> true
+ | _ -> false)
+ vl)
+ then
+ failwith "metavariable with int constraint must be an int"
+ | _ -> ())
+ constraints
+ | _ -> ());
let tok = check_meta(Ast.MetaExpDecl(arity,name,ty)) in
- !Data.add_exp_meta ty name constraints pure; tok) }
-
+ !Data.add_exp_meta ty name constraints pure; tok)
+ }
meta_exp_type:
- t=ctype
+ t=typedef_ctype
{ [Ast0_cocci.ast0_type_to_type t] }
+| t=typedef_ctype TOCro TCCro
+ { [Type_cocci.Array (Ast0_cocci.ast0_type_to_type t)] }
| TOBrace t=comma_list(ctype) TCBrace m=list(TMul)
{ List.map
(function x -> P.ty_pointerify (Ast0_cocci.ast0_type_to_type x) m)
| TPlus0 { Ast.MULTI }
| /* empty */ { Ast.NONE }
-generic_ctype:
- q=ctype_qualif
- { Ast0.wrap(Ast0.ImplicitInt(q)) }
- | q=ioption(ctype_qualif) ty=Tchar
- { Ast0.wrap(Ast0.BaseType(P.clt2mcode Ast.CharType ty, q)) }
- | q=ioption(ctype_qualif) ty=Tshort
- { Ast0.wrap(Ast0.BaseType(P.clt2mcode Ast.ShortType ty, q)) }
- | q=ioption(ctype_qualif) ty=Tint
- { Ast0.wrap(Ast0.BaseType(P.clt2mcode Ast.IntType ty, q)) }
- | t=Tdouble
- { Ast0.wrap(Ast0.BaseType(P.clt2mcode Ast.DoubleType t, None)) }
- | t=Tfloat
- { Ast0.wrap(Ast0.BaseType(P.clt2mcode Ast.FloatType t, None)) }
- | q=ioption(ctype_qualif) ty=Tlong
- { Ast0.wrap(Ast0.BaseType(P.clt2mcode Ast.LongType ty, q)) }
- | s=struct_or_union i=ident
- { Ast0.wrap(Ast0.StructUnionName(s, Some i)) }
- | s=struct_or_union i=ioption(ident)
- l=TOBrace d=struct_decl_list r=TCBrace
- { (if i = None && !Data.in_iso
- then failwith "structures must be named in the iso file");
- Ast0.wrap(Ast0.StructUnionDef(Ast0.wrap(Ast0.StructUnionName(s, i)),
- P.clt2mcode "{" l,
- d, P.clt2mcode "}" r)) }
- | s=TMetaType l=TOBrace d=struct_decl_list r=TCBrace
- { let (nm,pure,clt) = s in
- let ty =
- Ast0.wrap(Ast0.MetaType(P.clt2mcode nm clt,pure)) in
- Ast0.wrap
- (Ast0.StructUnionDef(ty,P.clt2mcode "{" l,d,P.clt2mcode "}" r)) }
- | r=TRuleName TDot p=TIdent
- { let nm = (r,P.id2name p) in
- (* this is only possible when we are in a metavar decl. Otherwise,
- it will be represented already as a MetaType *)
- let _ = P.check_meta(Ast.MetaTypeDecl(Ast.NONE,nm)) in
- Ast0.wrap(Ast0.MetaType(P.clt2mcode nm (P.id2clt p),
- Ast0.Impure (*will be ignored*))) }
- | p=TTypeId
- { Ast0.wrap(Ast0.TypeName(P.id2mcode p)) }
- | p=TMetaType
- { let (nm,pure,clt) = p in
- Ast0.wrap(Ast0.MetaType(P.clt2mcode nm clt,pure)) }
+/* ---------------------------------------------------------------------- */
+
+%inline
+signable_types:
+ ty=Tchar
+ { Ast0.wrap(Ast0.BaseType(Ast.CharType,[P.clt2mcode "char" ty])) }
+| ty=Tshort
+ { Ast0.wrap(Ast0.BaseType(Ast.ShortType,[P.clt2mcode "short" ty])) }
+| ty=Tint
+ { Ast0.wrap(Ast0.BaseType(Ast.IntType,[P.clt2mcode "int" ty])) }
+| p=TMetaType
+ { let (nm,pure,clt) = p in
+ Ast0.wrap(Ast0.MetaType(P.clt2mcode nm clt,pure)) }
+| r=TRuleName TDot p=TIdent
+ { let nm = (r,P.id2name p) in
+ (* this is only possible when we are in a metavar decl. Otherwise,
+ it will be represented already as a MetaType *)
+ let _ = P.check_meta(Ast.MetaTypeDecl(Ast.NONE,nm)) in
+ Ast0.wrap(Ast0.MetaType(P.clt2mcode nm (P.id2clt p),
+ Ast0.Impure (*will be ignored*))) }
+| ty=Tlong
+ { Ast0.wrap(Ast0.BaseType(Ast.LongType,[P.clt2mcode "long" ty])) }
+| ty1=Tlong ty2=Tlong
+ { Ast0.wrap
+ (Ast0.BaseType
+ (Ast.LongLongType,
+ [P.clt2mcode "long" ty1;P.clt2mcode "long" ty2])) }
+
+%inline
+non_signable_types:
+ ty=Tvoid
+ { Ast0.wrap(Ast0.BaseType(Ast.VoidType,[P.clt2mcode "void" ty])) }
+| ty=Tdouble
+ { Ast0.wrap(Ast0.BaseType(Ast.DoubleType,[P.clt2mcode "double" ty])) }
+| ty=Tfloat
+ { Ast0.wrap(Ast0.BaseType(Ast.FloatType,[P.clt2mcode "float" ty])) }
+| ty=Tsize_t
+ { Ast0.wrap(Ast0.BaseType(Ast.SizeType,[P.clt2mcode "size_t" ty])) }
+| ty=Tssize_t
+ { Ast0.wrap(Ast0.BaseType(Ast.SSizeType,[P.clt2mcode "ssize_t" ty])) }
+| ty=Tptrdiff_t
+ { Ast0.wrap(Ast0.BaseType(Ast.PtrDiffType,[P.clt2mcode "ptrdiff_t" ty])) }
+| s=Tenum i=ident
+ { Ast0.wrap(Ast0.EnumName(P.clt2mcode "enum" s, Some i)) }
+| s=Tenum i=ioption(ident) l=TOBrace ids=enum_decl_list r=TCBrace
+ { (if i = None && !Data.in_iso
+ then failwith "enums must be named in the iso file");
+ Ast0.wrap(Ast0.EnumDef(Ast0.wrap(Ast0.EnumName(P.clt2mcode "enum" s, i)),
+ P.clt2mcode "{" l, ids, P.clt2mcode "}" r)) }
+| s=struct_or_union i=type_ident // allow typedef name
+ { Ast0.wrap(Ast0.StructUnionName(s, Some i)) }
+| s=struct_or_union i=ioption(type_ident)
+ l=TOBrace d=struct_decl_list r=TCBrace
+ { (if i = None && !Data.in_iso
+ then failwith "structures must be named in the iso file");
+ Ast0.wrap(Ast0.StructUnionDef(Ast0.wrap(Ast0.StructUnionName(s, i)),
+ P.clt2mcode "{" l,
+ d, P.clt2mcode "}" r)) }
+| s=TMetaType l=TOBrace d=struct_decl_list r=TCBrace
+ { let (nm,pure,clt) = s in
+ let ty = Ast0.wrap(Ast0.MetaType(P.clt2mcode nm clt,pure)) in
+ Ast0.wrap(Ast0.StructUnionDef(ty,P.clt2mcode "{" l,d,P.clt2mcode "}" r)) }
+| p=TTypeId
+ { Ast0.wrap(Ast0.TypeName(P.id2mcode p)) }
+
+%inline
+all_basic_types:
+ r=Tsigned ty=signable_types
+ { Ast0.wrap(Ast0.Signed(P.clt2mcode Ast.Signed r,Some ty)) }
+| r=Tunsigned ty=signable_types
+ { Ast0.wrap(Ast0.Signed(P.clt2mcode Ast.Unsigned r,Some ty)) }
+| ty=signable_types { ty }
+| ty=non_signable_types { ty }
+
+ctype:
+ cv=ioption(const_vol) ty=all_basic_types m=list(TMul)
+ { P.pointerify (P.make_cv cv ty) m }
+| r=Tsigned
+ { Ast0.wrap(Ast0.Signed(P.clt2mcode Ast.Signed r,None)) }
+| r=Tunsigned
+ { Ast0.wrap(Ast0.Signed(P.clt2mcode Ast.Unsigned r,None)) }
+| lp=TOPar0 t=midzero_list(ctype,ctype) rp=TCPar0
+ { let (mids,code) = t in
+ Ast0.wrap
+ (Ast0.DisjType(P.clt2mcode "(" lp,code,mids, P.clt2mcode ")" rp)) }
+
+mctype:
+| TMeta { tmeta_to_type $1 }
+| ctype {$1}
+
+/* signed, unsigned alone not allowed */
+typedef_ctype:
+ cv=ioption(const_vol) ty=all_basic_types m=list(TMul)
+ { P.pointerify (P.make_cv cv ty) m }
+| lp=TOPar0 t=midzero_list(mctype,mctype) rp=TCPar0
+ { let (mids,code) = t in
+ Ast0.wrap
+ (Ast0.DisjType(P.clt2mcode "(" lp,code,mids, P.clt2mcode ")" rp)) }
+| TMeta { tmeta_to_type $1 }
+
+/* ---------------------------------------------------------------------- */
struct_or_union:
s=Tstruct { P.clt2mcode Ast.Struct s }
| u=Tunion { P.clt2mcode Ast.Union u }
struct_decl:
- TNothing { [] }
+ TNothing { [] }
+ | struct_decl_one { [$1] }
+
+struct_decl_one:
+ | TMetaField { P.meta_field $1 }
+ | TMetaFieldList { P.meta_field_list $1 }
+ | TMeta { tmeta_to_field $1 }
| t=ctype d=d_ident pv=TPtVirg
{ let (id,fn) = d in
- [Ast0.wrap(Ast0.UnInit(None,fn t,id,P.clt2mcode ";" pv))] }
- | t=fn_ctype lp1=TOPar st=TMul d=d_ident rp1=TCPar
+ Ast0.wrap(Ast0.UnInit(None,fn t,id,P.clt2mcode ";" pv)) }
+ | t=ctype lp1=TOPar st=TMul d=d_ident rp1=TCPar
lp2=TOPar p=decl_list(name_opt_decl) rp2=TCPar pv=TPtVirg
{ let (id,fn) = d in
let t =
(Ast0.FunctionPointer
(t,P.clt2mcode "(" lp1,P.clt2mcode "*" st,P.clt2mcode ")" rp1,
P.clt2mcode "(" lp2,p,P.clt2mcode ")" rp2)) in
- [Ast0.wrap(Ast0.UnInit(None,fn t,id,P.clt2mcode ";" pv))] }
+ Ast0.wrap(Ast0.UnInit(None,fn t,id,P.clt2mcode ";" pv)) }
| cv=ioption(const_vol) i=pure_ident d=d_ident pv=TPtVirg
{ let (id,fn) = d in
let idtype = P.make_cv cv (Ast0.wrap (Ast0.TypeName(P.id2mcode i))) in
- [Ast0.wrap(Ast0.UnInit(None,fn idtype,id,P.clt2mcode ";" pv))] }
+ Ast0.wrap(Ast0.UnInit(None,fn idtype,id,P.clt2mcode ";" pv)) }
struct_decl_list:
struct_decl_list_start { Ast0.wrap(Ast0.DOTS($1)) }
struct_decl_list_start:
struct_decl { $1 }
| struct_decl struct_decl_list_start { $1@$2 }
-| d=edots_when(TEllipsis,struct_decl) r=continue_struct_decl_list
- { (P.mkddots "..." d)::r }
+| d=edots_when(TEllipsis,struct_decl_one) r=continue_struct_decl_list
+ { (P.mkddots_one "..." d)::r }
continue_struct_decl_list:
/* empty */ { [] }
| struct_decl struct_decl_list_start { $1@$2 }
| struct_decl { $1 }
-ctype:
- cv=ioption(const_vol) ty=generic_ctype m=list(TMul)
- { P.pointerify (P.make_cv cv ty) m }
- | cv=ioption(const_vol) t=Tvoid m=nonempty_list(TMul)
- { let ty =
- Ast0.wrap(Ast0.BaseType(P.clt2mcode Ast.VoidType t, None)) in
- P.pointerify (P.make_cv cv ty) m }
- | lp=TOPar0 t=midzero_list(ctype,ctype) rp=TCPar0
- /* more hacks */
- { let (mids,code) = t in
- Ast0.wrap
- (Ast0.DisjType(P.clt2mcode "(" lp,code,mids, P.clt2mcode ")" rp)) }
+/* ---------------------------------------------------------------------- */
+/* very restricted what kinds of expressions can appear in an enum decl */
+
+enum_decl_one:
+ | disj_ident { Ast0.wrap(Ast0.Ident($1)) }
+ | disj_ident TEq enum_val
+ { let id = Ast0.wrap(Ast0.Ident($1)) in
+ Ast0.wrap
+ (Ast0.Assignment
+ (id,P.clt2mcode Ast.SimpleAssign $2,Ast0.set_arg_exp $3,
+ false)) }
-fn_ctype: // allows metavariables
- ty=generic_ctype m=list(TMul) { P.pointerify ty m }
- | t=Tvoid m=list(TMul)
- { P.pointerify
- (Ast0.wrap(Ast0.BaseType(P.clt2mcode Ast.VoidType t, None)))
- m }
+enum_val:
+ ident { Ast0.wrap(Ast0.Ident($1)) }
+ | TInt
+ { let (x,clt) = $1 in
+ Ast0.wrap(Ast0.Constant (P.clt2mcode (Ast.Int x) clt)) }
+ | TMeta { tmeta_to_exp $1 }
+ | TMetaConst
+ { let (nm,constraints,pure,ty,clt) = $1 in
+ Ast0.wrap
+ (Ast0.MetaExpr(P.clt2mcode nm clt,constraints,ty,Ast.CONST,pure)) }
+ | TMetaExp
+ { let (nm,constraints,pure,ty,clt) = $1 in
+ Ast0.wrap
+ (Ast0.MetaExpr(P.clt2mcode nm clt,constraints,ty,Ast.ANY,pure)) }
+ | TMetaIdExp
+ { let (nm,constraints,pure,ty,clt) = $1 in
+ Ast0.wrap
+ (Ast0.MetaExpr(P.clt2mcode nm clt,constraints,ty,Ast.ID,pure)) }
-ctype_qualif:
- Tunsigned { P.clt2mcode Ast.Unsigned $1 }
- | Tsigned { P.clt2mcode Ast.Signed $1 }
+enum_decl_list:
+ nonempty_list_start(enum_decl_one,edots_when(TEllipsis,enum_decl_one))
+ { Ast0.wrap(Ast0.DOTS($1 P.mkedots (fun c -> Ast0.EComma c))) }
/*****************************************************************************/
/* have to inline everything to avoid conflicts? switch to proper
declarations, statements, and expressions for the subterms */
-minus_body:
+minus_body:
f=loption(filespec)
b=loption(minus_start)
- ew=loption(error_words)
- { match f@b@ew with
+ /*ew=loption(error_words)*/
+ { match f@b(*@ew*) with
[] -> raise (Semantic_cocci.Semantic "minus slice can't be empty")
| code -> Top_level.top_level code }
-plus_body:
+plus_body:
f=loption(filespec)
b=loption(plus_start)
- ew=loption(error_words)
- { Top_level.top_level (f@b@ew) }
+ /*ew=loption(error_words)*/
+ { Top_level.top_level (f@b(*@ew*)) }
minus_exp_body:
f=loption(filespec)
b=top_eexpr
- ew=loption(error_words)
- { match f@[b]@ew with
+ /*ew=loption(error_words)*/
+ { match f@[b](*@ew*) with
[] -> raise (Semantic_cocci.Semantic "minus slice can't be empty")
| code -> Top_level.top_level code }
plus_exp_body:
f=loption(filespec)
b=top_eexpr
- ew=loption(error_words)
- { Top_level.top_level (f@[b]@ew) }
+ /*ew=loption(error_words)*/
+ { Top_level.top_level (f@[b](*@ew*)) }
filespec:
TMinusFile TPlusFile
includes:
TIncludeL
{ Ast0.wrap
- (Ast0.Include(P.clt2mcode "#include" (P.drop_aft (P.id2clt $1)),
+ (Ast0.Include(P.clt2mcode "#include"
+ (P.drop_pos (P.drop_aft (P.id2clt $1))),
let (arity,ln,lln,offset,col,strbef,straft,pos) =
P.id2clt $1 in
let clt =
(P.drop_bef clt))) }
| TIncludeNL
{ Ast0.wrap
- (Ast0.Include(P.clt2mcode "#include" (P.drop_aft (P.id2clt $1)),
+ (Ast0.Include(P.clt2mcode "#include"
+ (P.drop_pos (P.drop_aft (P.id2clt $1))),
let (arity,ln,lln,offset,col,strbef,straft,pos) =
P.id2clt $1 in
let clt =
P.clt2mcode
(Ast.NonLocal (Parse_aux.str2inc (P.id2name $1)))
(P.drop_bef clt))) }
+| TUndef TLineEnd
+ { let (clt,ident) = $1 in
+ Ast0.wrap
+ (Ast0.Undef
+ (P.clt2mcode "#undef" clt,
+ (match ident with
+ TMetaId((nm,constraints,pure,clt)) ->
+ Ast0.wrap(Ast0.MetaId(P.clt2mcode nm clt,constraints,pure))
+ | TIdent(nm_pure) ->
+ Ast0.wrap(Ast0.Id(P.id2mcode nm_pure))
+ | _ ->
+ raise
+ (Semantic_cocci.Semantic
+ "unexpected name for a #define")))) }
+| d=defineop TLineEnd
+ { d (Ast0.wrap(Ast0.DOTS([]))) }
| d=defineop t=ctype TLineEnd
{ let ty = Ast0.wrap(Ast0.TopExp(Ast0.wrap(Ast0.TypeExp(t)))) in
d (Ast0.wrap(Ast0.DOTS([ty]))) }
Ast0.wrap Ast0.NoParams,
body)) }
| TDefineParam define_param_list_option TCPar
- { let (clt,ident,parenoff) = $1 in
+ { let (clt,ident,parenoff,parencol) = $1 in
+ (* clt is the start of the #define itself *)
let (arity,line,lline,offset,col,strbef,straft,pos) = clt in
let lp =
- P.clt2mcode "(" (arity,line,lline,parenoff,0,[],[],Ast0.NoMetaPos) in
+ P.clt2mcode "("
+ (arity,line,lline,parenoff,parencol,[],[],Ast0.NoMetaPos) in
function body ->
Ast0.wrap
(Ast0.Define
/* ---------------------------------------------------------------------- */
-define_param_list: define_param_list_start
- {let circle x =
- match Ast0.unwrap x with Ast0.DPcircles(_) -> true | _ -> false in
- if List.exists circle $1
- then Ast0.wrap(Ast0.CIRCLES($1))
- else Ast0.wrap(Ast0.DOTS($1)) }
-
-define_param_list_start:
- ident { [Ast0.wrap(Ast0.DParam $1)] }
- | ident TComma define_param_list_start
- { Ast0.wrap(Ast0.DParam $1)::
- Ast0.wrap(Ast0.DPComma(P.clt2mcode "," $2))::$3 }
- | d=TEllipsis r=list(dp_comma_args(TEllipsis))
- { (P.mkdpdots "..." d)::
- (List.concat (List.map (function x -> x (P.mkdpdots "...")) r)) }
-
-dp_comma_args(dotter):
- c=TComma d=dotter
- { function dot_builder ->
- [Ast0.wrap(Ast0.DPComma(P.clt2mcode "," c)); dot_builder d] }
-| TComma ident
- { function dot_builder ->
- [Ast0.wrap(Ast0.DPComma(P.clt2mcode "," $1));
- Ast0.wrap(Ast0.DParam $2)] }
-
-define_param_list_option: define_param_list { $1 }
- | /* empty */ { Ast0.wrap(Ast0.DOTS([])) }
+dparam: mident { Ast0.wrap(Ast0.DParam $1) }
+
+define_param_list_option:
+ empty_list_start(dparam,TEllipsis)
+ { Ast0.wrap
+ (Ast0.DOTS
+ ($1
+ (fun _ d -> Ast0.wrap(Ast0.DPdots(P.clt2mcode "," d)))
+ (fun c -> Ast0.DPComma c))) }
/*****************************************************************************/
funproto:
s=ioption(storage) t=ctype
- id=func_ident lp=TOPar d=decl_list(name_opt_decl) rp=TCPar pt=TPtVirg
+ id=fn_ident lp=TOPar d=decl_list(name_opt_decl) rp=TCPar pt=TPtVirg
{ Ast0.wrap
(Ast0.UnInit
(s,
(Ast0.FunctionType(Some t,
P.clt2mcode "(" lp, d, P.clt2mcode ")" rp)),
id, P.clt2mcode ";" pt)) }
-| s=ioption(storage) t=Tvoid
- id=func_ident lp=TOPar d=decl_list(name_opt_decl) rp=TCPar pt=TPtVirg
- { let t = Ast0.wrap(Ast0.BaseType(P.clt2mcode Ast.VoidType t, None)) in
- Ast0.wrap
- (Ast0.UnInit
- (s,
- Ast0.wrap
- (Ast0.FunctionType(Some t,
- P.clt2mcode "(" lp, d, P.clt2mcode ")" rp)),
- id, P.clt2mcode ";" pt)) }
-
fundecl:
f=fninfo
- TFunDecl i=func_ident lp=TOPar d=decl_list(decl) rp=TCPar
+ TFunDecl i=fn_ident lp=TOPar d=decl_list(decl) rp=TCPar
lb=TOBrace b=fun_start rb=TCBrace
- { Ast0.wrap(Ast0.FunDecl((Ast0.default_info(),Ast0.context_befaft()),
+ { P.verify_parameter_declarations (Ast0.undots d);
+ Ast0.wrap(Ast0.FunDecl((Ast0.default_info(),Ast0.context_befaft()),
f, i,
P.clt2mcode "(" lp, d,
P.clt2mcode ")" rp,
List.find (function Ast0.FStorage(_) -> true | _ -> false) $2 in
raise (Semantic_cocci.Semantic "duplicate storage")
with Not_found -> (Ast0.FStorage($1))::$2 }
- | t=fn_ctype r=fninfo_nt { (Ast0.FType(t))::r }
+ | t=ctype r=fninfo_nt { (Ast0.FType(t))::r }
| Tinline fninfo
{ try
let _ = List.find (function Ast0.FInline(_) -> true | _ -> false) $2 in
| s=Tregister { P.clt2mcode Ast.Register s }
| s=Textern { P.clt2mcode Ast.Extern s }
-decl: t=ctype i=ident
- { Ast0.wrap(Ast0.Param(t, Some i)) }
- | t=fn_ctype lp=TOPar s=TMul i=ident rp=TCPar
+decl: t=ctype i=disj_ident a=list(array_dec)
+ { let t = P.arrayify t a in Ast0.wrap(Ast0.Param(t, Some i)) }
+ | t=ctype { (*verify in FunDecl*) Ast0.wrap(Ast0.Param(t, None)) }
+ | t=ctype lp=TOPar s=TMul i=disj_ident rp=TCPar
lp1=TOPar d=decl_list(name_opt_decl) rp1=TCPar
{ let fnptr =
Ast0.wrap
(t,P.clt2mcode "(" lp,P.clt2mcode "*" s,P.clt2mcode ")" rp,
P.clt2mcode "(" lp1,d,P.clt2mcode ")" rp1)) in
Ast0.wrap(Ast0.Param(fnptr, Some i)) }
- | t=Tvoid
- { let ty = Ast0.wrap(Ast0.BaseType(P.clt2mcode Ast.VoidType t, None)) in
- Ast0.wrap(Ast0.VoidParam(ty)) }
| TMetaParam
{ let (nm,pure,clt) = $1 in
Ast0.wrap(Ast0.MetaParam(P.clt2mcode nm clt,pure)) }
+ | TMeta { tmeta_to_param $1 }
name_opt_decl:
decl { $1 }
- | t=ctype { Ast0.wrap(Ast0.Param(t, None)) }
- | t=fn_ctype lp=TOPar s=TMul rp=TCPar
+ | t=ctype lp=TOPar s=TMul rp=TCPar
lp1=TOPar d=decl_list(name_opt_decl) rp1=TCPar
{ let fnptr =
Ast0.wrap
statement:
includes { $1 } /* shouldn't be allowed to be a single_statement... */
+| TMeta { tmeta_to_statement $1}
| TMetaStm
{ P.meta_stm $1 }
| expr TPtVirg
{ P.doloop $1 $2 $3 $4 $5 $6 $7 }
| iter_ident TOPar eexpr_list_option TCPar single_statement
{ P.iterator $1 $2 $3 $4 $5 }
-| TSwitch TOPar eexpr TCPar TOBrace list(case_line) TCBrace
- { P.switch $1 $2 $3 $4 $5 $6 $7 }
+| TSwitch TOPar eexpr TCPar TOBrace list(decl_var) list(case_line) TCBrace
+ { P.switch $1 $2 $3 $4 $5 (List.concat $6) $7 $8 }
| TReturn eexpr TPtVirg { P.ret_exp $1 $2 $3 }
| TReturn TPtVirg { P.ret $1 $2 }
| TBreak TPtVirg { P.break $1 $2 }
| TContinue TPtVirg { P.cont $1 $2 }
-| ident TDotDot { P.label $1 $2 }
-| TGoto ident TPtVirg { P.goto $1 $2 $3 }
+| mident TDotDot { P.label $1 $2 }
+| TGoto disj_ident TPtVirg { P.goto $1 $2 $3 }
| TOBrace fun_start TCBrace
{ P.seq $1 $2 $3 }
{ Ast0.wrap(Ast0.Nest(P.clt2mcode "<+..." $1, b,
P.clt2mcode "...+>" c, List.concat w, true)) }
-whenppdecs: w=whens(when_start,rule_elem_statement)
+%inline stm_dots_ell:
+ a=TEllipsis w=list(whenppdecs)
+ { Ast0.wrap(Ast0.Dots(P.clt2mcode "..." a, List.concat w)) }
+
+%inline stm_dots_nest:
+ a=TOEllipsis w=list(whenppdecs) b=nest_start c=TCEllipsis
+ { Ast0.wrap(Ast0.Nest(P.clt2mcode "<..." a, b,
+ P.clt2mcode "...>" c, List.concat w, false)) }
+| a=TPOEllipsis w=list(whenppdecs) b=nest_start c=TPCEllipsis
+ { Ast0.wrap(Ast0.Nest(P.clt2mcode "<+..." a, b,
+ P.clt2mcode "...+>" c, List.concat w, true)) }
+
+whenppdecs: w=whens(when_start,rule_elem_statement,any_strict)
{ w }
/* a statement that fits into a single rule_elem. should nests be included?
case_line:
TDefault TDotDot fun_start
- { Ast0.wrap(Ast0.Default(P.clt2mcode "default" $1,P.clt2mcode ":" $2,$3)) }
+ { Ast0.wrap
+ (Ast0.Default(P.clt2mcode "default" $1,P.clt2mcode ":" $2,$3)) }
| TCase eexpr TDotDot fun_start
{ Ast0.wrap(Ast0.Case(P.clt2mcode "case" $1,$2,P.clt2mcode ":" $3,$4)) }
+/* | lp=TOPar0 t=midzero_list(case_line,case_line) rp=TCPar0
+ { let (mids,code) = ([],[t]) in
+ Ast0.wrap
+ (Ast0.DisjCase(P.clt2mcode "(" lp,code,mids, P.clt2mcode ")" rp)) } */
/* In the following, an identifier as a type is not fully supported. Indeed,
the language is ambiguous: what is foo * bar; */
decl_var:
t=ctype pv=TPtVirg
{ [Ast0.wrap(Ast0.TyDecl(t,P.clt2mcode ";" pv))] }
+ | TMetaDecl { [P.meta_decl $1] }
| s=ioption(storage) t=ctype d=comma_list(d_ident) pv=TPtVirg
{ List.map
(function (id,fn) ->
P.clt2mcode ";" pv))] }
/* function pointer type */
| s=ioption(storage)
- t=fn_ctype lp1=TOPar st=TMul d=d_ident rp1=TCPar
+ t=ctype lp1=TOPar st=TMul d=d_ident rp1=TCPar
lp2=TOPar p=decl_list(name_opt_decl) rp2=TCPar
pv=TPtVirg
{ let (id,fn) = d in
[Ast0.wrap(Ast0.UnInit(s,fn t,id,P.clt2mcode ";" pv))] }
| decl_ident TOPar eexpr_list_option TCPar TPtVirg
{ [Ast0.wrap(Ast0.MacroDecl($1,P.clt2mcode "(" $2,$3,
- P.clt2mcode ")" $4,P.clt2mcode ";" $5))] }
+ P.clt2mcode ")" $4,P.clt2mcode ";" $5))] }
| s=ioption(storage)
- t=fn_ctype lp1=TOPar st=TMul d=d_ident rp1=TCPar
+ t=ctype lp1=TOPar st=TMul d=d_ident rp1=TCPar
lp2=TOPar p=decl_list(name_opt_decl) rp2=TCPar
q=TEq e=initialize pv=TPtVirg
{ let (id,fn) = d in
(t,P.clt2mcode "(" lp1,P.clt2mcode "*" st,P.clt2mcode ")" rp1,
P.clt2mcode "(" lp2,p,P.clt2mcode ")" rp2)) in
[Ast0.wrap(Ast0.Init(s,fn t,id,P.clt2mcode "=" q,e,P.clt2mcode ";" pv))]}
- | s=Ttypedef t=ctype id=typedef_ident pv=TPtVirg
+ | s=Ttypedef t=typedef_ctype id=comma_list(typedef_ident) pv=TPtVirg
{ let s = P.clt2mcode "typedef" s in
- [Ast0.wrap(Ast0.Typedef(s,t,id,P.clt2mcode ";" pv))] }
+ List.map
+ (function id ->
+ Ast0.wrap(Ast0.Typedef(s,t,id,P.clt2mcode ";" pv)))
+ id }
one_decl_var:
t=ctype pv=TPtVirg
{ Ast0.wrap(Ast0.TyDecl(t,P.clt2mcode ";" pv)) }
+ | TMetaDecl { P.meta_decl $1 }
| s=ioption(storage) t=ctype d=d_ident pv=TPtVirg
{ let (id,fn) = d in
Ast0.wrap(Ast0.UnInit(s,fn t,id,P.clt2mcode ";" pv)) }
P.clt2mcode ";" pv)) }
/* function pointer type */
| s=ioption(storage)
- t=fn_ctype lp1=TOPar st=TMul d=d_ident rp1=TCPar
+ t=ctype lp1=TOPar st=TMul d=d_ident rp1=TCPar
lp2=TOPar p=decl_list(name_opt_decl) rp2=TCPar
pv=TPtVirg
{ let (id,fn) = d in
Ast0.wrap(Ast0.UnInit(s,fn t,id,P.clt2mcode ";" pv)) }
| decl_ident TOPar eexpr_list_option TCPar TPtVirg
{ Ast0.wrap(Ast0.MacroDecl($1,P.clt2mcode "(" $2,$3,
- P.clt2mcode ")" $4,P.clt2mcode ";" $5)) }
+ P.clt2mcode ")" $4,P.clt2mcode ";" $5)) }
| s=ioption(storage)
- t=fn_ctype lp1=TOPar st=TMul d=d_ident rp1=TCPar
+ t=ctype lp1=TOPar st=TMul d=d_ident rp1=TCPar
lp2=TOPar p=decl_list(name_opt_decl) rp2=TCPar
q=TEq e=initialize pv=TPtVirg
{ let (id,fn) = d in
d_ident:
- ident list(array_dec)
- { ($1,
- function t ->
- List.fold_right
- (function (l,i,r) ->
- function rest ->
- Ast0.wrap
- (Ast0.Array(rest,P.clt2mcode "[" l,i,P.clt2mcode "]" r)))
- $2 t) }
+ disj_ident list(array_dec)
+ { ($1, function t -> P.arrayify t $2) }
array_dec: l=TOCro i=option(eexpr) r=TCCro { (l,i,r) }
eexpr
{ Ast0.wrap(Ast0.InitExpr($1)) }
| TOBrace initialize_list TCBrace
- { Ast0.wrap(Ast0.InitList(P.clt2mcode "{" $1,$2,P.clt2mcode "}" $3)) }
- | TOBrace TCBrace
- { Ast0.wrap
- (Ast0.InitList(P.clt2mcode "{" $1,Ast0.wrap(Ast0.DOTS []),
- P.clt2mcode "}" $2)) }
+ { if P.struct_initializer $2
+ then
+ let il = P.drop_dot_commas $2 in
+ Ast0.wrap(Ast0.InitList(P.clt2mcode "{" $1,il,P.clt2mcode "}" $3,false))
+ else
+ Ast0.wrap(Ast0.InitList(P.clt2mcode "{" $1,$2,P.clt2mcode "}" $3,true)) }
+ | TMetaInit
+ {let (nm,pure,clt) = $1 in
+ Ast0.wrap(Ast0.MetaInit(P.clt2mcode nm clt,pure)) }
initialize2:
/*arithexpr and not eexpr because can have ambiguity with comma*/
/*dots and nests probably not allowed at top level, haven't looked into why*/
arith_expr(eexpr,invalid) { Ast0.wrap(Ast0.InitExpr($1)) }
| TOBrace initialize_list TCBrace
- { Ast0.wrap(Ast0.InitList(P.clt2mcode "{" $1,$2,P.clt2mcode "}" $3)) }
-| TOBrace TCBrace
- { Ast0.wrap
- (Ast0.InitList(P.clt2mcode "{" $1,Ast0.wrap(Ast0.DOTS []),
- P.clt2mcode "}" $2)) }
+ { if P.struct_initializer $2
+ then
+ let il = P.drop_dot_commas $2 in
+ Ast0.wrap(Ast0.InitList(P.clt2mcode "{" $1,il,P.clt2mcode "}" $3,false))
+ else
+ Ast0.wrap(Ast0.InitList(P.clt2mcode "{" $1,$2,P.clt2mcode "}" $3,true)) }
/* gccext:, labeled elements */
-| TDot ident TEq initialize2
- { Ast0.wrap(Ast0.InitGccDotName(P.clt2mcode "." $1,$2,P.clt2mcode "=" $3,$4)) }
-| ident TDotDot initialize2
+| list(designator) TEq initialize2 /*can we have another of these on the rhs?*/
+ { Ast0.wrap(Ast0.InitGccExt($1,P.clt2mcode "=" $2,$3)) }
+| mident TDotDot initialize2
{ Ast0.wrap(Ast0.InitGccName($1,P.clt2mcode ":" $2,$3)) } /* in old kernel */
-| TOCro eexpr TCCro TEq initialize2
- { Ast0.wrap(Ast0.InitGccIndex(P.clt2mcode "[" $1,$2,P.clt2mcode "]" $3,
- P.clt2mcode "=" $4,$5)) }
-| TOCro eexpr TEllipsis eexpr TCCro TEq initialize2
- { Ast0.wrap(Ast0.InitGccRange(P.clt2mcode "[" $1,$2,P.clt2mcode "..." $3,
- $4,P.clt2mcode "]" $5,P.clt2mcode "=" $6,$7)) }
+
+designator:
+ | TDot disj_ident
+ { Ast0.DesignatorField (P.clt2mcode "." $1,$2) }
+ | TOCro eexpr TCCro
+ { Ast0.DesignatorIndex (P.clt2mcode "[" $1,$2,P.clt2mcode "]" $3) }
+ | TOCro eexpr TEllipsis eexpr TCCro
+ { Ast0.DesignatorRange (P.clt2mcode "[" $1,$2,P.clt2mcode "..." $3,
+ $4,P.clt2mcode "]" $5) }
initialize_list:
- initialize_list_start { Ast0.wrap(Ast0.DOTS($1)) }
-
-initialize_list_start:
- initialize2 TComma { [$1;Ast0.wrap(Ast0.IComma(P.clt2mcode "," $2))] }
-| initialize2 TComma initialize_list_start
- { $1::Ast0.wrap(Ast0.IComma(P.clt2mcode "," $2))::$3 }
-| d=edots_when(TEllipsis,initialize)
- r=comma_initializers(edots_when(TEllipsis,initialize))
- { (P.mkidots "..." d)::
- (List.concat(List.map (function x -> x (P.mkidots "...")) r)) }
-
-comma_initializers(dotter):
- /* empty */ { [] }
-| d=dotter r=comma_initializers2(dotter)
- { (function dot_builder -> [dot_builder d])::r }
-| i=initialize2 c=TComma r=comma_initializers(dotter)
- { (function dot_builder -> [i; Ast0.wrap(Ast0.IComma(P.clt2mcode "," c))])::
- r }
-
-comma_initializers2(dotter):
- /* empty */ { [] }
-| i=initialize2 c=TComma r=comma_initializers(dotter)
- { (function dot_builder -> [i; Ast0.wrap(Ast0.IComma(P.clt2mcode "," c))])::
- r }
+ empty_list_start(initialize2,edots_when(TEllipsis,initialize))
+ { Ast0.wrap(Ast0.DOTS($1 P.mkidots (fun c -> Ast0.IComma c))) }
/* a statement that is part of a list */
decl_statement:
/*****************************************************************************/
-/* The following cannot contain <... ...> at the top level. This can only
-be allowed as an expression when the expression is delimited on both sides
-by expression-specific markers. In that case, the rule eexpr is used, which
+/* expr cannot contain <... ...> at the top level. This can only
+be allowed as an expression when the expression is delimited on the left
+by an expression-specific marker. In that case, the rule eexpr is used, which
allows <... ...> anywhere. Hopefully, this will not be too much of a problem
-in practice. */
+in practice.
+dot_expressions is the most permissive. all three kinds of expressions use
+this once an expression_specific token has been seen */
expr: basic_expr(expr,invalid) { $1 }
/* allows ... and nests */
eexpr: basic_expr(eexpr,dot_expressions) { $1 }
TEllipsis { Ast0.wrap(Ast0.Edots(P.clt2mcode "..." $1,None)) }
| nest_expressions { $1 }
+/* not clear what whencode would mean, so just drop it */
nest_expressions:
- TOEllipsis w=option(whenexp) e=expr_dots(TEllipsis) c=TCEllipsis
+ TOEllipsis e=expr_dots(TEllipsis) c=TCEllipsis
{ Ast0.wrap(Ast0.NestExpr(P.clt2mcode "<..." $1,
Ast0.wrap(Ast0.DOTS(e (P.mkedots "..."))),
- P.clt2mcode "...>" c, w, false)) }
-| TPOEllipsis w=option(whenexp) e=expr_dots(TEllipsis) c=TPCEllipsis
+ P.clt2mcode "...>" c, None, false)) }
+| TPOEllipsis e=expr_dots(TEllipsis) c=TPCEllipsis
{ Ast0.wrap(Ast0.NestExpr(P.clt2mcode "<+..." $1,
Ast0.wrap(Ast0.DOTS(e (P.mkedots "..."))),
- P.clt2mcode "...+>" c, w, true)) }
+ P.clt2mcode "...+>" c, None, true)) }
+| TMeta { tmeta_to_exp $1 }
-whenexp: TWhen TNotEq w=eexpr TLineEnd { w }
+//whenexp: TWhen TNotEq w=eexpr TLineEnd { w }
basic_expr(recurser,primary_extra):
- assign_expr(recurser,primary_extra) { $1 }
+ assign_expr(recurser,primary_extra) { $1 }
assign_expr(r,pe):
cond_expr(r,pe) { $1 }
cond_expr(r,pe):
arith_expr(r,pe) { $1 }
- | l=arith_expr(r,pe) w=TWhy t=option(eexpr) dd=TDotDot r=cond_expr(r,pe)
+ | l=arith_expr(r,pe) w=TWhy t=option(eexpr) dd=TDotDot r=eexpr/*see parser_c*/
{ Ast0.wrap(Ast0.CondExpr (l, P.clt2mcode "?" w, t,
P.clt2mcode ":" dd, r)) }
arith_expr(r,pe):
cast_expr(r,pe) { $1 }
- | arith_expr(r,pe) TMul arith_expr(r,pe)
+ | arith_expr(r,pe) TMul arith_expr_bis
{ P.arith_op Ast.Mul $1 $2 $3 }
- | arith_expr(r,pe) TDmOp arith_expr(r,pe)
+ | arith_expr(r,pe) TDmOp arith_expr_bis
{ let (op,clt) = $2 in P.arith_op op $1 clt $3 }
- | arith_expr(r,pe) TPlus arith_expr(r,pe)
+ | arith_expr(r,pe) TPlus arith_expr_bis
{ P.arith_op Ast.Plus $1 $2 $3 }
- | arith_expr(r,pe) TMinus arith_expr(r,pe)
+ | arith_expr(r,pe) TMinus arith_expr_bis
{ P.arith_op Ast.Minus $1 $2 $3 }
- | arith_expr(r,pe) TShOp arith_expr(r,pe)
+ | arith_expr(r,pe) TShLOp arith_expr_bis
+ { let (op,clt) = $2 in P.arith_op op $1 clt $3 }
+ | arith_expr(r,pe) TShROp arith_expr_bis
{ let (op,clt) = $2 in P.arith_op op $1 clt $3 }
- | arith_expr(r,pe) TLogOp arith_expr(r,pe)
+ | arith_expr(r,pe) TLogOp arith_expr_bis
{ let (op,clt) = $2 in P.logic_op op $1 clt $3 }
- | arith_expr(r,pe) TEqEq arith_expr(r,pe)
+ | arith_expr(r,pe) TEqEq arith_expr_bis
{ P.logic_op Ast.Eq $1 $2 $3 }
- | arith_expr(r,pe) TNotEq arith_expr(r,pe)
+ | arith_expr(r,pe) TNotEq arith_expr_bis
{ P.logic_op Ast.NotEq $1 $2 $3 }
- | arith_expr(r,pe) TAnd arith_expr(r,pe)
+ | arith_expr(r,pe) TAnd arith_expr_bis
{ P.arith_op Ast.And $1 $2 $3 }
- | arith_expr(r,pe) TOr arith_expr(r,pe)
+ | arith_expr(r,pe) TOr arith_expr_bis
{ P.arith_op Ast.Or $1 $2 $3 }
- | arith_expr(r,pe) TXor arith_expr(r,pe)
+ | arith_expr(r,pe) TXor arith_expr_bis
{ P.arith_op Ast.Xor $1 $2 $3 }
- | arith_expr(r,pe) TAndLog arith_expr(r,pe)
+ | arith_expr(r,pe) TAndLog arith_expr_bis
{ P.logic_op Ast.AndLog $1 $2 $3 }
- | arith_expr(r,pe) TOrLog arith_expr(r,pe)
+ | arith_expr(r,pe) TOrLog arith_expr_bis
{ P.logic_op Ast.OrLog $1 $2 $3 }
+// allows dots now that an expression-specific token has been seen
+// need an extra rule because of recursion restrictions
+arith_expr_bis:
+ cast_expr(eexpr,dot_expressions) { $1 }
+ | arith_expr_bis TMul arith_expr_bis
+ { P.arith_op Ast.Mul $1 $2 $3 }
+ | arith_expr_bis TDmOp arith_expr_bis
+ { let (op,clt) = $2 in P.arith_op op $1 clt $3 }
+ | arith_expr_bis TPlus arith_expr_bis
+ { P.arith_op Ast.Plus $1 $2 $3 }
+ | arith_expr_bis TMinus arith_expr_bis
+ { P.arith_op Ast.Minus $1 $2 $3 }
+ | arith_expr_bis TShLOp arith_expr_bis
+ { let (op,clt) = $2 in P.arith_op op $1 clt $3 }
+ | arith_expr_bis TShROp arith_expr_bis
+ { let (op,clt) = $2 in P.arith_op op $1 clt $3 }
+ | arith_expr_bis TLogOp arith_expr_bis
+ { let (op,clt) = $2 in P.logic_op op $1 clt $3 }
+ | arith_expr_bis TEqEq arith_expr_bis
+ { P.logic_op Ast.Eq $1 $2 $3 }
+ | arith_expr_bis TNotEq arith_expr_bis
+ { P.logic_op Ast.NotEq $1 $2 $3 }
+ | arith_expr_bis TAnd arith_expr_bis
+ { P.arith_op Ast.And $1 $2 $3 }
+ | arith_expr_bis TOr arith_expr_bis
+ { P.arith_op Ast.Or $1 $2 $3 }
+ | arith_expr_bis TXor arith_expr_bis
+ { P.arith_op Ast.Xor $1 $2 $3 }
+ | arith_expr_bis TAndLog arith_expr_bis
+ { P.logic_op Ast.AndLog $1 $2 $3 }
+// no OrLog because it is left associative and this is for
+// a right argument, not sure why not the same problem for AndLog
+
cast_expr(r,pe):
unary_expr(r,pe) { $1 }
| lp=TOPar t=ctype rp=TCPar e=cast_expr(r,pe)
unary_expr(r,pe):
postfix_expr(r,pe) { $1 }
- | TInc unary_expr(r,pe)
+ | TInc unary_expr_bis
+ { Ast0.wrap(Ast0.Infix ($2, P.clt2mcode Ast.Inc $1)) }
+ | TDec unary_expr_bis
+ { Ast0.wrap(Ast0.Infix ($2, P.clt2mcode Ast.Dec $1)) }
+ | unary_op cast_expr(r,pe)
+ { let mcode = $1 in Ast0.wrap(Ast0.Unary($2, mcode)) }
+ | TBang unary_expr_bis
+ { let mcode = P.clt2mcode Ast.Not $1 in
+ Ast0.wrap(Ast0.Unary($2, mcode)) }
+ | TSizeof unary_expr_bis
+ { Ast0.wrap(Ast0.SizeOfExpr (P.clt2mcode "sizeof" $1, $2)) }
+ | s=TSizeof lp=TOPar t=ctype rp=TCPar
+ { Ast0.wrap(Ast0.SizeOfType (P.clt2mcode "sizeof" s,
+ P.clt2mcode "(" lp,t,
+ P.clt2mcode ")" rp)) }
+
+// version that allows dots
+unary_expr_bis:
+ postfix_expr(eexpr,dot_expressions) { $1 }
+ | TInc unary_expr_bis
{ Ast0.wrap(Ast0.Infix ($2, P.clt2mcode Ast.Inc $1)) }
- | TDec unary_expr(r,pe)
+ | TDec unary_expr_bis
{ Ast0.wrap(Ast0.Infix ($2, P.clt2mcode Ast.Dec $1)) }
- | unary_op unary_expr(r,pe)
+ | unary_op cast_expr(eexpr,dot_expressions)
{ let mcode = $1 in Ast0.wrap(Ast0.Unary($2, mcode)) }
- | TBang unary_expr(r,pe)
+ | TBang unary_expr_bis
{ let mcode = P.clt2mcode Ast.Not $1 in
Ast0.wrap(Ast0.Unary($2, mcode)) }
- | TSizeof unary_expr(r,pe)
+ | TSizeof unary_expr_bis
{ Ast0.wrap(Ast0.SizeOfExpr (P.clt2mcode "sizeof" $1, $2)) }
| s=TSizeof lp=TOPar t=ctype rp=TCPar
{ Ast0.wrap(Ast0.SizeOfType (P.clt2mcode "sizeof" s,
| postfix_expr(r,pe) TOCro eexpr TCCro
{ Ast0.wrap(Ast0.ArrayAccess ($1,P.clt2mcode "[" $2,$3,
P.clt2mcode "]" $4)) }
- | postfix_expr(r,pe) TDot ident
+ | postfix_expr(r,pe) TDot disj_ident
{ Ast0.wrap(Ast0.RecordAccess($1, P.clt2mcode "." $2, $3)) }
- | postfix_expr(r,pe) TPtrOp ident
+ | postfix_expr(r,pe) TPtrOp disj_ident
{ Ast0.wrap(Ast0.RecordPtAccess($1, P.clt2mcode "->" $2,
$3)) }
| postfix_expr(r,pe) TInc
pure_ident:
TIdent { $1 }
+pure_ident_kwd:
+ | TIdentifier { "identifier" }
+ | TExpression { "expression" }
+ | TStatement { "statement" }
+ | TFunction { "function" }
+ | TLocal { "local" }
+ | TType { "type" }
+ | TParameter { "parameter" }
+ | TIdExpression { "idexpression" }
+ | TInitialiser { "initialiser" }
+ | Tlist { "list" }
+ | TFresh { "fresh" }
+ | TConstant { "constant" }
+ | TError { "error" }
+ | TWords { "words" }
+ | TPure { "pure" }
+ | TContext { "context" }
+ | TGenerated { "generated" }
+ | TTypedef { "typedef" }
+ | TDeclarer { "declarer" }
+ | TIterator { "iterator" }
+ | TName { "name" }
+ | TPosition { "position" }
+
meta_ident:
- TRuleName TDot pure_ident { (Some $1,P.id2name $3) }
+ TRuleName TDot pure_ident { (Some $1,P.id2name $3) }
+ | TRuleName TDot pure_ident_kwd { (Some $1,$3) }
pure_ident_or_meta_ident:
pure_ident { (None,P.id2name $1) }
+ | pure_ident_kwd { (None,$1) }
| meta_ident { $1 }
- | Tlist { (None,"list") }
- | TError { (None,"error") }
- | TType { (None,"type") }
-
-pure_ident_or_meta_ident_with_not_eq(not_eq):
- i=pure_ident_or_meta_ident l=loption(not_eq) { (i,l) }
-not_eq:
- TNotEq i=pure_ident
+pure_ident_or_meta_ident_with_seed:
+ pure_ident_or_meta_ident { ($1,Ast.NoVal) }
+ | pure_ident_or_meta_ident TEq
+ separated_nonempty_list(TCppConcatOp,seed_elem)
+ { match $3 with
+ [Ast.SeedString s] -> ($1,Ast.StringSeed s)
+ | _ -> ($1,Ast.ListSeed $3) }
+
+seed_elem:
+ TString { let (x,_) = $1 in Ast.SeedString x }
+| TMetaId { let (x,_,_,_) = $1 in Ast.SeedId x }
+| TMeta {failwith "tmeta"}
+| TRuleName TDot pure_ident
+ { let nm = ($1,P.id2name $3) in
+ P.check_meta(Ast.MetaIdDecl(Ast.NONE,nm));
+ Ast.SeedId nm }
+
+pure_ident_or_meta_ident_with_x_eq(x_eq):
+ i=pure_ident_or_meta_ident l=loption(x_eq)
+ {
+ (i, l)
+ }
+
+pure_ident_or_meta_ident_with_econstraint(x_eq):
+ i=pure_ident_or_meta_ident optc=option(x_eq)
+ {
+ match optc with
+ None -> (i, Ast0.NoConstraint)
+ | Some c -> (i, c)
+ }
+
+pure_ident_or_meta_ident_with_idconstraint_virt(constraint_type):
+ i=pure_ident_or_meta_ident c=option(constraint_type)
+ {
+ Common.Left
+ (match c with
+ None -> (i, Ast.IdNoConstraint)
+ | Some constraint_ -> (i,constraint_))
+ }
+| TVirtual TDot pure_ident
+ {
+ let nm = P.id2name $3 in
+ Iteration.parsed_virtual_identifiers :=
+ Common.union_set [nm]
+ !Iteration.parsed_virtual_identifiers;
+ Common.Right nm
+ }
+
+pure_ident_or_meta_ident_with_idconstraint(constraint_type):
+ i=pure_ident_or_meta_ident c=option(constraint_type)
+ {
+ match c with
+ None -> (i, Ast.IdNoConstraint)
+ | Some constraint_ -> (i,constraint_)
+ }
+
+re_or_not_eqid:
+ re=regexp_eqid {Ast.IdRegExpConstraint re}
+ | ne=not_eqid {ne}
+
+regexp_eqid:
+ TTildeEq re=TString
+ { (if !Data.in_iso
+ then failwith "constraints not allowed in iso file");
+ (if !Data.in_generating
+ then failwith "constraints not allowed in a generated rule file");
+ let (s,_) = re in Ast.IdRegExp (s,Str.regexp s)
+ }
+ | TTildeExclEq re=TString
+ { (if !Data.in_iso
+ then failwith "constraints not allowed in iso file");
+ (if !Data.in_generating
+ then failwith "constraints not allowed in a generated rule file");
+ let (s,_) = re in Ast.IdNotRegExp (s,Str.regexp s)
+ }
+
+not_eqid:
+ TNotEq i=pure_ident_or_meta_ident
{ (if !Data.in_iso
then failwith "constraints not allowed in iso file");
- [Ast0.wrap(Ast0.Id(P.id2mcode i))] }
- | TNotEq TOBrace l=comma_list(pure_ident) TCBrace
+ (if !Data.in_generating
+ (* pb: constraints not stored with metavars; too lazy to search for
+ them in the pattern *)
+ then failwith "constraints not allowed in a generated rule file");
+ (match i with
+ (Some rn,id) ->
+ let i =
+ P.check_inherited_constraint i
+ (function mv -> Ast.MetaIdDecl(Ast.NONE,mv)) in
+ Ast.IdNegIdSet([],[i])
+ | (None,i) -> Ast.IdNegIdSet([i],[])) }
+ | TNotEq TOBrace l=comma_list(pure_ident_or_meta_ident) TCBrace
{ (if !Data.in_iso
then failwith "constraints not allowed in iso file");
- List.map (function i -> Ast0.wrap(Ast0.Id(P.id2mcode i))) l }
+ (if !Data.in_generating
+ then failwith "constraints not allowed in a generated rule file");
+ let (str,meta) =
+ List.fold_left
+ (function (str,meta) ->
+ function
+ (Some rn,id) as i ->
+ let i =
+ P.check_inherited_constraint i
+ (function mv -> Ast.MetaIdDecl(Ast.NONE,mv)) in
+ (str,i::meta)
+ | (None,i) -> (i::str,meta))
+ ([],[]) l in
+ Ast.IdNegIdSet(str,meta)
+ }
+
+re_or_not_eqe_or_sub:
+ re=regexp_eqid {Ast0.NotIdCstrt re}
+ | ne=not_eqe {Ast0.NotExpCstrt ne}
+ | s=sub {Ast0.SubExpCstrt s}
+
+not_ceq_or_sub:
+ ceq=not_ceq {Ast0.NotExpCstrt ceq}
+ | s=sub {Ast0.SubExpCstrt s}
not_eqe:
TNotEq i=pure_ident
{ (if !Data.in_iso
then failwith "constraints not allowed in iso file");
- [Ast0.wrap(Ast0.Ident(Ast0.wrap(Ast0.Id(P.id2mcode i))))] }
+ (if !Data.in_generating
+ then failwith "constraints not allowed in a generated rule file");
+ [Ast0.wrap(Ast0.Ident(Ast0.wrap(Ast0.Id(P.id2mcode i))))]
+ }
| TNotEq TOBrace l=comma_list(pure_ident) TCBrace
{ (if !Data.in_iso
then failwith "constraints not allowed in iso file");
+ (if !Data.in_generating
+ then failwith "constraints not allowed in a generated rule file");
List.map
(function i ->
- Ast0.wrap(Ast0.Ident(Ast0.wrap(Ast0.Id(P.id2mcode i)))))
- l }
+ Ast0.wrap(Ast0.Ident(Ast0.wrap(Ast0.Id(P.id2mcode i)))))
+ l
+ }
not_ceq:
TNotEq i=ident_or_const
{ (if !Data.in_iso
then failwith "constraints not allowed in iso file");
+ (if !Data.in_generating
+ then failwith "constraints not allowed in a generated rule file");
[i] }
| TNotEq TOBrace l=comma_list(ident_or_const) TCBrace
{ (if !Data.in_iso
then failwith "constraints not allowed in iso file");
+ (if !Data.in_generating
+ then failwith "constraints not allowed in a generated rule file");
l }
+sub:
+ (* has to be inherited because not clear how to check subterm constraints
+ in the functorized CTL engine, so need the variable to be bound
+ already when bind the subterm constrained metavariable *)
+ TSub i=meta_ident
+ { (if !Data.in_iso
+ then failwith "constraints not allowed in iso file");
+ (if !Data.in_generating
+ then failwith "constraints not allowed in a generated rule file");
+ let i =
+ P.check_inherited_constraint i
+ (function mv -> Ast.MetaExpDecl(Ast.NONE,mv,None)) in
+ [i] }
+ | TSub TOBrace l=comma_list(meta_ident) TCBrace
+ { (if !Data.in_iso
+ then failwith "constraints not allowed in iso file");
+ (if !Data.in_generating
+ then failwith "constraints not allowed in a generated rule file");
+ List.map
+ (function i ->
+ P.check_inherited_constraint i
+ (function mv -> Ast.MetaExpDecl(Ast.NONE,mv,None)))
+ l}
+
ident_or_const:
i=pure_ident { Ast0.wrap(Ast0.Ident(Ast0.wrap(Ast0.Id(P.id2mcode i)))) }
| TInt
TNotEq i=meta_ident
{ (if !Data.in_iso
then failwith "constraints not allowed in iso file");
- match i with
- (None,_) -> failwith "constraint must be an inherited variable"
- | (Some rule,name) ->
- let i = (rule,name) in
- P.check_meta(Ast.MetaPosDecl(Ast.NONE,i));
- [i] }
+ (if !Data.in_generating
+ then failwith "constraints not allowed in a generated rule file");
+ let i =
+ P.check_inherited_constraint i
+ (function mv -> Ast.MetaPosDecl(Ast.NONE,mv)) in
+ [i] }
| TNotEq TOBrace l=comma_list(meta_ident) TCBrace
{ (if !Data.in_iso
then failwith "constraints not allowed in iso file");
+ (if !Data.in_generating
+ then failwith "constraints not allowed in a generated rule file");
List.map
- (function
- (None,_) ->
- failwith "constraint must be an inherited variable"
- | (Some rule,name) ->
- let i = (rule,name) in
- P.check_meta(Ast.MetaPosDecl(Ast.NONE,i));
- i)
+ (function i ->
+ P.check_inherited_constraint i
+ (function mv -> Ast.MetaPosDecl(Ast.NONE,mv)))
l }
-func_ident: pure_ident
- { Ast0.wrap(Ast0.Id(P.id2mcode $1)) }
- | TMetaId
+func_ident: ident { $1 }
+ | TMetaFunc
{ let (nm,constraints,pure,clt) = $1 in
- Ast0.wrap(Ast0.MetaId(P.clt2mcode nm clt,constraints,pure)) }
+ Ast0.wrap(Ast0.MetaFunc(P.clt2mcode nm clt,constraints,pure)) }
+ | TMetaLocalFunc
+ { let (nm,constraints,pure,clt) = $1 in
+ Ast0.wrap
+ (Ast0.MetaLocalFunc(P.clt2mcode nm clt,constraints,pure)) }
+
+fn_ident: disj_ident { $1 }
| TMetaFunc
{ let (nm,constraints,pure,clt) = $1 in
Ast0.wrap(Ast0.MetaFunc(P.clt2mcode nm clt,constraints,pure)) }
{ let (nm,constraints,pure,clt) = $1 in
Ast0.wrap(Ast0.MetaId(P.clt2mcode nm clt,constraints,pure)) }
+mident: pure_ident
+ { Ast0.wrap(Ast0.Id(P.id2mcode $1)) }
+ | TMeta { tmeta_to_ident $1 }
+ | TMetaId
+ { let (nm,constraints,pure,clt) = $1 in
+ Ast0.wrap(Ast0.MetaId(P.clt2mcode nm clt,constraints,pure)) }
+
+disj_ident:
+ mident { $1 }
+ | lp=TOPar0 t=midzero_list(disj_ident,disj_ident) rp=TCPar0
+ { let (mids,code) = t in
+ Ast0.wrap
+ (Ast0.DisjId(P.clt2mcode "(" lp,code,mids, P.clt2mcode ")" rp)) }
+
+type_ident: disj_ident { $1 }
+ | TTypeId
+ { Ast0.wrap(Ast0.Id(P.id2mcode $1)) }
+
decl_ident:
TDeclarerId
{ Ast0.wrap(Ast0.Id(P.id2mcode $1)) }
typedef_ident:
pure_ident
{ Ast0.wrap(Ast0.TypeName(P.id2mcode $1)) }
+ | TMeta { tmeta_to_type $1 }
| TMetaType
{ let (nm,pure,clt) = $1 in
Ast0.wrap(Ast0.MetaType(P.clt2mcode nm clt,pure)) }
/*****************************************************************************/
decl_list(decl):
- decl_list_start(decl)
- {let circle x =
- match Ast0.unwrap x with Ast0.Pcircles(_) -> true | _ -> false in
- if List.exists circle $1
- then Ast0.wrap(Ast0.CIRCLES($1))
- else Ast0.wrap(Ast0.DOTS($1)) }
-
-decl_list_start(decl):
- one_dec(decl) { [$1] }
-| one_dec(decl) TComma decl_list_start(decl)
- { $1::Ast0.wrap(Ast0.PComma(P.clt2mcode "," $2))::$3 }
-| TEllipsis list(comma_decls(TEllipsis,decl))
- { Ast0.wrap(Ast0.Pdots(P.clt2mcode "..." $1))::
- (List.concat(List.map (function x -> x (P.mkpdots "...")) $2)) }
+ empty_list_start(one_dec(decl),TEllipsis)
+ { Ast0.wrap
+ (Ast0.DOTS
+ ($1
+ (fun _ d -> Ast0.wrap(Ast0.Pdots(P.clt2mcode "..." d)))
+ (fun c -> Ast0.PComma c))) }
one_dec(decl):
decl { $1 }
| TMetaParamList
{ let (nm,lenname,pure,clt) = $1 in
let nm = P.clt2mcode nm clt in
- let lenname =
- match lenname with
- Some nm -> Some(P.clt2mcode nm clt)
- | None -> None in
+ let lenname =
+ match lenname with
+ Ast.AnyLen -> Ast0.AnyListLen
+ | Ast.MetaLen nm -> Ast0.MetaListLen(P.clt2mcode nm clt)
+ | Ast.CstLen n -> Ast0.CstListLen n in
Ast0.wrap(Ast0.MetaParamList(nm,lenname,pure)) }
-
-comma_decls(dotter,decl):
- TComma dotter
- { function dot_builder ->
- [Ast0.wrap(Ast0.PComma(P.clt2mcode "," $1));
- dot_builder $2] }
-| TComma one_dec(decl)
- { function dot_builder ->
- [Ast0.wrap(Ast0.PComma(P.clt2mcode "," $1)); $2] }
+
+/* ---------------------------------------------------------------------- */
+/* comma list parser, used for fn params, fn args, enums, initlists,
+ #define params */
+
+/* enums: enum_decl, edots_when(TEllipsis,enum_decl_one)
+fun s d -> P.mkedots "..." d
+fun c -> Ast0.EComma c
+ */
+
+empty_list_start(elem,dotter):
+ /* empty */ { fun build_dots build_comma -> [] }
+| nonempty_list_start(elem,dotter) { $1 }
+
+nonempty_list_start(elem,dotter): /* dots allowed */
+ elem { fun build_dots build_comma -> [$1] }
+| elem TComma
+ { fun build_dots build_comma ->
+ $1::[Ast0.wrap(build_comma(P.clt2mcode "," $2))] }
+| elem TComma nonempty_list_start(elem,dotter)
+ { fun build_dots build_comma ->
+ $1::(Ast0.wrap(build_comma(P.clt2mcode "," $2)))::
+ ($3 build_dots build_comma) }
+| TNothing nonempty_list_start(elem,dotter) { $2 }
+| d=dotter { fun build_dots build_comma -> [(build_dots "..." d)] }
+| d=dotter TComma
+ { fun build_dots build_comma ->
+ [(build_dots "..." d);Ast0.wrap(build_comma(P.clt2mcode "," $2))] }
+| d=dotter TComma r=continue_list(elem,dotter)
+ { fun build_dots build_comma ->
+ (build_dots "..." d)::
+ (Ast0.wrap(build_comma(P.clt2mcode "," $2)))::
+ (r build_dots build_comma) }
+
+continue_list(elem,dotter): /* dots not allowed */
+ elem { fun build_dots build_comma -> [$1] }
+| elem TComma
+ { fun build_dots build_comma ->
+ $1::[Ast0.wrap(build_comma(P.clt2mcode "," $2))] }
+| elem TComma nonempty_list_start(elem,dotter)
+ { fun build_dots build_comma ->
+ $1::(Ast0.wrap(build_comma(P.clt2mcode "," $2)))::
+ ($3 build_dots build_comma) }
+| TNothing nonempty_list_start(elem,dotter) { $2 }
/* ---------------------------------------------------------------------- */
-error_words:
+/* error words make it complicated to be able to use error as a metavariable
+name or a type in a metavariable list; for that we would like to allow TError
+as an ident, but that makes conflicts with this rule. To add back error words,
+need to find some appropriate delimiter for it, but it has not been used much
+so just drop it */
+/*error_words:
TError TWords TEq TOCro cl=comma_list(dexpr) TCCro
{ [Ast0.wrap(Ast0.ERRORWORDS(cl))] }
+*/
/* ---------------------------------------------------------------------- */
/* sequences of statements and expressions */
fundecl { [Ast0.wrap(Ast0.DECL($1))] }
| ctype { [Ast0.wrap(Ast0.OTHER(Ast0.wrap(Ast0.Ty($1))))] }
| top_init { [Ast0.wrap(Ast0.OTHER(Ast0.wrap(Ast0.TopInit($1))))] }
-| toplevel_seq_start(toplevel_after_dots_init)
+| toplevel_seq_startne(toplevel_after_dots_init)
{ List.map (function x -> Ast0.wrap(Ast0.OTHER(x))) $1 }
+toplevel_seq_startne(after_dots_init):
+ a=stm_dots_ell b=after_dots_init { a::b }
+| a=stm_dots_nest b=after_dots_init { a::b }
+| a=stm_dots_nest { [a] }
+| expr toplevel_after_exp { (Ast0.wrap(Ast0.Exp($1)))::$2 }
+| decl_statement_expr toplevel_after_stm { $1@$2 }
+
toplevel_seq_start(after_dots_init):
stm_dots after_dots_init { $1::$2 }
| expr toplevel_after_exp { (Ast0.wrap(Ast0.Exp($1)))::$2 }
top_init:
TOInit initialize_list TCBrace
- { Ast0.wrap(Ast0.InitList(P.clt2mcode "{" $1,$2,P.clt2mcode "}" $3)) }
+ { if P.struct_initializer $2
+ then
+ let il = P.drop_dot_commas $2 in
+ Ast0.wrap(Ast0.InitList(P.clt2mcode "{" $1,il,P.clt2mcode "}" $3,false))
+ else
+ Ast0.wrap(Ast0.InitList(P.clt2mcode "{" $1,$2,P.clt2mcode "}" $3,true)) }
/* ------------------------------------------------------------------------ */
/* Plus top level */
/* ---------------------------------------------------------------------- */
-eexpr_list:
- eexpr_list_start
- {let circle x =
- match Ast0.unwrap x with Ast0.Ecircles(_) -> true | _ -> false in
- let star x =
- match Ast0.unwrap x with Ast0.Estars(_) -> true | _ -> false in
- if List.exists circle $1
- then Ast0.wrap(Ast0.CIRCLES($1))
- else
- if List.exists star $1
- then Ast0.wrap(Ast0.STARS($1))
- else Ast0.wrap(Ast0.DOTS($1)) }
-
/* arg expr. may contain a type or a explist metavariable */
aexpr:
- eexpr
- { Ast0.set_arg_exp $1 }
+ dexpr { Ast0.set_arg_exp $1 }
| TMetaExpList
{ let (nm,lenname,pure,clt) = $1 in
let nm = P.clt2mcode nm clt in
let lenname =
match lenname with
- Some nm -> Some(P.clt2mcode nm clt)
- | None -> None in
+ Ast.AnyLen -> Ast0.AnyListLen
+ | Ast.MetaLen nm -> Ast0.MetaListLen(P.clt2mcode nm clt)
+ | Ast.CstLen n -> Ast0.CstListLen n in
Ast0.wrap(Ast0.MetaExprList(nm,lenname,pure)) }
| ctype
{ Ast0.set_arg_exp(Ast0.wrap(Ast0.TypeExp($1))) }
-eexpr_list_start:
- aexpr { [$1] }
- | aexpr TComma eexpr_list_start
- { $1::Ast0.wrap(Ast0.EComma(P.clt2mcode "," $2))::$3 }
-
-comma_args(dotter):
- c=TComma d=dotter
- { function dot_builder ->
- [Ast0.wrap(Ast0.EComma(P.clt2mcode "," c)); dot_builder d] }
-| TComma aexpr
- { function dot_builder ->
- [Ast0.wrap(Ast0.EComma(P.clt2mcode "," $1)); $2] }
-
-eexpr_list_option: eexpr_list { $1 }
- | /* empty */ { Ast0.wrap(Ast0.DOTS([])) }
+eexpr_list_option:
+ empty_list_start(aexpr,TEllipsis)
+ { Ast0.wrap
+ (Ast0.DOTS
+ ($1
+ (fun _ d -> Ast0.wrap(Ast0.Edots(P.clt2mcode "..." d,None)))
+ (fun c -> Ast0.EComma c))) }
/****************************************************************************/
d=dotter { (d,None) }
| d=dotter TWhen TNotEq w=when_grammar TLineEnd { (d,Some w) }
-whens(when_grammar,simple_when_grammar):
+whens(when_grammar,simple_when_grammar,any_strict):
TWhen TNotEq w=when_grammar TLineEnd { [Ast0.WhenNot w] }
| TWhen TEq w=simple_when_grammar TLineEnd { [Ast0.WhenAlways w] }
| TWhen comma_list(any_strict) TLineEnd
*****************************************************************************/
iso_main:
- TIsoExpression e1=dexpr el=list(iso(dexpr)) EOF
- { P.iso_adjust (function x -> Ast0.ExprTag x) e1 el }
-| TIsoArgExpression e1=dexpr el=list(iso(dexpr)) EOF
- { P.iso_adjust (function x -> Ast0.ArgExprTag x) e1 el }
-| TIsoTestExpression e1=dexpr el=list(iso(dexpr)) EOF
- { P.iso_adjust (function x -> Ast0.TestExprTag x) e1 el }
+ TIsoExpression e1=eexpr el=list(iso(eexpr)) EOF
+ { let fn x = Ast0.ExprTag x in P.iso_adjust fn fn e1 el }
+| TIsoArgExpression e1=eexpr el=list(iso(eexpr)) EOF
+ { let fn x = Ast0.ArgExprTag x in P.iso_adjust fn fn e1 el }
+| TIsoTestExpression e1=eexpr el=list(iso(eexpr)) EOF
+ { let fn x = Ast0.TestExprTag x in P.iso_adjust fn fn e1 el }
+| TIsoToTestExpression e1=eexpr el=list(iso(eexpr)) EOF
+ { let ffn x = Ast0.ExprTag x in
+ let fn x = Ast0.TestExprTag x in
+ P.iso_adjust ffn fn e1 el }
| TIsoStatement s1=single_statement sl=list(iso(single_statement)) EOF
- { P.iso_adjust (function x -> Ast0.StmtTag x) s1 sl }
+ { let fn x = Ast0.StmtTag x in P.iso_adjust fn fn s1 sl }
| TIsoType t1=ctype tl=list(iso(ctype)) EOF
- { P.iso_adjust (function x -> Ast0.TypeCTag x) t1 tl }
+ { let fn x = Ast0.TypeCTag x in P.iso_adjust fn fn t1 tl }
| TIsoTopLevel e1=nest_start el=list(iso(nest_start)) EOF
- { P.iso_adjust (function x -> Ast0.DotsStmtTag x) e1 el }
+ { let fn x = Ast0.DotsStmtTag x in P.iso_adjust fn fn e1 el }
| TIsoDeclaration d1=decl_var dl=list(iso(decl_var)) EOF
{ let check_one = function
[x] -> x
Common.Left x -> Common.Left(check_one x)
| Common.Right x -> Common.Right(check_one x))
dl in
- P.iso_adjust (function x -> Ast0.DeclTag x) d1 dl }
+ let fn x = Ast0.DeclTag x in P.iso_adjust fn fn d1 dl }
iso(term):
TIso t=term { Common.Left t }
| TPArob TMetaPos { () }
| TScriptData { () }
-script_meta_main: py=pure_ident TShOp TRuleName TDot cocci=pure_ident TMPtVirg
- { (P.id2name py, ($3, P.id2name cocci)) }
+script_meta_main:
+ py=pure_ident TMPtVirg
+ { ((Some (P.id2name py), None), None) }
+ | py=pure_ident script_name_decl TMPtVirg
+ { ((Some (P.id2name py), None), Some $2) }
+ | TOPar TUnderscore TComma ast=pure_ident TCPar script_name_decl TMPtVirg
+ { ((None, Some (P.id2name ast)), Some $6) }
+ | TOPar str=pure_ident TComma TUnderscore TCPar script_name_decl TMPtVirg
+ { ((Some (P.id2name str), None), Some $6) }
+ | TOPar str=pure_ident TComma ast=pure_ident TCPar script_name_decl TMPtVirg
+ { ((Some (P.id2name str), Some (P.id2name ast)), Some $6) }
+
+script_name_decl:
+ TShLOp TRuleName TDot cocci=pure_ident
+ { let nm = P.id2name cocci in
+ let mv = Parse_aux.lookup $2 nm in
+ (($2, nm), mv) }
+ | TShLOp TVirtual TDot cocci=pure_ident
+ { let nm = P.id2name cocci in
+ Iteration.parsed_virtual_identifiers :=
+ Common.union_set [nm]
+ !Iteration.parsed_virtual_identifiers;
+ let name = ("virtual", nm) in
+ let mv = Ast.MetaIdDecl(Ast.NONE,name) in
+ (name,mv) }