123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259(****************************************************************************)(* Sail *)(* *)(* Sail and the Sail architecture models here, comprising all files and *)(* directories except the ASL-derived Sail code in the aarch64 directory, *)(* are subject to the BSD two-clause licence below. *)(* *)(* The ASL derived parts of the ARMv8.3 specification in *)(* aarch64/no_vector and aarch64/full are copyright ARM Ltd. *)(* *)(* Copyright (c) 2013-2021 *)(* Kathyrn Gray *)(* Shaked Flur *)(* Stephen Kell *)(* Gabriel Kerneis *)(* Robert Norton-Wright *)(* Christopher Pulte *)(* Peter Sewell *)(* Alasdair Armstrong *)(* Brian Campbell *)(* Thomas Bauereiss *)(* Anthony Fox *)(* Jon French *)(* Dominic Mulligan *)(* Stephen Kell *)(* Mark Wassell *)(* Alastair Reid (Arm Ltd) *)(* *)(* All rights reserved. *)(* *)(* This work was partially supported by EPSRC grant EP/K008528/1 <a *)(* href="http://www.cl.cam.ac.uk/users/pes20/rems">REMS: Rigorous *)(* Engineering for Mainstream Systems</a>, an ARM iCASE award, EPSRC IAA *)(* KTF funding, and donations from Arm. This project has received *)(* funding from the European Research Council (ERC) under the European *)(* Union’s Horizon 2020 research and innovation programme (grant *)(* agreement No 789108, ELVER). *)(* *)(* This software was developed by SRI International and the University of *)(* Cambridge Computer Laboratory (Department of Computer Science and *)(* Technology) under DARPA/AFRL contracts FA8650-18-C-7809 ("CIFV") *)(* and FA8750-10-C-0237 ("CTSRD"). *)(* *)(* Redistribution and use in source and binary forms, with or without *)(* modification, are permitted provided that the following conditions *)(* are met: *)(* 1. Redistributions of source code must retain the above copyright *)(* notice, this list of conditions and the following disclaimer. *)(* 2. Redistributions in binary form must reproduce the above copyright *)(* notice, this list of conditions and the following disclaimer in *)(* the documentation and/or other materials provided with the *)(* distribution. *)(* *)(* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' *)(* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED *)(* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A *)(* PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR *)(* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, *)(* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT *)(* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF *)(* USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND *)(* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, *)(* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT *)(* OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF *)(* SUCH DAMAGE. *)(****************************************************************************)openParse_ast(* Simple preprocessor features for conditional file loading *)moduleStringSet=Set.Make(String)letdefault_symbols=List.fold_left(funsetstr->StringSet.addstrset)StringSet.empty["FEATURE_IMPLICITS";"FEATURE_CONSTANT_TYPES";"FEATURE_BITVECTOR_TYPE";"FEATURE_UNION_BARRIER";"FEATURE_STRICT_VAR";]letsymbols=refdefault_symbolslethave_symbolsymbol=StringSet.memsymbol!symbolsletclear_symbols()=symbols:=default_symbolsletadd_symbolstr=symbols:=StringSet.addstr!symbolslet()=letopenInteractiveinArgString("symbol",funsymbol->ActionUnit(fun_->add_symbolsymbol))|>register_command~name:"define_symbol"~help:"Define preprocessor symbol";ArgString("symbol",funsymbol->ActionUnit(fun_->symbols:=StringSet.removesymbol!symbols))|>register_command~name:"undef_symbol"~help:"Undefine preprocessor symbol";ActionUnit(fun_->List.iterprint_endline(StringSet.elements!symbols))|>register_command~name:"symbols"~help:"Print defined preprocessor symbols"letcond_pragmaldefs=letdepth=ref0inletin_then=reftrueinletthen_defs=ref[]inletelse_defs=ref[]inletpush_defdef=if!in_thenthenthen_defs:=def::!then_defselseelse_defs:=def::!else_defsinletrecscan=function|DEF_aux(DEF_pragma("endif",_),_)::defswhen!depth=0->(List.rev!then_defs,List.rev!else_defs,defs)|DEF_aux(DEF_pragma("else",_),_)::defswhen!depth=0->in_then:=false;scandefs|(DEF_aux(DEF_pragma(p,_),_)asdef)::defswhenp="ifdef"||p="ifndef"||p="iftarget"->incrdepth;push_defdef;scandefs|(DEF_aux(DEF_pragma("endif",_),_)asdef)::defs->decrdepth;push_defdef;scandefs|def::defs->push_defdef;scandefs|[]->raise(Reporting.err_generall"$ifdef, $ifndef, or $iftarget never ended by $endif")inscandefs(* We want to provide warnings for e.g. a mispelled pragma rather than
just silently ignoring them, so we have a list here of all
recognised pragmas. *)letall_pragmas=List.fold_left(funsetstr->StringSet.addstrset)StringSet.empty["define";"anchor";"span";"include";"ifdef";"ifndef";"iftarget";"else";"endif";"option";"optimize";"latex";"property";"counterexample";"suppress_warnings";"include_start";"include_end";"sail_internal";"target_set";"non_exec";]letwrap_includelfile=function|[]->[]|defs->[DEF_aux(DEF_pragma("include_start",file),l)]@defs@[DEF_aux(DEF_pragma("include_end",file),l)]letpreprocessdirtargetopts=letmoduleP=Parse_astinletrecauxacc=function|[]->List.revacc|DEF_aux(DEF_pragma("define",symbol),_)::defs->symbols:=StringSet.addsymbol!symbols;auxaccdefs|(DEF_aux(DEF_pragma("option",command),l)asopt_pragma)::defs->beginletfirst_lineerr_msg=matchString.split_on_char'\n'err_msgwithline::_->"\n"^line|[]->(""[@coverageoff])(* Don't expect this should ever happen, but we are fine if it does *)intryletargs=Str.split(Str.regexp" +")commandinletfile_argfile=raise(Reporting.err_generall("Anonymous argument '"^file^"' cannot be passed via $option directive"))inArg.parse_argv~current:(ref0)(Array.of_list("sail"::args))optsfile_arg""with|Arg.Helpmsg->raise(Reporting.err_generall"-help flag passed to $option directive")|Arg.Badmsg->raise(Reporting.err_generall("Invalid flag passed to $option directive"^first_linemsg))end;aux(opt_pragma::acc)defs|DEF_aux(DEF_pragma("ifndef",symbol),l)::defs->letthen_defs,else_defs,defs=cond_pragmaldefsinifnot(StringSet.memsymbol!symbols)thenauxacc(then_defs@defs)elseauxacc(else_defs@defs)|DEF_aux(DEF_pragma("ifdef",symbol),l)::defs->letthen_defs,else_defs,defs=cond_pragmaldefsinifStringSet.memsymbol!symbolsthenauxacc(then_defs@defs)elseauxacc(else_defs@defs)|DEF_aux(DEF_pragma("iftarget",t),l)::defs->letthen_defs,else_defs,defs=cond_pragmaldefsinbeginmatchtargetwithSomet'whent=t'->auxacc(then_defs@defs)|_->auxacc(else_defs@defs)end|DEF_aux(DEF_pragma("include",file),l)::defs->letlen=String.lengthfileiniflen=0then(Reporting.warn""l"Skipping bad $include. No file argument.";auxaccdefs)elseiffile.[0]='"'&&file.[len-1]='"'then(letrelative=matchlwith|Parse_ast.Range(pos,_)->Filename.dirnameLexing.(pos.pos_fname)|_->failwith"Couldn't figure out relative path for $include. This really shouldn't ever happen."inletfile=String.subfile1(len-2)inletinclude_file=Filename.concatrelativefileinletinclude_defs=Initial_check.parse_file~loc:l(Filename.concatrelativefile)|>snd|>aux[]inaux(List.rev(wrap_includelinclude_fileinclude_defs)@acc)defs)elseiffile.[0]='<'&&file.[len-1]='>'then(letfile=String.subfile1(len-2)inletsail_dir=Reporting.get_sail_dirdirinletfile=Filename.concatsail_dir("lib/"^file)inletinclude_defs=Initial_check.parse_file~loc:lfile|>snd|>aux[]inaux(List.rev(wrap_includelfileinclude_defs)@acc)defs)else(lethelp="Make sure the filename is surrounded by quotes or angle brackets"inReporting.warn""l("Skipping bad $include "^file^". "^help);auxaccdefs)|DEF_aux(DEF_pragma("suppress_warnings",_),l)::defs->beginmatchReporting.simp_loclwith|None->()(* This shouldn't happen, but if it does just continue *)|Some(p,_)->Reporting.suppress_warnings_for_filep.pos_fnameend;auxaccdefs(* Filter file_start and file_end out of the AST so when we
round-trip files through the compiler we don't end up with
incorrect start/end annotations *)|(DEF_aux(DEF_pragma("file_start",_),_)|DEF_aux(DEF_pragma("file_end",_),_))::defs->auxaccdefs|DEF_aux(DEF_pragma(p,arg),l)::defs->ifnot(StringSet.mempall_pragmas)thenReporting.warn""l("Unrecognised directive: "^p);aux(DEF_aux(DEF_pragma(p,arg),l)::acc)defs|DEF_aux(DEF_outcome(outcome_spec,inner_defs),l)::defs->aux(DEF_aux(DEF_outcome(outcome_spec,aux[]inner_defs),l)::acc)defs|(DEF_aux(DEF_default(DT_aux(DT_order(_,ATyp_aux(atyp,_)),_)),l)asdef)::defs->beginmatchatypwith|Parse_ast.ATyp_inc->symbols:=StringSet.add"_DEFAULT_INC"!symbols;aux(def::acc)defs|Parse_ast.ATyp_dec->symbols:=StringSet.add"_DEFAULT_DEC"!symbols;aux(def::acc)defs|_->aux(def::acc)defsend|def::defs->aux(def::acc)defsinaux[]