Release coccinelle-0.1.6
[bpt/coccinelle.git] / parsing_cocci / .#parse_cocci.ml.1.180
diff --git a/parsing_cocci/.#parse_cocci.ml.1.180 b/parsing_cocci/.#parse_cocci.ml.1.180
new file mode 100644 (file)
index 0000000..91c0768
--- /dev/null
@@ -0,0 +1,1628 @@
+(*
+* 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.
+*)
+
+
+(* splits the entire file into minus and plus fragments, and parses each
+separately (thus duplicating work for the parsing of the context elements) *)
+
+module D = Data
+module PC = Parser_cocci_menhir
+module V0 = Visitor_ast0
+module Ast = Ast_cocci
+module Ast0 = Ast0_cocci
+let pr = Printf.sprintf
+(*let pr2 s = prerr_string s; prerr_string "\n"; flush stderr*)
+let pr2 s = Printf.printf "%s\n" s
+
+(* for isomorphisms.  all should be at the front!!! *)
+let reserved_names =
+  ["all";"optional_storage";"optional_qualifier";"value_format";"comm_assoc"]
+
+(* ----------------------------------------------------------------------- *)
+(* Debugging... *)
+
+let line_type (d,_,_,_,_,_,_,_) = d
+
+let line_type2c tok =
+  match line_type tok with
+    D.MINUS | D.OPTMINUS | D.UNIQUEMINUS -> ":-"
+  | D.PLUS -> ":+"
+  | D.CONTEXT | D.UNIQUE | D.OPT -> ""
+
+let token2c (tok,_) =
+ match tok with
+    PC.TIdentifier -> "identifier"
+  | PC.TType -> "type"
+  | PC.TParameter -> "parameter"
+  | PC.TConstant -> "constant"
+  | PC.TExpression -> "expression"
+  | PC.TIdExpression -> "idexpression"
+  | PC.TInitialiser -> "initialiser"
+  | PC.TStatement -> "statement"
+  | PC.TPosition -> "position"
+  | PC.TPosAny -> "any"
+  | PC.TFunction -> "function"
+  | PC.TLocal -> "local"
+  | PC.Tlist -> "list"
+  | PC.TFresh -> "fresh"
+  | PC.TPure -> "pure"
+  | PC.TContext -> "context"
+  | PC.TTypedef -> "typedef"
+  | PC.TDeclarer -> "declarer"
+  | PC.TIterator -> "iterator"
+  | PC.TName -> "name"
+  | PC.TRuleName str -> "rule_name-"^str
+  | PC.TUsing -> "using"
+  | PC.TPathIsoFile str -> "path_iso_file-"^str
+  | PC.TDisable -> "disable"
+  | PC.TExtends -> "extends"
+  | PC.TDepends -> "depends"
+  | PC.TOn -> "on"
+  | PC.TEver -> "ever"
+  | PC.TNever -> "never"
+  | PC.TExists -> "exists"
+  | PC.TForall -> "forall"
+  | PC.TReverse -> "reverse"
+  | PC.TError -> "error"
+  | PC.TWords -> "words"
+  | PC.TGenerated -> "generated"
+
+  | PC.TNothing -> "nothing"
+
+  | PC.Tchar(clt) -> "char"^(line_type2c  clt)
+  | PC.Tshort(clt) -> "short"^(line_type2c clt)
+  | PC.Tint(clt) -> "int"^(line_type2c clt)
+  | PC.Tdouble(clt) -> "double"^(line_type2c clt)
+  | PC.Tfloat(clt) -> "float"^(line_type2c clt)
+  | PC.Tlong(clt) -> "long"^(line_type2c clt)
+  | PC.Tvoid(clt) -> "void"^(line_type2c clt)
+  | PC.Tstruct(clt) -> "struct"^(line_type2c clt)
+  | PC.Tunion(clt) -> "union"^(line_type2c clt)
+  | PC.Tenum(clt) -> "enum"^(line_type2c clt)
+  | PC.Tunsigned(clt) -> "unsigned"^(line_type2c clt)
+  | PC.Tsigned(clt) -> "signed"^(line_type2c clt)
+  | PC.Tstatic(clt) -> "static"^(line_type2c clt)
+  | PC.Tinline(clt) -> "inline"^(line_type2c clt)
+  | PC.Ttypedef(clt) -> "typedef"^(line_type2c clt)
+  | PC.Tattr(s,clt) -> s^(line_type2c clt)
+  | PC.Tauto(clt) -> "auto"^(line_type2c clt)
+  | PC.Tregister(clt) -> "register"^(line_type2c clt)
+  | PC.Textern(clt) -> "extern"^(line_type2c clt)
+  | PC.Tconst(clt) -> "const"^(line_type2c clt)
+  | PC.Tvolatile(clt) -> "volatile"^(line_type2c clt)
+
+  | PC.TPragma(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.TDefine(clt,_) -> "#define"^(line_type2c clt)
+  | PC.TDefineParam(clt,_,_) -> "#define_param"^(line_type2c clt)
+  | PC.TMinusFile(s,clt) -> (pr "--- %s" s)^(line_type2c clt)
+  | PC.TPlusFile(s,clt) -> (pr "+++ %s" s)^(line_type2c clt)
+
+  | PC.TInc(clt) -> "++"^(line_type2c clt)
+  | PC.TDec(clt) -> "--"^(line_type2c clt)
+
+  | PC.TIf(clt) -> "if"^(line_type2c clt)
+  | PC.TElse(clt) -> "else"^(line_type2c clt)
+  | PC.TWhile(clt) -> "while"^(line_type2c clt)
+  | PC.TFor(clt) -> "for"^(line_type2c clt)
+  | PC.TDo(clt) -> "do"^(line_type2c clt)
+  | PC.TSwitch(clt) -> "switch"^(line_type2c clt)
+  | PC.TCase(clt) -> "case"^(line_type2c clt)
+  | PC.TDefault(clt) -> "default"^(line_type2c clt)
+  | PC.TReturn(clt) -> "return"^(line_type2c clt)
+  | PC.TBreak(clt) -> "break"^(line_type2c clt)
+  | PC.TContinue(clt) -> "continue"^(line_type2c clt)
+  | PC.TGoto(clt) -> "goto"^(line_type2c clt)
+  | PC.TIdent(s,clt) -> (pr "ident-%s" s)^(line_type2c clt)
+  | 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.TMetaDeclarer(_,_,_,clt) -> "declmeta"^(line_type2c clt)
+  | PC.TMetaIterator(_,_,_,clt) -> "itermeta"^(line_type2c clt)
+
+  | PC.TSizeof(clt) -> "sizeof"^(line_type2c clt)
+
+  | PC.TString(x,clt) -> x^(line_type2c clt)
+  | PC.TChar(x,clt) -> x^(line_type2c clt)
+  | PC.TFloat(x,clt) -> x^(line_type2c clt)
+  | PC.TInt(x,clt) -> x^(line_type2c clt)
+
+  | PC.TOrLog(clt) -> "||"^(line_type2c clt)
+  | PC.TAndLog(clt) -> "&&"^(line_type2c clt)
+  | PC.TOr(clt) -> "|"^(line_type2c clt)
+  | PC.TXor(clt) -> "^"^(line_type2c clt)
+  | PC.TAnd (clt) -> "&"^(line_type2c clt)
+  | PC.TEqEq(clt) -> "=="^(line_type2c clt)
+  | PC.TNotEq(clt) -> "!="^(line_type2c clt)
+  | PC.TLogOp(op,clt) ->
+      (match op with
+       Ast.Inf -> "<"
+      |        Ast.InfEq -> "<="
+      |        Ast.Sup -> ">"
+      |        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.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.Mod -> "%"
+      |        _ -> failwith "not possible")
+      ^(line_type2c clt)
+  | PC.TTilde (clt) -> "~"^(line_type2c clt)
+
+  | PC.TMetaParam(_,_,clt) -> "parammeta"^(line_type2c clt)
+  | PC.TMetaParamList(_,_,_,clt) -> "paramlistmeta"^(line_type2c clt)
+  | PC.TMetaConst(_,_,_,_,clt) -> "constmeta"^(line_type2c clt)
+  | PC.TMetaErr(_,_,_,clt) -> "errmeta"^(line_type2c clt)
+  | PC.TMetaExp(_,_,_,_,clt) -> "expmeta"^(line_type2c clt)
+  | 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.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.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.TScript -> "script"
+
+  | PC.TWhen(clt) -> "WHEN"^(line_type2c clt)
+  | PC.TWhenTrue(clt) -> "WHEN TRUE"^(line_type2c clt)
+  | PC.TWhenFalse(clt) -> "WHEN FALSE"^(line_type2c clt)
+  | PC.TAny(clt) -> "ANY"^(line_type2c clt)
+  | PC.TStrict(clt) -> "STRICT"^(line_type2c clt)
+  | PC.TEllipsis(clt) -> "..."^(line_type2c clt)
+(*
+  | PC.TCircles(clt)  -> "ooo"^(line_type2c clt)
+  | PC.TStars(clt)    -> "***"^(line_type2c clt)
+*)
+
+  | PC.TOEllipsis(clt) -> "<..."^(line_type2c clt)
+  | PC.TCEllipsis(clt) -> "...>"^(line_type2c clt)
+  | PC.TPOEllipsis(clt) -> "<+..."^(line_type2c clt)
+  | PC.TPCEllipsis(clt) -> "...+>"^(line_type2c clt)
+(*
+  | PC.TOCircles(clt)  -> "<ooo"^(line_type2c clt)
+  | PC.TCCircles(clt)  -> "ooo>"^(line_type2c clt)
+  | PC.TOStars(clt)    -> "<***"^(line_type2c clt)
+  | PC.TCStars(clt)    -> "***>"^(line_type2c clt)
+*)
+  | PC.TBang0 -> "!"
+  | PC.TPlus0 -> "+"
+  | PC.TWhy0  -> "?"
+
+  | PC.TWhy(clt)   -> "?"^(line_type2c clt)
+  | PC.TDotDot(clt)   -> ":"^(line_type2c clt)
+  | PC.TBang(clt)  -> "!"^(line_type2c clt)
+  | PC.TOPar(clt)  -> "("^(line_type2c clt)
+  | PC.TOPar0(clt) -> "("^(line_type2c clt)
+  | PC.TMid0(clt)  -> "|"^(line_type2c clt)
+  | PC.TCPar(clt)  -> ")"^(line_type2c clt)
+  | PC.TCPar0(clt) -> ")"^(line_type2c clt)
+
+  | PC.TOBrace(clt) -> "{"^(line_type2c clt)
+  | PC.TCBrace(clt) -> "}"^(line_type2c clt)
+  | PC.TOCro(clt) -> "["^(line_type2c clt)
+  | PC.TCCro(clt) -> "]"^(line_type2c clt)
+  | PC.TOInit(clt) -> "{"^(line_type2c clt)
+
+  | PC.TPtrOp(clt) -> "->"^(line_type2c clt)
+
+  | PC.TEq(clt) -> "="^(line_type2c clt)
+  | PC.TAssign(_,clt) -> "=op"^(line_type2c clt)
+  | PC.TDot(clt) -> "."^(line_type2c clt)
+  | PC.TComma(clt) -> ","^(line_type2c clt)
+  | PC.TPtVirg(clt) -> ";"^(line_type2c clt)
+
+  | PC.EOF -> "eof"
+  | PC.TLineEnd(clt) -> "line end"
+  | PC.TInvalid -> "invalid"
+  | PC.TFunDecl(clt) -> "fundecl"
+
+  | PC.TIso -> "<=>"
+  | PC.TRightIso -> "=>"
+  | PC.TIsoTopLevel -> "TopLevel"
+  | PC.TIsoExpression -> "Expression"
+  | PC.TIsoArgExpression -> "ArgExpression"
+  | PC.TIsoTestExpression -> "TestExpression"
+  | PC.TIsoStatement -> "Statement"
+  | PC.TIsoDeclaration -> "Declaration"
+  | PC.TIsoType -> "Type"
+  | PC.TScriptData s -> s
+
+let print_tokens s tokens =
+  Printf.printf "%s\n" s;
+  List.iter (function x -> Printf.printf "%s " (token2c x)) tokens;
+  Printf.printf "\n\n";
+  flush stdout
+
+type plus = PLUS | NOTPLUS | SKIP
+
+let plus_attachable (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.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.TDefineParam(clt,_,_) | PC.TMinusFile(_,clt) | PC.TPlusFile(_,clt)
+
+  | PC.TInc(clt) | PC.TDec(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) | 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.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.TDmOp(_,clt) | PC.TTilde (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.TWhen(clt) |  PC.TWhenTrue(clt) |  PC.TWhenFalse(clt)
+  | PC.TAny(clt) | PC.TStrict(clt) | PC.TEllipsis(clt)
+  (* | PC.TCircles(clt) | PC.TStars(clt) *)
+
+  | PC.TWhy(clt) | PC.TDotDot(clt) | PC.TBang(clt) | PC.TOPar(clt)
+  | PC.TCPar(clt)
+
+  | PC.TOBrace(clt) | PC.TCBrace(clt) | PC.TOCro(clt) | PC.TCCro(clt)
+  | PC.TOInit(clt)
+
+  | PC.TPtrOp(clt)
+
+  | PC.TEq(clt) | PC.TAssign(_,clt) | PC.TDot(clt) | PC.TComma(clt)
+  | PC.TPtVirg(clt) ->
+      if line_type clt = D.PLUS 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.TMetaPos(nm,_,_,_) -> 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.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.TDefineParam(clt,_,_) | PC.TMinusFile(_,clt) | PC.TPlusFile(_,clt)
+
+  | PC.TInc(clt) | PC.TDec(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) | 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.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.TDmOp(_,clt) | PC.TTilde (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.TWhen(clt) | PC.TWhenTrue(clt) | PC.TWhenFalse(clt) |
+    PC.TAny(clt) | PC.TStrict(clt) | PC.TEllipsis(clt)
+  (* | PC.TCircles(clt) | PC.TStars(clt) *)
+
+  | PC.TWhy(clt) | PC.TDotDot(clt) | PC.TBang(clt) | PC.TOPar(clt)
+  | PC.TCPar(clt)
+
+  | PC.TOBrace(clt) | PC.TCBrace(clt) | PC.TOCro(clt) | PC.TCCro(clt)
+  | PC.TOInit(clt)
+
+  | PC.TPtrOp(clt)
+
+  | PC.TEq(clt) | PC.TAssign(_,clt) | PC.TDot(clt) | PC.TComma(clt)
+  | PC.TPtVirg(clt)
+
+  | 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) *) -> clt
+
+  | _ -> failwith "no clt"
+
+let update_clt (tok,x) clt =
+  match tok with
+    PC.Tchar(_) -> (PC.Tchar(clt),x)
+  | PC.Tshort(_) -> (PC.Tshort(clt),x)
+  | PC.Tint(_) -> (PC.Tint(clt),x)
+  | PC.Tdouble(_) -> (PC.Tdouble(clt),x)
+  | PC.Tfloat(_) -> (PC.Tfloat(clt),x)
+  | PC.Tlong(_) -> (PC.Tlong(clt),x)
+  | PC.Tvoid(_) -> (PC.Tvoid(clt),x)
+  | PC.Tstruct(_) -> (PC.Tstruct(clt),x)
+  | PC.Tunion(_) -> (PC.Tunion(clt),x)
+  | PC.Tenum(_) -> (PC.Tenum(clt),x)
+  | PC.Tunsigned(_) -> (PC.Tunsigned(clt),x)
+  | PC.Tsigned(_) -> (PC.Tsigned(clt),x)
+  | PC.Tstatic(_) -> (PC.Tstatic(clt),x)
+  | PC.Tinline(_) -> (PC.Tinline(clt),x)
+  | PC.Ttypedef(_) -> (PC.Ttypedef(clt),x)
+  | PC.Tattr(s,_) -> (PC.Tattr(s,clt),x)
+  | PC.Tauto(_) -> (PC.Tauto(clt),x)
+  | PC.Tregister(_) -> (PC.Tregister(clt),x)
+  | PC.Textern(_) -> (PC.Textern(clt),x)
+  | PC.Tconst(_) -> (PC.Tconst(clt),x)
+  | PC.Tvolatile(_) -> (PC.Tvolatile(clt),x)
+
+  | PC.TIncludeL(s,_) -> (PC.TIncludeL(s,clt),x)
+  | PC.TIncludeNL(s,_) -> (PC.TIncludeNL(s,clt),x)
+  | PC.TDefine(_,a) -> (PC.TDefine(clt,a),x)
+  | PC.TDefineParam(_,a,b) -> (PC.TDefineParam(clt,a,b),x)
+  | PC.TMinusFile(s,_) -> (PC.TMinusFile(s,clt),x)
+  | PC.TPlusFile(s,_) -> (PC.TPlusFile(s,clt),x)
+
+  | PC.TInc(_) -> (PC.TInc(clt),x)
+  | PC.TDec(_) -> (PC.TDec(clt),x)
+
+  | PC.TIf(_) -> (PC.TIf(clt),x)
+  | PC.TElse(_) -> (PC.TElse(clt),x)
+  | PC.TWhile(_) -> (PC.TWhile(clt),x)
+  | PC.TFor(_) -> (PC.TFor(clt),x)
+  | PC.TDo(_) -> (PC.TDo(clt),x)
+  | PC.TSwitch(_) -> (PC.TSwitch(clt),x)
+  | PC.TCase(_) -> (PC.TCase(clt),x)
+  | PC.TDefault(_) -> (PC.TDefault(clt),x)
+  | PC.TReturn(_) -> (PC.TReturn(clt),x)
+  | PC.TBreak(_) -> (PC.TBreak(clt),x)
+  | PC.TContinue(_) -> (PC.TContinue(clt),x)
+  | PC.TGoto(_) -> (PC.TGoto(clt),x)
+  | PC.TIdent(s,_) -> (PC.TIdent(s,clt),x)
+  | 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.TSizeof(_) -> (PC.TSizeof(clt),x)
+
+  | PC.TString(s,_) -> (PC.TString(s,clt),x)
+  | PC.TChar(s,_) -> (PC.TChar(s,clt),x)
+  | PC.TFloat(s,_) -> (PC.TFloat(s,clt),x)
+  | PC.TInt(s,_) -> (PC.TInt(s,clt),x)
+
+  | PC.TOrLog(_) -> (PC.TOrLog(clt),x)
+  | PC.TAndLog(_) -> (PC.TAndLog(clt),x)
+  | PC.TOr(_) -> (PC.TOr(clt),x)
+  | PC.TXor(_) -> (PC.TXor(clt),x)
+  | PC.TAnd (_) -> (PC.TAnd (clt),x)
+  | PC.TEqEq(_) -> (PC.TEqEq(clt),x)
+  | PC.TNotEq(_) -> (PC.TNotEq(clt),x)
+  | PC.TLogOp(op,_) -> (PC.TLogOp(op,clt),x)
+  | PC.TShOp(op,_) -> (PC.TShOp(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.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)
+  | PC.TMetaErr(a,b,c,_) -> (PC.TMetaErr(a,b,c,clt),x)
+  | PC.TMetaExp(a,b,c,d,_) -> (PC.TMetaExp(a,b,c,d,clt),x)
+  | 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.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.TMetaFunc(a,b,c,_)  -> (PC.TMetaFunc(a,b,c,clt),x)
+  | PC.TMetaLocalFunc(a,b,c,_) -> (PC.TMetaLocalFunc(a,b,c,clt),x)
+
+  | PC.TWhen(_) -> (PC.TWhen(clt),x)
+  | PC.TWhenTrue(_) -> (PC.TWhenTrue(clt),x)
+  | PC.TWhenFalse(_) -> (PC.TWhenFalse(clt),x)
+  | PC.TAny(_) -> (PC.TAny(clt),x)
+  | PC.TStrict(_) -> (PC.TStrict(clt),x)
+  | PC.TEllipsis(_) -> (PC.TEllipsis(clt),x)
+(*
+  | PC.TCircles(_)  -> (PC.TCircles(clt),x)
+  | PC.TStars(_)    -> (PC.TStars(clt),x)
+*)
+
+  | PC.TOEllipsis(_) -> (PC.TOEllipsis(clt),x)
+  | PC.TCEllipsis(_) -> (PC.TCEllipsis(clt),x)
+  | PC.TPOEllipsis(_) -> (PC.TPOEllipsis(clt),x)
+  | PC.TPCEllipsis(_) -> (PC.TPCEllipsis(clt),x)
+(*
+  | PC.TOCircles(_)  -> (PC.TOCircles(clt),x)
+  | PC.TCCircles(_)  -> (PC.TCCircles(clt),x)
+  | PC.TOStars(_)    -> (PC.TOStars(clt),x)
+  | PC.TCStars(_)    -> (PC.TCStars(clt),x)
+*)
+
+  | PC.TWhy(_)   -> (PC.TWhy(clt),x)
+  | PC.TDotDot(_)   -> (PC.TDotDot(clt),x)
+  | PC.TBang(_)  -> (PC.TBang(clt),x)
+  | PC.TOPar(_)  -> (PC.TOPar(clt),x)
+  | PC.TOPar0(_) -> (PC.TOPar0(clt),x)
+  | PC.TMid0(_)  -> (PC.TMid0(clt),x)
+  | PC.TCPar(_)  -> (PC.TCPar(clt),x)
+  | PC.TCPar0(_) -> (PC.TCPar0(clt),x)
+
+  | PC.TOBrace(_) -> (PC.TOBrace(clt),x)
+  | PC.TCBrace(_) -> (PC.TCBrace(clt),x)
+  | PC.TOCro(_) -> (PC.TOCro(clt),x)
+  | PC.TCCro(_) -> (PC.TCCro(clt),x)
+  | PC.TOInit(_) -> (PC.TOInit(clt),x)
+
+  | PC.TPtrOp(_) -> (PC.TPtrOp(clt),x)
+
+  | PC.TEq(_) -> (PC.TEq(clt),x)
+  | PC.TAssign(s,_) -> (PC.TAssign(s,clt),x)
+  | PC.TDot(_) -> (PC.TDot(clt),x)
+  | PC.TComma(_) -> (PC.TComma(clt),x)
+  | PC.TPtVirg(_) -> (PC.TPtVirg(clt),x)
+
+  | PC.TLineEnd(_) -> (PC.TLineEnd(clt),x)
+  | PC.TFunDecl(_) -> (PC.TFunDecl(clt),x)
+
+  | _ -> failwith "no clt"
+
+
+(* ----------------------------------------------------------------------- *)
+
+let make_name prefix ln = Printf.sprintf "%s starting on line %d" prefix ln
+
+(* ----------------------------------------------------------------------- *)
+(* Read tokens *)
+
+let wrap_lexbuf_info lexbuf =
+  (Lexing.lexeme lexbuf, Lexing.lexeme_start lexbuf)
+
+let tokens_all_full token table file get_ats lexbuf end_markers :
+    (bool * ((PC.token * (string * (int * int) * (int * int))) list)) =
+  try
+    let rec aux () =
+      let result = token lexbuf in
+      let info = (Lexing.lexeme lexbuf,
+                  (table.(Lexing.lexeme_start lexbuf)),
+                  (Lexing.lexeme_start lexbuf, Lexing.lexeme_end lexbuf)) in
+      if result = PC.EOF
+      then
+       if get_ats
+       then failwith "unexpected end of file in a metavariable declaration"
+       else (false,[(result,info)])
+      else if List.mem result end_markers
+      then (true,[(result,info)])
+      else
+       let (more,rest) = aux() in
+       (more,(result, info)::rest)
+    in aux ()
+  with
+    e -> pr2 (Common.error_message file (wrap_lexbuf_info lexbuf) ); raise e
+
+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
+
+let tokens_script_all table file get_ats lexbuf end_markers :
+    (bool * ((PC.token * (string * (int * int) * (int * int))) list)) =
+  tokens_all_full Lexer_script.token table file get_ats lexbuf end_markers
+
+(* ----------------------------------------------------------------------- *)
+(* Split tokens into minus and plus fragments *)
+
+let split t clt =
+  let (d,_,_,_,_,_,_,_) = clt in
+  match d with
+    D.MINUS | D.OPTMINUS | D.UNIQUEMINUS -> ([t],[])
+  | D.PLUS -> ([],[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.TFunction | PC.TTypedef | PC.TDeclarer | PC.TIterator | PC.TName
+  | PC.TType | PC.TParameter | PC.TLocal | PC.Tlist | PC.TFresh | PC.TPure
+  | PC.TContext | PC.TRuleName(_) | PC.TUsing | PC.TDisable | PC.TExtends
+  | PC.TPathIsoFile(_)
+  | PC.TDepends | PC.TOn | PC.TEver | PC.TNever | PC.TExists | PC.TForall
+  | PC.TReverse
+  | 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.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) | PC.Tvolatile(clt) -> split t clt
+
+  | PC.TPragma(s) -> ([],[t]) (* only allowed in + *)
+  | 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.TIf(clt) | PC.TElse(clt)  | PC.TWhile(clt) | PC.TFor(clt) | PC.TDo(clt)
+  | PC.TSwitch(clt) | PC.TCase(clt) | PC.TDefault(clt)
+  | PC.TSizeof(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.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.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 -> ([t],[t])
+  | PC.TPArob | PC.TMetaPos(_,_,_,_) -> ([t],[])
+
+  | 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.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])
+
+  | PC.TWhy(clt)  | PC.TDotDot(clt)
+  | PC.TBang(clt) | PC.TOPar(clt) | PC.TOPar0(clt)
+  | PC.TMid0(clt) | PC.TCPar(clt) | PC.TCPar0(clt) -> split t clt
+
+  | PC.TInc(clt) | PC.TDec(clt) -> split t clt
+
+  | PC.TString(_,clt) | PC.TChar(_,clt) | PC.TFloat(_,clt) | PC.TInt(_,clt) ->
+      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.TDmOp(_,clt) | PC.TTilde (clt) -> split t clt
+
+  | PC.TOBrace(clt) | PC.TCBrace(clt) | PC.TOInit(clt) -> split t clt
+  | PC.TOCro(clt) | PC.TCCro(clt) -> split t clt
+
+  | PC.TPtrOp(clt) -> split t clt
+
+  | 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.TIso | PC.TRightIso
+  | PC.TIsoExpression | PC.TIsoStatement | PC.TIsoDeclaration | PC.TIsoType
+  | PC.TIsoTopLevel | PC.TIsoArgExpression | PC.TIsoTestExpression ->
+      failwith "unexpected tokens"
+  | PC.TScriptData s -> ([t],[t])
+
+let split_token_stream tokens =
+  let rec loop = function
+      [] -> ([],[])
+    | token::tokens ->
+       let (minus,plus) = split_token token in
+       let (minus_stream,plus_stream) = loop tokens in
+       (minus@minus_stream,plus@plus_stream) in
+  loop tokens
+
+(* ----------------------------------------------------------------------- *)
+(* Find function names *)
+(* This addresses a shift-reduce problem in the parser, allowing us to
+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
+
+(* ----------------------------------------------------------------------- *)
+(* an attribute is an identifier that preceeds another identifier and
+   begins with __ *)
+
+let rec detect_attr l =
+  let is_id = function
+      (PC.TIdent(_,_),_) | (PC.TMetaId(_,_,_,_),_) | (PC.TMetaFunc(_,_,_,_),_)
+    | (PC.TMetaLocalFunc(_,_,_,_),_) -> true
+    | _ -> false in
+  let rec loop = function
+      [] -> []
+    | [x] -> [x]
+    | ((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))
+       else t1::(loop (id::rest))
+    | x::xs -> x::(loop xs) in
+  loop l
+
+(* ----------------------------------------------------------------------- *)
+(* Look for variable declarations where the name is a typedef name.
+We assume that C code does not contain a multiplication as a top-level
+statement. *)
+
+(* bug: once a type, always a type, even if the same name is later intended
+   to be used as a real identifier *)
+let detect_types in_meta_decls l =
+  let is_delim infn = function
+      (PC.TOEllipsis(_),_) (* | (PC.TOCircles(_),_) | (PC.TOStars(_),_) *)
+    | (PC.TPOEllipsis(_),_) (* | (PC.TOCircles(_),_) | (PC.TOStars(_),_) *)
+    | (PC.TEllipsis(_),_) (* | (PC.TCircles(_),_) | (PC.TStars(_),_) *)
+    | (PC.TPtVirg(_),_) | (PC.TOBrace(_),_) | (PC.TOInit(_),_)
+    | (PC.TCBrace(_),_)
+    | (PC.TPure,_) | (PC.TContext,_)
+    | (PC.Tstatic(_),_) | (PC.Textern(_),_)
+    | (PC.Tinline(_),_) | (PC.Ttypedef(_),_) | (PC.Tattr(_),_) -> true
+    | (PC.TComma(_),_) when infn > 0 or in_meta_decls -> true
+    | (PC.TDotDot(_),_) when in_meta_decls -> true
+    | _ -> false in
+  let is_choices_delim = function
+      (PC.TOBrace(_),_) | (PC.TComma(_),_) -> true | _ -> false in
+  let is_id = function
+      (PC.TIdent(_,_),_) | (PC.TMetaId(_,_,_,_),_) | (PC.TMetaFunc(_,_,_,_),_)
+    | (PC.TMetaLocalFunc(_,_,_,_),_) -> true
+    | (PC.TMetaParam(_,_,_),_)
+    | (PC.TMetaParamList(_,_,_,_),_)
+    | (PC.TMetaConst(_,_,_,_,_),_)
+    | (PC.TMetaErr(_,_,_,_),_)
+    | (PC.TMetaExp(_,_,_,_,_),_)
+    | (PC.TMetaIdExp(_,_,_,_,_),_)
+    | (PC.TMetaLocalIdExp(_,_,_,_,_),_)
+    | (PC.TMetaExpList(_,_,_,_),_)
+    | (PC.TMetaType(_,_,_),_)
+    | (PC.TMetaInit(_,_,_),_)
+    | (PC.TMetaStm(_,_,_),_)
+    | (PC.TMetaStmList(_,_,_),_)
+    | (PC.TMetaPos(_,_,_,_),_) -> in_meta_decls
+    | _ -> false in
+  let redo_id ident clt v =
+    !Data.add_type_name ident;
+    (PC.TTypeId(ident,clt),v) in
+  let rec loop start infn type_names = function
+      (* infn: 0 means not in a function header
+        > 0 means in a function header, after infn - 1 unmatched open parens*)
+      [] -> []
+    | ((PC.TOBrace(clt),v)::_) as all when in_meta_decls ->
+       collect_choices type_names all (* never a function header *)
+    | delim::(PC.TIdent(ident,clt),v)::((PC.TMul(_),_) as x)::rest
+      when is_delim infn delim ->
+       let newid = redo_id ident clt v in
+       delim::newid::x::(loop false infn (ident::type_names) rest)
+    | delim::(PC.TIdent(ident,clt),v)::id::rest
+      when is_delim infn delim && is_id id ->
+       let newid = redo_id ident clt v in
+       delim::newid::id::(loop false infn (ident::type_names) rest)
+    | ((PC.TFunDecl(_),_) as fn)::rest ->
+       fn::(loop false 1 type_names rest)
+    | ((PC.TOPar(_),_) as lp)::rest when infn > 0 ->
+       lp::(loop false (infn + 1) type_names rest)
+    | ((PC.TCPar(_),_) as rp)::rest when infn > 0 ->
+       if infn - 1 = 1
+       then rp::(loop false 0 type_names rest) (* 0 means not in fn header *)
+       else rp::(loop false (infn - 1) type_names rest)
+    | (PC.TIdent(ident,clt),v)::((PC.TMul(_),_) as x)::rest when start ->
+       let newid = redo_id ident clt v in
+       newid::x::(loop false infn (ident::type_names) rest)
+    | (PC.TIdent(ident,clt),v)::id::rest when start && is_id id ->
+       let newid = redo_id ident clt v in
+       newid::id::(loop false infn (ident::type_names) rest)
+    | (PC.TIdent(ident,clt),v)::rest when List.mem ident type_names ->
+       (PC.TTypeId(ident,clt),v)::(loop false infn type_names rest)
+    | ((PC.TIdent(ident,clt),v) as x)::rest ->
+       x::(loop false infn type_names rest)
+    | x::rest -> x::(loop false infn type_names rest)
+  and collect_choices type_names = function
+      [] -> [] (* should happen, but let the parser detect that *)
+    | (PC.TCBrace(clt),v)::rest ->
+       (PC.TCBrace(clt),v)::(loop false 0 type_names rest)
+    | delim::(PC.TIdent(ident,clt),v)::rest
+      when is_choices_delim delim ->
+       let newid = redo_id ident clt v in
+       delim::newid::(collect_choices (ident::type_names) rest)
+    | x::rest -> x::(collect_choices type_names rest) in
+  loop true 0 [] l
+
+
+(* ----------------------------------------------------------------------- *)
+(* Insert TLineEnd tokens at the end of a line that contains a WHEN.
+   WHEN is restricted to a single line, to avoid ambiguity in eg:
+   ... WHEN != x
+   +3 *)
+
+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.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)
+  | PC.Tvolatile(clt)
+
+  | PC.TInc(clt) | PC.TDec(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) | PC.TSizeof (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.TMetaDeclarer(_,_,_,clt) | PC.TMetaIterator(_,_,_,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.TDmOp(_,clt) | PC.TTilde (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.TMetaStm(_,_,clt) | PC.TMetaStmList(_,_,clt) | PC.TMetaFunc(_,_,_,clt)
+  | PC.TMetaLocalFunc(_,_,_,clt) | PC.TMetaPos(_,_,_,clt)
+
+  | PC.TFunDecl(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.TOPar0(clt) | PC.TMid0(clt) | PC.TCPar(clt)
+  | PC.TCPar0(clt)
+
+  | PC.TOBrace(clt) | PC.TCBrace(clt) | PC.TOCro(clt) | PC.TCCro(clt)
+  | PC.TOInit(clt)
+
+  | PC.TPtrOp(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) ->
+      let (_,line,_,_,_,_,_,_) = clt in Some line
+
+  | _ -> None
+
+let rec insert_line_end = function
+    [] -> []
+  | (((PC.TWhen(clt),q) as x)::xs) ->
+      x::(find_line_end true (token2line x) clt q 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)
+  | x::xs -> x::(insert_line_end xs)
+
+and find_line_end inwhen line clt q = function
+    (* don't know what 2nd component should be so just use the info of
+       the When.  Also inherit - of when, if any *)
+    [] -> [(PC.TLineEnd(clt),q)]
+  | ((PC.TIdent("strict",clt),a) as x)::xs when token2line x = line ->
+      (PC.TStrict(clt),a) :: (find_line_end inwhen line clt q xs)
+  | ((PC.TIdent("STRICT",clt),a) as x)::xs when token2line x = line ->
+      (PC.TStrict(clt),a) :: (find_line_end inwhen line clt q xs)
+  | ((PC.TIdent("any",clt),a) as x)::xs when token2line x = line ->
+      (PC.TAny(clt),a) :: (find_line_end inwhen line clt q xs)
+  | ((PC.TIdent("ANY",clt),a) as x)::xs when token2line x = line ->
+      (PC.TAny(clt),a) :: (find_line_end inwhen line clt q xs)
+  | ((PC.TIdent("forall",clt),a) as x)::xs when token2line x = line ->
+      (PC.TForall,a) :: (find_line_end inwhen line clt q xs)
+  | ((PC.TIdent("exists",clt),a) as x)::xs when token2line x = line ->
+      (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)
+  | x::xs when token2line x = line -> x :: (find_line_end inwhen line clt q xs)
+  | xs -> (PC.TLineEnd(clt),q)::(insert_line_end xs)
+
+let rec translate_when_true_false = function
+    [] -> []
+  | (PC.TWhen(clt),q)::((PC.TNotEq(_),_) as x)::(PC.TIdent("true",_),_)::xs ->
+      (PC.TWhenTrue(clt),q)::x::(translate_when_true_false xs)
+  | (PC.TWhen(clt),q)::((PC.TNotEq(_),_) as x)::(PC.TIdent("false",_),_)::xs ->
+      (PC.TWhenFalse(clt),q)::x::(translate_when_true_false xs)
+  | x::xs -> x :: (translate_when_true_false xs)
+
+(* ----------------------------------------------------------------------- *)
+(* top level initializers: a sequence of braces followed by a dot *)
+
+let find_top_init tokens =
+  match tokens with
+    (PC.TOBrace(clt),q) :: rest ->
+      let rec dot_start acc = function
+         ((PC.TOBrace(_),_) as x) :: rest ->
+           dot_start (x::acc) rest
+       | ((PC.TDot(_),_) :: rest) as x ->
+           Some ((PC.TOInit(clt),q) :: (List.rev acc) @ x)
+       | l -> None in
+      let rec comma_end acc = function
+         ((PC.TCBrace(_),_) as x) :: rest ->
+           comma_end (x::acc) rest
+       | ((PC.TComma(_),_) :: rest) as x ->
+           Some ((PC.TOInit(clt),q) :: (List.rev x) @ acc)
+       | l -> None in
+      (match dot_start [] rest with
+       Some x -> x
+      |        None ->
+         (match List.rev rest with
+           (* not super sure what this does, but EOF, @, and @@ should be
+              the same, markind the end of a rule *)
+           ((PC.EOF,_) as x)::rest | ((PC.TArob,_) as x)::rest
+         | ((PC.TArobArob,_) as x)::rest ->
+             (match comma_end [x] rest with
+               Some x -> x
+             | None -> tokens)
+         | _ ->
+             failwith "unexpected empty token list"))
+  | _ -> tokens
+
+(* ----------------------------------------------------------------------- *)
+(* process pragmas: they can only be used in + code, and adjacent to
+another + token.  They are concatenated to the string representation of
+that other token. *)
+
+let rec collect_all_pragmas collected = function
+    (PC.TPragma(s),_)::rest -> collect_all_pragmas (s::collected) rest
+  | l -> (List.rev collected,l)
+
+let rec collect_up_to_pragmas skipped = function
+    [] -> None (* didn't reach a pragma, so nothing to do *)
+  | ((PC.TPragma(s),_) as t)::rest ->
+      let (pragmas,rest) = collect_all_pragmas [] (t::rest) in
+      Some (List.rev skipped,pragmas,rest)
+  | x::xs ->
+      match plus_attachable x with
+       PLUS -> None
+      |        NOTPLUS -> None
+      |        SKIP -> collect_up_to_pragmas (x::skipped) xs
+
+let rec collect_up_to_plus skipped = function
+    [] -> failwith "nothing to attach a pragma to (empty)"
+  | x::xs ->
+      match plus_attachable x with
+       PLUS -> (List.rev skipped,x,xs)
+      |        NOTPLUS -> failwith "nothing to attach a pragma to"
+      |        SKIP -> collect_up_to_plus (x::skipped) xs
+
+let rec process_pragmas = function
+    [] -> []
+  | ((PC.TPragma(s),_)::_) as l ->
+      let (pragmas,rest) = collect_all_pragmas [] l in
+      let (skipped,aft,rest) = collect_up_to_plus [] rest in
+      let (a,b,c,d,e,strbef,straft,pos) = get_clt aft in
+      skipped@
+      (process_pragmas ((update_clt aft (a,b,c,d,e,pragmas,straft,pos))::rest))
+  | bef::xs ->
+      (match plus_attachable bef with
+       PLUS ->
+         (match collect_up_to_pragmas [] xs with
+           Some(skipped,pragmas,rest) ->
+             let (a,b,c,d,e,strbef,straft,pos) = get_clt bef in
+             (update_clt bef (a,b,c,d,e,strbef,pragmas,pos))::
+             skipped@(process_pragmas rest)
+         | None -> bef::(process_pragmas xs))
+      |        _ -> bef::(process_pragmas xs))
+
+(* ----------------------------------------------------------------------- *)
+(* Drop ... ... .  This is only allowed in + code, and arises when there is
+some - code between the ... *)
+(* drop whens as well - they serve no purpose in + code and they cause
+problems for drop_double_dots *)
+
+let rec drop_when = function
+    [] -> []
+  | (PC.TWhen(clt),info)::xs ->
+      let rec loop = function
+         [] -> []
+       | (PC.TLineEnd(_),info)::xs -> drop_when xs
+       | x::xs -> loop xs in
+      loop xs
+  | x::xs -> x::drop_when xs
+
+(* instead of dropping the double dots, we put TNothing in between them.
+these vanish after the parser, but keeping all the ...s in the + code makes
+it easier to align the + and - code in context_neg and in preparation for the
+isomorphisms.  This shouldn't matter because the context code of the +
+slice is mostly ignored anyway *)
+let minus_to_nothing l =
+  (* for cases like | <..., which may or may not arise from removing minus
+     code, depending on whether <... is a statement or expression *)
+  let is_minus tok =
+    try
+      let (d,_,_,_,_,_,_,_) = get_clt tok in
+      (match d with
+       D.MINUS | D.OPTMINUS | D.UNIQUEMINUS -> true
+      | D.PLUS -> false
+      | D.CONTEXT | D.UNIQUE | D.OPT -> false)
+    with _ -> false in
+  let rec minus_loop = function
+      [] -> []
+    | (d::ds) as l -> if is_minus d then minus_loop ds else l in
+  let rec loop = function
+      [] -> []
+    | ((PC.TMid0(clt),i) as x)::t1::ts when is_minus t1 ->
+       (match minus_loop ts with
+         ((PC.TOEllipsis(_),_)::_) | ((PC.TPOEllipsis(_),_)::_)
+       | ((PC.TEllipsis(_),_)::_) as l -> x::(PC.TNothing,i)::(loop l)
+       | l -> x::(loop l))
+    | t::ts -> t::(loop ts) in
+  loop l
+
+let rec drop_double_dots l =
+  let start = function
+      (PC.TOEllipsis(_),_) | (PC.TPOEllipsis(_),_)
+ (* | (PC.TOCircles(_),_) | (PC.TOStars(_),_) *) ->
+       true
+    | _ -> false in
+  let middle = function
+      (PC.TEllipsis(_),_) (* | (PC.TCircles(_),_) | (PC.TStars(_),_) *) -> true
+    | _ -> false in
+  let whenline = function
+      (PC.TLineEnd(_),_) -> true
+    (*| (PC.TMid0(_),_) -> true*)
+    | _ -> false in
+  let final = function
+      (PC.TCEllipsis(_),_) | (PC.TPCEllipsis(_),_)
+ (* | (PC.TCCircles(_),_) | (PC.TCStars(_),_) *) ->
+       true
+    | _ -> false in
+  let any_before x = start x or middle x or final x or whenline x in
+  let any_after x = start x or middle x or final x in
+  let rec loop ((_,i) as prev) = function
+      [] -> []
+    | x::rest when any_before prev && any_after x ->
+       (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
+
+(* ( | ... | ) also causes parsing problems *)
+
+exception Not_empty
+
+let rec drop_empty_thing starter middle ender = function
+    [] -> []
+  | hd::rest when starter hd ->
+      let rec loop = function
+         x::rest when middle x -> loop rest
+       | x::rest when ender x -> rest
+       | _ -> raise Not_empty in
+      (match try Some(loop rest) with Not_empty -> None with
+       Some x -> drop_empty_thing starter middle ender x
+      |        None -> hd :: drop_empty_thing starter middle ender rest)
+  | x::rest -> x :: drop_empty_thing starter middle ender rest
+
+let drop_empty_or =
+  drop_empty_thing
+    (function (PC.TOPar0(_),_) -> true | _ -> false)
+    (function (PC.TMid0(_),_) -> true | _ -> false)
+    (function (PC.TCPar0(_),_) -> true | _ -> false)
+
+let drop_empty_nest = drop_empty_thing
+
+(* ----------------------------------------------------------------------- *)
+(* Read tokens *)
+
+let get_s_starts (_, (s,_,(starts, ends))) =
+  Printf.printf "%d %d\n" starts ends; (s, starts)
+
+let pop2 l =
+  let v = List.hd !l in
+  l := List.tl !l;
+  v
+
+let reinit _ =
+  PC.reinit (function _ -> PC.TArobArob (* a handy token *))
+    (Lexing.from_function
+       (function buf -> function n -> raise Common.Impossible))
+
+let parse_one str parsefn file toks =
+  let all_tokens = ref toks in
+  let cur_tok    = ref (List.hd !all_tokens) in
+
+  let lexer_function _ =
+      let (v, info) = pop2 all_tokens in
+      cur_tok := (v, info);
+      v in
+
+  let lexbuf_fake =
+    Lexing.from_function
+      (function buf -> function n -> raise Common.Impossible)
+  in
+
+  reinit();
+
+  try parsefn lexer_function lexbuf_fake
+  with
+    Lexer_cocci.Lexical s ->
+      failwith
+       (Printf.sprintf "%s: lexical error: %s\n =%s\n" str s
+          (Common.error_message file (get_s_starts !cur_tok) ))
+  | Parser_cocci_menhir.Error ->
+      failwith
+       (Printf.sprintf "%s: parse error: \n = %s\n" str
+          (Common.error_message file (get_s_starts !cur_tok) ))
+  | Semantic_cocci.Semantic s ->
+      failwith
+       (Printf.sprintf "%s: semantic error: %s\n =%s\n" str s
+          (Common.error_message file (get_s_starts !cur_tok) ))
+
+  | e -> raise e
+
+let prepare_tokens tokens =
+  find_top_init
+    (translate_when_true_false (* after insert_line_end *)
+       (insert_line_end
+         (detect_types false (find_function_names (detect_attr tokens)))))
+
+let prepare_mv_tokens tokens =
+  detect_types false (detect_attr tokens)
+
+let rec consume_minus_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
+
+let any_modif rule =
+  let mcode x =
+    match Ast0.get_mcode_mcodekind x with
+      Ast0.MINUS _ | Ast0.PLUS -> true
+    | _ -> false in
+  let donothing r k e = k e in
+  let bind x y = x or y in
+  let option_default = false in
+  let fn =
+    V0.combiner bind option_default
+      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
+  List.exists fn.V0.combiner_top_level rule
+
+let drop_last extra l = List.rev(extra@(List.tl(List.rev l)))
+
+let partition_either l =
+  let rec part_either left right = function
+  | [] -> (List.rev left, List.rev right)
+  | x :: l ->
+      (match x with
+      | Common.Left  e -> part_either (e :: left) right l
+      | Common.Right e -> part_either left (e :: right) l) in
+  part_either [] [] l
+
+let get_metavars parse_fn table file lexbuf =
+  let rec meta_loop acc (* read one decl at a time *) =
+    let (_,tokens) =
+      tokens_all table file true lexbuf [PC.TArobArob;PC.TMPtVirg] in
+    let tokens = prepare_mv_tokens tokens in
+    match tokens with
+      [(PC.TArobArob,_)] -> List.rev acc
+    | _ ->
+       let metavars = parse_one "meta" parse_fn file tokens in
+       meta_loop (metavars@acc) in
+  partition_either (meta_loop [])
+
+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
+    let tokens = prepare_tokens tokens in
+    match tokens with
+      [(PC.TArobArob, _)] -> List.rev acc
+    | _ ->
+      let metavar = parse_one "scriptmeta" parse_fn file tokens in
+      meta_loop (metavar :: acc)
+  in
+  meta_loop []
+
+let get_rule_name parse_fn starts_with_name get_tokens file prefix =
+  Data.in_rule_name := true;
+  let mknm _ = make_name prefix (!Lexer_cocci.line) in
+  let name_res =
+    if starts_with_name
+    then
+      let (_,tokens) = get_tokens [PC.TArob] in
+      let check_name = function
+         None -> Some (mknm())
+       | Some nm ->
+           (if List.mem nm reserved_names
+           then failwith (Printf.sprintf "invalid name %s\n" nm));
+           Some nm in
+      match parse_one "rule name" parse_fn file tokens with
+       Ast.CocciRulename (nm,a,b,c,d,e) ->
+          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)
+    else
+      Ast.CocciRulename(Some(mknm()),Ast.NoDep,[],[],Ast.Undetermined,false) in
+  Data.in_rule_name := false;
+  name_res
+
+let parse_iso file =
+  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
+    let res =
+      match get_tokens [PC.TArobArob;PC.TArob] with
+       (true,start) ->
+         let parse_start start =
+           let rev = List.rev start in
+           let (arob,_) = List.hd rev in
+           (arob = PC.TArob,List.rev(List.tl rev)) in
+         let (starts_with_name,start) = parse_start start in
+         let rec loop starts_with_name start =
+           (!Data.init_rule)();
+           (* get metavariable declarations - have to be read before the
+              rest *)
+           let (rule_name,_,_,_,_,_) =
+              match get_rule_name PC.iso_rule_name starts_with_name get_tokens
+               file ("iso file "^file) with
+                Ast.CocciRulename (Some n,a,b,c,d,e) -> (n,a,b,c,d,e)
+              | _ -> failwith "Script rules cannot appear in isomorphism rules"
+              in
+           Ast0.rule_name := rule_name;
+           Data.in_meta := true;
+           let iso_metavars =
+             match get_metavars PC.iso_meta_main table file lexbuf with
+               (iso_metavars,[]) -> iso_metavars
+             | _ -> failwith "unexpected inheritance in iso" in
+           Data.in_meta := false;
+           (* get the rule *)
+           let (more,tokens) =
+             get_tokens
+               [PC.TIsoStatement;PC.TIsoExpression;PC.TIsoArgExpression;
+                 PC.TIsoTestExpression;
+                 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
+           let tokens = prepare_tokens (start@tokens) in
+            (*
+              print_tokens "iso tokens" tokens;
+           *)
+           let entry = parse_one "iso main" PC.iso_main file tokens in
+           let entry = List.map (List.map Test_exps.process_anything) entry in
+           if more
+           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
+               (true,start) ->
+                 let (starts_with_name,start) = parse_start start in
+                 (iso_metavars,entry,rule_name) ::
+                 (loop starts_with_name (next_start::start))
+             | _ -> failwith "isomorphism ends early"
+           else [(iso_metavars,entry,rule_name)] in
+         loop starts_with_name start
+      | (false,_) -> [] in
+    res)
+
+let parse_iso_files existing_isos iso_files extra_path =
+  let get_names = List.map (function (_,_,nm) -> nm) in
+  let old_names = get_names existing_isos in
+  Data.in_iso := true;
+  let (res,_) =
+    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
+         let current = parse_iso file in
+         let new_names = get_names current in
+         if List.exists (function x -> List.mem x names) new_names
+         then failwith (Printf.sprintf "repeated iso name found in %s" file);
+         (current::prev,new_names @ names))
+      ([],old_names) iso_files in
+  Data.in_iso := false;
+  existing_isos@(List.concat (List.rev res))
+
+let parse file =
+  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
+  Data.in_prolog := false;
+  let res =
+    match initial_tokens with
+    (true,data) ->
+      (match List.rev data with
+       ((PC.TArobArob as x),_)::_ | ((PC.TArob as x),_)::_ ->
+         let iso_files =
+           parse_one "iso file names" PC.include_main file data in
+
+          let parse_cocci_rule ruletype old_metas
+             (rule_name, dependencies, iso, dropiso, exists, is_expression) =
+            Ast0.rule_name := rule_name;
+            Data.inheritable_positions :=
+               rule_name :: !Data.inheritable_positions;
+
+            (* get metavariable declarations *)
+            Data.in_meta := true;
+            let (metavars, inherited_metavars) =
+              get_metavars PC.meta_main table file lexbuf in
+            Data.in_meta := false;
+            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 (minus_tokens, _) = split_token_stream tokens in
+            let (_, plus_tokens) =
+             split_token_stream (minus_to_nothing tokens) in
+
+           let minus_tokens = consume_minus_positions minus_tokens in
+           let minus_tokens = prepare_tokens minus_tokens in
+           let plus_tokens = prepare_tokens plus_tokens in
+
+           (*
+              print_tokens "minus tokens" minus_tokens;
+              print_tokens "plus tokens" plus_tokens;
+           *)
+
+           let plus_tokens =
+             process_pragmas
+               (fix (function x -> drop_double_dots (drop_empty_or x))
+                  (drop_when plus_tokens)) in
+           (*
+               print_tokens "plus tokens" plus_tokens;
+              Printf.printf "before minus parse\n";
+           *)
+           let minus_res =
+             if is_expression
+             then parse_one "minus" PC.minus_exp_main file minus_tokens
+             else parse_one "minus" PC.minus_main file minus_tokens in
+           (*
+              Unparse_ast0.unparse minus_res;
+              Printf.printf "before plus parse\n";
+           *)
+           let plus_res =
+             if !Flag.sgrep_mode2
+             then (* not actually used for anything, except context_neg *)
+               List.map
+                 (Iso_pattern.rebuild_mcode None).V0.rebuilder_top_level
+                 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
+           (*
+              Printf.printf "after plus parse\n";
+           *)
+
+           (if not !Flag.sgrep_mode2 &&
+             (any_modif minus_res or any_modif plus_res)
+           then Data.inheritable_positions := []);
+
+           Check_meta.check_meta rule_name old_metas inherited_metavars
+             metavars minus_res plus_res;
+
+            (more, Ast0.CocciRule ((minus_res, metavars,
+              (iso, dropiso, dependencies, rule_name, exists)),
+              (plus_res, metavars), ruletype), metavars, tokens) in
+
+          let parse_script_rule language old_metas deps =
+            let get_tokens = tokens_script_all table file false lexbuf in
+
+              (* meta-variables *)
+            Data.in_meta := true;
+            let metavars =
+             get_script_metavars PC.script_meta_main table file lexbuf in
+            Data.in_meta := false;
+
+            let exists_in old_metas (py,(r,m)) =
+              let test (rr,mr) x =
+                let (ro,vo) = Ast.get_meta_name x in
+                ro = rr && vo = mr in
+              List.exists (test (r,m)) old_metas in
+
+           List.iter
+             (function x ->
+               let meta2c (r,n) = Printf.sprintf "%s.%s" r n in
+               if not (exists_in old_metas x) then
+                 failwith
+                   (Printf.sprintf
+                      "Script references unknown meta-variable: %s"
+                      (meta2c(snd x))))
+             metavars;
+
+              (* script code *)
+            let (more, tokens) = get_tokens [PC.TArobArob; PC.TArob] in
+            let data =
+              match List.hd tokens with
+                (PC.TScriptData(s),_) -> s
+              | (PC.TArobArob,_) | (PC.TArob,_) -> ""
+              | _ -> failwith "Malformed script rule" in
+            (more,Ast0.ScriptRule(language, deps, metavars, data),[],tokens) 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
+            | _ -> failwith "Malformed rule name"
+            in
+
+         let rec loop old_metas starts_with_name =
+           (!Data.init_rule)();
+
+            let gen_starts_with_name more tokens =
+              more &&
+              (match List.hd (List.rev tokens) with
+                    (PC.TArobArob,_) -> false
+                  | (PC.TArob,_) -> true
+                  | _ -> failwith "unexpected token")
+            in
+
+            let (more, rule, metavars, tokens) =
+              parse_rule old_metas starts_with_name in
+            if more then
+              rule::
+             (loop (metavars @ old_metas) (gen_starts_with_name more tokens))
+            else [rule];
+
+            in
+
+         (iso_files, loop [] (x = PC.TArob))
+      |        _ -> failwith "unexpected code before the first rule\n")
+  | (false,[(PC.TArobArob,_)]) | (false,[(PC.TArob,_)]) ->
+      ([],([] : Ast0.parsed_rule list))
+  | _ -> failwith "unexpected code before the first rule\n" in
+  res)
+
+(* 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 std_isos =
+    match isofile with
+      None -> []
+    | Some iso_file -> parse_iso_files [] [Common.Left iso_file] "" in
+  let global_isos = parse_iso_files std_isos iso_files extra_path in
+  let rules = Unitary_ast0.do_unitary rules in
+  let parsed =
+    List.map
+      (function
+          Ast0.ScriptRule (a,b,c,d) -> [([],Ast.ScriptRule (a,b,c,d))]
+       | Ast0.CocciRule
+           ((minus, metavarsm,
+             (iso, dropiso, dependencies, rule_name, exists)),
+            (plus, metavars),ruletype) ->
+              let chosen_isos =
+                parse_iso_files global_isos
+                  (List.map (function x -> Common.Left x) iso)
+                  extra_path in
+              let chosen_isos =
+            (* check that dropped isos are actually available *)
+                (try
+                  let iso_names =
+                    List.map (function (_,_,nm) -> nm) chosen_isos in
+                  let local_iso_names = reserved_names @ iso_names in
+                  let bad_dropped =
+                    List.find
+                      (function dropped ->
+                        not (List.mem dropped local_iso_names))
+                      dropiso in
+                  failwith
+                    ("invalid iso name " ^ bad_dropped ^ " in " ^ rule_name)
+                with Not_found -> ());
+                if List.mem "all" dropiso
+                then
+                  if List.length dropiso = 1
+                  then []
+                  else failwith "disable all should only be by itself"
+                else (* drop those isos *)
+                  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 ->
+                    (match dropiso with
+                      ["all"] -> others
+                    | _ ->
+                        List.filter (function x -> List.mem x dropiso) others)
+                | _ ->
+                    failwith
+                      "bad list of reserved names - all must be at start" in
+              let minus = Test_exps.process minus in
+              let minus = Compute_lines.compute_lines minus in
+              let plus = Compute_lines.compute_lines plus in
+              let is_exp =
+                (* only relevant to Flag.make_hrule *)
+                (* doesn't handle multiple minirules properly, but since
+                   we don't really handle them in lots of other ways, it
+                   doesn't seem very important *)
+                match plus with
+                  [] -> [false]
+                | p::_ ->
+                    [match Ast0.unwrap p with
+                      Ast0.CODE c ->
+                        (match List.map Ast0.unwrap (Ast0.undots c) with
+                          [Ast0.Exp e] -> true | _ -> false)
+                    | _ -> false] in
+              let minus = Arity.minus_arity minus in
+              let ((metavars,minus),function_prototypes) =
+                Function_prototypes.process
+                  rule_name metavars dropped_isos minus plus ruletype in
+          (* 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
+              then Insert_plus.insert_plus m p (chosen_isos = []));
+              Type_infer.type_infer minus;
+              let (extra_meta, minus) =
+                match (chosen_isos,ruletype) with
+                  (* separate case for [] because applying isos puts
+                     some restrictions on the -+ code *)
+                  ([],_) | (_,Ast.Generated) -> ([],minus)
+                | _ -> Iso_pattern.apply_isos chosen_isos minus rule_name in
+              let minus = Comm_assoc.comm_assoc minus rule_name dropiso in
+              let minus =
+                if !Flag.sgrep_mode2 then minus
+                else Single_statement.single_statement minus in
+              let minus = Simple_assignments.simple_assignments 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 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)