/*
-* Copyright 2005-2009, 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 2005-2010, 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.
+ */
%{
%token TPure TContext TGenerated
%token TTypedef TDeclarer TIterator TName TPosition TPosAny
%token TUsing TDisable TExtends TDepends TOn TEver TNever TExists TForall
-%token TScript TInitialize TFinalize TNothing
+%token TScript TInitialize TFinalize TNothing TVirtual
%token<string> TRuleName
%token<Data.clt> Tchar Tshort Tint Tdouble Tfloat Tlong
%token <Data.clt> TBreak TContinue TGoto TSizeof TFunDecl
%token <string * Data.clt> TIdent TTypeId TDeclarerId TIteratorId 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
-%token <Parse_aux.list_info> TMetaParamList TMetaExpList
-%token <Parse_aux.typed_info> TMetaExp TMetaIdExp TMetaLocalIdExp TMetaConst
-%token <Parse_aux.pos_info> TMetaPos
+%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
+%token <Parse_aux.list_info> TMetaParamList TMetaExpList
+%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> TOr
%token <Data.clt> TXor
%token <Data.clt> TAnd
-%token <Data.clt> TEqEq TNotEq
+%token <Data.clt> TEqEq TNotEq TTildeEq TTildeExclEq
%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> TDmOp /* TDiv TMod */
%start meta_main
%type <(Ast_cocci.metavar,Ast_cocci.metavar) Common.either list> meta_main
-%start <string * (string * string)> script_meta_main
+%start <string * Ast_cocci.meta_name> script_meta_main
%start iso_main
%type <Ast0_cocci.anything list list> iso_main
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
+ (* 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_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))
+ 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_x_eq(not_ceq)) 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
+ 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 *)
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 id=pure_ident_or_meta_ident TCCro
ids=comma_list(pure_ident_or_meta_ident) TMPtVirg
let tok = check_meta(Ast.MetaFreshIdDecl(name,seed)) in
!Data.add_fresh_id_meta name; tok) }
+/* metavariable kinds with no constraints, etc */
%inline metakind:
TParameter
{ (fun arity name pure check_meta ->
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 ->
+ 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) }
TExpression
{ (fun arity name pure check_meta constraints ->
let tok = check_meta(Ast.MetaExpDecl(arity,name,None)) in
- !Data.add_exp_meta None name constraints pure; tok) }
+ !Data.add_exp_meta None name (Ast0.NotExpCstrt constraints) pure; tok) }
| 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
| _ -> ())
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 (Ast0.NotExpCstrt constraints) pure; tok)
+ }
meta_exp_type:
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.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 }
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; */
(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=typedef_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
| ident TDotDot initialize2
{ Ast0.wrap(Ast0.InitGccName($1,P.clt2mcode ":" $2,$3)) } /* in old kernel */
-designator:
- | TDot ident
- { Ast0.DesignatorField (P.clt2mcode "." $1,$2) }
- | TOCro eexpr TCCro
+designator:
+ | TDot ident
+ { Ast0.DesignatorField (P.clt2mcode "." $1,$2) }
+ | TOCro eexpr TCCro
{ Ast0.DesignatorIndex (P.clt2mcode "[" $1,$2,P.clt2mcode "]" $3) }
- | TOCro eexpr TEllipsis eexpr TCCro
+ | TOCro eexpr TEllipsis eexpr TCCro
{ Ast0.DesignatorRange (P.clt2mcode "[" $1,$2,P.clt2mcode "..." $3,
$4,P.clt2mcode "]" $5) }
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 }
- | TIdentifier { (None, "identifier") }
- | TExpression { (None, "expression") }
- | TStatement { (None, "statement") }
- | TFunction { (None, "function") }
- | TLocal { (None, "local") }
- | TType { (None, "type") }
- | TParameter { (None, "parameter") }
- | TIdExpression { (None, "idexpression") }
- | TInitialiser { (None, "initialiser") }
- | Tlist { (None, "list") }
- | TFresh { (None, "fresh") }
- | TConstant { (None, "constant") }
- | TError { (None, "error") }
- | TWords { (None, "words") }
- | TPure { (None, "pure") }
- | TContext { (None, "context") }
- | TGenerated { (None, "generated") }
- | TTypedef { (None, "typedef") }
- | TDeclarer { (None, "declarer") }
- | TIterator { (None, "iterator") }
- | TName { (None, "name") }
- | TPosition { (None, "position") }
pure_ident_or_meta_ident_with_seed:
pure_ident_or_meta_ident { ($1,Ast.NoVal) }
P.check_meta(Ast.MetaIdDecl(Ast.NONE,nm));
Ast.SeedId nm }
-pure_ident_or_meta_ident_with_not_eq(not_eq):
- i=pure_ident_or_meta_ident l=loption(not_eq) { (i,l) }
+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 { Common.Right (P.id2name $3) }
+
+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 {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_eq:
+not_eqid:
TNotEq i=pure_ident
{ (if !Data.in_iso
then failwith "constraints not allowed in iso file");
(* 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");
- [Ast0.wrap(Ast0.Id(P.id2mcode i))] }
+ Ast.IdNegIdSet([fst 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.Id(P.id2mcode i))) l }
+ Ast.IdNegIdSet(List.map fst l)
+ }
+
+re_or_not_eqe:
+ re=regexp_eqid {Ast0.NotIdCstrt (re)}
+ | ne=not_eqe {Ast0.NotExpCstrt (ne)}
not_eqe:
TNotEq i=pure_ident
then failwith "constraints not allowed in iso file");
(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))))] }
+ [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");
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
| TPArob TMetaPos { () }
| TScriptData { () }
-script_meta_main: py=pure_ident TShOp TRuleName TDot cocci=pure_ident TMPtVirg
+script_meta_main:
+ py=pure_ident TShOp TRuleName TDot cocci=pure_ident TMPtVirg
{ (P.id2name py, ($3, P.id2name cocci)) }
+ | py=pure_ident TShOp TVirtual TDot cocci=pure_ident TMPtVirg
+ { (P.id2name py, ("virtual", P.id2name cocci)) }