123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116moduleCP=Character.Make(Unit)(* No state needed. *)(Int)(* The parser returns a number. *)(String)(* The possible semantic error. *)openCPletwhitespace:intt=skip_zero_or_more(char' ')typeaddop=Plus|Minustypemulop=Times|Divideletoperator(c:char)(op:'a):'at=map(fun_->op)(charc)letaddop:addopt=(* Parse an addition operator. *)let*op=operator'+'Plus</>operator'-'Minusinlet*_=whitespacein(* strip whitespace *)returnopletmulop:mulopt=(* Parse a multiplication operator. *)let*op=operator'*'Times</>operator'/'Divideinlet*_=whitespacein(* strip whitespace *)returnopletnumber:intt=(* Parse one number. *)let*v=one_or_more_fold_left(fund->returnd)(funvd->10*v+d|>return)digitinlet*_=whitespacein(* strip whitespace *)returnvletparenthesized(p:unit->'at):'at=let*_=char'('inlet*_=whitespaceinlet*x=p()inlet*_=char')'inlet*_=whitespaceinreturnxletrecexpr():intt=(* Parse a sum [a + b - c ...]. *)one_or_more_separatedreturn(funsopx->matchopwith|Plus->s+x|>return|Minus->s-x|>return)(product())addopandatomic():intt=number</>parenthesizedexprandfactors(opnd1:int):intt=(* Parse the factors of a product. *)(let*op=mulopinlet*opnd2=atomic()inmatchopwith|Times->factors(opnd1*opnd2)|Divide->ifopnd2=0thenfail"division by zero"elsefactors(opnd1/opnd2))</>returnopnd1andproduct():intt=(* Parse a product [f1 * f2 / f3 ...]. *)let*n=atomic()infactorsnletcalculator:Parser.t=make()(expr())let%test_=letp=Parser.run_on_string"(1 + 2) * 6 / 2 -1"calculatorinParser.has_succeededp&&Parser.finalp=8let%test_=letp=Parser.run_on_string"1 / 0"calculatorinParser.has_failed_semanticp