@@ -60,9 +60,63 @@ fun fromLabel (env, lab) {
6060-- Stack machine interpreter. Takes an environment, an SM-configuration and a program,
6161-- returns a final configuration
6262fun eval (env, c, insns) {
63- failure ("SM eval not implemented\n")
63+ let impl = fix (fun (rec) {
64+ fun ([c, insns]) {
65+ case insns of
66+ {} -> c
67+ | i : tl ->
68+ let [c, next] = evalInsn (c, i) in
69+ let insnsNext = case next of
70+ Some (label) -> fromLabel (env, label)
71+ | _ -> tl
72+ esac in rec ([c, insnsNext])
73+ esac
74+ }
75+ }) in impl ([c, insns])
6476}
6577
78+ fun evalInsn (c@[stack, state, world], insn) {
79+ fun noJmp (c) {
80+ [c, None]
81+ }
82+
83+ fun jmp (c, label) {
84+ [c, Some (label)]
85+ }
86+
87+ case insn of
88+ READ -> let [v, w] = world.readWorld in
89+ [v : stack, state, w].noJmp
90+ | WRITE -> let v : rest = stack in
91+ [rest, state, v.writeWorld(world)].noJmp
92+ | BINOP(s) -> let r : rest = stack in
93+ let l : rest = rest in
94+ let v = evalOp(s, l, r) in
95+ [v : rest, state, world].noJmp
96+ | LD(x) -> let v = x.state in
97+ [v : stack, state, world].noJmp
98+ | LDA(x) -> [Ref (x) : stack, state, world].noJmp
99+ | ST(x) -> let v : _ = stack in
100+ [stack, state <- [x, v], world].noJmp
101+ | STI -> let v : Ref(x) : rest = stack in
102+ [v : rest, state <- [x, v], world].noJmp
103+ | CONST(n) -> [n : stack, state, world].noJmp
104+ | LABEL(l) -> c.noJmp
105+ | JMP(l) -> c.jmp (l)
106+ | CJMP(cnd, l) ->
107+ let v : rest = stack in
108+ let nc = [rest, state, world] in
109+ case cnd of
110+ "z" -> if v == 0 then nc.jmp (l) else nc.noJmp fi
111+ | "nz" -> if v != 0 then nc.jmp (l) else nc.noJmp fi
112+ | _ -> failure ("Unknown condition %s\n", cnd.string)
113+ esac
114+ | DROP -> let _ : rest = stack in [rest, state, world].noJmp
115+ | _ -> failure ("Unknown instruction %s\n", insn.string)
116+ esac
117+ }
118+
119+
66120-- Runs a stack machine for a given input and a given program, returns an output
67121public fun evalSM (input, insns) {
68122 eval (initEvalEnv (insns), [{}, emptyState, createWorld (input)], insns)[2].getOutput
@@ -111,11 +165,72 @@ public fun compileSM (stmt) {
111165
112166 fun compile (lab, env, stmt) {
113167 case stmt of
114- Skip -> [false, env, emptyBuffer ()]
115- | Var (x) -> [false, env, singletonBuffer (LD (x))]
116- | Ref (x) -> [false, env, singletonBuffer (LDA (x))]
117- | Const (n) -> [false, env, singletonBuffer (CONST (n))]
118- | _ -> failure ("compileSM not implemented\n")
168+ Skip -> [false, env, emptyBuffer ()]
169+ | Var (x) -> [false, env, singletonBuffer (LD (x))]
170+ | Ref (x) -> [false, env, singletonBuffer (LDA (x))]
171+ | Const (n) -> [false, env, singletonBuffer (CONST (n))]
172+ | Seq (s1, s2) ->
173+ let [s2Lab, env] = env.genLabel in
174+ let [s2LabUsed, env, s1Code] = compile (s2Lab, env, s1) in
175+ let [labUsed, env, s2Code] = compile (lab, env, s2) in
176+ [labUsed, env, s1Code <+> label (s2Lab, s2LabUsed) <+> s2Code]
177+ | If (c, t, e) ->
178+ let [cLab, env] = env.genLabel in
179+ let [cLabUsed, env, cCode] = compile (cLab, env, c) in
180+ let [_, env, tCode] = compile (lab, env, t) in
181+ let [_, env, eCode] = compile (lab, env, e) in
182+ let [eLab, env] = env.genLabel in
183+ let code = cCode <+> label (cLab, cLabUsed) <+
184+ CJMP("z", eLab) <+> tCode <+ JMP (lab) <+
185+ LABEL (eLab) <+> eCode in
186+ [true, env, code]
187+ | While (c, b) ->
188+ let [cLab, sLab, env] = env.genLabels (2) in
189+ let [cLabUsed, env, cCode] = compile (cLab, env, c) in
190+ let [_, env, bCode] = compile (sLab, env, b) in
191+ let code = singletonBuffer (LABEL (sLab)) <+> cCode <+>
192+ label (cLab, cLabUsed) <+ CJMP("z", lab) <+>
193+ bCode <+ JMP (sLab) in
194+ [true, env, code]
195+ | DoWhile (b, c) ->
196+ let [cLab, sLab, eLab, env] = env.genLabels (3) in
197+ let [eLabUsed, env, cCode] = compile (eLab, env, c) in
198+ let [cLabUsed, env, bCode ] = compile (cLab, env, b) in
199+ let code = singletonBuffer (LABEL (sLab)) <+> bCode <+>
200+ label (cLab, cLabUsed) <+> cCode <+>
201+ label (eLab, eLabUsed) <+ CJMP("nz", sLab) in
202+ [false, env, code]
203+ | Read (e) ->
204+ let [eLab, env] = env.genLabel in
205+ let [eLabUsed, env, eCode] = compile (eLab, env, e) in
206+ let code = eCode <+> label (eLab, eLabUsed) <+ READ <+ STI <+ DROP in
207+ [false, env, code]
208+ | Write (e) ->
209+ let [eLab, env] = env.genLabel in
210+ let [eLabUsed, env, eCode] = compile (eLab, env, e) in
211+ let code = eCode <+> label (eLab, eLabUsed) <+ WRITE in
212+ [false, env, code]
213+ | Ignore (e) ->
214+ let [eLab, env] = env.genLabel in
215+ let [eLabUsed, env, eCode] = compile (eLab, env, e) in
216+ [false, env, eCode <+> label (eLab, eLabUsed) <+ DROP]
217+ | Assn (l, r) ->
218+ let [lLab, rLab, env] = env.genLabels (2) in
219+ let [rLabUsed, env, rCode] = compile (rLab, env, r) in
220+ let [lLabUsed, env, lCode] = compile (lLab, env, l) in
221+ let code = lCode <+> label (lLab, lLabUsed) <+>
222+ rCode <+> label (rLab, rLabUsed) <+
223+ STI in
224+ [false, env, code]
225+ | Binop (op, l, r) ->
226+ let [lLab, rLab, env] = env.genLabels (2) in
227+ let [rLabUsed, env, rCode] = compile (rLab, env, r) in
228+ let [lLabUsed, env, lCode] = compile (lLab, env, l) in
229+ let code = lCode <+> label (lLab, lLabUsed) <+>
230+ rCode <+> label (rLab, rLabUsed) <+
231+ BINOP (op) in
232+ [false, env, code]
233+ | _ -> failure ("Unexpected expression %s\n", stmt.string)
119234 esac
120235 }
121236
0 commit comments