clojure:在一个简单的基于vm的堆栈中实现jmp

时间:2015-02-13 13:44:35

标签: clojure

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"通过这种方法?

1 个答案:

答案 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]))))

我只需要将所有指令和指针......以及所有内容传递给函数,并修改多方法。它看起来并不优雅,但它确实有效。