let rec                                                       -- Semantic Types
    type Locn == Int

and type Sv = SvInt Int + SvBool Bool               -- Storable Values
and type Ev = EvInt Int + EvBool Bool + EvLocn Locn -- Expressible Values
and type Dv = DvLocn Locn                           -- Denotable Values
and type Bv = BvInt Int + BvBool Bool               -- Basic Values

and type Store == Locn -> Sv
and type State = st Store Int (List Bv) -- Store, Locn counter, Answer

and type Env == Ide -> Dv

in let                                                      -- utility routines
    update f x v y = if x=y then v else f y

and SvtoEv (SvInt n)  = EvInt n

and EvtoSv (EvInt n)  = SvInt n  || EvtoSv (EvBool b)  = SvBool b
and EvtoDv (EvLocn l) = DvLocn l
and EvtoBv (EvInt n)  = BvInt n  || EvtoBv (EvBool b)  = BvBool b

and DvtoEv (DvLocn l) = EvLocn l

and rec
    show [] = [] ||
    show (BvInt n  . t) = itos n @ " " @ show t  ||
    show (BvBool b . t) = (if b then "T" else "F") @ " " @ show t

in let rec                                                                 -- C
    C (Cmds g1 g2)    env s = C g2 env (C g1 env s)  ||

    C (Assign e1 e2)  env s =
       let EvLocn l, s2 = L e1 env s
       in  let v, st s f a = R e2 env s2
           in  st (update s l (EvtoSv v)) f a  ||

    C (IfCmd be gt gf) env s = let EvBool v, s2 = R be env s
                               in  C (if v then gt else gf) env s2  ||

    C (WhileCmd be g)  env s = let EvBool v, s2 = R be env s
                               in if v then C (WhileCmd be g) env (C g env s2)
                                          else s2  ||

    C (Block d g)     env s = uncurry (C g) (D d env s)  ||

    C (Write e)       env s = let v, st s f a = R e env s
                              in  st s f (a @ [EvtoBv v])


and E (Ident x) env s = DvtoEv(env x), s  ||                               -- E

    E (Num n)   env s = EvInt n, s ||

    E (UExp op e) env s = let v, s2 = R e env s
                          in  U op v, s2  ||

    E (BExp op e1 e2) env s =
       let v1, s2 = R e1 env s
       in  let v2, s3 = R e2 env s2
           in  O op v1 v2, s3


and L e env s = let EvLocn l, s2 = E e env s                               -- L
                in  EvLocn l, s2

and R e env s = case E e env s in                                          -- R
                EvLocn l, st s f a: SvtoEv(s l), st s f a ||
                v, s2             : v, s2
                end


and D (VarDec x) env (st s f a) = update env x (DvLocn f), st s (f+1) a  ||-- D

    D (Decs d1 d2) env s = uncurry (D d2) (D d1 env s)


and U plusSy  (EvInt n) = EvInt n    ||                                    -- U
    U minusSy (EvInt n) = EvInt(-n)  ||
    U not     (EvBool true) = EvBool false    ||
    U not     (EvBool false) = EvBool true


and O plusSy  (EvInt n1) (EvInt n2) = EvInt (n1+n2)  ||                    -- O
    O minusSy (EvInt n1) (EvInt n2) = EvInt (n1-n2)  ||
    O timesSy (EvInt n1) (EvInt n2) = EvInt (n1*n2)  ||
    O divSy   (EvInt n1) (EvInt n2) = EvInt (n1/n2)  ||

    O eqSy    v1 v2 = EvBool(v1=v2)  ||
    O neSy    v1 v2 = EvBool(v1~=v2) ||
    O gtSy    (EvInt n1) (EvInt n2) = EvBool (n1 >  n2)  ||
    O geSy    (EvInt n1) (EvInt n2) = EvBool (n1 >= n2)  ||
    O ltSy    (EvInt n1) (EvInt n2) = EvBool (n1 <  n2)  ||
    O leSy    (EvInt n1) (EvInt n2) = EvBool (n1 <= n2)  ||

    O andSy   (EvBool b1) (EvBool b2) = EvBool (b1 & b2) ||
    O orSy    (EvBool b1) (EvBool b2) = EvBool (b1 | b2)


--\fB Direct Semantics in LML. \fP
-- L.Allison, Department of Computer Science, Monash University, Australia
