-
Notifications
You must be signed in to change notification settings - Fork 0
/
bfcl.bf
586 lines (543 loc) · 29 KB
/
bfcl.bf
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
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
This is version 0_1 of bfcl
bfcl is a BrainFuck compiler for Linux written itself in BrainFuck
It reads the input from stdin and outputs a Linux ELF binary on stdout
Currently no optimization at all is done (which is another reason why
this thing is so sloooooooow on my system :) but that is planned for
version 0_2
Conventions assumed in this program:
fields are one byte long and decreasing zero is possible
Conventions in the binaries compiled with bfcl:
a) fields are one byte long
b) there are 30 000 fields
c) moving the pointer outside this area will lead to your computer
catching fire;
nothing is done to prevent you from doing that however
d) when end of file is encountered the program stores whatever
the Linux syscall returns (I believe it's zero but I'm too lazy to
check)
e) No checks are made on matching parentheses; maybe for version 0_3 :)
And yes; I know the code is far from pretty; far from optimized; and not
very well documented; but I'm sending it out anyway because the longer I
stare at it the more my head hurts
Final word of thanks: many ideas are shamelessly stolen from Brian
Raiter's 171 byte BF compiler available from www_muppetlabs_com/~breadbox/
For questions and comments you can reach me at
vissers@theochem dot kun dot nl
You will forgive me for not typing the dots :)
Ge Vissers
17 april 2003
**************************************************************************
>>>>>>> reserve some extra space
so we can shift the program later
Read the program
Reading a character is a bit of a nuisance since different compilers
use different strategies:
a) leave byte unchanged
b) set byte to zero
c) set byte to 0xff
I *believe* the following code snippets catches all three possibilities above
so that the program ends on either a null or a 0xff byte
>- set character to 0xff
, read a character
[<+>->+<] copy byte to previous and next field
>[+<]> if byte is not zero
add one to it
[ if it is still not zero
[-]< clear the copy
+++++[<-------->-]<--- subtract plus from input
[ if char is not plus
- subtract 1 from char
[ if char is not comma
- subtract 1 from char
[ if char is not minus
- subtract 1 from char
[ if char is not dot
-------------- subtract 14 from char
[ if char is not left angle
-- subtract 2 from char
[ if char is not right angle
>+++[<---------->-]<+ subtract 29 from char
[ if char is not left bracket
-- subtract 2 from char
[ if char is not right bracket
<--------> set opcode to minus 8
[-] clear character
]
<+> increase opcode
] end if (char is not left bracket)
<+> increase opcode
] end if (char is not right angle)
<+> increase opcode
] end if (char is not left angle)
<+> increase opcode
] end if (char is not dot)
<+> increase opcode
] end if (char is not minus)
<+> increase opcode
] end if (char is not comma)
<+> increase opcode
] end if (char is not plus)
<+ increase opcode
[ if opcode is not zero
> move to next field
] end if (opcode is not zero)
>>-, read in a new character
[<+>->+<] copy to previous and next field
>[+<]> if not null check if it's 0xff
] end while not EOF
<<[+] clear possible 0xff
>>++++++++[<++++++++++>-]<++++< 84 bytes for ELF header
>++++++++++++< 12 bytes to initialize program
>++++++< 6 bytes to end program
Calculate file size
<<[<]> move to first opcode
[ while opcode exists
[<<+<+>>>-]<< copy to two previous fields
- decrease
[ if opcode is not plus
- decrease opcode
[ if opcode is not comma
- decrease opcode
[ if opcode is not minus
- decrease opcode
[ if opcode is not dot
- decrease opcode
[ if opcode is not left angle
- decrease opcode
[ if opcode is not right angle
- decrease opcode
[ if opcode is not left bracket
>>>[>]>+++++ indicate 5 bytes should be added
<<[<]-<< set indicator to minus one
-
] end if (opcode is not left bracket)
>>[<-<->>+]<[>-<+]<+ copy indicator and increase
[ else (opcode is left bracket)
>>>[>]>++++++++ indicate 8 bytes should be added
<<[<]-<< set indicator to minus one
-
] end else (opcode is left bracket)
] end if (opcode is not right angle)
>>[<-<->>+]<[>-<+]<+ copy indicator and increase
[ else (opcode is right angle)
>>>[>]>+ indicate 1 byte should be added
<<[<]-<< set indicator to minus 1
-
] end else (opcode is right angle)
] end if (opcode is not left angle)
>>[<-<->>+]<[>-<+]<+ copy indicator and increase
[ else (opcode is left angle)
>>>[>]>+ indicate 1 byte should be added
<<[<]-<< set indicator to minus 1
-
] end else (opcode is left angle)
] end if (opcode is not dot)
>>[<-<->>+]<[>-<+]<+ copy indicator and increase
[ else (opcode is dot)
>>>[>]>++++++ indicate 6 bytes should be added
<<[<]-<< set indicator to minus 1
-
] end else (opcode is dot)
] end if (opcode is not minus)
>>[<-<->>+]<[>-<+]<+ copy indicator and increase
[ else (opcode is minus)
>>>[>]>++ indicate 2 bytes should be added
<<[<]-<< set indicator to minus 1
-
] end else (opcode is minus)
] end if (opcode is not comma)
>>[<-<->>+]<[>-<+]<+ copy indicator and increase
[ else (opcode is comma)
>>>[>]>++++++ indicate 6 bytes should be added
<<[<]-<< set indicator to minus 1
-
] end else (opcode is comma)
] end if (opcode is not plus)
>>[<-<->>+]<[>-<+]<+ copy indicator and increase
[ else (opcode is plus)
>>>[>]>++ indicate 2 bytes should be added
<<[<]-<< set indicator to minus 1
-
] end else (opcode is plus)
>>+>[>]> move to increment
[>+ increase byte 1
[>>>>+>+<<<<<-]>>>>>[<<<<<+>>>>>-] copy byte 1
<[>-<[-]] if no overflow set field to minus 1
>+[- if overflow
<<<<+ increase byte 2
[>>>+>+<<<<-]>>>>[<<<<+>>>>-] copy byte 2
<[>-<[-]] if no overflow set field to minus 1
>+[- if overflow
<<<+ increase byte 3
[>>+>+<<<-]>>>[<<<+>>>-] copy byte 3
<[>-<[-]] if no overflow set field to minus 1
>+[- if overflow
<<+ increase byte 4
>>
] end if
] end if
] end if
<<<<<<- decrease increment
]
<<[<]> move to next opcode
]
>>>>>> move behind file size
>++++++++[<++++++++++++++++>-]<-. output ELF magic bytes
>+++++++[<-------->-]<--.
+++++++.------.
[-]+...-.........++.--.+++.---.+.-... print rest of ELF header
>++++++++[<++++++++++>-]<++++.
>++++++[<+++++++>-]<++.[-]++++.++++.
>++++++[<+++++++>-]<++.[-]...........
>+++++++[<+++++++>-]<+++.>.++++
[<----->-]<.>.+.-.<++++++++.[-].....
+.-........>
++++++++[<++++++++++++++++>-]<.>++++.
++++.>.<<.>----.++++.
<<<<<.>.>.>. this is file size
Copy the file size since we need it to initialize ecx
>[-]>[-]<< clear the fields
<<<[>>>>+>+<<<<<-]>>>>>[<<<<<+>>>>>-] copy the bytes
<<<<[>>>>+>+<<<<<-]>>>>>[<<<<<+>>>>>-]
<<<<[>>>>+>+<<<<<-]>>>>>[<<<<<+>>>>>-]
<<<<[>>>>+>+<<<<<-]>>>>>[<<<<<+>>>>>-]
We have to add 30 000 = 0x75 30 to the file size
Start with 0x30
>>>++++++[<++++++++>-]< set to 0x30
[ while increment is not 0
<<<<<<+ increase byte 1
[>>>>+>+<<<<<-]>>>>>[<<<<<+>>>>>-] copy byte 1
<[>-<[-]] if no overflow set field to minus 1
>+[-
<<<<+ if overflow increase byte 2
[>>>+>+<<<<-]>>>>[<<<<+>>>>-] copy byte 2
<[>-<[-]] if no overflow set field to minus 1
>+[-
<<<+ if overflow increase byte 3
[>>+>+<<<-]>>>[<<<+>>>-] copy byte 3
<[>-<[-]] if no overflow set field to minus 1
>+[<<+>>-] if overflow increase byte 4
]
]
>- decrease increment
]
<<<<<<. print first byte
Now do 0x75 00
>>>>>>>
+++++++[<++++++++++++++++>-]<+++++ set increment
[ while increment is not 0
<<<<<+ increase byte 2
[>>>+>+<<<<-]>>>>[<<<<+>>>>-] copy byte 2
<[>-<[-]] if no overflow set field to minus 1
>+[-
<<<+ if overflow increase byte 3
[>>+>+<<<-]>>>[<<<+>>>-] copy byte 3
<[>-<[-]] if no overflow set field to minus 1
>+[<<+>>-] if overflow increase byte 4
]
>- decrease increment
]
<<<<<.>.>. print other 3 bytes
[-]<[-]<[-]<[-] clear up
++++++.------....++++++++++++++++. print rest of header
[-]..
add 0x80 00 to file size
>++++++++[<++++++++++++++++>-]< set counter to 0x80
[<<<+ increase byte 2
[>>>>+>+<<<<<-]>>>>>[<<<<<+>>>>>-] copy byte 2
<[>-<[-]] if no overflow set indicator to minus 1
>+[- if overflow
<<<<+ increase byte 3
[>>>+>+<<<<]>>>>[<<<<+>>>>-] copy byte 3
<[>-<[-]] if no overflow set indicator to minus 1
>+[<<<+>>>-] if overflow increase byte 4
]
<<- decrease counter
] loop until counter is zero
add 0x04 00 00 to file size
++++ set counter to 0x04
[<<+ increase byte 3
[>>>+>+<<<<-]>>>>[<<<<+>>>>-] copy byte 3
<[>-<[-]] if no overflow set indicator to minus 1
>+[<<<+>>>-] if overflow increase byte 4
<<- decrease counter
] loop until counter is zero
add 0x08 00 00 00 to file size
<++++++++>
Initialize registers
>>+++++++[<+++++++>-]<. xor eax eax
>>++++++++++++[<++++++++++++++++>-]<.
<.>>+++[<+++++++++>-]<. xor ebx ebx
>++++[<-------->-]<--.<<<<<<.>.>.>. mov ecx filesize
>>.>>+++++[<+++++>-]<. xor edx edx
>++++[<<++++>>-]<<+. inc edx
Now start compiling
>[-]<[-]<[-]<[-]<[-]<[-]<[-] clean up
<<<<<<[<]> move to first instruction
[ while opcode exists
- decrease opcode
[ if opcode is not plus
- decrease opcode
[ if opcode is not comma
- decrease opcode
[ if opcode is not minus
- decrease opcode
[ if opcode is not dot
- decrease opcode
[ if opcode is not left angle
- decrease opcode
[ if opcode is not right angle
- decrease opcode
[ if opcode is not left bracket
<++++[>------<-]>. output e9
[-] clear this field
>[>]>>>>>>>>[>>>>>>] move to end of loop size stack
-------->->->-<<< initialize increment
<<<<< move to byte 1 of size
[ while byte 1 is not zero
>>>>>- decrease byte 1
[>>>>+>+<<<<<-] copy byte 1
>>>>>[<<<<<+>>>>>-]
<[>-<[-]] if no underflow set field to minus 1
>+[- if underflow
<<<<- decrease byte 2
[>>>+>+<<<<-] copy byte 2
>>>>[<<<<+>>>>-]
<[>-<[-]] if no underflow set field to minus 1
>+[- if underflow
<<<- decrease byte 3
[>>+>+<<<-] copy byte 3
>>>[<<<+>>>-]
<[>-<[-]] if no underflow set field to minus 1
>+[-<<->>] if underflow decrease byte 4
] end if
] end if
<<<<<<<<<<- decrease byte 1 of size
] end while
> move to byte 2 of size
[ while byte 2 is not zero
>>>>>- decrease byte 2
[>>>+>+<<<<-] copy byte two
>>>>[<<<<+>>>>-]
<[>-<[-]] if no underflow set field to minus 1
>+[- if underflow
<<<- decrease byte 3
[>>+>+<<<-] copy byte 3
>>>[<<<+>>>-]
<[>-<[-]] if no underflow set field to minus 1
>+[-<<->>] if underflow decrease byte 4
] end if
<<<<<<<<<- decrease byte 2 of size
] end while
> move to byte 3 of size
[ while byte 3 is not zero
>>>>>- decrease byte 3
[>>+>+<<<-] copy byte 3
>>>[<<<+>>>-]
<[>-<[-]] if no underflow set field to minus 1
>+[-<<->>] if underflow decrease byte 4
<<<<<<<<- decrease byte 3 of size
]
> move to byte 4 of size
[ while byte 4 is not zero
>>>>>-<<<<<- decrease byte 4
]
>->.>.>.>. print increment
[+]<[+]<[+]<[+] clear increment
<<<<<<- remove size from stack
<[<<<<<<]<<<<<<<<[<] move back to opcode
<-> set indicator to minus 1
] end if (opcode is not left bracket)
<+ increase indicator
[ else (opcode is left bracket)
++++++[>++++++++<-] set to 38
>++.---------. output 3a 31
<+++++++++++++++. output 0f
+[>+++++<-]>+++. output 84
[-] clear this byte
clear the byte counter
+ set nesting level to one
[ while nesting greater than 0
>[<<<+<+>>>>-] copy opcode before nesting level
<<<------- subtract 7 from opcode
[ if opcode is not left bracket
- decrease opcode
[ if opcode is not right bracket
[+] clear field
>-< set indicator to minus 1
] end if opcode is not right braket
>+ increase indicator
[ else (opcode is right bracket)
>-<- decrease nesting level
] end else (opcode is right bracket)
-< set indicator to minus 1
] end if (opcode is not left bracket)
>+ increase indicator
[ else (opcode is left bracket)
>+<- increase nesting level
] end else (opcode is left bracket)
>[>+<-]> copy nesting to next field
] end while (nesting greater than 0)
<<<< move to last opcode in loop
[ while there are opcodes
[>>>+>+<<<<-] copy the opcode twice
>>> move to first copy
- decrease opcode
[ if opcode is not plus
- decrease opcode
[ if opcode is not comma
- decrease opcode
[ if opcode is not minus
- decrease opcode
[ if opcode is not dot
- decrease opcode
[ if opcode is not left angle
- decrease opcode
[ if opcode is not right angle
- decrease opcode
[ if opcode is not left bracket
- then it must be right bracket
set increment to five bytes
<<+++++>->
] end if (opcode is not left bracket)
<+ increase indicator
[ else (opcode is left bracket)
set increment to 8 bytes
<++++++++>-
] end else (opcode is left bracket)
-> set indicator to minus 1
] end if (opcode is not right angle)
<+ increase indicator
[ else (opcode is right angle)
<+>- set increment to 1 byte
] end else (opcode is right angle)
-> set indicator to minus 1
] end if (opcode is not left angle)
<+ increase indicator
[ else (opcode is left angle)
<+>- set increment to 1 byte
] end else (opcode is left angle)
-> set indicator to minus 1
] end else (opcode is not dot)
<+ increase indicator
[ else (opcode is dot)
<++++++>- set increment to 6 bytes
] end else (opcode is dot)
-> set indicator to minus 1
] end if (opcode is not minus)
<+ increase indicator
[ else (opcode is minus)
<++>- set increment to two bytes
] end else (opcode is minus)
-> set indicator to minus 1
] end if (opcode is not comma)
<+ increase indicator
[ else (opcode is comma)
<++++++>- set increment to 6 bytes
] end else (opcode is comma)
-> set indicator to minus 1
] end if (opcode is not plus)
<+ increase indicator
[ else (opcode is plus)
<++>- set increment to 2 bytes
] end else (opcode is plus)
<[>>>[>]>+<<[<]<<-] copy increment behind program
>>>[>]> move to increment
[ while increment is not zero
>+ increase byte 1
[>>>>+>+<<<<<-] copy byte 1
>>>>>[<<<<<+>>>>>-]
<[>-<[-]] if no overflow set field to minus 1
>+[- if overflow
<<<<+ increase byte 2
[>>>+>+<<<<-] copy byte 2
>>>>[<<<<+>>>>-]
<[>-<[-]] if no overflow set field to minus 1
>+[- if overflow
<<<+ increase byte 3
[>>+>+<<<-] copy byte 3
>>>[<<<+>>>-]
<[>-<[-]] if no overflow set field to minus 1
>+[- if overflow
<<+>> increase byte 4
]
] end if
] end if
<<<<<<- decrease increment
] end while
<<[<]<<<< move to next opcode
] end while opcode exists
>>>>>[>]>>.>.>.>. output the loop increment
<<< move to byte 1
copy byte 1 on stack
[>>>>>>[>>>>>>]>+<<[<<<<<<]<<<<<-]
> move to byte 2
copy byte 2 on stack
[>>>>>[>>>>>>]>>+<<<[<<<<<<]<<<<-]
> move to byte 3
copy byte 3 on stack
[>>>>[>>>>>>]>>>+<<<<[<<<<<<]<<<-]
> move to byte 4
copy byte 4 on stack
[>>>[>>>>>>]>>>>+<<<<<[<<<<<<]<<-]
set surrounding 1 bytes
>>>[>>>>>>]+>>>>>+<<<<<<[<<<<<<]<<
<<<<<<[<] move back to start of loop
< move to indicator field
] end else (opcode is left bracket)
-> set indicator to minus 1
] end if (opcode is not right angle)
<+ increase indicator
[ else (opcode is right angle)
+++++++[>++++++++<-]>+ set to 41
.[-]< output 41 and clear up
] end else (opcode is right angle)
-> set indicator to minus 1
] end if (opcode is not left angle)
<+ increase indicator
[ else (opcode is left angle)
+++++++[>+++++++++<-]>+. output 49
[-]< clear up
] end else (opcode is left angle)
-> set indicator to minus 1
] end if (opcode is not dot)
<+ increase indicator
[ else (opcode is dot)
++++++++++ set to b0
[>++++++++++++++++<-]>. output b0
<++++.>+++.<---. output 04 b3 01
+[>+++++++++++++<-]>. output cd
<+++++++[>-----------<-]>. output 80
[-]< clear up
] end else (opcode is dot)
-> set indicator to minus 1
] end if (opcode is not minus)
<+ increase indicator
[ else (opcode is minus)
>--.++<++++++++.--------- output fe 09
] end else (opcode is minus)
-> set indicator to minus 1
] end if (opcode is not comma)
<+ increase indicator
[ else (opcode is comma)
++++++++++[>++++++++++++++++<-] set to b0
>.<+++.>+++.<---. output b0 03 b3 00
++[>+++++++++++++<-]>.< output cd
+++++++[>-----------<-]>. output 80
[-]< clear up
] end else (opcode is comma)
-> set indicator to minus one
] end if (opcode is not plus)
<+ increase indicator
[ else (opcode is plus)
---.+++.- output fe 01
] end else (opcode is plus)
>> move to next opcode
]
[>]>
Clean up
>+++++++++++[<++++++++++++++++>-]<. mov al 1
>+.
<+++.>-. mov bl 0
++++[<++++++>-]<++. int 0x80
>>++++++++[<++++++++++++++++>-]<.