clojure新手,我目前正在clojure中实现一个简单的基于堆栈的vm,只是为了练习和乐趣。
我试图尽可能地发挥作用。我构造了以下代码:
(defmulti execute-byte (fn [stack b] b))
(defmethod execute-byte 0x00 [stack _] ;; nop
stack)
(defmethod execute-byte 0x01 [stack _] ;; unimplemented
())
(defmethod execute-byte 0x02 [stack _] ;; del
(rest stack))
(defmethod execute-byte 0x03 [stack _] ;; jmp, honestly I don't know how to implement this
())
(defmethod execute-byte 0x10 [stack _] ;; add
(let [f (first stack)
s (second stack)]
(cons (+ f s) (nthrest stack 2))))
(defmethod execute-byte 0x11 [stack _] ;; sub
(let [f (first stack)
s (second stack)]
(cons (- f s) (nthrest stack 2))))
(defmethod execute-byte 0x12 [stack _] ;; multi
(let [f (first stack)
s (second stack)]
(cons (* f s) (nthrest stack 2))))
(defmethod execute-byte 0x13 [stack _] ;; div
(let [f (first stack)
s (second stack)]
(cons (/ f s) (nthrest stack 2))))
(defmethod execute-byte :default [stack bc] ;; just a testing workaround
(cons bc stack))
(defn execute-single-stack-step
[[inst stack]]
[(rest inst) (execute-byte stack (first inst))])
(defn execute-bytes
[inst stack step]
(last (take step (iterate execute-single-stack-step [inst stack]))))
它有点工作。 "有点"因为它目前仅作为反向抛光表示法计算器
(execute-bytes [0x50 0x50 0x10] [] 4) ;; equivalent to [0x50 0x50 +] and gets [() (160)] as a result
我希望vm至少能够执行" jmp",读取从堆栈中弹出的值并移动"光标"价值所指的地方,但我目前的设计似乎不可能。 (目前的设计功能只有"减少",并且根本没有这样的"光标"。
为了更好地表示我使用的方法
(execute-bytes [0x50 0x50 0x10] [] 1)
;;[[80 80 16] []]
(execute-bytes [0x50 0x50 0x10] [] 2)
;;[(80 16) (80)]
(execute-bytes [0x50 0x50 0x10] [] 3)
;;[(16) (80 80)]
(execute-bytes [0x50 0x50 0x10] [] 4)
;;[() (160)]
所以我有什么方法可以实现" jmp"通过这种方法?
答案 0 :(得分:1)
我设法让它发挥作用。
为了演示结果:
lunadial.logic> (execute-bytes [0x01 0x10 0x01 0x10 0x10 0x03 0x00] [] 1) ;; push 0x10 push 0x10 add jump 0x00
[[] [1 16 1 16 16 3 0] 0]
lunadial.logic> (execute-bytes [0x01 0x10 0x01 0x10 0x10 0x03 0x00] [] 2)
[(16) [1 16 1 16 16 3 0] 2]
lunadial.logic> (execute-bytes [0x01 0x10 0x01 0x10 0x10 0x03 0x00] [] 3)
[(16 16) [1 16 1 16 16 3 0] 4]
lunadial.logic> (execute-bytes [0x01 0x10 0x01 0x10 0x10 0x03 0x00] [] 4)
[(32) [1 16 1 16 16 3 0] 5]
lunadial.logic> (execute-bytes [0x01 0x10 0x01 0x10 0x10 0x03 0x00] [] 5)
[(32) [1 16 1 16 16 3 0] 0]
lunadial.logic> (execute-bytes [0x01 0x10 0x01 0x10 0x10 0x03 0x00] [] 6)
[(16 32) [1 16 1 16 16 3 0] 2]
lunadial.logic> (execute-bytes [0x01 0x10 0x01 0x10 0x10 0x03 0x00] [] 7)
[(16 16 32) [1 16 1 16 16 3 0] 4]
lunadial.logic> (execute-bytes [0x01 0x10 0x01 0x10 0x10 0x03 0x00] [] 8)
[(32 32) [1 16 1 16 16 3 0] 5]
lunadial.logic> (execute-bytes [0x01 0x10 0x01 0x10 0x10 0x03 0x00] [] 9)
[(32 32) [1 16 1 16 16 3 0] 0]
lunadial.logic> (execute-bytes [0x01 0x10 0x01 0x10 0x10 0x03 0x00] [] 10)
[(16 32 32) [1 16 1 16 16 3 0] 2]
和代码:
(defmulti execute-byte (fn [stack inst point] (nth inst point)))
(defmethod execute-byte 0x00 [stack inst point] ;; nop
[stack inst (inc point)])
(defmethod execute-byte 0x01 [stack inst point] ;; push
(let [the-bc-after (nth inst (inc point))]
[(cons the-bc-after stack) inst (inc (inc point))]))
(defmethod execute-byte 0x02 [stack inst point] ;; del
[(rest stack) inst (inc point)])
(defmethod execute-byte 0x03 [stack inst point] ;; jmp
(let [the-bc-after (nth inst (inc point))]
[stack inst the-bc-after]))
(defmethod execute-byte 0x10 [stack inst point] ;; add
(let [f (first stack)
s (second stack)]
[(cons (+ f s) (nthrest stack 2)) inst (inc point)]))
(defmethod execute-byte 0x11 [stack inst point] ;; sub
(let [f (first stack)
s (second stack)]
[(cons (- f s) (nthrest stack 2)) inst (inc point)]))
(defmethod execute-byte 0x12 [stack inst point] ;; multi
(let [f (first stack)
s (second stack)]
[(cons (* f s) (nthrest stack 2)) inst (inc point)]))
(defmethod execute-byte 0x13 [stack inst point] ;; div
(let [f (first stack)
s (second stack)]
[(cons (/ f s) (nthrest stack 2)) inst (inc point)]))
(defmethod execute-byte :default [stack inst point] ;; just a testing workaround
[(cons (nth inst point) stack) inst (inc point)])
(defn execute-single-stack-step ;; the iterator wrapper for the multimethod
[[stack inst point]]
(execute-byte stack inst point))
(defn execute-bytes
[inst stack step]
(last (take step (iterate execute-single-stack-step [stack inst 0]))))
我只需要将所有指令和指针......以及所有内容传递给函数,并修改多方法。它看起来并不优雅,但它确实有效。