project
project
Version 5.0
1 Introduction
In this project, you are required to implement an interpreter for the programming language SimPL (pronounced
simple). SimPL is a simplified dialect of ML, which can be used for both functional and imperative programming.
This specification presents a definition of SimPL and provides guidelines to help you implement the interpreter.
2 Lexical Definition
The lexical definition of SimPL consists of four aspects: comments, atoms, keywords, and operators.
2.1 Comments
• Comments in SimPL are enclosed by pairs of (* and *).
• Comments and whitespaces (spaces, tabs, newlines) should be ignored and not evaluated.
2.2 Atoms
• Atoms are either integer literals or identifiers.
• Integer literals are in decimal format, and leading zeros are insignificant, e.g. both 0123 and 000123 repre-
sent the integer 123.
2.3 Keywords
All the following identifiers are keywords. Related keywords are grouped in the same line for better readability.
Keywords cannot be bound to anything.
• nil
• ref
1
• fn rec
• let in end
• if then else
• while do
• true false
• not andalso orelse
2.4 Operators
• + - * / % ˜
• = <> < <= > >=
• :: () =>
• := !
• , ; ( )
3 Syntax
• All SimPL programs are expressions. Exp is the set of all expressions.
• Expressions, names, and integer literals are denoted by meta variables e, x, and n.
• Binary operator bop ∈ {+, -, *, /, %, =, <>, <, <=, >, >=, andalso, orelse, ::, :=, ;}
2
3.1 Operator Precedence
Priority Operator(s) Associativity
1 ; left
2 := none
3 orelse right
4 andalso right
5 = <> < <= > >= none
6 :: right
7 + - left
8 * / % left
9 (application) left
10 ~ not ! right
4 Typing
4.1 Definition
The set of all types Typ is the smallest set satisfying the following rules.
• ∀t 1 , t 2 ∈ Typ, t 1 × t 2 ∈ Typ
• ∀t 1 , t 2 ∈ Typ, t 1 → t 2 ∈ Typ
Type environment Γ : Var → Typ is a mapping from names to arbitrary types. The replacement of x with t in Γ,
i.e. Γ[x : t ], is defined as follows. (
t if x = y
Γ[x : t ](y) =
Γ(y) otherwise
Typing rules:
3
(T-N IL )
(T-I NT ) (T-T RUE ) Γ ⊢ nil : α list
Γ ⊢ n : int Γ ⊢ true : bool
Γ(x) = t (T-U NIT )
(T-N AME ) (T-FALSE ) Γ ⊢ () : unit
Γ⊢x :t Γ ⊢ false : bool Γ⊢e :t
Γ[x : t 1 ] ⊢ e : t 2 Γ ⊢ e : int
(T-F N ) (T-N EG ) Γ ⊢ (e ) : t
Γ ⊢ fn x => e : t 1 → t 2 Γ ⊢ ~e : int (T-G ROUP )
Γ[x : t ] ⊢ e : t Γ ⊢ e : bool
(T-R EC ) (T-N OT ) Γ ⊢ e 1 : uni t Γ ⊢ e 2 : t 2
Γ ⊢ rec x => e : t Γ ⊢ not e : bool (T-S EQ )
Γ ⊢ e 1 ;e 2 : t 2
Γ ⊢ e 1 : t1 Γ ⊢ e 2 : t2 Γ ⊢ e 1 : bool Γ ⊢ e 2 : bool
(T-PAIR ) (T-A ND A LSO )
Γ ⊢ (e 1 , e 2 ) : t 1 × t 2 Γ ⊢ e 1 andalso e 2 : bool
Γ ⊢ e 1 : t2 → t1 Γ ⊢ e 2 : t2 Γ ⊢ e 1 : bool Γ ⊢ e 2 : t Γ ⊢ e 3 : t
(T-A PP ) (T-C OND )
Γ ⊢ e 1 e 2 : t1 Γ ⊢ if e 1 then e 2 else e 3 : t
4.2 Polymorphism
There is no explicit type annotations in SimPL. So principal type inference is necessary.
4
(CT-I NT )
Γ ⊢ n : int, {} Γ ⊢ e 1 : t 1 , q 1 Γ ⊢ e 2 : t 2 , q 2 bop ∈ {+, -, *, /, %}
(CT-A RITH )
Γ ⊢ e 1 bop e 2 : int, q 1 ∪ q 2 ∪ {t 1 = i nt , t 2 = i nt }
Γ(x) = t
(CT-N AME )
Γ ⊢ x : t , {} Γ ⊢ e 1 : t 1 , q 1 Γ ⊢ e 2 : t 2 , q 2 bop ∈ {<, <=, >, >=}
(CT-R EL )
Γ ⊢ e 1 bop e 2 : bool, q 1 ∪ q 2 ∪ {t 1 = i nt , t 2 = i nt }
(CT-T RUE )
Γ ⊢ true : bool, {}
Γ, x : a ⊢ e : t , q
(CT-F N )
Γ ⊢ fn x : a => e : b : a → b, q ∪ {t = b}
(CT-FALSE )
Γ ⊢ false : bool, {}
2. Unification algorithm:
Γ ⊢ e 2 [e 1 /x] : t 2 Γ ⊢ e 1 : t 1
(T − Let Pol y)
Γ ⊢ let x = e 1 in e 2 end : t 2
Γ ⊢ e 2 [e 1 /x] : t 2 , q 1 Γ ⊢ e 1 : t 1
(C T − Let Pol y)
Γ ⊢ let x = e 1 in e 2 end : t 2 , q 1
5
5 Semantics
5.1 State
A state s ∈ State is a triple (E , M , p) where E ∈ Env is the environment, M ∈ Mem is the memory, and p ∈ N is the
memory pointer.
Both the environment and the memory are updateable mappings. Given an updateable mapping f : X → Y ,
the updated mapping f [x 7→ y], where x ∈ X , y ∈ Y , is defined as
(
′ y if x = x ′
f [x 7→ y](x ) =
f (x) otherwise.
Val consists of integers, booleans, lists, references, pairs, and functions. Rec is the set of recursions.
Vt
[
Val =
t ∈Typ
Vunit = {unit}
Vint = Z = {· · · , −3, −2, −1, 0, 1, 2, 3, · · · }
Vbool = B = {tt, ff}
∞
Vt list = Vt(ilist
)
[
i =0
Vt(0)
list = {nil}
Vt(ilist
+1)
= {cons} × Vt × Vt(ilist
)
Vt ref = {ref} × N
Vt1 ×t2 = {pair} × Vt1 × Vt2
Vt1 →t2 = Vt1 Vt2 ⊆ {fun} × Env × Var × Exp
Rec = {rec} × Env × Var × Exp
5.2 Rules
Judgement form: E , M , p; e ⇓ M ′ , p ′ ; v where E ∈ Env, M , M ′ ∈ Mem, p ∈ N, e ∈ Exp, v ∈ Val
6
n = N Jn K
(E-I NT )
E , M , p; n ⇓ M , p; n
E (x) = (rec, E 1 , x 1 , e 1 ) E 1 , M , p; rec x 1 => e 1 ⇓ M ′ , p ′ ; v
(E-N AME 1)
E , M , p; x ⇓ M ′ , p ′ ; v
E (x) = v
(E-N AME 2)
E , M , p; x ⇓ M , p; v
(E-T RUE )
E , M , p; true ⇓ M , p; tt
(E-FALSE )
E , M , p; false ⇓ M , p; ff
(E-N IL )
E , M , p; nil ⇓ M , p; nil
(E-U NIT )
E , M , p; () ⇓ M , p; unit
E , M , p; e ⇓ M , p; v
(E-G ROUP )
E , M , p; (e ) ⇓ M , p; v
E , M , p + 1; e ⇓ M ′′ , p ′ ; v M ′ = M ′′ [p 7→ v]
(E-R EF )
E , M , p; ref e ⇓ M ′ , p ′ ; (ref, p)
E , M , p; e 1 ⇓ M ′ , p ′ ; (ref, p 1 ) E , M ′ , p ′ ; e 2 ⇓ M ′′′ , p ′′ ; v M ′′ = M ′′′ [p 1 7→ v]
(E-A SSIGN )
E , M , p; e 1 := e 2 ⇓ M ′′ , p ′′ ; unit
E , M , p; e ⇓ M ′ , p ′ ; (ref, p 1 ) v = M ′ (p 1 )
(E-D EREF )
E , M , p; !e ⇓ M ′ , p ′ ; v
(E-F N )
E , M , p; fn x => e ⇓ M , p; (fun, E , x, e)
E [x 7→ (rec, E , x, e)], M , p; e ⇓ M ′ , p ′ ; v
(E-R EC )
E , M , p; rec x => e ⇓ M ′ , p ′ ; v
E , M , p; e 1 ⇓ M ′ , p ′ ; (fun, E 1 , x, e) E , M ′ , p ′ ; e 2 ⇓ M ′′ , p ′′ ; v 2 E 1 [x 7→ v 2 ], M ′′ , p ′′ ; e ⇓ M ′′′ , p ′′′ ; v
(E-A PP )
E , M , p; e 1 e 2 ⇓ M ′′′ , p ′′′ , v
E , M , p; e 1 ⇓ M ′ , p ′ ; v 1 E , M ′ , p ′ ; e 2 ⇓ M ′′ , p ′′ ; v 2
(E-PAIR )
E , M , p; (e 1 , e 2 ) ⇓ M ′′ , p ′′ ; (pair, v 1 , v 2 )
E , M , p; e 1 ⇓ M ′ , p ′ ; v 1 E , M ′ , p ′ ; e 2 ⇓ M ′′ , p ′′ ; v 2
(E-C ONS )
E , M , p; e 1 :: e 2 ⇓ M ′′ , p ′′ ; (cons, v 1 , v 2 )
7
E , M , p; e ⇓ M ′ , p ′ ; v v ′ = −v
(E-N EG )
E , M , p; ~e ⇓ M ′ , p ′ ; v ′
E , M , p; e 1 ⇓ M ′ , p ′ ; v 1 E , M ′ , p ′ ; e 2 ⇓ M ′′ , p ′′ ; v 2 v = v1 + v2
(E-A DD )
E , M , p; e 1 + e 2 ⇓ M ′′ , p ′′ ; v
E , M , p; e 1 ⇓ M ′ , p ′ ; v 1 E , M ′ , p ′ ; e 2 ⇓ M ′′ , p ′′ ; v 2 v = v1 − v2
(E-S UB )
E , M , p; e 1 - e 2 ⇓ M ′′ , p ′′ ; v
E , M , p; e 1 ⇓ M ′ , p ′ ; v 1 E , M ′ , p ′ ; e 2 ⇓ M ′′ , p ′′ ; v 2 v = v1 v2
(E-M UL )
E , M , p; e 1 * e 2 ⇓ M ′′ , p ′′ ; v
E , M , p; e 1 ⇓ M ′ , p ′ ; v 1 E , M ′ , p ′ ; e 2 ⇓ M ′′ , p ′′ ; v 2 v 2 ̸= 0 v = v 1 div v 2
(E-D IV )
E , M , p; e 1 / e 2 ⇓ M ′′ , p ′′ ; v
E , M , p; e 1 ⇓ M ′ , p ′ ; v 1 E , M ′ , p ′ ; e 2 ⇓ M ′′ , p ′′ ; v 2 v 2 ̸= 0 v = v 1 mod v 2
(E-M OD )
E , M , p; e 1 % e 2 ⇓ M ′′ , p ′′ ; v
E , M , p; e 1 ⇓ M ′ , p ′ ; v 1 E , M ′ , p ′ ; e 2 ⇓ M ′′ , p ′′ ; v 2 v1 < v2
(E-L ESS 1)
E , M , p; e 1 < e 2 ⇓ M ′′ , p ′′ ; tt
E , M , p; e 1 ⇓ M ′ , p ′ ; v 1 E , M ′ , p ′ ; e 2 ⇓ M ′′ , p ′′ ; v 2 v1 ≥ v2
(E-L ESS 2)
E , M , p; e 1 < e 2 ⇓ M ′′ , p ′′ ; ff
E , M , p; e 1 ⇓ M ′ , p ′ ; v 1 E , M ′ , p ′ ; e 2 ⇓ M ′′ , p ′′ ; v 2 v1 ≤ v2
(E-L ESS E Q 1)
E , M , p; e 1 <= e 2 ⇓ M ′′ , p ′′ ; tt
E , M , p; e 1 ⇓ M ′ , p ′ ; v 1 E , M ′ , p ′ ; e 2 ⇓ M ′′ , p ′′ ; v 2 v1 > v2
(E-L ESS E Q 2)
E , M , p; e 1 <= e 2 ⇓ M ′′ , p ′′ ; ff
E , M , p; e 1 ⇓ M ′ , p ′ ; v 1 E , M ′ , p ′ ; e 2 ⇓ M ′′ , p ′′ ; v 2 v1 > v2
(E-G REATER 1)
E , M , p; e 1 > e 2 ⇓ M ′′ , p ′′ ; tt
E , M , p; e 1 ⇓ M ′ , p ′ ; v 1 E , M ′ , p ′ ; e 2 ⇓ M ′′ , p ′′ ; v 2 v1 ≤ v2
(E-G REATER 2)
E , M , p; e 1 > e 2 ⇓ M ′′ , p ′′ ; ff
E , M , p; e 1 ⇓ M ′ , p ′ ; v 1 E , M ′ , p ′ ; e 2 ⇓ M ′′ , p ′′ ; v 2 v1 ≥ v2
(E-G REATER E Q 1)
E , M , p; e 1 >= e 2 ⇓ M ′′ , p ′′ ; tt
E , M , p; e 1 ⇓ M ′ , p ′ ; v 1 E , M ′ , p ′ ; e 2 ⇓ M ′′ , p ′′ ; v 2 v1 < v2
(E-G REATER E Q 2)
E , M , p; e 1 >= e 2 ⇓ M ′′ , p ′′ ; ff
E , M , p; e 1 ⇓ M ′ , p ′ ; v 1 E , M ′ , p ′ ; e 2 ⇓ M ′′ , p ′′ ; v 2 v1 = v2
(E-E Q 1)
E , M , p; e 1 = e 2 ⇓ M ′′ , p ′′ ; tt
E , M , p; e 1 ⇓ M ′ , p ′ ; v 1 E , M ′ , p ′ ; e 2 ⇓ M ′′ , p ′′ ; v 2 v 1 ̸= v 2
(E-E Q 2)
E , M , p; e 1 = e 2 ⇓ M ′′ , p ′′ ; ff
E , M , p; e 1 ⇓ M ′ , p ′ ; v 1 E , M ′ , p ′ ; e 2 ⇓ M ′′ , p ′′ ; v 2 v 1 ̸= v 2
(E-N EQ 1)
E , M , p; e 1 <> e 2 ⇓ M ′′ , p ′′ ; tt
E , M , p; e 1 ⇓ M ′ , p ′ ; v 1 E , M ′ , p ′ ; e 2 ⇓ M ′′ , p ′′ ; v 2 v1 = v2
(E-N EQ 2)
E , M , p; e 1 <> e 2 ⇓ M ′′ , p ′′ ; ff
8
E , M , p; e ⇓ M ′ , p ′ ; tt
(E-N OT 1)
E , M , p; not e ⇓ M ′ , p ′ ; ff
E , M , p; e ⇓ M ′ , p ′ ; ff
(E-N OT 2)
E , M , p; not e ⇓ M ′ , p ′ ; tt
E , M , p; e 1 ⇓ M ′ , p ′ ; tt E , M ′ , p ′ ; e 2 ⇓ M ′′ , p ′′ ; v
(E-A ND A LSO 1)
E , M , p; e 1 andalso e 2 ⇓ M ′′ , p ′′ ; v
E , M , p; e 1 ⇓ M ′ , p ′ ; ff
(E-A ND A LSO 2)
E , M , p; e 1 andalso e 2 ⇓ M ′ , p ′ ; ff
E , M , p; e 1 ⇓ M ′ , p ′ ; tt
(E-O R E LSE 1)
E , M , p; e 1 orelse e 2 ⇓ M ′ , p ′ ; tt
E , M , p; e 1 ⇓ M ′ , p ′ ; ff E , M ′ , p ′ ; e 2 ⇓ M ′′ , p ′′ ; v
(E-O R E LSE 2)
E , M , p; e 1 orelse e 2 ⇓ M ′′ , p ′′ ; v
E , M , p; e 1 ⇓ M ′ , p ′ ; v 1 E , M ′ , p ′ ; e 2 ⇓ M ′′ , p ′′ ; v 2
(E-S EQ )
E , M , p; e 1 ;e 2 ⇓ M ′′ , p ′′ ; v 2
E , M , p; e 1 ⇓ M ′ , p ′ ; v 1 E [x 7→ v 1 ], M ′ , p ′ ; e 2 ⇓ M ′′ , p ′′ ; v 2
(E-L ET )
E , M , p; let x = e 1 in e 2 end ⇓ M ′′ , p ′′ ; v 2
E , M , p; e 1 ⇓ M ′ , p ′ ; tt E , M ′ , p ′ ; e 2 ⇓ M ′′ , p ′′ ; v
(E-C OND 1)
E , M , p; if e 1 then e 2 else e 3 ⇓ M ′′ , p ′′ ; v
E , M , p; e 1 ⇓ M ′ , p ′ ; ff E , M ′ , p ′ ; e 3 ⇓ M ′′ , p ′′ ; v
(E-C OND 2)
E , M , p; if e 1 then e 2 else e 3 ⇓ M ′′ , p ′′ ; v
E , M , p; e 1 ⇓ M ′ , p ′ ; tt E , M ′ , p ′ ; e 2 ; while e 1 do e 2 ⇓ M ′′ , p ′′ ; v
(E-L OOP 1)
E , M , p; while e 1 do e 2 ⇓ M ′′ , p ′′ ; v
E , M , p; e 1 ⇓ M ′ , p ′ ; ff
(E-L OOP 2)
E , M , p; while e 1 do e 2 ⇓ M ′ , p ′ ; unit
• If a and d are integers, with d non-zero, then a remainder a mod d is an integer r such that a = qd + r for
some integer q, and with |r | < |d |. a div d = q is the quotient.
– ∀n ∈ Z, n = n
– tt = tt, ff = ff
– nil = nil
– (cons, h 1 , t 1 ) = (cons, h 2 , t 2 ) ⇐⇒ h 1 = h 2 ∧ t 1 = t 2
– (ref, p 1 ) = (ref, p 2 ) ⇐⇒ p 1 = p 2
– (pair, a 1 , b 1 ) = (pair, a 2 , b 2 ) ⇐⇒ a 1 = a 2 ∧ b 1 = b 2
– v 1 ̸= v 2 ⇐⇒ ¬(v 1 = v 2 )
9
6 Examples
1 let
2 sum = rec sum = >
3 fn a = > if a = nil
4 then 0
5 else hd a + sum ( tl a )
6 in
7 sum (1::2::3:: nil )
8 end
9 (* == > 6 *)
examples/sum.spl
10
7 Implementation
7.1 Command-line Interface
You are required to implement the SimPL interpreter in Java, and submit a runnable JAR file, say SimPL.jar. Your
interpreter should accept exactly one command-line argument, which is the path of the SimPL program, and then
read the program file for execution. Your interpreter should output the result of the execution to the standard
output (System.out).
• If the result is a pair, output pair@v 1 @v 2 where v i is i -th element of the pair.
• For any test program, your interpreter has up to 5 seconds to execute it.
• Your interpreter is started in a sandbox environment and can only read the current test program.
f st : t 1 × t 2 → t 1
snd : t 1 × t 2 → t 2
hd : t list → t
t l : t list → t list
f st (pair, v 1 , v 2 ) = v 1
snd (pair, v 1 , v 2 ) = v 2
hd (cons, v 1 , v 2 ) = v 1
t l (cons, v 1 , v 2 ) = v 2
hd (nil) = error
t l (nil) = error
fst, snd, hd, and tl are not keywords. They are predefined names in the topmost environment, work in the
same way as user-defined functions, and can be bound to other values.
11
8 Bonus
• Mutually recursive combinator
• Infinite streams
• Tail recursion
• Lazy evaluation
12