123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124(**********************************************************************)(* *)(* LASCAr *)(* *)(* Copyright (c) 2017-present, Jocelyn SEROT. All rights reserved. *)(* *)(* This source code is licensed under the license found in the *)(* LICENSE file in the root directory of this source tree. *)(* *)(**********************************************************************)typeident=stringtypevalue=inttypet=EConstofvalue(** Constants *)|EVarofident(** Input, output or local variable *)|EBinopofstring*t*t(** Binary operation *)typeenv=(ident*valueoption)listexceptionUnknownofidentexceptionUnboundofidentexceptionIllegal_exprletlookupenvid=trymatchList.associdenvwithSomev->v|None->raise(Unboundid)withNot_found->raise(Unknownid)letbinary_ops=["+",(+);"-",(-);"*",(*);"/",(/);]lettest_ops=[(* TO FIX : should only be in [Fsm], not here, but this complicates the lexer defns *)"=",(=);"!=",(<>);"<",(<);">",(>);"<=",(<=);">=",(>=)]letbinary_opop=tryList.assocopbinary_opswithNot_found->raise(Unknownop)letrecevalenvexp=matchexpwithEConstv->v|EVarid->lookupenvid|EBinop(op,exp1,exp2)->binary_opop(evalenvexp1)(evalenvexp2)(* let subst_vars vars exp =
* let rec subst e = match e with
* EConst _ -> e
* | EVar v -> if List.mem_assoc v vars then EConst (List.assoc v vars) else e
* | EBinop (op, exp1, exp2) -> EBinop (op, subst exp1, subst exp2) in
* subst exp *)(* Parsing *)(* BNF :
<exp> ::= INT
| ID
| <exp> <op> <exp>
| '(' <exp> ')' <int>
<op> ::= '+' | '-' | '*' | '/'
*)letkeywords=List.mapfstbinary_ops@List.mapfsttest_ops@[":=";"(";")";";"]letmk_binary_minuss=s|>String.split_on_char'-'|>String.concat" - "letlexers=s|>mk_binary_minus|>Stream.of_string|>Genlex.make_lexerkeywordsopenGenlexletrecp_exp0s=matchStream.nextswith|Intn->EConstn|Identi->EVari|Kwd"("->lete=p_expsinbeginmatchStream.peekswith|Some(Kwd")")->Stream.junks;e|_->raiseStream.Failureend|_->raiseStream.Failureandp_exp1s=lete1=p_exp0sinp_exp2e1sandp_exp2e1s=matchStream.peekswith|Some(Kwd"*")->Stream.junks;lete2=p_exp1sinEBinop("*",e1,e2)|Some(Kwd"/")->Stream.junks;lete2=p_exp1sinEBinop("/",e1,e2)|_->e1andp_exps=lete1=p_exp1sinp_exp3e1sandp_exp3e1s=matchStream.peekswith|Some(Kwd"+")->Stream.junks;lete2=p_expsinEBinop("+",e1,e2)|Some(Kwd"-")->Stream.junks;lete2=p_expsinEBinop("-",e1,e2)|_->e1letparse=p_expletof_strings=s|>lexer|>p_expletrecto_stringe=matchewithEConstc->string_of_intc|EVarn->n|EBinop(op,e1,e2)->to_stringe1^op^to_stringe2(* TODO : add parens *)