Version 1.0.0-rc17 has been released. Some changes are:
[bpt/coccinelle.git] / parsing_cocci / parse_cocci.ml
index 5ab5251..a193b3f 100644 (file)
@@ -1,25 +1,30 @@
 (*
-* 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 2012, INRIA
+ * Julia Lawall, Gilles Muller
+ * Copyright 2010-2011, 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.
+ *)
+
+
+# 0 "./parse_cocci.ml"
 (* splits the entire file into minus and plus fragments, and parses each
 separately (thus duplicating work for the parsing of the context elements) *)
 
@@ -29,6 +34,9 @@ module V0 = Visitor_ast0
 module VT0 = Visitor_ast0_types
 module Ast = Ast_cocci
 module Ast0 = Ast0_cocci
+
+exception Bad_virt of string
+
 let pr = Printf.sprintf
 (*let pr2 s = prerr_string s; prerr_string "\n"; flush stderr*)
 let pr2 s = Printf.printf "%s\n" s
@@ -46,19 +54,25 @@ let line_type2c tok =
   match line_type tok with
     D.MINUS | D.OPTMINUS | D.UNIQUEMINUS -> ":-"
   | D.PLUS -> ":+"
+  | D.PLUSPLUS -> ":++"
   | D.CONTEXT | D.UNIQUE | D.OPT -> ""
 
 let token2c (tok,_) =
  match tok with
-    PC.TIdentifier -> "identifier"
+    PC.TMetavariable -> "metavariable"
+  | PC.TIdentifier -> "identifier"
   | PC.TType -> "type"
   | PC.TParameter -> "parameter"
   | PC.TConstant -> "constant"
   | PC.TExpression -> "expression"
   | PC.TIdExpression -> "idexpression"
   | PC.TInitialiser -> "initialiser"
+  | PC.TSymbol -> "symbol"
+  | PC.TDeclaration -> "declaration"
+  | PC.TField -> "field"
   | PC.TStatement -> "statement"
   | PC.TPosition -> "position"
+  | PC.TAnalysis -> "analysis"
   | PC.TPosAny -> "any"
   | PC.TFunction -> "function"
   | PC.TLocal -> "local"
@@ -73,6 +87,7 @@ let token2c (tok,_) =
   | PC.TName -> "name"
   | PC.TRuleName str -> "rule_name-"^str
   | PC.TUsing -> "using"
+  | PC.TVirtual -> "virtual"
   | PC.TPathIsoFile str -> "path_iso_file-"^str
   | PC.TDisable -> "disable"
   | PC.TExtends -> "extends"
@@ -95,6 +110,9 @@ let token2c (tok,_) =
   | PC.Tfloat(clt) -> "float"^(line_type2c clt)
   | PC.Tlong(clt) -> "long"^(line_type2c clt)
   | PC.Tvoid(clt) -> "void"^(line_type2c clt)
+  | PC.Tsize_t(clt) -> "size_t"^(line_type2c clt)
+  | PC.Tssize_t(clt) -> "ssize_t"^(line_type2c clt)
+  | PC.Tptrdiff_t(clt) -> "ptrdiff_t"^(line_type2c clt)
   | PC.Tstruct(clt) -> "struct"^(line_type2c clt)
   | PC.Tunion(clt) -> "union"^(line_type2c clt)
   | PC.Tenum(clt) -> "enum"^(line_type2c clt)
@@ -110,9 +128,12 @@ let token2c (tok,_) =
   | PC.Tconst(clt) -> "const"^(line_type2c clt)
   | PC.Tvolatile(clt) -> "volatile"^(line_type2c clt)
 
-  | PC.TPragma(s,_) -> s
+  | PC.TPragma(Ast.Noindent s,_) -> s
+  | PC.TPragma(Ast.Indent s,_)   -> s
+  | PC.TPragma(Ast.Space s,_)   -> s
   | PC.TIncludeL(s,clt) -> (pr "#include \"%s\"" s)^(line_type2c clt)
   | PC.TIncludeNL(s,clt) -> (pr "#include <%s>" s)^(line_type2c clt)
+  | PC.TUndef(clt,_) -> "#undef"^(line_type2c clt)
   | PC.TDefine(clt,_) -> "#define"^(line_type2c clt)
   | PC.TDefineParam(clt,_,_,_) -> "#define_param"^(line_type2c clt)
   | PC.TMinusFile(s,clt) -> (pr "--- %s" s)^(line_type2c clt)
@@ -137,6 +158,7 @@ let token2c (tok,_) =
   | PC.TTypeId(s,clt) -> (pr "typename-%s" s)^(line_type2c clt)
   | PC.TDeclarerId(s,clt) -> (pr "declarername-%s" s)^(line_type2c clt)
   | PC.TIteratorId(s,clt) -> (pr "iteratorname-%s" s)^(line_type2c clt)
+  | PC.TSymId(s,clt)      -> (pr "symbol-%s" s)^(line_type2c clt)
   | PC.TMetaDeclarer(_,_,_,clt) -> "declmeta"^(line_type2c clt)
   | PC.TMetaIterator(_,_,_,clt) -> "itermeta"^(line_type2c clt)
 
@@ -154,6 +176,9 @@ let token2c (tok,_) =
   | PC.TAnd (clt) -> "&"^(line_type2c clt)
   | PC.TEqEq(clt) -> "=="^(line_type2c clt)
   | PC.TNotEq(clt) -> "!="^(line_type2c clt)
+  | PC.TSub(clt) -> "<="^(line_type2c clt)
+  | PC.TTildeEq(clt) -> "~="^(line_type2c clt)
+  | PC.TTildeExclEq(clt) -> "~!="^(line_type2c clt)
   | PC.TLogOp(op,clt) ->
       (match op with
        Ast.Inf -> "<"
@@ -162,23 +187,22 @@ let token2c (tok,_) =
       |        Ast.SupEq -> ">="
       |        _ -> failwith "not possible")
       ^(line_type2c clt)
-  | PC.TShOp(op,clt) ->
-      (match op with
-       Ast.DecLeft -> "<<"
-      |        Ast.DecRight -> ">>"
-      |        _ -> failwith "not possible")
-      ^(line_type2c clt)
+  | PC.TShLOp(op,clt) -> "<<"^(line_type2c clt)
+  | PC.TShROp(op,clt) -> ">>"^(line_type2c clt)
   | PC.TPlus(clt) -> "+"^(line_type2c clt)
   | PC.TMinus(clt) -> "-"^(line_type2c clt)
   | PC.TMul(clt) -> "*"^(line_type2c clt)
   | PC.TDmOp(op,clt) ->
       (match op with
        Ast.Div -> "/"
+      |        Ast.Min -> "<?"
+      |        Ast.Max -> ">?"
       |        Ast.Mod -> "%"
       |        _ -> failwith "not possible")
       ^(line_type2c clt)
   | PC.TTilde (clt) -> "~"^(line_type2c clt)
 
+  | PC.TMeta(_,_,clt) -> "meta"^(line_type2c clt)
   | PC.TMetaParam(_,_,clt) -> "parammeta"^(line_type2c clt)
   | PC.TMetaParamList(_,_,_,clt) -> "paramlistmeta"^(line_type2c clt)
   | PC.TMetaConst(_,_,_,_,clt) -> "constmeta"^(line_type2c clt)
@@ -187,18 +211,22 @@ let token2c (tok,_) =
   | PC.TMetaIdExp(_,_,_,_,clt) -> "idexpmeta"^(line_type2c clt)
   | PC.TMetaLocalIdExp(_,_,_,_,clt) -> "localidexpmeta"^(line_type2c clt)
   | PC.TMetaExpList(_,_,_,clt) -> "explistmeta"^(line_type2c clt)
-  | PC.TMetaId(_,_,_,clt)    -> "idmeta"^(line_type2c clt)
+  | PC.TMetaId(nm,_,_,_,clt)    -> "idmeta-"^(Dumper.dump nm)^(line_type2c clt)
   | PC.TMetaType(_,_,clt)    -> "typemeta"^(line_type2c clt)
   | PC.TMetaInit(_,_,clt)    -> "initmeta"^(line_type2c clt)
-  | PC.TMetaStm(_,_,clt)   -> "stmmeta"^(line_type2c clt)
-  | PC.TMetaStmList(_,_,clt)   -> "stmlistmeta"^(line_type2c clt)
+  | PC.TMetaInitList(_,_,_,clt)    -> "initlistmeta"^(line_type2c clt)
+  | PC.TMetaDecl(_,_,clt)    -> "declmeta"^(line_type2c clt)
+  | PC.TMetaField(_,_,clt)   -> "fieldmeta"^(line_type2c clt)
+  | PC.TMetaFieldList(_,_,_,clt)   -> "fieldlistmeta"^(line_type2c clt)
+  | PC.TMetaStm(_,_,clt)     -> "stmmeta"^(line_type2c clt)
+  | PC.TMetaStmList(_,_,clt) -> "stmlistmeta"^(line_type2c clt)
   | PC.TMetaFunc(_,_,_,clt)  -> "funcmeta"^(line_type2c clt)
   | PC.TMetaLocalFunc(_,_,_,clt) -> "funcmeta"^(line_type2c clt)
   | PC.TMetaPos(_,_,_,clt)   -> "posmeta"
   | PC.TMPtVirg -> ";"
   | PC.TArobArob -> "@@"
   | PC.TArob -> "@"
-  | PC.TPArob -> "P@"
+  | PC.TPArob clt -> "P@"
   | PC.TScript -> "script"
   | PC.TInitialize -> "initialize"
   | PC.TFinalize -> "finalize"
@@ -262,14 +290,16 @@ let token2c (tok,_) =
   | PC.TIsoExpression -> "Expression"
   | PC.TIsoArgExpression -> "ArgExpression"
   | PC.TIsoTestExpression -> "TestExpression"
+  | PC.TIsoToTestExpression -> "ToTestExpression"
   | PC.TIsoStatement -> "Statement"
   | PC.TIsoDeclaration -> "Declaration"
   | PC.TIsoType -> "Type"
+  | PC.TUnderscore -> "_"
   | PC.TScriptData s -> s
 
 let print_tokens s tokens =
   Printf.printf "%s\n" s;
-  List.iter (function x -> Printf.printf "%s " (token2c x)) tokens;
+  List.iter (function x -> Printf.printf "|%s| " (token2c x)) tokens;
   Printf.printf "\n\n";
   flush stdout
 
@@ -278,14 +308,17 @@ type plus = PLUS | NOTPLUS | SKIP
 let plus_attachable only_plus (tok,_) =
   match tok with
     PC.Tchar(clt) | PC.Tshort(clt) | PC.Tint(clt) | PC.Tdouble(clt)
-  | PC.Tfloat(clt) | PC.Tlong(clt) | PC.Tvoid(clt) | PC.Tstruct(clt)
+  | PC.Tfloat(clt) | PC.Tlong(clt)
+  | PC.Tsize_t(clt) | PC.Tssize_t(clt) | PC.Tptrdiff_t(clt)
+  | PC.Tstruct(clt)
   | PC.Tunion(clt) | PC.Tenum(clt) | PC.Tunsigned(clt) | PC.Tsigned(clt)
   | PC.Tstatic(clt)
   | PC.Tinline(clt) | PC.Ttypedef(clt) | PC.Tattr(_,clt)
   | PC.Tauto(clt) | PC.Tregister(clt)
   | PC.Textern(clt) | PC.Tconst(clt) | PC.Tvolatile(clt)
 
-  | PC.TIncludeL(_,clt) | PC.TIncludeNL(_,clt) | PC.TDefine(clt,_)
+  | PC.TIncludeL(_,clt) | PC.TIncludeNL(_,clt) | PC.TUndef(clt,_)
+  | PC.TDefine(clt,_)
   | PC.TDefineParam(clt,_,_,_) | PC.TMinusFile(_,clt) | PC.TPlusFile(_,clt)
 
   | PC.TInc(clt) | PC.TDec(clt)
