I'm working on modernizing Rosetta Code's infrastructure. Starting with communications. Please accept this time-limited open invite to RC's Slack.. --Michael Mol (talk) 20:59, 30 May 2020 (UTC)

Execute Brain****/Clojure

From Rosetta Code
Execute Brain****/Clojure is an implementation of Brainf***. Other implementations of Brainf***.
Execute Brain****/Clojure is part of RCBF. You may find other members of RCBF at Category:RCBF.

This is a brainfuck interpreter in Clojure which completely refrains from mutating any state. The nature of Clojure (namely, that hashes and sets are functions) facilitates a rather clean loop/recur approach. At each iteration, the components of the execution model (the program counter, byte pointer, and tape) are "redefined" as the application of some function (informed by the current instruction) to their previous value.

(defn pair-brackets [indexed]
"indexed is a sequence of 2-tuples of the form [index instruction].
This is reduced into a hash of indices that is used to inform jumps."

(fn [pairs cur]
(condp = (cur 1)
\[ (merge-with conj pairs {:pend (cur 0)}) ; new pending open bracket
\] (merge pairs
{(first (pairs :pend)) (cur 0) ; store both
(cur 0) (first (pairs :pend)) ; directions
 :pend (pop (pairs :pend))}) ; no longer pending
{:pend ()} indexed))
(defn brainfuck [insns]
[valid (set "[]<>-+.,")
program (vec (keep #(valid %) insns)) ; sets are functions of their values
jumps (pair-brackets
(map vector (range) program))]
[pc 0 ; program counter
bp 0 ; byte pointer
tape {}]
(if (< pc (count program))
(let [insn (program pc)
cur (tape bp 0)]
(if (= \. insn)
(print (char cur)))
; program counter
((cond ; use jumps hash as the function if applicable, otherwise inc
(and (= \[ insn) (= 0 cur)) jumps
(and (= \] insn) (not= 0 cur)) jumps
 :else inc) pc)
; byte pointer
(({\< dec \> inc} insn identity) bp) ; function hash with fallback
; tape
(#{\- \+} insn)
(merge tape {bp (({\- dec \+ inc} insn) cur)})
(= \, insn)
(merge tape {bp (. System/in read)})
 :else tape)))))))
(-> *command-line-args*
last slurp brainfuck)
$ echo "(> fvzcyr rnfl)" | lein exec bf.clj rot13.bf
(> simple easy)