2 * Copyright 2005-2008, Ecole des Mines de Nantes, University of Copenhagen
3 * Yoann Padioleau, Julia Lawall, Rene Rydhof Hansen, Henrik Stuart, Gilles Muller
4 * This file is part of Coccinelle.
6 * Coccinelle is free software: you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation, according to version 2 of the License.
10 * Coccinelle is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
15 * You should have received a copy of the GNU General Public License
16 * along with Coccinelle. If not, see <http://www.gnu.org/licenses/>.
18 * The authors reserve the right to distribute this or future versions of
19 * Coccinelle under other licenses.
23 (* splits the entire file into minus and plus fragments, and parses each
24 separately (thus duplicating work for the parsing of the context elements) *)
27 module PC = Parser_cocci_menhir
28 module V0 = Visitor_ast0
29 module Ast = Ast_cocci
30 module Ast0 = Ast0_cocci
31 let pr = Printf.sprintf
32 (*let pr2 s = prerr_string s; prerr_string "\n"; flush stderr*)
33 let pr2 s = Printf.printf "%s\n" s
35 (* for isomorphisms. all should be at the front!!! *)
37 ["all";"optional_storage";"optional_qualifier";"value_format";"comm_assoc"]
39 (* ----------------------------------------------------------------------- *)
42 let line_type (d,_,_,_,_,_,_,_) = d
45 match line_type tok with
46 D.MINUS | D.OPTMINUS | D.UNIQUEMINUS -> ":-"
48 | D.CONTEXT | D.UNIQUE | D.OPT -> ""
52 PC.TIdentifier -> "identifier"
54 | PC.TParameter -> "parameter"
55 | PC.TConstant -> "constant"
56 | PC.TExpression -> "expression"
57 | PC.TIdExpression -> "idexpression"
58 | PC.TStatement -> "statement"
59 | PC.TPosition -> "position"
61 | PC.TFunction -> "function"
62 | PC.TLocal -> "local"
64 | PC.TFresh -> "fresh"
66 | PC.TContext -> "context"
67 | PC.TTypedef -> "typedef"
68 | PC.TDeclarer -> "declarer"
69 | PC.TIterator -> "iterator"
71 | PC.TRuleName str -> "rule_name-"^str
72 | PC.TUsing -> "using"
73 | PC.TPathIsoFile str -> "path_iso_file-"^str
74 | PC.TDisable -> "disable"
75 | PC.TExtends -> "extends"
76 | PC.TDepends -> "depends"
79 | PC.TNever -> "never"
80 | PC.TExists -> "exists"
81 | PC.TForall -> "forall"
82 | PC.TReverse -> "reverse"
83 | PC.TError -> "error"
84 | PC.TWords -> "words"
86 | PC.TNothing -> "nothing"
88 | PC.Tchar(clt) -> "char"^(line_type2c clt)
89 | PC.Tshort(clt) -> "short"^(line_type2c clt)
90 | PC.Tint(clt) -> "int"^(line_type2c clt)
91 | PC.Tdouble(clt) -> "double"^(line_type2c clt)
92 | PC.Tfloat(clt) -> "float"^(line_type2c clt)
93 | PC.Tlong(clt) -> "long"^(line_type2c clt)
94 | PC.Tvoid(clt) -> "void"^(line_type2c clt)
95 | PC.Tstruct(clt) -> "struct"^(line_type2c clt)
96 | PC.Tunion(clt) -> "union"^(line_type2c clt)
97 | PC.Tunsigned(clt) -> "unsigned"^(line_type2c clt)
98 | PC.Tsigned(clt) -> "signed"^(line_type2c clt)
99 | PC.Tstatic(clt) -> "static"^(line_type2c clt)
100 | PC.Tinline(clt) -> "inline"^(line_type2c clt)
101 | PC.Ttypedef(clt) -> "typedef"^(line_type2c clt)
102 | PC.Tattr(s,clt) -> s^(line_type2c clt)
103 | PC.Tauto(clt) -> "auto"^(line_type2c clt)
104 | PC.Tregister(clt) -> "register"^(line_type2c clt)
105 | PC.Textern(clt) -> "extern"^(line_type2c clt)
106 | PC.Tconst(clt) -> "const"^(line_type2c clt)
107 | PC.Tvolatile(clt) -> "volatile"^(line_type2c clt)
110 | PC.TIncludeL(s,clt) -> (pr "#include \"%s\"" s)^(line_type2c clt)
111 | PC.TIncludeNL(s,clt) -> (pr "#include <%s>" s)^(line_type2c clt)
112 | PC.TDefine(clt,_) -> "#define"^(line_type2c clt)
113 | PC.TDefineParam(clt,_,_) -> "#define_param"^(line_type2c clt)
114 | PC.TMinusFile(s,clt) -> (pr "--- %s" s)^(line_type2c clt)
115 | PC.TPlusFile(s,clt) -> (pr "+++ %s" s)^(line_type2c clt)
117 | PC.TInc(clt) -> "++"^(line_type2c clt)
118 | PC.TDec(clt) -> "--"^(line_type2c clt)
120 | PC.TIf(clt) -> "if"^(line_type2c clt)
121 | PC.TElse(clt) -> "else"^(line_type2c clt)
122 | PC.TWhile(clt) -> "while"^(line_type2c clt)
123 | PC.TFor(clt) -> "for"^(line_type2c clt)
124 | PC.TDo(clt) -> "do"^(line_type2c clt)
125 | PC.TSwitch(clt) -> "switch"^(line_type2c clt)
126 | PC.TCase(clt) -> "case"^(line_type2c clt)
127 | PC.TDefault(clt) -> "default"^(line_type2c clt)
128 | PC.TReturn(clt) -> "return"^(line_type2c clt)
129 | PC.TBreak(clt) -> "break"^(line_type2c clt)
130 | PC.TContinue(clt) -> "continue"^(line_type2c clt)
131 | PC.TGoto(clt) -> "goto"^(line_type2c clt)
132 | PC.TIdent(s,clt) -> (pr "ident-%s" s)^(line_type2c clt)
133 | PC.TTypeId(s,clt) -> (pr "typename-%s" s)^(line_type2c clt)
134 | PC.TDeclarerId(s,clt) -> (pr "declarername-%s" s)^(line_type2c clt)
135 | PC.TIteratorId(s,clt) -> (pr "iteratorname-%s" s)^(line_type2c clt)
136 | PC.TMetaDeclarer(_,_,_,clt) -> "declmeta"^(line_type2c clt)
137 | PC.TMetaIterator(_,_,_,clt) -> "itermeta"^(line_type2c clt)
139 | PC.TSizeof(clt) -> "sizeof"^(line_type2c clt)
141 | PC.TString(x,clt) -> x^(line_type2c clt)
142 | PC.TChar(x,clt) -> x^(line_type2c clt)
143 | PC.TFloat(x,clt) -> x^(line_type2c clt)
144 | PC.TInt(x,clt) -> x^(line_type2c clt)
146 | PC.TOrLog(clt) -> "||"^(line_type2c clt)
147 | PC.TAndLog(clt) -> "&&"^(line_type2c clt)
148 | PC.TOr(clt) -> "|"^(line_type2c clt)
149 | PC.TXor(clt) -> "^"^(line_type2c clt)
150 | PC.TAnd (clt) -> "&"^(line_type2c clt)
151 | PC.TEqEq(clt) -> "=="^(line_type2c clt)
152 | PC.TNotEq(clt) -> "!="^(line_type2c clt)
153 | PC.TLogOp(op,clt) ->
159 | _ -> failwith "not possible")
161 | PC.TShOp(op,clt) ->
164 | Ast.DecRight -> ">>"
165 | _ -> failwith "not possible")
167 | PC.TPlus(clt) -> "+"^(line_type2c clt)
168 | PC.TMinus(clt) -> "-"^(line_type2c clt)
169 | PC.TMul(clt) -> "*"^(line_type2c clt)
170 | PC.TDmOp(op,clt) ->
174 | _ -> failwith "not possible")
176 | PC.TTilde (clt) -> "~"^(line_type2c clt)
178 | PC.TMetaParam(_,_,clt) -> "parammeta"^(line_type2c clt)
179 | PC.TMetaParamList(_,_,_,clt) -> "paramlistmeta"^(line_type2c clt)
180 | PC.TMetaConst(_,_,_,_,clt) -> "constmeta"^(line_type2c clt)
181 | PC.TMetaErr(_,_,_,clt) -> "errmeta"^(line_type2c clt)
182 | PC.TMetaExp(_,_,_,_,clt) -> "expmeta"^(line_type2c clt)
183 | PC.TMetaIdExp(_,_,_,_,clt) -> "idexpmeta"^(line_type2c clt)
184 | PC.TMetaLocalIdExp(_,_,_,_,clt) -> "localidexpmeta"^(line_type2c clt)
185 | PC.TMetaExpList(_,_,_,clt) -> "explistmeta"^(line_type2c clt)
186 | PC.TMetaId(_,_,_,clt) -> "idmeta"^(line_type2c clt)
187 | PC.TMetaType(_,_,clt) -> "typemeta"^(line_type2c clt)
188 | PC.TMetaStm(_,_,clt) -> "stmmeta"^(line_type2c clt)
189 | PC.TMetaStmList(_,_,clt) -> "stmlistmeta"^(line_type2c clt)
190 | PC.TMetaFunc(_,_,_,clt) -> "funcmeta"^(line_type2c clt)
191 | PC.TMetaLocalFunc(_,_,_,clt) -> "funcmeta"^(line_type2c clt)
192 | PC.TMetaPos(_,_,_,clt) -> "posmeta"
194 | PC.TArobArob -> "@@"
198 | PC.TWhen(clt) -> "WHEN"^(line_type2c clt)
199 | PC.TAny(clt) -> "ANY"^(line_type2c clt)
200 | PC.TStrict(clt) -> "STRICT"^(line_type2c clt)
201 | PC.TEllipsis(clt) -> "..."^(line_type2c clt)
203 | PC.TCircles(clt) -> "ooo"^(line_type2c clt)
204 | PC.TStars(clt) -> "***"^(line_type2c clt)
207 | PC.TOEllipsis(clt) -> "<..."^(line_type2c clt)
208 | PC.TCEllipsis(clt) -> "...>"^(line_type2c clt)
209 | PC.TPOEllipsis(clt) -> "<+..."^(line_type2c clt)
210 | PC.TPCEllipsis(clt) -> "...+>"^(line_type2c clt)
212 | PC.TOCircles(clt) -> "<ooo"^(line_type2c clt)
213 | PC.TCCircles(clt) -> "ooo>"^(line_type2c clt)
214 | PC.TOStars(clt) -> "<***"^(line_type2c clt)
215 | PC.TCStars(clt) -> "***>"^(line_type2c clt)
221 | PC.TWhy(clt) -> "?"^(line_type2c clt)
222 | PC.TDotDot(clt) -> ":"^(line_type2c clt)
223 | PC.TBang(clt) -> "!"^(line_type2c clt)
224 | PC.TOPar(clt) -> "("^(line_type2c clt)
225 | PC.TOPar0(clt) -> "("^(line_type2c clt)
226 | PC.TMid0(clt) -> "|"^(line_type2c clt)
227 | PC.TCPar(clt) -> ")"^(line_type2c clt)
228 | PC.TCPar0(clt) -> ")"^(line_type2c clt)
230 | PC.TOBrace(clt) -> "{"^(line_type2c clt)
231 | PC.TCBrace(clt) -> "}"^(line_type2c clt)
232 | PC.TOCro(clt) -> "["^(line_type2c clt)
233 | PC.TCCro(clt) -> "]"^(line_type2c clt)
235 | PC.TPtrOp(clt) -> "->"^(line_type2c clt)
237 | PC.TEq(clt) -> "="^(line_type2c clt)
238 | PC.TAssign(_,clt) -> "=op"^(line_type2c clt)
239 | PC.TDot(clt) -> "."^(line_type2c clt)
240 | PC.TComma(clt) -> ","^(line_type2c clt)
241 | PC.TPtVirg(clt) -> ";"^(line_type2c clt)
244 | PC.TLineEnd(clt) -> "line end"
245 | PC.TInvalid -> "invalid"
246 | PC.TFunDecl(clt) -> "fundecl"
249 | PC.TRightIso -> "=>"
250 | PC.TIsoTopLevel -> "TopLevel"
251 | PC.TIsoExpression -> "Expression"
252 | PC.TIsoArgExpression -> "ArgExpression"
253 | PC.TIsoTestExpression -> "TestExpression"
254 | PC.TIsoStatement -> "Statement"
255 | PC.TIsoDeclaration -> "Declaration"
256 | PC.TIsoType -> "Type"
257 | PC.TScriptData s -> s
259 let print_tokens s tokens =
260 Printf.printf "%s\n" s;
261 List.iter (function x -> Printf.printf "%s " (token2c x)) tokens;
262 Printf.printf "\n\n";
265 type plus = PLUS | NOTPLUS | SKIP
267 let plus_attachable (tok,_) =
269 PC.Tchar(clt) | PC.Tshort(clt) | PC.Tint(clt) | PC.Tdouble(clt)
270 | PC.Tfloat(clt) | PC.Tlong(clt) | PC.Tvoid(clt) | PC.Tstruct(clt)
271 | PC.Tunion(clt) | PC.Tunsigned(clt) | PC.Tsigned(clt) | PC.Tstatic(clt)
272 | PC.Tinline(clt) | PC.Ttypedef(clt) | PC.Tattr(_,clt)
273 | PC.Tauto(clt) | PC.Tregister(clt)
274 | PC.Textern(clt) | PC.Tconst(clt) | PC.Tvolatile(clt)
276 | PC.TIncludeL(_,clt) | PC.TIncludeNL(_,clt) | PC.TDefine(clt,_)
277 | PC.TDefineParam(clt,_,_) | PC.TMinusFile(_,clt) | PC.TPlusFile(_,clt)
279 | PC.TInc(clt) | PC.TDec(clt)
281 | PC.TIf(clt) | PC.TElse(clt) | PC.TWhile(clt) | PC.TFor(clt) | PC.TDo(clt)
282 | PC.TSwitch(clt) | PC.TCase(clt) | PC.TDefault(clt) | PC.TReturn(clt)
283 | PC.TBreak(clt) | PC.TContinue(clt) | PC.TGoto(clt) | PC.TIdent(_,clt)
284 | PC.TTypeId(_,clt) | PC.TDeclarerId(_,clt) | PC.TIteratorId(_,clt)
288 | PC.TString(_,clt) | PC.TChar(_,clt) | PC.TFloat(_,clt) | PC.TInt(_,clt)
290 | PC.TOrLog(clt) | PC.TAndLog(clt) | PC.TOr(clt) | PC.TXor(clt)
291 | PC.TAnd (clt) | PC.TEqEq(clt) | PC.TNotEq(clt) | PC.TLogOp(_,clt)
292 | PC.TShOp(_,clt) | PC.TPlus(clt) | PC.TMinus(clt) | PC.TMul(clt)
293 | PC.TDmOp(_,clt) | PC.TTilde (clt)
295 | PC.TMetaParam(_,_,clt) | PC.TMetaParamList(_,_,_,clt)
296 | PC.TMetaConst(_,_,_,_,clt) | PC.TMetaErr(_,_,_,clt)
297 | PC.TMetaExp(_,_,_,_,clt) | PC.TMetaIdExp(_,_,_,_,clt)
298 | PC.TMetaLocalIdExp(_,_,_,_,clt)
299 | PC.TMetaExpList(_,_,_,clt)
300 | PC.TMetaId(_,_,_,clt)
301 | PC.TMetaType(_,_,clt) | PC.TMetaStm(_,_,clt)
302 | PC.TMetaStmList(_,_,clt) | PC.TMetaFunc(_,_,_,clt)
303 | PC.TMetaLocalFunc(_,_,_,clt)
305 | PC.TWhen(clt) | PC.TAny(clt) | PC.TStrict(clt) | PC.TEllipsis(clt)
306 (* | PC.TCircles(clt) | PC.TStars(clt) *)
308 | PC.TWhy(clt) | PC.TDotDot(clt) | PC.TBang(clt) | PC.TOPar(clt)
311 | PC.TOBrace(clt) | PC.TCBrace(clt) | PC.TOCro(clt) | PC.TCCro(clt)
315 | PC.TEq(clt) | PC.TAssign(_,clt) | PC.TDot(clt) | PC.TComma(clt)
317 if line_type clt = D.PLUS then PLUS else NOTPLUS
319 | PC.TOPar0(clt) | PC.TMid0(clt) | PC.TCPar0(clt)
320 | PC.TOEllipsis(clt) | PC.TCEllipsis(clt)
321 | PC.TPOEllipsis(clt) | PC.TPCEllipsis(clt) (* | PC.TOCircles(clt)
322 | PC.TCCircles(clt) | PC.TOStars(clt) | PC.TCStars(clt) *) -> NOTPLUS
323 | PC.TMetaPos(nm,_,_,_) -> NOTPLUS
327 let get_clt (tok,_) =
329 PC.Tchar(clt) | PC.Tshort(clt) | PC.Tint(clt) | PC.Tdouble(clt)
330 | PC.Tfloat(clt) | PC.Tlong(clt) | PC.Tvoid(clt) | PC.Tstruct(clt)
331 | PC.Tunion(clt) | PC.Tunsigned(clt) | PC.Tsigned(clt) | PC.Tstatic(clt)
332 | PC.Tinline(clt) | PC.Tattr(_,clt) | PC.Tauto(clt) | PC.Tregister(clt)
333 | PC.Textern(clt) | PC.Tconst(clt) | PC.Tvolatile(clt)
335 | PC.TIncludeL(_,clt) | PC.TIncludeNL(_,clt) | PC.TDefine(clt,_)
336 | PC.TDefineParam(clt,_,_) | PC.TMinusFile(_,clt) | PC.TPlusFile(_,clt)
338 | PC.TInc(clt) | PC.TDec(clt)
340 | PC.TIf(clt) | PC.TElse(clt) | PC.TWhile(clt) | PC.TFor(clt) | PC.TDo(clt)
341 | PC.TSwitch(clt) | PC.TCase(clt) | PC.TDefault(clt) | PC.TReturn(clt)
342 | PC.TBreak(clt) | PC.TContinue(clt) | PC.TGoto(clt) | PC.TIdent(_,clt)
343 | PC.TTypeId(_,clt) | PC.TDeclarerId(_,clt) | PC.TIteratorId(_,clt)
347 | PC.TString(_,clt) | PC.TChar(_,clt) | PC.TFloat(_,clt) | PC.TInt(_,clt)
349 | PC.TOrLog(clt) | PC.TAndLog(clt) | PC.TOr(clt) | PC.TXor(clt)
350 | PC.TAnd (clt) | PC.TEqEq(clt) | PC.TNotEq(clt) | PC.TLogOp(_,clt)
351 | PC.TShOp(_,clt) | PC.TPlus(clt) | PC.TMinus(clt) | PC.TMul(clt)
352 | PC.TDmOp(_,clt) | PC.TTilde (clt)
354 | PC.TMetaParam(_,_,clt) | PC.TMetaParamList(_,_,_,clt)
355 | PC.TMetaConst(_,_,_,_,clt) | PC.TMetaErr(_,_,_,clt)
356 | PC.TMetaExp(_,_,_,_,clt) | PC.TMetaIdExp(_,_,_,_,clt)
357 | PC.TMetaLocalIdExp(_,_,_,_,clt)
358 | PC.TMetaExpList(_,_,_,clt)
359 | PC.TMetaId(_,_,_,clt)
360 | PC.TMetaType(_,_,clt) | PC.TMetaStm(_,_,clt)
361 | PC.TMetaStmList(_,_,clt) | PC.TMetaFunc(_,_,_,clt)
362 | PC.TMetaLocalFunc(_,_,_,clt) | PC.TMetaPos(_,_,_,clt)
364 | PC.TWhen(clt) | PC.TAny(clt) | PC.TStrict(clt) | PC.TEllipsis(clt)
365 (* | PC.TCircles(clt) | PC.TStars(clt) *)
367 | PC.TWhy(clt) | PC.TDotDot(clt) | PC.TBang(clt) | PC.TOPar(clt)
370 | PC.TOBrace(clt) | PC.TCBrace(clt) | PC.TOCro(clt) | PC.TCCro(clt)
374 | PC.TEq(clt) | PC.TAssign(_,clt) | PC.TDot(clt) | PC.TComma(clt)
377 | PC.TOPar0(clt) | PC.TMid0(clt) | PC.TCPar0(clt)
378 | PC.TOEllipsis(clt) | PC.TCEllipsis(clt)
379 | PC.TPOEllipsis(clt) | PC.TPCEllipsis(clt) (* | PC.TOCircles(clt)
380 | PC.TCCircles(clt) | PC.TOStars(clt) | PC.TCStars(clt) *) -> clt
382 | _ -> failwith "no clt"
384 let update_clt (tok,x) clt =
386 PC.Tchar(_) -> (PC.Tchar(clt),x)
387 | PC.Tshort(_) -> (PC.Tshort(clt),x)
388 | PC.Tint(_) -> (PC.Tint(clt),x)
389 | PC.Tdouble(_) -> (PC.Tdouble(clt),x)
390 | PC.Tfloat(_) -> (PC.Tfloat(clt),x)
391 | PC.Tlong(_) -> (PC.Tlong(clt),x)
392 | PC.Tvoid(_) -> (PC.Tvoid(clt),x)
393 | PC.Tstruct(_) -> (PC.Tstruct(clt),x)
394 | PC.Tunion(_) -> (PC.Tunion(clt),x)
395 | PC.Tunsigned(_) -> (PC.Tunsigned(clt),x)
396 | PC.Tsigned(_) -> (PC.Tsigned(clt),x)
397 | PC.Tstatic(_) -> (PC.Tstatic(clt),x)
398 | PC.Tinline(_) -> (PC.Tinline(clt),x)
399 | PC.Ttypedef(_) -> (PC.Ttypedef(clt),x)
400 | PC.Tattr(s,_) -> (PC.Tattr(s,clt),x)
401 | PC.Tauto(_) -> (PC.Tauto(clt),x)
402 | PC.Tregister(_) -> (PC.Tregister(clt),x)
403 | PC.Textern(_) -> (PC.Textern(clt),x)
404 | PC.Tconst(_) -> (PC.Tconst(clt),x)
405 | PC.Tvolatile(_) -> (PC.Tvolatile(clt),x)
407 | PC.TIncludeL(s,_) -> (PC.TIncludeL(s,clt),x)
408 | PC.TIncludeNL(s,_) -> (PC.TIncludeNL(s,clt),x)
409 | PC.TDefine(_,a) -> (PC.TDefine(clt,a),x)
410 | PC.TDefineParam(_,a,b) -> (PC.TDefineParam(clt,a,b),x)
411 | PC.TMinusFile(s,_) -> (PC.TMinusFile(s,clt),x)
412 | PC.TPlusFile(s,_) -> (PC.TPlusFile(s,clt),x)
414 | PC.TInc(_) -> (PC.TInc(clt),x)
415 | PC.TDec(_) -> (PC.TDec(clt),x)
417 | PC.TIf(_) -> (PC.TIf(clt),x)
418 | PC.TElse(_) -> (PC.TElse(clt),x)
419 | PC.TWhile(_) -> (PC.TWhile(clt),x)
420 | PC.TFor(_) -> (PC.TFor(clt),x)
421 | PC.TDo(_) -> (PC.TDo(clt),x)
422 | PC.TSwitch(_) -> (PC.TSwitch(clt),x)
423 | PC.TCase(_) -> (PC.TCase(clt),x)
424 | PC.TDefault(_) -> (PC.TDefault(clt),x)
425 | PC.TReturn(_) -> (PC.TReturn(clt),x)
426 | PC.TBreak(_) -> (PC.TBreak(clt),x)
427 | PC.TContinue(_) -> (PC.TContinue(clt),x)
428 | PC.TGoto(_) -> (PC.TGoto(clt),x)
429 | PC.TIdent(s,_) -> (PC.TIdent(s,clt),x)
430 | PC.TTypeId(s,_) -> (PC.TTypeId(s,clt),x)
431 | PC.TDeclarerId(s,_) -> (PC.TDeclarerId(s,clt),x)
432 | PC.TIteratorId(s,_) -> (PC.TIteratorId(s,clt),x)
434 | PC.TSizeof(_) -> (PC.TSizeof(clt),x)
436 | PC.TString(s,_) -> (PC.TString(s,clt),x)
437 | PC.TChar(s,_) -> (PC.TChar(s,clt),x)
438 | PC.TFloat(s,_) -> (PC.TFloat(s,clt),x)
439 | PC.TInt(s,_) -> (PC.TInt(s,clt),x)
441 | PC.TOrLog(_) -> (PC.TOrLog(clt),x)
442 | PC.TAndLog(_) -> (PC.TAndLog(clt),x)
443 | PC.TOr(_) -> (PC.TOr(clt),x)
444 | PC.TXor(_) -> (PC.TXor(clt),x)
445 | PC.TAnd (_) -> (PC.TAnd (clt),x)
446 | PC.TEqEq(_) -> (PC.TEqEq(clt),x)
447 | PC.TNotEq(_) -> (PC.TNotEq(clt),x)
448 | PC.TLogOp(op,_) -> (PC.TLogOp(op,clt),x)
449 | PC.TShOp(op,_) -> (PC.TShOp(op,clt),x)
450 | PC.TPlus(_) -> (PC.TPlus(clt),x)
451 | PC.TMinus(_) -> (PC.TMinus(clt),x)
452 | PC.TMul(_) -> (PC.TMul(clt),x)
453 | PC.TDmOp(op,_) -> (PC.TDmOp(op,clt),x)
454 | PC.TTilde (_) -> (PC.TTilde (clt),x)
456 | PC.TMetaParam(a,b,_) -> (PC.TMetaParam(a,b,clt),x)
457 | PC.TMetaParamList(a,b,c,_) -> (PC.TMetaParamList(a,b,c,clt),x)
458 | PC.TMetaConst(a,b,c,d,_) -> (PC.TMetaConst(a,b,c,d,clt),x)
459 | PC.TMetaErr(a,b,c,_) -> (PC.TMetaErr(a,b,c,clt),x)
460 | PC.TMetaExp(a,b,c,d,_) -> (PC.TMetaExp(a,b,c,d,clt),x)
461 | PC.TMetaIdExp(a,b,c,d,_) -> (PC.TMetaIdExp(a,b,c,d,clt),x)
462 | PC.TMetaLocalIdExp(a,b,c,d,_) -> (PC.TMetaLocalIdExp(a,b,c,d,clt),x)
463 | PC.TMetaExpList(a,b,c,_) -> (PC.TMetaExpList(a,b,c,clt),x)
464 | PC.TMetaId(a,b,c,_) -> (PC.TMetaId(a,b,c,clt),x)
465 | PC.TMetaType(a,b,_) -> (PC.TMetaType(a,b,clt),x)
466 | PC.TMetaStm(a,b,_) -> (PC.TMetaStm(a,b,clt),x)
467 | PC.TMetaStmList(a,b,_) -> (PC.TMetaStmList(a,b,clt),x)
468 | PC.TMetaFunc(a,b,c,_) -> (PC.TMetaFunc(a,b,c,clt),x)
469 | PC.TMetaLocalFunc(a,b,c,_) -> (PC.TMetaLocalFunc(a,b,c,clt),x)
471 | PC.TWhen(_) -> (PC.TWhen(clt),x)
472 | PC.TAny(_) -> (PC.TAny(clt),x)
473 | PC.TStrict(_) -> (PC.TStrict(clt),x)
474 | PC.TEllipsis(_) -> (PC.TEllipsis(clt),x)
476 | PC.TCircles(_) -> (PC.TCircles(clt),x)
477 | PC.TStars(_) -> (PC.TStars(clt),x)
480 | PC.TOEllipsis(_) -> (PC.TOEllipsis(clt),x)
481 | PC.TCEllipsis(_) -> (PC.TCEllipsis(clt),x)
482 | PC.TPOEllipsis(_) -> (PC.TPOEllipsis(clt),x)
483 | PC.TPCEllipsis(_) -> (PC.TPCEllipsis(clt),x)
485 | PC.TOCircles(_) -> (PC.TOCircles(clt),x)
486 | PC.TCCircles(_) -> (PC.TCCircles(clt),x)
487 | PC.TOStars(_) -> (PC.TOStars(clt),x)
488 | PC.TCStars(_) -> (PC.TCStars(clt),x)
491 | PC.TWhy(_) -> (PC.TWhy(clt),x)
492 | PC.TDotDot(_) -> (PC.TDotDot(clt),x)
493 | PC.TBang(_) -> (PC.TBang(clt),x)
494 | PC.TOPar(_) -> (PC.TOPar(clt),x)
495 | PC.TOPar0(_) -> (PC.TOPar0(clt),x)
496 | PC.TMid0(_) -> (PC.TMid0(clt),x)
497 | PC.TCPar(_) -> (PC.TCPar(clt),x)
498 | PC.TCPar0(_) -> (PC.TCPar0(clt),x)
500 | PC.TOBrace(_) -> (PC.TOBrace(clt),x)
501 | PC.TCBrace(_) -> (PC.TCBrace(clt),x)
502 | PC.TOCro(_) -> (PC.TOCro(clt),x)
503 | PC.TCCro(_) -> (PC.TCCro(clt),x)
505 | PC.TPtrOp(_) -> (PC.TPtrOp(clt),x)
507 | PC.TEq(_) -> (PC.TEq(clt),x)
508 | PC.TAssign(s,_) -> (PC.TAssign(s,clt),x)
509 | PC.TDot(_) -> (PC.TDot(clt),x)
510 | PC.TComma(_) -> (PC.TComma(clt),x)
511 | PC.TPtVirg(_) -> (PC.TPtVirg(clt),x)
513 | PC.TLineEnd(_) -> (PC.TLineEnd(clt),x)
514 | PC.TFunDecl(_) -> (PC.TFunDecl(clt),x)
516 | _ -> failwith "no clt"
519 (* ----------------------------------------------------------------------- *)
521 let make_name prefix ln = Printf.sprintf "%s starting on line %d" prefix ln
523 (* ----------------------------------------------------------------------- *)
526 let wrap_lexbuf_info lexbuf =
527 (Lexing.lexeme lexbuf, Lexing.lexeme_start lexbuf)
529 let tokens_all_full token table file get_ats lexbuf end_markers :
530 (bool * ((PC.token * (string * (int * int) * (int * int))) list)) =
533 let result = token lexbuf in
534 let info = (Lexing.lexeme lexbuf,
535 (table.(Lexing.lexeme_start lexbuf)),
536 (Lexing.lexeme_start lexbuf, Lexing.lexeme_end lexbuf)) in
540 then failwith "unexpected end of file in a metavariable declaration"
541 else (false,[(result,info)])
542 else if List.mem result end_markers
543 then (true,[(result,info)])
545 let (more,rest) = aux() in
546 (more,(result, info)::rest)
549 e -> pr2 (Common.error_message file (wrap_lexbuf_info lexbuf) ); raise e
551 let tokens_all table file get_ats lexbuf end_markers :
552 (bool * ((PC.token * (string * (int * int) * (int * int))) list)) =
553 tokens_all_full Lexer_cocci.token table file get_ats lexbuf end_markers
555 let tokens_script_all table file get_ats lexbuf end_markers :
556 (bool * ((PC.token * (string * (int * int) * (int * int))) list)) =
557 tokens_all_full Lexer_script.token table file get_ats lexbuf end_markers
559 (* ----------------------------------------------------------------------- *)
560 (* Split tokens into minus and plus fragments *)
563 let (d,_,_,_,_,_,_,_) = clt in
565 D.MINUS | D.OPTMINUS | D.UNIQUEMINUS -> ([t],[])
567 | D.CONTEXT | D.UNIQUE | D.OPT -> ([t],[t])
569 let split_token ((tok,_) as t) =
571 PC.TIdentifier | PC.TConstant | PC.TExpression | PC.TIdExpression
572 | PC.TStatement | PC.TPosition | PC.TPosAny
573 | PC.TFunction | PC.TTypedef | PC.TDeclarer | PC.TIterator | PC.TName
574 | PC.TType | PC.TParameter | PC.TLocal | PC.Tlist | PC.TFresh | PC.TPure
575 | PC.TContext | PC.TRuleName(_) | PC.TUsing | PC.TDisable | PC.TExtends
577 | PC.TDepends | PC.TOn | PC.TEver | PC.TNever | PC.TExists | PC.TForall
579 | PC.TError | PC.TWords | PC.TNothing -> ([t],[t])
581 | PC.Tchar(clt) | PC.Tshort(clt) | PC.Tint(clt) | PC.Tdouble(clt)
582 | PC.Tfloat(clt) | PC.Tlong(clt) | PC.Tvoid(clt) | PC.Tstruct(clt)
583 | PC.Tunion(clt) | PC.Tunsigned(clt) | PC.Tsigned(clt)
584 | PC.Tstatic(clt) | PC.Tauto(clt) | PC.Tregister(clt) | PC.Textern(clt)
585 | PC.Tinline(clt) | PC.Ttypedef(clt) | PC.Tattr(_,clt)
586 | PC.Tconst(clt) | PC.Tvolatile(clt) -> split t clt
588 | PC.TPragma(s) -> ([],[t]) (* only allowed in + *)
589 | PC.TPlusFile(s,clt) | PC.TMinusFile(s,clt)
590 | PC.TIncludeL(s,clt) | PC.TIncludeNL(s,clt) ->
592 | PC.TDefine(clt,_) | PC.TDefineParam(clt,_,_) -> split t clt
594 | PC.TIf(clt) | PC.TElse(clt) | PC.TWhile(clt) | PC.TFor(clt) | PC.TDo(clt)
595 | PC.TSwitch(clt) | PC.TCase(clt) | PC.TDefault(clt)
597 | PC.TReturn(clt) | PC.TBreak(clt) | PC.TContinue(clt) | PC.TGoto(clt)
599 | PC.TTypeId(_,clt) | PC.TDeclarerId(_,clt) | PC.TIteratorId(_,clt)
600 | PC.TMetaConst(_,_,_,_,clt) | PC.TMetaExp(_,_,_,_,clt)
601 | PC.TMetaIdExp(_,_,_,_,clt) | PC.TMetaLocalIdExp(_,_,_,_,clt)
602 | PC.TMetaExpList(_,_,_,clt)
603 | PC.TMetaParam(_,_,clt) | PC.TMetaParamList(_,_,_,clt)
604 | PC.TMetaId(_,_,_,clt) | PC.TMetaType(_,_,clt)
605 | PC.TMetaStm(_,_,clt) | PC.TMetaStmList(_,_,clt) | PC.TMetaErr(_,_,_,clt)
606 | PC.TMetaFunc(_,_,_,clt) | PC.TMetaLocalFunc(_,_,_,clt)
607 | PC.TMetaDeclarer(_,_,_,clt) | PC.TMetaIterator(_,_,_,clt) -> split t clt
608 | PC.TMPtVirg | PC.TArob | PC.TArobArob -> ([t],[t])
609 | PC.TPArob | PC.TMetaPos(_,_,_,_) -> ([t],[])
612 | PC.TWhen(clt) | PC.TAny(clt) | PC.TStrict(clt) | PC.TLineEnd(clt)
613 | PC.TEllipsis(clt) (* | PC.TCircles(clt) | PC.TStars(clt) *) -> split t clt
615 | PC.TOEllipsis(_) | PC.TCEllipsis(_) (* clt must be context *)
616 | PC.TPOEllipsis(_) | PC.TPCEllipsis(_) (* clt must be context *)
618 | PC.TOCircles(_) | PC.TCCircles(_) (* clt must be context *)
619 | PC.TOStars(_) | PC.TCStars(_) (* clt must be context *)
621 | PC.TBang0 | PC.TPlus0 | PC.TWhy0 ->
624 | PC.TWhy(clt) | PC.TDotDot(clt)
625 | PC.TBang(clt) | PC.TOPar(clt) | PC.TOPar0(clt)
626 | PC.TMid0(clt) | PC.TCPar(clt) | PC.TCPar0(clt) -> split t clt
628 | PC.TInc(clt) | PC.TDec(clt) -> split t clt
630 | PC.TString(_,clt) | PC.TChar(_,clt) | PC.TFloat(_,clt) | PC.TInt(_,clt) ->
633 | PC.TOrLog(clt) | PC.TAndLog(clt) | PC.TOr(clt) | PC.TXor(clt)
634 | PC.TAnd (clt) | PC.TEqEq(clt) | PC.TNotEq(clt) | PC.TLogOp(_,clt)
635 | PC.TShOp(_,clt) | PC.TPlus(clt) | PC.TMinus(clt) | PC.TMul(clt)
636 | PC.TDmOp(_,clt) | PC.TTilde (clt) -> split t clt
638 | PC.TOBrace(clt) | PC.TCBrace(clt) -> split t clt
639 | PC.TOCro(clt) | PC.TCCro(clt) -> split t clt
641 | PC.TPtrOp(clt) -> split t clt
643 | PC.TEq(clt) | PC.TAssign(_,clt) | PC.TDot(clt) | PC.TComma(clt)
644 | PC.TPtVirg(clt) -> split t clt
646 | PC.EOF | PC.TInvalid -> ([t],[t])
648 | PC.TIso | PC.TRightIso
649 | PC.TIsoExpression | PC.TIsoStatement | PC.TIsoDeclaration | PC.TIsoType
650 | PC.TIsoTopLevel | PC.TIsoArgExpression | PC.TIsoTestExpression ->
651 failwith "unexpected tokens"
652 | PC.TScriptData s -> ([t],[t])
654 let split_token_stream tokens =
655 let rec loop = function
658 let (minus,plus) = split_token token in
659 let (minus_stream,plus_stream) = loop tokens in
660 (minus@minus_stream,plus@plus_stream) in
663 (* ----------------------------------------------------------------------- *)
664 (* Find function names *)
665 (* This addresses a shift-reduce problem in the parser, allowing us to
666 distinguish a function declaration from a function call even if the latter
667 has no return type. Undoubtedly, this is not very nice, but it doesn't
668 seem very convenient to refactor the grammar to get around the problem. *)
670 let rec find_function_names = function
672 | ((PC.TIdent(_,clt),info) as t1) :: ((PC.TOPar(_),_) as t2) :: rest
673 | ((PC.TMetaId(_,_,_,clt),info) as t1) :: ((PC.TOPar(_),_) as t2) :: rest
674 | ((PC.TMetaFunc(_,_,_,clt),info) as t1) :: ((PC.TOPar(_),_) as t2) :: rest
675 | ((PC.TMetaLocalFunc(_,_,_,clt),info) as t1)::((PC.TOPar(_),_) as t2)::rest
677 let rec skip level = function
679 | ((PC.TCPar(_),_) as t)::rest ->
680 let level = level - 1 in
683 else let (pre,found,post) = skip level rest in (t::pre,found,post)
684 | ((PC.TOPar(_),_) as t)::rest ->
685 let level = level + 1 in
686 let (pre,found,post) = skip level rest in (t::pre,found,post)
687 | ((PC.TArobArob,_) as t)::rest
688 | ((PC.TArob,_) as t)::rest
689 | ((PC.EOF,_) as t)::rest -> ([t],false,rest)
691 let (pre,found,post) = skip level rest in (t::pre,found,post) in
692 let (pre,found,post) = skip 1 rest in
693 (match (found,post) with
694 (true,((PC.TOBrace(_),_) as t3)::rest) ->
695 (PC.TFunDecl(clt),info) :: t1 :: t2 :: pre @
696 t3 :: (find_function_names rest)
697 | _ -> t1 :: t2 :: pre @ find_function_names post)
698 | t :: rest -> t :: find_function_names rest
700 (* ----------------------------------------------------------------------- *)
701 (* an attribute is an identifier that preceeds another identifier and
704 let rec detect_attr l =
706 (PC.TIdent(_,_),_) | (PC.TMetaId(_,_,_,_),_) | (PC.TMetaFunc(_,_,_,_),_)
707 | (PC.TMetaLocalFunc(_,_,_,_),_) -> true
709 let rec loop = function
712 | ((PC.TIdent(nm,clt),info) as t1)::id::rest when is_id id ->
713 if String.length nm > 2 && String.sub nm 0 2 = "__"
714 then (PC.Tattr(nm,clt),info)::(loop (id::rest))
715 else t1::(loop (id::rest))
716 | x::xs -> x::(loop xs) in
719 (* ----------------------------------------------------------------------- *)
720 (* Look for variable declarations where the name is a typedef name.
721 We assume that C code does not contain a multiplication as a top-level
724 (* bug: once a type, always a type, even if the same name is later intended
725 to be used as a real identifier *)
726 let detect_types in_meta_decls l =
727 let is_delim infn = function
728 (PC.TOEllipsis(_),_) (* | (PC.TOCircles(_),_) | (PC.TOStars(_),_) *)
729 | (PC.TPOEllipsis(_),_) (* | (PC.TOCircles(_),_) | (PC.TOStars(_),_) *)
730 | (PC.TEllipsis(_),_) (* | (PC.TCircles(_),_) | (PC.TStars(_),_) *)
731 | (PC.TPtVirg(_),_) | (PC.TOBrace(_),_) | (PC.TCBrace(_),_)
732 | (PC.TPure,_) | (PC.TContext,_)
733 | (PC.Tstatic(_),_) | (PC.Textern(_),_)
734 | (PC.Tinline(_),_) | (PC.Ttypedef(_),_) | (PC.Tattr(_),_) -> true
735 | (PC.TComma(_),_) when infn > 0 or in_meta_decls -> true
736 | (PC.TDotDot(_),_) when in_meta_decls -> true
738 let is_choices_delim = function
739 (PC.TOBrace(_),_) | (PC.TComma(_),_) -> true | _ -> false in
741 (PC.TIdent(_,_),_) | (PC.TMetaId(_,_,_,_),_) | (PC.TMetaFunc(_,_,_,_),_)
742 | (PC.TMetaLocalFunc(_,_,_,_),_) -> true
743 | (PC.TMetaParam(_,_,_),_)
744 | (PC.TMetaParamList(_,_,_,_),_)
745 | (PC.TMetaConst(_,_,_,_,_),_)
746 | (PC.TMetaErr(_,_,_,_),_)
747 | (PC.TMetaExp(_,_,_,_,_),_)
748 | (PC.TMetaIdExp(_,_,_,_,_),_)
749 | (PC.TMetaLocalIdExp(_,_,_,_,_),_)
750 | (PC.TMetaExpList(_,_,_,_),_)
751 | (PC.TMetaType(_,_,_),_)
752 | (PC.TMetaStm(_,_,_),_)
753 | (PC.TMetaStmList(_,_,_),_)
754 | (PC.TMetaPos(_,_,_,_),_) -> in_meta_decls
756 let redo_id ident clt v =
757 !Data.add_type_name ident;
758 (PC.TTypeId(ident,clt),v) in
759 let rec loop start infn type_names = function
760 (* infn: 0 means not in a function header
761 > 0 means in a function header, after infn - 1 unmatched open parens*)
763 | ((PC.TOBrace(clt),v)::_) as all when in_meta_decls ->
764 collect_choices type_names all (* never a function header *)
765 | delim::(PC.TIdent(ident,clt),v)::((PC.TMul(_),_) as x)::rest
766 when is_delim infn delim ->
767 let newid = redo_id ident clt v in
768 delim::newid::x::(loop false infn (ident::type_names) rest)
769 | delim::(PC.TIdent(ident,clt),v)::id::rest
770 when is_delim infn delim && is_id id ->
771 let newid = redo_id ident clt v in
772 delim::newid::id::(loop false infn (ident::type_names) rest)
773 | ((PC.TFunDecl(_),_) as fn)::rest ->
774 fn::(loop false 1 type_names rest)
775 | ((PC.TOPar(_),_) as lp)::rest when infn > 0 ->
776 lp::(loop false (infn + 1) type_names rest)
777 | ((PC.TCPar(_),_) as rp)::rest when infn > 0 ->
779 then rp::(loop false 0 type_names rest) (* 0 means not in fn header *)
780 else rp::(loop false (infn - 1) type_names rest)
781 | (PC.TIdent(ident,clt),v)::((PC.TMul(_),_) as x)::rest when start ->
782 let newid = redo_id ident clt v in
783 newid::x::(loop false infn (ident::type_names) rest)
784 | (PC.TIdent(ident,clt),v)::id::rest when start && is_id id ->
785 let newid = redo_id ident clt v in
786 newid::id::(loop false infn (ident::type_names) rest)
787 | (PC.TIdent(ident,clt),v)::rest when List.mem ident type_names ->
788 (PC.TTypeId(ident,clt),v)::(loop false infn type_names rest)
789 | ((PC.TIdent(ident,clt),v) as x)::rest ->
790 x::(loop false infn type_names rest)
791 | x::rest -> x::(loop false infn type_names rest)
792 and collect_choices type_names = function
793 [] -> [] (* should happen, but let the parser detect that *)
794 | (PC.TCBrace(clt),v)::rest ->
795 (PC.TCBrace(clt),v)::(loop false 0 type_names rest)
796 | delim::(PC.TIdent(ident,clt),v)::rest
797 when is_choices_delim delim ->
798 let newid = redo_id ident clt v in
799 delim::newid::(collect_choices (ident::type_names) rest)
800 | x::rest -> x::(collect_choices type_names rest) in
804 (* ----------------------------------------------------------------------- *)
805 (* Insert TLineEnd tokens at the end of a line that contains a WHEN.
806 WHEN is restricted to a single line, to avoid ambiguity in eg:
810 let token2line (tok,_) =
812 PC.Tchar(clt) | PC.Tshort(clt) | PC.Tint(clt) | PC.Tdouble(clt)
813 | PC.Tfloat(clt) | PC.Tlong(clt) | PC.Tvoid(clt) | PC.Tstruct(clt)
814 | PC.Tunion(clt) | PC.Tunsigned(clt) | PC.Tsigned(clt)
815 | PC.Tstatic(clt) | PC.Tauto(clt) | PC.Tregister(clt) | PC.Textern(clt)
816 | PC.Tinline(clt) | PC.Ttypedef(clt) | PC.Tattr(_,clt) | PC.Tconst(clt)
819 | PC.TInc(clt) | PC.TDec(clt)
821 | PC.TIf(clt) | PC.TElse(clt) | PC.TWhile(clt) | PC.TFor(clt) | PC.TDo(clt)
822 | PC.TSwitch (clt) | PC.TCase (clt) | PC.TDefault (clt) | PC.TSizeof (clt)
823 | PC.TReturn(clt) | PC.TBreak(clt) | PC.TContinue(clt) | PC.TGoto(clt)
825 | PC.TTypeId(_,clt) | PC.TDeclarerId(_,clt) | PC.TIteratorId(_,clt)
826 | PC.TMetaDeclarer(_,_,_,clt) | PC.TMetaIterator(_,_,_,clt)
828 | PC.TString(_,clt) | PC.TChar(_,clt) | PC.TFloat(_,clt) | PC.TInt(_,clt)
830 | PC.TOrLog(clt) | PC.TAndLog(clt) | PC.TOr(clt) | PC.TXor(clt)
831 | PC.TAnd (clt) | PC.TEqEq(clt) | PC.TNotEq(clt) | PC.TLogOp(_,clt)
832 | PC.TShOp(_,clt) | PC.TPlus(clt) | PC.TMinus(clt) | PC.TMul(clt)
833 | PC.TDmOp(_,clt) | PC.TTilde (clt)
835 | PC.TMetaParam(_,_,clt) | PC.TMetaParamList(_,_,_,clt)
836 | PC.TMetaConst(_,_,_,_,clt) | PC.TMetaExp(_,_,_,_,clt)
837 | PC.TMetaIdExp(_,_,_,_,clt) | PC.TMetaLocalIdExp(_,_,_,_,clt)
838 | PC.TMetaExpList(_,_,_,clt)
839 | PC.TMetaId(_,_,_,clt) | PC.TMetaType(_,_,clt)
840 | PC.TMetaStm(_,_,clt) | PC.TMetaStmList(_,_,clt) | PC.TMetaFunc(_,_,_,clt)
841 | PC.TMetaLocalFunc(_,_,_,clt) | PC.TMetaPos(_,_,_,clt)
844 | PC.TWhen(clt) | PC.TAny(clt) | PC.TStrict(clt) | PC.TEllipsis(clt)
845 (* | PC.TCircles(clt) | PC.TStars(clt) *)
847 | PC.TOEllipsis(clt) | PC.TCEllipsis(clt)
848 | PC.TPOEllipsis(clt) | PC.TPCEllipsis(clt) (*| PC.TOCircles(clt)
849 | PC.TCCircles(clt) | PC.TOStars(clt) | PC.TCStars(clt) *)
851 | PC.TWhy(clt) | PC.TDotDot(clt) | PC.TBang(clt) | PC.TOPar(clt)
852 | PC.TOPar0(clt) | PC.TMid0(clt) | PC.TCPar(clt)
855 | PC.TOBrace(clt) | PC.TCBrace(clt) | PC.TOCro(clt) | PC.TCCro(clt)
859 | PC.TDefine(clt,_) | PC.TDefineParam(clt,_,_)
860 | PC.TIncludeL(_,clt) | PC.TIncludeNL(_,clt)
862 | PC.TEq(clt) | PC.TAssign(_,clt) | PC.TDot(clt) | PC.TComma(clt)
864 let (_,line,_,_,_,_,_,_) = clt in Some line
868 let rec insert_line_end = function
870 | (((PC.TWhen(clt),q) as x)::xs) ->
871 x::(find_line_end true (token2line x) clt q xs)
872 | (((PC.TDefine(clt,_),q) as x)::xs)
873 | (((PC.TDefineParam(clt,_,_),q) as x)::xs) ->
874 x::(find_line_end false (token2line x) clt q xs)
875 | x::xs -> x::(insert_line_end xs)
877 and find_line_end inwhen line clt q = function
878 (* don't know what 2nd component should be so just use the info of
879 the When. Also inherit - of when, if any *)
880 [] -> [(PC.TLineEnd(clt),q)]
881 | ((PC.TIdent("strict",clt),a) as x)::xs when token2line x = line ->
882 (PC.TStrict(clt),a) :: (find_line_end inwhen line clt q xs)
883 | ((PC.TIdent("STRICT",clt),a) as x)::xs when token2line x = line ->
884 (PC.TStrict(clt),a) :: (find_line_end inwhen line clt q xs)
885 | ((PC.TIdent("any",clt),a) as x)::xs when token2line x = line ->
886 (PC.TAny(clt),a) :: (find_line_end inwhen line clt q xs)
887 | ((PC.TIdent("ANY",clt),a) as x)::xs when token2line x = line ->
888 (PC.TAny(clt),a) :: (find_line_end inwhen line clt q xs)
889 | ((PC.TIdent("forall",clt),a) as x)::xs when token2line x = line ->
890 (PC.TForall,a) :: (find_line_end inwhen line clt q xs)
891 | ((PC.TIdent("exists",clt),a) as x)::xs when token2line x = line ->
892 (PC.TExists,a) :: (find_line_end inwhen line clt q xs)
893 | ((PC.TComma(clt),a) as x)::xs when token2line x = line ->
894 (PC.TComma(clt),a) :: (find_line_end inwhen line clt q xs)
895 | ((PC.TPArob,a) as x)::xs -> (* no line #, just assume on the same line *)
896 x :: (find_line_end inwhen line clt q xs)
897 | x::xs when token2line x = line -> x :: (find_line_end inwhen line clt q xs)
898 | xs -> (PC.TLineEnd(clt),q)::(insert_line_end xs)
900 (* ----------------------------------------------------------------------- *)
901 (* process pragmas: they can only be used in + code, and adjacent to
902 another + token. They are concatenated to the string representation of
905 let rec collect_all_pragmas collected = function
906 (PC.TPragma(s),_)::rest -> collect_all_pragmas (s::collected) rest
907 | l -> (List.rev collected,l)
909 let rec collect_up_to_pragmas skipped = function
910 [] -> None (* didn't reach a pragma, so nothing to do *)
911 | ((PC.TPragma(s),_) as t)::rest ->
912 let (pragmas,rest) = collect_all_pragmas [] (t::rest) in
913 Some (List.rev skipped,pragmas,rest)
915 match plus_attachable x with
918 | SKIP -> collect_up_to_pragmas (x::skipped) xs
920 let rec collect_up_to_plus skipped = function
921 [] -> failwith "nothing to attach a pragma to"
923 match plus_attachable x with
924 PLUS -> (List.rev skipped,x,xs)
925 | NOTPLUS -> failwith "nothing to attach a pragma to"
926 | SKIP -> collect_up_to_plus (x::skipped) xs
928 let rec process_pragmas = function
930 | ((PC.TPragma(s),_)::_) as l ->
931 let (pragmas,rest) = collect_all_pragmas [] l in
932 let (skipped,aft,rest) = collect_up_to_plus [] rest in
933 let (a,b,c,d,e,strbef,straft,pos) = get_clt aft in
935 (process_pragmas ((update_clt aft (a,b,c,d,e,pragmas,straft,pos))::rest))
937 (match plus_attachable bef with
939 (match collect_up_to_pragmas [] xs with
940 Some(skipped,pragmas,rest) ->
941 let (a,b,c,d,e,strbef,straft,pos) = get_clt bef in
942 (update_clt bef (a,b,c,d,e,strbef,pragmas,pos))::
943 skipped@(process_pragmas rest)
944 | None -> bef::(process_pragmas xs))
945 | _ -> bef::(process_pragmas xs))
947 (* ----------------------------------------------------------------------- *)
948 (* Drop ... ... . This is only allowed in + code, and arises when there is
949 some - code between the ... *)
950 (* drop whens as well - they serve no purpose in + code and they cause
951 problems for drop_double_dots *)
953 let rec drop_when = function
955 | (PC.TWhen(clt),info)::xs ->
956 let rec loop = function
958 | (PC.TLineEnd(_),info)::xs -> drop_when xs
959 | x::xs -> loop xs in
961 | x::xs -> x::drop_when xs
963 (* instead of dropping the double dots, we put TNothing in between them.
964 these vanish after the parser, but keeping all the ...s in the + code makes
965 it easier to align the + and - code in context_neg and in preparation for the
966 isomorphisms. This shouldn't matter because the context code of the +
967 slice is mostly ignored anyway *)
968 let rec drop_double_dots l =
970 (PC.TOEllipsis(_),_) | (PC.TPOEllipsis(_),_)
971 (* | (PC.TOCircles(_),_) | (PC.TOStars(_),_) *) ->
974 let middle = function
975 (PC.TEllipsis(_),_) (* | (PC.TCircles(_),_) | (PC.TStars(_),_) *) -> true
978 (PC.TCEllipsis(_),_) | (PC.TPCEllipsis(_),_)
979 (* | (PC.TCCircles(_),_) | (PC.TCStars(_),_) *) ->
982 let rec loop ((_,i) as prev) = function
984 | x::rest when middle prev && middle x -> (PC.TNothing,i)::x::(loop x rest)
985 | x::rest when start prev && middle x -> (PC.TNothing,i)::x::(loop x rest)
986 | x::rest when start prev && final x -> (PC.TNothing,i)::x::(loop x rest)
987 | x::rest when middle prev && final x -> (PC.TNothing,i)::x::(loop x rest)
988 | x::rest -> x :: (loop x rest) in
991 | (x::xs) -> x :: loop x xs
995 if l = cur then l else fix f cur
997 (* ( | ... | ) also causes parsing problems *)
1001 let rec drop_empty_thing starter middle ender = function
1003 | hd::rest when starter hd ->
1004 let rec loop = function
1005 x::rest when middle x -> loop rest
1006 | x::rest when ender x -> rest
1007 | _ -> raise Not_empty in
1008 (match try Some(loop rest) with Not_empty -> None with
1009 Some x -> drop_empty_thing starter middle ender x
1010 | None -> hd :: drop_empty_thing starter middle ender rest)
1011 | x::rest -> x :: drop_empty_thing starter middle ender rest
1015 (function (PC.TOPar0(_),_) -> true | _ -> false)
1016 (function (PC.TMid0(_),_) -> true | _ -> false)
1017 (function (PC.TCPar0(_),_) -> true | _ -> false)
1019 let drop_empty_nest = drop_empty_thing
1021 (* ----------------------------------------------------------------------- *)
1024 let get_s_starts (_, (s,_,(starts, ends))) =
1025 Printf.printf "%d %d\n" starts ends; (s, starts)
1028 let v = List.hd !l in
1033 PC.reinit (function _ -> PC.TArobArob (* a handy token *))
1034 (Lexing.from_function
1035 (function buf -> function n -> raise Common.Impossible))
1037 let parse_one str parsefn file toks =
1038 let all_tokens = ref toks in
1039 let cur_tok = ref (List.hd !all_tokens) in
1041 let lexer_function _ =
1042 let (v, info) = pop2 all_tokens in
1043 cur_tok := (v, info);
1047 Lexing.from_function
1048 (function buf -> function n -> raise Common.Impossible)
1053 try parsefn lexer_function lexbuf_fake
1055 Lexer_cocci.Lexical s ->
1057 (Printf.sprintf "%s: lexical error: %s\n =%s\n" str s
1058 (Common.error_message file (get_s_starts !cur_tok) ))
1059 | Parser_cocci_menhir.Error ->
1061 (Printf.sprintf "%s: parse error: \n = %s\n" str
1062 (Common.error_message file (get_s_starts !cur_tok) ))
1063 | Semantic_cocci.Semantic s ->
1065 (Printf.sprintf "%s: semantic error: %s\n =%s\n" str s
1066 (Common.error_message file (get_s_starts !cur_tok) ))
1070 let prepare_tokens tokens =
1072 (detect_types false (find_function_names (detect_attr tokens)))
1074 let rec consume_minus_positions = function
1076 | x::(PC.TPArob,_)::(PC.TMetaPos(name,constraints,per,clt),_)::xs ->
1077 let (arity,ln,lln,offset,col,strbef,straft,_) = get_clt x in
1078 let name = Parse_aux.clt2mcode name clt in
1081 (arity,ln,lln,offset,col,strbef,straft,
1082 Ast0.MetaPos(name,constraints,per)) in
1083 x::(consume_minus_positions xs)
1084 | x::xs -> x::consume_minus_positions xs
1086 let any_modif rule =
1088 match Ast0.get_mcode_mcodekind x with
1089 Ast0.MINUS _ | Ast0.PLUS -> true
1091 let donothing r k e = k e in
1092 let bind x y = x or y in
1093 let option_default = false in
1095 V0.combiner bind option_default
1096 mcode mcode mcode mcode mcode mcode mcode mcode mcode mcode mcode mcode
1098 donothing donothing donothing donothing donothing donothing
1099 donothing donothing donothing donothing donothing donothing donothing
1100 donothing donothing in
1101 List.exists fn.V0.combiner_top_level rule
1103 let drop_last extra l = List.rev(extra@(List.tl(List.rev l)))
1105 let partition_either l =
1106 let rec part_either left right = function
1107 | [] -> (List.rev left, List.rev right)
1110 | Common.Left e -> part_either (e :: left) right l
1111 | Common.Right e -> part_either left (e :: right) l) in
1114 let get_metavars parse_fn table file lexbuf =
1115 let rec meta_loop acc (* read one decl at a time *) =
1117 tokens_all table file true lexbuf [PC.TArobArob;PC.TMPtVirg] in
1118 let tokens = prepare_tokens tokens in
1120 [(PC.TArobArob,_)] -> List.rev acc
1122 let metavars = parse_one "meta" parse_fn file tokens in
1123 meta_loop (metavars@acc) in
1124 partition_either (meta_loop [])
1126 let get_script_metavars parse_fn table file lexbuf =
1127 let rec meta_loop acc =
1129 tokens_all table file true lexbuf [PC.TArobArob; PC.TMPtVirg] in
1130 let tokens = prepare_tokens tokens in
1132 [(PC.TArobArob, _)] -> List.rev acc
1134 let metavar = parse_one "scriptmeta" parse_fn file tokens in
1135 meta_loop (metavar :: acc)
1139 let get_rule_name parse_fn starts_with_name get_tokens file prefix =
1140 Data.in_rule_name := true;
1141 let mknm _ = make_name prefix (!Lexer_cocci.line) in
1145 let (_,tokens) = get_tokens [PC.TArob] in
1146 match parse_one "rule name" parse_fn file tokens with
1147 Ast.CocciRulename (None,a,b,c,d,e) ->
1148 Ast.CocciRulename (Some (mknm()),a,b,c,d,e)
1149 | Ast.CocciRulename (Some nm,a,b,c,d,e) ->
1150 (if List.mem nm reserved_names
1151 then failwith (Printf.sprintf "invalid name %s\n" nm));
1152 Ast.CocciRulename (Some nm,a,b,c,d,e)
1153 | Ast.ScriptRulename(s,deps) -> Ast.ScriptRulename(s,deps)
1155 Ast.CocciRulename(Some(mknm()),Ast.NoDep,[],[],Ast.Undetermined,false) in
1156 Data.in_rule_name := false;
1159 let parse_iso file =
1160 let table = Common.full_charpos_to_pos file in
1161 Common.with_open_infile file (fun channel ->
1162 let lexbuf = Lexing.from_channel channel in
1163 let get_tokens = tokens_all table file false lexbuf in
1165 match get_tokens [PC.TArobArob;PC.TArob] with
1167 let parse_start start =
1168 let rev = List.rev start in
1169 let (arob,_) = List.hd rev in
1170 (arob = PC.TArob,List.rev(List.tl rev)) in
1171 let (starts_with_name,start) = parse_start start in
1172 let rec loop starts_with_name start =
1173 (!Data.init_rule)();
1174 (* get metavariable declarations - have to be read before the
1176 let (rule_name,_,_,_,_,_) =
1177 match get_rule_name PC.iso_rule_name starts_with_name get_tokens
1178 file ("iso file "^file) with
1179 Ast.CocciRulename (Some n,a,b,c,d,e) -> (n,a,b,c,d,e)
1180 | _ -> failwith "Script rules cannot appear in isomorphism rules"
1182 Ast0.rule_name := rule_name;
1183 Data.in_meta := true;
1185 match get_metavars PC.iso_meta_main table file lexbuf with
1186 (iso_metavars,[]) -> iso_metavars
1187 | _ -> failwith "unexpected inheritance in iso" in
1188 Data.in_meta := false;
1192 [PC.TIsoStatement;PC.TIsoExpression;PC.TIsoArgExpression;
1193 PC.TIsoTestExpression;
1194 PC.TIsoDeclaration;PC.TIsoType;PC.TIsoTopLevel] in
1195 let next_start = List.hd(List.rev tokens) in
1196 let dummy_info = ("",(-1,-1),(-1,-1)) in
1197 let tokens = drop_last [(PC.EOF,dummy_info)] tokens in
1198 let tokens = prepare_tokens (start@tokens) in
1200 print_tokens "iso tokens" tokens;
1202 let entry = parse_one "iso main" PC.iso_main file tokens in
1203 let entry = List.map (List.map Test_exps.process_anything) entry in
1205 then (* The code below allows a header like Statement list,
1206 which is more than one word. We don't have that any more,
1207 but the code is left here in case it is put back. *)
1208 match get_tokens [PC.TArobArob;PC.TArob] with
1210 let (starts_with_name,start) = parse_start start in
1211 (iso_metavars,entry,rule_name) ::
1212 (loop starts_with_name (next_start::start))
1213 | _ -> failwith "isomorphism ends early"
1214 else [(iso_metavars,entry,rule_name)] in
1215 loop starts_with_name start
1216 | (false,_) -> [] in
1219 let parse_iso_files existing_isos iso_files extra_path =
1220 let get_names = List.map (function (_,_,nm) -> nm) in
1221 let old_names = get_names existing_isos in
1222 Data.in_iso := true;
1225 (function (prev,names) ->
1227 Lexer_cocci.init ();
1230 Common.Left(fl) -> Filename.concat extra_path fl
1231 | Common.Right(fl) -> Filename.concat Config.path fl in
1232 let current = parse_iso file in
1233 let new_names = get_names current in
1234 if List.exists (function x -> List.mem x names) new_names
1235 then failwith (Printf.sprintf "repeated iso name found in %s" file);
1236 (current::prev,new_names @ names))
1237 ([],old_names) iso_files in
1238 Data.in_iso := false;
1239 existing_isos@(List.concat (List.rev res))
1242 let table = Common.full_charpos_to_pos file in
1243 Common.with_open_infile file (fun channel ->
1244 let lexbuf = Lexing.from_channel channel in
1245 let get_tokens = tokens_all table file false lexbuf in
1246 Data.in_prolog := true;
1247 let initial_tokens = get_tokens [PC.TArobArob;PC.TArob] in
1248 Data.in_prolog := false;
1250 match initial_tokens with
1252 (match List.rev data with
1253 ((PC.TArobArob as x),_)::_ | ((PC.TArob as x),_)::_ ->
1255 parse_one "iso file names" PC.include_main file data in
1257 let parse_cocci_rule old_metas
1258 (rule_name, dependencies, iso, dropiso, exists, is_expression) =
1259 Ast0.rule_name := rule_name;
1260 Data.inheritable_positions :=
1261 rule_name :: !Data.inheritable_positions;
1263 (* get metavariable declarations *)
1264 Data.in_meta := true;
1265 let (metavars, inherited_metavars) =
1266 get_metavars PC.meta_main table file lexbuf in
1267 Data.in_meta := false;
1268 Hashtbl.add Data.all_metadecls rule_name metavars;
1269 Hashtbl.add Lexer_cocci.rule_names rule_name ();
1270 Hashtbl.add Lexer_cocci.all_metavariables rule_name
1272 (fun key v rest -> (key,v)::rest)
1273 Lexer_cocci.metavariables []);
1275 (* get transformation rules *)
1276 let (more, tokens) = get_tokens [PC.TArobArob; PC.TArob] in
1277 let (minus_tokens, plus_tokens) = split_token_stream tokens in
1279 let minus_tokens = consume_minus_positions minus_tokens in
1280 let minus_tokens = prepare_tokens minus_tokens in
1281 let plus_tokens = prepare_tokens plus_tokens in
1284 print_tokens "minus tokens" minus_tokens;
1285 print_tokens "plus tokens" plus_tokens;
1290 (fix (function x -> drop_double_dots (drop_empty_or x))
1291 (drop_when plus_tokens)) in
1293 print_tokens "plus tokens" plus_tokens;
1294 Printf.printf "before minus parse\n";
1298 then parse_one "minus" PC.minus_exp_main file minus_tokens
1299 else parse_one "minus" PC.minus_main file minus_tokens in
1301 Unparse_ast0.unparse minus_res;
1302 Printf.printf "before plus parse\n";
1305 if !Flag.sgrep_mode2
1306 then (* not actually used for anything, except context_neg *)
1308 (Iso_pattern.rebuild_mcode None).V0.rebuilder_top_level
1312 then parse_one "plus" PC.plus_exp_main file plus_tokens
1313 else parse_one "plus" PC.plus_main file plus_tokens in
1315 Printf.printf "after plus parse\n";
1318 (if not !Flag.sgrep_mode2 &&
1319 (any_modif minus_res or any_modif plus_res)
1320 then Data.inheritable_positions := []);
1322 Check_meta.check_meta rule_name old_metas inherited_metavars
1323 metavars minus_res plus_res;
1325 (more, Ast0.CocciRule ((minus_res, metavars,
1326 (iso, dropiso, dependencies, rule_name, exists)),
1327 (plus_res, metavars)), metavars, tokens) in
1329 let parse_script_rule language old_metas deps =
1330 let get_tokens = tokens_script_all table file false lexbuf in
1332 (* meta-variables *)
1333 Data.in_meta := true;
1335 get_script_metavars PC.script_meta_main table file lexbuf in
1336 Data.in_meta := false;
1338 let exists_in old_metas (py,(r,m)) =
1339 let test (rr,mr) x =
1340 let (ro,vo) = Ast.get_meta_name x in
1341 ro = rr && vo = mr in
1342 List.exists (test (r,m)) old_metas in
1346 let meta2c (r,n) = Printf.sprintf "%s.%s" r n in
1347 if not (exists_in old_metas x) then
1350 "Script references unknown meta-variable: %s"
1355 let (more, tokens) = get_tokens [PC.TArobArob; PC.TArob] in
1357 match List.hd tokens with
1358 (PC.TScriptData(s),_) -> s
1359 | (PC.TArobArob,_) | (PC.TArob,_) -> ""
1360 | _ -> failwith "Malformed script rule" in
1361 (more,Ast0.ScriptRule(language, deps, metavars, data),[],tokens) in
1363 let parse_rule old_metas starts_with_name =
1365 get_rule_name PC.rule_name starts_with_name get_tokens file
1368 Ast.CocciRulename (Some s, a, b, c, d, e) ->
1369 parse_cocci_rule old_metas (s, a, b, c, d, e)
1370 | Ast.ScriptRulename (l,deps) -> parse_script_rule l old_metas deps
1371 | _ -> failwith "Malformed rule name"
1374 let rec loop old_metas starts_with_name =
1375 (!Data.init_rule)();
1377 let gen_starts_with_name more tokens =
1379 (match List.hd (List.rev tokens) with
1380 (PC.TArobArob,_) -> false
1381 | (PC.TArob,_) -> true
1382 | _ -> failwith "unexpected token")
1385 let (more, rule, metavars, tokens) =
1386 parse_rule old_metas starts_with_name in
1389 (loop (metavars @ old_metas) (gen_starts_with_name more tokens))
1394 (iso_files, loop [] (x = PC.TArob))
1395 | _ -> failwith "unexpected code before the first rule\n")
1396 | (false,[(PC.TArobArob,_)]) | (false,[(PC.TArob,_)]) ->
1397 ([],([] : Ast0.parsed_rule list))
1398 | _ -> failwith "unexpected code before the first rule\n" in
1401 (* parse to ast0 and then convert to ast *)
1402 let process file isofile verbose =
1403 let extra_path = Filename.dirname file in
1405 let (iso_files, rules) = parse file in
1409 | Some iso_file -> parse_iso_files [] [Common.Left iso_file] "" in
1410 let global_isos = parse_iso_files std_isos iso_files extra_path in
1411 let rules = Unitary_ast0.do_unitary rules in
1415 Ast0.ScriptRule (a,b,c,d) -> [([],Ast.ScriptRule (a,b,c,d))]
1418 (iso, dropiso, dependencies, rule_name, exists)),
1419 (plus, metavars)) ->
1421 parse_iso_files global_isos
1422 (List.map (function x -> Common.Left x) iso)
1425 (* check that dropped isos are actually available *)
1428 List.map (function (_,_,nm) -> nm) chosen_isos in
1429 let local_iso_names = reserved_names @ iso_names in
1432 (function dropped ->
1433 not (List.mem dropped local_iso_names))
1436 ("invalid iso name " ^ bad_dropped ^ " in " ^ rule_name)
1437 with Not_found -> ());
1438 if List.mem "all" dropiso
1440 if List.length dropiso = 1
1442 else failwith "disable all should only be by itself"
1443 else (* drop those isos *)
1445 (function (_,_,nm) -> not (List.mem nm dropiso))
1447 List.iter Iso_compile.process chosen_isos;
1449 match reserved_names with
1454 List.filter (function x -> List.mem x dropiso) others)
1457 "bad list of reserved names - all must be at start" in
1458 let minus = Test_exps.process minus in
1459 let minus = Compute_lines.compute_lines minus in
1460 let plus = Compute_lines.compute_lines plus in
1462 (* only relevant to Flag.make_hrule *)
1463 (* doesn't handle multiple minirules properly, but since
1464 we don't really handle them in lots of other ways, it
1465 doesn't seem very important *)
1469 [match Ast0.unwrap p with
1471 (match List.map Ast0.unwrap (Ast0.undots c) with
1472 [Ast0.Exp e] -> true | _ -> false)
1474 let minus = Arity.minus_arity minus in
1475 let ((metavars,minus),function_prototypes) =
1476 Function_prototypes.process
1477 rule_name metavars dropped_isos minus plus in
1478 (* warning! context_neg side-effects its arguments *)
1479 let (m,p) = List.split (Context_neg.context_neg minus plus) in
1480 Type_infer.type_infer p;
1481 (if not !Flag.sgrep_mode2 then Insert_plus.insert_plus m p);
1482 Type_infer.type_infer minus;
1483 let (extra_meta, minus) =
1484 Iso_pattern.apply_isos chosen_isos minus rule_name in
1485 let minus = Comm_assoc.comm_assoc minus rule_name dropiso in
1487 if !Flag.sgrep_mode2 then minus
1488 else Single_statement.single_statement minus in
1489 let minus = Simple_assignments.simple_assignments minus in
1491 Ast0toast.ast0toast rule_name dependencies dropped_isos
1492 exists minus is_exp in
1493 match function_prototypes with
1494 None -> [(extra_meta @ metavars, minus_ast)]
1496 [(extra_meta @ metavars, minus_ast); mv_fp])
1497 (* Ast0.CocciRule ((minus, metavarsm, (iso, dropiso, dependencies, rule_name, exists)), (plus, metavars))*)
1499 let parsed = List.concat parsed in
1500 let disjd = Disjdistr.disj parsed in
1502 let (code,fvs,neg_pos,ua,pos) = Free_vars.free_vars disjd in
1503 if !Flag_parsing_cocci.show_SP
1504 then List.iter Pretty_print_cocci.unparse code;
1507 Common.profile_code "get_constants"
1508 (fun () -> Get_constants.get_constants code) in (* for grep *)
1509 let glimpse_tokens2 =
1510 Common.profile_code "get_glimpse_constants"
1511 (fun () -> Get_constants2.get_constants code neg_pos) in(* for glimpse *)
1512 (code,fvs,neg_pos,ua,pos,grep_tokens,glimpse_tokens2)