@@ -300,23 +333,31 @@ let plus_attachable only_plus (tok,_) =
   | PC.TString(_,clt) | PC.TChar(_,clt) | PC.TFloat(_,clt) | PC.TInt(_,clt)
 
   | PC.TOrLog(clt) | PC.TAndLog(clt) | PC.TOr(clt) | PC.TXor(clt)
-  | PC.TAnd (clt) | PC.TEqEq(clt) | PC.TNotEq(clt) | PC.TLogOp(_,clt)
-  | PC.TShOp(_,clt) | PC.TPlus(clt) | PC.TMinus(clt) | PC.TMul(clt)
+  | PC.TAnd (clt) | PC.TEqEq(clt) | PC.TNotEq(clt) | PC.TTildeEq(clt)
+  | PC.TLogOp(_,clt)
+  | PC.TShLOp(_,clt) | PC.TShROp(_,clt)
+  | PC.TPlus(clt) | PC.TMinus(clt) | PC.TMul(clt)
   | PC.TDmOp(_,clt) | PC.TTilde (clt)
 
-  | PC.TMetaParam(_,_,clt) | PC.TMetaParamList(_,_,_,clt)
+  | PC.TMeta(_,_,clt) | PC.TMetaParam(_,_,clt) | PC.TMetaParamList(_,_,_,clt)
   | PC.TMetaConst(_,_,_,_,clt) | PC.TMetaErr(_,_,_,clt)
   | PC.TMetaExp(_,_,_,_,clt) | PC.TMetaIdExp(_,_,_,_,clt)
   | PC.TMetaLocalIdExp(_,_,_,_,clt)
   | PC.TMetaExpList(_,_,_,clt)
-  | PC.TMetaId(_,_,_,clt)
-  | PC.TMetaType(_,_,clt) | PC.TMetaInit(_,_,clt) | PC.TMetaStm(_,_,clt)
-  | PC.TMetaStmList(_,_,clt)  | PC.TMetaFunc(_,_,_,clt)
-  | PC.TMetaLocalFunc(_,_,_,clt)
+  | PC.TMetaId(_,_,_,_,clt)
+  | PC.TMetaType(_,_,clt) | PC.TMetaInit(_,_,clt) | PC.TMetaInitList(_,_,_,clt)
+  | PC.TMetaStm(_,_,clt)
+  | PC.TMetaStmList(_,_,clt)
+  | PC.TMetaDecl(_,_,clt) | PC.TMetaField(_,_,clt)
+  | PC.TMetaFieldList(_,_,_,clt)
+  | PC.TMetaFunc(_,_,_,clt) | PC.TMetaLocalFunc(_,_,_,clt)
 
   | PC.TWhen(clt) |  PC.TWhenTrue(clt) |  PC.TWhenFalse(clt)
   | PC.TAny(clt) | PC.TStrict(clt) | PC.TEllipsis(clt)
   (* | PC.TCircles(clt) | PC.TStars(clt) *)
+  | PC.TOEllipsis(clt) | PC.TCEllipsis(clt)
+  | PC.TPOEllipsis(clt) | PC.TPCEllipsis(clt) (* | PC.TOCircles(clt)
+  | PC.TCCircles(clt) | PC.TOStars(clt) | PC.TCStars(clt) *)
 
   | PC.TWhy(clt) | PC.TDotDot(clt) | PC.TBang(clt) | PC.TOPar(clt)
   | PC.TCPar(clt)
@@ -328,29 +369,30 @@ let plus_attachable only_plus (tok,_) =
 
   | PC.TEq(clt) | PC.TAssign(_,clt) | PC.TDot(clt) | PC.TComma(clt)
   | PC.TPtVirg(clt) ->
-      if line_type clt = D.PLUS
+      if List.mem (line_type clt) [D.PLUS;D.PLUSPLUS]
       then PLUS
       else if only_plus then NOTPLUS
       else if line_type clt = D.CONTEXT then PLUS else NOTPLUS
 
-  | PC.TOPar0(clt) | PC.TMid0(clt) | PC.TCPar0(clt)
-  | PC.TOEllipsis(clt) | PC.TCEllipsis(clt)
-  | PC.TPOEllipsis(clt) | PC.TPCEllipsis(clt) (* | PC.TOCircles(clt)
-  | PC.TCCircles(clt) | PC.TOStars(clt) | PC.TCStars(clt) *) -> NOTPLUS
+  | PC.TOPar0(clt) | PC.TMid0(clt) | PC.TCPar0(clt) -> NOTPLUS
   | PC.TMetaPos(nm,_,_,_) -> NOTPLUS
+  | PC.TSub(clt) -> NOTPLUS
 
   | _ -> SKIP
 
 let get_clt (tok,_) =
   match tok with
     PC.Tchar(clt) | PC.Tshort(clt) | PC.Tint(clt) | PC.Tdouble(clt)
-  | PC.Tfloat(clt) | PC.Tlong(clt) | PC.Tvoid(clt) | PC.Tstruct(clt)
+  | PC.Tfloat(clt) | PC.Tlong(clt) | PC.Tvoid(clt)
+  | PC.Tsize_t(clt) | PC.Tssize_t(clt) | PC.Tptrdiff_t(clt)
+  | PC.Tstruct(clt)
   | PC.Tunion(clt) | PC.Tenum(clt) | PC.Tunsigned(clt) | PC.Tsigned(clt)
   | PC.Tstatic(clt)
   | PC.Tinline(clt) | PC.Tattr(_,clt) | PC.Tauto(clt) | PC.Tregister(clt)
   | PC.Textern(clt) | PC.Tconst(clt) | PC.Tvolatile(clt)
 
-  | PC.TIncludeL(_,clt) | PC.TIncludeNL(_,clt) | PC.TDefine(clt,_)
+  | PC.TIncludeL(_,clt) | PC.TIncludeNL(_,clt) | PC.TUndef(clt,_)
+  | PC.TDefine(clt,_)
   | PC.TDefineParam(clt,_,_,_) | PC.TMinusFile(_,clt) | PC.TPlusFile(_,clt)
 
   | PC.TInc(clt) | PC.TDec(clt)
@@ -358,26 +400,34 @@ let get_clt (tok,_) =
   | PC.TIf(clt) | PC.TElse(clt) | PC.TWhile(clt) | PC.TFor(clt) | PC.TDo(clt)
   | PC.TSwitch(clt) | PC.TCase(clt) | PC.TDefault(clt) | PC.TReturn(clt)
   | PC.TBreak(clt) | PC.TContinue(clt) | PC.TGoto(clt) | PC.TIdent(_,clt)
-  | PC.TTypeId(_,clt) | PC.TDeclarerId(_,clt) | PC.TIteratorId(_,clt)
-
+  | PC.TTypeId(_,clt) | PC.TSymId(_,clt)
+  | PC.TDeclarerId(_,clt) | PC.TIteratorId(_,clt)
+  
   | PC.TSizeof(clt)
 
   | PC.TString(_,clt) | PC.TChar(_,clt) | PC.TFloat(_,clt) | PC.TInt(_,clt)
 
   | PC.TOrLog(clt) | PC.TAndLog(clt) | PC.TOr(clt) | PC.TXor(clt)
-  | PC.TAnd (clt) | PC.TEqEq(clt) | PC.TNotEq(clt) | PC.TLogOp(_,clt)
-  | PC.TShOp(_,clt) | PC.TPlus(clt) | PC.TMinus(clt) | PC.TMul(clt)
+  | PC.TAnd (clt) | PC.TEqEq(clt) | PC.TNotEq(clt) | PC.TTildeEq(clt)
+  | PC.TSub(clt) | PC.TLogOp(_,clt)
+  | PC.TShLOp(_,clt) | PC.TShROp(_,clt)
+  | PC.TPlus(clt) | PC.TMinus(clt) | PC.TMul(clt)
   | PC.TDmOp(_,clt) | PC.TTilde (clt)
 
-  | PC.TMetaParam(_,_,clt) | PC.TMetaParamList(_,_,_,clt)
+  | PC.TMeta(_,_,clt) | PC.TMetaParam(_,_,clt) | PC.TMetaParamList(_,_,_,clt)
   | PC.TMetaConst(_,_,_,_,clt) | PC.TMetaErr(_,_,_,clt)
   | PC.TMetaExp(_,_,_,_,clt) | PC.TMetaIdExp(_,_,_,_,clt)
   | PC.TMetaLocalIdExp(_,_,_,_,clt)
   | PC.TMetaExpList(_,_,_,clt)
-  | PC.TMetaId(_,_,_,clt)
-  | PC.TMetaType(_,_,clt) | PC.TMetaInit(_,_,clt) | PC.TMetaStm(_,_,clt)
-  | PC.TMetaStmList(_,_,clt)  | PC.TMetaFunc(_,_,_,clt)
-  | PC.TMetaLocalFunc(_,_,_,clt) | PC.TMetaPos(_,_,_,clt)
+  | PC.TMetaId(_,_,_,_,clt)
+  | PC.TMetaType(_,_,clt) | PC.TMetaInit(_,_,clt) | PC.TMetaInitList(_,_,_,clt)
+  | PC.TMetaStm(_,_,clt)
+  | PC.TMetaStmList(_,_,clt)
+  | PC.TMetaDecl(_,_,clt) | PC.TMetaField(_,_,clt)
+  | PC.TMetaFieldList(_,_,_,clt)
+  | PC.TMetaFunc(_,_,_,clt) | PC.TMetaLocalFunc(_,_,_,clt)
+  | PC.TMetaPos(_,_,_,clt)
+  | PC.TMetaDeclarer(_,_,_,clt) | PC.TMetaIterator(_,_,_,clt)
 
   | PC.TWhen(clt) | PC.TWhenTrue(clt) | PC.TWhenFalse(clt) |
     PC.TAny(clt) | PC.TStrict(clt) | PC.TEllipsis(clt)
@@ -392,7 +442,7 @@ let get_clt (tok,_) =
   | PC.TPtrOp(clt)
 
   | PC.TEq(clt) | PC.TAssign(_,clt) | PC.TDot(clt) | PC.TComma(clt)
-  | PC.TPtVirg(clt)
+  | PC.TPArob(clt) | PC.TPtVirg(clt)
 
   | PC.TOPar0(clt) | PC.TMid0(clt) | PC.TCPar0(clt)
   | PC.TOEllipsis(clt) | PC.TCEllipsis(clt)
@@ -410,6 +460,9 @@ let update_clt (tok,x) clt =
   | PC.Tfloat(_) -> (PC.Tfloat(clt),x)
   | PC.Tlong(_) -> (PC.Tlong(clt),x)
   | PC.Tvoid(_) -> (PC.Tvoid(clt),x)
+  | PC.Tsize_t(_) -> (PC.Tsize_t(clt),x)
+  | PC.Tssize_t(_) -> (PC.Tssize_t(clt),x)
+  | PC.Tptrdiff_t(_) -> (PC.Tptrdiff_t(clt),x)
   | PC.Tstruct(_) -> (PC.Tstruct(clt),x)
   | PC.Tunion(_) -> (PC.Tunion(clt),x)
   | PC.Tenum(_) -> (PC.Tenum(clt),x)
@@ -427,6 +480,7 @@ let update_clt (tok,x) clt =
 
   | PC.TIncludeL(s,_) -> (PC.TIncludeL(s,clt),x)
   | PC.TIncludeNL(s,_) -> (PC.TIncludeNL(s,clt),x)
+  | PC.TUndef(_,a) -> (PC.TUndef(clt,a),x)
   | PC.TDefine(_,a) -> (PC.TDefine(clt,a),x)
   | PC.TDefineParam(_,a,b,c) -> (PC.TDefineParam(clt,a,b,c),x)
   | PC.TMinusFile(s,_) -> (PC.TMinusFile(s,clt),x)
@@ -451,6 +505,7 @@ let update_clt (tok,x) clt =
   | PC.TTypeId(s,_) -> (PC.TTypeId(s,clt),x)
   | PC.TDeclarerId(s,_) -> (PC.TDeclarerId(s,clt),x)
   | PC.TIteratorId(s,_) -> (PC.TIteratorId(s,clt),x)
