123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256(**************************************************************************)(* *)(* This file is part of Frama-C. *)(* *)(* Copyright (C) 2007-2024 *)(* 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). *)(* *)(**************************************************************************)openLogic_ptreeopenCil_typesopenCil_datatype(* -------------------------------------------------------------------------- *)(* --- Region Specifications --- *)(* -------------------------------------------------------------------------- *)typepath={loc:location;typ:typ;step:step;}andstep=|Varofvarinfo|AddrOfofpath|Starofpath|Shiftofpath|Indexofpath*int|Fieldofpath*fieldinfo|Castoftyp*pathtyperegion={rname:stringoption;rpath:pathlist;}(* -------------------------------------------------------------------------- *)(* --- Printers --- *)(* -------------------------------------------------------------------------- *)letatomic=function|Var_|AddrOf_|Star_|Index_|Field_->true|Shift_|Cast_->falseletrecpp_stepfmt=function|Varx->Varinfo.prettyfmtx|Field(p,f)->pfieldpffmt|Index(a,n)->Format.fprintffmt"%a[%d]"pp_atoman|Shifta->Format.fprintffmt"%a+(..)"pp_atoma|Stara->Format.fprintffmt"*%a"pp_atoma|AddrOfa->Format.fprintffmt"&%a"pp_atoma|Cast(t,a)->Format.fprintffmt"(%a)@,%a"Typ.prettytpp_atomaandpfieldpfdfmt=matchp.stepwith|Starp->Format.fprintffmt"%a->%a"pp_atompFieldinfo.prettyfd|_->Format.fprintffmt"%a.%a"pp_atompFieldinfo.prettyfdandpp_atomfmta=ifatomica.stepthenpp_stepfmta.stepelseFormat.fprintffmt"@[<hov 2>(%a)@]"pp_stepa.stepandpp_pathfmta=pp_stepfmta.stepletpp_namedfmt=functionNone->()|Somea->Format.fprintffmt"%s: "aletpp_regionfmtr=matchr.rpathwith|[]->Format.pp_print_stringfmt"\null"|p::ps->beginFormat.fprintffmt"@[<hov 2>";pp_namedfmtr.rname;pp_pathfmtp;List.iter(Format.fprintffmt",@ %a"pp_path)ps;Format.fprintffmt"@]";endletpp_regionsfmt=function|[]->Format.pp_print_stringfmt"\null"|r::rs->beginFormat.fprintffmt"@[<hv 0>";pp_regionfmtr;List.iter(Format.fprintffmt",@ %a"pp_region)rs;Format.fprintffmt"@]";end(* -------------------------------------------------------------------------- *)(* --- Parsers --- *)(* -------------------------------------------------------------------------- *)typeenv={context:Logic_typing.typing_context;mutablenamed:stringoption;mutablepaths:pathlist;mutablespecs:regionlist;}leterror(env:env)~locmsg=env.context.errorlocmsgletparse_variable(env:env)~locx=matchenv.context.find_varxwith|{lv_origin=Somev}->{loc;typ=v.vtype;step=Varv}|_->errorenv~loc"Variable '%s' is not a C-variable"xletparse_fieldenv~loccompf=tryCil.getCompFieldcompfwithNot_found->errorenv~loc"No field '%s' in compound type '%s'"fcomp.cnameletparse_compinfoenv~loctyp=tryCil.getCompTypetypwithNot_found->errorenv~loc"Expected compound type for term"letparse_lrange(env:env)(e:lexpr)=matche.lexpr_nodewith|PLrange(None,None)->()|_->errorenv~loc:e.lexpr_loc"Unexpected index (use unspecified range only)"letparse_typenv~loct=letopenLogic_typinginletg=env.contextinlett=g.logic_typeglocg.pre_statetinmatchLogic_utils.unroll_typetwith|Ctypetyp->typ|_->errorenv~loc"C-type expected for casting l-values"letrecparse_lpath(env:env)(e:lexpr)=letloc=e.lexpr_locinmatche.lexpr_nodewith|PLvarx->parse_variableenv~locx|PLunop(Ustar,p)->letlv=parse_lpathenvpinifCil.isPointerTypelv.typthenlette=Cil.typeOf_pointedlv.typin{loc;step=Starlv;typ=te}elseerrorenv~loc"Pointer-type expected for operator '*'"|PLunop(Uamp,p)->letlv=parse_lpathenvpinlettyp=TPtr(lv.typ,[])in{loc;step=AddrOflv;typ}|PLbinop(p,Badd,rg)->parse_lrangeenvrg;let{typ}aslv=parse_lpathenvpinifCil.isPointerTypetypthen{loc;step=Shiftlv;typ=typ}elseifCil.isArrayTypetypthenlette=Cil.typeOf_array_elemtypin{loc;step=Shiftlv;typ=TPtr(te,[])}elseerrorenv~loc"Pointer-type expected for operator '+'"|PLdot(p,f)->letlv=parse_lpathenvpinletcomp=parse_compinfoenv~loc:lv.loclv.typinletfd=parse_fieldenv~loccompfin{loc;step=Field(lv,fd);typ=fd.ftype}|PLarrow(p,f)->letsp={lexpr_loc=loc;lexpr_node=PLunop(Ustar,p)}inletpf={lexpr_loc=loc;lexpr_node=PLdot(sp,f)}inparse_lpathenvpf|PLarrget(p,rg)->parse_lrangeenvrg;let{typ}aslv=parse_lpathenvpinifCil.isPointerTypetypthenletpointed=Cil.typeOf_pointedtypinletls={loc;step=Shiftlv;typ}in{loc;step=Starls;typ=pointed}elseifCil.isArrayTypetypthenletelt,size=Cil.typeOf_array_elem_sizetypin{loc;step=Index(lv,Z.to_int@@Option.getsize);typ=elt}elseerrorenv~loc:lv.loc"Pointer or array type expected"|PLcast(t,a)->letlv=parse_lpathenvainletty=parse_typenv~loctin{loc;step=Cast(ty,lv);typ=ty}|_->errorenv~loc"Unexpected expression for region spec"letrecparse_named_lpath(env:env)p=matchp.lexpr_nodewith|PLnamed(name,p)->ifenv.named<>None&&env.paths<>[]thenbeginenv.specs<-{rname=env.named;rpath=env.paths}::env.specs;env.paths<-[];end;env.named<-Somename;parse_named_lpathenvp|_->letpath=parse_lpathenvpinenv.paths<-path::env.paths(* -------------------------------------------------------------------------- *)(* --- Spec Typechecking & Printing --- *)(* -------------------------------------------------------------------------- *)letkspec=ref0letregistry=Hashtbl.create0letof_extidid=tryHashtbl.findregistryidwithNot_found->[]letof_extension=function|{ext_name="region";ext_kind=Ext_idk}->of_extidk|_->[]letof_code_annot=function|{annot_content=AExtended(_,_,e)}->of_extensione|_->[]letof_behaviorbhv=List.concat_mapof_extensionbhv.b_extendedlettypechecktyping_context_locps=letenv={named=None;context=typing_context;paths=[];specs=[];}inList.iter(parse_named_lpathenv)ps;letid=!kspecinincrkspec;letspecs={rname=env.named;rpath=env.paths}::env.specsinHashtbl.addregistryid@@List.revspecs;Ext_ididletprinter_ppfmt=function|Ext_idk->letrs=tryHashtbl.findregistrykwithNot_found->[]inpp_regionsfmtrs|_->()let()=beginAcsl_extension.register_behavior~plugin:"region""region"typecheck~printerfalse;Acsl_extension.register_code_annot~plugin:"region""alias"typecheck~printerfalse;end(* -------------------------------------------------------------------------- *)