--- /dev/null
+(*
+* 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)