+  | PC.TSymId(a,_) -> (PC.TSymId(a,clt),x)
 
   | PC.TSizeof(_) -> (PC.TSizeof(clt),x)
 
@@ -466,14 +521,18 @@ let update_clt (tok,x) clt =
   | PC.TAnd (_) -> (PC.TAnd (clt),x)
   | PC.TEqEq(_) -> (PC.TEqEq(clt),x)
   | PC.TNotEq(_) -> (PC.TNotEq(clt),x)
+  | PC.TTildeEq(_) -> (PC.TTildeEq(clt),x)
+  | PC.TSub(_) -> (PC.TSub(clt),x)
   | PC.TLogOp(op,_) -> (PC.TLogOp(op,clt),x)
-  | PC.TShOp(op,_) -> (PC.TShOp(op,clt),x)
+  | PC.TShLOp(op,_) -> (PC.TShLOp(op,clt),x)
+  | PC.TShROp(op,_) -> (PC.TShROp(op,clt),x)
   | PC.TPlus(_) -> (PC.TPlus(clt),x)
   | PC.TMinus(_) -> (PC.TMinus(clt),x)
   | PC.TMul(_) -> (PC.TMul(clt),x)
   | PC.TDmOp(op,_) -> (PC.TDmOp(op,clt),x)
   | PC.TTilde (_) -> (PC.TTilde (clt),x)
 
+  | PC.TMeta(a,b,_)      -> (PC.TMeta(a,b,clt),x)
   | PC.TMetaParam(a,b,_) -> (PC.TMetaParam(a,b,clt),x)
   | PC.TMetaParamList(a,b,c,_) -> (PC.TMetaParamList(a,b,c,clt),x)
   | PC.TMetaConst(a,b,c,d,_) -> (PC.TMetaConst(a,b,c,d,clt),x)
@@ -482,14 +541,21 @@ let update_clt (tok,x) clt =
   | PC.TMetaIdExp(a,b,c,d,_) -> (PC.TMetaIdExp(a,b,c,d,clt),x)
   | PC.TMetaLocalIdExp(a,b,c,d,_) -> (PC.TMetaLocalIdExp(a,b,c,d,clt),x)
   | PC.TMetaExpList(a,b,c,_) -> (PC.TMetaExpList(a,b,c,clt),x)
-  | PC.TMetaId(a,b,c,_)    -> (PC.TMetaId(a,b,c,clt),x)
+  | PC.TMetaId(a,b,c,d,_)    -> (PC.TMetaId(a,b,c,d,clt),x)
   | PC.TMetaType(a,b,_)    -> (PC.TMetaType(a,b,clt),x)
   | PC.TMetaInit(a,b,_)    -> (PC.TMetaInit(a,b,clt),x)
-  | PC.TMetaStm(a,b,_)   -> (PC.TMetaStm(a,b,clt),x)
-  | PC.TMetaStmList(a,b,_)   -> (PC.TMetaStmList(a,b,clt),x)
+  | PC.TMetaInitList(a,b,c,_) -> (PC.TMetaInitList(a,b,c,clt),x)
+  | PC.TMetaDecl(a,b,_)    -> (PC.TMetaDecl(a,b,clt),x)
+  | PC.TMetaField(a,b,_)   -> (PC.TMetaField(a,b,clt),x)
+  | PC.TMetaFieldList(a,b,c,_)   -> (PC.TMetaFieldList(a,b,c,clt),x)
+  | PC.TMetaStm(a,b,_)     -> (PC.TMetaStm(a,b,clt),x)
+  | PC.TMetaStmList(a,b,_) -> (PC.TMetaStmList(a,b,clt),x)
   | PC.TMetaFunc(a,b,c,_)  -> (PC.TMetaFunc(a,b,c,clt),x)
   | PC.TMetaLocalFunc(a,b,c,_) -> (PC.TMetaLocalFunc(a,b,c,clt),x)
 
+  | PC.TMetaDeclarer(a,b,c,_) -> (PC.TMetaDeclarer(a,b,c,clt),x)
+  | PC.TMetaIterator(a,b,c,_) -> (PC.TMetaIterator(a,b,c,clt),x)
+
   | PC.TWhen(_) -> (PC.TWhen(clt),x)
   | PC.TWhenTrue(_) -> (PC.TWhenTrue(clt),x)
   | PC.TWhenFalse(_) -> (PC.TWhenFalse(clt),x)
@@ -533,6 +599,7 @@ let update_clt (tok,x) clt =
   | PC.TAssign(s,_) -> (PC.TAssign(s,clt),x)
   | PC.TDot(_) -> (PC.TDot(clt),x)
   | PC.TComma(_) -> (PC.TComma(clt),x)
+  | PC.TPArob(_) -> (PC.TPArob(clt),x)
   | PC.TPtVirg(_) -> (PC.TPtVirg(clt),x)
 
   | PC.TLineEnd(_) -> (PC.TLineEnd(clt),x)
@@ -551,7 +618,7 @@ let make_name prefix ln = Printf.sprintf "%s starting on line %d" prefix ln
 let wrap_lexbuf_info lexbuf =
   (Lexing.lexeme lexbuf, Lexing.lexeme_start lexbuf)
 
-let tokens_all_full token table file get_ats lexbuf end_markers :
+let tokens_all_full token table file get_ats lexbuf end_predicate :
     (bool * ((PC.token * (string * (int * int) * (int * int))) list)) =
   try
     let rec aux () =
@@ -564,7 +631,7 @@ let tokens_all_full token table file get_ats lexbuf end_markers :
        if get_ats
        then failwith "unexpected end of file in a metavariable declaration"
        else (false,[(result,info)])
-      else if List.mem result end_markers
+      else if end_predicate result
       then (true,[(result,info)])
       else
        let (more,rest) = aux() in
@@ -573,6 +640,9 @@ let tokens_all_full token table file get_ats lexbuf end_markers :
   with
     e -> pr2 (Common.error_message file (wrap_lexbuf_info lexbuf) ); raise e
 
+let in_list list tok =
+  List.mem tok list
+
 let tokens_all table file get_ats lexbuf end_markers :
     (bool * ((PC.token * (string * (int * int) * (int * int))) list)) =
   tokens_all_full Lexer_cocci.token table file get_ats lexbuf end_markers
@@ -588,23 +658,27 @@ let split t clt =
   let (d,_,_,_,_,_,_,_) = clt in
   match d with
     D.MINUS | D.OPTMINUS | D.UNIQUEMINUS -> ([t],[])
-  | D.PLUS -> ([],[t])
+  | D.PLUS | D.PLUSPLUS -> ([],[t])
   | D.CONTEXT | D.UNIQUE | D.OPT -> ([t],[t])
 
 let split_token ((tok,_) as t) =
   match tok with
-    PC.TIdentifier | PC.TConstant | PC.TExpression | PC.TIdExpression
-  | PC.TStatement | PC.TPosition | PC.TPosAny | PC.TInitialiser
+    PC.TMetavariable | PC.TIdentifier
+  | PC.TConstant | PC.TExpression | PC.TIdExpression
+  | PC.TDeclaration | PC.TField
+  | PC.TStatement | PC.TPosition | PC.TAnalysis | PC.TPosAny | PC.TInitialiser | PC.TSymbol
   | PC.TFunction | PC.TTypedef | PC.TDeclarer | PC.TIterator | PC.TName
   | PC.TType | PC.TParameter | PC.TLocal | PC.Tlist | PC.TFresh
   | PC.TCppConcatOp | PC.TPure
-  | PC.TContext | PC.TRuleName(_) | PC.TUsing | PC.TDisable | PC.TExtends
-  | PC.TPathIsoFile(_)
+  | PC.TContext | PC.TRuleName(_) | PC.TUsing | PC.TVirtual | PC.TDisable
+  | PC.TExtends | PC.TPathIsoFile(_)
   | PC.TDepends | PC.TOn | PC.TEver | PC.TNever | PC.TExists | PC.TForall
   | PC.TError | PC.TWords | PC.TGenerated | PC.TNothing -> ([t],[t])
 
   | PC.Tchar(clt) | PC.Tshort(clt) | PC.Tint(clt) | PC.Tdouble(clt)
-  | PC.Tfloat(clt) | PC.Tlong(clt) | PC.Tvoid(clt) | PC.Tstruct(clt)
+  | PC.Tfloat(clt) | PC.Tlong(clt) | PC.Tvoid(clt)
+  | PC.Tsize_t(clt) | PC.Tssize_t(clt) | PC.Tptrdiff_t(clt)
+  | PC.Tstruct(clt)
   | PC.Tunion(clt) | PC.Tenum(clt) | PC.Tunsigned(clt) | PC.Tsigned(clt)
   | PC.Tstatic(clt) | PC.Tauto(clt) | PC.Tregister(clt) | PC.Textern(clt)
   | PC.Tinline(clt) | PC.Ttypedef(clt) | PC.Tattr(_,clt)
@@ -614,7 +688,8 @@ let split_token ((tok,_) as t) =
   | PC.TPlusFile(s,clt) | PC.TMinusFile(s,clt)
   | PC.TIncludeL(s,clt) | PC.TIncludeNL(s,clt) ->
       split t clt
-  | PC.TDefine(clt,_) | PC.TDefineParam(clt,_,_,_) -> split t clt
+  | PC.TUndef(clt,_) | PC.TDefine(clt,_) | PC.TDefineParam(clt,_,_,_) ->
+      split t clt
 
   | PC.TIf(clt) | PC.TElse(clt)  | PC.TWhile(clt) | PC.TFor(clt) | PC.TDo(clt)
   | PC.TSwitch(clt) | PC.TCase(clt) | PC.TDefault(clt)
@@ -622,29 +697,34 @@ let split_token ((tok,_) as t) =
   | PC.TReturn(clt) | PC.TBreak(clt) | PC.TContinue(clt) | PC.TGoto(clt)
   | PC.TIdent(_,clt)
   | PC.TTypeId(_,clt) | PC.TDeclarerId(_,clt) | PC.TIteratorId(_,clt)
-  | PC.TMetaConst(_,_,_,_,clt) | PC.TMetaExp(_,_,_,_,clt)
+  | PC.TSymId(_,clt)
+  | PC.TMeta(_,_,clt) | PC.TMetaConst(_,_,_,_,clt) | PC.TMetaExp(_,_,_,_,clt)
   | PC.TMetaIdExp(_,_,_,_,clt) | PC.TMetaLocalIdExp(_,_,_,_,clt)
   | PC.TMetaExpList(_,_,_,clt)
   | PC.TMetaParam(_,_,clt) | PC.TMetaParamList(_,_,_,clt)
-  | PC.TMetaId(_,_,_,clt) | PC.TMetaType(_,_,clt) | PC.TMetaInit(_,_,clt)
+  | PC.TMetaId(_,_,_,_,clt) | PC.TMetaType(_,_,clt)
+  | PC.TMetaInit(_,_,clt) | PC.TMetaInitList(_,_,_,clt)
+  | PC.TMetaDecl(_,_,clt) | PC.TMetaField(_,_,clt)
+  | PC.TMetaFieldList(_,_,_,clt)
   | PC.TMetaStm(_,_,clt) | PC.TMetaStmList(_,_,clt) | PC.TMetaErr(_,_,_,clt)
   | PC.TMetaFunc(_,_,_,clt) | PC.TMetaLocalFunc(_,_,_,clt)
   | PC.TMetaDeclarer(_,_,_,clt) | PC.TMetaIterator(_,_,_,clt) -> split t clt
   | PC.TMPtVirg | PC.TArob | PC.TArobArob | PC.TScript
   | PC.TInitialize | PC.TFinalize -> ([t],[t])
-  | PC.TPArob | PC.TMetaPos(_,_,_,_) -> ([t],[])
+  | PC.TPArob clt | PC.TMetaPos(_,_,_,clt) -> split t clt
 
   | PC.TFunDecl(clt)
   | PC.TWhen(clt) | PC.TWhenTrue(clt) | PC.TWhenFalse(clt)
   | PC.TAny(clt) | PC.TStrict(clt) | PC.TLineEnd(clt)
