123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387(* Time-stamp: <modified the 14/04/2022 (at 21:22) by Erwan Jahier> *)(*-----------------------------------------------------------------------
** This file may only be copied under the terms of the CeCILL
** Public License
**-----------------------------------------------------------------------
**
** File: rifIO.ml
** Author: erwan.jahier@univ-grenoble-alpes.fr
*)openListletlexer=LocalGenlex.make_lexer["q";"nil";"?";"ERROR";"Error";"error";"#";"x";"load_luc";"#@";"@#";"end"](* xxx Which pragmas should be defined ? *)letdflt_pragmas=["inputs";"reset";"quit"](* let dflt_pragmas = ["outs";"outputs";"program";"inputs";"step";"reset" ] *)typestream=LocalGenlex.tokenStream.tletrec(_parse_string_list:stream->stringlist->stringlist)=funstreamsl->try(match(Stream.nextstream)with(LocalGenlex.String(str))->_parse_string_liststream(str::sl)|_->failwith("### rif parse error. A \"string\" (wrapped with double"^"quotes) was expected. \n"))withStream.Failure->slopenData(*------------------------------------------------------------------------*)exceptionByeexceptionResetletread_linedebuglabelicoc=ifdebugthen(prerr_string("["^label^"] RifIO.read_line: wait for something to read...\n");flushstderr);letstr=input_lineicinlet_=ifdebugthen(prerr_string("["^label^"] RifIO.read_line:'"^str^"'\n");flushstderr)inletstr=Str.global_replace(Str.regexp"\013")""strin(matchocwith|Someoc->output_stringocstr;flushoc|None->());strletget_streamdebuglabelicoc=tryletstr=read_linedebuglabelicocinstr,lexer(Stream.of_stringstr)withEnd_of_file->raiseEnd_of_file|e->print_string("*** Error when parsing RIF: "^(Printexc.to_stringe)^"\n");flushstdout;exit2let(rm_blank:string->string)=funs->letbuff=ref""infori=0toString.lengths-1domatchs.[i]with|' '|'\t'|'\n'|'\"'->()|c->buff:=!buff^(String.make1c)done;!bufflet(to_pair:string->string*Data.t)=funs->matchStr.split(Str.regexp":")swith|[n;t]->rm_blankn,Data.type_of_string(rm_blankt)|_->failwith("Rif parse error: Cannot split '"^s^"'. I expect a string of the form <ident>:<ident>")let_=assert(to_pair"T:bool"=("T",Data.Bool))letstrsubstrij=tryString.substrijwith_->Printf.printf"invalid arg in 'String.sub %s %i %i'\n"strij;flushstdout;exit2letrec(read_until_pragma_end:?debug:(bool)->in_channel->out_channeloption->string->string)=fun?(debug=false)icocstr->letline=read_linedebug""icocintryleti=Str.search_forward(Str.regexp"#@")line0in(String.subline0i)^strwithNot_found->read_until_pragma_end~debug:debugicoc(str^" "^line)(* exported *)let(read_interface:?debug:(bool)->?label:(string)->in_channel->out_channeloption->vntl*vntl)=fun?(debug=false)?(label="")icoc->letrecloopinsoutsin_doneout_done=ifin_done&&out_donethenins,outselseletline=read_linedebuglabelicocintryif(Str.string_match(Str.regexp"#end")line0)||line="q"||line="bye"then(Printf.printf"\n*** RifIO.read_interface: The process %s died before "label;Printf.printf"sending its interface declarations.\n*** Hara-Kiring!\n";flushstdout;raiseBye)elseifStr.string_match(Str.regexp"#inputs")line0thenletstr=strsubline7(String.lengthline-7)inletl=Str.split(Str.regexp" ")strinletl=List.filter(funstr->str<>"")linloop(List.mapto_pairl)outstrueout_doneelseifStr.string_match(Str.regexp"@#inputs")line0thenletstr=strsubline8(String.lengthline-8)inletstr=read_until_pragma_end~debug:debugicocstrinletl=Str.split(Str.regexp" ")strinletl=List.filter(funstr->str<>"")linloop(List.mapto_pairl)outstrueout_doneelseifStr.string_match(Str.regexp"#outputs")line0thenletstr=strsubline8(String.lengthline-8)inletl=Str.split(Str.regexp" ")strinletl=List.filter(funstr->str<>"")linloopins(List.mapto_pairl)in_donetrueelseifStr.string_match(Str.regexp"@#outputs")line0thenletstr=strsubline9(String.lengthline-9)inletstr=read_until_pragma_end~debug:debugicocstrinletl=Str.split(Str.regexp" ")strinletl=List.filter(funstr->str<>"")linloopins(List.mapto_pairl)in_donetrueelseloopinsoutsin_doneout_donewithe->print_string("#"^line^"\n");flushstdout;raiseeinloop[][]falsefalse(* exported *)(** Reads input values on ic. It should follow the rif format. *)letrec(read:?debug:(bool)->?label:(string)->?pragma:(stringlist)->in_channel->out_channeloption->vntl->substlist)=fun?(debug=false)?(label="")?(pragma=dflt_pragmas)icocvntl->lettbl=[]inifvntl=[]thentblelseletstr,stream=get_streamdebuglabelicocinparse_rif_stream~debug:debuglabelicocvntl(str,stream)tblpragmaand(parse_rif_stream:?debug:(bool)->string->in_channel->out_channeloption->vntl->string*stream->substlist->stringlist->substlist)=fun?(debug=false)labelicocvntl(str,stream)tblpragma->ifvntl=[]thentblelselettok_list=Stream.npeek2streaminmatchtok_listwith|[LocalGenlex.Kwd("#");LocalGenlex.Ident(id)]->ifList.memidpragmathen(Stream.junkstream;Stream.junkstream;ifid="quit"||id="q"thenraiseBye;ifid="reset"thenraiseReset;parse_rif_streamlabelicocvntl(str,stream)tblpragma)else((* We skip everything that occurs after a [#], until the next eol. *)Stream.junkstream;(* prerr_endline (">>" ^str); print the ignored string on stderr *)parse_rif_streamlabelicocvntl(get_streamdebuglabelicoc)tblpragma)|(LocalGenlex.Kwd("ERROR"|"Error"|"error"))::_->print_string("#ERROR value read. bye! ("^str^")\n");flushstdout;raiseBye|(LocalGenlex.Kwd("#"))::(LocalGenlex.Kwd("ERROR"|"Error"|"end"))::_->print_string("#ERROR value read. bye! ("^str^")\n");flushstdout;raiseBye|(LocalGenlex.Kwd("#"))::_->Stream.junkstream;(* prerr_endline (">>>" ^str); print the ignored string on stderr *)parse_rif_streamlabelicocvntl(get_streamdebuglabelicoc)tblpragma|(LocalGenlex.Kwd("q"))::_->print_string"# bye!\n";raiseBye|(LocalGenlex.Kwd("#@"))::_->(* Beginning of multi-line comment. Note that here,
unlike the rif format, we ignore multi line pragmas;
namely, we handle them as a multi-line comment. *)(Stream.junkstream;ignore_toks_until_end_of_pragmasdebuglabelicocvntl(str,stream)tblpragma)|(LocalGenlex.Kwd("nil"))::_|(LocalGenlex.Kwd("?"))::_->Stream.junkstream;lettbl=tbl@[fst(hdvntl),U]inparse_rif_streamlabelicoc(tlvntl)(str,stream)tblpragma|(LocalGenlex.Float(f))::_->(Stream.junkstream;(* Hashtbl.add tbl (Var.name (hd vntl)) (N(F(f))) ; *)letv=matchsnd(hdvntl)with|Data.Bool->print_string("\n*** Warning: type error, "^(string_of_floatf)^" is a real, but an boolean is expected.\n");B(f<>0.0)|Data.Real->F(f)|Data.Int->leti=int_of_floatfinprint_string("\n*** Warning: type error, "^(string_of_floatf)^" is a real, but an int is expected. I convert it to '"^(string_of_inti)^"'\n");I(i)|e->print_string("\n*** Type Error: float found, "^(Data.type_to_stringe)^" expected\n");exit2inlettbl=tbl@[fst(hdvntl),v]inparse_rif_streamlabelicoc(tlvntl)(str,stream)tblpragma)|(LocalGenlex.Int(i))::_->(Stream.junkstream;letv=matchsnd(hdvntl)with|Data.Bool->B(i<>0)|Data.Int->I(i)|Data.Real->letf=float_of_intiinprint_string"\n*** Warning: type error, ";print_string((string_of_inti)^" is an int, but a real is expected. I convert it to '"^(string_of_floatf)^"'\n");F(f)|Data.String->Data.Str(string_of_inti)|e->print_string("\n*** Type Error: int found, "^(Data.type_to_stringe)^"e xpected \n");exit2inlettbl=tbl@[fst(hdvntl),v]inparse_rif_streamlabelicoc(tlvntl)(str,stream)tblpragma)|(LocalGenlex.String(b))::_->(Stream.junkstream;letv=Str(b)inlettbl=tbl@[fst(hdvntl),v]inparse_rif_streamlabelicoc(tlvntl)(str,stream)tblpragma)|(LocalGenlex.Ident(b))::_->(Stream.junkstream;letv=ifmemb["f";"F";"false"]thenB(false)elseifmemb["t";"T";"true"]thenB(true)elseStr(b)inlettbl=tbl@[fst(hdvntl),v]inparse_rif_streamlabelicoc(tlvntl)(str,stream)tblpragma)|[]->(* Eol is is reached; proceed with the next one *)parse_rif_streamlabelicocvntl(get_streamdebuglabelicoc)tblpragma|_->failwith("### rif parse error: not in RIF format ("^str^").\n")and(ignore_toks_until_end_of_pragmas:bool->string->in_channel->out_channeloption->vntl->string*stream->substlist->stringlist->substlist)=fundebuglabelicocvntl(str,stream)tblpragma->(* ignore all tokens until "@#" is reached *)lettok_opt=Stream.peekstreaminmatchtok_optwith|Some(LocalGenlex.Kwd("@#"))->(Stream.junkstream;parse_rif_streamlabelicocvntl(str,stream)tblpragma)|Some(_)->(Stream.junkstream;ignore_toks_until_end_of_pragmasdebuglabelicocvntl(str,stream)tblpragma)|None->(* Eol is is reached; proceed with the next one *)(ignore_toks_until_end_of_pragmasdebuglabelicocvntl(get_streamdebuglabelicoc)tblpragma)(*------------------------------------------------------------------------*)(* exported *)let(write:out_channel->string->unit)=funocstr->output_stringocstrlet(flush:out_channel->unit)=funoc->flushoc(*------------------------------------------------------------------------*)(* exported *)let(write_interface:out_channel->vntl->vntl->vntloption->vntllistoption->unit)=funocin_varsout_varsloc_vars_optoracle_vars_opt->letstr=(List.fold_left(funacc(vn,vt)->acc^"\""^vn^"\":"^(Data.type_to_stringvt)^" ")"#inputs "in_vars)^"\n#outputs "^(List.fold_left(funacc(vn,vt)->acc^"\""^vn^"\":"^(Data.type_to_stringvt)^" ")""out_vars)^(matchloc_vars_optwith|None->"\n"|Someloc_vars->((List.fold_left(funacc(vn,vt)->acc^"\""^vn^"\":"^(Data.type_to_stringvt)^" ")"\n#locals "loc_vars)^"\n"))^(matchoracle_vars_optwith|None->""|Somevars_l->(List.fold_left(funaccvars->((List.fold_left(funacc(vn,vt)->acc^"\""^vn^"\":"^(Data.type_to_stringvt)^" ")"#oracle_outputs "vars)^"\n"^acc))""vars_l))inwriteocstr(*------------------------------------------------------------------------*)(* exported *)let(write_outputs:out_channel->(float->string)->vntl->substlist->unit)=funocs2fvntlsl->letstr=List.fold_left(funacc(vn,_vt)->acc^(tryData.val_to_strings2f(List.assocvnsl)with|Not_found->Printf.eprintf("\n*** RifIO: %s not found in {%s} \n")vn(String.concat","(List.map(fun(n,_)->n)sl));flushstderr;"nil")^" ")""vntlinoutput_stringocstr