2020-05-12 09:33:33 -04:00
|
|
|
; We don't have atoms built in, mutable vectors
|
|
|
|
|
; are our base building block. In order to make the
|
|
|
|
|
; following BF implementation nice, let's add atoms!
|
|
|
|
|
; They will be implmented as length 1 vectors with nice syntax for deref
|
2020-05-12 00:40:36 -04:00
|
|
|
(def! make-atom (fn* (x) [x]))
|
|
|
|
|
(def! set-atom! (fn* (x y) (set-nth! x 0 y)))
|
|
|
|
|
(def! get-atom (fn* (x) (nth x 0)))
|
2020-05-12 09:33:33 -04:00
|
|
|
(add_grammer_rule 'form ["@" 'form] (fn* (_ x) `(get-atom ~x)))
|
2020-05-12 00:40:36 -04:00
|
|
|
|
2020-05-12 09:33:33 -04:00
|
|
|
; Now begin by defining our BF syntax & semantics
|
2020-05-10 21:33:47 -04:00
|
|
|
; Define our tokens as BF atoms
|
2020-05-12 09:33:33 -04:00
|
|
|
(add_grammer_rule 'bfs_atom ["<"] (fn* (_) '(set-atom! cursor (- @cursor 1))))
|
|
|
|
|
(add_grammer_rule 'bfs_atom [">"] (fn* (_) '(set-atom! cursor (+ @cursor 1))))
|
|
|
|
|
(add_grammer_rule 'bfs_atom ["\\+"] (fn* (_) '(set-nth! tape @cursor (+ (nth tape @cursor) 1))))
|
|
|
|
|
(add_grammer_rule 'bfs_atom ["-"] (fn* (_) '(set-nth! tape @cursor (- (nth tape @cursor) 1))))
|
|
|
|
|
(add_grammer_rule 'bfs_atom [","] (fn* (_) '(let* (value (nth input @inptr)) (do (set-atom! inptr (+ 1 @inptr)) (do (set-nth! tape @cursor value))))))
|
|
|
|
|
(add_grammer_rule 'bfs_atom ["."] (fn* (_) '(set-atom! output (cons (nth tape @cursor) @output))))
|
2020-05-10 21:33:47 -04:00
|
|
|
|
|
|
|
|
; Define strings of BF atoms
|
2020-05-12 09:33:33 -04:00
|
|
|
(add_grammer_rule 'bfs ['bfs_atom *] (fn* (x) x))
|
2020-05-10 21:33:47 -04:00
|
|
|
|
|
|
|
|
; Add loop as an atom
|
2020-05-12 09:33:33 -04:00
|
|
|
; (note that closure cannot yet close over itself by value, so we pass it in)
|
|
|
|
|
(add_grammer_rule 'bfs_atom ["\\[" 'bfs "]"] (fn* (_ x _)
|
2020-05-10 21:33:47 -04:00
|
|
|
`(let* (f (fn* (f)
|
2020-05-12 09:19:01 -04:00
|
|
|
(if (= 0 (nth tape @cursor))
|
2020-05-10 21:33:47 -04:00
|
|
|
nil
|
2020-05-12 09:33:33 -04:00
|
|
|
(do ,x (f f)))))
|
2020-05-10 21:33:47 -04:00
|
|
|
(f f))))
|
|
|
|
|
|
|
|
|
|
; For now, stick BFS rule inside an unambigious BFS block
|
2020-05-12 09:33:33 -04:00
|
|
|
; Also add setup code
|
2020-05-10 21:33:47 -04:00
|
|
|
(add_grammer_rule 'form ["bf" 'optional_WS "{" 'optional_WS 'bfs 'optional_WS "}"]
|
2020-05-12 09:33:33 -04:00
|
|
|
(fn* (_ _ _ _ x _ _)
|
2020-05-10 21:33:47 -04:00
|
|
|
`(fn* (input)
|
|
|
|
|
(let* (
|
|
|
|
|
tape (vector 0 0 0 0 0)
|
2020-05-12 00:40:36 -04:00
|
|
|
cursor (make-atom 0)
|
|
|
|
|
inptr (make-atom 0)
|
|
|
|
|
output (make-atom (vector))
|
2020-05-10 21:33:47 -04:00
|
|
|
)
|
2020-05-12 09:33:33 -04:00
|
|
|
(do (println "beginning bfs") ,x (nth output 0))))))
|
2020-05-10 21:33:47 -04:00
|
|
|
|
|
|
|
|
; Let's try it out! This BF program prints the input 3 times
|
2020-05-12 00:32:12 -04:00
|
|
|
(println (bf { ,>+++[<.>-] } [1337]))
|
|
|
|
|
; we can also have it compile into our main program
|
|
|
|
|
(def! main (fn* () (do (println "BF: " (bf { ,>+++[<.>-] } [1337])) 0)))
|