755 lines
22 KiB
OCaml
755 lines
22 KiB
OCaml
(* Yoann Padioleau
|
|
*
|
|
* Copyright (C) 2002-2008 Yoann Padioleau
|
|
* Copyright (C) 2011 Facebook
|
|
*
|
|
* This program is free software; you can redistribute it and/or
|
|
* modify it under the terms of the GNU General Public License (GPL)
|
|
* version 2 as published by the Free Software Foundation.
|
|
*
|
|
* This program 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
|
|
* file license.txt for more details.
|
|
*)
|
|
open Common
|
|
|
|
module Flag = Flag_parsing_cpp
|
|
module Ast = Ast_cpp
|
|
|
|
module TH = Token_helpers_cpp
|
|
module TV = Token_views_cpp
|
|
module Parser = Parser_cpp
|
|
module PI = Parse_info
|
|
|
|
open Parser_cpp
|
|
open Token_views_cpp
|
|
|
|
open Parsing_hacks_lib
|
|
|
|
(*****************************************************************************)
|
|
(* Prelude *)
|
|
(*****************************************************************************)
|
|
(*
|
|
* This file gathers parsing heuristics related to the C preprocessor cpp.
|
|
*)
|
|
|
|
(*****************************************************************************)
|
|
(* Helpers *)
|
|
(*****************************************************************************)
|
|
|
|
let (==~) = Common2.(==~)
|
|
|
|
(* the pair is the status of '()' and '{}', ex: (-1,0)
|
|
* if too much ')' and good '{}'
|
|
* could do for [] too ?
|
|
* could do for ',' if encounter ',' at "toplevel", not inside () or {}
|
|
* then if have ifdef, then certainly can lead to a problem.
|
|
*)
|
|
let (count_open_close_stuff_ifdef_clause: ifdef_grouped list -> (int * int)) =
|
|
fun xs ->
|
|
let cnt_paren, cnt_brace = ref 0, ref 0 in
|
|
xs +> iter_token_ifdef (fun x ->
|
|
(match x.t with
|
|
| x when TH.is_opar x -> incr cnt_paren
|
|
| x when TH.is_obrace x -> incr cnt_brace
|
|
| x when TH.is_cpar x -> decr cnt_paren
|
|
| x when TH.is_obrace x -> decr cnt_brace
|
|
| _ -> ()
|
|
)
|
|
);
|
|
!cnt_paren, !cnt_brace
|
|
|
|
(* look if there is a '{' just after the closing ')', and handling the
|
|
* possibility to have nested expressions inside nested parenthesis
|
|
*)
|
|
(*
|
|
let is_really_foreach xs =
|
|
let rec is_foreach_aux = function
|
|
| [] -> false, []
|
|
| TCPar _::TOBrace _::xs -> true, xs
|
|
(* the following attempts to handle the cases where there is a
|
|
single statement in the body of the loop. undoubtedly more
|
|
cases are needed.
|
|
todo: premier(statement) - suivant(funcall)
|
|
*)
|
|
| TCPar _::TIdent _::xs -> true, xs
|
|
| TCPar _::Tif _::xs -> true, xs
|
|
| TCPar _::Twhile _::xs -> true, xs
|
|
| TCPar _::Tfor _::xs -> true, xs
|
|
| TCPar _::Tswitch _::xs -> true, xs
|
|
|
|
| TCPar _::xs -> false, xs
|
|
| TOPar _::xs ->
|
|
let (_, xs') = is_foreach_aux xs in
|
|
is_foreach_aux xs'
|
|
| x::xs -> is_foreach_aux xs
|
|
in
|
|
is_foreach_aux xs +> fst
|
|
*)
|
|
|
|
(* TODO: set_ifdef_parenthize_info ?? from parsing_c/ *)
|
|
|
|
let filter_pp_or_comment_stuff xs =
|
|
let rec aux xs =
|
|
match xs with
|
|
| [] -> []
|
|
| x::xs ->
|
|
(match x.TV.t with
|
|
| tok when TH.is_comment tok ->
|
|
aux xs
|
|
(* don't want drop the define, or if drop, have to drop
|
|
* also its body otherwise the line heuristics may be lost
|
|
* by not finding the TDefine in column 0 but by finding
|
|
* a TDefineIdent in a column > 0
|
|
*
|
|
* todo? but define often contain some unbalanced {
|
|
*)
|
|
| Parser.TDefine _ ->
|
|
x::aux xs
|
|
| tok when TH.is_pp_instruction tok ->
|
|
aux xs
|
|
| _ ->
|
|
x::aux xs
|
|
)
|
|
in
|
|
aux xs
|
|
|
|
(*****************************************************************************)
|
|
(* Ifdef keeping/passing *)
|
|
(*****************************************************************************)
|
|
|
|
(* #if 0, #if 1, #if LINUX_VERSION handling *)
|
|
let rec find_ifdef_bool xs =
|
|
xs +> List.iter (function
|
|
| NotIfdefLine _ -> ()
|
|
| Ifdefbool (is_ifdef_positif, xxs, info_ifdef_stmt) ->
|
|
|
|
if is_ifdef_positif
|
|
then pr2_pp "commenting parts of a #if 1 or #if LINUX_VERSION"
|
|
else pr2_pp "commenting a #if 0 or #if LINUX_VERSION or __cplusplus";
|
|
|
|
(match xxs with
|
|
| [] -> raise Impossible
|
|
| firstclause::xxs ->
|
|
info_ifdef_stmt +> List.iter (set_as_comment Token_cpp.CppDirective);
|
|
|
|
if is_ifdef_positif
|
|
then xxs +> List.iter
|
|
(iter_token_ifdef (set_as_comment Token_cpp.CppOther))
|
|
else begin
|
|
firstclause +> iter_token_ifdef (set_as_comment Token_cpp.CppOther);
|
|
(match List.rev xxs with
|
|
(* keep only last *)
|
|
| _last::startxs ->
|
|
startxs +> List.iter
|
|
(iter_token_ifdef (set_as_comment Token_cpp.CppOther))
|
|
| [] -> (* not #else *) ()
|
|
);
|
|
end
|
|
);
|
|
|
|
| Ifdef (xxs, _info_ifdef_stmt) -> xxs +> List.iter find_ifdef_bool
|
|
)
|
|
|
|
|
|
|
|
let thresholdIfdefSizeMid = 6
|
|
|
|
(* infer ifdef involving not-closed expressions/statements *)
|
|
let rec find_ifdef_mid xs =
|
|
xs +> List.iter (function
|
|
| NotIfdefLine _ -> ()
|
|
| Ifdef (xxs, info_ifdef_stmt) ->
|
|
(match xxs with
|
|
| [] -> raise Impossible
|
|
| [_first] -> ()
|
|
| _first::second::rest ->
|
|
(* don't analyse big ifdef *)
|
|
if xxs +> List.for_all
|
|
(fun xs -> List.length xs <= thresholdIfdefSizeMid) &&
|
|
(* don't want nested ifdef *)
|
|
xxs +> List.for_all (fun xs ->
|
|
xs +> List.for_all
|
|
(function NotIfdefLine _ -> true | _ -> false)
|
|
)
|
|
|
|
then
|
|
let counts = xxs +> List.map count_open_close_stuff_ifdef_clause in
|
|
let cnt1, cnt2 = List.hd counts in
|
|
if cnt1 <> 0 || cnt2 <> 0
|
|
(*???? && counts +> List.for_all (fun x -> x = (cnt1, cnt2)) *)
|
|
(*
|
|
if counts +> List.exists (fun (cnt1, cnt2) ->
|
|
cnt1 <> 0 || cnt2 <> 0
|
|
)
|
|
*)
|
|
then begin
|
|
pr2_pp "found ifdef-mid-something";
|
|
(* keep only first, treat the rest as comment *)
|
|
info_ifdef_stmt +> List.iter (set_as_comment Token_cpp.CppDirective);
|
|
(second::rest) +> List.iter
|
|
(iter_token_ifdef (set_as_comment Token_cpp.CppOther));
|
|
end
|
|
|
|
);
|
|
List.iter find_ifdef_mid xxs
|
|
|
|
(* no need complex analysis for ifdefbool *)
|
|
| Ifdefbool (_, xxs, _info_ifdef_stmt) ->
|
|
List.iter find_ifdef_mid xxs
|
|
)
|
|
|
|
|
|
let thresholdFunheaderLimit = 4
|
|
|
|
(* ifdef defining alternate function header, type *)
|
|
let rec find_ifdef_funheaders = function
|
|
| [] -> ()
|
|
| NotIfdefLine _::xs -> find_ifdef_funheaders xs
|
|
|
|
(* ifdef-funheader if ifdef with 2 lines and a '{' in next line *)
|
|
| Ifdef
|
|
([(NotIfdefLine (({col = 0} as _xline1)::_line1))::ifdefblock1;
|
|
(NotIfdefLine (({col = 0} as xline2)::line2))::ifdefblock2
|
|
], info_ifdef_stmt
|
|
)
|
|
::NotIfdefLine (({t=TOBrace _i; col = 0})::_line3)
|
|
::xs
|
|
when List.length ifdefblock1 <= thresholdFunheaderLimit &&
|
|
List.length ifdefblock2 <= thresholdFunheaderLimit
|
|
->
|
|
find_ifdef_funheaders xs;
|
|
info_ifdef_stmt +> List.iter (set_as_comment Token_cpp.CppDirective);
|
|
let all_toks = [xline2] @ line2 in
|
|
all_toks +> List.iter (set_as_comment Token_cpp.CppOther) ;
|
|
ifdefblock2 +> iter_token_ifdef (set_as_comment Token_cpp.CppOther);
|
|
|
|
(* ifdef with nested ifdef *)
|
|
| Ifdef
|
|
([[NotIfdefLine (({col = 0} as _xline1)::_line1)];
|
|
[Ifdef
|
|
([[NotIfdefLine (({col = 0} as xline2)::line2)];
|
|
[NotIfdefLine (({col = 0} as xline3)::line3)];
|
|
], info_ifdef_stmt2
|
|
)
|
|
]
|
|
], info_ifdef_stmt
|
|
)
|
|
::NotIfdefLine (({t=TOBrace _i; col = 0})::_line4)
|
|
::xs
|
|
->
|
|
find_ifdef_funheaders xs;
|
|
info_ifdef_stmt +> List.iter (set_as_comment Token_cpp.CppDirective);
|
|
info_ifdef_stmt2 +> List.iter (set_as_comment Token_cpp.CppDirective);
|
|
let all_toks = [xline2;xline3] @ line2 @ line3 in
|
|
all_toks +> List.iter (set_as_comment Token_cpp.CppOther);
|
|
|
|
(* ifdef with elseif *)
|
|
| Ifdef
|
|
([[NotIfdefLine (({col = 0} as _xline1)::_line1)];
|
|
[NotIfdefLine (({col = 0} as xline2)::line2)];
|
|
[NotIfdefLine (({col = 0} as xline3)::line3)];
|
|
], info_ifdef_stmt
|
|
)
|
|
::NotIfdefLine (({t=TOBrace _i; col = 0})::_line4)
|
|
::xs
|
|
->
|
|
find_ifdef_funheaders xs;
|
|
info_ifdef_stmt +> List.iter (set_as_comment Token_cpp.CppDirective);
|
|
let all_toks = [xline2;xline3] @ line2 @ line3 in
|
|
all_toks +> List.iter (set_as_comment Token_cpp.CppOther)
|
|
|
|
|
|
| Ifdef (xxs,_)::xs
|
|
| Ifdefbool (_, xxs,_)::xs ->
|
|
List.iter find_ifdef_funheaders xxs;
|
|
find_ifdef_funheaders xs
|
|
|
|
|
|
(*
|
|
let adjust_inifdef_include xs =
|
|
xs +> List.iter (function
|
|
| NotIfdefLine _ -> ()
|
|
| Ifdef (xxs, info_ifdef_stmt) | Ifdefbool (_, xxs, info_ifdef_stmt) ->
|
|
xxs +> List.iter (iter_token_ifdef (fun tokext ->
|
|
match tokext.t with
|
|
| Parser.TInclude (s1, s2, ii) ->
|
|
(* todo: inifdef_ref := true; *)
|
|
()
|
|
| _ -> ()
|
|
));
|
|
)
|
|
*)
|
|
|
|
(*****************************************************************************)
|
|
(* Builtin macros using standard.h or other defs *)
|
|
(*****************************************************************************)
|
|
(* now in pp_token.ml *)
|
|
|
|
(*****************************************************************************)
|
|
(* Stringification *)
|
|
(*****************************************************************************)
|
|
|
|
let rec find_string_macro_paren xs =
|
|
match xs with
|
|
| [] -> ()
|
|
| Parenthised(xxs, _)::xs ->
|
|
xxs +> List.iter (fun xs ->
|
|
if xs +> List.exists
|
|
(function PToken({t=TString _}) -> true | _ -> false) &&
|
|
xs +> List.for_all
|
|
(function PToken({t=TString _}) | PToken({t=TIdent _}) ->
|
|
true | _ -> false)
|
|
then
|
|
xs +> List.iter (fun tok ->
|
|
match tok with
|
|
| PToken({t=TIdent (_s,_)} as id) ->
|
|
change_tok id (TIdent_MacroString (TH.info_of_tok id.t))
|
|
| _ -> ()
|
|
)
|
|
else
|
|
find_string_macro_paren xs
|
|
);
|
|
find_string_macro_paren xs
|
|
| PToken _ ::xs ->
|
|
find_string_macro_paren xs
|
|
|
|
|
|
(*****************************************************************************)
|
|
(* Macros *)
|
|
(*****************************************************************************)
|
|
|
|
(* don't forget to recurse in each case.
|
|
* note that the code below is called after the ifdef phase simplification,
|
|
* so if this previous phase is buggy, then it may pass some code that
|
|
* could be matched by the following rules but will not.
|
|
**)
|
|
let rec find_macro_paren xs =
|
|
match xs with
|
|
| [] -> ()
|
|
|
|
(* attribute *)
|
|
| PToken ({t=Tattribute _} as id)
|
|
::Parenthised (xxs,info_parens)
|
|
::xs
|
|
->
|
|
pr2_pp ("MACRO: __attribute detected ");
|
|
[Parenthised (xxs, info_parens)] +>
|
|
iter_token_paren (set_as_comment Token_cpp.CppAttr);
|
|
set_as_comment Token_cpp.CppAttr id;
|
|
find_macro_paren xs
|
|
|
|
(* stringification
|
|
*
|
|
* the order of the matching clause is important
|
|
*
|
|
*)
|
|
|
|
(* string macro with params, before case *)
|
|
| PToken ({t=TString _})::PToken ({t=TIdent (_s,_)} as id)
|
|
::Parenthised (xxs, info_parens)
|
|
::xs ->
|
|
change_tok id (TIdent_MacroString (TH.info_of_tok id.t));
|
|
[Parenthised (xxs, info_parens)] +>
|
|
iter_token_paren (set_as_comment Token_cpp.CppMacro);
|
|
find_macro_paren xs
|
|
|
|
(* after case *)
|
|
| PToken ({t=TIdent (_s,_)} as id)
|
|
::Parenthised (xxs, info_parens)
|
|
::PToken ({t=TString _})
|
|
::xs ->
|
|
change_tok id (TIdent_MacroString (TH.info_of_tok id.t));
|
|
[Parenthised (xxs, info_parens)] +>
|
|
iter_token_paren (set_as_comment Token_cpp.CppMacro);
|
|
find_macro_paren xs
|
|
|
|
|
|
(* for the case where the string is not inside a funcall, but
|
|
* for instance in an initializer.
|
|
*)
|
|
|
|
(* string macro variable, before case *)
|
|
| PToken ({t=TString ((str,_),_)})::PToken ({t=TIdent (_s,_)} as id)
|
|
::xs ->
|
|
|
|
(* c++ext: *)
|
|
if str <> "C" then begin
|
|
change_tok id (TIdent_MacroString (TH.info_of_tok id.t));
|
|
find_macro_paren xs
|
|
end
|
|
(* bugfix, forgot to recurse in else case too ... *)
|
|
else
|
|
find_macro_paren xs
|
|
|
|
(* after case *)
|
|
| PToken ({t=TIdent (_s,_)} as id)::PToken ({t=TString _})
|
|
::xs ->
|
|
change_tok id (TIdent_MacroString (TH.info_of_tok id.t));
|
|
find_macro_paren xs
|
|
|
|
(* TODO: cooperating with standard.h *)
|
|
| PToken ({t=TIdent (s,_i1)} as id)::xs
|
|
when s = "MACROSTATEMENT" ->
|
|
change_tok id (TIdent_MacroStmt(TH.info_of_tok id.t));
|
|
find_macro_paren xs
|
|
|
|
|
|
|
|
(* recurse *)
|
|
| (PToken _x)::xs -> find_macro_paren xs
|
|
| (Parenthised (xxs, _))::xs ->
|
|
xxs +> List.iter find_macro_paren;
|
|
find_macro_paren xs
|
|
|
|
|
|
|
|
|
|
|
|
(* don't forget to recurse in each case *)
|
|
let rec find_macro_lineparen xs =
|
|
match xs with
|
|
| [] -> ()
|
|
|
|
(* firefoxext: ex: NS_DECL_NSIDOMNODELIST *)
|
|
| (Line ([PToken ({t=TIdent (s,_)} as macro);]))::xs
|
|
when s ==~ regexp_ns_decl_like ->
|
|
set_as_comment Token_cpp.CppMacro macro;
|
|
|
|
find_macro_lineparen (xs)
|
|
|
|
(* firefoxext: ex: NS_DECL_NSIDOMNODELIST; *)
|
|
| (Line ([PToken ({t=TIdent (s,_)} as macro);
|
|
PToken ({t=TPtVirg _})]))::xs
|
|
when s ==~ regexp_ns_decl_like ->
|
|
set_as_comment Token_cpp.CppMacro macro;
|
|
|
|
find_macro_lineparen (xs)
|
|
|
|
(* firefoxext: ex: NS_IMPL_XXX(a) *)
|
|
| (Line ([PToken ({t=TIdent (s,_)} as macro);
|
|
Parenthised (xxs,info_parens);
|
|
]))::xs
|
|
when s ==~ regexp_ns_decl_like ->
|
|
|
|
[Parenthised (xxs, info_parens)] +>
|
|
iter_token_paren (set_as_comment Token_cpp.CppMacro);
|
|
set_as_comment Token_cpp.CppMacro macro;
|
|
|
|
find_macro_lineparen (xs)
|
|
|
|
|
|
(* linuxext: ex: static [const] DEVICE_ATTR(); *)
|
|
| (Line
|
|
(
|
|
[PToken ({t=Tstatic _});
|
|
PToken ({t=TIdent (s,_)} as macro);
|
|
Parenthised (_xxs,_);
|
|
PToken ({t=TPtVirg _});
|
|
]
|
|
))::xs
|
|
when (s ==~ regexp_macro) ->
|
|
let info = TH.info_of_tok macro.t in
|
|
change_tok macro (TIdent_MacroDecl (PI.str_of_info info, info));
|
|
|
|
find_macro_lineparen (xs)
|
|
|
|
(* the static const case *)
|
|
| (Line
|
|
(
|
|
[PToken ({t=Tstatic _});
|
|
PToken ({t=Tconst _} as const);
|
|
PToken ({t=TIdent (s,_)} as macro);
|
|
Parenthised (_xxs,_info_parens);
|
|
PToken ({t=TPtVirg _});
|
|
]
|
|
(*as line1*)
|
|
|
|
))
|
|
::xs
|
|
when (s ==~ regexp_macro) ->
|
|
let info = TH.info_of_tok macro.t in
|
|
change_tok macro (TIdent_MacroDecl (PI.str_of_info info, info));
|
|
|
|
(* need retag this const, otherwise ambiguity in grammar
|
|
21: shift/reduce conflict (shift 121, reduce 137) on Tconst
|
|
decl2 : Tstatic . TMacroDecl TOPar argument_list TCPar ...
|
|
decl2 : Tstatic . Tconst TMacroDecl TOPar argument_list TCPar ...
|
|
storage_class_spec : Tstatic . (137)
|
|
*)
|
|
change_tok const (Tconst_MacroDeclConst (TH.info_of_tok const.t));
|
|
|
|
find_macro_lineparen (xs)
|
|
|
|
|
|
(* same but without trailing ';'
|
|
*
|
|
* I do not put the final ';' because it can be on a multiline and
|
|
* because of the way mk_line is coded, we will not have access to
|
|
* this ';' on the next line, even if next to the ')' *)
|
|
| (Line
|
|
([PToken ({t=Tstatic _});
|
|
PToken ({t=TIdent (s,_)} as macro);
|
|
Parenthised (_xxs,_);
|
|
]
|
|
))::xs
|
|
when s ==~ regexp_macro ->
|
|
|
|
let info = TH.info_of_tok macro.t in
|
|
change_tok macro (TIdent_MacroDecl (PI.str_of_info info, info));
|
|
|
|
find_macro_lineparen (xs)
|
|
|
|
|
|
|
|
|
|
(* on multiple lines *)
|
|
| (Line
|
|
(
|
|
(PToken ({t=Tstatic _})::[]
|
|
)))
|
|
::(Line
|
|
(
|
|
[PToken ({t=TIdent (s,_)} as macro);
|
|
Parenthised (_,_);
|
|
PToken ({t=TPtVirg _});
|
|
]
|
|
)
|
|
)::xs
|
|
when (s ==~ regexp_macro) ->
|
|
let info = TH.info_of_tok macro.t in
|
|
change_tok macro (TIdent_MacroDecl (PI.str_of_info info, info));
|
|
|
|
find_macro_lineparen xs
|
|
|
|
|
|
(* linuxext: ex: DECLARE_BITMAP();
|
|
*
|
|
* Here I use regexp_declare and not regexp_macro because
|
|
* Sometimes it can be a FunCallMacro such as DEBUG(foo());
|
|
* Here we don't have the preceding 'static' so only way to
|
|
* not have positive is to restrict to .*DECLARE.* macros.
|
|
*
|
|
* but there is a grammar rule for that, so don't need this case anymore
|
|
* unless the parameter of the DECLARE_xxx are wierd and can not be mapped
|
|
* on a argument_list
|
|
*)
|
|
|
|
| (Line
|
|
([PToken ({t=TIdent (s,_)} as macro);
|
|
Parenthised (_,_);
|
|
PToken ({t=TPtVirg _});
|
|
]
|
|
))::xs
|
|
when (s ==~ regexp_declare) ->
|
|
|
|
let info = TH.info_of_tok macro.t in
|
|
change_tok macro (TIdent_MacroDecl (PI.str_of_info info, info));
|
|
|
|
find_macro_lineparen xs
|
|
|
|
(* toplevel macros.
|
|
* module_init(xxx)
|
|
*
|
|
* Could also transform the TIdent in a TMacroTop but can have false
|
|
* positive, so easier to just change the TCPar and so just solve
|
|
* the end-of-stream pb of ocamlyacc
|
|
*)
|
|
| (Line
|
|
([PToken ({t=TIdent (_s,_ii); col = col1; where = ctx} as _macro);
|
|
Parenthised (_,info_parens);
|
|
] as _line1
|
|
))
|
|
::xs when col1 = 0
|
|
->
|
|
let condition =
|
|
(* to reduce number of false positive *)
|
|
(match xs with
|
|
| (Line (PToken ({col = col2 } as other)::_restline2))::_ ->
|
|
TH.is_eof other.t || (col2 = 0 &&
|
|
(match other.t with
|
|
| TOBrace _ -> false (* otherwise would match funcdecl *)
|
|
| TCBrace _ when List.hd ctx <> InFunction -> false
|
|
| TPtVirg _
|
|
| TCol _
|
|
-> false
|
|
| tok when TH.is_binary_operator tok -> false
|
|
|
|
| _ -> true
|
|
)
|
|
)
|
|
| _ -> false
|
|
)
|
|
in
|
|
if condition
|
|
then begin
|
|
(* just to avoid the end-of-stream pb of ocamlyacc *)
|
|
let tcpar = Common2.list_last info_parens in
|
|
change_tok tcpar (TCPar_EOL (TH.info_of_tok tcpar.t));
|
|
(*macro.t <- TMacroTop (s, TH.info_of_tok macro.t);*)
|
|
end;
|
|
find_macro_lineparen xs
|
|
|
|
|
|
|
|
(* macro with parameters
|
|
* ex: DEBUG()
|
|
* return x;
|
|
*)
|
|
| (Line
|
|
([PToken ({t=TIdent (_s,_ii); col = col1; where = ctx} as macro);
|
|
Parenthised (xxs,info_parens);
|
|
] as _line1
|
|
))
|
|
::(Line
|
|
(PToken ({col = col2 } as other)::_restline2
|
|
) as line2)
|
|
::xs
|
|
(* when s ==~ regexp_macro *)
|
|
->
|
|
let condition =
|
|
(col1 = col2 &&
|
|
(match other.t with
|
|
| TOBrace _ -> false (* otherwise would match funcdecl *)
|
|
| TCBrace _ when List.hd ctx <> InFunction -> false
|
|
| TPtVirg _
|
|
| TCol _
|
|
-> false
|
|
| tok when TH.is_binary_operator tok -> false
|
|
|
|
| _ -> true
|
|
)
|
|
)
|
|
||
|
|
(col2 <= col1 &&
|
|
(match other.t with
|
|
| TCBrace _ when List.hd ctx = InFunction -> true
|
|
| Treturn _ -> true
|
|
| Tif _ -> true
|
|
| Telse _ -> true
|
|
|
|
| _ -> false
|
|
)
|
|
)
|
|
|
|
in
|
|
|
|
if condition
|
|
then
|
|
if col1 = 0 then ()
|
|
else begin
|
|
change_tok macro (TIdent_MacroStmt (TH.info_of_tok macro.t));
|
|
[Parenthised (xxs, info_parens)] +>
|
|
iter_token_paren (set_as_comment Token_cpp.CppMacro);
|
|
end;
|
|
|
|
find_macro_lineparen (line2::xs)
|
|
|
|
(* linuxext:? single macro
|
|
* ex: LOCK
|
|
* foo();
|
|
* UNLOCK
|
|
*)
|
|
| (Line
|
|
([PToken ({t=TIdent (_s,_ii); col = col1; where = ctx} as macro);
|
|
] as _line1
|
|
))
|
|
::(Line
|
|
(PToken ({col = col2 } as other)::_restline2
|
|
) as line2)
|
|
::xs ->
|
|
(* when s ==~ regexp_macro *)
|
|
|
|
let condition =
|
|
(col1 = col2 &&
|
|
col1 <> 0 && (* otherwise can match typedef of fundecl*)
|
|
(match other.t with
|
|
| TPtVirg _ -> false
|
|
| TOr _ -> false
|
|
| TCBrace _ when List.hd ctx <> InFunction -> false
|
|
| tok when TH.is_binary_operator tok -> false
|
|
|
|
| _ -> true
|
|
)) ||
|
|
(col2 <= col1 &&
|
|
(match other.t with
|
|
| TCBrace _ when List.hd ctx = InFunction -> true
|
|
| Treturn _ -> true
|
|
| Tif _ -> true
|
|
| Telse _ -> true
|
|
| _ -> false
|
|
))
|
|
in
|
|
|
|
if condition
|
|
then change_tok macro (TIdent_MacroStmt (TH.info_of_tok macro.t));
|
|
|
|
find_macro_lineparen (line2::xs)
|
|
|
|
| _x::xs ->
|
|
find_macro_lineparen xs
|
|
|
|
|
|
(*****************************************************************************)
|
|
(* #Define tobrace init *)
|
|
(*****************************************************************************)
|
|
|
|
let is_init tok2 tok3 =
|
|
match tok2.t, tok3.t with
|
|
| TInt _, TComma _ -> true
|
|
| TString _, TComma _ -> true
|
|
| TIdent _, TComma _ -> true
|
|
| _ -> false
|
|
|
|
let find_define_init_brace_paren xs =
|
|
let rec aux xs =
|
|
match xs with
|
|
| [] -> ()
|
|
|
|
(* mainly for firefox *)
|
|
| (PToken {t=TDefine _})
|
|
::(PToken {t=TIdent_Define (_s,_)})
|
|
::(PToken ({t=TOBrace i1} as tokbrace))
|
|
::(PToken tok2)
|
|
::(PToken tok3)
|
|
::xs ->
|
|
if is_init tok2 tok3
|
|
then change_tok tokbrace (TOBrace_DefineInit i1);
|
|
aux xs
|
|
|
|
(* mainly for linux, especially in sound/ *)
|
|
| (PToken {t=TDefine _})
|
|
::(PToken {t=TIdent_Define (s,_); col=c})
|
|
::(Parenthised(_, {col=c2; _}::_))
|
|
::(PToken ({t=TOBrace i1} as tokbrace))
|
|
::(PToken tok2)
|
|
::(PToken tok3)
|
|
::xs when c2 = c + String.length s ->
|
|
if is_init tok2 tok3
|
|
then change_tok tokbrace (TOBrace_DefineInit i1);
|
|
|
|
aux xs
|
|
|
|
(* ugly: for plan9, too general? *)
|
|
| (PToken {t=TDefine _})
|
|
::(PToken {t=TIdent_Define (_s,_)})
|
|
::(Parenthised(_xxx, _))
|
|
::(PToken ({t=TOBrace i1} as tokbrace))
|
|
(* can be more complex expression than just an int, like (b)&... *)
|
|
::(Parenthised(_, _))
|
|
::(PToken {t=(TAnd _|TOr _);_})
|
|
::xs ->
|
|
change_tok tokbrace (TOBrace_DefineInit i1);
|
|
aux xs
|
|
|
|
(* recurse *)
|
|
| (PToken _)::xs -> aux xs
|
|
| (Parenthised (_, _))::xs ->
|
|
(* not need for tobrace init:
|
|
* xxs +> List.iter aux;
|
|
*)
|
|
aux xs
|
|
in
|
|
aux xs
|
|
|