Release coccinelle-0.2.1-rc1
[bpt/coccinelle.git] / parsing_cocci / parser_cocci_menhir.mly
index b475b45..86972fa 100644 (file)
@@ -1,23 +1,23 @@
 /*
-* 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.
+ */
 
 
 %{
@@ -43,7 +43,7 @@ module P = Parse_aux
 %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
@@ -58,14 +58,14 @@ module P = Parse_aux
 %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
@@ -91,7 +91,7 @@ module P = Parse_aux
 %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 */
@@ -156,7 +156,7 @@ rule_name
 %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
@@ -256,6 +256,13 @@ incl:
   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
@@ -264,20 +271,32 @@ metadec:
 | 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 *)
@@ -287,7 +306,7 @@ metadec:
       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
@@ -313,6 +332,7 @@ metadec:
       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 ->
@@ -358,13 +378,24 @@ metadec:
       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) }
@@ -425,7 +456,7 @@ metadec:
   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
@@ -445,7 +476,8 @@ metadec:
          | _ -> ())
        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:
@@ -627,7 +659,8 @@ filespec:
 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 =
@@ -637,7 +670,8 @@ includes:
                              (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 =
@@ -850,8 +884,8 @@ statement:
     { 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 }
@@ -917,9 +951,14 @@ single_statement:
 
 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; */
@@ -979,9 +1018,12 @@ decl_var:
               (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
@@ -1076,12 +1118,12 @@ initialize2:
 | 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) }
 
@@ -1372,34 +1414,38 @@ no_dot_start_end(grammar,dotter):
 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) }
@@ -1417,10 +1463,59 @@ seed_elem:
       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");
@@ -1428,13 +1523,18 @@ not_eq:
            (* 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
@@ -1442,7 +1542,8 @@ not_eqe:
           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");
@@ -1450,8 +1551,9 @@ not_eqe:
           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
@@ -1883,5 +1985,8 @@ never_used: TPragma { () }
   | 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)) }