-  | PC.TEllipsis(clt) (* | PC.TCircles(clt) | PC.TStars(clt) *) -> split t clt
+  | PC.TEllipsis(clt) (* | PC.TCircles(clt) | PC.TStars(clt) *)
+  | PC.TOEllipsis(clt) | PC.TCEllipsis(clt)
+  | PC.TPOEllipsis(clt) | PC.TPCEllipsis(clt) -> split t clt
 
-  | PC.TOEllipsis(_) | PC.TCEllipsis(_) (* clt must be context *)
-  | PC.TPOEllipsis(_) | PC.TPCEllipsis(_) (* clt must be context *)
 (*
   | PC.TOCircles(_) | PC.TCCircles(_)   (* clt must be context *)
   | PC.TOStars(_) | PC.TCStars(_)       (* clt must be context *)
 *)
+
   | PC.TBang0 | PC.TPlus0 | PC.TWhy0 ->
       ([t],[t])
 
@@ -658,8 +738,10 @@ let split_token ((tok,_) as t) =
       split t clt
 
   | PC.TOrLog(clt) | PC.TAndLog(clt) | PC.TOr(clt) | PC.TXor(clt)
-  | PC.TAnd (clt) | PC.TEqEq(clt) | PC.TNotEq(clt) | PC.TLogOp(_,clt)
-  | PC.TShOp(_,clt) | PC.TPlus(clt) | PC.TMinus(clt) | PC.TMul(clt)
+  | PC.TAnd (clt) | PC.TEqEq(clt) | PC.TNotEq(clt) | PC.TTildeEq(clt)
+  | PC.TTildeExclEq(clt) | PC.TSub(clt) | PC.TLogOp(_,clt)
+  | PC.TShLOp(_,clt) | PC.TShROp(_,clt)
+  | PC.TPlus(clt) | PC.TMinus(clt) | PC.TMul(clt)
   | PC.TDmOp(_,clt) | PC.TTilde (clt) -> split t clt
 
   | PC.TOBrace(clt) | PC.TCBrace(clt) | PC.TOInit(clt) -> split t clt
@@ -670,11 +752,12 @@ let split_token ((tok,_) as t) =
   | PC.TEq(clt) | PC.TAssign(_,clt) | PC.TDot(clt) | PC.TComma(clt)
   | PC.TPtVirg(clt) -> split t clt
 
-  | PC.EOF | PC.TInvalid -> ([t],[t])
+  | PC.EOF | PC.TInvalid | PC.TUnderscore -> ([t],[t])
 
   | PC.TIso | PC.TRightIso
   | PC.TIsoExpression | PC.TIsoStatement | PC.TIsoDeclaration | PC.TIsoType
-  | PC.TIsoTopLevel | PC.TIsoArgExpression | PC.TIsoTestExpression ->
+  | PC.TIsoTopLevel | PC.TIsoArgExpression | PC.TIsoTestExpression
+  | PC.TIsoToTestExpression ->
       failwith "unexpected tokens"
   | PC.TScriptData s -> ([t],[t])
 
@@ -694,35 +777,77 @@ distinguish a function declaration from a function call even if the latter
 has no return type.  Undoubtedly, this is not very nice, but it doesn't
 seem very convenient to refactor the grammar to get around the problem. *)
 
-let rec find_function_names = function
-    [] -> []
-  | ((PC.TIdent(_,clt),info) as t1) :: ((PC.TOPar(_),_) as t2) :: rest
-  | ((PC.TMetaId(_,_,_,clt),info) as t1) :: ((PC.TOPar(_),_) as t2) :: rest
-  | ((PC.TMetaFunc(_,_,_,clt),info) as t1) :: ((PC.TOPar(_),_) as t2) :: rest
-  | ((PC.TMetaLocalFunc(_,_,_,clt),info) as t1)::((PC.TOPar(_),_) as t2)::rest
-    ->
-      let rec skip level = function
-         [] -> ([],false,[])
-       | ((PC.TCPar(_),_) as t)::rest ->
-           let level = level - 1 in
-           if level = 0
-           then ([t],true,rest)
-           else let (pre,found,post) = skip level rest in (t::pre,found,post)
-       | ((PC.TOPar(_),_) as t)::rest ->
-           let level = level + 1 in
-           let (pre,found,post) = skip level rest in (t::pre,found,post)
-       | ((PC.TArobArob,_) as t)::rest
-       | ((PC.TArob,_) as t)::rest
-       | ((PC.EOF,_) as t)::rest -> ([t],false,rest)
-       | t::rest ->
-           let (pre,found,post) = skip level rest in (t::pre,found,post) in
-      let (pre,found,post) = skip 1 rest in
-      (match (found,post) with
-       (true,((PC.TOBrace(_),_) as t3)::rest) ->
-         (PC.TFunDecl(clt),info) :: t1 :: t2 :: pre @
-         t3 :: (find_function_names rest)
-      |        _ -> t1 :: t2 :: pre @ find_function_names post)
-  | t :: rest -> t :: find_function_names rest
+exception Irrelevant
+
+let rec find_function_names l =
+  let is_ident = function
+      (PC.TIdent(_,clt),info)
+    | (PC.TMeta(_,_,clt),info)
+    | (PC.TMetaId(_,_,_,_,clt),info)
+    | (PC.TMetaFunc(_,_,_,clt),info)
+    | (PC.TMetaLocalFunc(_,_,_,clt),info) -> true
+    | _ -> false in
+  let is_mid = function
+      (PC.TMid0(_),info) -> true
+    | _ -> false in
+  let is_par = function
+      (PC.TOPar0(_),info) -> true
+    | _ -> false in
+  let rec split acc = function
+      [] | [_] -> raise Irrelevant
+    | ((PC.TCPar(_),_) as t1) :: ((PC.TOBrace(_),_) as t2) :: rest ->
+       (List.rev (t1::acc),(t2::rest))
+    | x::xs -> split (x::acc) xs in
+  let rec balanced_name level = function
+      [] -> raise Irrelevant
+    | (PC.TCPar0(_),_)::rest ->
+       let level = level - 1 in
+       if level = 0
+       then rest
+       else balanced_name level rest
+    | (PC.TOPar0(_),_)::rest ->
+       let level = level + 1 in
+       balanced_name level rest
+    | (PC.TArobArob,_)::_ | (PC.TArob,_)::_ | (PC.EOF,_)::_ ->
+       raise Irrelevant
+    | t::rest when is_ident t && level = 0 -> rest
+    | t::rest when is_ident t or is_mid t -> balanced_name level rest
+    | _ -> raise Irrelevant in
+  let rec balanced_args level = function
+      [] -> raise Irrelevant
+    | (PC.TCPar(_),_)::rest ->
+       let level = level - 1 in
+       if level = 0
+       then rest
+       else balanced_args level rest
+    | (PC.TOPar(_),_)::rest ->
+       let level = level + 1 in
+       balanced_args level rest
+    | (PC.TArobArob,_)::_ | (PC.TArob,_)::_ | (PC.EOF,_)::_ ->
+       raise Irrelevant
+    | t::rest -> balanced_args level rest in
+  let rec loop = function
+      [] -> []
+    | t :: rest ->
+       if is_par t or is_mid t or is_ident t
+       then
+         let (t,rest) =
+           try
+             let (bef,aft) = split [] (t::rest) in
+             let rest = balanced_name 0 bef in
+             (match rest with
+               (PC.TOPar(_),_)::_ ->
+                 (match balanced_args 0 rest with
+                   [] ->
+                     let (_,info) as h = List.hd bef in
+                     let clt = get_clt h in
+                     (((PC.TFunDecl(clt),info) :: bef), aft)
+                 | _ -> raise Irrelevant)
+             | _ -> raise Irrelevant)
+           with Irrelevant -> ([t],rest) in
+         t @ (loop rest)
+       else t :: (loop rest) in
+  loop l
 
 (* ----------------------------------------------------------------------- *)
 (* an attribute is an identifier that preceeds another identifier and
@@ -730,12 +855,16 @@ let rec find_function_names = function
 
 let rec detect_attr l =
   let is_id = function
-      (PC.TIdent(_,_),_) | (PC.TMetaId(_,_,_,_),_) | (PC.TMetaFunc(_,_,_,_),_)
+      (PC.TIdent(_,_),_) | (PC.TMetaId(_,_,_,_,_),_) | (PC.TMetaFunc(_,_,_,_),_)
     | (PC.TMetaLocalFunc(_,_,_,_),_) -> true
     | _ -> false in
   let rec loop = function
       [] -> []
     | [x] -> [x]
+    | ((PC.Tstruct _,_) as t1)::x::rest ->
+       t1::x::loop rest
+    | ((PC.Tunion _,_) as t1)::x::rest ->
+       t1::x::loop rest
     | ((PC.TIdent(nm,clt),info) as t1)::id::rest when is_id id ->
        if String.length nm > 2 && String.sub nm 0 2 = "__"
        then (PC.Tattr(nm,clt),info)::(loop (id::rest))
@@ -766,7 +895,7 @@ let detect_types in_meta_decls l =
   let is_choices_delim = function
       (PC.TOBrace(_),_) | (PC.TComma(_),_) -> true | _ -> false in
   let is_id = function
-      (PC.TIdent(_,_),_) | (PC.TMetaId(_,_,_,_),_) | (PC.TMetaFunc(_,_,_,_),_)
+      (PC.TIdent(_,_),_) | (PC.TMetaId(_,_,_,_,_),_) | (PC.TMetaFunc(_,_,_,_),_)
     | (PC.TMetaLocalFunc(_,_,_,_),_) -> true
     | (PC.TMetaParam(_,_,_),_)
     | (PC.TMetaParamList(_,_,_,_),_)
@@ -778,6 +907,10 @@ let detect_types in_meta_decls l =
     | (PC.TMetaExpList(_,_,_,_),_)
     | (PC.TMetaType(_,_,_),_)
     | (PC.TMetaInit(_,_,_),_)
+    | (PC.TMetaInitList(_,_,_,_),_)
+    | (PC.TMetaDecl(_,_,_),_)
+    | (PC.TMetaField(_,_,_),_)
+    | (PC.TMetaFieldList(_,_,_,_),_)
     | (PC.TMetaStm(_,_,_),_)
     | (PC.TMetaStmList(_,_,_),_)
     | (PC.TMetaPos(_,_,_,_),_) -> in_meta_decls
@@ -839,7 +972,9 @@ let detect_types in_meta_decls l =
 let token2line (tok,_) =
   match tok with
     PC.Tchar(clt) | PC.Tshort(clt) | PC.Tint(clt) | PC.Tdouble(clt)
-  | PC.Tfloat(clt) | PC.Tlong(clt) | PC.Tvoid(clt) | PC.Tstruct(clt)
+  | PC.Tfloat(clt) | PC.Tlong(clt) | PC.Tvoid(clt)
+  | PC.Tsize_t(clt) | PC.Tssize_t(clt) | PC.Tptrdiff_t(clt)
+  | PC.Tstruct(clt)
   | PC.Tunion(clt) | PC.Tenum(clt) | PC.Tunsigned(clt) | PC.Tsigned(clt)
   | PC.Tstatic(clt) | PC.Tauto(clt) | PC.Tregister(clt) | PC.Textern(clt)
   | PC.Tinline(clt) | PC.Ttypedef(clt) | PC.Tattr(_,clt) | PC.Tconst(clt)
@@ -854,18 +989,24 @@ let token2line (tok,_) =
   | PC.TTypeId(_,clt) | PC.TDeclarerId(_,clt) | PC.TIteratorId(_,clt)
   | PC.TMetaDeclarer(_,_,_,clt) | PC.TMetaIterator(_,_,_,clt)
 
+  | PC.TSymId(_,clt)
+
   | PC.TString(_,clt) | PC.TChar(_,clt) | PC.TFloat(_,clt) | PC.TInt(_,clt)
 
   | PC.TOrLog(clt) | PC.TAndLog(clt) | PC.TOr(clt) | PC.TXor(clt)
   | PC.TAnd (clt) | PC.TEqEq(clt) | PC.TNotEq(clt) | PC.TLogOp(_,clt)
-  | PC.TShOp(_,clt) | PC.TPlus(clt) | PC.TMinus(clt) | PC.TMul(clt)
+  | PC.TShLOp(_,clt) | PC.TShROp(_,clt)
+  | PC.TPlus(clt) | PC.TMinus(clt) | PC.TMul(clt)
   | PC.TDmOp(_,clt) | PC.TTilde (clt)
 
-  | PC.TMetaParam(_,_,clt) | PC.TMetaParamList(_,_,_,clt)
+  | PC.TMeta(_,_,clt) | PC.TMetaParam(_,_,clt) | PC.TMetaParamList(_,_,_,clt)
   | PC.TMetaConst(_,_,_,_,clt) | PC.TMetaExp(_,_,_,_,clt)
   | PC.TMetaIdExp(_,_,_,_,clt) | PC.TMetaLocalIdExp(_,_,_,_,clt)
   | PC.TMetaExpList(_,_,_,clt)
-  | PC.TMetaId(_,_,_,clt) | PC.TMetaType(_,_,clt) | PC.TMetaInit(_,_,clt)
+  | PC.TMetaId(_,_,_,_,clt) | PC.TMetaType(_,_,clt)
+  | PC.TMetaInit(_,_,clt) | PC.TMetaInitList(_,_,_,clt)
+  | PC.TMetaDecl(_,_,clt) | PC.TMetaField(_,_,clt)
+  | PC.TMetaFieldList(_,_,_,clt)
   | PC.TMetaStm(_,_,clt) | PC.TMetaStmList(_,_,clt) | PC.TMetaFunc(_,_,_,clt)
   | PC.TMetaLocalFunc(_,_,_,clt) | PC.TMetaPos(_,_,_,clt)
 
@@ -887,11 +1028,11 @@ let token2line (tok,_) =
 
   | PC.TPtrOp(clt)
 
-  | PC.TDefine(clt,_) | PC.TDefineParam(clt,_,_,_)
+  | PC.TUndef(clt,_) | PC.TDefine(clt,_) | PC.TDefineParam(clt,_,_,_)
   | PC.TIncludeL(_,clt) | PC.TIncludeNL(_,clt)
 
   | PC.TEq(clt) | PC.TAssign(_,clt) | PC.TDot(clt) | PC.TComma(clt)
-  | PC.TPtVirg(clt) ->
+  | PC.TPArob(clt) | PC.TPtVirg(clt) ->
       let (_,line,_,_,_,_,_,_) = clt in Some line
 
   | _ -> None
@@ -900,6 +1041,7 @@ let rec insert_line_end = function
     [] -> []
   | (((PC.TWhen(clt),q) as x)::xs) ->
       x::(find_line_end true (token2line x) clt q xs)
+  | (((PC.TUndef(clt,_),q) as x)::xs)
   | (((PC.TDefine(clt,_),q) as x)::xs)
   | (((PC.TDefineParam(clt,_,_,_),q) as x)::xs) ->
       x::(find_line_end false (token2line x) clt q xs)
@@ -923,8 +1065,8 @@ and find_line_end inwhen line clt q = function
       (PC.TExists,a) :: (find_line_end inwhen line clt q xs)
   | ((PC.TComma(clt),a) as x)::xs when token2line x = line ->
       (PC.TComma(clt),a) :: (find_line_end inwhen line clt q xs)
-  | ((PC.TPArob,a) as x)::xs -> (* no line #, just assume on the same line *)
-      x :: (find_line_end inwhen line clt q xs)
+  | ((PC.TPArob(clt),a) as x)::xs when token2line x = line ->
+      (PC.TPArob(clt),a) :: (find_line_end inwhen line clt q xs)
   | x::xs when token2line x = line -> x :: (find_line_end inwhen line clt q xs)
   | xs -> (PC.TLineEnd(clt),q)::(insert_line_end xs)
 
@@ -938,6 +1080,33 @@ let rec translate_when_true_false = function
 
 (* ----------------------------------------------------------------------- *)
 
+(* In a nest, if the nest is -, all of the nested code must also be -. *)
+let check_nests tokens =
+  let is_minus t =
+    let (line_type,a,b,c,d,e,f,g) = get_clt t in
+    List.mem line_type [D.MINUS;D.OPTMINUS;D.UNIQUEMINUS] in
+  let check_minus t =
+    let clt = try Some(get_clt t) with Failure _ -> None in
+       match clt with
+         Some (line_type,a,b,c,d,e,f,g) ->
+           (match line_type with
+             D.MINUS | D.OPTMINUS | D.UNIQUEMINUS -> t
+           | _ -> failwith "minus token expected")
+       | None -> t in
+  let rec outside = function
+      [] -> []
+    | ((PC.TPOEllipsis(clt),q) as t)::r when is_minus t -> t :: inside 0 r
+    | t::r -> t :: outside r
+  and inside stack = function
+      [] -> failwith "missing nest end"
+    | ((PC.TPCEllipsis(clt),q) as t)::r ->
+       (check_minus t)
+       :: (if stack = 0 then outside r else inside (stack - 1) r)
+    | ((PC.TPOEllipsis(clt),q) as t)::r ->
+       (check_minus t) :: (inside (stack + 1) r)
+    | t :: r -> (check_minus t) :: (inside stack r) in
+  outside tokens
+
 let check_parentheses tokens =
   let clt2line (_,line,_,_,_,_,_,_) = line in
   let rec loop seen_open = function
@@ -954,7 +1123,7 @@ let check_parentheses tokens =
              (Printf.sprintf
                 "unexpected close parenthesis in line %d\n" (clt2line clt))
        | Common.Left _ :: seen_open -> loop seen_open rest
-       | Common.Right open_line :: _ -> 
+       | Common.Right open_line :: _ ->
            failwith
              (Printf.sprintf
                 "disjunction parenthesis in line %d column 0 matched to normal parenthesis on line %d\n" open_line (clt2line clt)))
@@ -965,7 +1134,7 @@ let check_parentheses tokens =
              (Printf.sprintf
                 "unexpected close parenthesis in line %d\n" (clt2line clt))
        | Common.Right _ :: seen_open -> loop seen_open rest
-       | Common.Left open_line :: _ -> 
+       | Common.Left open_line :: _ ->
            failwith
              (Printf.sprintf
                 "normal parenthesis in line %d matched to disjunction parenthesis on line %d column 0\n" open_line (clt2line clt)))
