-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathcgbfi2.bf
More file actions
399 lines (343 loc) · 14.4 KB
/
cgbfi2.bf
File metadata and controls
399 lines (343 loc) · 14.4 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
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
Brainfuck Self Interpreter: by Clive Gifford
Version 1: 01 December 2006 (one trip between code and data per op)
Version 2: 16 December 2006 (virtual codes for various combinations)
Credits
A large section of code to load the input to the interpreter is copied
from the the 423 byte dbfi interpreter as described in the November 2003
paper "A Very Small Interpeter" by Oleg Mazonka and Daniel B Cristofani
Goals
The goal for this interpreter was to be efficient rather than small and
particularly to allow as many copies of itself as possible to be "stacked"
up with something else on top / In other words to achieve a low "eigenratio"
(See http eigenratios dot blogspot dot com for more information)
The main idea of the first version was to only make one round trip between
the emulated code and emulated data for each instruction executed instead
of multiple round trips which is what Daniel and Oleg's version does
The second version does more pre processing of the guest program in order
to map several common sequences to virtual codes thus reducing the memory
footprint and also further reducing the number of round trips between the
emulated code and data
Other info:
The input must consist of valid brainfuck code (to be interpreted) which
must always be followed by an exclamation mark and then any associated data
Input can also include "comments" (if desired) except for exclamation mark
If you are stacking multiple copies of this interpreter then each additional
level also has to appear in the input with a trailing exclamation mark and
then we finally have the input for the very top level to finish things off
The underlying brainfuck machine determines the possible range of values in
the data cell values and what happens if an attempt is made to go outside the
supported range but this interpreter does not more than 8 bit data itself
Loops in the emulated code can be nested up to the maximum cell value in the
underlying machine and this interpreter requires that at least 17 levels of
nesting is supported
Behaviour on end of input is also inherited from the next level down
>>>> leave a little extra space before the program code
+ start in left hand cell of first program code pair
[
->>> clear flag and move to the starting position
++>+>+++++++ setup differences and read char as per dbfi
[<++++>>++<-]++>>+>+> (by Daniel B Cristofani)
+++++[>++>++++++<<-]
+>>>,<++
[
[>[->>]<[>>]<<-] see section 3 of dbfi paper
<[<]<+>>[>]>
[ see section 4 of dbfi paper
<+>-
[[<+>-]>] see section 5 of dbfi paper
< see section 6 of dbfi paper
[
[[-]<] scan left and zero the differences
++<- see section 7 of dbfi paper
[
<+++++++++>[<->-]>>
]
>>
]
]
<<
]
a three way switch to handle possibilities and adjust positioning
>[-]+<< set "done" flag and position to value
[
-- 2 means last decode was for a valid instruction
[ so if we still have something left now it was a 9
[-] originally (meaning input should be ignored)
>>- <<<+> so all we do is set the "more input" flag
]
>>
[
-
<<<<[>+<-] for valid input move everything right one
start of processing to find and recode certain combinations of codes
+<<+ set flags to indicate we want to process
the last two instructions in the loop below
[
-> clear flag and move to instruction
[<+>>>>>>+<<<<<-] double copy instruction and then
<[>+<-]>>>>>> restore original before moving to copy
map relevant codes to values giving unique pairwise sums and also
set a flag if we see the end of a loop
>+<
[
-[
-[
-[
-[
-[
-[
-[
-[
[-]
>-<
]>[-<<+++++++>>] <
]
]
]>[-]<
]>[-<<+++>>]<
]>[-<<+>>]<
]>[-]<
]>[-<<<<<<<+>>>>>>>]< set flag if it is end of loop
]>[-]<
<<<< goto next instruction flag
]
add values from above together to get unique sum
>>>[<<+>>-]
<+<
setup a switch to figure out what it means
[
-[
-[
-[
-[
-[
-[
-[
-[
-[
-[
[-]
>-<<<[-]<<+>> change code 8 (add 1) to 9 (add 2)
]
]
]
]>[-]<
]>[-<<<[-]<<+++++++>>>]< change code 4 (left) to 11 (left 2)
]
]
]>[-]<
]>[-<<<[-]<<+++++++>>>]< change code 3 (right) to 10 (right 2)
]
]>[-]<
clear flag set if second to last was end of loop
and go to similar flag for last instruction
<<<<<[-]>>
[
-
<<<[>+>>+<<<-]>[<+>-]>> copy third to last instruction
if it is the start of a loop then we can (in some cases)
collapse the last three instructions to single virtual code
[
-[
-[
[-]
>>
]
>
[ Now we are ready to check what code is in the loop (must be at least 1)
<<[<+>>+<-]>[<+>-]+<<
-
[
-[
-[
-[
-[
-[
-[
-[
-[
-[
-
<+> fall through & code as 16 (double skip left)
]<+++++++++++++>>[-]>->-<< code as 15 (double skip right)
]
]
]>>[->>>>>]<<
]>>[-<<<++++++++++++>>[-]>>-]<< code as 14 (zero)
]>>[->>>>>]<<
]>>[-<<<+++++++++++>>[-]>>-]<< code as 13 (skip left)
]>>[-<<<++++++++++>>[-]>>-]<< code as 12 (skip right)
]
]>>[->>>>>]<<
]
<
]
]>[>>]<
<<
]
>>+>>>
]
<<
]
>> [->+>] << end of input so clear "done" and set data mark and
finally position to a zero cell ready for next phase
< move to "more input" flag
]
<<[<<]>> go to the first instruction
******** MAIN INTERPRETER LOOPS STARTS HERE ********
[ start on current instruction code
setup a big switch statement to decode instructions
[<+>>+<-] move/copy instruction code and set "done" flag to
+<- start with '(i less 1) (1) (i) for i = instruction
[
-[
-[
-[
-[
-[
-[
-[
-[
-[
-[
-[
-[
-[
-[
- can't be anything but 1 so bracketing not needed
>->> [>>] >> [>>]< [<-<<-<] <[<<] << [<<]< double skip left (code 16)
]
>[->> [>>] >> [>>]< [>+>>+>] <[<<] << [<<]]< double skip right (code 15)
]
>[->> [>>] >> [>>] <[-]< [<<] << [<<]]< zero (code 14)
]
>[->> [>>] >> [>>]< [<-<] <[<<] << [<<]]< skip left (code 13)
]
>[->> [>>] >> [>>]< [>+>] <[<<] << [<<]]< skip right (code 12)
]
>[->> [>>] >> [>>]< <-<<-< <[<<] << [<<]]< double move left (code 11)
]
>[->> [>>] >> [>>] +>>+ [<<] << [<<]]< double move right (code 10)
]
>[->> [>>] >> [>>]< ++ <[<<] << [<<]]< add 2 (code 9)
]
>[->> [>>] >> [>>]< + <[<<] << [<<]]< increment
]
>[->> [>>] >> [>>]< , <[<<] << [<<]]< input
]
>[->> [>>] >> [>>]< - <[<<] << [<<]]< decrement
]
>[->> [>>] >> [>>]< . <[<<] << [<<]]< output
]
>[->> [>>] >> [>>] <<-<< [<<] << [<<]]< move left
]
>[->> [>>] >> [>>] + [<<] << [<<]]< move right
]
>
[- left hand bracket
>> [>>] >> [>>]< move to data cell
[>+>>+<<<-]> make double copy and move to first
[<+>-] restore original data cell value
>>[<<+>>[-]]+ This and the following achieves
<<[>>-<<-] x = not x
>> go to flag cell (0 or 1)
Some tricky stuff here: set up (not flag) also so we can later choose
appropriate instruction sequence to get back to code area in one pass
In one case we set flags at the other end (data greater than 0) but
for the other we just go back without setting any flags (data equals 0)
[<<+>>>>+<<-] make two copies of flag
>>[<<+>>-]
<<[>>+<<-]+ This and the following achieves
>>[<<->>-]<< x = not x
<< so we now have (data) '(flag) (?) (not flag)
[ if flag set then
-<< [<<] << [<<]< clear and return to code section where we save
<< << ++ a 2 meaning we need (later) to match left bracket
>> stop in zero cell for now
]
>> if we executed code above then now at switch flag
else it will put us ready to return from data area
[-<<<<<<[<<]<<[<<]<] move back to switch flag without setting anything
>
]
<
]
>
[- right hand bracket
>> [>>] >> [>>]< move to data cell
[>+>>+<<<-]> make double copy and move to first
[[<+>-]>>[-]+<<] restore data from one then zero second and set flag
>> go to flag cell (0 or 1)
Some tricky stuff here: set up (not flag) also so we can later choose
appropriate instruction sequence to get back to code area in one pass
In one case we set flags at the other end (data greater than 0) but
for the other we just go back without setting any flags (data equals 0)
[<<+>>>>+<<-] make two copes of flag
>>[<<+>>-]
<<[>>+<<-]+ This and the following achieves
>>[<<->>-]<< x = not x
<< so we now have (data) '(flag) (?) (not flag)
[ if flag set then
-<< [<<] << [<<]< clear and return to code section where we save
<< << + a 1 meaning we need (later) to match right bracket
>> stop in zero cell for now
]
>> if we executed code above then now at switch flag
else it will put us ready to return from data area
[-<<<<<<[<<]<<[<<]<] move back to switch flag without setting anything
>
]
>[<+>-] restore original instruction code
*** We are positioned in the cell immediately to the right of the ***
*** instruction that has just been "executed" in the switch above ***
*** The following code is to handle finding matching brackets ***
*** because code above has only set a cell value to 1 or 2 to show ***
*** what kind of loop scanning is required (1=scan left 2=right) ***
<< << << position to cell showing if matching required
[ if non zero we need to find a matching bracket
>> + set up "done" flag for switch and
<< - decrement switch value so now is 0 or 1
[ if 1 we are looking for matching right bracket
- >> - >> + clear switch value & "done" & set level to 1
[ while level is more than 0
>>>[-<+>>+<] make double copy of instruction code
+<- set flag and prepare for switch
[
-[
[-] clear whatever is left of code
> - < do nothing except clear flag
]
> [- <<< + >>>] < increment level
]
> [- <<< - >>>] decrement level
>[-<+>]<< restore instruction code
<< go to level
[>>+<<-] if level then move right one instruction
>>
]
<< << << go back to switch value cell
]
>> go to switch done flag and if still set then
[ we must be looking for a matching left bracket
- << + clear switch value & "done" & set level to 1
[ repeat while level is more than 0
>>>[-<+>>+<] make double copy of instruction code
+<- set flag and prepare for switch
[
-[
[-] clear whatever is left of code
> - < do nothing except clear flag
]
> [- <<< - >>>] < decrement level
]
> [- <<< + >>>] increment level
>[-<+>]<< restore instruction code
<< go to level
[<<+>>-] if level then move left one instruction
<<
]
]
]
>> >> >>
> move forward to next instruction
]