Repository navigation
Expand file tree
/
Copy pathbrainfuck.lisp
More file actions
169 lines (134 loc) · 4.3 KB
/
Copy pathbrainfuck.lisp
File metadata and controls
169 lines (134 loc) · 4.3 KB
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
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
;; brainfuck.lisp - Brainfuck interpreter in slisp
;;
;; This is slow. This is terrible. This works.
;;
;; Usage:
;;
;; ./brainfuck [path/to/program.bf]
;;
;; If no program is supplied the default one is executed
;; (which is the "hello world" program).
;;
;;; utility
(defun string-to-list (s)
"Split the given string into a list of characters.
We use this because while our compiler has 'implode' it will return a list of
CHARACTERS and our interpreter doesn't understand character types."
(if (= (strlen s) 0)
nil
(cons
(substr s 0 1)
(string-to-list (substr s 1 (- (strlen s) 1))))))
(defun program-length (xs)
"We have a custom function here because our interpreter doesn't have a
(length str|lst) implementation in its standard library."
(if (nil? xs)
0
(+ 1 (program-length (cdr xs)))))
;;; Brainfuck loop finding
(defun buildJumps (program)
(let ((table (makeCells (program-length program))))
(buildJumpsRec program 0 nil table)
table))
(defun buildJumpsRec (program pos stack table)
(if (= pos (program-length program))
table
(let ((ch (nth program pos)))
(cond
((= ch "[")
(buildJumpsRec
program
(+ pos 1)
(cons pos stack)
table))
((= ch "]")
(let ((open (car stack)))
;; store both directions
(nth! table open pos)
(nth! table pos open)
(buildJumpsRec
program
(+ pos 1)
(cdr stack)
table)))
(t
(buildJumpsRec
program
(+ pos 1)
stack
table))))))
;;; Interpreter
(defun run (program)
(let ((i 0) ; offset into program
(len (program-length program)) ; length of program
(ptr 0) ; PTR value
(cells (makeCells 300)) ; cells.
(jumps (buildJumps program))) ; jumps
; while we've not run off the end of the program
(while (< i len)
; get the next instruction
(let ((ins (nth program i)))
; handle it
(cond
;; +
((= ins "+")
(let ((v (nth cells ptr)))
(nth! cells ptr (% (+ v 1) 256)))
(set! i (+ i 1)))
;; -
((= ins "-")
(let ((v (nth cells ptr)))
(nth! cells ptr (% (- v 1) 256)))
(set! i (+ i 1)))
;; >
((= ins ">")
(set! ptr (+ ptr 1))
(set! i (+ i 1)))
;; <
((= ins "<")
(set! ptr (- ptr 1))
(set! i (+ i 1)))
;; [
((= ins "[")
(if (= (nth cells ptr) 0)
(set! i (+ (nth jumps i) 1))
(set! i (+ i 1))))
;; ]
((= ins "]")
(if (= (nth cells ptr) 0)
(set! i (+ i 1))
(set! i (+ (nth jumps i) 1))))
;; ,
((= ins ".")
(print (chr (nth cells ptr)))
(set! i (+ i 1)))
;; ,
((= ins ",")
(let ((c (getc)))
(if (<= c 0)
(exit 0))
(nth! cells ptr c)
(set! i (+ i 1))))
;; skip over unknown instructions
(t (set! i (+ i 1))))))))
;; Create ranges of numbers in a list
(defun makeCells (count)
(if (> count 0)
(cons 0 (makeCells (- count 1)))
nil))
;; Entry-point
(defun main (args)
(let ((program "++++++++[>++++[>++>+++>+++>+<<<<-]>+>+>->>+[<]<-]>>.>---.+++++++..+++.>>.<-.<.+++.------.--------.>>+.>++."))
; If we got an argument.
(if (= (length args) 2)
(do
(let ((handle (fopen (car (cdr args)) "r")) ; open
(data (fread handle)) ; read
(discard (fclose handle))) ; close
(if data
(set! program data)
(do
(print "failed to read file ")
(println (car (cdr args)))
(exit 1))))))
(run (string-to-list program))))