@@ -1035,12 +1204,17 @@ let add_bef = function Some x -> [x] | None -> []
 
 (*skips should be things like line end
 skips is things before pragmas that can't be attached to, pass is things
-after.  pass is used immediately.  skips accumulates. *)
+after.  pass is used immediately.  skips accumulates.
+When stuff is added before some + code, the logical line of the + code
+becomes that of the pragma.  context_neg relies on things that are adjacent
+having sequential logical lines.  Not sure that this is good enough,
+as it might result in later gaps in the logical lines... *)
 let rec process_pragmas bef skips = function
     [] -> add_bef bef @ List.rev skips
   | ((PC.TPragma(s,i),_)::_) as l ->
       let (pragmas,rest) = collect_all_pragmas [] l in
       let (pass,rest0) = collect_pass rest in
+      let (_,_,prag_lline,_,_,_,_,_) = i in
       let (next,rest) =
        match rest0 with [] -> (None,[]) | next::rest -> (Some next,rest) in
       (match (bef,plus_attach true bef,next,plus_attach true next) with
@@ -1049,10 +1223,10 @@ let rec process_pragmas bef skips = function
          (update_clt bef (a,b,c,d,e,strbef,pragmas,pos))::List.rev skips@
          pass@process_pragmas None [] rest0
       |        (_,_,Some next,PLUS) ->
-         let (a,b,c,d,e,strbef,straft,pos) = get_clt next in
+         let (a,b,lline,d,e,strbef,straft,pos) = get_clt next in
          (add_bef bef) @ List.rev skips @ pass @
          (process_pragmas
-            (Some (update_clt next (a,b,c,d,e,pragmas,straft,pos)))
+            (Some (update_clt next (a,b,prag_lline,d,e,pragmas,straft,pos)))
             [] rest)
       |        _ ->
          (match (bef,plus_attach false bef,next,plus_attach false next) with
@@ -1061,10 +1235,11 @@ let rec process_pragmas bef skips = function
              (update_clt bef (a,b,c,d,e,strbef,pragmas,pos))::List.rev skips@
              pass@process_pragmas None [] rest0
          | (_,_,Some next,PLUS) ->
-             let (a,b,c,d,e,strbef,straft,pos) = get_clt next in
+             let (a,b,lline,d,e,strbef,straft,pos) = get_clt next in
              (add_bef bef) @ List.rev skips @ pass @
              (process_pragmas
-                (Some (update_clt next (a,b,c,d,e,pragmas,straft,pos)))
+                (Some
+                   (update_clt next (a,b,prag_lline,d,e,pragmas,straft,pos)))
                 [] rest)
          | _ -> failwith "nothing to attach pragma to"))
   | x::xs ->
@@ -1101,7 +1276,7 @@ let minus_to_nothing l =
       let (d,_,_,_,_,_,_,_) = get_clt tok in
       (match d with
        D.MINUS | D.OPTMINUS | D.UNIQUEMINUS -> true
-      | D.PLUS -> false
+      | D.PLUS | D.PLUSPLUS -> false
       | D.CONTEXT | D.UNIQUE | D.OPT -> false)
     with _ -> false in
   let rec minus_loop = function
@@ -1141,14 +1316,42 @@ let rec drop_double_dots l =
       [] -> []
     | x::rest when any_before prev && any_after x ->
        (PC.TNothing,i)::x::(loop x rest)
+    | ((PC.TComma(_),_) as c)::x::rest when any_before prev && any_after x ->
+       c::(PC.TNothing,i)::x::(loop x rest)
     | x::rest -> x :: (loop x rest) in
   match l with
     [] -> []
   | (x::xs) -> x :: loop x xs
 
-let rec fix f l =
-  let cur = f l in
-  if l = cur then l else fix f cur
+(* ignore uncomparable pcre regular expressions *)
+let strip_for_fix l =
+  List.map
+    (function
+       (PC.TMetaId(nm,_,seed,pure,clt),info) ->
+         (PC.TMetaId(nm,Ast.IdNoConstraint,seed,pure,clt),info)
+      |        (PC.TMetaFunc(nm,_,pure,clt),info) ->
+         (PC.TMetaFunc(nm,Ast.IdNoConstraint,pure,clt),info)
+      |        (PC.TMetaLocalFunc(nm,_,pure,clt),info) ->
+         (PC.TMetaLocalFunc(nm,Ast.IdNoConstraint,pure,clt),info)
+      |        (PC.TMetaErr(nm,_,pure,clt),info) ->
+         (PC.TMetaErr(nm,Ast0.NoConstraint,pure,clt),info)
+      |        (PC.TMetaExp(nm,_,pure,ty,clt),info) ->
+         (PC.TMetaExp(nm,Ast0.NoConstraint,pure,ty,clt),info)
+      |        (PC.TMetaIdExp(nm,_,pure,ty,clt),info) ->
+         (PC.TMetaIdExp(nm,Ast0.NoConstraint,pure,ty,clt),info)
+      |        (PC.TMetaLocalIdExp(nm,_,pure,ty,clt),info) ->
+         (PC.TMetaLocalIdExp(nm,Ast0.NoConstraint,pure,ty,clt),info)
+      |        (PC.TMetaConst(nm,_,pure,ty,clt),info) ->
+         (PC.TMetaConst(nm,Ast0.NoConstraint,pure,ty,clt),info)
+      |        t -> t)
+    l
+
+let fix f l =
+  let rec loop f l stripped_l =
+    let cur = f l in
+    let stripped_cur = strip_for_fix cur in
+    if stripped_l = stripped_cur then l else loop f cur stripped_cur in
+  loop f l (strip_for_fix l)
 
 (* ( | ... | ) also causes parsing problems *)
 
