-
Notifications
You must be signed in to change notification settings - Fork 1
/
Copy pathbrainfuck.clj
59 lines (49 loc) · 1.28 KB
/
brainfuck.clj
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
(ns brainfuck
(:refer-clojure :exclude [eval])
(:require [instaparse.core :as insta]))
;; eval
(defmulti eval (fn [_ cmd] cmd))
(defmethod eval "+"
[{:keys [pos] :as state} _]
(update-in state [:stack pos] inc))
(defmethod eval "-"
[{:keys [pos] :as state} _]
(update-in state [:stack pos] dec))
(defmethod eval ">"
[{:keys [pos stack]} _]
{:pos (inc pos)
:stack (if (= (inc pos) (count stack))
(conj stack 0)
stack)})
(defmethod eval "<"
[{:keys [pos] :as state} _]
(let [new-pos (dec pos)]
(if (neg? new-pos)
(update-in state [:stack] into [0])
(assoc state :pos new-pos))))
(defmethod eval "."
[{:keys [pos] :as state} _]
(-> (get-in state [:stack pos])
char
print)
state)
(defmethod eval ","
[{:keys [pos] :as state} _]
(->> (read-line)
first
(assoc-in state [:stack pos])))
(defmethod eval :default
[state [_ & seq]]
(loop [{:keys [pos] :as state} state]
(if (zero? (get-in state [:stack pos]))
state
(recur (reduce eval state seq)))))
;; parse
(def p (insta/parser "brainfuck.bnf"))
(defn -main [s]
(let [result (p s)]
(if (insta/failure? result)
(print (insta/get-failure result))
(reduce eval {:stack [0]
:pos 0}
result))))