123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313(************************************************************************)(* * The Coq Proof Assistant / The Coq Development Team *)(* v * Copyright INRIA, CNRS and contributors *)(* <O___,, * (see version control and CREDITS file for authors & dates) *)(* \VV/ **************************************************************)(* // * This file is distributed under the terms of the *)(* * GNU Lesser General Public License Version 2.1 *)(* * (see LICENSE file for the text of the license) *)(************************************************************************)moduleStream=Gramlib.Stream(** We keep the string to preserve the user representation,
e.g. "e"/"E" or the presence of leading 0s, or the presence of a +
in the exponent *)typenum_class=CDec|CHexletstring_del_headns=String.subsn(String.lengths-n)moduleUnsignedNat=structtypet=stringletof_strings=assert(String.lengths>0);assert(s.[0]>='0'&&s.[0]<='9');sletto_strings=String.(mapChar.lowercase_ascii(concat""(split_on_char'_'s)))letsprints=sletprints=Pp.str(sprints)letclassifys=ifString.lengths>=2&&(s.[1]='x'||s.[1]='X')thenCHexelseCDec(** Comparing two raw numbers (base 10 or 16, big-endian, non-negative).
A bit nasty, but not critical: used e.g. to decide when a number
is considered as large (see threshold warnings in notation.ml). *)exceptionCompofintletreccomparess'=letl=String.lengthsandl'=String.lengths'inifl<l'then-compares'selseletd=l-l'intryfori=0tod-1doifs.[i]!='0'thenraise(Comp1)done;fori=dtol-1doletc=Stdlib.compares.[i]s'.[i-d]inifc!=0thenraise(Compc)done;0withCompc->cletcomparend=assert(classifyd=CDec);matchclassifynwith|CDec->compare(to_stringn)(to_stringd)|CHex->compare(string_del_head2(to_stringn))(to_stringd)letis_zeros=compares"0"=0endtypesign=SPlus|SMinustype'aexp=EDecof'a|EBinof'amoduleSignedNat=structtypet=sign*UnsignedNat.tletof_strings=assert(String.lengths>0);letsign,n=matchs.[0]with|'-'->(SMinus,string_del_head1s)|'+'->(SPlus,string_del_head1s)|_->(SPlus,s)in(sign,UnsignedNat.of_stringn)letto_string(sign,n)=(matchsignwithSPlus->""|SMinus->"-")^UnsignedNat.to_stringnletclassify(_,n)=UnsignedNat.classifynletbigint_of_string(sign,n)=Z.of_string(to_string(sign,n))letto_bigintn=bigint_of_stringnletstring_of_nonneg_bigintcn=matchcwith|CDec->Z.format"%d"n|CHex->Z.format"%#x"nletof_bigintcn=letsign,n=ifInt.equal(-1)(Z.signn)then(SMinus,Z.negn)else(SPlus,n)in(sign,string_of_nonneg_bigintcn)endmoduleUnsigned=structtypet={int:string;frac:string;exp:string}(**
- int: \[0-9\]\[0-9_\]*
- frac: empty or \[0-9_\]+
- exp: empty or \[eE\]\[+-\]?\[0-9\]\[0-9_\]*
or
- int: 0\[xX\]\[0-9a-fA-F\]\[0-9a-fA-F_\]*
- frac: empty or \[0-9a-fA-F_\]+
- exp: empty or \[pP\]\[+-\]?\[0-9\]\[0-9_\]* *)letequaln1n2=String.(equaln1.intn2.int&&equaln1.fracn2.frac&&equaln1.expn2.exp)letparse=letbuff=ref(Bytes.create80)inletstorelenx=letopenBytesiniflen>=length!buffthenbuff:=cat!buff(create(length!buff));set!bufflenx;succleninletget_bufflen=Bytes.sub_string!buff0lenin(* reads [0-9_]* *)letrecnumberlens=matchStream.peek()swith|Some('0'..'9'asc)->Stream.junk()s;number(storelenc)s|Some('_'asc)whenlen>0->Stream.junk()s;number(storelenc)s|_->lenin(* reads [0-9a-fA-F_]* *)letrechex_numberlens=matchStream.peek()swith|Some(('0'..'9'|'a'..'f'|'A'..'F')asc)->Stream.junk()s;hex_number(storelenc)s|Some('_'asc)whenlen>0->Stream.junk()s;hex_number(storelenc)s|_->leninfuns->lethex,i=matchStream.npeek()3swith|'0'::(('x'|'X')asx)::(('0'..'9'|'a'..'f'|'A'..'F')asc)::_->Stream.junk()s;Stream.junk()s;Stream.junk()s;true,get_buff(hex_number(store(store(store0'0')x)c)s)|_->false,get_buff(number0s)inassert(i<>"");letf=matchhex,Stream.npeek()2swith|true,'.'::(('0'..'9'|'a'..'f'|'A'..'F'|'_')asc)::_->Stream.junk()s;Stream.junk()s;get_buff(hex_number(store0c)s)|false,'.'::(('0'..'9'|'_')asc)::_->Stream.junk()s;Stream.junk()s;get_buff(number(store0c)s)|_->""inlete=matchhex,Stream.npeek()2swith|true,(('p'|'P')ase)::('0'..'9'asc)::_|false,(('e'|'E')ase)::('0'..'9'asc)::_->Stream.junk()s;Stream.junk()s;get_buff(number(store(store0e)c)s)|true,(('p'|'P')ase)::(('+'|'-')assign)::_|false,(('e'|'E')ase)::(('+'|'-')assign)::_->beginmatchStream.npeek()3swith|_::_::('0'..'9'asc)::_->Stream.junk()s;Stream.junk()s;Stream.junk()s;get_buff(number(store(store(store0e)sign)c)s)|_->""end|_->""in{int=i;frac=f;exp=e}letsprintn=n.int^(ifn.frac=""then""else"."^n.frac)^n.expletprintn=Pp.str(sprintn)letparse_strings=ifs=""||s.[0]<'0'||s.[0]>'9'thenNoneelseletstrm=Stream.of_string(s^" ")inletn=parsestrminifStream.countstrm>=String.lengthsthenSomenelseNoneletof_strings=matchparse_stringswith|None->assertfalse|Somes->sletto_string=sprint(* We could remove the '_' but not necessary for float_of_string *)letto_nat=function|{int=i;frac="";exp=""}->Somei|_->Noneletis_nat=function|{int=_;frac="";exp=""}->true|_->falseletclassifyn=UnsignedNat.classifyn.intendopenUnsignedmoduleSigned=structtypet=sign*Unsigned.tletequal(s1,n1)(s2,n2)=s1=s2&&equaln1n2letis_zero=function|(SPlus,{int;frac;exp})->UnsignedNat.is_zeroint&&UnsignedNat.is_zerofrac|_->falseletof_int_frac_and_exponent(sign,int)fe=assert(matchewithNone->true|Somee->SignedNat.classifye=CDec);letc=UnsignedNat.classifyintinletexp=matchewithNone->""|Somee->lete=SignedNat.to_stringeinmatchcwithCDec->"e"^e|CHex->"p"^einletfrac=matchfwithNone->""|Somef->assert(c=UnsignedNat.classifyf);letf=UnsignedNat.to_stringfinmatchcwithCDec->f|CHex->string_del_head2finsign,{int;frac;exp}letto_int_frac_and_exponent(sign,{int;frac;exp})=lete=ifexp=""thenNoneelseSome(matchexp.[1]with|'-'->SMinus,string_del_head2exp|'+'->SPlus,string_del_head2exp|_->SPlus,string_del_head1exp)inletf=iffrac=""thenNoneelseSome(matchUnsignedNat.classifyintwith|CDec->frac|CHex->"0x"^frac)in(sign,int),f,eletof_nati=(SPlus,{int=i;frac="";exp=""})letof_int(s,i)=(s,{int=i;frac="";exp=""})letof_int_strings=of_int(SignedNat.of_strings)letto_int=function|(s,{int=i;frac="";exp=""})->Some(s,i)|_->Noneletis_intn=matchto_intnwithNone->false|Some_->trueletsprint(s,i)=(matchswithSPlus->""|SMinus->"-")^Unsigned.sprintiletprinti=Pp.str(sprinti)letparse_strings=ifs=""||s="-"||s="+"||(s.[0]<'0'||s.[0]>'9')&&((s.[0]<>'-'&&s.[0]<>'+')||s.[1]<'0'||s.[1]>'9')thenNoneelseletstrm=Stream.of_string(s^" ")inletsign=matchs.[0]with|'-'->(Stream.junk()strm;SMinus)|'+'->(Stream.junk()strm;SPlus)|_->SPlusinletn=parsestrminifStream.countstrm>=String.lengthsthenSome(sign,n)elseNoneletof_strings=assert(s<>"");letsign,u=matchs.[0]with|'-'->(SMinus,string_del_head1s)|'+'->(SPlus,string_del_head1s)|_->(SPlus,s)in(sign,Unsigned.of_stringu)letto_string(sign,u)=(matchsignwithSPlus->""|SMinus->"-")^Unsigned.to_stringuletto_bigint=function|(sign,{int=n;frac="";exp=""})->Some(SignedNat.to_bigint(sign,UnsignedNat.to_stringn))|_->Noneletof_bigintcn=of_int(SignedNat.of_bigintcn)letto_bigint_and_exponent(s,{int;frac;exp})=letc=UnsignedNat.classifyintinletint=UnsignedNat.to_stringintinletfrac=UnsignedNat.to_stringfracinleti=SignedNat.to_bigint(s,int^frac)inlete=lete=ifexp=""thenZ.zeroelsematchexp.[1]with|'+'->Z.of_string(UnsignedNat.to_string(string_del_head2exp))|'-'->Z.(neg(of_string(UnsignedNat.to_string(string_del_head2exp))))|_->Z.of_string(UnsignedNat.to_string(string_del_head1exp))inletl=String.lengthfracinletl=matchcwithCDec->l|CHex->4*linZ.(sube(of_intl))in(i,matchcwithCDec->EDece|CHex->EBine)letof_bigint_and_exponentie=letc=matchewithEDec_->CDec|EBin_->CHexinlete=matchewithEDece|EBine->Some(SignedNat.of_bigintCDece)inof_int_frac_and_exponent(SignedNat.of_bigintci)Noneeletis_bigger_int_than(s,{int;frac;exp})i=frac=""&&exp=""&&UnsignedNat.compareinti>0letclassify(_,n)=Unsigned.classifynend