@@ -1188,7 +1391,7 @@ let pop2 l =
 let reinit _ =
   PC.reinit (function _ -> PC.TArobArob (* a handy token *))
     (Lexing.from_function
-       (function buf -> function n -> raise Common.Impossible))
+       (function buf -> function n -> raise (Common.Impossible 157)))
 
 let parse_one str parsefn file toks =
   let all_tokens = ref toks in
@@ -1201,7 +1404,7 @@ let parse_one str parsefn file toks =
 
   let lexbuf_fake =
     Lexing.from_function
-      (function buf -> function n -> raise Common.Impossible)
+      (function buf -> function n -> raise (Common.Impossible 158))
   in
 
   reinit();
@@ -1228,29 +1431,122 @@ let prepare_tokens tokens =
     (translate_when_true_false (* after insert_line_end *)
        (insert_line_end
          (detect_types false
-            (find_function_names (detect_attr (check_parentheses tokens))))))
+            (find_function_names
+               (detect_attr
+                  (check_nests
+                     (check_parentheses tokens)))))))
 
 let prepare_mv_tokens tokens =
   detect_types false (detect_attr tokens)
 
-let rec consume_minus_positions = function
+let unminus (d,x1,x2,x3,x4,x5,x6,x7) = (* for hidden variables *)
+  match d with
+    D.MINUS | D.OPTMINUS | D.UNIQUEMINUS -> (D.CONTEXT,x1,x2,x3,x4,x5,x6,x7)
+  | D.PLUS -> failwith "unexpected plus code"
+  | D.PLUSPLUS -> failwith "unexpected plus code"
+  | D.CONTEXT | D.UNIQUE | D.OPT -> (D.CONTEXT,x1,x2,x3,x4,x5,x6,x7)
+
+let process_minus_positions x name clt meta =
+  let (arity,ln,lln,offset,col,strbef,straft,pos) = get_clt x in
+  let name = Parse_aux.clt2mcode name (unminus clt) in
+  update_clt x (arity,ln,lln,offset,col,strbef,straft,meta name::pos)
+
+(* first attach positions, then the others, so that positions can refer to
+the larger term represented by the preceding metavariable *)
+let rec consume_minus_positions toks =
+  let rec loop_pos = function
+      [] -> []
+    | ((PC.TOPar0(_),_) as x)::xs | ((PC.TCPar0(_),_) as x)::xs
+    | ((PC.TMid0(_),_) as x)::xs -> x::loop_pos xs
+    | x::(PC.TPArob _,_)::(PC.TMetaPos(name,constraints,per,clt),_)::xs ->
+       let x =
+         process_minus_positions x name clt
+           (function name ->
+             Ast0.MetaPosTag(Ast0.MetaPos(name,constraints,per))) in
+       (loop_pos (x::xs))
+    | x::xs -> x::loop_pos xs in
+  let rec loop_other = function
+      [] -> []
+    | ((PC.TOPar0(_),_) as x)::xs | ((PC.TCPar0(_),_) as x)::xs
+    | ((PC.TMid0(_),_) as x)::xs -> x::loop_other xs
+    | x::(PC.TPArob _,_)::(PC.TMetaId(name,constraints,seed,pure,clt),_)::xs ->
+       let x =
+         process_minus_positions x name clt
+           (function name ->
+             Ast0.IdentTag
+               (Ast0.wrap
+                  (Ast0.MetaId(name,constraints,seed,pure)))) in
+       (loop_other (x::xs))
+    | x::(PC.TPArob _,_)::(PC.TMetaExp(name,constraints,pure,ty,clt),_)::xs ->
+       let x =
+         process_minus_positions x name clt
+           (function name ->
+             Ast0.ExprTag
+               (Ast0.wrap
+                  (Ast0.MetaExpr(name,constraints,ty,Ast.ANY,pure)))) in
+       (loop_other (x::xs))
+    | x::(PC.TPArob _,_)::(PC.TMetaExpList(name,len,pure,clt),_)::xs ->
+       let x =
+         process_minus_positions x name clt
+           (function name ->
+             let len =
+               match len with
+                 Ast.AnyLen -> Ast0.AnyListLen
+               | Ast.MetaLen nm ->
+                   Ast0.MetaListLen(Parse_aux.clt2mcode nm clt)
+               | Ast.CstLen n -> Ast0.CstListLen n in
+             Ast0.ExprTag
+               (Ast0.wrap
+                  (Ast0.MetaExprList(name,len,pure)))) in
+       (loop_other (x::xs))
+    | x::(PC.TPArob _,_)::(PC.TMetaInit(name,pure,clt),_)::xs ->
+       let x =
+         process_minus_positions x name clt
+           (function name ->
+             Ast0.InitTag(Ast0.wrap(Ast0.MetaInit(name,pure)))) in
+       (loop_other (x::xs))
+    | x::(PC.TPArob _,_)::(PC.TMetaType(name,pure,clt),_)::xs ->
+       let x =
+         process_minus_positions x name clt
+           (function name ->
+             Ast0.TypeCTag(Ast0.wrap(Ast0.MetaType(name,pure)))) in
+       (loop_other (x::xs))
+    | x::(PC.TPArob _,_)::(PC.TMetaDecl(name,pure,clt),_)::xs ->
+       let x =
+         process_minus_positions x name clt
+           (function name ->
+             Ast0.DeclTag(Ast0.wrap(Ast0.MetaDecl(name,pure)))) in
+       (loop_other (x::xs))
+    | x::(PC.TPArob _,_)::(PC.TMetaStm(name,pure,clt),_)::xs ->
+       let x =
+         process_minus_positions x name clt
+           (function name ->
+             Ast0.StmtTag(Ast0.wrap(Ast0.MetaStmt(name,pure)))) in
+       (loop_other (x::xs))
+    | x::(PC.TPArob _,_)::(PC.TMetaIdExp(name,constraints,pure,ty,clt),_)::xs ->
+       let x =
+         process_minus_positions x name clt
+           (function name ->
+             Ast0.ExprTag
+               (Ast0.wrap
+                  (Ast0.MetaExpr(name,constraints,ty,Ast.ANY,pure)))) in
+       (loop_other (x::xs))
+
+    | x::((PC.TPArob _,_) as x')::x''::xs -> 
+       x::loop_other (x'::x''::xs)
+
+    | x::xs -> x::loop_other xs in
+  loop_other(loop_pos toks)
+    
+let rec consume_plus_positions = function
     [] -> []
-  | ((PC.TOPar0(_),_) as x)::xs | ((PC.TCPar0(_),_) as x)::xs
-  | ((PC.TMid0(_),_) as x)::xs -> x::consume_minus_positions xs
-  | x::(PC.TPArob,_)::(PC.TMetaPos(name,constraints,per,clt),_)::xs ->
-      let (arity,ln,lln,offset,col,strbef,straft,_) = get_clt x in
-      let name = Parse_aux.clt2mcode name clt in
-      let x =
-       update_clt x
-         (arity,ln,lln,offset,col,strbef,straft,
-          Ast0.MetaPos(name,constraints,per)) in
-      x::(consume_minus_positions xs)
-  | x::xs -> x::consume_minus_positions xs
+  | (PC.TPArob _,_)::x::xs -> consume_plus_positions xs
+  | x::xs -> x::consume_plus_positions xs
 
 let any_modif rule =
   let mcode x =
     match Ast0.get_mcode_mcodekind x with
-      Ast0.MINUS _ | Ast0.PLUS -> true
+      Ast0.MINUS _ | Ast0.PLUS -> true
     | _ -> false in
   let donothing r k e = k e in
   let bind x y = x or y in
@@ -1260,9 +1556,16 @@ let any_modif rule =
       mcode mcode mcode mcode mcode mcode mcode mcode mcode mcode mcode mcode
       donothing donothing donothing donothing donothing donothing
       donothing donothing donothing donothing donothing donothing donothing
-      donothing donothing in
+      donothing donothing donothing in
   List.exists fn.VT0.combiner_rec_top_level rule
 
+let eval_virt virt =
+  List.iter
+    (function x ->
+      if not (List.mem x virt)
+      then raise (Bad_virt x))
+    !Flag.defined_virtual_rules
+
 let drop_last extra l = List.rev(extra@(List.tl(List.rev l)))
 
 let partition_either l =
@@ -1274,15 +1577,65 @@ let partition_either l =
       | Common.Right e -> part_either left (e :: right) l) in
   part_either [] [] l
 
+let rec collect_script_tokens = function
+    [(PC.EOF,_)] | [(PC.TArobArob,_)] | [(PC.TArob,_)] -> ""
+  | (PC.TScriptData(s),_)::[] -> 
+      s
+  | (PC.TScriptData(s),_)::xs -> 
+      s^(collect_script_tokens xs)
+  | toks ->
+      List.iter
+       (function x ->
+         Printf.printf "%s\n" (token2c x))
+       toks;
+      failwith "Malformed script rule"
+
 let get_metavars parse_fn table file lexbuf =
   let rec meta_loop acc (* read one decl at a time *) =
     let (_,tokens) =
       Data.call_in_meta
        (function _ ->
-         tokens_all table file true lexbuf [PC.TArobArob;PC.TMPtVirg]) in
+         tokens_all table file true lexbuf (in_list [PC.TArobArob;PC.TMPtVirg;PC.TAnalysis])) in
     let tokens = prepare_mv_tokens tokens in
     match tokens with
       [(PC.TArobArob,_)] -> List.rev acc
+    | (PC.TAnalysis _, _) :: tl -> 
+       Lexer_script.file := file;
+       Lexer_script.language := "ocaml";
+        let get_tokens = tokens_script_all table file false lexbuf in
+       let rec loop n toks =
+         let (more, newtoks) = get_tokens (in_list [PC.TScriptData ")"]) in
+         (* we stop at the first close paren*)
+         let n = n - 1 in
+         (* count open parens *)
+         let count str toks =
+           List.fold_left (fun n (t, _) ->
+             if t = PC.TScriptData str 
+             then n + 1
+             else n) 0 toks in
+         let n = n + count "(" newtoks in
+         (* continue parsing *)
+         if n = 0 
+         then toks @ newtoks
+         else loop n (toks @ newtoks) in
+       begin
+         match get_tokens (in_list [PC.TScriptData "("]) with
+         | (_, ([(s, _)] as toks)) -> 
+             let data = collect_script_tokens (loop 1 toks) in
+             let (_,tokens) =
+               Data.call_in_meta
+                 (function _ ->
+                   tokens_all table file true lexbuf (in_list [PC.TArobArob;PC.TMPtVirg])) in
+             begin
+               match tokens with
+               | [(PC.TIdent (id, _), _); (PC.TMPtVirg, _)] ->
+                   let metavar = Common.Left (Ast.MetaAnalysisDecl (data, (!Ast0.rule_name, id))) in
+                   meta_loop (metavar :: acc)
+               | _ -> failwith "'analysis' can only have one variable"
+             end
+         | (_, toks) -> failwith ("'analysis' should be followed by an '(', but was followed by:\n"^(collect_script_tokens toks))
+       end
+
     | _ ->
        let metavars = parse_one "meta" parse_fn file tokens in
        meta_loop (metavars@acc) in
@@ -1291,7 +1644,7 @@ let get_metavars parse_fn table file lexbuf =
 let get_script_metavars parse_fn table file lexbuf =
   let rec meta_loop acc =
     let (_, tokens) =
-      tokens_all table file true lexbuf [PC.TArobArob; PC.TMPtVirg] in
+      tokens_all table file true lexbuf (in_list [PC.TArobArob; PC.TMPtVirg]) in
     let tokens = prepare_tokens tokens in
     match tokens with
       [(PC.TArobArob, _)] -> List.rev acc
