(* Yoann Padioleau * * Copyright (C) 2011 Facebook * Copyright (C) 2006, 2007, 2008 Ecole des Mines de Nantes * * 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 T = Parser_cpp module TH = Token_helpers_cpp module PI = Parse_info (*****************************************************************************) (* Wrappers *) (*****************************************************************************) let pr2_err, _pr2_once = Common2.mk_pr2_wrappers Flag_parsing_cpp.verbose_parsing let pr2_err s = pr2_err ("ERROR_RECOV: " ^s) (*****************************************************************************) (* Helpers *) (*****************************************************************************) (*****************************************************************************) (* Skipping stuff, find next "synchronisation" point *) (*****************************************************************************) (* todo: do something if find T.Eof ? *) let rec find_next_synchro ~next ~already_passed = (* Maybe because not enough }, because for example an ifdef contains * in both branch some opening {, we later eat too much, "on deborde * sur la fonction d'apres". So already_passed may be too big and * looking for next synchro point starting from next may not be the * best. So maybe we can find synchro point inside already_passed * instead of looking in next. * * But take care! must progress. We must not stay in infinite loop! * For instance now I have as a error recovery to look for * a "start of something", corresponding to start of function, * but must go beyond this start otherwise will loop. * So look at premier(external_declaration2) in parser.output and * pass at least those first tokens. * * I have chosen to start search for next synchro point after the * first { I found, so quite sure we will not loop. *) let last_round = List.rev already_passed in let is_define = let xs = last_round +> List.filter TH.is_not_comment in match xs with | T.TDefine _::_ -> true | _ -> false in if is_define then find_next_synchro_define (last_round @ next) [] else let (before, after) = last_round +> Common.span (fun tok -> match tok with (* by looking at TOBrace we are sure that the "start of something" * will not arrive too early *) | T.TOBrace _ -> false | T.TDefine _ -> false | _ -> true ) in find_next_synchro_orig (after @ next) (List.rev before) and find_next_synchro_define next already_passed = match next with | [] -> pr2_err "end of file while in recovery mode"; already_passed, [] | (T.TCommentNewline_DefineEndOfMacro _ as v)::xs -> pr2_err (spf "found sync end of #define at line %d" (TH.line_of_tok v)); v::already_passed, xs | v::xs -> find_next_synchro_define xs (v::already_passed) and find_next_synchro_orig next already_passed = match next with | [] -> pr2_err "end of file while in recovery mode"; already_passed, [] | (T.TCBrace i as v)::xs when PI.col_of_info i = 0 -> pr2_err (spf "found sync '}' at line %d" (PI.line_of_info i)); (match xs with | [] -> raise Impossible (* there is a EOF token normally *) (* still useful: now parser.mly allow empty ';' so normally no pb *) | T.TPtVirg iptvirg::xs -> pr2_err "found sync bis, eating } and ;"; (T.TPtVirg iptvirg)::v::already_passed, xs | T.TIdent x::T.TPtVirg iptvirg::xs -> pr2_err "found sync bis, eating ident, }, and ;"; (T.TPtVirg iptvirg)::(T.TIdent x)::v::already_passed, xs | T.TCommentSpace sp::T.TIdent x::T.TPtVirg iptvirg ::xs -> pr2_err "found sync bis, eating ident, }, and ;"; (T.TCommentSpace sp):: (T.TPtVirg iptvirg):: (T.TIdent x):: v:: already_passed, xs | _ -> v::already_passed, xs ) | v::xs -> let info = TH.info_of_tok v in if PI.col_of_info info = 0 && TH.is_start_of_something v then begin pr2_err (spf "found sync col 0 at line %d " (PI.line_of_info info)); already_passed, v::xs end else find_next_synchro_orig xs (v::already_passed)