123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171(**************************************************************************)(* *)(* This file is part of the Frama-C's E-ACSL plug-in. *)(* *)(* Copyright (C) 2012-2023 *)(* CEA (Commissariat à l'énergie atomique et aux énergies *)(* alternatives) *)(* *)(* you can redistribute it and/or modify it under the terms of the GNU *)(* Lesser General Public License as published by the Free Software *)(* Foundation, version 2.1. *)(* *)(* It 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 Lesser General Public License for more details. *)(* *)(* See the GNU Lesser General Public License version 2.1 *)(* for more details (enclosed in the file licenses/LGPLv2.1). *)(* *)(**************************************************************************)moduleResulting_projects=State_builder.Hashtbl(Datatype.String.Hashtbl)(Project.Datatype)(structletname="E-ACSL resulting projects"letsize=7letdependencies=Ast.self::Options.parameter_statesend)letgenerate_code=Resulting_projects.memo(funname->Options.feedback"beginning translation.";Temporal.enable(Options.Temporal_validity.get());Options.setup();(* slightly more efficient to copy the project before computing the AST
if it is not yet computed *)letrtl_prj_name=Options.Project_name.get()^" RTL"inletrtl_prj=Project.create_by_copy~last:falsertl_prj_namein(* force AST computation before copying the project it belongs to *)Ast.compute();letcopied_prj=Project.create_by_copy~last:truenameinProject.oncopied_prj(fun()->(* preparation of the AST does not concern the E-ACSL RTL:
do it first *)Prepare_ast.prepare();Rtl.linkrtl_prj;(* the E-ACSL type system ensures the soundness of the generated
arithmetic operations. Therefore, deactivate the corresponding
options in order to prevent RTE to generate spurious alarms. *)letsigned=Kernel.SignedOverflow.get()inletunsigned=Kernel.UnsignedOverflow.get()in(* we do know that setting these flags does not modify the program's
semantics: using their unsafe variants is thus safe and preserve
all emitted property statuses. *)Kernel.SignedOverflow.unsafe_setfalse;Kernel.UnsignedOverflow.unsafe_setfalse;letfinally()=Kernel.SignedOverflow.unsafe_setsigned;Kernel.UnsignedOverflow.unsafe_setunsignedinFun.protect~finally(fun()->Gmp_types.init();Analyses.preprocess();Injector.inject());(* remove the RTE's results computed from E-ACSL: they are partial
and associated with the wrong kernel function (the one of the old
project). *)(* [TODO] what if RTE was already computed? To be fixed when
redoing the RTE management system *)letselection=State_selection.union(Rte.get_state_selection_with_dependencies())(State_selection.with_dependenciesOptions.Run.self)inProject.clear~selection~project:copied_prj();Resulting_projects.mark_as_computed())();ifnot(Options.debug_atleast1)thenProject.remove~project:rtl_prj();Options.feedback"translation done in project \"%s\"."(Options.Project_name.get());copied_prj)letgenerate_code=Dynamic.register~plugin:"E_ACSL""generate_code"(Datatype.funcDatatype.stringProject.ty)generate_code(* The Frama-C standard library contains specific built-in variables prefixed by
"__fc_" and declared as extern: they prevent the generated code to be
linked. This modification of the default printer replaces them by their
original version from the stdlib. For instance, [__fc_stdout] is replaced by
[stdout]. That is very hackish since it modifies the default Frama-C
printer.
TODO: should be done by the Frama-C default printer at some points. *)letchange_printer=(* not projectified on purpose: this printer change is common to each
project. *)letfirst=reftrueinfun()->if!firstthenbeginfirst:=false;letr=Str.regexp"^__fc_"inletmodulePrinter_class(X:Printer.PrinterClass)=structclassprinter=objectinheritX.printerassupermethod!varinfofmtvi=ifFunctions.Libc.is_vla_alloc_namevi.Cil_types.vnamethen(* Replace VLA allocation with calls to [__builtin_alloca] *)Format.fprintffmt"%s"Functions.Libc.actual_allocaelseif(notvi.vghost)&&vi.vstorage==Cil_types.Externthen(* Replace calls to Frama-C builtins with calls to their original
version from the libc *)lets=Str.replace_firstr""vi.Cil_types.vnameinFormat.fprintffmt"%s"selse(* Otherwise use the original printer *)super#varinfofmtvimethod!instrfmti=matchiwith|Call(_,fct,_,_)whenFunctions.Libc.is_vla_freefct->(* Nothing to print: VLA deallocation is done automatically when
leaving the scope *)Format.fprintffmt"/* ";super#instrfmti;Format.fprintffmt" */"|_->super#instrfmtimethod!globalfmtg=letis_vla_builtinvi=Functions.Libc.is_vla_alloc_namevi.Cil_types.vname||Functions.Libc.is_vla_free_namevi.Cil_types.vnameinmatchgwith|GFunDecl(_,vi,_)whenis_vla_builtinvi->(* Nothing to print: the VLA builtins don't have an original libc
version. *)()|_->super#globalfmtgendendinPrinter.update_printer(modulePrinter_class:Printer.PrinterExtension)endletmain()=ifOptions.Run.get()thenbeginchange_printer();ignore(generate_code(Options.Project_name.get()));endlet()=Db.Main.extendmain(*
Local Variables:
compile-command: "make -C ../../../.."
End:
*)