@@ -1307,7 +1660,7 @@ let get_rule_name parse_fn starts_with_name get_tokens file prefix =
   let name_res =
     if starts_with_name
     then
-      let (_,tokens) = get_tokens [PC.TArob] in
+      let (_,tokens) = get_tokens (in_list [PC.TArob]) in
       let check_name = function
          None -> Some (mknm())
        | Some nm ->
@@ -1319,9 +1672,12 @@ let get_rule_name parse_fn starts_with_name get_tokens file prefix =
           Ast.CocciRulename (check_name nm,a,b,c,d,e)
       | Ast.GeneratedRulename (nm,a,b,c,d,e) ->
           Ast.GeneratedRulename (check_name nm,a,b,c,d,e)
-      | Ast.ScriptRulename(s,deps) -> Ast.ScriptRulename(s,deps)
-      | Ast.InitialScriptRulename(s) -> Ast.InitialScriptRulename(s)
-      | Ast.FinalScriptRulename(s) -> Ast.FinalScriptRulename(s)
+      | Ast.ScriptRulename(nm,s,deps) ->
+         Ast.ScriptRulename(check_name nm,s,deps)
+      | Ast.InitialScriptRulename(_,s,deps) ->
+         Ast.InitialScriptRulename(check_name None,s,deps)
+      | Ast.FinalScriptRulename(_,s,deps) ->
+         Ast.FinalScriptRulename(check_name None,s,deps)
     else
       Ast.CocciRulename(Some(mknm()),Ast.NoDep,[],[],Ast.Undetermined,false) in
   Data.in_rule_name := false;
@@ -1333,7 +1689,7 @@ let parse_iso file =
     let lexbuf = Lexing.from_channel channel in
     let get_tokens = tokens_all table file false lexbuf in
     let res =
-      match get_tokens [PC.TArobArob;PC.TArob] with
+      match get_tokens (in_list [PC.TArobArob;PC.TArob]) with
        (true,start) ->
          let parse_start start =
            let rev = List.rev start in
@@ -1358,9 +1714,9 @@ let parse_iso file =
            (* get the rule *)
            let (more,tokens) =
              get_tokens
-               [PC.TIsoStatement;PC.TIsoExpression;PC.TIsoArgExpression;
-                 PC.TIsoTestExpression;
-                 PC.TIsoDeclaration;PC.TIsoType;PC.TIsoTopLevel] in
+               (in_list [PC.TIsoStatement;PC.TIsoExpression;PC.TIsoArgExpression;
+                 PC.TIsoTestExpression; PC.TIsoToTestExpression;
+                 PC.TIsoDeclaration;PC.TIsoType;PC.TIsoTopLevel]) in
            let next_start = List.hd(List.rev tokens) in
            let dummy_info = ("",(-1,-1),(-1,-1)) in
            let tokens = drop_last [(PC.EOF,dummy_info)] tokens in
@@ -1374,7 +1730,7 @@ let parse_iso file =
            then (* The code below allows a header like Statement list,
                    which is more than one word.  We don't have that any more,
                    but the code is left here in case it is put back. *)
-             match get_tokens [PC.TArobArob;PC.TArob] with
+             match get_tokens (in_list [PC.TArobArob;PC.TArob]) with
                (true,start) ->
                  let (starts_with_name,start) = parse_start start in
                  (iso_metavars,entry,rule_name) ::
@@ -1383,6 +1739,7 @@ let parse_iso file =
            else [(iso_metavars,entry,rule_name)] in
          loop starts_with_name start
       | (false,_) -> [] in
+    List.iter Iso_compile.process res;
     res)
 
 let parse_iso_files existing_isos iso_files extra_path =
@@ -1393,11 +1750,11 @@ let parse_iso_files existing_isos iso_files extra_path =
     List.fold_left
       (function (prev,names) ->
        function file ->
-         Lexer_cocci.init ();
          let file =
            match file with
              Common.Left(fl)  -> Filename.concat extra_path fl
            | Common.Right(fl) -> Filename.concat Config.path fl in
+         Lexer_cocci.init ();
          let current = parse_iso file in
          let new_names = get_names current in
          if List.exists (function x -> List.mem x names) new_names
@@ -1407,13 +1764,50 @@ let parse_iso_files existing_isos iso_files extra_path =
   Data.in_iso := false;
   existing_isos@(List.concat (List.rev res))
 
-let rec parse file =
+(* None = dependency not satisfied
+   Some dep = dependency satisfied or unknown and dep has virts optimized
+   away *)
+let eval_depend dep virt =
+  let rec loop dep =
+    match dep with
+      Ast.Dep req | Ast.EverDep req ->
+       if List.mem req virt
+       then
+         if List.mem req !Flag.defined_virtual_rules
+         then Ast.NoDep
+         else Ast.FailDep
+       else dep
+    | Ast.AntiDep antireq | Ast.NeverDep antireq ->
+       if List.mem antireq virt
+       then
+         if not(List.mem antireq !Flag.defined_virtual_rules)
+         then Ast.NoDep
+         else Ast.FailDep
+       else dep
+    | Ast.AndDep(d1,d2) ->
+       (match (loop d1, loop d2) with
+         (Ast.NoDep,x) | (x,Ast.NoDep) -> x
+       | (Ast.FailDep,x) | (x,Ast.FailDep) -> Ast.FailDep
+       | (x,y) -> Ast.AndDep(x,y))
+    | Ast.OrDep(d1,d2) ->
+       (match (loop d1, loop d2) with
+         (Ast.NoDep,x) | (x,Ast.NoDep) -> Ast.NoDep
+       | (Ast.FailDep,x) | (x,Ast.FailDep) -> x
+       | (x,y) -> Ast.OrDep(x,y))
+    | Ast.NoDep | Ast.FailDep -> dep
+    in
+  loop dep
+
+let parse file =
+  Lexer_cocci.init ();
+  let rec parse_loop file =
+  Lexer_cocci.include_init ();
   let table = Common.full_charpos_to_pos file in
   Common.with_open_infile file (fun channel ->
   let lexbuf = Lexing.from_channel channel in
   let get_tokens = tokens_all table file false lexbuf in
   Data.in_prolog := true;
-  let initial_tokens = get_tokens [PC.TArobArob;PC.TArob] in
+  let initial_tokens = get_tokens (in_list [PC.TArobArob;PC.TArob]) in
   Data.in_prolog := false;
   let res =
     match initial_tokens with
@@ -1423,19 +1817,29 @@ let rec parse file =
          let include_and_iso_files =
            parse_one "include and iso file names" PC.include_main file data in
 
-         let (include_files,iso_files) =
+         let (include_files,iso_files,virt) =
            List.fold_left
-             (function (include_files,iso_files) ->
+             (function (include_files,iso_files,virt) ->
                function
-                   Data.Include s -> (s::include_files,iso_files)
-                 | Data.Iso s -> (include_files,s::iso_files))
-             ([],[]) include_and_iso_files in
-
-         let (extra_iso_files, extra_rules) =
-           List.split (List.map parse include_files) in
+                   Data.Include s -> (s::include_files,iso_files,virt)
+                 | Data.Iso s -> (include_files,s::iso_files,virt)
+                 | Data.Virt l -> (include_files,iso_files,l@virt))
+             ([],[],[]) include_and_iso_files in
+
+         List.iter (function x -> Hashtbl.add Lexer_cocci.rule_names x ())
+           virt;
+
+         let (extra_iso_files, extra_rules, extra_virt, extra_metas) =
+           let rec loop = function
+               [] -> ([],[],[],[])
+             | (a,b,c,d)::rest ->
+                 let (x,y,z,zz) = loop rest in
+                 (a::x,b::y,c::z,d@zz) in
+           loop (List.map parse_loop include_files) in
 
           let parse_cocci_rule ruletype old_metas
              (rule_name, dependencies, iso, dropiso, exists, is_expression) =
+           let dropiso = !Flag_parsing_cocci.disabled_isos @ dropiso in
             Ast0.rule_name := rule_name;
             Data.inheritable_positions :=
                rule_name :: !Data.inheritable_positions;
@@ -1443,20 +1847,26 @@ let rec parse file =
             (* get metavariable declarations *)
             let (metavars, inherited_metavars) =
              get_metavars PC.meta_main table file lexbuf in
-            Hashtbl.add Data.all_metadecls rule_name metavars;
-            Hashtbl.add Lexer_cocci.rule_names rule_name ();
-            Hashtbl.add Lexer_cocci.all_metavariables rule_name
-              (Hashtbl.fold
+           Hashtbl.add Data.all_metadecls rule_name metavars;
+           Hashtbl.add Lexer_cocci.rule_names rule_name ();
+           Hashtbl.add Lexer_cocci.all_metavariables rule_name
+             (Hashtbl.fold
                 (fun key v rest -> (key,v)::rest)
                 Lexer_cocci.metavariables []);
 
             (* get transformation rules *)
-            let (more, tokens) = get_tokens [PC.TArobArob; PC.TArob] in
+            let (more, tokens) = get_tokens (in_list [PC.TArobArob; PC.TArob]) in
             let (minus_tokens, _) = split_token_stream tokens in
             let (_, plus_tokens) =
              split_token_stream (minus_to_nothing tokens) in
 
+           (*
+              print_tokens "minus tokens" minus_tokens;
+              print_tokens "plus tokens" plus_tokens;
+           *)
+
            let minus_tokens = consume_minus_positions minus_tokens in
+           let plus_tokens = consume_plus_positions plus_tokens in
            let minus_tokens = prepare_tokens minus_tokens in
            let plus_tokens = prepare_tokens plus_tokens in
 
@@ -1482,21 +1892,39 @@ let rec parse file =
               Printf.printf "before plus parse\n";
            *)
            let plus_res =
-             if !Flag.sgrep_mode2
+             (* put ignore_patch_or_match with * case, which is less
+                constraining *)
+             if !Flag.sgrep_mode2 or !D.ignore_patch_or_match
              then (* not actually used for anything, except context_neg *)
                List.map
                  (Iso_pattern.rebuild_mcode None).VT0.rebuilder_rec_top_level
-                 minus_res
+                 (Top_level.top_level false minus_res)
              else
                if is_expression
                then parse_one "plus" PC.plus_exp_main file plus_tokens
                else parse_one "plus" PC.plus_main file plus_tokens in
+           let plus_res = Top_level.top_level false plus_res in
+           (* minus code has to be CODE if the + code is CODE, otherwise
+              doesn't matter if + code is CODE or DECL or TOPCODE *)
+           let minus_res =
+             let any_code =
+               List.exists
+                 (function x ->
+                   match Ast0.unwrap x with Ast0.CODE _ -> true | _ -> false)
+                 plus_res in
+             if any_code
+             then Top_level.top_level true minus_res
+             else Top_level.top_level false minus_res in
+           let minus_res = Top_level.clean minus_res in
+           let plus_res = Top_level.clean plus_res in
            (*
+              Unparse_ast0.unparse plus_res;
               Printf.printf "after plus parse\n";
            *)
 
            (if not !Flag.sgrep_mode2 &&
-             (any_modif minus_res or any_modif plus_res)
+             (any_modif minus_res or any_modif plus_res) &&
+             not(dependencies = Ast.FailDep)
            then Data.inheritable_positions := []);
 
            Check_meta.check_meta rule_name old_metas inherited_metavars
@@ -1506,17 +1934,9 @@ let rec parse file =
               (iso, dropiso, dependencies, rule_name, exists)),
               (plus_res, metavars), ruletype), metavars, tokens) in
 
-         let rec collect_script_tokens = function
-             [(PC.EOF,_)] | [(PC.TArobArob,_)] | [(PC.TArob,_)] -> ""
-           | (PC.TScriptData(s),_)::xs -> s^(collect_script_tokens xs)
-           | toks ->
-               List.iter
-                 (function x ->
-                   Printf.printf "%s\n" (token2c x))
-                 toks;
-               failwith "Malformed script rule" in
-
-          let parse_script_rule language old_metas deps =
+          let parse_script_rule name language old_metas deps =
+           Lexer_script.file := file;
+           Lexer_script.language := language;
             let get_tokens = tokens_script_all table file false lexbuf in
 
               (* meta-variables *)
@@ -1524,8 +1944,28 @@ let rec parse file =
              Data.call_in_meta
                (function _ ->
                  get_script_metavars PC.script_meta_main table file lexbuf) in
+           let (metavars,script_metavars) =
+             List.fold_left
+               (function (metavars,script_metavars) ->
+                 function
+                     (script_var,Some(parent,var)) ->
+                       ((script_var,parent,var) :: metavars, script_metavars)
+                   | ((Some script_var,None),None) ->
+                       (metavars, (name,script_var) :: script_metavars)
+                   | _ -> failwith "not possible")
+               ([],[]) metavars in
+           let metavars = List.rev metavars in
+           let script_metavars = List.rev script_metavars in
+
+           Hashtbl.add Data.all_metadecls name
+             (List.map (function x -> Ast.MetaIdDecl(Ast.NONE,x))
+                script_metavars);
+           Hashtbl.add Lexer_cocci.rule_names name ();
+           (*TODOHashtbl.add Lexer_cocci.all_metavariables name script_metavars;*)
 
+(*
             let exists_in old_metas (py,(r,m)) =
+             r = "virtual" or
               let test (rr,mr) x =
                 let (ro,vo) = Ast.get_meta_name x in
                 ro = rr && vo = mr in
@@ -1540,48 +1980,78 @@ let rec parse file =
                       "Script references unknown meta-variable: %s"
                       (meta2c(snd x))))
              metavars;
-
+*)
               (* script code *)
-            let (more, tokens) = get_tokens [PC.TArobArob; PC.TArob] in
+            let (more, tokens) = get_tokens (in_list [PC.TArobArob; PC.TArob]) in
             let data = collect_script_tokens tokens in
-            (more,Ast0.ScriptRule(language, deps, metavars, data),[],tokens) in
-
-          let parse_if_script_rule k language =
+            (more,
+            Ast0.ScriptRule(name, language, deps, metavars,
+                            script_metavars, data),
+            [],tokens) in
+
+          let parse_if_script_rule k name language _ deps =
+           Lexer_script.file := file;
+           Lexer_script.language := language;
             let get_tokens = tokens_script_all table file false lexbuf in
 
               (* script code *)
-            let (more, tokens) = get_tokens [PC.TArobArob; PC.TArob] in
+            let (more, tokens) = get_tokens (in_list [PC.TArobArob; PC.TArob]) in
             let data = collect_script_tokens tokens in
-            (more,k (language, data),[],tokens) in
+            (more,k (name, language, deps, data),[],tokens) in
 
          let parse_iscript_rule =
            parse_if_script_rule
-             (function (language,data) ->
-               Ast0.InitialScriptRule(language,data)) in
+             (function (name,language,deps,data) ->
+               Ast0.InitialScriptRule(name,language,deps,data)) in
 
          let parse_fscript_rule =
            parse_if_script_rule
-             (function (language,data) ->
-               Ast0.FinalScriptRule(language,data)) in
+             (function (name,language,deps,data) ->
+               Ast0.FinalScriptRule(name,language,deps,data)) in
+
+         let do_parse_script_rule fn name l old_metas deps =
+           fn name l old_metas (eval_depend deps virt) in
 
           let parse_rule old_metas starts_with_name =
             let rulename =
              get_rule_name PC.rule_name starts_with_name get_tokens file
                "rule" in
             match rulename with
-              Ast.CocciRulename (Some s, a, b, c, d, e) ->
-                parse_cocci_rule Ast.Normal old_metas (s, a, b, c, d, e)
-            | Ast.GeneratedRulename (Some s, a, b, c, d, e) ->
-               Data.in_generating := true;
-                let res =
-                 parse_cocci_rule Ast.Generated old_metas (s,a,b,c,d,e) in
-               Data.in_generating := false;
-               res
-            | Ast.ScriptRulename(l,deps) -> parse_script_rule l old_metas deps
-            | Ast.InitialScriptRulename(l) -> parse_iscript_rule l
-            | Ast.FinalScriptRulename(l) -> parse_fscript_rule l
-            | _ -> failwith "Malformed rule name"
-            in
+              Ast.CocciRulename (Some s, dep, b, c, d, e) ->
+               (match eval_depend dep virt with
+                 Ast.FailDep ->
+                   D.ignore_patch_or_match := true;
+                    let res =
+                     parse_cocci_rule Ast.Normal old_metas
+                       (s, Ast.FailDep, b, c, d, e) in
+                   D.ignore_patch_or_match := false;
+                   res
+               | dep -> parse_cocci_rule Ast.Normal old_metas (s,dep,b,c,d,e))
+            | Ast.GeneratedRulename (Some s, dep, b, c, d, e) ->
+               (match eval_depend dep virt with
+                 Ast.FailDep ->
+                   D.ignore_patch_or_match := true;
+                   Data.in_generating := true;
+                    let res =
+                     parse_cocci_rule Ast.Generated old_metas
+                       (s, Ast.FailDep, b, c, d, e) in
+                   D.ignore_patch_or_match := false;
+                   Data.in_generating := false;
+                   res
+               | dep ->
+                   Data.in_generating := true;
+                   let res =
+                     parse_cocci_rule Ast.Generated old_metas
+                       (s,dep,b,c,d,e) in
+                   Data.in_generating := false;
+                   res)
+            | Ast.ScriptRulename(Some s,l,deps) ->
+               do_parse_script_rule parse_script_rule s l old_metas deps
+            | Ast.InitialScriptRulename(Some s,l,deps) ->
+               do_parse_script_rule parse_iscript_rule s l old_metas deps
+            | Ast.FinalScriptRulename(Some s,l,deps)   ->
+               do_parse_script_rule parse_fscript_rule s l old_metas deps
+            | _ -> failwith "Malformed rule name" in
 
          let rec loop old_metas starts_with_name =
            (!Data.init_rule)();
@@ -1596,28 +2066,37 @@ let rec parse file =
 
             let (more, rule, metavars, tokens) =
               parse_rule old_metas starts_with_name in
+           let all_metas = metavars @ old_metas in
+
             if more then
-              rule::
-             (loop (metavars @ old_metas) (gen_starts_with_name more tokens))
-            else [rule] in
+             let (all_rules,all_metas) =
+               loop all_metas (gen_starts_with_name more tokens) in
+             (rule::all_rules,all_metas)
+            else ([rule],all_metas) in
+
+         let (all_rules,all_metas) =
+           loop extra_metas (x = PC.TArob) in
 
          (List.fold_left
             (function prev -> function cur -> Common.union_set cur prev)
             iso_files extra_iso_files,
-          List.fold_left
-            (function prev -> function cur -> cur @ prev)
-            (loop [] (x = PC.TArob)) extra_rules)
+          (* included rules first *)
+          List.fold_left (function prev -> function cur -> cur@prev)
+            all_rules (List.rev extra_rules),
+          List.fold_left (@) virt extra_virt (*no dups allowed*),
+          (all_metas : 'a list))
       |        _ -> failwith "unexpected code before the first rule\n")
   | (false,[(PC.TArobArob,_)]) | (false,[(PC.TArob,_)]) ->
-      ([],([] : Ast0.parsed_rule list))
+      ([],([] : Ast0.parsed_rule list),[] (*virtual rules*), [] (*all metas*))
   | _ -> failwith "unexpected code before the first rule\n" in
-  res)
+  res) in
+  parse_loop file
 
 (* parse to ast0 and then convert to ast *)
 let process file isofile verbose =
   let extra_path = Filename.dirname file in
-  Lexer_cocci.init();
-  let (iso_files, rules) = parse file in
+  let (iso_files, rules, virt, _metas) = parse file in
+  eval_virt virt;
   let std_isos =
     match isofile with
       None -> []
@@ -1627,9 +2106,12 @@ let process file isofile verbose =
   let parsed =
     List.map
       (function
-          Ast0.ScriptRule (a,b,c,d) -> [([],Ast.ScriptRule (a,b,c,d))]
-       | Ast0.InitialScriptRule (a,b) -> [([],Ast.InitialScriptRule (a,b))]
-       | Ast0.FinalScriptRule (a,b) -> [([],Ast.FinalScriptRule (a,b))]
+          Ast0.ScriptRule (a,b,c,d,fv,e) ->
+           [([],Ast.ScriptRule (a,b,c,d,fv,e))]
+       | Ast0.InitialScriptRule(a,b,c,d) ->
+           [([],Ast.InitialScriptRule (a,b,c,d))]
+       | Ast0.FinalScriptRule (a,b,c,d) ->
+           [([],Ast.FinalScriptRule (a,b,c,d))]
        | Ast0.CocciRule
            ((minus, metavarsm,
              (iso, dropiso, dependencies, rule_name, exists)),
@@ -1661,7 +2143,6 @@ let process file isofile verbose =
                   List.filter
                     (function (_,_,nm) -> not (List.mem nm dropiso))
                     chosen_isos in
-              List.iter Iso_compile.process chosen_isos;
               let dropped_isos =
                 match reserved_names with
                   "all"::others ->
@@ -1696,7 +2177,7 @@ let process file isofile verbose =
           (* warning! context_neg side-effects its arguments *)
               let (m,p) = List.split (Context_neg.context_neg minus plus) in
               Type_infer.type_infer p;
-              (if not !Flag.sgrep_mode2
+              (if not (!Flag.sgrep_mode2 or dependencies = Ast.FailDep)
               then Insert_plus.insert_plus m p (chosen_isos = []));
               Type_infer.type_infer minus;
               let (extra_meta, minus) =
@@ -1705,6 +2186,8 @@ let process file isofile verbose =
                      some restrictions on the -+ code *)
                   ([],_) | (_,Ast.Generated) -> ([],minus)
                 | _ -> Iso_pattern.apply_isos chosen_isos minus rule_name in
+              (* must be before adj *)
+              let minus = Commas_on_lists.process minus in
               (* after iso, because iso can intro ... *)
               let minus = Adjacency.compute_adjacency minus in
               let minus = Comm_assoc.comm_assoc minus rule_name dropiso in
@@ -1712,25 +2195,28 @@ let process file isofile verbose =
                 if !Flag.sgrep_mode2 then minus
                 else Single_statement.single_statement minus in
               let minus = Simple_assignments.simple_assignments minus in
+              (* has to be last, introduced AsExpr, etc *)
+              let minus = Get_metas.process minus in
               let minus_ast =
                 Ast0toast.ast0toast rule_name dependencies dropped_isos
                   exists minus is_exp ruletype in
+
               match function_prototypes with
                 None -> [(extra_meta @ metavars, minus_ast)]
               | Some mv_fp -> [(extra_meta @ metavars, minus_ast); mv_fp])
 (*          Ast0.CocciRule ((minus, metavarsm, (iso, dropiso, dependencies, rule_name, exists)), (plus, metavars))*)
       rules in
+
   let parsed = List.concat parsed in
+  let parsed = Safe_for_multi_decls.safe_for_multi_decls parsed in
   let disjd = Disjdistr.disj parsed in
 
   let (metavars,code,fvs,neg_pos,ua,pos) = Free_vars.free_vars disjd in
   if !Flag_parsing_cocci.show_SP
   then List.iter Pretty_print_cocci.unparse code;
 
-  let grep_tokens =
-    Common.profile_code "get_constants"
-      (fun () -> Get_constants.get_constants code) in (* for grep *)
-  let glimpse_tokens2 =
-    Common.profile_code "get_glimpse_constants"
-      (fun () -> Get_constants2.get_constants code neg_pos) in(* for glimpse *)
-  (metavars,code,fvs,neg_pos,ua,pos,grep_tokens,glimpse_tokens2)
+  let search_tokens =
+    Common.profile_code "get_glimpse_constants" (* for glimpse *)
+      (fun () -> Get_constants2.get_constants code neg_pos) in
+
+  (metavars,code,fvs,neg_pos,ua,pos,search_tokens)