| Bytes | Lang | Time | Link |
|---|---|---|---|
| 407 | C gcc Linux AArch64 | 230918T081006Z | ceilingc |
| 277 | Swift 6 Linux | 250428T175534Z | macOSist |
| 456 | Casio BASIC Casio FX9750GIII | 241002T200928Z | madeforl |
| 120 | 6502 machine code for the Apple II+ | 250113T040208Z | mmphosis |
| 167 | C gcc | 220224T061034Z | Qaziquza |
| 033 | Vyxal DO | 210715T043658Z | emanresu |
| 359 | Haskell | 241007T065119Z | Antonio |
| 349 | Uiua | 240821T131312Z | jan |
| 535 | sed 4.2.2 rn | 240424T195314Z | guest430 |
| 611 | Acc!! | 240521T033056Z | engineer |
| 519 | TIBasic TI84 Plus | 240513T132325Z | madeforl |
| 076 | Z80Golf | 240423T235831Z | EasyasPi |
| 294 | Exceptionally | 240315T000944Z | emanresu |
| 193 | Julia 1.7 | 231111T225230Z | MarcMush |
| nan | Julia 0.6 | 160324T165613Z | M L |
| 000 | Atto8* | 231107T200614Z | Emilien |
| 089 | X86_64/Linux Machine Code | 230815T201325Z | Noah |
| nan | ReRegex | 230925T091933Z | ATaco |
| 347 | C gcc Linux x86_64 | 190103T094035Z | ceilingc |
| 303 | ABPL | 230920T163637Z | J Je |
| 353 | Lua | 230915T221928Z | Luatic |
| 377 | Go | 230915T210229Z | Luatic |
| 365 | ASCII FALSE | 230915T163931Z | Luatic |
| 470 | Desmos | 230817T174453Z | fwoosh |
| 660 | niceexpr | 230502T214536Z | bigyihsu |
| 234 | Rattle | 220208T005004Z | d01 |
| 148 | Vyxal | 220613T054245Z | lyxal |
| 1771 | TypeScript Types | 211128T000514Z | tjjfvi |
| nan | JavaScript ES6 | 210715T183313Z | FZs |
| 116 | ARM Thumb2 Machine code Linux | 211009T061247Z | EasyasPi |
| 247 | Python 3.8 prerelease | 211007T124333Z | Stephen |
| 459 | Scala | 211006T170942Z | nick-iva |
| 580 | Vim | 210419T202841Z | Aaroneou |
| 260 | Duocentehexaquinquagesimal | 210414T184802Z | Makonede |
| nan | C 306 243 237 235 | 201115T225702Z | Shipof12 |
| 312 | Rust | 201116T191521Z | Aiden4 |
| 280 | Python 3 no eval | 190619T231340Z | Daniil T |
| 335 | C# | 200512T102000Z | tdashroy |
| nan | 120911T232901Z | olivecod | |
| 711 | Python 3.8 single expression | 200624T214526Z | timfi |
| 489 | dirt | 200325T064455Z | cardboar |
| 342 | Javascript | 190620T192420Z | Geza Ker |
| 306 | Python 3 | 190618T145808Z | Pâr |
| 268 | C gcc | 180412T171027Z | LambdaBe |
| 173 | Powershell | 181113T191603Z | mazzy |
| 123 | PynTree | 180601T120826Z | hyperneu |
| 111 | Gol><> | 180426T084340Z | Bubbler |
| 386 | Retina 0.8.2 | 160329T191803Z | mbomb007 |
| 953 | Conveyor | 150505T172431Z | xenia |
| 594 | Recall | 151123T044213Z | user4264 |
| 075 | CJam | 160528T151550Z | lynn |
| 258 | SmileBASIC | 180215T045750Z | 12Me21 |
| 691 | brainfuck | 171126T020859Z | Jo King |
| 104 | 16bit x86 assembler code | 171126T015247Z | peter fe |
| 948 | Brainfuck | 170609T191732Z | MD XF |
| nan | C | 110804T204404Z | phimuemu |
| 317 | Python no eval | 110704T072902Z | boothby |
| 194 | C | 160709T041220Z | orlp |
| 232 | Cy | 160327T232336Z | Cyoce |
| 730 | VB.net | 131211T030557Z | Adam Spe |
| 112 | Binary Lambda Calculus | 120910T014409Z | John Tro |
| 104 | Binary Lambda Calculus | 141010T201245Z | Tuomas L |
| 208 | PHP | 110205T220513Z | Arnaud L |
| 103 | Simplex v.0.5 | 151020T111124Z | Conor O& |
| 084 | C# 2861 char | 130125T142020Z | theB |
| 263 | LiveScript evaling JavaScript | 141204T040427Z | Claudia |
| 317 | C | 130508T165929Z | Fors |
| 223 | Python 2 | 130508T123530Z | Reinstat |
| 4414 | Smalltalk | 130508T010516Z | aka.nice |
| 285 | Lua | 130115T144445Z | mniip |
| 166 | PHP 5.4 | 110130T205621Z | Kevin Br |
| 120 | Perl | 110214T221010Z | J B |
| 168 | 16 bit 8086 machine code | 110216T155727Z | Skizz |
| 267 | C | 120805T020820Z | baby-rab |
| 148 | From sepp2k solution | 120804T090905Z | applicat |
| 235 | JavaScript Partial Solution | 110912T221628Z | Billy Mo |
| 255 | Python | 110130T013811Z | Alexandr |
| 333 | C | 110806T032439Z | Potatosw |
| 147 | Ruby 1.8.7 | 110130T161109Z | sepp2k |
| 328 | Delphi | 110311T230902Z | Patrickv |
| 497 | OCamllex | 110317T115443Z | bltxd |
| nan | 110313T001635Z | jpjacobs | |
| nan | 110130T191122Z | snmcdona | |
| 413 | Haskell | 110215T073749Z | MtnViewM |
| 150 | golfscript | 110214T141940Z | roobs |
| 489 | F# | 110206T144841Z | cfern |
| 204 | Windows PowerShell | 110213T212506Z | Joey |
| 368 | C | 110131T002311Z | jtjacque |
C (gcc) Linux AArch64, 483 461 449 439 424 413 407 bytes
#define S(x)"(\0@9\b\5\0"#x"(\0\0\71":
*T=" \0\1J\b\xfc\0\21!@\0\xd4",c,h,*mmap(),*wcpcpy();d[7500];(*p)();*j(int*a){int*t=a,*n,q=0;for(;read(h,&c,!q);)t=c==91?n=j(t+2),*t++='9@\0(',*t=n-t<<5|8|90<<25,n:c==93?q=*t=a-t-2&402653183,t+1:wcpcpy(t,c-60?c-62?c-45?c-43?c-46?c-44?t:T:T+1:S(\21)S(Q)"!\4\0\x91":"!\4\0\xd1");return t;}main(P,g)int**g;{*j(p=mmap(0,1<<20,6,34,h=open(g[1],0),0))=3596551104;p(1,d,1);}
This is a JIT that compiles BF code into AArch64 machine language at runtime. This performs a straight translation so commonly occurring sequences such as >>>, <<<, +++ and --- aren't coalesced into faster instructions.
This is a port of the "JIT" for x86_64 https://codegolf.stackexchange.com/a/178298/52904
Less golfed version:
#include<wchar.h>
// size of data area
c,*mmap();d[7500];h;(*p)();
*j(int*a){
int*t=a,*n,q=0;
for(;read(h,&c,!q);){
t=c==91?
// ldrb w8, [x1]
// cbz w8, n-t
n=j(t+2),
*t++=0x39400028,
*t=n-t<<5|8|180<<24,
n
:c==93?
// b a-t-2
q=a-t-2,
*t=q&0x1ffffff|22<<24,
t+1
:
wcpcpy(t,c-'<'?
c-'>'?
c-'-'?
c-'+'?
c-'.'?
c-','?
L""
:
// eor w0, w1, w1
// add w8, w0, #0x3f ; read(0,buf,1)
// svc #0x201 ; Linux is not picky about the argument
L"\x4a010020\x1100fc08\xd4004021"
:
// add w8, w0, #0x3f ; write(1,buf,1)
// svc #0x201 ; w0 was 1 from last syscall
L"\x1100fc08\xd4004021"
:
// ldrb w8, [x1]
// add w8,w8, 1
// strb w8, [x1]
L"\x39400028\x11000508\x39000028"
:
// ldrb w8, [x1]
// sub w8,w8, 1
// strb w8, [x1]
L"\x39400028\x51000508\x39000028"
:
// add x1, x1, 1
L"\x91000421"
:
// sub x1, x1, 1
L"\xd1000421"
);
}
return t;
}
main(P,g)int**g;{
// allocate text (executable) memory and mark as executable
p=mmap(0,1<<20,6,34,h=open(g[1],0),0);
// run JIT, exit gracefully
*j(p)=0xd65f03c0;
// set %x2=1 and call code like a function
p(1,d,1);
}
Swift 6 (Linux), 426 418 410 361 350 328 314 301 283 282 277 bytes
The macOS version requires import Darwin instead of import Glibc (1 extra byte), but is otherwise identical.
import Glibc
let b={var p=0,c=0,a=[0:0],s=$1+[0],d=zip(0...,$0+[]).map{$1>91 ?s.popLast():$1<91 ?0:(s+=[$0],0).1}
while c<d.count{let v=a[p] ?? 0,n=$0[c]-44
n<2 ?a[p]=n==0 ?s.removeFirst():v-n:n<3 ?_=putchar(CInt(v)):n<19 ?p+=n-17:(c=n<48 ?v<1 ?d.index(of:c)!:c:d[c]!-1)
c+=1}}
b takes in 2 arguments, the program and the input. Both are arrays of ASCII values ([Int]).
Quirks
End-of-input is handled by setting the current cell to 0 (this will only occur once, though — running , twice after end-of-input is reached will crash). This is pretty much just a happy coincidence arising from type inference tricks.
As another fun little side effect, the tape is infinitely large in both directions — this occurs because I used a Dictionary to store the tape instead of an Array.
Non-instruction characters or excess right brackets will throw the program into a deterministically unpredictable state; most other issues will simply cause a crash.
Casio BASIC (Casio FX-9750GIII), 532 468 456 bytes
" !.#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[.]^_`ABCDEFGHIJKLMNOPQRSTUVWXYZ{|}~."→Str 3
255→Dim List1
{0,-1,1}→List2
50→Dim List3
1→L~S
For 1→I To StrLen(Str 1
StrMid(Str 1,I,1→Str 2
If Not D
Then If Not StrCmp(Str 2,"."
Then 1+MOD(Q-1,20→Z
List1[P]-31→J
J<1⇒15→J
Locate Z,((Q-1) Int÷ 20+2,StrMid(Str 3,J,1)
Isz Q
IfEnd
MOD(List1[P]+List2[StrScr("-+",Str 2)+1],255→List1[P
1+MOD(P+List2[StrSrc("12",Str 2)+1]-1,255→P
IfEnd
If Not StrCmp(Str 2,"["
Then If D+List1[P
Then I→List3[L]
Isz L
Else Isz S
1→D
IfEnd
IfEnd
If Not StrCmp(Str 2,"]"
Then S>1⇒Dsz S
If SD
Then 0→D
Dsz S
Else If List1[P
Then List3[L-1]→I
Else Dsz L
IfEnd
IfEnd
IfEnd
Next
this isn't perfect AT ALL. you can't do input.
You have to enter the program into Str 1, and you have to replace < and > with 1 and 2 respectively
its also super slow (but not slower than the TI-84 program I made a while earlier)
6502 machine code for the Apple II+, 120 bytes
300:
:20 E2 F3 20 11 F4 20 DE F3 F0 68 20 61 3 20 4C 3 A5 E1 5 E2 D0 F4 A2
:26 C9 3E F0 48 C9 3C F0 37 E9 2B AA 86 EB F0 19 B1 26 D0 6 E0 30 F0
:DE D0 6 24 E6 E0 32 F0 D6 CA CA F0 D E0 FD B0 4 60 20 53 D5 E5 EB 91
:26 60 4C 5C DB B1 1A A2 E1 C9 5B F0 11 C9 5D D0 1F B5 0 D0 2 D6 1 D6
:0 60 A2 1A 70 F3 F6 0 D0 E F6 1 60 20 17 3 B8 20 61 3 B1 1A D0 F5 60
C (gcc), 194 187 176 167 bytes (thanks to @ceilingcat)
char t['u0'],*p=t;c;l;f(char*b){for(;c=*b;b++)for(c-=44,read(write(l=1,p+=c==18,c==2),p-=c==16,!c),*p-=(c*c<2)*c,c-=47;c<3u&!*p-c/2&&l;l-=*b==93-c)l+=0[b-=c-1]==91+c;}
C (gcc), (Try it online!) 231 bytes
char t['u0'],*p=t;c;l;f(char*b){for (;c=*b;b++) {l=1;c-43||++*p;c-45||--*p;c-60||p--;c-62||p++;c-46||putchar(*p);c-44||(*p=getchar());for(;l&&!*p&&c==91;){++b;*b-91||l++;*b-93||l--;}for(;l&&*p&&c==93;){--b;*b-93||l++;*b-91||l--;}}}
Vyxal DO, 33 bytes
kT`}„‟‹›`f`:C₴_?C{:|`²JǔĿ4↵T(0)„Ė
Try it Online! It's been three years, time for a much newer and cleaner brainfuck interpreter. See the revision history for the old, 50 byte version. Input is taken char-by-char (stuff like newlines can be input via "\n").
The basic idea is that a stack is a wrapping tape if you can rotate the whole thing. So it's really just setting up the input, pushing 0s, and transpiling brainfuck commands to Vyxal:
[-{:|- set a while loop without popping the top]-}- close a while loop<-„- rotate stack left>-‟- rotate stack right+-›- increment the current item--‹- decrement the current item.-:C₴- Duplicate, make a char and output without a trailing newline,-_?C- pop, then take a character from input and get its charcode
For some reason, vyxal has a builtin kT with the brainfuck commands, which is in the order described above - []<>+-.,, which is quite convenient for mapping - all the built-ins that must be transpiled to multiple characters are together.
Then, 4↵T(0) pushes 30000 0s (4↵: 10^4; T: triple; (0): that many times, push 0) and „Ė runs the code!
Haskell, 380, 359 bytes
import System.IO
import System.Environment
z x=pure x
f!j=(.f).(=<<)<$>b j
b(c:r)|c==']'=(r,z)|c=='[',let(x,y)=b r;k m|m 0=='\0'=z m|0<1=y m>>=k=k!x|let f m|let f?0=f.m$0;f?x=m x=last$z m:[g|(t,g)<-zip"><+-.,"[z$m.succ,z$m.pred,z(succ?),z(pred?),putChar(m 0)>>m<$hFlush stdout,(?).z<$>getChar],t==c]=f!r
b _=b"]"
main=getArgs>>=readFile.head>>=($z '\0').snd.b
Adapted from other Haskell answer. Saved some bytes by using Integer -> Char to store the program's memory.
Uiua, 349 characters
P←⊡3
O←⊡4
R←⊡2
A←⊡1
v!←⍜A(◿256^!1)
«‼←(⍜A◌⍜^!(:∩□⨬(°⊂|0)=0⊸⧻°□)⍜⊙^!(□⊂∩°□)⊸A)
⟦‼‼!←(⨬(⍜P◌:⊢⊢^!▽=⊢⇌⍉⟜:▽^!⊃(°□P|⊢⍉.°□⊡7|°□+^!⊸⊡5)|⍜(⊡5)(^!1))◇^!0⊸A)
B←⇌O⍢∘(⟜⨬(
⋅◌|⍜P(+1)⨬(v!+|v!-|«‼⊢R|«‼R⊢|⍜O◌:□◇⊂⊃(+@\0A)⊸O|⍜A◌:-@\0:⍜(⊡8)(□:°⊂°□)|⟦‼‼!∘>1+≠|⟦‼‼!⇌<0-=|∘)⊗:"+-><.,[]"◇⊡
):⟜◇>⊃P(⊸◇⧻⊸⊡6)){[]0[]0""0⟜(▽⊙(⍉⊟⇡⧻.)∈"[]"⊙+:⊸=@])⟜(⇌◌∧(⟜⊂⨬(+1|-1|∘)⊗:"[]")⊙⊃0[])⊙∘}
ungolfed version (takes like 20 seconds to calculate the primes up to 16)
golfed version (propably even slower) (it interprets comments as noops instead of filtering them out)
It's a pretty standard brainfuck interpreter, Uiua doesn't have an eval built-in. Noteworthy things I "invented" are
- a 9-element box array that stores the memory as two bottomless stacks and an accumulator, the program counter, the output, the nesting level, the code, the NLJT, and the input. There is just a required figurative ton of data that you have to keep around that having it in different stack positions doesn't make sense. This has the effect that I use a lot of
by (pick 1),under (pick 1) pop flipand similar. - The Nesting Level Jump Table is a two column table which lists all the indecies in the code where brackets occur, together with how many brackets surround the code they contain. The bracket's jump behaviour is then conditionally looking up the next bracket on the same nesting level in the direction the bracket is pointing, and jumping there.
sed 4.2.2 -rn, 992 580 554 540 535 bytes
s/[^][<>+.,-]//g;x #delete non-bf chars
s/.*/ /;s//&&&&&/;s//&&&&&/
s//&&&&&/;s//&&&&&/;s// !&&&&&&/ #initilize 30000-char array
x;G;s/^/!/ #format into '!code\n !a r r a y'
: #label ''
/!\+/{s//+!/;s/ !/&a/;t} #if +, move forward, add one to array at pos, return to ''
/!-/{s//-!/;s/ !a?/ !/;t} #if -, move forward, (if array>0, subtract one from array at pos), return to ''
/!\./{s//.!/;h;s/.* !(a*).*/\1/p;x;t} #if ., move forward, print value at array pos, return to ''
/!,/{s//,!/;N;s/ !a*(.*)\n(.*)/ !\2\1/;t} #if ,, move forward, get input, replace value at array pos, return to ''
/!</{s//<!/;s/ (a* )?!/ !\1/;t} #if <, move forward, move array pos one closer to the start, return to ''
/!>/{s//>!/;s/!(a* )/\1!/;t} #if >, move forward, move array pos one closer to the end, return to ''
/!\[/{s//[!/;h;s/.* !(a*).*/\1/ #if [, move forward, load value at array pos
/^$/{x;:[;s/!([%-?])/\1!/;t[ # if 0, load code, label [, (if non-][ char, move forward, return to [,)
/!]/{s//]!/;T;x;s/a//;x;T;T[} # if [, move forward, i++, return to [
s/!./[!/;x;s/|/a/;x;t[} # else, move forward, (if i--, return to [,) return to ''
x;t} # else, load code, return to ''
/!]/{h;s/.* !(a*).*/\1/ #if ], load value at array pos
/^$/!{z;x;:];s/([%-?])!/!\1/;t] # if not 0, i=0, load code, label ], (if non-][ char, move backward, return to ],)
/]!/{s//!]/;x;s/|/a/;x;t]} # if ], move backward, i++, return to ]
s/.!/![/;T;x;s/a//;x;T;T]} # else, move backward, (if i--, return to ],) return to ''
x;s/!]/]!/;t} # else, load code, move forward, return to ''
# notes: no evals, pure sed, i/o is in unary
Try it online! (can print primes up to 8) or, here's without the Primes up to: text and with an array size of 48 which can print primes up to 20 and still exit properly: try it online!
input and output are strings of unary as. no evals in this version! to run it yourself on bash, put the whole thing in quotes like sed -rn '${code}' or save as a file and run like sed -rnf code.sed (no piping allowed; running sed without any input lets you have interactive I/O). the first line of input is the bf code, and it will consume as many lines after that as it needs to for ,s in the code. once the program finishes, you can put in another bf program or ^D to exit. if your bf program has newlines in it, add a -z to the sed call and a ^@ to the end of your code; but that also means that each input has to end with a ^@ instead of ^J as well. if you have a sed newer than 4.2.2, add a p after the : sitting on its own line and after all the t/Ts followed by a semicolon, newline, or closing curly brace.
to this interpreter, 0-1=0 and 255+1=256. there is no theoretical upper bound to what can be stored in a cell but the computer you run this sed script on likely has less than infinite memory so it'll crash eventually.
changes from v2 to v3:
- 450+ bytes off!
- no more numeric pointer, uses a
!to track where it currently is in the array - much faster; the
Primes up to:'text' can be printed without shortening the array in ~10 seconds on TIO compared to previously taking a minute to print justPreven after shortening the array to 8. - no more
evals - a bit of future proofing for v4 which may take io as characters instead of unary (that'll bring a couple new
eflags in though) - instead of
!code\npointer\narrayit's now just!code\n !a r r a ywhere!is a 'current position' marker. - using
//{}conditional notation for the easy functions instead of:a;tajumps, which means fewer labels but more slashes.
v4 with actual characters as i/o instead of unary:
sed 4.2.2 -r, 844 789 755 702 bytes
s/[^][<>+.,-]//g;x
s/.*/ /;s//&&&&&&/;s//&&&&&/;s//&&&&&/;s//&&&&&/;s// !&&&&&/;x;G;s/^/!/
:
/!\+/{s//+!/;s/ !/&a/;t}
/!-/{s//-!/;s/ !a?/ !/;t}
/!\./{s//.!/;h;s/.* !(a*).*/\1/;:.;s/a/<<1234567a01>/;s/(.)<.*\1(a?.).*>/\2/;t.;s/.*/sed 's%z%\\o&%'<<<z/e;x;G;t}
/!,/{s//,!/;h;N;s%.*(.)%dc -e"`od -td1<<<'\1'`orp"%e;s/1/0a/g;:,;s/a0/0aa/g;t,;G;s/(a*)\n(.* !)a*/\2\1/;t}
/!</{s//<!/;s/ (a* )?!/ !\1/;t}
/!>/{s//>!/;s/!(a* )/\1!/;t}
/!\[/{s//[!/;h;s/.* !(a*).*/\1/
/^$/{x;:[;s/!([%-?])/\1!/;t[
/!]/{s//]!/;T;x;s/a//;x;T;T[}
s/!./[!/;x;s/|/a/;x;t[}
x;t}
/!]/{h;s/.* !(a*).*/\1/
/^$/!{z;x;:];s/([%-?])!/!\1/;t]
/]!/{s//!]/;x;s/|/a/;x;t]}
s/.!/![/;T;x;s/a//;x;T;T]}
x;s/!]/]!/;t}
s/.* ![a ]*//
s/.(.)/\1/g
# notes: 2 evals, uses dc & od to convert char to binary
Try it online!, or use the fast version with a small array and no prefix
the overall program flow hasn't really changed except that the output is collected and actually outputted when the program finishes instead of as it goes along, and there is an eval occurring for both commas[input] and periods[output] (I'm sure you can find those two lines pretty easily now...)
let's start with output:
sed 4.2.2, 73 bytes
: # begin loop
s%a%<<1234567a01>% # replace the first 'a' with '<<1234567a01>'
s%(.)<.*\1(a?.).*>%\2% # magic regex, explained below
t # if anything happened, restart the loop
s/.*/sed 's%o%\\o&%'<<<o/e # print char with that octal code
sadly I can't claim authorship of the first half, but the way it works is absolutely beautiful. in sed, there's no way to actually work with numbers, but this manages to convert unary chars to numbers in only 47 bytes. the regex basically says, replace the character before <, and everything between <>, with whichever character within the <>s which comes after that first character except that if there's an 'a' before the character, it also includes the 'a'. this means < becomes 1, numbers get incremented, and 7 becomes a0. since numbers get incremented when there is an a next to them, the a0 takes care of carrying by pushing the a up a digit.
for input, let's follow the data flow. it first goes through od: od -td1<<<'\1'. the \1 is filled by sed, and is the character we are trying to determine the ascii value of. -td1"type: decimal, one" outputs individual bytes in decimal. the <<< "here string" includes a newline, so we get an output looking like 0000000 104 10 0000002. the graves around the od command means it gets ran and replaced with its output, so the shell next runs dc -e"0000000 104 10 0000002orp". dc is a stack based language; so numbers push themselves, o pops a number for the output radix (2 since there's 2 chars), r swaps the two top values, p prints the top value. the rest of the line converts binary to unary, and puts the number in array.
if you just can't accept using anything but sed, even in evals, and need input and output in actual chars, here's the version which includes an ascii table to do that for you:
sed 4.2.2 -r, 902 bytes
s/[^][<>+.,-]//g;x
s/.*/ /;s//&&&&&&/;s//&&&&&/;s//&&&&&/;s//&&&&&/;s// !&&&&&/;x;G;s/^/!/
:
/!\+/{s//+!/;s/ !/&a/;t}
/!-/{s//-!/;s/ !a?/ !/;t}
/!\./{s//.!/;h;s/.* !(a*).*/\1/;:.;s/a/<<1234567a01>/;s/(.)<.*\1(a?.).*>/\2/;t.;s/.*/sed 's%z%\\o&%'<<<z/e;x;G;t}
/!,/{s//,!/;h;N;s/.*\n//;/^$/s//\n/;:,;s/./&\d1\d2\d3\d4\d5\d6\a\d8\t\n\v\f\r\xe\xf\d16\d17\d18\d19\d20\d21\d22\d23\d24\d25\d26\d27\d28\d29\d30\d31 !"#$%\&'()*+,-.\/0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_`abcdefghijklmnopqrstuvwxyz{|}~>/;T;s/(.).*(.)\1.*>/\2a/;t,;G;s/.*~>(a+)\n(.* !)a*/\2a\1/;t}
/!</{s//<!/;s/ (a* )?!/ !\1/;t}
/!>/{s//>!/;s/!(a* )/\1!/;t}
/!\[/{s//[!/;h;s/.* !(a*).*/\1/
/^$/{x;:[;s/!([%-?])/\1!/;t[
/!]/{s//]!/;T;x;s/a//;x;T;T[}
s/!./[!/;x;s/|/a/;x;t[}
x;t}
/!]/{h;s/.* !(a*).*/\1/
/^$/!{z;x;:];s/([%-?])!/!\1/;t]
/]!/{s//!]/;x;s/|/a/;x;t]}
s/.!/![/;T;x;s/a//;x;T;T]}
x;s/!]/]!/;t}
s/.* ![a ]*//
s/.(.)/\1/g
# notes: 1 eval, pure sed, uses ascii table to convert chars
Acc!!, 678 652 611 bytes
-26 bytes thanks to @Mukundan314
-41 bytes thanks to @emanresu A
Count i while _/256^(8+i)-33 {
_+N*256^(9+i)+2^32
}
Count i while (_-_/2^32)%4^8 {
_-(_/2^48%256-_/256^(9+_%4^8)%256)*2^48-(_/2^64%256-_/256^(9+(_/4^8+_/2^32)%4^8)%256)*2^64
Count j while 0^((_/2^48%256-91-j)^2+_/2^64%256)+_/2^64%256*0^(_/2^48%256-93-j)^2+_/2^56%256 {
_+(92-_/2^48%256)*0^0^j
_+5*2^91/2^(_/256^(9+_%4^8)%256)%2*(_/256^(9+_%4^8)%256*(_/2^48%256)%4-2)*2^56
}
Count j while 0^(_/2^48%256-44)^2-j {
_-(_/2^64%256-N)*256^(9+(_/4^8+_/2^32)%4^8)
}
Write _/2^64%256)*(0^(_/2^48%256-46)^2
_+5*2^43/2^(_/2^48%256)%2*256^(9+(_/4^8+_/2^32)%4^8)*(44-_/2^48%256)+5*2^60/2^(_/2^48%256)%2*4^8*(_/2^48%256-61)+1
Explanation
# Accumulator is split up into indivually-addressable chunks of bytes
# MSB [memory][code][memcache][depth][codecache][c][p][r] LSB, where:
# Field Size LSb/LSB Explanation
# r u16 2^0 Program counter / instruction pointer
# p u16 2^16 Memory pointer
# c u16 2^32 Size of code in bytes
# codecache u8 2^48 Saved copy of code[r] to save space
# depth u8 2^56 Current bracket depth when handling [ and ]
# memcache u8 2^64 Saved copy of memory[p] to save space
# code u8[c] 256^9 Code as read directly from input
# memory u8[] 256^(9+c) Brainfuck memory tape
# Bit k of _ (_/2^k%2)
# Byte k of _ (_/256^k%256)
# code[c] (_/256^(9+_/2^32%4^8)%256)
# code[r] (_/256^(9+_%4^8)%256)
# memory[p] (_/256^(9+(_/4^8+_/2^32)%4^8)%256)
# a == b 0^(a-b)^2
# a != b a-b (or 0^0^(a-b)^2 for only 0/1 output)
# if(cnd) _+=i _+i*0^(cnd)^2
# if(cnd) {..} Count z while 0^(cnd)^2-z {..}
# Read source code while code[c-1] != 33 ('!')
# i = c in this loop
Count i while _/256^(8+i)-33 {
_ + N*256^(9+i) + 2^32 # Read N to code[c] and c++
}
# Interpret loop
# Loop while r != c (while r-c nonzero)
Count i while (_-_/2^32)%4^8 {
# Cache code[r] in 2^48 to reduce duplication
# Cache memory[p] in 2^64 to reduce duplication
# Clear old values and set new values
_ - (_/2^48%256 - _/256^(9+_%4^8)%256) * 2^48
- (_/2^64%256 - _/256^(9+(_/4^8+_/2^32)%4^8)%256) * 2^64
# Handle [ and ] instructions - code[r] == 91/93
# Skip / backtrack to matched ] / [ while depth nonzero
Count j while
0^((_/2^48%256-91-j)^2 + _/2^64%256) # (code[r]==91 & memory[p]==0)
+ _/2^64%256 * 0^(_/2^48%256-93-j)^2 # or (code[r]==93 & memory[p]!=0)
+ _/2^56%256 # or (depth!=0)
{
# r++/-- if past first iteration
# Since code[r] is 91 or 93, 92-code[r] is 1/-1 for [/] respectively.
_ + (92-_/2^48%256) * 0^0^j
# depth++/-- if code[r] == 91 / [
# depth--/++ if code[r] == 93 / ]
_ + 5*2^91/2^(_/256^(9+_%4^8)%256)%2
* (_/256^(9+_%4^8)%256 * (_/2^48%256) % 4 - 2)
* 2^56
}
# Handle , instruction - code[r] == 44
Count j while 0^(_/2^48%256-44)^2-j {
# Clear memory[p] / Read N into memory[p]
_ - (_/2^64%256 - N)*256^(9+(_/4^8+_/2^32)%4^8)
}
# Handle . instruction - code[r] == 46
# Uses interpreter exploit - becomes (in python):
# print(chr( <memory[p]>)*(<code[r]==46> ))
Write _/2^64%256) * (0^(_/2^48%256-46)^2
# Handle + instruction / memory[p]++ if code[r] == 43
# Handle - instruction / memory[p]-- if code[r] == 45
# Handle < instruction / p-- if code[r] == 60
# Handle > instruction / p++ if code[r] == 62
# Next instruction / r++
_ + 5*2^43/2^(_/2^48%256)%2 # code[r] == 43/45 ? 1 : 0
* 256^(9+(_/4^8+_/2^32)%4^8) # * shift for memory[p]
* (44-_/2^48%256) # * direction (44-code[r])
+ 5*2^60/2^(_/2^48%256)%2 # code[r] == 60/62 ? 1 : 0
* 4^8 # * shift for p
* (_/2^48%256-61) # * direction (code[r]-61)
+ 1 # r++
# } for this count block can be omitted as i is never used (interpreter exploit)
TI-Basic (TI-84 Plus), 519 bytes
*fixed an error
"................................ !.....'()*+,-./0123456789:.<=>?.ABCDEFGHIJKLMNOPQRSTUVWXYZ[.]^..abcdefghijklmnopqrstuvwxyz{.}.→Str2
Prompt Str1
50→dim(L₁
Fill(0,L₁
50→Dim(L₂
Fill(0,L₂
5→P
0→L
0→D
0→X
1→Y
0→S
ClrHome
For(I,1,length(Str1
sub(Str1,I,1→Str3
If not(D
Then
If Str3=",
Then
Input Str4
inString(Str2,Str4→L₁(P
End
If Str3=".
Then
If L₁(P
Output(int(X/16)+1,remainder(X,16)+1,sub(Str2,L₁(P),1
X+1+X
End
L₁(P)+(Str3="+")-(Str3="-→L₁(P
remainder(abs(254(L₁(P)<0)-L₁(P)),256→L₁(P
P+(Str3=">")-(Str3="<→P
End
If Str3="[
Then
If L₁(P
Then
L+1→L
I→L₂(L
Else
S+1→S
1→D
End
End
If Str3="]
Then
S(S>1→S
If D(S=1
Then
0→D
0→S
Else
If L₁(P
Then
L₂(L→I
Else
L-1→L
End
End
End
End
I had to re-create the ASCII code page myself, since the TI-84 plus doesn't have a command that gets a character from its char code. The periods are characters that are not on the TI-84 Plus.
Keep in mind this is extremely slow at just printing Hello World (around 70 seconds to do it) so I couldn't imagine it trying to calculate primes.
It prompts you for code when the program starts, you MUST put a quotation mark (") before your code because of how the TI-84 works.
When prompting you for an input, you also have to put a quotation mark before your input.
There might be an error in the code due to me manually copying it from my calculator to my computer. If there is, please tell me.
Z80Golf, 76 bytes
00000000: 5e d5 3e 21 cd 03 80 0e 09 2e 26 ed b1 20 f3 09 ^.>!......&.. ..
00000010: 09 ed a0 0c 20 ec eb c9 7e c3 00 80 d5 13 d5 c9 .... ...~.......
00000020: af cd 03 80 77 c9 2b 2d 3c 3e 2e 2c 5b 5d 21 76 ....w.+-<>.,[]!v
00000030: c9 ff e7 df 23 2b 35 34 d1 1b 46 04 10 de 1a 13 ....#+54..F.....
00000040: fe c9 28 04 04 3c 28 fc 10 f4 d5 c9 ..(..<(.....
Commented assembly:
; A tiny (76 bytes), non-optimizing Brainfuck bytecode based interpreter for Z80Golf
; The bytecode is a sequence of 1 byte instructions which either execute directly or trap+emulate.
; z80asm brainfuck-z80g.asm -o brainfuck-z80g.z8g
AT: MACRO ADDR
IF $ != ADDR
not ADDR
ENDIF
ENDM
PUTC: EQU 0x8000 ; Z80Golf putc syscall
GETC: EQU 0x8003 ; Z80Golf getc syscall
RETOPC: EQU 0xC9 ; Opcode for RET, used in the scan loop
EOF: EQU '!' ; Standard EOF extension for Brainfuck
ORG 0x0000
_start:
ld e, (hl) ; 00 Start assembling at DE = 0x005E (read the opcode itself lol)
push de ; 01 Push return address to start of code
parse: ; == Parse loop ==
ld a, EOF ; 02 Default to EOF ('!')
call GETC ; 04 Read byte from stdin
ld c, 9 ; 07 Length of table
ld l, table ; 09 Address of table
cpir ; 0B Scan the lookup table (WHILE BC && *HL != A; HL++; BC--)
jr nz, parse ; 0D Not found, next byte
translate: ; == Found a match, translate from BF to bytecode ==
add hl, bc ; 0F Add BC (remainder from CPIR) to HL. HL == bytecode
add hl, bc ; 10 Add again, this time pointing to the table entry
ldi ; 11 Copy compiled code to (DE), decrement BC. On EOF, BC == -1
inc c ; 13 Increment C to test if BC == -1
jr nz, parse ; 14 Not EOF, continue parsing
exec: ; == Finalize and jump to the code ==
ex de, hl ; 16 Swap DE (code pointer) to HL, setting HL to the tape
ret ; 17 Jump to start of code (0x005E) we pushed earlier
AT 0x18
rst_print: ; == RST 0x18: Syscall for print (.) ==
ld a, (hl) ; 18 Load byte from tape
jp PUTC ; 19 Tail call PUTC
loop_cont: ; == Push return for ']' to stack and continue. DE = ptr to '[' ==
push de ; 1C Push return address for ']' to RET to
inc de ; 1D Increment to get past the '['
push de ; 1E Push DE
ret ; 1F and jump to it
AT 0x20
rst_read: ; == RST 0x20: Syscall for read (,) ==
xor a ; 20 Default to 0
call GETC ; 21 Read byte from stdin
ld (hl), a ; 24 Store to tape
ret ; 25 Return
table: ; == Lookup table for Brainfuck opcodes ==
DB "+-<>.,[]", EOF ; 26-2E BF opcodes
bytecode: ; == Reversed compiled bytecode ==
term: halt ; 2F EOF
end: ret ; 30 ] (RET to the start of the loop pushed by ']')
begin: rst rst_begin ; 31 [ (Scan to skip loop or push return address for ']')
read: rst rst_read ; 32 , (Wrap GETC)
print: rst rst_print ; 33 . (Wrap PUTC)
right: inc hl ; 34 >
left: dec hl ; 35 <
minus: dec (hl) ; 36 -
plus: inc (hl) ; 37 +
AT 0x38
rst_begin: ; == RST 0x38: Syscall for begin ([) ==
pop de ; 38 Pop return address (points past the '[')
dec de ; 39 Decrement to point to the '['
ld b, (hl) ; 3A Load tape value into B
inc b ; 3B INC B/DJNZ: test for B == 0
djnz loop_cont ; 3C If nonzero, loop is true, continue execution.
scan_loop: ; == Scan bytecode to match []. B is conveniently 0. ==
ld a, (de) ; 3E Load compiled opcode
inc de ; 3F Advance DE
cp RETOPC ; 40 Test for ']' which is encoded as RET
jr z, scan_djnz ; 42 If ']', jump to the DJNZ for a net of -1
incr_again: ;
inc b ; 44 Increment B
inc a ; 45 Increment A to test for '[' (RST 0x38 == 0xFF).
jr z, incr_again ; 46 If '[', repeat the increment for a net of +1,
scan_djnz: ; otherwise cancel out the inc b with djnz
djnz scan_loop ; 48 Decrement loop depth and loop if nonzero
push de ; 4A Push DE
ret ; 4B and jump to it
Long time no see, PPCG! 🙋♀️
Surprised there wasn't a Z80Golf entry, it is actually very elegant.
This takes advantage of the fact that with only 3 rst routines, we can do a 1:1 mapping of Brainfuck to 1-byte opcodes, and just execute directly removing the need for an interpreter loop or manual PC tracking (we just pop the return address of rst)
+:inc (hl)-:dec (hl)>:inc hl<:dec hl.:rst 0x18- wraps PUTC (0x8000)
,:rst 0x20- wraps GETC (0x8003)
[:rst 0x38- If zero, scan forward to skip, else push address of
[to the call stack and continue.
- If zero, scan forward to skip, else push address of
]:ret- Return unconditionally to the pushed address of
[to test again
- Return unconditionally to the pushed address of
!(EOF):halt
Specs:
- Wrapping 8-bit cells
- Maximum stripped program size of (if my calculations are correct) 32673 bytes
- Maximum tape size of (64924 - stripped program size) bytes, non wrapping
- Maximum loop depth of 255
- Program is read from stdin as
prog!inputor EOF terminated - Cells are set to 0 on EOF
The code is carefully written to line up with the RST addresses perfectly without NOPs, opcode overlaps, excess jumps or other weirdness, another thing I find elegant.
Also it is technically a JIT compiler, which is what all the cool kids do, right? 🤓
Exceptionally, 294 bytes
{0C}r{c?!1!14G}cG+r}i{0}p}q}fR}t}s{""}o{1F}u{t:29999?{t;~0;}t{t:q}k{c:p?{o;P;/A}d{f>0?!11{d=91?!3{f+1}f=93?!3{f-1}f{0}d{q}l{d=43?!3{k+1}k{d=44?!7{i:0A}k{i[1}i=45?!3{k-1}k{d=46?!6{kC}y{o+y}o{d=62?!3{q+1}q{d=91?!8{k=0?!3{1}f!3{s~p}s=93?!7{s:u-1}p{s]u}s=60?!3{q-1}q{k%256}k{t[l[1}u{t]l~k+u}t{p+1}p
Attempt This Online! This took ages to write.
Input is terminated with a null byte (and going past this crashes it), wrapping the tape is undefined behaviour for reasons explained below.
Ungolfed version (ish). Also, here's a modified version that appends a trailing newline to the input running the example primes code. This is so slow that it times out for n=10, so this is n=5.
Explanation
Exceptionally is a language created by DLosc where the program runs in an infinite loop, and the only form of control flow is throwing and catching exceptions.
A few quirks of this answer:
- Rather than initialising the tape as an array of 30000 0s, which couldn't be done in one cycle, I start with [] and append a 0 before each iteration, up to a length of 30000. This only causes issues if the program attempts to go to the left of the tape, so that's undefined behaviour and will result in the IP pointing to the constantly-updating end of the tape.
- Exceptionally only allows printing strings with a leading newline, so I store the output in a buffer and print it upon termination.
- I can't easily change the value of one item in an array, so instead I take
tape[:ip-1] + [new_value] + tape[ip+1:]. - To deal with loops, I store a stack of previous
[bracket positions, jump back to the last]on a[, and if the current cell is 0 on a[I move forward until I find the matching bracket.
Setup
{0C}r{c?!1!14G}cG+r}i{0}p}q}fR}t}s{""}o{1F}u
{0C}r ' r = "\0"
{c?!1!14 ' If c (code) is not defined (to only run once)
G}c ' c = input()
G+r}i ' i (input) = input() + "\0"
{0}p}q}f ' p (IP) = q (tape pointer) = f (skip counter) = 0
R}t}s ' t (tape) = s (bracket stack) = []
{""}o ' o (output)
{1F}u ' u = -1
{t:29999?{t;~0;}t{t:q}k{c:p?{o;P;/A}d{f>0?!11{d=91?!3{f+1}f=93?!3{f-1}f{0}d{q}l
{t:29999? ' If tape length < 30000
{t;~0;}t ' Append a zero to the tape
{t:q}k ' k (current cell) = tape[tp]
{c:p A}d ' d (current char) = ord(code[ip])
?{o;P;/ ' If that crashes because IP's gone out of bounds, print output and terminate
{f>0?!11------------------------------ ' If skip > 0 (currently skipping a loop)
{d=91?!3{f+1}f ' If d is 91 ("[") increment skip counter
=93?!3{f-1}f ' If d is 93 ("]") decrement skip counter
{0}d ' Nullify current char (currently skipping chars)
{q}l ' Make a copy of IP for tape-shifting purposes
Commands
{d=43?!3{k+1}k{d=44?!7{i:0A}k{i[1}i=45?!3{k-1}k{d=46?!6{kC}y{o+y}o
{d=43?!3 ' If current char is 43 (+)
{k+1}k ' Increment current cell
{d=44?!7 ' If 44 (,)
{i:0A}k ' current cell = ord(input[0])
{i[1}i ' remove first char of input buffer
=45?!3 ' If 45 (-)
{k-1}k ' Decrement current cell
{d=46?!6 ' If 46 (.)
{kC}y{o+y}o ' Append chr(current cell) to output buffer
{d=62?!3{q+1}q{d=91?!8{k=0?!3{1}f!3{s~p}s=93?!7{s:u-1}p{s]u}s=60?!3{q-1}q
{d=62?!3 ' If current char is 62 (>)
{q+1}q ' Increment tape pointer
{d=91?!8 ' If 91 ([)
{k=0?!3 ' If current cell is 0
{1}f ' Start skipping chars
!3{s~p}s ' Else (nonzero) continue normal execution and push current IP to call stack
=93?!7 ' If 93 (])
{s:u-1}p{s]u}s ' Jump to before last item of call stack, pop call stack
=60?!3 ' If 60 (<)
{q-1}q ' Decrement tape pointer
Final stuff
{k%256}k{t[l[1}u{t]l~k+u}t{p+1}p
{k%256}k ' Modulo current cell by 256
{t[l[1}u ' u = all tape cells past IP
{t]l ' All tape cells before IP
~k+u ' Append new current cell value and concatenate rest of tape
}t ' Store into tape
{p+1}p ' Increment IP
Julia 1.7, 193 bytes
!x="let a=fill(0,8^5),i=1
"*replace(x*"]",(["><+-.,[]"...].=>[["i" "a[i]"].*["+=1";"-=1"]...
"print('\0'+a[i])"
"a[i:i]=read(stdin,1)"
"while a[i]>0"
"end"].*";")...,r"."s=>"")|>Meta.parse|>eval
Julia 1.7 is needed for replace with multiple patterns
ungolfed code:
!x="let a=fill(0,8^5),i=1
"*replace(x*"]", # add `end` to close the `let` block
'>' => "i+=1;",
'<' => "i-=1;",
'+' => "a[i]+=1;",
'-' => "a[i]-=1;",
'.' => "print('\0'+a[i]);",
',' => "a[i:i]=read(stdin,1);",
'[' => "while a[i]>0;",
']' => "end;",
r"."s => "" # remove all other characters
)|>Meta.parse|>eval
This function takes the program as parameter.
Program with the stricter IO (as a file given as argument): 206 bytes
Julia 0.6, 427 422 bytes
I know the challenge is old, but who cares... My solution feels huge, and I bet it could be a lot shorter.
function g(n::AbstractString) p=open(n);c=readchomp(p);close(p);b="a[k]";e=30000;j="a=zeros(UInt8,$e);k=1;";for i=1:length(c) c[i]=='<'?(j=j*"k-=1;"):c[i]=='>'?(j=j*"k+=1;"):c[i]=='+'?(j=j*"$b+=1;"):c[i]=='-'?(j=j*"$b-=1;"):c[i]=='['?(j=j*"while $b>0 "):c[i]==']'?(j=j*"end;"):c[i]=='.'?(j=j*"print(Char($b));"):c[i]==','?(j=j*"s=chomp(readline(STDIN));s==\"\"?$b=10:$b=s[1];"):nothing;end;println(j);@eval $(parse(j));end
Characters are entered one by one, no buffered input. Just hitting the enter key sends newline (ASCII 10).
Execution of the test case for primes up to 255, on my i5 2410 M laptop takes about 9.5 minutes:
julia> @time bf("primes.bf")
Primes up to: 2
5
5
2 3 5 7 11 13 17 19 23 29 31 37 41 43 47 53 59 61 67 71 73 79 83 89 97 101 103 107 109 113 127 131 137 139 149 151 157 163 167 173 179 181 191 193 197 199 211 223 227 229 233 239 241 251
567.207327 seconds (301.29 k allocations: 19.484 MB)
Ungolfed:
function bf(n::AbstractString)
p=open(n)
c=readchomp(p)
close(p)
b="a[k]"
U="UInt8(1)"
e=30000
j="a=zeros(UInt8,$e);k=1;"
for i=1:length(c)
c[i]=='<' ? (j=j*"k-=1;") :
c[i]=='>' ? (j=j*"k+=1;") :
c[i]=='+' ? (j=j*"$b+=$U;") :
c[i]=='-' ? (j=j*"$b-=$U;") :
c[i]=='[' ? (j=j*"while $b>0 ") :
c[i]==']' ? (j=j*"end;") :
c[i]=='.' ? (j=j*"print(Char($b));") :
c[i]==',' ? (j=j*"s=chomp(readline(STDIN));s==\"\" ? $b=10 : $b=s[1];") : nothing
end
j=parse(j)
@eval $j
end
The interpreter generates julia code from the bf source and evaluates the code. For the test case, the result would look like this:
a=zeros(UInt8,30000);k=1;k+=1;a[k]+=1;a[k]+=1;a[k]+=1;a[k]+=1;a[k]+=1;a[k]+=1;...........
In a more readable version with newlines instead of semicolons, this results in 1368 SLOC:
a=zeros(UInt8,30000)
k=1
k+=1
a[k]+=1
a[k]+=1
a[k]+=1
a[k]+=1
a[k]+=1
a[k]+=1
a[k]+=1
a[k]+=1
while a[k]>0
k-=1
a[k]+=1
a[k]+=1
a[k]+=1
a[k]+=1
a[k]+=1
a[k]+=1
a[k]+=1
a[k]+=1
k+=1
a[k]-=1
end
...
...
...
while a[k]>0
a[k]-=1
end
k-=1
while a[k]>0
a[k]-=1
end
k-=1
k-=1
a[k]-=1
end
a[k]+=1
a[k]+=1
a[k]+=1
a[k]+=1
a[k]+=1
a[k]+=1
a[k]+=1
a[k]+=1
a[k]+=1
a[k]+=1
print(Char(a[k]))
while a[k]>0
a[k]-=1
end
Atto-8*, 0 bytes
*with brainfuck frontend
Unfortunately couldn't manage to golf off additional bytes. Open to suggestions if anyone has pointers.
Explanation
The Atto-8 microprocessor, when built with its brainfuck frontend, begins executing ASCII-encoded brainfuck directly from RAM, on bare metal. The microprocessor's machine code is brainfuck source code, and so no interpreter is required.
X86_64/Linux Machine Code, 104 101 100 99 98 97 96 95 93 92 91 89
Usage:
$> gcc -s -static -nostartfiles -nodefaultlibs -nostdlib -Wl,-Tbss=0x7ffe0000 -DBF_IDEAL_BSS -Wl,--build-id=none bf.S -o bf
$> ./bf <input>
Notes
- Size is measured in machine code (i.e 89 bytes of
PROGBITS;.text,.data, etc...) -9bytes if reads input prog from stdin-4more bytes withoutBF_EXITCLEANLY(it will segfault to exit).-2more bytes withBF_BALANCED(assumes that over course of program data cell returns to start).- So minimum possible size 74 bytes.
- NOTE Without the ideal bss setup (at address
0x7ffe0000andBF_IDEAL_BSSdefined as seen in compile command above) add+2bytes.
#define BF_LBRACE 91
#define BF_RBRACE 93
#define BF_DOT 46
#define BF_COMMA 44
#define BF_PLUS 43
#define BF_MINUS 45
#define BF_LSHIFT 60
#define BF_RSHIFT 62
#define BF_READFILE
#define BF_EXITCLEANLY
// #define BF_IDEAL_BSS
// #define BF_BALANCED
.global _start
.text
_start:
/* All incoming registers at zero. */
/* Large read range. This may cause errors for huge programs
(which will fail anyways). */
decl %edx
#ifdef BF_READFILE
/* open. */
movb $2, %al
/* 3rd argument in rsp is first commandline argument. */
pop %rdi
pop %rdi
pop %rdi
/* O_RDONLY is zero. */
syscall
/* Error is okay, we will eventually just exit w.o executing. */
xchgl %eax, %edi
/* Sets ESI at 2 ** 31. This is an arbitrary address > 65536
(minimum deref address on linux) < 2 ** 32 - PROG_SPACE
(PROG_SPACE ~= 262144). We setup bss at 2 ** 31 - 131072 via
linker script (-Tbss=0x7ffe0000). */
# ifdef BF_IDEAL_BSS
bts %edx, %esi
# else
movl $(G_mem + 65536), %esi
# endif
/* bss initialized memory is zero. This is cheapest way to zero
out eax. */
lodsl
#else
# ifdef BF_IDEAL_BSS
bts %edx, %esi
# else
movl $(G_mem + 65536), %esi
# endif
#endif
/* eax/edi are already zero which happens to match
SYS_read/STDIN_FILENO. */
syscall
/* Usage linux' pre-allocated stack for braces. */
/* Program code grows up. */
movl %esi, %ebx
/* Assuming no errors, reach stores size in eax. Note errors or
0-byte reads are okay. The ebx is readable memory and zero-
initialized (bss), so it its zero-length, it will just be an
invalid op and we will hit bounds check below. If its error,
eax is negative so ebx will be negative and likewise we will
hit bounds check below. */
#ifdef BF_BALANCED
addl %eax, %esi
xchgl %eax, %ebp
#else
addl %esi, %eax
xchgl %eax, %ebp
movl %ebp, %esi
#endif
/* We have -1 in edx, so negative to get 1. 1 is needed in a
variety of places. */
negl %edx
run_program:
/* Need to zero eax. */
movb (%rbx), %al
incl %ebx
/* %al contains the program "instruction". Its unique to one of
8 values so just test each in order. If instruction matches
execute it then fallthrough (%al can only ever match one).
We occasionally set al but are sure never to set it to the
ASCII value of any of our 8 instructions. */
/* TODO: Brace handling could probably be smaller. */
try_lbrace:
cmpb $BF_LBRACE, %al
je do_lbrace
try_rbrace:
cmpb $BF_RBRACE, %al
jne try_cont
do_rbrace:
/* Popping state (we might repush if we are looping back). */
pop %rdx
pop %rdi
/* Non-zero cell means loop. Note we have 1 cached in edx. */
cmpb %dl, (%rsi)
jb next_insn
movl %edi, %ebx
do_lbrace:
/* Restore loop state. */
push %rbx
push %rdx
/* If cell is zero, then we are skipping till RBRACE. Note we
have 1 cached in edx. */
cmpb %dl, (%rsi)
/* -1 if we want to start skipping. */
sbb %dh, %dh
try_cont:
orb %dh, %al
/* we have set ah s.t its either zero or has a value that makes
any further matches impossible. */
/* For the rest of the ops we take advantage of the fact that
the ascii values of the pairs '<'/'>', '+'/'-', and '.',','
are all 2 apart. This allows use to test a pair with the
following formula: `((al - PAIR_LO) & -3) == 0`. This will
always leave the pair as 0/2 and will match only the pair.
It turns out 0/2 are useful and can be used to do all the
rest of the operations w.o extra branches. */
try_lshift:
subb $BF_LSHIFT, %al
testb $-3, %al
jnz try_comma
addl %eax, %esi
decl %esi
try_comma:
try_dot:
subb $(BF_PLUS - BF_LSHIFT), %al
/* We have 0/1/2/3 for '+'/','/'-'/'.' so check if we remaining
valid opcode. */
cmpb $3, %al
ja next_insn
/* 0/2 are '+'/'-' so check low bits. TODO: There may be a way
to just care from `shr $1, %al' which would save us an
instruction. But it messes up the '+'/'-' case. */
testb $-3, %al
jz try_minus
/* al is either 3/1. Shift by 1 to get 1/0 for our syscall number. */
shrb $1, %al
// btsq $, %rax
/* SYS_write == STDOUT_FILENO, SYS_read == STDIN_FILENO. */
movl %eax, %edi
/* We already have 1 in rdx. */
syscall
/* Assuming no io error, eax is 1. We will subtract 1 from eax
in try_minus/try_plus so it will be +/- 0 which does
nothing. */
try_minus:
try_plus:
/* If not coming from syscall eax is 0/2. 0 --> plus, 2 -->
minus. So (rsi - eax + 1) translates. */
// setbe %cl
subb %al, (%rsi)
incb (%rsi)
next_insn:
#ifdef BF_BALANCED
/* If BF_BALANCED is set, we assume that the program will have
shifted back columns to start before exiting. */
cmpl %ebx, %esi
#else
cmpl %ebx, %ebp
#endif
jg run_program
#ifdef BF_EXITCLEANLY
/* eax has zero upper 24 bits so we can cheat and use movb here.
(This isn't exact correct, assuming no IO errors on last
instruction). */
movb $60, %al
syscall
#endif
.section .bss
.align 32
G_mem: .space(65536 * 4)
Edit: Just for fun, here a compliant 269 byte fully contained ELF file that implements brainfuck on Linux/X86_64:
Its possible to make this smaller.
- We could take advantage of the known linux ELF impl and put code in known-unused fields.
00000000 7f 45 4c 46 02 01 01 00 00 00 00 00 00 00 00 00 |.ELF............|
00000010 02 00 3e 00 01 00 00 00 b0 10 40 00 00 00 00 00 |..>.......@.....|
00000020 40 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |@...............|
00000030 00 00 00 00 40 00 38 00 02 00 00 00 00 00 00 00 |....@.8.........|
00000040 01 00 00 00 05 00 00 00 00 00 00 00 00 00 00 00 |................|
00000050 00 10 40 00 00 00 00 00 00 10 40 00 00 00 00 00 |..@.......@.....|
00000060 cd 00 00 00 00 00 00 00 cd 00 00 00 00 00 00 00 |................|
00000070 00 00 00 00 00 00 00 00 01 00 00 00 06 00 00 00 |................|
00000080 00 00 00 00 00 00 00 00 00 00 fe 7f 00 00 00 00 |................|
00000090 00 00 fe 7f 00 00 00 00 00 00 00 00 00 00 00 00 |................|
000000a0 00 00 04 00 00 00 00 00 20 00 00 00 00 00 00 00 |........ .......|
000000b0 ff ca b0 02 5f 5f 5f 0f 05 97 0f ab d6 ad 0f 05 |....___.........|
000000c0 89 f4 89 f3 01 c6 89 f5 f7 da 0f b6 03 ff c3 3c |...............<|
000000d0 5b 74 0c 3c 5d 75 0e 5a 5f 38 16 72 28 89 fb 53 |[t.<]u.Z_8.r(..S|
000000e0 52 38 16 18 f6 08 f0 2c 3c a8 fd 75 04 01 c6 ff |R8.....,<..u....|
000000f0 ce 2c ef 3c 03 77 0e a8 fd 74 06 d0 e8 89 c7 0f |.,.<.w...t......|
00000100 05 28 06 fe 06 39 dd 7f c1 b0 3c 0f 05 |.(...9....<..|
0000010d
ReRegex, 12046 bytes
#import math
^1([^$]*?)[^\[\]<>,.+-]/1$1/^1([\[\]<>,.+-]*)(\$[^$]*)$/2'$1\$$2/^1([\[\]<>,.+-]*)$/2'$1\$\$/^2([^$]*)'([()<>,.+-])/2$1$2'/^2([^()$]*)'\[/2$1'\(/^2([^()$]*)'\]/2$1'/^2([^$]*?)(=*)\(([^()$]*)'\[/2$1$2($3$2=('/^2([^$]*?)(=*)\(([^()$]*)'\]/2$1$2($3$2)'/^2([^$]*?)(=*)=\)([^()$]*)'\]/2$1$2=)$3$2)'/^2([^$]*?)(=*)\)([^()$]*)'\[/2$1$2)$3$2('/^2([^']*)'\$/3'\$'$1\$/^4([_,']*\$[^']*)'([^$])/3$1$2'/^3([_,]*)'([^$]*)\$([^']*)'\+/4$1'_$2\$$3'+/_{256}//^3([_,]*)'_([^$]*)\$([^']*)'-/4$1'$2\$$3'-/^3([_,]*)'(?=[^_])([^$]*)\$([^']*)'-/4$1'u<255>$2\$$3'-/^3([_,]*)'(_*),?([_,]*)\$([^']*)'>/4$1$2,'$3\$$4'>/^3([_,]*?)(_*),?'([_,]*)\$([^']*)'</4$1'$2,$3\$$4'</^3([_,]*?)'(_*)([_,]*)\$([^']*)'\.([^$]*)\$([^$]*)/4$1'$2$3\$$4'.$5\$$6$2,/^3([_,]*?)'(_*)([_,]*)\$([^']*)',([^$]*\$[^$]*)\$([\x00-\xFF])/5$1':$6$3\$$4',$5\$/^3([_,]*?)'(_*)([_,]*)\$([^']*)',([^$]*\$[^$]*)\$$/4$1'$3\$$4',$5\$/^5([_,]*)':\x00/4$1'u<0>/^5([_,]*)':\x01/4$1'u<1>/^5([_,]*)':\x02/4$1'u<2>/^5([_,]*)':\x03/4$1'u<3>/^5([_,]*)':\x04/4$1'u<4>/^5([_,]*)':\x05/4$1'u<5>/^5([_,]*)':\x06/4$1'u<6>/^5([_,]*)':\x07/4$1'u<7>/^5([_,]*)':\x08/4$1'u<8>/^5([_,]*)':\x09/4$1'u<9>/^5([_,]*)':\x0A/4$1'u<10>/^5([_,]*)':\x0B/4$1'u<11>/^5([_,]*)':\x0C/4$1'u<12>/^5([_,]*)':\x0D/4$1'u<13>/^5([_,]*)':\x0E/4$1'u<14>/^5([_,]*)':\x0F/4$1'u<15>/^5([_,]*)':\x10/4$1'u<16>/^5([_,]*)':\x11/4$1'u<17>/^5([_,]*)':\x12/4$1'u<18>/^5([_,]*)':\x13/4$1'u<19>/^5([_,]*)':\x14/4$1'u<20>/^5([_,]*)':\x15/4$1'u<21>/^5([_,]*)':\x16/4$1'u<22>/^5([_,]*)':\x17/4$1'u<23>/^5([_,]*)':\x18/4$1'u<24>/^5([_,]*)':\x19/4$1'u<25>/^5([_,]*)':\x1A/4$1'u<26>/^5([_,]*)':\x1B/4$1'u<27>/^5([_,]*)':\x1C/4$1'u<28>/^5([_,]*)':\x1D/4$1'u<29>/^5([_,]*)':\x1E/4$1'u<30>/^5([_,]*)':\x1F/4$1'u<31>/^5([_,]*)':\x20/4$1'u<32>/^5([_,]*)':\x21/4$1'u<33>/^5([_,]*)':\x22/4$1'u<34>/^5([_,]*)':\x23/4$1'u<35>/^5([_,]*)':\x24/4$1'u<36>/^5([_,]*)':\x25/4$1'u<37>/^5([_,]*)':\x26/4$1'u<38>/^5([_,]*)':\x27/4$1'u<39>/^5([_,]*)':\x28/4$1'u<40>/^5([_,]*)':\x29/4$1'u<41>/^5([_,]*)':\x2A/4$1'u<42>/^5([_,]*)':\x2B/4$1'u<43>/^5([_,]*)':\x2C/4$1'u<44>/^5([_,]*)':\x2D/4$1'u<45>/^5([_,]*)':\x2E/4$1'u<46>/^5([_,]*)':\x2F/4$1'u<47>/^5([_,]*)':\x30/4$1'u<48>/^5([_,]*)':\x31/4$1'u<49>/^5([_,]*)':\x32/4$1'u<50>/^5([_,]*)':\x33/4$1'u<51>/^5([_,]*)':\x34/4$1'u<52>/^5([_,]*)':\x35/4$1'u<53>/^5([_,]*)':\x36/4$1'u<54>/^5([_,]*)':\x37/4$1'u<55>/^5([_,]*)':\x38/4$1'u<56>/^5([_,]*)':\x39/4$1'u<57>/^5([_,]*)':\x3A/4$1'u<58>/^5([_,]*)':\x3B/4$1'u<59>/^5([_,]*)':\x3C/4$1'u<60>/^5([_,]*)':\x3D/4$1'u<61>/^5([_,]*)':\x3E/4$1'u<62>/^5([_,]*)':\x3F/4$1'u<63>/^5([_,]*)':\x40/4$1'u<64>/^5([_,]*)':\x41/4$1'u<65>/^5([_,]*)':\x42/4$1'u<66>/^5([_,]*)':\x43/4$1'u<67>/^5([_,]*)':\x44/4$1'u<68>/^5([_,]*)':\x45/4$1'u<69>/^5([_,]*)':\x46/4$1'u<70>/^5([_,]*)':\x47/4$1'u<71>/^5([_,]*)':\x48/4$1'u<72>/^5([_,]*)':\x49/4$1'u<73>/^5([_,]*)':\x4A/4$1'u<74>/^5([_,]*)':\x4B/4$1'u<75>/^5([_,]*)':\x4C/4$1'u<76>/^5([_,]*)':\x4D/4$1'u<77>/^5([_,]*)':\x4E/4$1'u<78>/^5([_,]*)':\x4F/4$1'u<79>/^5([_,]*)':\x50/4$1'u<80>/^5([_,]*)':\x51/4$1'u<81>/^5([_,]*)':\x52/4$1'u<82>/^5([_,]*)':\x53/4$1'u<83>/^5([_,]*)':\x54/4$1'u<84>/^5([_,]*)':\x55/4$1'u<85>/^5([_,]*)':\x56/4$1'u<86>/^5([_,]*)':\x57/4$1'u<87>/^5([_,]*)':\x58/4$1'u<88>/^5([_,]*)':\x59/4$1'u<89>/^5([_,]*)':\x5A/4$1'u<90>/^5([_,]*)':\x5B/4$1'u<91>/^5([_,]*)':\x5C/4$1'u<92>/^5([_,]*)':\x5D/4$1'u<93>/^5([_,]*)':\x5E/4$1'u<94>/^5([_,]*)':\x5F/4$1'u<95>/^5([_,]*)':\x60/4$1'u<96>/^5([_,]*)':\x61/4$1'u<97>/^5([_,]*)':\x62/4$1'u<98>/^5([_,]*)':\x63/4$1'u<99>/^5([_,]*)':\x64/4$1'u<100>/^5([_,]*)':\x65/4$1'u<101>/^5([_,]*)':\x66/4$1'u<102>/^5([_,]*)':\x67/4$1'u<103>/^5([_,]*)':\x68/4$1'u<104>/^5([_,]*)':\x69/4$1'u<105>/^5([_,]*)':\x6A/4$1'u<106>/^5([_,]*)':\x6B/4$1'u<107>/^5([_,]*)':\x6C/4$1'u<108>/^5([_,]*)':\x6D/4$1'u<109>/^5([_,]*)':\x6E/4$1'u<110>/^5([_,]*)':\x6F/4$1'u<111>/^5([_,]*)':\x70/4$1'u<112>/^5([_,]*)':\x71/4$1'u<113>/^5([_,]*)':\x72/4$1'u<114>/^5([_,]*)':\x73/4$1'u<115>/^5([_,]*)':\x74/4$1'u<116>/^5([_,]*)':\x75/4$1'u<117>/^5([_,]*)':\x76/4$1'u<118>/^5([_,]*)':\x77/4$1'u<119>/^5([_,]*)':\x78/4$1'u<120>/^5([_,]*)':\x79/4$1'u<121>/^5([_,]*)':\x7A/4$1'u<122>/^5([_,]*)':\x7B/4$1'u<123>/^5([_,]*)':\x7C/4$1'u<124>/^5([_,]*)':\x7D/4$1'u<125>/^5([_,]*)':\x7E/4$1'u<126>/^5([_,]*)':\x7F/4$1'u<127>/^5([_,]*)':\x80/4$1'u<128>/^5([_,]*)':\x81/4$1'u<129>/^5([_,]*)':\x82/4$1'u<130>/^5([_,]*)':\x83/4$1'u<131>/^5([_,]*)':\x84/4$1'u<132>/^5([_,]*)':\x85/4$1'u<133>/^5([_,]*)':\x86/4$1'u<134>/^5([_,]*)':\x87/4$1'u<135>/^5([_,]*)':\x88/4$1'u<136>/^5([_,]*)':\x89/4$1'u<137>/^5([_,]*)':\x8A/4$1'u<138>/^5([_,]*)':\x8B/4$1'u<139>/^5([_,]*)':\x8C/4$1'u<140>/^5([_,]*)':\x8D/4$1'u<141>/^5([_,]*)':\x8E/4$1'u<142>/^5([_,]*)':\x8F/4$1'u<143>/^5([_,]*)':\x90/4$1'u<144>/^5([_,]*)':\x91/4$1'u<145>/^5([_,]*)':\x92/4$1'u<146>/^5([_,]*)':\x93/4$1'u<147>/^5([_,]*)':\x94/4$1'u<148>/^5([_,]*)':\x95/4$1'u<149>/^5([_,]*)':\x96/4$1'u<150>/^5([_,]*)':\x97/4$1'u<151>/^5([_,]*)':\x98/4$1'u<152>/^5([_,]*)':\x99/4$1'u<153>/^5([_,]*)':\x9A/4$1'u<154>/^5([_,]*)':\x9B/4$1'u<155>/^5([_,]*)':\x9C/4$1'u<156>/^5([_,]*)':\x9D/4$1'u<157>/^5([_,]*)':\x9E/4$1'u<158>/^5([_,]*)':\x9F/4$1'u<159>/^5([_,]*)':\xA0/4$1'u<160>/^5([_,]*)':\xA1/4$1'u<161>/^5([_,]*)':\xA2/4$1'u<162>/^5([_,]*)':\xA3/4$1'u<163>/^5([_,]*)':\xA4/4$1'u<164>/^5([_,]*)':\xA5/4$1'u<165>/^5([_,]*)':\xA6/4$1'u<166>/^5([_,]*)':\xA7/4$1'u<167>/^5([_,]*)':\xA8/4$1'u<168>/^5([_,]*)':\xA9/4$1'u<169>/^5([_,]*)':\xAA/4$1'u<170>/^5([_,]*)':\xAB/4$1'u<171>/^5([_,]*)':\xAC/4$1'u<172>/^5([_,]*)':\xAD/4$1'u<173>/^5([_,]*)':\xAE/4$1'u<174>/^5([_,]*)':\xAF/4$1'u<175>/^5([_,]*)':\xB0/4$1'u<176>/^5([_,]*)':\xB1/4$1'u<177>/^5([_,]*)':\xB2/4$1'u<178>/^5([_,]*)':\xB3/4$1'u<179>/^5([_,]*)':\xB4/4$1'u<180>/^5([_,]*)':\xB5/4$1'u<181>/^5([_,]*)':\xB6/4$1'u<182>/^5([_,]*)':\xB7/4$1'u<183>/^5([_,]*)':\xB8/4$1'u<184>/^5([_,]*)':\xB9/4$1'u<185>/^5([_,]*)':\xBA/4$1'u<186>/^5([_,]*)':\xBB/4$1'u<187>/^5([_,]*)':\xBC/4$1'u<188>/^5([_,]*)':\xBD/4$1'u<189>/^5([_,]*)':\xBE/4$1'u<190>/^5([_,]*)':\xBF/4$1'u<191>/^5([_,]*)':\xC0/4$1'u<192>/^5([_,]*)':\xC1/4$1'u<193>/^5([_,]*)':\xC2/4$1'u<194>/^5([_,]*)':\xC3/4$1'u<195>/^5([_,]*)':\xC4/4$1'u<196>/^5([_,]*)':\xC5/4$1'u<197>/^5([_,]*)':\xC6/4$1'u<198>/^5([_,]*)':\xC7/4$1'u<199>/^5([_,]*)':\xC8/4$1'u<200>/^5([_,]*)':\xC9/4$1'u<201>/^5([_,]*)':\xCA/4$1'u<202>/^5([_,]*)':\xCB/4$1'u<203>/^5([_,]*)':\xCC/4$1'u<204>/^5([_,]*)':\xCD/4$1'u<205>/^5([_,]*)':\xCE/4$1'u<206>/^5([_,]*)':\xCF/4$1'u<207>/^5([_,]*)':\xD0/4$1'u<208>/^5([_,]*)':\xD1/4$1'u<209>/^5([_,]*)':\xD2/4$1'u<210>/^5([_,]*)':\xD3/4$1'u<211>/^5([_,]*)':\xD4/4$1'u<212>/^5([_,]*)':\xD5/4$1'u<213>/^5([_,]*)':\xD6/4$1'u<214>/^5([_,]*)':\xD7/4$1'u<215>/^5([_,]*)':\xD8/4$1'u<216>/^5([_,]*)':\xD9/4$1'u<217>/^5([_,]*)':\xDA/4$1'u<218>/^5([_,]*)':\xDB/4$1'u<219>/^5([_,]*)':\xDC/4$1'u<220>/^5([_,]*)':\xDD/4$1'u<221>/^5([_,]*)':\xDE/4$1'u<222>/^5([_,]*)':\xDF/4$1'u<223>/^5([_,]*)':\xE0/4$1'u<224>/^5([_,]*)':\xE1/4$1'u<225>/^5([_,]*)':\xE2/4$1'u<226>/^5([_,]*)':\xE3/4$1'u<227>/^5([_,]*)':\xE4/4$1'u<228>/^5([_,]*)':\xE5/4$1'u<229>/^5([_,]*)':\xE6/4$1'u<230>/^5([_,]*)':\xE7/4$1'u<231>/^5([_,]*)':\xE8/4$1'u<232>/^5([_,]*)':\xE9/4$1'u<233>/^5([_,]*)':\xEA/4$1'u<234>/^5([_,]*)':\xEB/4$1'u<235>/^5([_,]*)':\xEC/4$1'u<236>/^5([_,]*)':\xED/4$1'u<237>/^5([_,]*)':\xEE/4$1'u<238>/^5([_,]*)':\xEF/4$1'u<239>/^5([_,]*)':\xF0/4$1'u<240>/^5([_,]*)':\xF1/4$1'u<241>/^5([_,]*)':\xF2/4$1'u<242>/^5([_,]*)':\xF3/4$1'u<243>/^5([_,]*)':\xF4/4$1'u<244>/^5([_,]*)':\xF5/4$1'u<245>/^5([_,]*)':\xF6/4$1'u<246>/^5([_,]*)':\xF7/4$1'u<247>/^5([_,]*)':\xF8/4$1'u<248>/^5([_,]*)':\xF9/4$1'u<249>/^5([_,]*)':\xFA/4$1'u<250>/^5([_,]*)':\xFB/4$1'u<251>/^5([_,]*)':\xFC/4$1'u<252>/^5([_,]*)':\xFD/4$1'u<253>/^5([_,]*)':\xFE/4$1'u<254>/^5([_,]*)':\xFF/4$1'u<255>/^3([_,]*)'(_+)([,_]*)\$([^']*)'(=*)\(/4$1'$2$3\$$4$5'(/^3([_,]*)'(?!_)([,_]*)\$([^']*)'(=*)\(([^$]*?)(?<!=)\4\)/4$1'$2\$$3$4($5$4')/^3([_,]*)'(_+)([,_]*)\$([^']*)(?<!=)(=*)\(([^']*?)'\5\)/4$1'$2$3\$$4$5'($6$5)/^3([_,]*)'(?!_)([,_]*)\$([^']*)(?<!=)(=*)\(([^']*?)'\4\)/4$1'$2\$$3$4($5$4')/^3['_,]*\$[^$]*'\$([_,]*)\$[^\x00-\xFF]*$/6$1\$/^6_{0,31},([_,]*)\$([\x00-\xff]*)/6$1\$$2/^6_{32},([_,]*)\$([\x00-\xff]*)/6$1\$$2 /^6_{33},([_,]*)\$([\x00-\xff]*)/6$1\$$2!/^6_{34},([_,]*)\$([\x00-\xff]*)/6$1\$$2"/^6_{35},([_,]*)\$([\x00-\xff]*)/6$1\$$2\#/^6_{36},([_,]*)\$([\x00-\xff]*)/6$1\$$2\$/^6_{37},([_,]*)\$([\x00-\xff]*)/6$1\$$2%/^6_{38},([_,]*)\$([\x00-\xff]*)/6$1\$$2&/^6_{39},([_,]*)\$([\x00-\xff]*)/6$1\$$2'/^6_{40},([_,]*)\$([\x00-\xff]*)/6$1\$$2(/^6_{41},([_,]*)\$([\x00-\xff]*)/6$1\$$2)/^6_{42},([_,]*)\$([\x00-\xff]*)/6$1\$$2*/^6_{43},([_,]*)\$([\x00-\xff]*)/6$1\$$2+/^6_{44},([_,]*)\$([\x00-\xff]*)/6$1\$$2,/^6_{45},([_,]*)\$([\x00-\xff]*)/6$1\$$2-/^6_{46},([_,]*)\$([\x00-\xff]*)/6$1\$$2./^6_{47},([_,]*)\$([\x00-\xff]*)/6$1\$$2\//^6_{48},([_,]*)\$([\x00-\xff]*)/6$1\$$20/^6_{49},([_,]*)\$([\x00-\xff]*)/6$1\$$21/^6_{50},([_,]*)\$([\x00-\xff]*)/6$1\$$22/^6_{51},([_,]*)\$([\x00-\xff]*)/6$1\$$23/^6_{52},([_,]*)\$([\x00-\xff]*)/6$1\$$24/^6_{53},([_,]*)\$([\x00-\xff]*)/6$1\$$25/^6_{54},([_,]*)\$([\x00-\xff]*)/6$1\$$26/^6_{55},([_,]*)\$([\x00-\xff]*)/6$1\$$27/^6_{56},([_,]*)\$([\x00-\xff]*)/6$1\$$28/^6_{57},([_,]*)\$([\x00-\xff]*)/6$1\$$29/^6_{58},([_,]*)\$([\x00-\xff]*)/6$1\$$2:/^6_{59},([_,]*)\$([\x00-\xff]*)/6$1\$$2;/^6_{60},([_,]*)\$([\x00-\xff]*)/6$1\$$2</^6_{61},([_,]*)\$([\x00-\xff]*)/6$1\$$2=/^6_{62},([_,]*)\$([\x00-\xff]*)/6$1\$$2>/^6_{63},([_,]*)\$([\x00-\xff]*)/6$1\$$2?/^6_{64},([_,]*)\$([\x00-\xff]*)/6$1\$$2@/^6_{65},([_,]*)\$([\x00-\xff]*)/6$1\$$2A/^6_{66},([_,]*)\$([\x00-\xff]*)/6$1\$$2B/^6_{67},([_,]*)\$([\x00-\xff]*)/6$1\$$2C/^6_{68},([_,]*)\$([\x00-\xff]*)/6$1\$$2D/^6_{69},([_,]*)\$([\x00-\xff]*)/6$1\$$2E/^6_{70},([_,]*)\$([\x00-\xff]*)/6$1\$$2F/^6_{71},([_,]*)\$([\x00-\xff]*)/6$1\$$2G/^6_{72},([_,]*)\$([\x00-\xff]*)/6$1\$$2H/^6_{73},([_,]*)\$([\x00-\xff]*)/6$1\$$2I/^6_{74},([_,]*)\$([\x00-\xff]*)/6$1\$$2J/^6_{75},([_,]*)\$([\x00-\xff]*)/6$1\$$2K/^6_{76},([_,]*)\$([\x00-\xff]*)/6$1\$$2L/^6_{77},([_,]*)\$([\x00-\xff]*)/6$1\$$2M/^6_{78},([_,]*)\$([\x00-\xff]*)/6$1\$$2N/^6_{79},([_,]*)\$([\x00-\xff]*)/6$1\$$2O/^6_{80},([_,]*)\$([\x00-\xff]*)/6$1\$$2P/^6_{81},([_,]*)\$([\x00-\xff]*)/6$1\$$2Q/^6_{82},([_,]*)\$([\x00-\xff]*)/6$1\$$2R/^6_{83},([_,]*)\$([\x00-\xff]*)/6$1\$$2S/^6_{84},([_,]*)\$([\x00-\xff]*)/6$1\$$2T/^6_{85},([_,]*)\$([\x00-\xff]*)/6$1\$$2U/^6_{86},([_,]*)\$([\x00-\xff]*)/6$1\$$2V/^6_{87},([_,]*)\$([\x00-\xff]*)/6$1\$$2W/^6_{88},([_,]*)\$([\x00-\xff]*)/6$1\$$2X/^6_{89},([_,]*)\$([\x00-\xff]*)/6$1\$$2Y/^6_{90},([_,]*)\$([\x00-\xff]*)/6$1\$$2Z/^6_{91},([_,]*)\$([\x00-\xff]*)/6$1\$$2[/^6_{92},([_,]*)\$([\x00-\xff]*)/6$1\$$2\\/^6_{93},([_,]*)\$([\x00-\xff]*)/6$1\$$2]/^6_{94},([_,]*)\$([\x00-\xff]*)/6$1\$$2^/^6_{95},([_,]*)\$([\x00-\xff]*)/6$1\$$2_/^6_{96},([_,]*)\$([\x00-\xff]*)/6$1\$$2`/^6_{97},([_,]*)\$([\x00-\xff]*)/6$1\$$2a/^6_{98},([_,]*)\$([\x00-\xff]*)/6$1\$$2b/^6_{99},([_,]*)\$([\x00-\xff]*)/6$1\$$2c/^6_{100},([_,]*)\$([\x00-\xff]*)/6$1\$$2d/^6_{101},([_,]*)\$([\x00-\xff]*)/6$1\$$2e/^6_{102},([_,]*)\$([\x00-\xff]*)/6$1\$$2f/^6_{103},([_,]*)\$([\x00-\xff]*)/6$1\$$2g/^6_{104},([_,]*)\$([\x00-\xff]*)/6$1\$$2h/^6_{105},([_,]*)\$([\x00-\xff]*)/6$1\$$2i/^6_{106},([_,]*)\$([\x00-\xff]*)/6$1\$$2j/^6_{107},([_,]*)\$([\x00-\xff]*)/6$1\$$2k/^6_{108},([_,]*)\$([\x00-\xff]*)/6$1\$$2l/^6_{109},([_,]*)\$([\x00-\xff]*)/6$1\$$2m/^6_{110},([_,]*)\$([\x00-\xff]*)/6$1\$$2n/^6_{111},([_,]*)\$([\x00-\xff]*)/6$1\$$2o/^6_{112},([_,]*)\$([\x00-\xff]*)/6$1\$$2p/^6_{113},([_,]*)\$([\x00-\xff]*)/6$1\$$2q/^6_{114},([_,]*)\$([\x00-\xff]*)/6$1\$$2r/^6_{115},([_,]*)\$([\x00-\xff]*)/6$1\$$2s/^6_{116},([_,]*)\$([\x00-\xff]*)/6$1\$$2t/^6_{117},([_,]*)\$([\x00-\xff]*)/6$1\$$2u/^6_{118},([_,]*)\$([\x00-\xff]*)/6$1\$$2v/^6_{119},([_,]*)\$([\x00-\xff]*)/6$1\$$2w/^6_{120},([_,]*)\$([\x00-\xff]*)/6$1\$$2x/^6_{121},([_,]*)\$([\x00-\xff]*)/6$1\$$2y/^6_{122},([_,]*)\$([\x00-\xff]*)/6$1\$$2z/^6_{123},([_,]*)\$([\x00-\xff]*)/6$1\$$2{/^6_{124},([_,]*)\$([\x00-\xff]*)/6$1\$$2|/^6_{125},([_,]*)\$([\x00-\xff]*)/6$1\$$2}/^6_{126},([_,]*)\$([\x00-\xff]*)/6$1\$$2~/^6_{127}_*,([_,]*)\$([\x00-\xff]*)/6$1\$$2/^6\$/=/1#input
With Comments
#import math
# Santize Input
# Keeps removing characters from the code that aren't the standard BF chars
^1([^$]*?)[^\[\]<>,.+-]/1$1/
^1([\[\]<>,.+-]*)(\$[^$]*)$/2'$1\$$2/
^1([\[\]<>,.+-]*)$/2'$1\$\$/
# Pair up brackets
# Bit by bit replaces square brackets with parentheticals, counting depth by proceeding them with =, eg.
# [a[b]c] becomes [a=[b=]c]
# This is vital for loops later.
^2([^$]*)'([()<>,.+-])/2$1$2'/
^2([^()$]*)'\[/2$1'\(/
^2([^()$]*)'\]/2$1'/
^2([^$]*?)(=*)\(([^()$]*)'\[/2$1$2($3$2=('/
^2([^$]*?)(=*)\(([^()$]*)'\]/2$1$2($3$2)'/
^2([^$]*?)(=*)=\)([^()$]*)'\]/2$1$2=)$3$2)'/
^2([^$]*?)(=*)\)([^()$]*)'\[/2$1$2)$3$2('/
# Afterwards, sets up the memory in the form of:
# 3aTAPE$CODE$OUTPUT$INPUT
^2([^']*)'\$/3'\$'$1\$/
# Alternator. This increments the instruction pointer by one after an instruction is ran.
# We use the states 3a and 3b to ensure exactly one instruction is run per tick
^4([_,']*\$[^']*)'([^$])/3$1$2'/
# +
^3([_,]*)'([^$]*)\$([^']*)'\+/4$1'_$2\$$3'+/
_{256}//
# - Has to manually wrap.
^3([_,]*)'_([^$]*)\$([^']*)'-/4$1'$2\$$3'-/
^3([_,]*)'(?=[^_])([^$]*)\$([^']*)'-/4$1'u<255>$2\$$3'-/
# >
^3([_,]*)'(_*),?([_,]*)\$([^']*)'>/4$1$2,'$3\$$4'>/
# <
^3([_,]*?)(_*),?'([_,]*)\$([^']*)'</4$1'$2,$3\$$4'</
# .
^3([_,]*?)'(_*)([_,]*)\$([^']*)'\.([^$]*)\$([^$]*)/4$1'$2$3\$$4'.$5\$$6$2,/
# ,
^3([_,]*?)'(_*)([_,]*)\$([^']*)',([^$]*\$[^$]*)\$([\x00-\xFF])/5$1':$6$3\$$4',$5\$/
^3([_,]*?)'(_*)([_,]*)\$([^']*)',([^$]*\$[^$]*)\$$/4$1'$3\$$4',$5\$/
^5([_,]*)':\x00/4$1'u<$i>/
^5([_,]*)':\x01/4$1'u<$i>/
^5([_,]*)':\x02/4$1'u<$i>/
^5([_,]*)':\x03/4$1'u<$i>/
^5([_,]*)':\x04/4$1'u<$i>/
^5([_,]*)':\x05/4$1'u<$i>/
^5([_,]*)':\x06/4$1'u<$i>/
^5([_,]*)':\x07/4$1'u<$i>/
^5([_,]*)':\x08/4$1'u<$i>/
^5([_,]*)':\x09/4$1'u<$i>/
^5([_,]*)':\x0A/4$1'u<$i>/
^5([_,]*)':\x0B/4$1'u<$i>/
^5([_,]*)':\x0C/4$1'u<$i>/
^5([_,]*)':\x0D/4$1'u<$i>/
^5([_,]*)':\x0E/4$1'u<$i>/
^5([_,]*)':\x0F/4$1'u<$i>/
^5([_,]*)':\x10/4$1'u<$i>/
^5([_,]*)':\x11/4$1'u<$i>/
^5([_,]*)':\x12/4$1'u<$i>/
^5([_,]*)':\x13/4$1'u<$i>/
^5([_,]*)':\x14/4$1'u<$i>/
^5([_,]*)':\x15/4$1'u<$i>/
^5([_,]*)':\x16/4$1'u<$i>/
^5([_,]*)':\x17/4$1'u<$i>/
^5([_,]*)':\x18/4$1'u<$i>/
^5([_,]*)':\x19/4$1'u<$i>/
^5([_,]*)':\x1A/4$1'u<$i>/
^5([_,]*)':\x1B/4$1'u<$i>/
^5([_,]*)':\x1C/4$1'u<$i>/
^5([_,]*)':\x1D/4$1'u<$i>/
^5([_,]*)':\x1E/4$1'u<$i>/
^5([_,]*)':\x1F/4$1'u<$i>/
^5([_,]*)':\x20/4$1'u<$i>/
^5([_,]*)':\x21/4$1'u<$i>/
^5([_,]*)':\x22/4$1'u<$i>/
^5([_,]*)':\x23/4$1'u<$i>/
^5([_,]*)':\x24/4$1'u<$i>/
^5([_,]*)':\x25/4$1'u<$i>/
^5([_,]*)':\x26/4$1'u<$i>/
^5([_,]*)':\x27/4$1'u<$i>/
^5([_,]*)':\x28/4$1'u<$i>/
^5([_,]*)':\x29/4$1'u<$i>/
^5([_,]*)':\x2A/4$1'u<$i>/
^5([_,]*)':\x2B/4$1'u<$i>/
^5([_,]*)':\x2C/4$1'u<$i>/
^5([_,]*)':\x2D/4$1'u<$i>/
^5([_,]*)':\x2E/4$1'u<$i>/
^5([_,]*)':\x2F/4$1'u<$i>/
^5([_,]*)':\x30/4$1'u<$i>/
^5([_,]*)':\x31/4$1'u<$i>/
^5([_,]*)':\x32/4$1'u<$i>/
^5([_,]*)':\x33/4$1'u<$i>/
^5([_,]*)':\x34/4$1'u<$i>/
^5([_,]*)':\x35/4$1'u<$i>/
^5([_,]*)':\x36/4$1'u<$i>/
^5([_,]*)':\x37/4$1'u<$i>/
^5([_,]*)':\x38/4$1'u<$i>/
^5([_,]*)':\x39/4$1'u<$i>/
^5([_,]*)':\x3A/4$1'u<$i>/
^5([_,]*)':\x3B/4$1'u<$i>/
^5([_,]*)':\x3C/4$1'u<$i>/
^5([_,]*)':\x3D/4$1'u<$i>/
^5([_,]*)':\x3E/4$1'u<$i>/
^5([_,]*)':\x3F/4$1'u<$i>/
^5([_,]*)':\x40/4$1'u<$i>/
^5([_,]*)':\x41/4$1'u<$i>/
^5([_,]*)':\x42/4$1'u<$i>/
^5([_,]*)':\x43/4$1'u<$i>/
^5([_,]*)':\x44/4$1'u<$i>/
^5([_,]*)':\x45/4$1'u<$i>/
^5([_,]*)':\x46/4$1'u<$i>/
^5([_,]*)':\x47/4$1'u<$i>/
^5([_,]*)':\x48/4$1'u<$i>/
^5([_,]*)':\x49/4$1'u<$i>/
^5([_,]*)':\x4A/4$1'u<$i>/
^5([_,]*)':\x4B/4$1'u<$i>/
^5([_,]*)':\x4C/4$1'u<$i>/
^5([_,]*)':\x4D/4$1'u<$i>/
^5([_,]*)':\x4E/4$1'u<$i>/
^5([_,]*)':\x4F/4$1'u<$i>/
^5([_,]*)':\x50/4$1'u<$i>/
^5([_,]*)':\x51/4$1'u<$i>/
^5([_,]*)':\x52/4$1'u<$i>/
^5([_,]*)':\x53/4$1'u<$i>/
^5([_,]*)':\x54/4$1'u<$i>/
^5([_,]*)':\x55/4$1'u<$i>/
^5([_,]*)':\x56/4$1'u<$i>/
^5([_,]*)':\x57/4$1'u<$i>/
^5([_,]*)':\x58/4$1'u<$i>/
^5([_,]*)':\x59/4$1'u<$i>/
^5([_,]*)':\x5A/4$1'u<$i>/
^5([_,]*)':\x5B/4$1'u<$i>/
^5([_,]*)':\x5C/4$1'u<$i>/
^5([_,]*)':\x5D/4$1'u<$i>/
^5([_,]*)':\x5E/4$1'u<$i>/
^5([_,]*)':\x5F/4$1'u<$i>/
^5([_,]*)':\x60/4$1'u<$i>/
^5([_,]*)':\x61/4$1'u<$i>/
^5([_,]*)':\x62/4$1'u<$i>/
^5([_,]*)':\x63/4$1'u<$i>/
^5([_,]*)':\x64/4$1'u<$i>/
^5([_,]*)':\x65/4$1'u<$i>/
^5([_,]*)':\x66/4$1'u<$i>/
^5([_,]*)':\x67/4$1'u<$i>/
^5([_,]*)':\x68/4$1'u<$i>/
^5([_,]*)':\x69/4$1'u<$i>/
^5([_,]*)':\x6A/4$1'u<$i>/
^5([_,]*)':\x6B/4$1'u<$i>/
^5([_,]*)':\x6C/4$1'u<$i>/
^5([_,]*)':\x6D/4$1'u<$i>/
^5([_,]*)':\x6E/4$1'u<$i>/
^5([_,]*)':\x6F/4$1'u<$i>/
^5([_,]*)':\x70/4$1'u<$i>/
^5([_,]*)':\x71/4$1'u<$i>/
^5([_,]*)':\x72/4$1'u<$i>/
^5([_,]*)':\x73/4$1'u<$i>/
^5([_,]*)':\x74/4$1'u<$i>/
^5([_,]*)':\x75/4$1'u<$i>/
^5([_,]*)':\x76/4$1'u<$i>/
^5([_,]*)':\x77/4$1'u<$i>/
^5([_,]*)':\x78/4$1'u<$i>/
^5([_,]*)':\x79/4$1'u<$i>/
^5([_,]*)':\x7A/4$1'u<$i>/
^5([_,]*)':\x7B/4$1'u<$i>/
^5([_,]*)':\x7C/4$1'u<$i>/
^5([_,]*)':\x7D/4$1'u<$i>/
^5([_,]*)':\x7E/4$1'u<$i>/
^5([_,]*)':\x7F/4$1'u<$i>/
^5([_,]*)':\x80/4$1'u<$i>/
^5([_,]*)':\x81/4$1'u<$i>/
^5([_,]*)':\x82/4$1'u<$i>/
^5([_,]*)':\x83/4$1'u<$i>/
^5([_,]*)':\x84/4$1'u<$i>/
^5([_,]*)':\x85/4$1'u<$i>/
^5([_,]*)':\x86/4$1'u<$i>/
^5([_,]*)':\x87/4$1'u<$i>/
^5([_,]*)':\x88/4$1'u<$i>/
^5([_,]*)':\x89/4$1'u<$i>/
^5([_,]*)':\x8A/4$1'u<$i>/
^5([_,]*)':\x8B/4$1'u<$i>/
^5([_,]*)':\x8C/4$1'u<$i>/
^5([_,]*)':\x8D/4$1'u<$i>/
^5([_,]*)':\x8E/4$1'u<$i>/
^5([_,]*)':\x8F/4$1'u<$i>/
^5([_,]*)':\x90/4$1'u<$i>/
^5([_,]*)':\x91/4$1'u<$i>/
^5([_,]*)':\x92/4$1'u<$i>/
^5([_,]*)':\x93/4$1'u<$i>/
^5([_,]*)':\x94/4$1'u<$i>/
^5([_,]*)':\x95/4$1'u<$i>/
^5([_,]*)':\x96/4$1'u<$i>/
^5([_,]*)':\x97/4$1'u<$i>/
^5([_,]*)':\x98/4$1'u<$i>/
^5([_,]*)':\x99/4$1'u<$i>/
^5([_,]*)':\x9A/4$1'u<$i>/
^5([_,]*)':\x9B/4$1'u<$i>/
^5([_,]*)':\x9C/4$1'u<$i>/
^5([_,]*)':\x9D/4$1'u<$i>/
^5([_,]*)':\x9E/4$1'u<$i>/
^5([_,]*)':\x9F/4$1'u<$i>/
^5([_,]*)':\xA0/4$1'u<$i>/
^5([_,]*)':\xA1/4$1'u<$i>/
^5([_,]*)':\xA2/4$1'u<$i>/
^5([_,]*)':\xA3/4$1'u<$i>/
^5([_,]*)':\xA4/4$1'u<$i>/
^5([_,]*)':\xA5/4$1'u<$i>/
^5([_,]*)':\xA6/4$1'u<$i>/
^5([_,]*)':\xA7/4$1'u<$i>/
^5([_,]*)':\xA8/4$1'u<$i>/
^5([_,]*)':\xA9/4$1'u<$i>/
^5([_,]*)':\xAA/4$1'u<$i>/
^5([_,]*)':\xAB/4$1'u<$i>/
^5([_,]*)':\xAC/4$1'u<$i>/
^5([_,]*)':\xAD/4$1'u<$i>/
^5([_,]*)':\xAE/4$1'u<$i>/
^5([_,]*)':\xAF/4$1'u<$i>/
^5([_,]*)':\xB0/4$1'u<$i>/
^5([_,]*)':\xB1/4$1'u<$i>/
^5([_,]*)':\xB2/4$1'u<$i>/
^5([_,]*)':\xB3/4$1'u<$i>/
^5([_,]*)':\xB4/4$1'u<$i>/
^5([_,]*)':\xB5/4$1'u<$i>/
^5([_,]*)':\xB6/4$1'u<$i>/
^5([_,]*)':\xB7/4$1'u<$i>/
^5([_,]*)':\xB8/4$1'u<$i>/
^5([_,]*)':\xB9/4$1'u<$i>/
^5([_,]*)':\xBA/4$1'u<$i>/
^5([_,]*)':\xBB/4$1'u<$i>/
^5([_,]*)':\xBC/4$1'u<$i>/
^5([_,]*)':\xBD/4$1'u<$i>/
^5([_,]*)':\xBE/4$1'u<$i>/
^5([_,]*)':\xBF/4$1'u<$i>/
^5([_,]*)':\xC0/4$1'u<$i>/
^5([_,]*)':\xC1/4$1'u<$i>/
^5([_,]*)':\xC2/4$1'u<$i>/
^5([_,]*)':\xC3/4$1'u<$i>/
^5([_,]*)':\xC4/4$1'u<$i>/
^5([_,]*)':\xC5/4$1'u<$i>/
^5([_,]*)':\xC6/4$1'u<$i>/
^5([_,]*)':\xC7/4$1'u<$i>/
^5([_,]*)':\xC8/4$1'u<$i>/
^5([_,]*)':\xC9/4$1'u<$i>/
^5([_,]*)':\xCA/4$1'u<$i>/
^5([_,]*)':\xCB/4$1'u<$i>/
^5([_,]*)':\xCC/4$1'u<$i>/
^5([_,]*)':\xCD/4$1'u<$i>/
^5([_,]*)':\xCE/4$1'u<$i>/
^5([_,]*)':\xCF/4$1'u<$i>/
^5([_,]*)':\xD0/4$1'u<$i>/
^5([_,]*)':\xD1/4$1'u<$i>/
^5([_,]*)':\xD2/4$1'u<$i>/
^5([_,]*)':\xD3/4$1'u<$i>/
^5([_,]*)':\xD4/4$1'u<$i>/
^5([_,]*)':\xD5/4$1'u<$i>/
^5([_,]*)':\xD6/4$1'u<$i>/
^5([_,]*)':\xD7/4$1'u<$i>/
^5([_,]*)':\xD8/4$1'u<$i>/
^5([_,]*)':\xD9/4$1'u<$i>/
^5([_,]*)':\xDA/4$1'u<$i>/
^5([_,]*)':\xDB/4$1'u<$i>/
^5([_,]*)':\xDC/4$1'u<$i>/
^5([_,]*)':\xDD/4$1'u<$i>/
^5([_,]*)':\xDE/4$1'u<$i>/
^5([_,]*)':\xDF/4$1'u<$i>/
^5([_,]*)':\xE0/4$1'u<$i>/
^5([_,]*)':\xE1/4$1'u<$i>/
^5([_,]*)':\xE2/4$1'u<$i>/
^5([_,]*)':\xE3/4$1'u<$i>/
^5([_,]*)':\xE4/4$1'u<$i>/
^5([_,]*)':\xE5/4$1'u<$i>/
^5([_,]*)':\xE6/4$1'u<$i>/
^5([_,]*)':\xE7/4$1'u<$i>/
^5([_,]*)':\xE8/4$1'u<$i>/
^5([_,]*)':\xE9/4$1'u<$i>/
^5([_,]*)':\xEA/4$1'u<$i>/
^5([_,]*)':\xEB/4$1'u<$i>/
^5([_,]*)':\xEC/4$1'u<$i>/
^5([_,]*)':\xED/4$1'u<$i>/
^5([_,]*)':\xEE/4$1'u<$i>/
^5([_,]*)':\xEF/4$1'u<$i>/
^5([_,]*)':\xF0/4$1'u<$i>/
^5([_,]*)':\xF1/4$1'u<$i>/
^5([_,]*)':\xF2/4$1'u<$i>/
^5([_,]*)':\xF3/4$1'u<$i>/
^5([_,]*)':\xF4/4$1'u<$i>/
^5([_,]*)':\xF5/4$1'u<$i>/
^5([_,]*)':\xF6/4$1'u<$i>/
^5([_,]*)':\xF7/4$1'u<$i>/
^5([_,]*)':\xF8/4$1'u<$i>/
^5([_,]*)':\xF9/4$1'u<$i>/
^5([_,]*)':\xFA/4$1'u<$i>/
^5([_,]*)':\xFB/4$1'u<$i>/
^5([_,]*)':\xFC/4$1'u<$i>/
^5([_,]*)':\xFD/4$1'u<$i>/
^5([_,]*)':\xFE/4$1'u<$i>/
^5([_,]*)':\xFF/4$1'u<$i>/
# [
^3([_,]*)'(_+)([,_]*)\$([^']*)'(=*)\(/4$1'$2$3\$$4$5'(/
^3([_,]*)'(?!_)([,_]*)\$([^']*)'(=*)\(([^$]*?)(?<!=)\4\)/4$1'$2\$$3$4($5$4')/
# ]
^3([_,]*)'(_+)([,_]*)\$([^']*)(?<!=)(=*)\(([^']*?)'\5\)/4$1'$2$3\$$4$5'($6$5)/
^3([_,]*)'(?!_)([,_]*)\$([^']*)(?<!=)(=*)\(([^']*?)'\4\)/4$1'$2\$$3$4($5$4')/
# Move to output finalization
^3['_,]*\$[^$]*'\$([_,]*)\$[^\x00-\xFF]*$/6$1\$/
^6_{0,31},([_,]*)\$([\x00-\xff]*)/6$1\$$2/
^6_{32},([_,]*)\$([\x00-\xff]*)/6$1\$$2 /
^6_{33},([_,]*)\$([\x00-\xff]*)/6$1\$$2!/
^6_{34},([_,]*)\$([\x00-\xff]*)/6$1\$$2"/
^6_{35},([_,]*)\$([\x00-\xff]*)/6$1\$$2\#/
^6_{36},([_,]*)\$([\x00-\xff]*)/6$1\$$2\$/
^6_{37},([_,]*)\$([\x00-\xff]*)/6$1\$$2%/
^6_{38},([_,]*)\$([\x00-\xff]*)/6$1\$$2&/
^6_{39},([_,]*)\$([\x00-\xff]*)/6$1\$$2'/
^6_{40},([_,]*)\$([\x00-\xff]*)/6$1\$$2(/
^6_{41},([_,]*)\$([\x00-\xff]*)/6$1\$$2)/
^6_{42},([_,]*)\$([\x00-\xff]*)/6$1\$$2*/
^6_{43},([_,]*)\$([\x00-\xff]*)/6$1\$$2+/
^6_{44},([_,]*)\$([\x00-\xff]*)/6$1\$$2,/
^6_{45},([_,]*)\$([\x00-\xff]*)/6$1\$$2-/
^6_{46},([_,]*)\$([\x00-\xff]*)/6$1\$$2./
^6_{47},([_,]*)\$([\x00-\xff]*)/6$1\$$2\//
^6_{48},([_,]*)\$([\x00-\xff]*)/6$1\$$20/
^6_{49},([_,]*)\$([\x00-\xff]*)/6$1\$$21/
^6_{50},([_,]*)\$([\x00-\xff]*)/6$1\$$22/
^6_{51},([_,]*)\$([\x00-\xff]*)/6$1\$$23/
^6_{52},([_,]*)\$([\x00-\xff]*)/6$1\$$24/
^6_{53},([_,]*)\$([\x00-\xff]*)/6$1\$$25/
^6_{54},([_,]*)\$([\x00-\xff]*)/6$1\$$26/
^6_{55},([_,]*)\$([\x00-\xff]*)/6$1\$$27/
^6_{56},([_,]*)\$([\x00-\xff]*)/6$1\$$28/
^6_{57},([_,]*)\$([\x00-\xff]*)/6$1\$$29/
^6_{58},([_,]*)\$([\x00-\xff]*)/6$1\$$2:/
^6_{59},([_,]*)\$([\x00-\xff]*)/6$1\$$2;/
^6_{60},([_,]*)\$([\x00-\xff]*)/6$1\$$2</
^6_{61},([_,]*)\$([\x00-\xff]*)/6$1\$$2=/
^6_{62},([_,]*)\$([\x00-\xff]*)/6$1\$$2>/
^6_{63},([_,]*)\$([\x00-\xff]*)/6$1\$$2?/
^6_{64},([_,]*)\$([\x00-\xff]*)/6$1\$$2@/
^6_{65},([_,]*)\$([\x00-\xff]*)/6$1\$$2A/
^6_{66},([_,]*)\$([\x00-\xff]*)/6$1\$$2B/
^6_{67},([_,]*)\$([\x00-\xff]*)/6$1\$$2C/
^6_{68},([_,]*)\$([\x00-\xff]*)/6$1\$$2D/
^6_{69},([_,]*)\$([\x00-\xff]*)/6$1\$$2E/
^6_{70},([_,]*)\$([\x00-\xff]*)/6$1\$$2F/
^6_{71},([_,]*)\$([\x00-\xff]*)/6$1\$$2G/
^6_{72},([_,]*)\$([\x00-\xff]*)/6$1\$$2H/
^6_{73},([_,]*)\$([\x00-\xff]*)/6$1\$$2I/
^6_{74},([_,]*)\$([\x00-\xff]*)/6$1\$$2J/
^6_{75},([_,]*)\$([\x00-\xff]*)/6$1\$$2K/
^6_{76},([_,]*)\$([\x00-\xff]*)/6$1\$$2L/
^6_{77},([_,]*)\$([\x00-\xff]*)/6$1\$$2M/
^6_{78},([_,]*)\$([\x00-\xff]*)/6$1\$$2N/
^6_{79},([_,]*)\$([\x00-\xff]*)/6$1\$$2O/
^6_{80},([_,]*)\$([\x00-\xff]*)/6$1\$$2P/
^6_{81},([_,]*)\$([\x00-\xff]*)/6$1\$$2Q/
^6_{82},([_,]*)\$([\x00-\xff]*)/6$1\$$2R/
^6_{83},([_,]*)\$([\x00-\xff]*)/6$1\$$2S/
^6_{84},([_,]*)\$([\x00-\xff]*)/6$1\$$2T/
^6_{85},([_,]*)\$([\x00-\xff]*)/6$1\$$2U/
^6_{86},([_,]*)\$([\x00-\xff]*)/6$1\$$2V/
^6_{87},([_,]*)\$([\x00-\xff]*)/6$1\$$2W/
^6_{88},([_,]*)\$([\x00-\xff]*)/6$1\$$2X/
^6_{89},([_,]*)\$([\x00-\xff]*)/6$1\$$2Y/
^6_{90},([_,]*)\$([\x00-\xff]*)/6$1\$$2Z/
^6_{91},([_,]*)\$([\x00-\xff]*)/6$1\$$2[/
^6_{92},([_,]*)\$([\x00-\xff]*)/6$1\$$2\\/
^6_{93},([_,]*)\$([\x00-\xff]*)/6$1\$$2]/
^6_{94},([_,]*)\$([\x00-\xff]*)/6$1\$$2^/
^6_{95},([_,]*)\$([\x00-\xff]*)/6$1\$$2_/
^6_{96},([_,]*)\$([\x00-\xff]*)/6$1\$$2`/
^6_{97},([_,]*)\$([\x00-\xff]*)/6$1\$$2a/
^6_{98},([_,]*)\$([\x00-\xff]*)/6$1\$$2b/
^6_{99},([_,]*)\$([\x00-\xff]*)/6$1\$$2c/
^6_{100},([_,]*)\$([\x00-\xff]*)/6$1\$$2d/
^6_{101},([_,]*)\$([\x00-\xff]*)/6$1\$$2e/
^6_{102},([_,]*)\$([\x00-\xff]*)/6$1\$$2f/
^6_{103},([_,]*)\$([\x00-\xff]*)/6$1\$$2g/
^6_{104},([_,]*)\$([\x00-\xff]*)/6$1\$$2h/
^6_{105},([_,]*)\$([\x00-\xff]*)/6$1\$$2i/
^6_{106},([_,]*)\$([\x00-\xff]*)/6$1\$$2j/
^6_{107},([_,]*)\$([\x00-\xff]*)/6$1\$$2k/
^6_{108},([_,]*)\$([\x00-\xff]*)/6$1\$$2l/
^6_{109},([_,]*)\$([\x00-\xff]*)/6$1\$$2m/
^6_{110},([_,]*)\$([\x00-\xff]*)/6$1\$$2n/
^6_{111},([_,]*)\$([\x00-\xff]*)/6$1\$$2o/
^6_{112},([_,]*)\$([\x00-\xff]*)/6$1\$$2p/
^6_{113},([_,]*)\$([\x00-\xff]*)/6$1\$$2q/
^6_{114},([_,]*)\$([\x00-\xff]*)/6$1\$$2r/
^6_{115},([_,]*)\$([\x00-\xff]*)/6$1\$$2s/
^6_{116},([_,]*)\$([\x00-\xff]*)/6$1\$$2t/
^6_{117},([_,]*)\$([\x00-\xff]*)/6$1\$$2u/
^6_{118},([_,]*)\$([\x00-\xff]*)/6$1\$$2v/
^6_{119},([_,]*)\$([\x00-\xff]*)/6$1\$$2w/
^6_{120},([_,]*)\$([\x00-\xff]*)/6$1\$$2x/
^6_{121},([_,]*)\$([\x00-\xff]*)/6$1\$$2y/
^6_{122},([_,]*)\$([\x00-\xff]*)/6$1\$$2z/
^6_{123},([_,]*)\$([\x00-\xff]*)/6$1\$$2{/
^6_{124},([_,]*)\$([\x00-\xff]*)/6$1\$$2|/
^6_{125},([_,]*)\$([\x00-\xff]*)/6$1\$$2}/
^6_{126},([_,]*)\$([\x00-\xff]*)/6$1\$$2~/
^6_{127}_*,([_,]*)\$([\x00-\xff]*)/6$1\$$2/
# Finalize output. For reasonable outputs, this can be blanked. To prevent re-interpreting, intentionally prepends a =
^6\$/=/
1#input
This behemoth of ReRegex code is a true torture test for the language.
Takes input after the $ character, Supports the full byte range on inputs, though is limited to printable ascii for outputs due to a limitation of the Java version used to run ReRegex.
Takes a couple seconds to run the simple Hello World, over a minute to run the golfed version, and primes to 15 is still running...
C (gcc) Linux x86_64, 884 621 525 487 439 383 358 347 bytes
*z,*mmap();d[7500];h;(*p)();*j(char*a){char*t=a,*n,c,q=0;for(;read(h,&c,!q);t=c==47?n=j(t+9),z=mempcpy(t,L"\xf003e80Ƅ",5),*z=n-t-9,n:c==49?q=*t++=233,z=t,*z=a-13-t,z+1:stpcpy(t,c-18?c-16?~c?c-1?c-2?c?t:"1\xc0P_\xF\5":"RXR_\xF\5":L"":L"۾":L"컿":L"웿"))c-=44;return t;}main(P,g)int**g;{*j(p=mmap(0,1<<20,6,34,h=open(g[1],0),0))=195;p(0,d,1);}
This is a JIT that compiles BF code into x86_64 machine language at runtime. This performs a straight translation so commonly occurring sequences such as >>>, <<<, +++ and --- aren't coalesced into faster instructions.
Less golfed version:
// size of data area
*z,c,*mmap();d[7500];h;(*p)();
// recursive function translates BF commands to x86_64 instructions
*j(char*a){
char*t=a,*n,q=0;
for(;read(h,&c,!q);)
c-=44,
t=c==47? // [
// cmpb $0x0,(%rsi)
// je n-t-9
n=j(t+9),
z=mempcpy(t,L"\xf003e80Ƅ",5),
*z=n-t-9,
n
:
c==49? // ]
// jmp a-13-t
q=*t++=233,
z=t,
*z=a-13-t,
z+1
:
stpcpy(t,c-18? // >
c-16? // <
~c? // +
c-1? // -
c-2? // .
c? // ,
""
:
// xor %eax,%eax
// push %rax
// pop %rdi
// syscall
"1\xc0P_\xF\5"
:
// push %rdx
// pop %rax
// push %rdx
// pop %rdi
// syscall
"RXR_\xF\5"
:
// decb (%rsi)
L""
:
// incb (%rsi)
L"۾"
:
// dec %esi
L"컿"
:
// inc %esi
L"웿");
return t;
}
main(P,g)int**g;{
// allocate text (executable) memory and mark as executable
p=mmap(0,1<<20,6,34,h=open(g[1],0),0);
// run JIT, set %rdx=1 and call code like a function
p(*j(p)=195,d,1);
}
ABPL: 303 bytes
{c0↓{αβ~# c↑0≠}{{"["=}{c↓1+↑}I{"]"=}{c↓1-↑}I}æ}wloop↓
"+++[->+++<]>."code↓0,30000~Am↓0p↑
{β~λα↓≠}{{βα~#"+"=}{m↓p↓~#1+m↓~^p↓~^~%m↑&}I{βα~#"-"=}{m↓p↓~#1-m↓~^p↓~^~%m↑&}I{βα~#"<"=}{p↓1-30000%}I{βα~#">"=}{p↓1+30000%}I{βα~#"["=}{wloop! αβ;}{βα~#"."=}{m↓p↓~#→}I{βα~#","=}{m↓p↓~#←m↓~^p↓~^~%m↑}I}W```
Lua, 353 bytes
Doesn't beat the other working Lua solution which transpiles the entire source to Lua, then runs that rather than doing the mish-mash this one does; very inefficient due to the use of heavy pattern matching for finding matching brackets concisely.
s=io.open(...):read"*a"f="if(d[p]or 0)%s0 then i=%s end"d={}p=1 i=1 while#s>i do load(({[43]="d[p]=(d[p]or 0)+1",[45]="d[p]=(d[p]or 0)-1",[60]="p=p-1",[62]="p=p+1",[46]="io.write(string.char(d[p]or 0))",[44]="d[p]=io.read(1):byte()",[91]=f:format("==","s:find('^%b[]()',i)-1"),[93]=f:format(">","s:sub(1,i):find('()%b[]$')")})[s:byte(i)]or"")()i=i+1 end
Or with some formatting:
s=io.open(...):read"*a"
f="if(d[p]or 0)%s0 then i=%s end"
g=""d={}p=1
i=1
while#s>i do
load(({
[43]="d[p]=(d[p]or 0)+1",
[45]="d[p]=(d[p]or 0)-1",
[60]="p=p-1",
[62]="p=p+1",
[46]="io.write(string.char(d[p]or 0))",
[44]="d[p]=io.read(1):byte()",
[91]=f:format("==","s:find('^%b[]()',i)-1"),
[93]=f:format(">","s:sub(1,i):find('()%b[]$')")
})[s:byte(i)]or"")()i=i+1
end
Go, 377 bytes
I just had to Golf this. Straightforward implementation; leverages constraints (no overflows, no bad instructions), prime finder works as expected. Takes path to Brainfuck program as first argument and input over stdin.
package main
import."os"
func main(){
var t[30000]uint8
d,i,s:=0,0,[]byte{0}
c,_:=ReadFile(Args[1])
for;i<len(c);i++{m:=func(j int){b:=j
for b!=0{i+=j
switch c[i]{case'[':b++
case']':b--}}}
switch c[i]{case',':Stdin.Read(s);t[d]=s[0]
case'.':s[0]=t[d];Stdout.Write(s)
case'<':d--
case'>':d++
case'+':t[d]++
case'-':t[d]--
case '[':if t[d]==0{m(1)}
case ']':if t[d]!=0{m(-1)}}}}
ASCII FALSE, 365 bytes
Takes Brainfuck program and input separated by $ ("end of Brainfuck"); very slow (replacing a cell is a linear time operation with bad constant factors; loops search for the matching bracket each time they are executed). Could be optimized by (1) doing peephole optimizations on most commands, most notably stripping loops, memorizing loop targets and compressing sequences of +/- into single instructions (2) using binary trees as the array representation, giving better O(log n) modification time (much more complex; requires managing binary trees, and basic GC if no memory is to be leaked).
EOF is all ones (255; it's unclear what "no EOF symbol" is supposed to mean). Overflow being undefined behavior is taken advantage of. The pointer not over/underflowing is taken advantage of as well.
Runs "hello world" correctly as well as the prime finder, though it is very inefficient (as expected). I recommend first stripping the prime finder of comments, then appending $<small number>:
>++++++++[<++++++++>-]<++++++++++++++++.[-]>++++++++++[<++++++++++>-]<++++++++++++++.[-]>++++++++++[<++++++++++>-]<+++++.[-]>++++++++++[<++++++++++>-]<+++++++++.[-]>++++++++++[<++++++++++>-]<+.[-]>++++++++++[<++++++++++>-]<+++++++++++++++.[-]>+++++[<+++++>-]<+++++++.[-]>++++++++++[<++++++++++>-]<+++++++++++++++++.[-]>++++++++++[<++++++++++>-]<++++++++++++.[-]>+++++[<+++++>-]<+++++++.[-]>++++++++++[<++++++++++>-]<++++++++++++++++.[-]>++++++++++[<++++++++++>-]<+++++++++++.[-]>+++++++[<+++++++>-]<+++++++++.[-]>+++++[<+++++>-]<+++++++.[-]+[->,----------[<+>-------------------------------------->[>+>+<<-]>>[<<+>>-]<>>>+++++++++[<<<[>+>+<<-]>>[<<+>>-]<[<<+>>-]>>-]<<<[-]<<[>+<-]]<]>>[<<+>>-]<<>+<-[>+[>+>+<<-]>>[<<+>>-]<>+<-->>>>>>>>+<<<<<<<<[>+<-<[>>>+>+<<<<-]>>>>[<<<<+>>>>-]<<<>[>>+>+<<<-]>>>[<<<+>>>-]<<<<>>>[>+>+<<-]>>[<<+>>-]<<<[>>>>>+<<<[>+>+<<-]>>[<<+>>-]<[>>[-]<<-]>>[<<<<[>+>+<<-]>>[<<+>>-]<>>>-]<<<-<<-]+>>[<<[-]>>-]<<>[-]<[>>>>>>[-]<<<<<<-]<<>>[-]>[-]<<<]>>>>>>>>[-<<<<<<<[-]<<[>>+>+<<<-]>>>[<<<+>>>-]<<<>>[>+<-]>[[>+>+<<-]>>[<<+>>-]<>+++++++++<[>>>+<<[>+>[-]<<-]>[<+>-]>[<<++++++++++>>-]<<-<-]+++++++++>[<->-]<[>+<-]<[>+<-]<[>+<-]>>>[<<<+>>>-]<>+++++++++<[>>>+<<[>+>[-]<<-]>[<+>-]>[<<++++++++++>>>+<-]<<-<-]>>>>[<<<<+>>>>-]<<<<>[-]<<+>]<[[>+<-]+++++++[<+++++++>-]<-><.[-]>>[<<+>>-]<<-]>++++[<++++++++>-]<.[-]>>>>>>>]<<<<<<<<>[-]<[-]<<-]++++++++++.[-]
$20
This runs in about 1s for me, producing
Primes up to: 2 3 5 7 11 13 17 19
(Since input is given after the program in stdin, the number "up to" which primes are printed is of course missing from the output; this could be addressed by outputting all read characters (insert $, after ^), if desired.)
Note: This is ASCII FALSE, using O instead of ø (if ø were to be used instead, it would be a couple bytes longer) and B instead of ß (buffering is not relevant here however). Interpreters for ASCII FALSE can be found here.
Golfed
[n;0=$[%%x;0~]?~[$0=$[% % n;1-n:q;!0 0~]?~[$1&\2/\ $[% q;!2*1|0~]?~[q;!2*]?]?]?]q:0c:[^$'$=~][c;1+c:]#%30000$t:[1-$][0\]#0i:0p:[t;c;+i;-1-O]o:[x:p;n:q;!]s:[o;!$'[=[b;1+b:]?']=[b;1-b:]?]j:[c;i;>][o;!k:k;'.=[p;O,]?k;',=[^255&s;!]?k;'>=[p;1+p:]?k;'<=[p;1-p:]?k;'+=[p;O1+s;!]?k;'-=[p;O1-s;!]?k;'[=[p;O0=[1b:[b;][i;1+i:j;!]#]?]?k;']=[p;O[1_b:[b;][i;1-i:j;!]#]?]?i;1+i:]#
There are most probably quite a few more easy golfs possible.
Ungolfed
The core function is q ("shove/splice"), which allows fully using the stack like an array by remembering items on the call stack, then mutating the stack by replacing an element, and then restoring the elements remembered on the call stack. Once we can use the stack as an array, the rest is straightforward.
{
shove/splice (q):
pop n elements, remembering them on the call stack,
then mutate the stack, dropping an item and replacing it with x,
then restore the popped elements
invocation: 101x: 42n: q;!
}
[
n;0=
$[% %x; 0~]?
~[
$0=
$[
% {kill cond}
% {kill dup'd zero on stack}
n; 1- n:
q;!
0 {this is to be left on the stack}
0~
]?
~[
$ 1& {extract lowest bit}
\ 2/ \ {>> 1 thing on stack}
$[
% q;! 2* 1| 0~
]?
~[
q;! 2*
]?
]?
]?
]q:
0c: {# commands}
[^$ '$=~][c;1+c:]# {loop until `$` is encountered, leaves chars on stack}
% {drop '$}
30000$t:[1-$][0\]# {leave 30k 0's on the stack (note: final iteration will leave zeroed counter itself on stack)}
0i: {instruction pointer}
0p: {data pointer (0-based)}
[t;c;+ {depth of stack} i;- 1- O]o: {get (o)p}
[x: p;n: q;!]s: {set item}
[
o;!
$'[=[b;1+b:]?
']=[b;1-b:]?
]j: {count bracket balance}
[c;i;>][
o;! k:
k;'.=[p;O ,]?
k;',=[^ 255& s;!]?
k;'>=[
p;1+p:
]?
k;'<=[
p;1-p:
]?
k;'+=[p;O 1+ s;!]?
k;'-=[p;O 1- s;!]?
k;'[=[
p;O 0=[
1b: {balance}
[b;][
i;1+i:
j;!
]#
]?
]?
k;']=[
p;O [
{analogeous with two small changes}
1_ b: {balance}
[b;][
i;1-i:
j;!
]#
]?
]?
i;1+i:
]#
```
Desmos, 470 bytes
Program input:
- variable \$P\$, containing an array of ASCII codepoints representing the brainfuck program.
- variable \$I\$, also containing an array of ASCII codes for stdin
You can use this program to convert your ASCII to a list of numbers. Unless you like to play the waiting game, I would also recommend that you minify your program
stdout is represented by the array \$O\$. Like \$P\$ and \$I\$, it is also an array of codepoints.
In addition, you can inspect the memory tape in variable \$M\$. The memory consists of 30000 unsigned bytes, though it will only store as many bytes as necessary because storing 30000 bytes is not great for performance.
To begin execution, run the "reset" action and then start the ticker.
Ticker code
\left\{j<=P.length:c,a\right\}
Expression list
O=[]
i=1
k=1
M=[0]
s(x)=M->[\{l=p:\mod(x,256),M[l]\}\for l=[1...M.\length]]
p=1
v=M[p]
w=P[i]
j=1
N=[]
S=[]
a=\{59<w<63:p->p+w-61,w=44:b,42<w<46:s(v+44-w),w=46:O->O.\join(v),w=91:i->\{v=0:N[i],i\}+1,w=93:i->\{v=0:i,N[i]\}+1\},\{w=62:\{30000>p>=M.\length:M->M.\join(0)\}\},\{\{w=91,w=93,0\}=0:i->i+1\}
b=s(I[k]),k->k+1
c=\{P[j]=93:d,N->N.\join(0)\},\{P[j]=91:S->\join(j,S)\},j->j+1
d=N->[\{m=S[1]:j,m=j:S[1],N[m]\}\for m=[1...j]],S->S[2...]
The program loaded in the above TioD is a "Hello, World!" program. The prime number program took around five minutes to print 2 3 5 so I decided that maybe it wasn't the best idea to run it.
How it works
The interpreter first matches up bracket pairs, then scans through the program character-by-character and executes them.
Below is the code for bracket-matching:
j=1
N=[]
S=[]
c=\{P[j]=93:d,N->N.\join(0)\},\{P[j]=91:S->\join(j,S)\},j->j+1
d=N->[\{m=S[1]:j,m=j:S[1],N[m]\}\for m=[1...j]],S->S[2...]
- \$j\$ is a list index, indicating that character \$P[j]\$ is currently being processed
- \$N\$ holds the index of the matching bracket pair, if it exists. If \$N[i]\$ is a positive integer, then \$P[i]\$ matches with \$P[N[i]]\$.
- \$S\$ is a stack containing the indices of all unmatched
[s thus far. The top of the stack is at \$S[1]\$.
Next there are two actions, \$c\$ and \$d\$.
Every time action \$c\$ is run, the next character in the program is processed.
c=\{P[j]=93:d,N->N.\join(0)\},\{P[j]=91:S->\join(j,S)\},j->j+1
c= c is an action containing:
\{ \}, a conditional...
P[j]=93:d, that runs d if P[j]=93 (']')
N->N.\join(0) and appends 0 to N otherwise
\{ \}, a conditional...
P[j]=91: that when P[j]=91 ('[')...
S->\join(j,S) pushes j to S
j->j+1 increment j
\$d\$ is the response to when a ']' character is detected. Because it consists of two actions, it cannot be directly placed in the conditional and thus must be defined separately.
d=N->[\{m=S[1]:j,m=j:S[1],N[m]\}\for m=[1...j]],S->S[2...]
d= d is an action consisting of:
N->[\{ N[m]\}\for m=[1...j]], a modification to N
m=S[1]:j, in which N[S[1]] is set to j
m=j:S[1], and N[j] is set to S[1]
S->S[2...] the topmost value is popped from S
Once bracket pairs are matched the expression is evaluated character-by-character:
i=1
k=1
M=[0]
s(x)=M->[\{l=p:\mod(x,256),M[l]\}\for l=[1...M.\length]]
p=1
v=M[p]
w=P[i]
a=\{59<w<63:p->p+w-61,w=44:b,42<w<46:s(v+44-w),w=46:O->O.\join(v),w=91:i->\{v=0:N[i],i\}+1,w=93:i->\{v=0:i,N[i]\}+1\},\{w=62:\{p=M.\length:M->M.\join(0)\}\},\{\{w=91,w=93,0\}=0:i->i+1\}
b=s(I[k]),k->k+1
- \$i\$ is the instruction pointer
- \$k\$ is the next character to be read in stdout
- \$M\$ is the memory tape
- \$s(x)\$ sets the value of the current cell to \$x\$
- \$p\$ points to the current memory cell
- \$v\$ is the value of the current cell
- \$w\$ is the current instruction
\$a\$ is an action that executes the next character. \$b\$ is a utility for reading from stdin - like \$d\$, \$b\$ is separated because conditional branches only support one action.
\$a\$ is rather long, so here it is branch-by-branch:
a=
\{
59<w<63:p->p+w-61, ><: hack for p±±-ing; 6 bytes smaller than doing it separately
w=44:b, ,: read from stdin (do this before +- to avoid interference)
42<w<46:s(v+44-w), +-: same hack
w=46:O->O.\join(v), .: write to stdout
w=91:i->\{v=0:N[i],i\}+1, [: jump to end if v=0
w=93:i->\{v=0:i,N[i]\}+1 ]: jump to start if v!=0
\},
\{w=62:\{p=M.\length:M->M.\join(0)\}\}, widen memory tape if necessary
\{\{w=91,w=93,0\}=0:i->i+1\} increment instruction pointer if not '[' or ']'
Essentially \$a\$ is a big conditional that performs different actions for different characters, then ties up some loose ends afterwards.
\$b\$, which reads from stdin, is relatively straightforward:
b=s(I[k]),k->k+1
b= b is an action that
s(I[k]), writes the next character from stdin into memory
k->k+1 and increments the character pointer for stdin
Finally, the exection of all of this is controlled by a ticker:
\left\{j<=P.length:c,a\right\}
This ticker will choose between \$a\$ and \$c\$ depending on whether the bracket matching is done or not.
When the input program and stdin are set up and the ticker is run, this program should be able to interpret any brainfuck expression. Just maybe not in a reasonable time frame.
nice-expr, 660 bytes
var f is func(str)none func(var C is str)none{var T is list[int]repeat(0,30001);var p is int;var B is map[int]int;var b is list[int];for var i is int0{var c is str C_i;if c="["then{set b+[i];}else if c="]"then{set B@b_-1is i;set B@i is b_-1;set b is b_0..-1;};set i+1;if i>=len(C)then{break;};};for var i is int0{var c is str C_i;if c=">"then{set p+1;}else if c="<"then{set p-1;}else if c="+"then{set T@p is(T_p)+1;}else if c="-"then{set T@p is(T_p)-1;}else if c="."then{print(char(T_p));}else if c=","then{set T@p is ord(inputchar());}else if c="["and(T_p)=0then{set i is B_i;}else if c="]"and(T_p)!=0then{set i is B_i;};set i+1;if i>=len(C)then{break;};};};
This is a function that takes takes in the brainfuck code as a string.
This certainly can be golfed down; half the code in the solution is only dedicated to pairing up brackets to each other.
Ungolfed Explanation
var interpret is func(str)none func(var code is str)none {
// there are neither 8-bit, nor unsigned, types in nice-expr.
// a list of ints will have to do.
var tape is list[int] repeat(0,30000);
var ptr is int 0; // start on the start of the tape.
var brackets is map[int]int <||>; // keys and values are indexes of brackets.
var bracketStack is list[int] []; // stack that holds left bracket indexes
for var i is int 0 { // first pass: match up brackets
var c is str code_i;
if c = "[" then {
set bracketStack + [i]; // push a left bracket
} else if c = "]" then {
// pop a left bracket
var left is int bracketStack_-1;
set bracketStack is bracketStack_0..-1;
var right is int i;
set brackets@left is right;
set brackets@right is left;
};
set i + 1;
if i >= len(code) then { break; };
};
for var i is int 0 {
var c is str code_i;
if c = ">" then {
set ptr + 1;
} else if c = "<" then {
set ptr - 1;
} else if c = "+" then {
set tape@ptr is (tape_ptr) + 1;
} else if c = "-" then {
set tape@ptr is (tape_ptr) - 1;
} else if c = "." then {
print(char(tape_ptr));
} else if c = "," then {
set tape@ptr is ord(inputchar());
} else if c = "[" and (tape_ptr) = 0 then {
set i is brackets_i; // jump to the matching right bracket
} else if c = "]" and (tape_ptr) != 0 then {
set i is brackets_i; // jump to matching left bracket
};
set i + 1;
if i >= len(code) then { break; };
};
};
Rattle, 234 bytes
\&[0]*199&99&\|!I[g0P4I~n[62P2g+s][60P2g-s][43f6+f5][45f6-f5][46f6,][91f6[0f0]]
[93f6[^0f1]][44g3P5I~nP2f5P5g+s]P4g+sg0I^[~q]g]0;P6g=+s[P4g+f2[91f3]g8[93f4[0f]]]0
;P6g=+s[P4g-f2[93f3]g8[91f4[0f]]]0;sg0I~ns8;P6g+s;P6g-s;r`g1l(~,\);g1P2I~
(without the line breaks)
This is by far Rattle's most complicated program yet.
This takes Brainf*** code as the first line of input and input for the Brainf*** code as the second line of input. Note that Rattle expects the second line to exist even if there is no input for Brainf***.
Here's a similar example except instead of the classic Hello World!, I've modified it to take ! as input but otherwise still output the same thing.
Explanation
This program is a little lengthy to do a full explanation for but here's a much more human-readable version of the program:
\&[0]*199&99&\|!I
[
g0 P4 I~n
[62 g2 + s2]
[60 g2 - s2]
[43 g1 P2 I~ + r` g1 l(~,\)]
[45 g1 P2 I~ - r` g1 l(~,\)]
[46 g1 P2 I~ ,]
[91 g1 P2 I~ [0 f0]]
[93 g1 P2 I~ [^0 f1]]
[44 g3 P5 I~ n r` g1 P2 l(~,\) g5 + s5]
g4 + s4
g0 I^ P4 [~q]
P4g
]0
;g6 =+ s6 [g4 + s4 g0 P4 I~ n s8 [91 g6 + s6] g8 [93 g6 - s6 [0 f]]]0
;g7 =+ s7 [g4 - s4 g0 P4 I~ n s8 [93 g7 + s7] g8 [91 g7 - s7 [0 f]]]0
:(this line and below is just a comment)
data tape values:
0 - code
1 - code data tape
2 - code pointer
3 - input
4 - code command index
5 - input character index
6 - open loop counter
7 - close loop counter
8 - temp
Vyxal, 150 149 148 bytes
k2T0ẋ→_0→0?£{D¥L<|¥i:‛+-$c[:‛ +ḟ←_:_←›Ǔṫ∇∇+J←›ǔ→_|:‛<>$c[:‛ >ḟ←+→|:\.=[←_← iC₴|:\,=[←_:_←?CȦ→_|:\[=[←_← i¬[Ȯ¥$ȯ\]ḟ∇∇+$]|:\]=[Ȯ¥$Ẏf\[=TG‹∇$_]]]]]]]_›
"But there's already a Vyxal answer that's 100 99 98 bytes shorter bro what is this cringe" I hear you say. Well this version doesn't use eval, and instead runs it manually. Note that it can be slow because it's doing things like rotating a 30000 item list quite frequently, so here's a version with only 100 cells for testing
Some assumptions this program makes:
- Closed brackets
- EOF handled manually
- Program on first line, each input character on a new line
Explained
Quick Overview
k2T0ẋ→_ # Tape
0→ # Cell pointer
0 # Instruction pointer
?£ # Prog
{D¥L<| # While the instruction pointer is less than program length
:,←_,¥i # Get command
:‛+-$c[:‛ +ḟ←_:_←›Ǔṫ∇∇+J←›ǔ→_| # Handle addition and subtraction in the same place
:‛<>$c[:‛ >ḟ←+→| # Handle moving the pointer left and right
:\.=[←_← iC,| # Output
:\,=[←_:_←?CȦ→_| # Input
:\[=[ # jump to next `]` if tape[cell] == 0
←_← i¬[Ȯ¥$ȯ:,\]ḟ›∇+$]|
:\]=[Ȯ¥$Ẏf\[=TG›∇$_] # Jump back to the previous `[`
]]]]]]
_ # Remove the char from the stack
› # Next command
}
Detailed Explanation
k2T0ẋ→_
This is the tape. It consists of 30000 0s in a list. It's stored in a global variable called _.
0→
This is the cell pointer. It tracks which cell is being pointed to. It's stored in the ghost variable. The ghost variable is another name for the variable with no name (as in, its name is literally "" - the empty string.)
0
This is the instruction pointer. It tracks which character of the program is being executed. It's stored on the stack as the bottom of the stack. Throughout this answer, the stack is [instruction pointer, current character, ...] where ... is whatever processing is happening in each command.
?£
This gets the program to execute and stores it in the register.
{D¥L<|
This is the main program execution loop. It calls its code while the instruction pointer is less than the length of the program. Before performing the comparison, the instruction pointer is triplicated (i.e. three copies of it are pushed to the stack). This is so that there is a copy for the comparison, for getting the current character in the program and for maintaining the value of the pointer.
¥i
This gets the character at the index of the instruction pointer and puts it on the stack. The stack is now [instruction pointer, command]. We now move on to handling the commands
Addition and Subtraction
:‛+-$c[:‛ +ḟ←_:_←›Ǔṫ∇∇+J←›ǔ→_
The above snippet is the entirety of the section that handles the + and - commands.
:‛+-$c
This checks if the command is in the string "+-", while leaving a copy of the command on the stack for further comparison if needed.
[:‛ +ḟ
If the command is one of + or -, then the command is duplicated yet again, and its index in the string " +" is returned. This returns 1 for + and -1 for -, as -1 is returned for characters not in the string. The 1 or -1 acts as an offset for the current cell, and saves having to check for + and - individually. It also means + can be used for both commands instead of › for addition and ‹ for subtraction.
←_:_←›Ǔ
This pushes the tape (stored in the global variable called _), the value of the cell pointer + 1 (stored in the ghost variable and then incremented) and then rotates the tape left that many times. The :_ after ←_ is needed because there seems to be a bug with list mutability when rotating. (TODO: Fix)
After the rotation, the cell that is to be incremented or decremented is at the tail of the tape.
ṫ∇∇+J
This separates the tail and the rest of the list - first it pushes tape[:-1] and then it pushes tape[-1]. It then rotates the top three items on the stack so that the order is [tape[:-1], tape[-1], offset]. The offset is then added to the tail, and the tail is then appended back to the rest of the tape.
←›ǔ→_
The tape is then rotated cell pointer + 1 times to the right to "undo" the left rotation and then placed back into the global variable called _.
Moving the Cell Pointer
|:‛<>$c[:‛ >ḟ←+→
The above snippet is the entirety of the section that handles the < and > commands.
|:‛<>$c
Just like with the + and - commands, a check is done to see if the command is in the string "<>".
[:‛ >ḟ
And also just like with the + and - commands, if the command is one of < or >, then the command is duplicated yet again, and its index in the string " >" is returned. This returns 1 for > and -1 for <. The 1 or -1 acts as an offset for the current cell location, and saves having to check for < and > individually. It also means + can be used for both commands instead of › for moving right and ‹ for moving left.
←+→
This adds the offset to the cell pointer and updates the value stored in the ghost variable. It also acts as a weird face.
Output
|:\.=[←_← iC₴
The above snippet is the entirety of the section that handles the . command.
|:\.=
This checks if the command is equal to the string ".". Unlike addition/subtraction and cell pointer movement, input and output cannot be handled in the same if-statement, as their functions are different at a fundamental level.
[←_← i
If the command is ., the tape is pushed, as well as the cell pointer's value. The item at the location of the cell pointer is then retrieved. The space after the second ← is needed to avoid it being interpreted as ←i
C₴
This prints that item after converting it to its ASCII equivalent (think chr in python)
Input
|:\,=[←_:_←?CȦ→_
The above snippet is the entirety of the section that handles the , command.
|:\,=
This checks if the command is equal to the string ",".
[←_:_←?C
If the command is ,, the tape and current cell pointer are pushed to the stack, as well as the ordinal value (think ord in python) of the next input.
Ȧ→_
This sets the cell pointerth item of tape to the input. Basically tape[cell_pointer] = ord(input()).
Looping
|:\[=[←_← i0=[Ȯ¥$ȯ\]ḟ∇∇+$]
The above snippet is the entirety of the section that handles the [ command.
|:\[=
The usual check for a certain character. [ this time.
[←_← i
If the command is [, get the cell pointerth item of tape.
¬[
If the cell is not a truthy value (i.e. not 0), then:
Ȯ¥$ȯ\]ḟ
Push program[instruction_pointer:] and find the first ] in that string. The stack is now [instruction pointer, command, position of "]"].
∇∇+$
Rotate the stack so that its order is [command, position of "]", instruction pointer] and add the position of the ] to the instruction pointer. This has the effect of iterating through the program until the next ] is found without having to have lengthy while loops.
|:\]=[Ȯ¥$Ẏf\[=TG‹∇$_
The above snippet is the entirety of the section that handles the ] command.
|:\]=
Check if the command is ]
[Ȯ¥$Ẏf\[=TG
And if it is, get the greatest index of all [s in the string program[0:instruction_pointer]. This has the effect of backtracking to the matching [ without having to have a lengthy while loop.
‹∇$_
Decrement that so that the instruction pointer will be re-incremented to the position of the matching [ and rotate the stack so that the stack order is once again [instruction pointer, command]
Final bits
]]]]]]] # Close all the if statements
_ # Remove the command from the stack
› # Move the instruction pointer forward 1
} # Close the main while loop
TypeScript Types, 1807 1771 bytes
//@ts-ignore
type B<X="\0\x01\x02\x03\x04\x05\x06\x07\b\t\n\v\f\r\x0E\x0F\x10\x11\x12\x13\x14\x15\x16\x17\x18\x19\x1A\x1B\x1C\x1D\x1E\x1F !\"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_`abcdefghijklmnopqrstuvwxyz{|}~\x7F\x80\x81\x82\x83\x84\x85\x86\x87\x88\x89\x8A\x8B\x8C\x8D\x8E\x8F\x90\x91\x92\x93\x94\x95\x96\x97\x98\x99\x9A\x9B\x9C\x9D\x9E\x9F\xa0\xa1\xa2\xa3\xa4\xa5\xa6\xa7\xa8\xa9\xaa\xab\xac\xad\xae\xaf\xb0\xb1\xb2\xb3\xb4\xb5\xb6\xb7\xb8\xb9\xba\xbb\xbc\xbd\xbe\xbf\xc0\xc1\xc2\xc3\xc4\xc5\xc6\xc7\xc8\xc9\xca\xcb\xcc\xcd\xce\xcf\xd0\xd1\xd2\xd3\xd4\xd5\xd6\xd7\xd8\xd9\xda\xdb\xdc\xdd\xde\xdf\xe0\xe1\xe2\xe3\xe4\xe5\xe6\xe7\xe8\xe9\xea\xeb\xec\xed\xee\xef\xf0\xf1\xf2\xf3\xf4\xf5\xf6\xf7\xf8\xf9\xfa\xfb\xfc\xfd\xfe\xff",a=[]>=X extends`${infer A}${infer C}`?B<C,[...a,A]>:a;type C={[K in keyof B&`${number}`as B[K]]:D<K>};type D<T,A=[]>=T extends`${A["length"]}`?A["length"]:D<T,[0,...A]>;type E<A=[]>=255 extends A["length"]?[...A,0]:E<[...A,[...A,0]["length"]]>;type F=[255,0,...E];type G<L,D=never>=L extends[infer A,{}]?A:D;type H<L,D=never>=L extends[{},infer B]?B:D;type M<a,b,c=0,d="",e=0,f=0,g=0,h=0,i=[],>=a extends`${infer j}${infer a}`?h extends 0?j extends"+"?M<a,b,c,d,e,E<[]>[f],g>:j extends"-"?M<a,b,c,d,e,F[f],g>:j extends"<"?e extends 0?M<a,b,c,d,e,f,g>:M<a,b,c,d,H<e>,G<e>,[f,g]>:j extends">"?M<a,b,c,d,[f,e],G<g,0>,H<g,[]>>:j extends"["?f extends 0?M<a,b,c,d,e,f,g,1>:M<a,b,[a,c],d,e,f,g>:j extends"]"?f extends 0?M<a,b,H<c>,d,e,f,g>:M<G<c>,b,c,d,e,f,g>:j extends","?b extends`${infer k}${infer b}`?M<a,b,c,d,e,k extends keyof j?j[k]:0,g>:M<a,b,c,d,e,0,g>:j extends"."?M<a,b,c,`${d}${B[f]}`,e,f,g>:M<a,b,c,d,e,f,g>:j extends"]"?M<a,b,c,d,e,f,g,G<i,0>,H<i,[]>>:j extends"["?M<a,b,c,d,e,f,g,1,[1,i]>:M<a,b,c,d,e,f,g,h,i>:d
JavaScript (ES6), 222 200 197 196 bytes
-19 bytes by stealing the idea of indexOfing from @GezaKerecsenyi's answer.
Takes BF code (b) and input (i) via currying, and returns the output.
b=>i=>eval(`m=Array(3e4).fill(k=p=0);o='';${[...b].map(c=>'m[p]++@m[p]--@p++@p--@while(m[p]){@}@m[p]=i.charCodeAt(k++)|0@o+=String.fromCharCode(m[p])'.split`@`['+-><[],.'.indexOf(c)]).join`;`};o`)
It works by generating a piece of valid JS code from the BF, then evals it. (If you strip away eval, you can see the generated code.)
Technical details
- Tape length: 30000 cells
- Tape left-hand-side: unusable
- Tape wrap-around: no
- Max value:
253-1(JSMAX_SAFE_INTEGER) - Negative numbers: allowed
- EOF:
0(solution with -2 bytes possible by letting EOF corrupt the tape with aNaN)
ARM Thumb-2 Machine code (Linux), 116 bytes
Hexdump (little endian)
9802 2705 df00 f44f 3280 ebad 0d42 4669
2703 df00 466b 1889 2201 cb20 b355 2001
2d3e bf08 3101 2d3c bf08 3901 780e 2d5b
d014 2d5d bf04 bc08 3b04 2d2b bf08 3601
2d2d bf08 3e01 700e 2d2e d101 2704 df00
2d2c d1e2 2000 2703 df00 e7de b10e b408
e7db cb20 2d5d d101 3801 d0d6 2d5b bf08
3001 e7f6
Commented assembly
.syntax unified
.arch armv6t2
.thumb
// The BF program must be saved in UTF-32LE, not ASCII. Use iconv if you have to.
.equ BUFSIZ, 65536 // should be movable
.thumb_func
.globl _start
_start:
// Open the file
// file = open(argv[1], O_RDONLY /* = 0 */)
ldr r0, [sp, #8] // argv[1] is at sp + 8
movs r7, #5 // open
svc #0
// Create a buffer for the file and the tape (todo: improve reg shuffling)
mov r2, #BUFSIZ
sub.w sp, sp, r2, lsl #1 // doubled
// Read into the file
// read(file, insn_ptr, BUFSIZ)
mov r1, sp
movs r7, #3 // read
svc #0
// insn_ptr = sp
mov r3, sp
// tape_ptr = &insn_ptr[BUFSIZ]
adds r1, r2
movs r2, #1 // 1 byte for read/write syscalls
// ----- Interpreter loop ------
.Linterpret:
// insn = *insn_ptr++
ldm r3!, {r5}
// Null terminator
cbz r5, .Lexit
movs r0, #1 // stdout, also loop depth
// > -> right
cmp r5, #'>'
it eq
addeq r1, #1
// < -> left
cmp r5, #'<'
it eq
subeq r1, #1
// Load
ldrb r6, [r1]
// [ -> start
cmp r5, #'['
beq .Ldo_loop // outlined
// ] -> end
cmp r5, #']'
// Pop insn_ptr
itt eq
popeq {r3}
subeq r3, #4
// + -> inc
cmp r5, #'+'
it eq
addeq r6, #1
// - -> dec
cmp r5, #'-'
it eq
subeq r6, #1
// Store
strb r6, [r1]
// . -> print
cmp r5, #'.'
bne .Lnot_dot
.Ldot:
// write(STDOUT_FILENO, tape_ptr, 1)
// r0 is already 1 for stdout.
movs r7, #4 // write
svc #0
.Lnot_dot:
// , -> read
cmp r5, #','
bne .Linterpret
.Lcomma:
// read(STDIN_FILENO, tape_ptr, 1)
movs r0, #0 // stdin
movs r7, #3 // read
svc #0
// Loop
b .Linterpret
// loop handling
.Ldo_loop:
// depth = 1; (from above)
// if (tape_val != 0)
cbz r6, .Ldo_loop.scan
.Ldo_loop.no_jump:
// Push insn_ptr to the call stack and continue
push {r3}
b .Linterpret
// else
// scan for the closing brace and jump.
.Ldo_loop.scan:
ldm r3!, {r5}
// ] -> --depth
cmp r5, #']'
bne .Ldo_loop.not_rb
.Ldo_loop.rb:
// if (--depth == 0) break;
subs r0, #1
beq .Linterpret
.Ldo_loop.not_rb:
// [ -> ++depth
cmp r5, #'['
it eq
addeq r0, #1
b .Ldo_loop.scan
.Lexit:
// segfault like a true chad :D
Notes
- Compiled as
clang --target= arm-linux-gnueabi -nostdlib -static bfarm.s -o bfarm. - The filename of the BF file is passed as the first command line argument.
- The BF file is encoded in UTF-32LE (not ASCII). (This saves 4 bytes thanks to
ldm). The input and output is still through 8-bit bytes though.iconv -f UTF-8 -t UTF-32LE prog.bf > prog.bf32if you need to convert.
- The BF file must be shorter than 65536 bytes (16384 codepoints) long and not contain null codepoints. The size can be configured, though, with some tweaking.
- You get a whopping 65536
u8cells, non-wrapping - Expects the default Linux ELF startup state.
argvis an array atsp + 4- The unused stack memory is clear
- All registers but
spandpcare zeroed
- Segfaults to exit by leaving the end of the
.textsection like a true gigachad. - EOF leaves the cell unchanged.
Python 3.8 (pre-release), 245 237 247 bytes
-8 bytes thanks to Jo King
+10 bytes because input wasn't handled correctly
from sys import*
i,n,*a=[0]*30002
exec('\n'.join([((i:=i+(v:=s=='[')-(s==']'))-v)*' '+'while(a[n]): 0 n-=1 n+=1 a[n]+=1 a[n]-=1 a[n]=ord(stdin.read(1)) print(end=chr(a[n]))'.split()[u.index(s)]for s in open(argv[1]).read()if s in(u:='[]<>+-,.')]))
Compiles bf source code to python and execs.
Scala, 459 bytes
I'd love to see other scala solutions!
The golfed version:
@main def a(n:String)={val t=io.Source.fromFile(n).mkString;var r=t;var p=0;var q=0;val b=Array.fill(30000){0};def f(c:Int)={var l=1;p=r.indexWhere(x=>{l+=Map('['->c,']'-> -c).getOrElse(x,0);l==0},p+1);1<0};def a=p=t.size-1-p;while(t.size!=p){t(p)match{case'+'=>b(q)+=1case'-'=>b(q)-=1case'>'=>q+=1case'<'=>q-=1case'['=>r=t;b(q)==0&&f(1)case']'=>r=t.reverse;a;b(q)!= 0&&f(-1);a case'.'=>print((b(q)&255).toChar)case','=>b(q)=Console.in.read()case _=>0};p+=1}}
The ungolfed version:
@main def evalFromFile(fileName: String) =
val code = io.Source.fromFile(fileName).mkString
val size = code.size
var tempCode = code
var codePtr = 0
var cellPtr = 0
val cells = Array.fill(30_000){0}
def moveLoopPtr(direction: Int) =
var count = 1;
codePtr = tempCode.indexWhere(x => {
count += Map('[' -> direction, ']' -> -direction).getOrElse(x, 0)
count == 0
}, codePtr + 1)
1 > 1
while (code.size != codePtr) {
code(codePtr) match
case '+' => cells(cellPtr) += 1
case '-' => cells(cellPtr) -= 1
case '>' => cellPtr += 1
case '<' => cellPtr -= 1
case '[' =>
tempCode = code;
cells(cellPtr) == 0 && moveLoopPtr(1)
case ']' =>
tempCode = code.reverse
codePtr = code.size - 1 - codePtr
cells(cellPtr) != 0 && moveLoopPtr(-1)
codePtr = code.size - 1 - codePtr
case '.' => print((cells(cellPtr) & 255).toChar)
case ',' => cells(cellPtr) = Console.in.read()
case _ => 0
codePtr += 1
}
Vim, 809 580 bytes
-229 bytes because shenanigans and balderdash.
qq<C-v><C-v><C-v>q<Esc>^mbO<C-r>q
elsei "<C-r>q<C-r>c"=="<Esc>^"xc$<C-r>q
norm <Esc>^"zc$en<C-r>q
<Esc>^"yd$i`b"cyl:if "<C-v><C-r>c"==">"<C-r>z@f<C-r>x<"<C-r>z@b<C-r>x+"<C-r>z@i<C-r>x-"<C-r>z@d<C-r>x,"<C-r>z@p<C-r>x."<C-r>z@o<C-r>x["<C-r>z@s<C-r>x]"<C-r>z@l<C-v>
<C-r>y`blmb@e<Esc>^"ec$`b^mbjj30000ddk30000o0<C-v><Esc>jjmo`lk$d`ox`bjjmp`ljmi`b<Esc>^"rc$`p:if line(".")<30002<C-r>zj<C-v>
<C-r>ymp<Esc>^"fc$`p:if line(".")>3<C-r>zk<C-v>
<C-r>ymp<Esc>^"bc$`p<C-v><C-a>Y:if <C-v><C-r>"<C-v><C-h>>255<C-r>z<C-v><C-x><C-v>
<C-r>y<Esc>^"ic$`p<C-v><C-x>Y:if <C-v><C-r>"<C-v><C-h><0<C-r>z<C-v><C-a><C-v>
<C-r>y<Esc>^"dc$`i"qx`p:if "<C-v><C-r>""!="<C-r>q<Esc>"<C-r>z3xi<C-r>q<C-r>=char2nr("<C-r>q<C-r>q")<C-r>q
<C-r>q<Esc><C-v>
else<C-r>z`i3i<C-v><C-v><Esc>a<C-v><Esc><C-r>q<Esc><C-v>
<C-r>y<Esc>^"pc$`py$`oA<C-v><C-r>=nr2char(<C-v><C-r>")<C-v>
<C-v><Esc>$mo<Esc>^"oc$`py$`b:if <C-v><C-r>"==0<C-r>z%mb<C-v>
<C-r>y<Esc>^"sc$`py$`b:if <C-v><C-r>"!=0<C-r>z%mb<C-v>
<C-r>y<Esc>^"ld$ddo<Esc>90i-<Esc>30000o0<Esc>o<Esc>90i-<Esc>o<Esc>moo<Esc>ml90i-<Esc>o<C-v><Esc><Esc>mio<Esc>90i-<Esc>`bjjmp
More than just an interpreter, this sets up an environment for programming in brainfuck with the following format:
brainfuck program
-------------------------------------------------------------------
list
of
30000
memory
cells
-------------------------------------------------------------------
program output
-------------------------------------------------------------------
program input ^[
-------------------------------------------------------------------
It also sets up some macros:
@f->moves the MP forward@b-<moves the MP backward@i-+increments the cell at the MP@d--decrements the cell at the MP@p-,input a character and store it in the cell at the MP@o-.output the signified by the cell at the MP@s-[startwhileloop@l-]endwhileloop@e- Execute. Recursively get the command at the IP and call the corresponding macro if it is a valid command, then increment the IP.@r- Reset. Clear the output, reset all memory cells, and move the IP back to the beginning of the program.
If using the TIO link, the input box is where the program goes to be executed. To pass input to the brainfuck program, add this to the footer before anything else: `iiYour Input Here<Esc>. Additionally, I added gg30003dd`l3dd to the footer to strip away everything except the brainfuck program's output, so you can remove that from the footer to see the entire result.
If using Vim, copy the TIO code and paste it into Vim to set up the environment. From there, you can use `b to jump to the brainfuck program, `p to jump to the MP, `o to jump to the output, and `i to jump to the input.
A few caveats:
- The environment does not support newlines in the program, so the brainfuck program must be a single line.
- The input must be terminated with
<Esc>. The setup code automatically puts the<Esc>in the input section, so just make sure that the input goes before the^[. - To "read the program from a file", as it were, you can use Vim to open a file containing the brainfuck program and paste this code to set everything up and then execute it, as long as the program is already in a single line.
- It's kinda slow. The test program for finding primes took ~2 minutes to finish with
n=2. It took ~10 minutes withn=7. I didn't even bother trying anything higher. Nevertheless, it works.
Note: This is the second version, and is golfed much further than the original, but I could almost certainly get it even shorter by defining the macros as macros instead of deleting into named registers. However, that will require pretty much rewriting this entire program, which I just golfed into illegibility, so I don't feel like doing it right now, but I might do it some time later.
Duocentehexaquinquagesimal, 260 bytes
5„-^ñ™[fyΛÈÐ\∍ζ=¦δW€ªвƵиˆóδˆ†¦#Ûø“:#”Ù@θý9îæζJ¯иεhlÎà₂âY&т9zì*qI∍`ç∍Šñí¼GÏ0¦R˜#ðžèLÛüûK;Øî“müƶrηÝ'ç0Œ©₆V²_Δ≠tδ<üC/ï„Õ›0aÜ7H:¡°RF®Õ(:3%Yñβù½Sègæ₁„z¹*ôŒ$Ðεüõ<тD8ʒ: óǝÁ¸33ùçUηïZ熧Ëh/Wαï¹AÑÜ׌ޢÍη.ÓAËΩćUQ¯Óƒ‡`EuÈänÖÎo'²₃ĆÄHн
Á3ÞIœæÃλ≠HΛ8ˆÔ„ö|ÐÛ¸Γ>)W₃âf?❮Ìмv₅—ƶζ
C - 306 243 237 235 bytes
This was actually my second ever code golf, and is from a while ago
char m[30000],*p=m,o[30000];i,c;k(v){return v==o[i];}main(x,y)int**y;{for(read(open(y[1],0),o,30000);o[i];i++)if(*(p+=k(62)-k(60))+=k(43)-k(45),x=k(91)-k(93),read(write(1,p,k(46)),p,k(44)),x&&!!*p^!~-x)for(i+=c=x;c+=k(91)-k(93);)i+=x;}
235 by ceilingcat
Rust, 312 bytes
use std::io::*;macro_rules! b{(@+)=>{A[I]+=1;};(@-)=>{A[I]-=1;};(@>)=>{I+=1;};(@<)=>{I-=1;};(@[$($t:tt)*])=>{while A[I]>0{$(b!(@$t);)*}};(@.)=>{print!("{}",A[I]as char);};(@,)=>{stdin().read(&mut A[I..=I]);};(@$t:tt)=>{};($($t:tt)*)=>{static mut A:[u8;30000]=[0;30000];static mut I:usize=0;unsafe{$(b!(@$t);)*}}}
Try it online!
A more readable (and expansionable) version here. A macro that takes in a list of tokens and transforms them into rust code. The code is inputted as rust tokens, so some characters need to have a separator between them, and the most common ones to avoid are the >>, <<, ->, <- and .. operators. If you would like to read the tape after the code's execution the statics generated will still be usable. Also, loops nested 31 or greater deep may run into the recursion limit.
Python 3 (no eval), 288 286 280 bytes
Based on @boothby's solution, but I replaced recursion with loop+stack and made other changes.
from sys import*
s=[];c=open(argv[1]).read();m=[0]*8**5;k=i=0
while i<len(c):
x='+-<>[],.'.find(c[i]);u=x>3;i+=1;d=m[1]
if m[2]<=k:
e=m[d]and x==4;k=m[2]+e;u=1;*s,i=s+[i-1]*e+[i]*(x!=5)
if x==6:m[d]=ord(stdin.read(1))
print(end=chr(m[d]*(x>6)))
m[x%8>>1or d]+=(1-x%2*2)*u
How it works
c- BF code to interpretm- memory, not cyclic (32768 total cells, 3 reserved)i- instruction pointerd- data pointerx- current command (-1 to 7)s- stack of return addressesk- depth at which execution is allowedu- flag: is memory update requirede- flag: should loop be executed or skipped
Cells m[1],m[2], and m[3] are reserved for internal use:
m[1]- actual data pointer,dis just a shortcut.m[2]- depth counter, it increases on[and decreases on]. If depth is more thank, instructions should be ignored: this is how interpreter reaches end of loop when condition is not met (but[and]still count depth).m[3]- trash cell, it increases on.and decreases on,and comments, but its value is never used.
To prevent accidental rewrite, user memory is reverted: it starts at m[0], next is m[-1], then m[-2] and so on.
C# - 373 349 339 335 chars
using C=System.Console;class P{static void Main(string[] z){try{for(dynamic c,p=z[0],a=new int[30000],s=new int[9],f=1>0,i=0,d=0,t=0;;i=c==51&&f&(f|=s[--t]<0)?s[t]:++i){c=p[i]-42;a[d+=(c-19)*(f&c>17&c<21?1:0)]+=(2-c)*(f&c>0&c<4?1:0);if(f&c==4)C.Write((char)a[d]);if(f&c==2)a[d]=C.Read();if(c==49)s[t++]=f?(f=a[d]!=0)?i:-1:i;}}catch{}}}
And more readable:
using C=System.Console;
class P
{
static void Main(string[] z)
{
try
{
for(dynamic c,p=z[0],a=new int[30000],s=new int[9],f=1>0,i=0,d=0,t=0;;i=c==51&&f&(f|=s[--t]<0)?s[t]:++i)
{
c=p[i]-42;
a[d+=(c-19)*(f&c>17&c<21?1:0)]+=(2-c)*(f&c>0&c<4?1:0);
if(f&c==4)C.Write((char)a[d]);
if(f&c==2)a[d]=C.Read();
if(c==49)s[t++]=f?(f=a[d]!=0)?i:-1:i;
}
}
catch{}
}
}
Limitation is it only handles nested [ up to 9 deep. Can make the s array bigger to handle more.
Edit 373 -> 349: Removed outer loop (was for a different site), character comparisons to integers, moved c declaration into the for loop
Edit 349 -> 339:
- Combined
+/-and>/<into single lines. - Reduced integer literal lengths by subtracting 42 from
cto allow for some of the integer literals to be a single character (credit @ceilingcat). - Moved
i=...into the for loop iterator section (credit @ceilingcat).
Edit 339 -> 335:
- Combined
+/-and>/<into a single line (credit @ceilingcat) - Removed unnecessary parenthesis in the
i=...(credit @ceilingcat)
[EDIT] C++11, 318, reads from file:
#include <bits/stdc++.h>
char b[99999]={0},g[99999]={0},*f=g,*p=b;std::function<void()>m[128]={[43]=[]{++*p;},[]{*p=getchar();},[]{--*p;},[]{putchar(*p);},[62]=[]{p++;},[60]=[]{p--;},[91]=[]{if(!(*p))while(*f-93)f++;f++;},[93]=[]{while(*f-91)f--;f--;}};int main(){
fread(g,99,999,stdin);for(;*f;f++)if(m[*f])m[*f]();}
Python 3.8 (single expression, no eval), 711 bytes
(g:=lambda s,a,b,p,c:None if p>=len(s)else g(s,a,b,p+1,c+1)if a==s[p]else(p if c==1 else g(s,a,b,p+1,c-1))if b==s[p]else g(s,a,b,p+1,c),x:=lambda f:None if f is None else x(f()),f:=lambda s,p,m,c:[None,(lambda:f(s,*{"+":lambda:(p,m[:p]+[m[p]+1]+m[p+1:],c+1),"-":lambda:(p,m[:p]+[m[p]-1]+m[p+1:],c+1),">":lambda:(p+1,m+[0]*(p+1>=len(m)),c+1),"<":lambda:(max(p-1,0),[0]*(p-1<0)+m,c+1),".":lambda:print(chr(m[p]),end="") or(p,m,c+1),",":lambda:(p,m[:p]+[ord(input())]+m[p+1:],c+1),"[":lambda:(p,m,(g(s,"[","]",c,0)if 0==m[p]else c)+1),"]":lambda:(p,m,len(s)-g(s[::-1],"]","[",len(s)-c-1,0)if m[p]!=0 else 1+c)}.get(s[c],lambda:(p,m,c+1))()))][c<len(s)],x(lambda:f(open(__import__("sys").argv[-1]).read(),0,[0],0)))
I've provided a hello world example here: Try it online!
single expression?
I've seen multiple fun python implementations already, but I thought that another hurdle beside just golfing would be fun.
As the single expression part implies the whole solution is packed into a single python expression, through the use of things like assignment expressions (:=).
Explanation
This solution, as it stands, consists of 3 distinct functions:
g: facilitates find the index of a matching bracketx: describes the main loop, i.e. drives the state transitionsf: implements the state transition of one "machine state" to another, i.e. the meat of the interpreter
g = lambda s, a, b, p, c: (
None
if p >= len(s)
else g(s, a, b, p + 1, c + 1)
if s[p] == a
else (p if c == 1 else g(s, a, b, p + 1, c - 1))
if s[p] == b
else g(s, a, b, p + 1, c)
)
x = lambda f: None if f is None else x(f())
f = lambda s, p, m, c: [
None,
(
lambda: f(
s,
*{
"+": lambda: (p, m[:p] + [m[p] + 1] + m[p + 1 :], c + 1),
"-": lambda: (p, m[:p] + [m[p] - 1] + m[p + 1 :], c + 1),
">": lambda: (p + 1, m + [0] * (p + 1 >= len(m)), c + 1),
"<": lambda: (max(p - 1, 0), [0] * (p - 1 < 0) + m, c + 1),
".": lambda: print(chr(m[p]), end="") or (p, m, c + 1),
",": lambda: (p, m[:p] + [ord(input())] + m[p + 1 :], c + 1),
"[": lambda: (p, m, (g(s, "[", "]", c, 0) if m[p] == 0 else c) + 1),
"]": lambda: (
p,
m,
len(s) - g(s[::-1], "]", "[", len(s) - c - 1, 0)
if m[p] != 0
else 1 + c,
),
}.get(s[c], lambda: (p, m, c + 1))(),
)
),
][c < len(s)]
Finally all of this gets stuffed together using a "simple" call to x with a curried f, already preloaded with the initial state:
x(lambda: f(open(__import__("sys").argv[-1]).read(), 0, [0], 0))
And voilà it works and is a true python one-liner. 🎉
Sadly this interpreter is limited in the amount of characters it can read in as it is driven by recursion and python doesn't like "very" deep recursion...
Python 3.8 (single expression, no recursion, no eval), 702 bytes
(i:=__import__,k:=i("itertools"),g:=lambda s,a,b,p:p+next(i for i,d in enumerate(k.accumulate({a:1,b:-1}.get(c,0)for c in s[p:]))if 0==d),f:=lambda s,p,m,c:(s,*{"+":lambda:(p,m[:p]+[m[p]+1]+m[p+1:],c+1),"-":lambda:(p,m[:p]+[m[p]-1]+m[p+1:],c+1),">":lambda:(p+1,m+[0]*(p+1>=len(m)),c+1),"<":lambda:(max(p-1,0),[0]*(p-1<0)+m,c+1),".":lambda:print(chr(m[p]),end="") or(p,m,c+1),",":lambda:(p,m[:p]+[ord(input()[0])]+m[p+1:],c+1),"[":lambda:(p,m,(g(s,"[","]",c)if 0==m[p]else c)+1),"]":lambda:(p,m,len(s)-g(s[::-1],"]","[",len(s)-c-1)if 0!=m[p]else 1+c)}.get(s[c],lambda:(p,m,c+1))()),i("functools").reduce(lambda s,_:exit(0)if len(s[0])<=s[3]else f(*s),k.count(1),(open(i("sys").argv[1]).read(),0,[0],0)))
To get around the nasty recursion depth in python I rewrote some parts, and it even turned out shorter than before... 🤣
Here is the hello world example for this version: Try it online!
dirt, 489
'@[^@]*"# @00000000 "(#[^#]*|"#")'#|[^R]*(('<R+`<|'>R+`>|'-R+`-|'+R+`+|'.R+`.|',R+`,|'['RR+`[|']`RR+`])|`R\]'@).*|.*((`<L+'<|`>L+'>|`-L+'-|`+L+'+|`.L+'.|`,L+',|`[`LL+'[|`]'LL+'])|'@\[`L)[^L]*|[^x]*(`x('0[^#]*#`0|'1[^#]*#`1)|(`x'0)+ .*##).*|.*`I",@"[^x]*|.*`o(0'o.*'0|1'o.*'1| .*)|.*`O".@"[^o]*|.*`@(-'@.*@([^ ]*`1'0|)(`0'1)* |\+'@.*@([^ ]*`0'1|)(`1'0)* |<'@.*#( @"00000000 "|.* '@[^ ]+ `@)|>'@.*`@[^ ]+ '@("00000000 "|[^#]+)#|\['@.*@([^ ]*1)|'L\]|\['R.*@0* |`,'I.*@({0|1}'x)* |`.'O.*@'o).*
Has unbounded tape but doesn't work with comment characters.
To run, save as brainfuck.dirt and run dirt brainfuck.dirt -i "[bf_program]#[binary_input]" (# can be omitted if there's no input). It will print [bf_program]#[memory]#[unread_input]#[output].
e.g.
> dirt brainfuck.dirt -i ",[.,]#0100100001001001"
,[.,]@# @00000000 ##0100100001001001
Use the -v flag to watch it as it runs:
> dirt brainfuck.dirt -v -i "+++++++[>+++++++<-]>.+.+."
+++++++[>+++++++<-]>.+.+.
@+++++++[>+++++++<-]>.+.+.# @00000000 ##
+@++++++[>+++++++<-]>.+.+.# @00000001 ##
++@+++++[>+++++++<-]>.+.+.# @00000010 ##
+++@++++[>+++++++<-]>.+.+.# @00000011 ##
++++@+++[>+++++++<-]>.+.+.# @00000100 ##
+++++@++[>+++++++<-]>.+.+.# @00000101 ##
++++++@+[>+++++++<-]>.+.+.# @00000110 ##
+++++++@[>+++++++<-]>.+.+.# @00000111 ##
+++++++[@>+++++++<-]>.+.+.# @00000111 ##
+++++++[>@+++++++<-]>.+.+.# 00000111 @00000000 ##
+++++++[>+@++++++<-]>.+.+.# 00000111 @00000001 ##
+++++++[>++@+++++<-]>.+.+.# 00000111 @00000010 ##
+++++++[>+++@++++<-]>.+.+.# 00000111 @00000011 ##
+++++++[>++++@+++<-]>.+.+.# 00000111 @00000100 ##
+++++++[>+++++@++<-]>.+.+.# 00000111 @00000101 ##
+++++++[>++++++@+<-]>.+.+.# 00000111 @00000110 ##
+++++++[>+++++++@<-]>.+.+.# 00000111 @00000111 ##
+++++++[>+++++++<@-]>.+.+.# @00000111 00000111 ##
+++++++[>+++++++<-@]>.+.+.# @00000110 00000111 ##
+++++++[>+++++++<-L]>.+.+.# @00000110 00000111 ##
+++++++[>+++++++<L-]>.+.+.# @00000110 00000111 ##
+++++++[>+++++++L<-]>.+.+.# @00000110 00000111 ##
+++++++[>++++++L+<-]>.+.+.# @00000110 00000111 ##
+++++++[>+++++L++<-]>.+.+.# @00000110 00000111 ##
+++++++[>++++L+++<-]>.+.+.# @00000110 00000111 ##
+++++++[>+++L++++<-]>.+.+.# @00000110 00000111 ##
+++++++[>++L+++++<-]>.+.+.# @00000110 00000111 ##
+++++++[>+L++++++<-]>.+.+.# @00000110 00000111 ##
+++++++[>L+++++++<-]>.+.+.# @00000110 00000111 ##
+++++++[L>+++++++<-]>.+.+.# @00000110 00000111 ##
+++++++@[>+++++++<-]>.+.+.# @00000110 00000111 ##
+++++++[@>+++++++<-]>.+.+.# @00000110 00000111 ##
+++++++[>@+++++++<-]>.+.+.# 00000110 @00000111 ##
+++++++[>+@++++++<-]>.+.+.# 00000110 @00001000 ##
+++++++[>++@+++++<-]>.+.+.# 00000110 @00001001 ##
+++++++[>+++@++++<-]>.+.+.# 00000110 @00001010 ##
+++++++[>++++@+++<-]>.+.+.# 00000110 @00001011 ##
+++++++[>+++++@++<-]>.+.+.# 00000110 @00001100 ##
+++++++[>++++++@+<-]>.+.+.# 00000110 @00001101 ##
+++++++[>+++++++@<-]>.+.+.# 00000110 @00001110 ##
+++++++[>+++++++<@-]>.+.+.# @00000110 00001110 ##
+++++++[>+++++++<-@]>.+.+.# @00000101 00001110 ##
+++++++[>+++++++<-L]>.+.+.# @00000101 00001110 ##
+++++++[>+++++++<L-]>.+.+.# @00000101 00001110 ##
+++++++[>+++++++L<-]>.+.+.# @00000101 00001110 ##
+++++++[>++++++L+<-]>.+.+.# @00000101 00001110 ##
+++++++[>+++++L++<-]>.+.+.# @00000101 00001110 ##
+++++++[>++++L+++<-]>.+.+.# @00000101 00001110 ##
+++++++[>+++L++++<-]>.+.+.# @00000101 00001110 ##
+++++++[>++L+++++<-]>.+.+.# @00000101 00001110 ##
+++++++[>+L++++++<-]>.+.+.# @00000101 00001110 ##
+++++++[>L+++++++<-]>.+.+.# @00000101 00001110 ##
+++++++[L>+++++++<-]>.+.+.# @00000101 00001110 ##
+++++++@[>+++++++<-]>.+.+.# @00000101 00001110 ##
+++++++[@>+++++++<-]>.+.+.# @00000101 00001110 ##
+++++++[>@+++++++<-]>.+.+.# 00000101 @00001110 ##
+++++++[>+@++++++<-]>.+.+.# 00000101 @00001111 ##
+++++++[>++@+++++<-]>.+.+.# 00000101 @00010000 ##
+++++++[>+++@++++<-]>.+.+.# 00000101 @00010001 ##
+++++++[>++++@+++<-]>.+.+.# 00000101 @00010010 ##
+++++++[>+++++@++<-]>.+.+.# 00000101 @00010011 ##
+++++++[>++++++@+<-]>.+.+.# 00000101 @00010100 ##
+++++++[>+++++++@<-]>.+.+.# 00000101 @00010101 ##
+++++++[>+++++++<@-]>.+.+.# @00000101 00010101 ##
+++++++[>+++++++<-@]>.+.+.# @00000100 00010101 ##
+++++++[>+++++++<-L]>.+.+.# @00000100 00010101 ##
+++++++[>+++++++<L-]>.+.+.# @00000100 00010101 ##
+++++++[>+++++++L<-]>.+.+.# @00000100 00010101 ##
+++++++[>++++++L+<-]>.+.+.# @00000100 00010101 ##
+++++++[>+++++L++<-]>.+.+.# @00000100 00010101 ##
+++++++[>++++L+++<-]>.+.+.# @00000100 00010101 ##
+++++++[>+++L++++<-]>.+.+.# @00000100 00010101 ##
+++++++[>++L+++++<-]>.+.+.# @00000100 00010101 ##
+++++++[>+L++++++<-]>.+.+.# @00000100 00010101 ##
+++++++[>L+++++++<-]>.+.+.# @00000100 00010101 ##
+++++++[L>+++++++<-]>.+.+.# @00000100 00010101 ##
+++++++@[>+++++++<-]>.+.+.# @00000100 00010101 ##
+++++++[@>+++++++<-]>.+.+.# @00000100 00010101 ##
+++++++[>@+++++++<-]>.+.+.# 00000100 @00010101 ##
+++++++[>+@++++++<-]>.+.+.# 00000100 @00010110 ##
+++++++[>++@+++++<-]>.+.+.# 00000100 @00010111 ##
+++++++[>+++@++++<-]>.+.+.# 00000100 @00011000 ##
+++++++[>++++@+++<-]>.+.+.# 00000100 @00011001 ##
+++++++[>+++++@++<-]>.+.+.# 00000100 @00011010 ##
+++++++[>++++++@+<-]>.+.+.# 00000100 @00011011 ##
+++++++[>+++++++@<-]>.+.+.# 00000100 @00011100 ##
+++++++[>+++++++<@-]>.+.+.# @00000100 00011100 ##
+++++++[>+++++++<-@]>.+.+.# @00000011 00011100 ##
+++++++[>+++++++<-L]>.+.+.# @00000011 00011100 ##
+++++++[>+++++++<L-]>.+.+.# @00000011 00011100 ##
+++++++[>+++++++L<-]>.+.+.# @00000011 00011100 ##
+++++++[>++++++L+<-]>.+.+.# @00000011 00011100 ##
+++++++[>+++++L++<-]>.+.+.# @00000011 00011100 ##
+++++++[>++++L+++<-]>.+.+.# @00000011 00011100 ##
+++++++[>+++L++++<-]>.+.+.# @00000011 00011100 ##
+++++++[>++L+++++<-]>.+.+.# @00000011 00011100 ##
+++++++[>+L++++++<-]>.+.+.# @00000011 00011100 ##
+++++++[>L+++++++<-]>.+.+.# @00000011 00011100 ##
+++++++[L>+++++++<-]>.+.+.# @00000011 00011100 ##
+++++++@[>+++++++<-]>.+.+.# @00000011 00011100 ##
+++++++[@>+++++++<-]>.+.+.# @00000011 00011100 ##
+++++++[>@+++++++<-]>.+.+.# 00000011 @00011100 ##
+++++++[>+@++++++<-]>.+.+.# 00000011 @00011101 ##
+++++++[>++@+++++<-]>.+.+.# 00000011 @00011110 ##
+++++++[>+++@++++<-]>.+.+.# 00000011 @00011111 ##
+++++++[>++++@+++<-]>.+.+.# 00000011 @00100000 ##
+++++++[>+++++@++<-]>.+.+.# 00000011 @00100001 ##
+++++++[>++++++@+<-]>.+.+.# 00000011 @00100010 ##
+++++++[>+++++++@<-]>.+.+.# 00000011 @00100011 ##
+++++++[>+++++++<@-]>.+.+.# @00000011 00100011 ##
+++++++[>+++++++<-@]>.+.+.# @00000010 00100011 ##
+++++++[>+++++++<-L]>.+.+.# @00000010 00100011 ##
+++++++[>+++++++<L-]>.+.+.# @00000010 00100011 ##
+++++++[>+++++++L<-]>.+.+.# @00000010 00100011 ##
+++++++[>++++++L+<-]>.+.+.# @00000010 00100011 ##
+++++++[>+++++L++<-]>.+.+.# @00000010 00100011 ##
+++++++[>++++L+++<-]>.+.+.# @00000010 00100011 ##
+++++++[>+++L++++<-]>.+.+.# @00000010 00100011 ##
+++++++[>++L+++++<-]>.+.+.# @00000010 00100011 ##
+++++++[>+L++++++<-]>.+.+.# @00000010 00100011 ##
+++++++[>L+++++++<-]>.+.+.# @00000010 00100011 ##
+++++++[L>+++++++<-]>.+.+.# @00000010 00100011 ##
+++++++@[>+++++++<-]>.+.+.# @00000010 00100011 ##
+++++++[@>+++++++<-]>.+.+.# @00000010 00100011 ##
+++++++[>@+++++++<-]>.+.+.# 00000010 @00100011 ##
+++++++[>+@++++++<-]>.+.+.# 00000010 @00100100 ##
+++++++[>++@+++++<-]>.+.+.# 00000010 @00100101 ##
+++++++[>+++@++++<-]>.+.+.# 00000010 @00100110 ##
+++++++[>++++@+++<-]>.+.+.# 00000010 @00100111 ##
+++++++[>+++++@++<-]>.+.+.# 00000010 @00101000 ##
+++++++[>++++++@+<-]>.+.+.# 00000010 @00101001 ##
+++++++[>+++++++@<-]>.+.+.# 00000010 @00101010 ##
+++++++[>+++++++<@-]>.+.+.# @00000010 00101010 ##
+++++++[>+++++++<-@]>.+.+.# @00000001 00101010 ##
+++++++[>+++++++<-L]>.+.+.# @00000001 00101010 ##
+++++++[>+++++++<L-]>.+.+.# @00000001 00101010 ##
+++++++[>+++++++L<-]>.+.+.# @00000001 00101010 ##
+++++++[>++++++L+<-]>.+.+.# @00000001 00101010 ##
+++++++[>+++++L++<-]>.+.+.# @00000001 00101010 ##
+++++++[>++++L+++<-]>.+.+.# @00000001 00101010 ##
+++++++[>+++L++++<-]>.+.+.# @00000001 00101010 ##
+++++++[>++L+++++<-]>.+.+.# @00000001 00101010 ##
+++++++[>+L++++++<-]>.+.+.# @00000001 00101010 ##
+++++++[>L+++++++<-]>.+.+.# @00000001 00101010 ##
+++++++[L>+++++++<-]>.+.+.# @00000001 00101010 ##
+++++++@[>+++++++<-]>.+.+.# @00000001 00101010 ##
+++++++[@>+++++++<-]>.+.+.# @00000001 00101010 ##
+++++++[>@+++++++<-]>.+.+.# 00000001 @00101010 ##
+++++++[>+@++++++<-]>.+.+.# 00000001 @00101011 ##
+++++++[>++@+++++<-]>.+.+.# 00000001 @00101100 ##
+++++++[>+++@++++<-]>.+.+.# 00000001 @00101101 ##
+++++++[>++++@+++<-]>.+.+.# 00000001 @00101110 ##
+++++++[>+++++@++<-]>.+.+.# 00000001 @00101111 ##
+++++++[>++++++@+<-]>.+.+.# 00000001 @00110000 ##
+++++++[>+++++++@<-]>.+.+.# 00000001 @00110001 ##
+++++++[>+++++++<@-]>.+.+.# @00000001 00110001 ##
+++++++[>+++++++<-@]>.+.+.# @00000000 00110001 ##
+++++++[>+++++++<-L]>.+.+.# @00000000 00110001 ##
+++++++[>+++++++<L-]>.+.+.# @00000000 00110001 ##
+++++++[>+++++++L<-]>.+.+.# @00000000 00110001 ##
+++++++[>++++++L+<-]>.+.+.# @00000000 00110001 ##
+++++++[>+++++L++<-]>.+.+.# @00000000 00110001 ##
+++++++[>++++L+++<-]>.+.+.# @00000000 00110001 ##
+++++++[>+++L++++<-]>.+.+.# @00000000 00110001 ##
+++++++[>++L+++++<-]>.+.+.# @00000000 00110001 ##
+++++++[>+L++++++<-]>.+.+.# @00000000 00110001 ##
+++++++[>L+++++++<-]>.+.+.# @00000000 00110001 ##
+++++++[L>+++++++<-]>.+.+.# @00000000 00110001 ##
+++++++@[>+++++++<-]>.+.+.# @00000000 00110001 ##
+++++++[R>+++++++<-]>.+.+.# @00000000 00110001 ##
+++++++[>R+++++++<-]>.+.+.# @00000000 00110001 ##
+++++++[>+R++++++<-]>.+.+.# @00000000 00110001 ##
+++++++[>++R+++++<-]>.+.+.# @00000000 00110001 ##
+++++++[>+++R++++<-]>.+.+.# @00000000 00110001 ##
+++++++[>++++R+++<-]>.+.+.# @00000000 00110001 ##
+++++++[>+++++R++<-]>.+.+.# @00000000 00110001 ##
+++++++[>++++++R+<-]>.+.+.# @00000000 00110001 ##
+++++++[>+++++++R<-]>.+.+.# @00000000 00110001 ##
+++++++[>+++++++<R-]>.+.+.# @00000000 00110001 ##
+++++++[>+++++++<-R]>.+.+.# @00000000 00110001 ##
+++++++[>+++++++<-]@>.+.+.# @00000000 00110001 ##
+++++++[>+++++++<-]>@.+.+.# 00000000 @00110001 ##
+++++++[>+++++++<-]>O+.+.# 00000000 @o00110001 ##
+++++++[>+++++++<-]>O+.+.# 00000000 @0o0110001 ##0
+++++++[>+++++++<-]>O+.+.# 00000000 @00o110001 ##00
+++++++[>+++++++<-]>O+.+.# 00000000 @001o10001 ##001
+++++++[>+++++++<-]>O+.+.# 00000000 @0011o0001 ##0011
+++++++[>+++++++<-]>O+.+.# 00000000 @00110o001 ##00110
+++++++[>+++++++<-]>O+.+.# 00000000 @001100o01 ##001100
+++++++[>+++++++<-]>O+.+.# 00000000 @0011000o1 ##0011000
+++++++[>+++++++<-]>O+.+.# 00000000 @00110001o ##00110001
+++++++[>+++++++<-]>O+.+.# 00000000 @00110001 ##00110001
+++++++[>+++++++<-]>.@+.+.# 00000000 @00110001 ##00110001
+++++++[>+++++++<-]>.+@.+.# 00000000 @00110010 ##00110001
+++++++[>+++++++<-]>.+O+.# 00000000 @o00110010 ##00110001
+++++++[>+++++++<-]>.+O+.# 00000000 @0o0110010 ##001100010
+++++++[>+++++++<-]>.+O+.# 00000000 @00o110010 ##0011000100
+++++++[>+++++++<-]>.+O+.# 00000000 @001o10010 ##00110001001
+++++++[>+++++++<-]>.+O+.# 00000000 @0011o0010 ##001100010011
+++++++[>+++++++<-]>.+O+.# 00000000 @00110o010 ##0011000100110
+++++++[>+++++++<-]>.+O+.# 00000000 @001100o10 ##00110001001100
+++++++[>+++++++<-]>.+O+.# 00000000 @0011001o0 ##001100010011001
+++++++[>+++++++<-]>.+O+.# 00000000 @00110010o ##0011000100110010
+++++++[>+++++++<-]>.+O+.# 00000000 @00110010 ##0011000100110010
+++++++[>+++++++<-]>.+.@+.# 00000000 @00110010 ##0011000100110010
+++++++[>+++++++<-]>.+.+@.# 00000000 @00110011 ##0011000100110010
+++++++[>+++++++<-]>.+.+O# 00000000 @o00110011 ##0011000100110010
+++++++[>+++++++<-]>.+.+O# 00000000 @0o0110011 ##00110001001100100
+++++++[>+++++++<-]>.+.+O# 00000000 @00o110011 ##001100010011001000
+++++++[>+++++++<-]>.+.+O# 00000000 @001o10011 ##0011000100110010001
+++++++[>+++++++<-]>.+.+O# 00000000 @0011o0011 ##00110001001100100011
+++++++[>+++++++<-]>.+.+O# 00000000 @00110o011 ##001100010011001000110
+++++++[>+++++++<-]>.+.+O# 00000000 @001100o11 ##0011000100110010001100
+++++++[>+++++++<-]>.+.+O# 00000000 @0011001o1 ##00110001001100100011001
+++++++[>+++++++<-]>.+.+O# 00000000 @00110011o ##001100010011001000110011
+++++++[>+++++++<-]>.+.+O# 00000000 @00110011 ##001100010011001000110011
+++++++[>+++++++<-]>.+.+.@# 00000000 @00110011 ##001100010011001000110011
Javascript - 342 bytes
This is pretty much a complete ripoff of https://codegolf.stackexchange.com/a/220/85546, but I've translated it to Javascript, which was mostly simple except for the converting of character codes, which required some extra lines of code.
d=l=>{i=0,b=new Array(300).fill(0),t="",q=[];r=new Response(l).text().then(q=>(q.split("").forEach(e=>{t+=["i++;","i--;","b[i]++;","b[i]--;","n=new Buffer(1);n[0]=b[i];q.push(n.toString());","b[i]=prompt().charCodeAt(0);","while (b[i]){","}"]["><+-.,[]".indexOf(e)]||"\n",i+=(92-e.charCodeAt(0))*(e.indexOf("][")>-1)});eval(t);return q))}
It reads input from a Blob (l), and returns the output as an array of numbers/strings/whatever. All other input is taken as a prompt, of which only the first character is stripped. As with @Alexandru's submission, it evals the translated code, which is simply mapped one character at a time to corresponding JS.
Python 3, 306 bytes (no eval)
from sys import*
s=open(argv[1]).read()
d=[0]*30000
i=p=a=0
k=[]
j=k+d
for o in s:
if o==']':j[a]=k.pop();j[j[a]]=a
k+=[a]*(o=='[');a+=1
while i<a:x,r='[]<>,.+-'.find(s[i]),d[p];d[p],p=(r+(x==6)-(x>6))%256if 4!=x else ord(stdin.read(1)),p+(x==3)-(x==2);i=j[i] if x==(r>0)else 1+i;print(end=chr(r)*(5==x))
Outputs null (0x00) characters though, and times out on prime example but should theoretically finish.
Can still be improved a bit.
C (gcc), 273 268 bytes
main(_,a){_=fopen("w.c","w");fputs("main(){char a[30000],*p=a;",_);x:a=getchar();fputs(a-62?a-60?a-43?a-45?a-46?a-44?a-91?a-93?~a?"":"}":"}":"while(*p){":"*p=getchar();":"putchar(*p);":"--*p;":"++*p;":"--p;":"++p;",_);if(~a)goto x;fclose(_);system("cc w.c;./a.out");};
-5 thanks to ceilingcat
Takes input from stdin.
This relies a little bit on the environment, but is pretty consistent. This is effectively the eval solution for c. It writes an appropriate C program to the file w.c, compiles it, and runs it as the desired executable. Thus as a bonus effect this actually compiles the bf code and leaves a.out as a binary for it. Note that depending on the system you may need to modify the last string. In particular most windows c compilers call the default executable "a.exe". Luckily as far as I can tell, they all have the same length so the bytecount is the same. (though if you don't have a cc defined you may need to add a letter such as gcc to the compile command, adding 1 byte).
I am aware that this thread is a bit old, but I didn't see this style of C solution yet, so I thought I'd add it.
Powershell, 175 195 183 175 173 bytes, Transpiler
,'$p=0
$c=@{}'+(gc $args|% t*y|%{(-split'$p++
$p--
$c.$p++
$c.$p--
$c.$p=[console]::Read()
write-host([char]$c.$p)-n
for(;$c.$p){
}
#')[('><+-,.[]'|% i*f $_)]
})-join'
'|iex
Explanation:
The script is transpiler from a brainfuck source code to a powershell source code. Finally, the script evaulates the result powershell code by command iex.
- init commands
$p=0and$c=@{} gc $args|% t*y|%{- for each character from file('><+-,.[]'|% i*f $_)+1- treats a current char as index in the array of code snippets. If character match no code snippet, the script uses the comment char#.- and
iexevaulates the result powershell code
Compared to Joey's answer, this script fixes a bug "Index operation failed; the array index evaluated to null" ($p=0 in the init block)
Known issues:
[console]::Read()eats first char inVSCode. This expression work correct in a powershell window.
Less golfed test script:
$f = {
'$p=0',
'$c=@{}'+
(gc $args|% t*y|%{
$bfcmd_Idx='><+-,.[]'.IndexOf($_) # IndexOf returns -1 if char $_ does not found.
@( '$p++',
'$p--',
'$c.$p++',
'$c.$p--',
'$c.$p=[console]::Read()',
'write-host([char]$c.$p)-n',
'for(;$c.$p){',
'}',
'#'
)[$bfcmd_Idx] # push to pipe an element. -1 means last element
})-join"`n"|Invoke-Expression
}
&$f interpret-brainf-hello.bf
&$f interpret-brainf-prime.bf
Output:
Hello World!
Primes up to: 100
2 3 5 7 11 13 17 19 23 29 31 37 41 43 47 53 59 61 67 71 73 79 83 89 97
File interpret-brainf-prime.bf contains a test script from the question.
File interpret-brainf-hello.bf (from wiki):
[ This program prints "Hello World!" and a newline to the screen, its
length is 106 active command characters. [It is not the shortest.]
This loop is an "initial comment loop", a simple way of adding a comment
to a BF program such that you don't have to worry about any command
characters. Any ".", ",", "+", "-", "<" and ">" characters are simply
ignored, the "[" and "]" characters just have to be balanced. This
loop and the commands it contains are ignored because the current cell
defaults to a value of 0; the 0 value causes this loop to be skipped.
]
++++++++ Set Cell #0 to 8
[
>++++ Add 4 to Cell #1; this will always set Cell #1 to 4
[ as the cell will be cleared by the loop
>++ Add 2 to Cell #2
>+++ Add 3 to Cell #3
>+++ Add 3 to Cell #4
>+ Add 1 to Cell #5
<<<<- Decrement the loop counter in Cell #1
] Loop till Cell #1 is zero; number of iterations is 4
>+ Add 1 to Cell #2
>+ Add 1 to Cell #3
>- Subtract 1 from Cell #4
>>+ Add 1 to Cell #6
[<] Move back to the first zero cell you find; this will
be Cell #1 which was cleared by the previous loop
<- Decrement the loop Counter in Cell #0
] Loop till Cell #0 is zero; number of iterations is 8
The result of this is:
Cell No : 0 1 2 3 4 5 6
Contents: 0 0 72 104 88 32 8
Pointer : ^
>>. Cell #2 has value 72 which is 'H'
>---. Subtract 3 from Cell #3 to get 101 which is 'e'
+++++++..+++. Likewise for 'llo' from Cell #3
>>. Cell #5 is 32 for the space
<-. Subtract 1 from Cell #4 for 87 to give a 'W'
<. Cell #3 was set to 'o' from the end of 'Hello'
+++.------.--------. Cell #3 for 'rl' and 'd'
>>+. Add 1 to Cell #5 gives us an exclamation point
>++. And finally a newline from Cell #6
Powershell, 257 bytes, Interpreter
$c=@{}
$p=$i=0
$m={for(;($b+=($s[$i]-92)|?{$_-in-1,1})){$i+=$args[0]}}
for($s=gc $args -ra;$i-lt$s.Length){switch($s[$i]-40){22{$p++}20{$p--}3{$c.$p++}5{$c.$p--}4{$c.$p=[console]::Read()}6{write-host([char]$c.$p)-n}51{if(!$c.$p){.$m 1}}53{.$m -1;$i--}}$i++}
Less golfed test script:
$f = {
$c=@{} # $c - hashtable
$p=$i=0 # $p - ptr (a key in the hashtable), $i - IC (Instruction Counter)
$m={
for(;($b+=($s[$i]-92)|?{$_-in-1,1})){ # $b - balance of the brackets
$i+=$args[0] # move IC forward or backward
} # while balance of the brackets is not 0
}
for($s=gc $args -ra;$i-lt$s.Length){ # -ra is shortcut for -raw parameter = get-content as char array
switch($s[$i]-40){ # '-40' needs to convert into [int] and to reduce cases 43 44 45 46 into 3 4 5 6 (-2 bytes)
22{$p++}
20{$p--}
3{$c.$p++}
5{$c.$p--}
4{$c.$p=[console]::Read()} # it eats a first char in a VSCode, it works correct in a Powershell terminal
6{write-host([char]$c.$p)-n}
51{if(!$c.$p){.$m 1}} # dot source the script block m
53{.$m -1;$i--} # dot sourcing does not create a new scope https://docs.microsoft.com/en-us/powershell/module/microsoft.powershell.core/about/about_scripts
}
$i++
}
}
&$f interpret-brainf-hello.bf
&$f interpret-brainf-prime.bf
Output:
Hello World!
Primes up to: 20
2 3 5 7 11 13 17 19
PynTree, 123 bytes
Æp+"Dw[0]Dy0"Ƭ+"æ#wy%+1#wy256"-"æ#wy%_#wy1 256"."ƤȮ#wy","æ#wy%OĊ256">";ß+y1æSwy"<"¿yß_y1æIw0 0"["¡#wy¤"]'}}JfxSėx"+-.,[]<>"
Transpiles Brainfuck to PynTree and then calls pyntree_eval on it. PynTree transpiles directly to Python.
Gol><>, 111 bytes
/2ds2e111`!a0im*aF+:ZB|0L.
^9R~`;r"0RXf2"WL0p|m0.
^8R~`P
^7R~"~iE0"
^6R~`M
^5R~":o"
^4R~`{
^3R~`}
^~~`W
^~`|
^~
Try Hello World online! or Try String Reverser online!
How it works
The first row is the main loop.
/2ds2e111`!a0im*aF+:ZB|0L.
2ds2e111`!a0 Push [2,29,2,14,1,1,1,33,10,0]
(the differences of all valid chars)
im* Take input and negate it
aF... | Repeat 10 times...
+:ZB Add, and break if the sum is 0
0L. Jump to another row based on loop count
Other rows share the structure:
^xR~...
xR~ Discard unneeded numbers x times
... Push relevant code
^ Return to the main loop
Newline is the delimiter between code and input.
^9R~`;r"0RXf2"WL0p|m0.
`;r"0RXf2" Add "2fXR0" to the start and ";" to the end
"2fXR0" pushes 2**15 zeros to the stack
";" finishes the program
W...| While there is some code on the stack...
L0p Write the code on the row 0
m0. Jump to row 0
Other lines are for command translation.
^8R~`P "+" => "P" Increment
^7R~"~iE0" "," => "~iE0" Erase current cell, take input and
change to 0 if EOF
^6R~`M "-" => "M" Decrement
^5R~":o" "." => ":o" Duplicate current cell and print
^4R~`{ "<" => "{" Rotate to the left
^3R~`} ">" => "}" Rotate to the right
^~~`W "[" => "W" While (non-popping)
^~`| "]" => "|" End while
^~ Others => "" Ignore
Inlining the switch-case turned out to be a nightmare (simply because there is no explicit if...else structure in Gol><>), so I used an index-jump method instead.
Retina 0.8.2, 386 391 386 bytes
Code contains unprintable NUL (0x00) characters. It's also not super golfed yet, because it's already really slow, and if I golf it more, I don't know how long it'd take to finish. Appears to time out on the prime-finding sample.
There may be bugs in the online interpreter or in my program (leading new lines don't show in the output?).
Takes input like <code>│<input>. No, that is not a pipe (|). It's the Unicode character U+2502. The code also uses the Unicode characters ÿ▶◀├║. Unicode characters are used in order to support input of all ASCII characters. Therefore, these characters need to be separated from the code by a non-ASCII character.
s`^.*
▶$0├║▶
s{`(▶>.*║.*)▶(.)(.?)
$1$2▶$3
▶$
▶
║▶
║▶
(▶<.*║.*)(.)▶
$1▶$2
T`ÿ-`o`(?<=▶\+.*║.*▶).
^\+
T`-ÿ`ÿo`(?<=▶-.*║.*▶).
^-
(▶\..*├.*)(║.*▶)(.)
$1$3$2$3
(▶,.*│)(.?)(.*├.*▶).
$1$3$2
▶\[(.*║.*▶)
[▶▶${1}
{`(▶▶+)([^[\]]*)\[
$2[$1▶
}`▶(▶+)([^[\]]*)\]
$2]$1
r`([[\]]*)▶\](.*║.*▶[^])
$1◀◀]$2
r{`\[([^[\]]*)(◀+)◀
$2[$1
}`\]([^[\]]*)(◀◀+)
$2◀]$1
◀
▶
}`▶([^│])(.*║)
$1▶$2
s\`.*├|║.*
Note there is a trailing newline there.
Brief Explanation:
Zeros 0x00 are used for the tape, which is infinite. The first replacement sets up the interpreter in the form ▶<code>│<input>├<output>║▶<tape>, where the first ▶ is the pointer for the code, and the second one is the pointer for the tape.
ÿ is 0xFF (255), which is used for Transliteration (used to implement + and -) to wrap the cells back around to zero.
◀ is only used for readability (in case the program is stopped in the middle or you want to see the program mid-execution). Otherwise, you couldn't tell which way the pointer was moving.
Commented Code:
s`^.* # Initialize
▶$0├║▶
s{`(▶>.*║.*)▶(.)(.?) # >
$1$2▶$3
▶$
▶
║▶ # <
║▶
(▶<.*║.*)(.)▶
$1▶$2
T`ÿ-`o`(?<=▶\+.*║.*▶). # +
^\+
T`-ÿ`ÿo`(?<=▶-.*║.*▶). # -
^-
(▶\..*├.*)(║.*▶)(.) # .
$1$3$2$3
(▶,.*│)(.?)(.*├.*▶). # ,
$1$3$2
▶\[(.*║.*▶) # [
[▶▶${1}
{`(▶▶+)([^[\]]*)\[
$2[$1▶
}`▶(▶+)([^[\]]*)\]
$2]$1
r`([[\]]*)▶\](.*║.*▶[^]) # ]
$1◀◀]$2
r{`\[([^[\]]*)(◀+)◀
$2[$1
}`\]([^[\]]*)(◀◀+)
$2◀]$1
◀
▶
}`▶([^│])(.*║) # next instruction
$1▶$2
s\`.*├|║.* # print output
Click here for the code with zeros in place of null bytes. Any occurrences of $0 should not be replaced with nulls.
Edit: Now supports empty input and suppresses trailing newline.
Infinite output is now supported. (403 bytes)
Conveyor, 953
This might be the most beautiful code you will ever see:
0
:I\1\@p
>#====)
^#====<
PP0
P<=======================<
00t:)01t1 a:P:P:P:P:P:P:^
>===========">">2>">2>">"^
^ +^-^5^ ^5^]^.^
^ "^"^*^"^*^"^"^
^ -^-^6^-^6^-^-^
^ #^#^*^#^*^#^#^
^ P P -^P )^P P
^ P P #^P )^P P
^t1\)t0:))t01 P -^ 1
^===========< P #^ 0
^ t1\(t0:))t01 P t
^=============< P )
^ t11(t01 0 0 )
^===============<. t P 10
^ FT#T#=<
^=================< P
^ t11)t01
^===================< 10t))0tP00t:(01t(1a:P:
^ >=====#=>==========">"
^ ^ ]^[
^ P ^ "^"
^===========================<=^#=====< -^-
^==< ^ PP#^#=
^===PTPT<
^ )P P
^=<=< (
^===<
Recall, 594 bytes
In short: Recall has no arithmetic operators in a classic sense, it only has bitwise operations. You can not just "add one" etc. Recall is also strictly stack-based.
DC505M22022M32032M606M42042M707M92092M4405022o032o06o042o07o092o044o1305022o06o042o092o52052q.q2305022o06o07o93093q.q5403206o07o14014q.q6403206o042o07o24024q.q74Yx34034z03MMMMMMMM034o3yY030401r3.4.101zyY040301r4.3.101zY01052gZ02Z040301052023s4.3.10zyY01023gZ02z030401023052s3.4.10zyY01093gZ02q20zyY01054gZ02u20zyY01014gZx20zyY01064gZ02X0zyY01024gZ03304302r33.43.20zyY01074gZ04303302r43.33.20zyyQ6205.8Y06208g6206208iZ08M808013izy062U7205.9Y07209g7207209iz09M909013izy072R53.63.82063MMMMMMMM053o63082013i53082KKKKKKKK82053063082S84.94.12.73.83t012073083TY083073012r83.73.12012084gzY012094gZt0zyy
Example 1: Print something
Input:
-[--->+<]>-----..-[----->+<]>.++++.+[->++++<]>.---[----->++<]>.---.------------.++++++++.++++++++.+[-->+++++<]>-.
Output:
PPCG rocks!
Example 2: Output square numbers up to 100
Input:
+[>++<-]>[<+++++>-]+<+[>[>+>+<<-]++>>[<<+>>-]>>>[-]++>[-]+>>>+[[-]++++++>>>]<<<[[<++++++++<++>>-]+<.<[>----<-]<]<<[>>>>>[>>>[-]+++++++++<[>-<-]+++++++++>[-[<->-]+[<<<]]<[>+<-]>]<<-]<<-]
Output:
0
1
4
9
16
25
36
49
64
81
100
This example might take a few minuted to execute and might cause a "this tab is frozen" message. Ignore that and wait.
CJam, 75 bytes
lq3e4Vc*@{"-<[],.+>"#"T1$T=(t T(:T; { _T=}g \0+(@T@t _T=o "_'(')er+S/=}%s~@
Try it online: string reverser, Hello World.
Explanation
Takes code on the first line of STDIN and input on all lines below it.
l Read a line from STDIN (the program) and push it.
q Read the rest of STDIN (the input) and push it.
3e4Vc* Push a list of 30000 '\0' characters.
@ Rotate the stack so the program is on top.
{ }% Apply this to each character in prog:
"-<[],.+>"# Map '-' to 0, '<' to 1, ... and everything else to -1.
...= Push a magical list and index from it.
s~ Concatenate the results and evaluate the resulting string as CJam code.
@ Rotate the top three elements again -- but there are only two, so the
program terminates.
What about that magical list?
"T1$T=(t T(:T; { _T=}g \0+(@T@t _T=o " Space-separated CJam snippets.
(Note the final space! We want an empty
string at the end of the list.)
_'(')er+ Duplicate, change (s to )s, append.
S/ Split over spaces.
The resulting list is as follows:
T1$T=(t (-)
T(:T; (<)
{ ([)
_T=}g (])
\0+(@T@t (,)
_T=o (.)
T1$T=)t (+)
T):T; (>)
{ (unused)
_T=}g (unused)
\0+(@T@t (unused)
_T=o (unused)
(all other characters)
We generate the snippets for + and > from those for - and <, simply by changing left parens (CJam’s “decrement”) into right parens (CJam’s “increment”).
SmileBASIC, 258 bytes
C=0DEF B S,K
DIM M[3E4]FOR I=0TO LEN(S)-1C=ASC(S[I])N=M[P]ON!F GOTO@C?CHR$(N)*(C==46);
O=C==91F=!N*O
K=K+CHR$(I)*O*!F
IF C==93THEN I=ASC(POP(K))-1
M[P]=N-N(42)P=P+N(59)IF C==44THEN M[P]=ASC(SHIFT(K))@C:F=F-N(90)
NEXT
END
DEF N(L)RETURN(C-L-2)*(C<L&&C<L+4)END
Call the function as B code,input
brainfuck, 843 691 bytes
Edit: decided to revisit this and found a surprising number of ways to golf off bytes
>>>,[>++++[-<-------->]<-[>+<<]>[----------[>]>[<+<+>>>>]<<<-[>]>[<+<+>>>>]<<<-[>]>[<+<+>>>>]<<<-[>]>[<-<+++>>>>]<<<--------------[>]>[<++<+>>>>]<<<--[>]>[<-<+++++++>>+>>]<<++++[-<------>]+<+[>]>[<++<+>>>>]<<<--[>]>[<<+>>>>]<<-<[+]<[>]>,>]<]<-[<]>[-[<<]>[<+[>]>>[<+[<<[<]<<-[>>]<[>>>>[>]>+<<[<]<]<-[>>]<[>>>>[>]>-<<[<]<]<++[->>+<<]>>[>]>]]<<<[<]>-<]>-[<<]>[<++[>]>+>[<-]<[<<[<]>[-<<+>>]>--[<<]>[[>]>+<<[<]<]>+[<<]>[[>]>-<<[<]<]>+[>]>]<<[<]>--<]>-[<<]>[[>]>>.<<<[<]<]>-[<<]>[[>]>>-<<<[<]<]>-[<<]>[[>]>>,<<<[<]<]>-[<<]>[[>]>>+<<<[<]<]>-[<<]>[[>]>>>[>>]>[<<<[<<]<+>>>[>>]>-]>[-]<<+[<[->>+<<]<]<[->>+<<]<[<]<]>-[<<]>[[>]>-[+>[-<<+>>]>]+<<[-]+[-<<]<[->>>[>>]>+<<<[<<]<]<[<]<]<++++++++>>[+<<->>]>]
This takes input in the form code!input where the !input is optional. It also simulates negative cells without using negative cells itself and can store up to (30000-(length of code+6))/2 cells.
16-bit x86 assembler code, 104 bytes
Assembles with YASM. It wants the file piped from stdin, though.
;compliant version, non-commands are ignored, but 104 bytes long
[bits 16]
[org 0x100]
; assume bp=091e used
; assume di=fffe
; assume si=0100
; assume dx=cs (see here)
; assume cx=00ff
; assume bx=0000
; assume ax=0000 used (ah)
; assume sp=fffe
start:
mov al, code_nothing - start
code_start:
mov ch, 0x7f ; allow bigger programs
mov bx, cx
mov di, cx
rep stosb
mov bp, find_right + start - code_start ;cache loop head for smaller compiled programs
jmp code_start_end
find_right:
pop si
dec si
dec si ;point to loop head
cmp [bx], cl
jne loop_right_end
loop_right:
lodsb
cmp al, 0xD5 ; the "bp" part of "call bp" (because 0xFF is not unique, watch for additional '[')
jne loop_left
inc cx
loop_left:
cmp al, 0xC3 ; ret (watch for ']')
jne loop_right
loop loop_right ;all brackets matched when cx==0
db 0x3c ;cmp al, xx (mask push)
loop_right_end:
push si
lodsw ; skip "call" or dummy "dec" instruction, depending on context
push si
code_sqright:
ret
code_dec:
dec byte [bx]
code_start_end:
db '$' ;end DOS string, also "and al, xx"
code_inc:
inc byte [bx]
db '$'
code_right:
inc bx ;al -> 2
code_nothing:
db '$'
code_left:
dec bx
db '$'
code_sqleft:
call bp
db '$'
; create lookup table
real_start:
inc byte [bx+''] ;point to code_right
mov byte [bx+'['], code_sqleft - start
mov byte [bx+']'], code_sqright - start
lea sp, [bx+45+2] ;'+' + 4 (2b='+', 2c=',', 2d='-', 2e='.')
push (code_dec - start) + (code_dot - start) * 256
push (code_inc - start) + (code_comma - start) * 256
pre_write:
mov ah, code_start >> 8
xchg dx, ax
; write
mov ah, 9
int 0x21
; read
code_comma:
mov dl, 0xff
db 0x3d ; cmp ax, xxxx (mask mov)
code_dot:
mov dl, [bx]
mov ah, 6
int 0x21
mov [bx], al
db '$'
db 0xff ; parameter for '$', doubles as test for zero
; switch
xlatb
jne pre_write
; next two lines can also be removed
; if the program ends with extra ']'
; and then we are at 100 bytes... :-)
the_end:
mov dl, 0xC3
int 0x21
int 0x20
Brainfuck, 948 bytes
Well, that took a while. I golfed a Brainfuck self-interpreter by ... not me.
->->>>-[,+>+<[->-]>[->]<+<-------------------------------------[+++++++++++++++++++++++++++++++++++++>-]>[->]<<[>++++++++[-<----->]<---[-[-[-[--------------[--[>+++++++[-<---->]<-[--[[+]->]<+[->++>]->]<+[->+>]->]<+[->+++++>]->]<+[->++++++>]->]<+[->+++++++>]->]<+[->++++>]->]<+[->++++++++>]->]<+[->+++>]->]+<+[->->]>[-<->]<]>>->>-<<<<<+++[<]>[-[-[-[-[-[-[-[-<<++++++++>>>[>]>>>>+[->>+]->,<<<+[-<<+]-<<<[<]<]>[<<<+++++++>>>[>]>>>>+[->>+]->.<<<+[-<<+]-<<<[<]]<]>[<<<++++++>>>[>]>>>>+[->>+]<<-<<+[-<<+]-<<<[<]]<]>[<<<+++++>>>[>]>>>>+[->>+]+>>-<<[-<<+]-<<<[<]]<]>[<<<++++>>>[>]>>>>+[->>+]->-<<<+[-<<+]-<<<[<]]<]>[<<<+++>>>[>]>>>>+[->>+]->+<<<+[-<<+]-<<<[<]]<]>[<++[>]>>>>+[->>+]->[<<<+[-<<+]-<<<[<]-[<<-[>->-[<+]]<+[->>[<]]<-[>-->+[<++]]<++[-->>[<]]<++>>[[-<+>]<<[->>+<<]]<[>]>]]<[<<+[-<<+]-<<<[<]>--<<++>]>]<]>[<<<+>>>[>]>>>>+[->>+]->[<<<+[-<<+]-<<<[<]]<[<<+[-<<+]-<<<[<]+[>-[<-<]<<[>>]>>-[<+<]<<[>>]>>++<[>[-<<+>>]<[->+<]]<[>]>]]>[[-<<+>>]<[->+<]>]]>]
C, 260 + 23 = 283 bytes
I created a C program which can be found here.
main(int a,char*s[]){int b[atoi(s[2])],*z=b,p;char*c=s[1],v,w;while(p=1,
*c){q('>',++z)q('<',--z)q('+',++*z)q('-',--*z)q('.',putchar(*z))q(',',*z
=getchar())if(*c=='['||*c==']'){v=*c,w=184-v;if(v<w?*z==0:*z!=0)while(p)
v<w?c++:c--,p+=*c==v?1:*c==w?-1:0;}c++;}}
Has to be compiled via gcc -D"q(a,b)"="*c-a||(b);" -o pmmbf pmmbf.c and can be called as follows: pmmbf ",[.-]" 30000 whereby the first argument (quoted) contains the bf-program to run, the second determines how large the tape should be.
Python (no eval), 317 bytes
from sys import*
def f(u,c,k):
while(c[1]>=k)*u:
j,u='[]<>+-,.'.find(u[0]),u[1:];b=(j>=0)*(1-j%2*2);c[1]+=b*(j<2)
while b*c[c[0]]and j<1:f(u,c,k+1);c[1]+=1
b*=c[1]==k;c[[0,c[0],2][j/2-1]]+=b
if(j==6)*b:c[c[0]]=ord(stdin.read(1))
if(j>6)*b:stdout.write(chr(c[c[0]]))
f(open(argv[1]).read(),[-1]+[0]*30003,0)
C, 194 bytes
s[99999],*p;char*c;k(h){h=*c-h;return h*h<2?h:0;}main(d,i){c=1[p=i];for(p=s;*c;++c){(*p)-=k(44);p+=k(61);*c^46?*c^44?0:(*p=getchar()):putchar(*p);d=k(92);if(*p?~d:d-1)for(i=d;i;i+=k(92))c-=d;}}
Expects the brainfuck program as the first command line argument.
Cy, 272 270 253 233 232 bytes
This is mind-numbingly slow, but I guess that's what I get for interpreting an inefficent language in an interpreted interpreted language.
Thanks to this answer, Cy is my first language to be proven Turing-complete!
[0 &=d] =C
{$C $d ::} =c
("+" "$C $d ::++" :
"-" "$C $d ::--" :
"<" ".d --" :
">" ".d ++ $C 0 <~" :
"[" "{c 0 >} {" :
"]" "} while" :
"." "c chr :<<" :
"," "$C $d :>c ord ::=" :
"",)=f
"" =m
:>R {=x .m $f $x :: "% " +=} each
$m exec
I have created a monster.
Ungolfed/"readable":
[0] =cells
0 =dp
{ $cells $dp :: } =cell
(
"+" " $cells $dp ::++ " :
"-" " $cells $dp ::-- " :
"<" "
.dp --
" :
">" "
.dp ++
$dp $cells len >< {
$cells 0 <~
} if
" :
"[" "
{ cell 0 > } {
" :
"]" "
} while
" :
"." " cell chr :<< " :
"," " $cells $dp :>c ord ::= " :
"" ,
) =funcs
:>R =code
"" =cmds
$code { =x
.cmds $funcs $x :: +=
} each
$cmds exec
VB.net, 730 bytes
If P.Aggregate(Of Int32)(0,Function(s,i)If(s<0,s,If(i="["c,s+1,If(i="]"c,s-1,s))))=0 Then Dim C=0,O=0,M(30000)As Int32:Dim J As Func(Of Int32,Int32,Int32,Char,Char,Int32)=Function(x,n,l,g,t)If(P(x)=g,J(x+n,n,l+1,g,t),If(P(x)=t,If(l=1,x,J(x+n,n,l-1,g,t)),J(x+n,n,l,g,t))):Dim Q As New Dictionary(Of Char,Action)From{{"+"c,Sub()M(O)=If(M(O)=255,255,M(O)+ 1)},{"-"c,Sub()M(O)=If(M(O)=0,0,M(O)-1)},{"<"c,Sub()O=If(O=0,M.Length,O-1)},{">"c,Sub()O=If(O=M.Length-1,0,O+1)},{"["c,Sub()C=If(M(O)=0,J(C,+1,0,"["c,"]"c),C)},{"]"c,Sub()C=If(M(O)=0,C,J(C,-1,0,"]"c,"["c))},{","c,Sub()M(O)=Console.Read()},{"."c,Sub()Console.Write(Convert.ToChar(M(O)))}}:For C=0To P.Length-1:Dim a=If(Q.ContainsKey(P(C)),Sub()Q(P(C))(),Sub()Exit Sub):a():Next
Binary Lambda Calculus 112
The program shown in the hex dump below
00000000 44 51 a1 01 84 55 d5 02 b7 70 30 22 ff 32 f0 00 |DQ...U...p0".2..|
00000010 bf f9 85 7f 5e e1 6f 95 7f 7d ee c0 e5 54 68 00 |....^.o..}...Th.|
00000020 58 55 fd fb e0 45 57 fd eb fb f0 b6 f0 2f d6 07 |XU...EW....../..|
00000030 e1 6f 73 d7 f1 14 bc c0 0b ff 2e 1f a1 6f 66 17 |.os..........of.|
00000040 e8 5b ef 2f cf ff 13 ff e1 ca 34 20 0a c8 d0 0b |.[./......4 ....|
00000050 99 ee 1f e5 ff 7f 5a 6a 1f ff 0f ff 87 9d 04 d0 |......Zj........|
00000060 ab 00 05 db 23 40 b7 3b 28 cc c0 b0 6c 0e 74 10 |....#@.;(...l.t.|
00000070
expects its input to consist of a Brainfuck program (looking only at bits 0,1,4 to distinguish among ,-.+<>][ ) followed by a ], followed by the input for the Brainfuck program.
Save the above hex dump with xxd -r > bf.Blc
Grab a blc interpreter from https://tromp.github.io/cl/cl.html
cc -O2 -DM=0x100000 -m32 -std=c99 uni.c -o uni
echo -n "++++++++++[>+++++++>++++++++++>+++>+<<<<-]>++.>+.+++++++..+++.>++.<<+++++++++++++++.>.+++.------.--------.>+.>.]" > hw.bf
cat bf.Blc hw.bf | ./uni
Hello World!
Binary Lambda Calculus 104 bytes (829 bits)
I didn't come up with this solution. Go credit whoever put it on wikipedia. However it is amazing.
( λ 11 ) ( λ ( λ λ λ 1 ( λ ( λ 2111 ( λ λ 133 ( λ λ 1 ( λ λ ( λ 7 ( 1 ( 3 ( λ λ λ λ λ 10 ̲ ( 1 ( λ 6143 ) ) ( λ 15 ( 65432 ) ) ) ( λ λ 2 ( ( λ 11 ) ( λ λ λ 2 ( λ λ λ 662 ( λ λ 6 ( λ 1 ( 26 ) 3 ) ( 15 ̲ ( 51 ( λ 1 ) ) ( 5 ( λ 1 ) 1 ) ) ) ) ( 12 ( λ λ λ 312 ) ) ) 1 ( λ λ 2 ) ) ) ) ) ( 3 ( 1 ( λ λ λ λ 9 ( 1 ( λ 51 ( λ 154 ) ) ) ( 24 ( λ 142 ) ) ) ) ( 5 ( 11 ̲ ( λ 1 ) ) ( 12 ̲ ( λ 2 ( ( λ 11 ) ( λ λ λ 1 ( ( λ 11 ) ( λ λ λ 2 ( 1 ( 33 ) ) ( λ 8 ( 771 ) ) ) ) 21 ) ) ) ) ) ) ) ( λ 12 ̲ ( λ 12 ̲ ( λ 3 ( 21 ) ) ) ) ) ) ) ) ( λ λ 1 ) ) ) ( 11 ) ) ( λ ( λ 11 ) ( λ λ 1 ( ( λ 1 ( 1 ( 1 ( λ λ 1 ( λ λ 2 ) 2 ) ) ) ) ( λ λ 2 ( 21 ) ) ( λ λ 1 ) ) ( 22 ) ) ( 1 ( λ λ λ λ λ λ 1 ) ) 1)
PHP, 208 bytes
<?$a=array_fill(0,3e4,$b=0);$A='$a[$b]';$c=explode('|',"|while($A){|}|echo chr($A);|$A=ord(fgetc(STDIN));|++$A;|--$A;".'|++$b;|--$b;');eval(preg_replace('~.~e','$c[strpos(" [].,+-><","\0")]',`cat $argv[1]`));
Tested with PRIME.BF
php ./bf.php PRIME.BF
Primes up to: 100
2 3 5 7 11 13 17 19 23 29 31 37 41 43 47 53 59 61 67 71 73 79 83 89 97
Simplex v.0.5, 103 bytes
br{j'>=?[v'R;Ru]'<=?[v'L;Ru]'+=?[v'I;Ru]'-=?[v'M;Ru]'.=?[v's;Ru]',=?[v'G;Ru]'[=?[v'{;Ru]']=?[v'};Ru]LL}
b ~~ Takes a string input (BF prgm)
r ~~ Reverses the string (pointer is at end)
{ LL} ~~ Loop until empty cell is found
j ~~ Inserts an empty cell at pointer
'> ~~ Sets empty cell to character (>)
= ~~ Sets cell to 1 if > is the current character
?[ ] ~~ Evaluate inside if cell is 1
v u ~~ Goes down, then up
'R ~~ Puts the character (R) to the byte
; ~~ Adds the current cell to the outer program
R ~~ Goes right (frees up next cell)
'< =? [v'L;Ru] ~~ …etc
'+ =? [v'I;Ru]
'- =? [v'M;Ru]
'. =? [v's;Ru]
', =? [v'G;Ru]
'[ =? [v'{;Ru]
'] =? [v'};Ru]
I used this program to prove that Simplex is Turing-complete, it being reducible to a Turing-complete language. It's simple enough; after evaluation of this program, a second program is evaluated, which contains the BF "transcript". Yeah, it really just compiled BF to Simplex. But hey! I think this is the shortest answer thus posted.
(Note that I implemented a theoretically infinite (unbound) version, as Simplex is thus.)
C# (2861 char, ~84 lines)
This is not the prettiest solution to the problem, and probably not all that 'Golf-ish', since I wasn't as concerned with length as I probably should have been. (I didn't remove the comments or extra white space.) I just wanted to try something in a new language, to see if I could. If I did it again, I'd drop the use of the stack for returning from ']' and just look back. Run without command line arguments it runs the hello world program given in the problem description. It accepts one command line argument, the filename of the program to run.
using System;
using System.Collections.Generic;
namespace ConsoleApplication1
{
class Program
{
static void Main(string[] args)
{
String ProgSource;
if (args.Length > 0)
ProgSource = System.IO.File.ReadAllText(args[0]);
else //hello world
ProgSource = "";
Stack<int> stack = new Stack<int>();
char[] bfProg = ProgSource.ToCharArray();
char[] mem = new char[30000];
int ptr = 0;
for (int ip = 0; ip<bfProg.Length; ip++){
switch (bfProg[ip])
{
case ('>'): ptr++; break;
case ('<'): ptr--; break;
case ('+'): mem[ptr]++; break;
case ('-'): mem[ptr]--; break;
case ('.'): Console.Write(mem[ptr]); break;
case (','):
char key = Console.ReadKey(false).KeyChar;
if (key == '\r')
{
key = (char)10;
Console.WriteLine();
}
mem[ptr] = key;
break;
case ('['):
if (mem[ptr] == 0)
{
int openBraces = 1;
//find the closing brace for this expression
for (int x = 1; x < (bfProg.Length - ip); x++)
{
if (bfProg[ip + x] == ']') openBraces--;
if (bfProg[ip + x] == '[') openBraces++;
if (openBraces == 0)
{
if (stack.Peek() == ip) stack.Pop();
ip += x;
break;
}
}
}
else
{
stack.Push(ip);
}
break;
case (']'):
if (mem[ptr] == 0)
stack.Pop();
else
{
ip = stack.Peek();
}
break;
}
}
Console.WriteLine("\n\n\nExecution Completed Sucessfully. Press any key to continue...");
Console.ReadKey();
}
}
}
Edit: Removed unused references.
LiveScript evaling JavaScript: 263
Note that this is currently untested.
p='process.std';g=p+'in.read';f='function(x){return';eval "eval('var i=0,m=[#{[0]*3e4*\,}];'+#g().map(#f'[]+-<>,.'.indexOf(x)).filter(#f~-x).map(#f['#{"while(8){,},i++,i--,8++,8--,#{p}out.write(String.fromCharCode(8)),#g(1)"/','*"','"/'8'*'m[i]'}'][x]).join(''))"
Ungolfed:
p='process.std'
g=p+'in.read'
f='function(x){return'
eval """
eval('
var i = 0,
m=[#{[0]*3e4*\,}];' +
#{g}()
.map(#{f} '[]+-<>,.'.indexOf(x))
.filter(#{f} ~-x)
.map(#{f} ['#{
"while( 8 ){ 0
} 0
i++ 0
i-- 0
8++ 0
8-- 0
#{p}out.write(String.fromCharCode( 8 )) 0
#{g}(1)" / '0' * "','" / '8' * 'm[i]'
}'][x])
.join(''))
"""
C: 317 characters (reads from a file)
#include <stdio.h>
char t[30000],*p=t,b[30000],c;void r(char*a){while((c=*a++)&&c-93){p+=c==62;p-=c==60;*p+=c==43;*p-=c==45;c^46||putchar(*p);c^44||(*p=getchar());if(c==91){while(*p)r(a);c=1;while(c+=(*a==91)-(*a++==93));}}}int main(int n,char**a){FILE*f;f=fopen(a[1],"r");fread(b,1,30000,f);fclose(f);r(b);return 0;}
This is my brainfuck interpreter that I wrote for a couple of months ago, it's quite a bit longer than it needs to be, but that is because I didn't focus on size when I wrote it, I focused on readability (just the fact that it compiles without error and even includes a library suggest that it is heavily shrinkable).
And expanded:
#include <stdio.h>
char t[30000],*p=t,b[30000],c;
void r(char*a){
while((c=*a++)&&c-93){
p+=c==62;
p-=c==60;
*p+=c==43;
*p-=c==45;
c^46||putchar(*p);
c^44||(*p=getchar());
if(c==91){
while(*p)r(a);
c=1;
while(c+=(*a==91)-(*a++==93));
}
}
}
int main(int n,char**a){
FILE*f;
f=fopen(a[1],"r");
fread(b,1,30000,f);
fclose(f);
r(b);
return 0;
}
I might return with an actually golfed version.
Python 2, 223
I admit that I recycled an old program of mine (but had to change it quite a bit, because the old version didn't have input, but error checking...).
P="";i,a=0,[0]*30000
import os,sys
for c in open(sys.argv[1]).read():x="><+-.[,]".find(c);P+=" "*i+"i+=1 i-=1 a[i]+=1 a[i]-=1 os.write(1,chr(a[i])) while+a[i]: a[i]=ord(os.read(0,1)) 0".split()[x]+"\n";i+=(x>4)*(6-x)
exec P
Runs the primes calculator fine.
I see now that Alexandru has an answer that has some similarities. I'll post mny answer anyways, because I think there are some new ideas in it.
Smalltalk, Squeak 4.x flavour 414 chars
Here is an interpreter which works exclusively with streams and block closures:
b:=[:c :i :o :n |
| v |
v := 1 to: n.
v := (v collect: [:x| | t |
t := 0.
Dictionary newFrom: {
$+ -> [t:=t+1\\256].
$- -> [t:=t-1\\256].
$. -> [o nextPut:t].
$, -> [t:=i next].
$< -> [v back].
$> -> [v next].
$[ -> [t=0 and: [
[c next=$[
ifTrue: [(v peek at: $[) value].
c peek=$]] whileFalse.
c next]].
$] -> [t=0 or: [c back.
[c back=$]
ifTrue: [(v peek at: c next) value. c back;back].
c peek=$[] whileFalse.
c next]].
}]) readStream.
[c atEnd] whileFalse: [(v peek at: c next ifAbsent: [[]]) value]]
- c is a readStream on code
- i is a readStream on input (a ByteArray)
- o is a writeStream on output (a ByteArray)
- v is a readStream on interpreters (an Array)
- n is number of cells
For each cell, we create an interpreter - that is a Dictionary which associate a Block to each BF command (a Character).
Those blocks close over a value t, initialized at zero.
The jump instructions are implemented recursively.
The pointers (code and data) are hidden in streams state.
To use the interpreter, we just have to feed this block with proper streams:
c := 'http://esoteric.sange.fi/brainfuck/bf-source/prog/PRIME.BF' asUrl retrieveContents contents readStream.
i := '15\' withCRs withUnixLineEndings asByteArray readStream.
o := #[] writeStream.
n := 30000.
b valueWithArguments: {c.i.o.n}.
^'',o contents
The interpreter can be golfed to 414 chars, using as:Dictionary which is shorter and by removing overflow and underflow protections (the cell value is then unbound).
b:=[:c :i :o :n||v|v:=1to:n.v:=(v collect:[:x||t|t:=0.{$+->[t:=t+1].$-->[t:=t-1].$.->[o nextPut:t].$,->[t:=i next].$<->[v back].$>->[v next].$[->[t=0and:[[c next=$[ifTrue:[(v peek at:$[)value].c peek=$]]whileFalse.c next]].$]->[t=0or:[c back.[c back=$]ifTrue:[(v peek at:c next)value.c back;back].c peek=$[]whileFalse.c next]]}as:Dictionary])readStream.[c atEnd]whileFalse:[(v peek at:c next ifAbsent:[[]])value]].
Lua, 285
loadstring("m,p={0},1 "..io.open(arg[1]):read"*a":gsub("[^.,<>[%]+-]",""):gsub(".",{["."]="io.write(string.char(@)) ",[","]="@=io.read(1):byte() ",["<"]="p=p-1 ",[">"]="p=p+1 @=@or 0 ",["["]="while @~=0 do ",["]"]="end ",["+"]="@=(@+1)%256 ",["-"]="@=(@-1)%256 "}):gsub("@","m[p]"))()
Somewhat readable version:
loadstring( --execute
"m,p={0},1 ".. --initialize memory and pointer
io.open(arg[1]) --open file
:read"*a" --read all
:gsub("[^.,<>[%]+-]","") --strip non-brainfuck
:gsub(".", --for each character left
{["."]="io.write(string.char(@)) ", -- '@' is shortcut for 'm[p]', see below
[","]="@=io.read(1):byte() ",
["<"]="p=p-1 ",
[">"]="p=p+1 @=@or 0 ", --if a before unexplored memory cell, set to 0
["["]="while @~=0 do ",
["]"]="end ",
["+"]="@=(@+1)%256 ", --i like it overflowing
["-"]="@=(@-1)%256 "
}
)
:gsub("@","m[p]") --replace the '@' shortcut
) --loadstring returns a function
() --call it
Works perfectly
Lua, 478, w/o loadstring
local m,p,i,r,c={0},1,1,{},io.open(arg[1]):read"*a"while i<=#c do(({[43]=function()m[p]=(m[p]+1)%256 end,[45]=function()m[p]=(m[p]-1)%256 end,[62]=function()p=p+1 m[p]=m[p]or 0 end,[60]=function()p=p-1 end,[46]=function()io.write(string.char(m[p]))end,[44]=function()m[p]=io.read(1):byte()end,[91]=function()if m[p]==0 then i=select(2,c:find("%b[]",i))else r[#r+1]=i end end,[93]=function()if m[p]==0 then r[#r]=nil else i=r[#r] end end})[c:byte(i)]or function()end)()i=i+1 end
Readable version:
local m, p, i, r, c= --memory, pointer, brackets stack, code
{0}, 1, 1, {}, io.open(arg[1]) --open file
:read"*a" --read it
while i<=#c do --while there's code
(
(
{
[43]=function() -- +
m[p]=(m[p]+1)%256
end,
[45]=function() -- -
m[p]=(m[p]-1)%256
end,
[62]=function() -- >
p=p+1 m[p]=m[p]or 0 --if new memory cell, set it to 0
end,
[60]=function() -- <
p=p-1
end,
[46]=function() -- .
io.write(string.char(m[p]))
end,
[44]=function() -- ,
m[p]=io.read(1):byte()
end,
[91]=function() -- [
if m[p]==0 then
i=select(2,c:find("%b[]",i)) --find matching ]
else
r[#r+1]=i --push position to the stack
end
end,
[93]=function() -- ]
if m[p]==0 then
r[#r]=nil --pop from stack
else
i=r[#r] --go to position on the top of stack
end
end
}
)[c:byte(i)] --transform character into code
or function()end --do nothing on non-brainfuck
)() --run the resulting function
i=i+1 --go to the next opcode
end
PHP 5.4, 296 294 273 263 261 209 191 183 178 166 characters:
I gave it a shot without using eval, but I eventually had to use it
<?$b=0;eval(strtr(`cat $argv[1]`,["]"=>'}',"["=>'while($$b){',"."=>'echo chr($$b);',","=>'$$b=fgetc(STDIN);',"+"=>'$$b++;',"-"=>'$$b--;',">"=>'$b++;',"<"=>'$b--;']));
All commands are working. This heavily abuses variable variables, and spews warnings. However, if one changes their php.ini to squelch warnings (or pipes stderr to /dev/null), this works great.
Verification (It's the "Hello World!" example from Wikipedia): http://codepad.viper-7.com/O9lYjl
Ungolfed, 367 365 335 296 267 characters:
<?php
$a[] = $b = 0;
$p = implode("",file($argv[1])); // Shorter than file_get_contents by one char
$m = array("]" => '}', "[" => 'while($a[$b]){',"." => 'echo chr($a[$b]);', "," => '$a[$b]=fgetc(STDIN);', "+" => '$a[$b]++;', "-" => '$a[$b]--;', ">" => '$b++;', "<" => '$b--;');
$p = strtr($p,$m);
@eval($p);
This should be run via the command line: php bf.php hello.bf
Perl, 120 138
%c=qw(> $p++ < $p-- + D++ - D-- [ while(D){ ] } . print+chrD , D=ord(getc));
$/=$,;$_=<>;s/./$c{$&};/g;s[D]'$b[$p]'g;eval
This runs hello.bf and primes.bf flawlessly:
$ perl bf.pl hello.bf
Hello World!
$ perl bf.pl prime.bf
Primes up to: 100
2 3 5 7 11 13 17 19 23 29 31 37 41 43 47 53 59 61 67 71 73 79 83 89 97
Initialization: The opcode to Perl translation table is stored in %c. The readable form looks like this:
%c=(
'>' => '$p++',
'<' => '$p--',
'+' => '$b[$p]++',
'-' => '$b[$p]--',
'[' => 'while($b[$p]){',
']' => '}',
'.' => 'print chr$b[$p]',
',' => '$b[$p]=ord(getc)',
);
Step 1: Slurp program input to $_ and transform it to Perl code using the translation table. Comments are automatically stripped (replaced with undef) in this step.
Step 2: Uncompress all $b[$p] occurrences
Step 3: Launch the program using eval.
16 bit 8086 machine code: 168 bytes
Here's the base64 encoded version, convert and save as 'bf.com' and run from Windows command prompt: 'bf progname'
gMYQUoDGEFKzgI1XAgIfiEcBtD3NIR8HcmOL2LQ/i88z0s0hcleL2DPA86sz/zP2/sU783NHrL0I
AGgyAU14DTqGmAF194qOoAH/4UfDJv4Fwyb+DcO0AiaKFc0hw7QBzSGqT8MmODV1+jPtO/NzDaw8
W3UBRTxddfJNee/DJjg1dPoz7U509YpE/zxddQFFPFt18U157sM+PCstLixbXUxjTlJWXmV+
EDIT
Here's some assembler (A86 style) to create the executable (I had to reverse engineer this as I'd misplaced the original source!)
add dh,10h
push dx
add dh,10h
push dx
mov bl,80h
lea dx,[bx+2]
add bl,[bx]
mov [bx+1],al
mov ah,3dh
int 21h
pop ds
pop es
jb ret
mov bx,ax
mov ah,3fh
mov cx,di
xor dx,dx
int 21h
jb ret
mov bx,ax
xor ax,ax
repz stosw
xor di,di
xor si,si
inc ch
program_loop:
cmp si,bx
jnb ret
lodsb
mov bp,8
push program_loop
symbol_search:
dec bp
js ret
cmp al,[bp+symbols]
jnz symbol_search
mov cl,[bp+instructions]
jmp cx
forward:
inc di
ret
increment:
inc b es:[di]
ret
decrement:
dec b es:[di]
ret
output:
mov ah,2
mov dl,es:[di]
int 21h
ret
input:
mov ah,1
int 21h
stosb
backward:
dec di
ret
jumpforwardifzero:
cmp es:[di],dh
jnz ret
xor bp,bp
l1: cmp si,bx
jnb ret
lodsb
cmp al,'['
jnz l2
inc bp
l2: cmp al,']'
jnz l1
dec bp
jns l1
ret
jumpbackwardifnotzero:
cmp es:[di],dh
jz ret
xor bp,bp
l3: dec si
jz ret
mov al,[si-1]
cmp al,']'
jnz l4
inc bp
l4: cmp al,'['
jnz l3
dec bp
jns l3
ret
symbols:
db '><+-.,[]'
instructions:
db forward and 255
db backward and 255
db increment and 255
db decrement and 255
db output and 255
db input and 255
db jumpforwardifzero and 255
db jumpbackwardifnotzero and 255
C, 267
#define J break;case
char*p,a[40000],*q=a;w(n){for(;*q-93;q++){if(n)switch(*q){J'>':++p;J'<':--p;J'+':++*p;J'-':--*p;J'.':putchar(*p);J',':*p=getchar();}if(*q==91){char*r=*p&&n?q-1:0;q++;w(r);q=r?r:q;}}}main(int n,char**v){p=a+read(open(v[1],0),a,9999);*p++=93;w(1);}
Run as ./a.out primes.bf
Ungolfed Version:
#define J break;case
char*p,a[40000],*q=a; // packed so program immediately followed by data
w(n){
for(;*q-93;q++){ // until ']'
if(n)switch(*q){ // n = flagged whether loop evaluate or skip(0)
J'>':++p;
J'<':--p;
J'+':++*p;
J'-':--*p;
J'.':putchar(*p);
J',':*p=getchar();
}
if(*q==91){char*r=*p&&n?q-1:0;q++;w(r);q=r?r:q;} // recurse on '[', record loop start
}
}
main(int n,char**v){
p=a+read(open(v[1],0),a,9999);
*p++=93; // mark EOF with extra ']' and set data pointer to next
w(1); // begin as a loop evaluate
}
From sepp2k solution - 148
eval"a=[i=0]*3e4;"+$<.bytes.map{|b|{?.,"putc a[i]",?,,"a[i]=getc",?[,"while a[i]>0",?],"end",?<,"i-=1",?>,"i+=1",?+,"a[i]+=1",?-,"a[i]-=1"}[b]}*";"
eval"a=[i=0]*3e4;"+$<.bytes.map{ can be replaced with a=[i=0]*3e4;eval$<.bytes.map{ -3 bytes
*";" => *$/ -1 bytes
"while a[i]>0" and"end" => "(" and ")while(a[i]>0)" -1 bytes
And we get 143 (5 bytes less)
a=[i=0]*3e4;eval$<.bytes.map{|b|{?.,"putc a[i]",?,,"a[i]=getc",?[,"(",?],")while a[i]>0",?<,"i-=1",?>,"i+=1",?+,"a[i]+=1",?-,"a[i]-=1"}[b]}*$/
And what if there aren't any comments in input (only +-<>[],.) http://codepad.org/EihHsoJO
we can write like this:
a=[i=0]*3e4;eval$<.bytes.map{|b|%w{putc(a[i]) a[i]=getc ( )while(a[i]>0) i-=1 i+=1 a[i]+=1 a[i]-=1}[".,[]<>+-\n".index b]}*$/
And this is 126 bytes, if there wouldn't be "\n" at the end, we can skip it in this part ".,[]<>+-\n" => ".,[]<>+-" saving 2 bytes
And this can be shorten to:
a=[i=0]*3e4;eval$<.bytes.map{|b|%w{i-=1 ( i+=1 )while(0<a[i]) a[i]+=1 a[i]=getc a[i]-=1 putc(a[i])}[b%30%9]}*$/
which is 112 bytes
where b%30%9 is a mapping from ascii code to array index
How to find this formula?
Very easy:
c="<[>]+,-."
(1..99).each do |i|
(1..99).each do |j|
r = c.each_byte.map {|a| a%i%j}.select {|x| x < c.size}.uniq
puts "#{r} #{i} #{j} " if r.size==c.size
end
end
>>>
[0, 1, 2, 3, 4, 5, 6, 7] 30 9
[4, 5, 6, 7, 0, 1, 2, 3] 43 13
[4, 3, 6, 5, 7, 0, 1, 2] 44 12
[0, 7, 2, 1, 3, 4, 5, 6] 52 8
[0, 7, 2, 1, 3, 4, 5, 6] 60 8
So if only we can assume, that there would be only <>+-[],. whe can shorten the solution to 112 bytes
JavaScript - Partial Solution (241 235)
Does not read from file - does not manage PRIMES.BF, but works for Hello World!
// not included in 235 count, the hello world code from wikipedia
var p="++++++++++[>+++++++>++++++++++>+++>+<<<<-]>++.>+.+++++++..+++.>++.<<+++++++++++++++.>.+++.------.--------.>+.>.",
// partial solution - dies on primes
a=[0,0,0,0,0],b=0
eval(p.replace(/[^\][.,+><-]/g,'').replace(/(.)/g,function(e){return "0while(a[b]){0}0console.log(String.fromCharCode(a[b]))0a[b]=prompt()0++a[b]0--a[b]0++b0--b".split(0)[" [].,+-><".search(new RegExp("\\"+e))]+";"}))
Just copy and paste it into javascript console to see it in action. Works in node.js, or broswer.
I was hoping to get PRIMES.BF to work in node.js, but not been able to emulate STDIN in a synchronous way yet.
With comments
// should read from file - easy with node.js
// this is the `Hello World! ` program from wikipedia
var p="++++++++++[>+++++++>++++++++++>+++>+<<<<-]>++.>+.+++++++..+++.>++.<<+++++++++++++++.>.+++.------.--------.>+.>.",
// declare a and b. If a needs to be longer, can use:
// a=[];for(0;a.length<30000;a.push(0))b=0
a=[0,0,0,0,0],b=0
// evaluate
eval(
// the brainfuck code
p
// replacing all the non brainfuck commands with nothing
.replace(/[^\][.,+><-]/g,'')
// replacing all commands (captured in parenthesis) with callback
.replace(/(.)/g,function(e){
// return swapped commands
return "0while(a[b]){0}0console.log(String.fromCharCode(a[b]))0a[b]=prompt()0++a[b]0--a[b]0++b0--b"
// split into array on the 0 (used as seperator - shorter than "|" when
// called in .split(0) function)
.split(0)[
// matching brainfuck commands
" [].,+-><"
// searched with escaped, captured command
.search(new RegExp("\\"+e))
// add a semicolon to all statements - extra semicolons do not interfere
// with execution of javascript
]+";"
})
)
Python 275 248 255
I decided to give it a try.
import sys
i=0
b=[0]*30000
t=''
for e in open(sys.argv[1]).read():
t+=' '*i+['i+=1','i-=1','b[i]+=1','b[i]-=1','sys.stdout.write(chr(b[i]))','b[i]=ord(sys.stdin.read(1))','while b[i]:','pass','']['><+-.,['.find(e)]+'\n'
i+=(92-ord(e))*(e in'][')
exec t
C, 333 characters
This is my first BF interpreter and the first golf I actually had to debug.
This runs the prime number generator on Mac OS X/GCC, but an additional #include<string.h> may be necessary at a cost of 19 more characters if the implicit definition of strchr doesn't happen to work on another platform. Also, it assumes O_RDONLY == 0. Aside from that, leaving int out of the declaration of M saves 3 characters but that doesn't seem to be C99 compliant. Same with the third * in b().
This depends on the particulars of ASCII encoding. The Brainfuck operators are all complementary pairs separated by a distance of 2 in the ASCII code space. Each function in this program implements a pair of operators.
#include<unistd.h>
char C[30000],*c=C,o,P[9000],*p=P,*S[9999],**s=S,*O="=,-\\",*t;
m(){c+=o;}
i(){*c-=o;}
w(){o<0?*c=getchar():putchar(*c);}
b(){if(o>0)*c?p=*s:*--s;else if(*c)*++s=p;else while(*p++!=93)*p==91&&b();}
int(*M[])()={m,i,w,b};
main(int N,char**V){
read(open(V[1],0),P,9e3);
while(o=*p++)
if(t=strchr(O,++o&~2))
o-=*t+1,
M[t-O]();
}
Ruby 1.8.7, 188 185 149 147 characters
eval"a=[i=0]*3e4;"+$<.bytes.map{|b|{?.,"putc a[i]",?,,"a[i]=getc",?[,"while a[i]>0",?],"end",?<,"i-=1",?>,"i+=1",?+,"a[i]+=1",?-,"a[i]-=1"}[b]}*";"
Somewhat readable version:
code = "a = [0] * 3e4; i = 0;"
more_code ARGF.bytes.map {|b|
replacements = {
?. => "putc a[i]",
?, => "a[i] = getc",
?[ => "while a[i] > 0 do",
?] => "end",
?< => "i -= 1",
?> => "i += 1",
?+ =>"a[i]+=1",
?- =>"a[i]-=1"
}
replacements[b]
}.join(";")
eval code+more_code
As you see I shamelessly stole your idea of translating to the host language and then using eval to run it.
Delphi, 397 382 378 371 366 364 328 characters
Eat this Delphi!
328 var p,d:PByte;f:File;z:Word=30000;x:Int8;begin p:=AllocMem(z+z);d:=p+z;Assign(F,ParamStr(1));Reset(F,1);BlockRead(F,p^,z);repeat z:=1;x:=p^;case x-43of 1:Read(PChar(d)^);3:Write(Char(d^));0,2:d^:=d^+44-x;17,19:d:=d+x-61;48,50:if(d^=0)=(x=91)then repeat p:=p+92-x;z:=z+Ord(p^=x)-Ord(p^=x xor 6);until z=0;end;Inc(p)until x=0;end.
Here the same code, indented and commented :
var
d,p:PByte;
x:Int8;
f:File;
z:Word=30000;
begin
// Allocate 30000 bytes for the program and the same amount for the data :
p:=AllocMem(z+z);
d:=p+z;
// Read the file (which path must be specified on the command line) :
Assign(F,ParamStr(1));
Reset(F,1);
BlockRead(F,p^,z);
// Handle all input, terminating at #0 (better than the spec requires) :
repeat
// Prevent a begin+end block by preparing beforehand (values are only usable in '[' and ']' cases) :
z:=1; // Start stack at 1
x:=p^; // Starting at '[' or ']'
// Choose a handler for this token (the offset saves 1 character in later use) :
case x-43of
1:Read(PChar(d)^); // ',' : Read 1 character from input into data-pointer
3:Write(Char(d^)); // '.' : Write 1 character from data-pointer to output
0,2:d^:=d^+44-x; // '+','-' : Increase or decrease data
17,19:d:=d+x-61; // '<','>' : Increase or decrease data pointer
48,50: // '[',']' : Start or end program block, the most complex part :
if(d^=0)=(x=91)then // When (data = 0 and forward), or when (data <> 0 and backward)
repeat //
p:=p+92-x; // Step program 1 byte back or forward
z:=z+Ord(p^=x) // Increase stack counter when at another bracket
-Ord(p^=x xor 6); // Decrease stack counter when at the mirror char
until z=0; // Stop when stack reaches 0
end;
Inc(p)
until x=0;
end.
This one took me a few hours, as it's not the kind of code I normally write, but enjoy!
Note : The prime test works, but doesn't stop at 100, because it reads #13 (CR) before #10 (LF)... do other submissions suffer this problem too when running on CRLF OSes?
OCaml(lex), 497 chars
OCamllex is part of the standard distribution of OCaml.
{let a=Array.create 30000 0
let(%)f g h=f(g h)
let s v i=a.(i)<-v;i
let o d i=s(a.(i)+d)i
let p i=print_char(Char.chr a.(i));flush stdout;i
let r i=s(Char.code(input_char stdin))i
let rec w g i=if 0=a.(i)then i else w g(g i)
let n x=x}
rule t f=parse
|'>'{t(succ%f)lexbuf}
|'<'{t(pred%f)lexbuf}
|'+'{t((o 1)%f)lexbuf}
|'-'{t((o(-1))%f)lexbuf}
|'.'{t(p%f)lexbuf}
|','{t(r%f)lexbuf}
|'['{t((w(t n lexbuf))%f)lexbuf}
|']'|eof{f}
|_{t f lexbuf}
{let _=t n(Lexing.from_channel(open_in Sys.argv.(1)))0}
Save as b.mll and run with
ocamllex b.mll && ocaml b.ml prime.bf
I don't like parsing by hand, so I used the provided lexer generator. From the tokens read, we compose a function for the whole brainf*ck program.
Lua (to long)
I made some Lua implementation, but I can't get the bracket stuff right. Here it is anyway:
-- > increment the data pointer (to point to the next cell to the right).
-- < decrement the data pointer (to point to the next cell to the left).
-- + increment (increase by one) the byte at the data pointer.
-- - decrement (decrease by one) the byte at the data pointer.
-- . output a character, the ASCII value of which being the byte at the data pointer.
-- , accept one byte of input, storing its value in the byte at the data pointer.
-- [ if the byte at the data pointer is zero, then instead of moving the instruction pointer forward to the next command, jump it forward to the
-- command after the matching ] command*.
-- ] if the byte at the data pointer is nonzero, then instead of moving the instruction pointer forward to the next command, jump it back to the
-- command after the matching [ command*.
s=setmetatable({0},{__index=function() return 0 end})
i=1 -- index array
j=1 -- index input
l=loadstring
t="><+-.,[]"
o=0
fh=arg[1] and io.open(arg[1]) or io.stdin
I=fh:read"*a":gsub("[^><%+%-%.,%[%]]","")
fh:close()
print(I)
for k=1,#I do io.write(k%5==1 and"+"or"-") end
io.write"\n"
for k=1,math.ceil(#I/5) do local n=5*(k-1)+1 local s=(" "):rep(4-math.floor(math.log10(n))) io.write(n,s) end
io.write"\n"
dbg=true
f={
"i=i+1 ", -- array index ++
"i=i-1 ", -- array index --
"s[i]=(s[i]+1)%256 ", -- byte + 1
"s[i]=(s[i]-1)%256 ", -- byte - 1
"io.write(string.char(s[i])) ", -- put byte
"local c=io.read(1):byte()s[i]=c==10 and s[i] or c", -- read byte "Newline required!"
[=[if s[i]==0 then
o=0
repeat
if dbg then print(j,"Forward!",o,b) end
b=I:sub(j,j):match'[%[%]]'
o= b=='['and o+1 or b==']' and o-1 or o;
j=j+1
until b==']' and o == 0
end
]=], -- jump to matching ]
[=[
if s[i]~=0 then
o=0
count=0
repeat
if dbg then print(j,"Backwards",o,b) end
b=I:sub(j,j):match"[%[%]]"
o= b=='['and o-1 or b==']' and o+1 or o;
j=j-1
until b=='[' and o == 0
end
]=], -- jump to matching ]
}
for k,v in ipairs(f) do f[t:sub(k,k)],e=l(v) if e then error(e)end end
function run()
j=1
while j<=#I do
f[I:sub(j,j)]()
j=j+1
end
end
res,err = pcall(run)
if not res then
print('error=',err)
print('Dumping state')
print('','stack')
for k,v in pairs(s) do print("",k,v) end
end
if debug then
print("stack")
for k,v in pairs(s) do print(k,v) end
end
It doesn't pass the prime test, but acts nicely with Hello World and all echo and reverse examples I tried. So if anyone sees the bug, feel free to catch it.
C 284 362 (From a file)
#include <stdio.h>
char b[30000],z[9999],*p=b,c,*a,i;f(char*r,int s){while(c=*a++){if(!s){(c-62)?(c-60)?(c-43)?(c-45)?(c-46)?(c-44)?0:(*p=getchar()):putchar(*p):--*p:++*p:--p:++p;if(c==91)f(a,!*p);else if(c==93){if(!*p)return;else a=r;}}else{if(c==93){--s;if(!*p&&!s)return;}else if(c==91){s++;}}}}main(int c,char**v){fread(z,1,9999,fopen(*++v,"r"));a=z;f(0,0);}
Primes:
Primes up to: 100 2 3 5 7 11 13 17 19 23 29 31 37 41 43 47 53 59 61 67 71 73 79 83 89 97 Press any key to continue . . .
Compiled and ran successfully VS2008
Original solution failed to recognize loops that were initially set to zero. Still some room to golf. But finally solves the Prime Number program.
Ungolfed:
#include <stdio.h>
char b[30000],z[9999],*p=b,c,*a,i;
f(char*r,int s)
{
while(c=*a++)
{
if(!s)
{
(c-62)?(c-60)?(c-43)?(c-45)?(c-46)?(c-44)?0:(*p=getchar()):putchar(*p):--*p:++*p:--p:++p;
if(c==91)f(a,!*p);
else if(c==93){if(!*p)return;else a=r;}
}
else
{
if(c==93)
{
--s;
if(!*p&&!s)return;
}
else if(c==91)
{
s++;
}
}
}
}
main(int c,char**v){
fread(z,1,9999,fopen(*++v,"r"));
a=z;
f(0,0);
}
Tests:
Haskell, 457 413 characters
import IO
import System
z=return
'>'#(c,(l,d:r))=z(d,(c:l,r))
'<'#(d,(c:l,r))=z(c,(l,d:r))
'+'#(c,m)=z(succ c,m)
'-'#(c,m)=z(pred c,m)
'.'#t@(c,_)=putChar c>>hFlush stdout>>z t
','#(_,m)=getChar>>=(\c->z(c,m))
_#t=z t
_%t@('\0',_)=z t
i%t=i t>>=(i%)
b('[':r)=k$b r
b(']':r)=(z,r)
b(c:r)=f(c#)$b r
b[]=(z,[])
f j(i,r)=(\t->j t>>=i,r)
k(i,r)=f(i%)$b r
main=getArgs>>=readFile.head>>=($('\0',("",repeat '\0'))).fst.b
This code "compiles" the BF program into an IO action of the form State -> IO State the state is a zipper on an infinite string.
Sad that I had to expend 29 characters to turn buffering off. Without those, it works, but you don't see the prompts before you have to type input. The compiler itself (b, f, and k) is just 99 characters, the runtime (# and %) is 216. The driver w/initial state another 32.
>ghc -O3 --make BF.hs
[1 of 1] Compiling Main ( BF.hs, BF.o )
Linking BF ...
>./BF HELLO.BF
Hello World!
>./BF PRIME.BF
Primes up to: 100
2 3 5 7 11 13 17 19 23 29 31 37 41 43 47 53 59 61 67 71 73 79 83 89 97
update 2011-02-15: Incorporated J B's suggestions, did a little renaming, and tightened up main
golfscript, partial solution only, 150 chars
:i;[0]30000*[]0 "#{File.open('f').read}"{{\(@=\''if}+['>+\\(@\\' '<@+\\)' '+1+256%' '-1- 256%' ".[0$]''+print " ',;i(\:i;' '[{.}{' ']}while']\%}%~;;;;
i am greatly indebted to the pattern of generating your own source and then eating it, as others have already posted.
misfeatures:
- only parses brainfuck code from the file
'f'. - all input you want to read with
','must be piped in at the beginning. - runs hello world, yet dies somewhere during prime.bf. i'm not sure why. i did read somewhere that golfscript is broken for nested while loops, so that might be it.
- stores a char=>string map in a way that is entertainingly horrible, at least to me.
I've tried loading arbitrary files with constructions like "#{File.open(" "some_file.bf" ").read}" + + but Ruby seems to helpfully escape the "#" for me so i dont accidentally load the file im trying to load. On the other hand, embedding "#{getc}" works okay for reading from stdin, but there's still the restriction that input is non-interactive - only stuff piped in at the start is read. Anyone know a way around one or more of these input issues?
F#: 489 chars
The following program doesn't jump at '[' / ']' instructions, but scans the source code for the next matching token. This of course makes it kind of slow, but it can still find the primes under 100. F# integer types don't overflow but wrap.
Here's the short version:
[<EntryPoint>]
let M a=
let A,B,i,p,w=Array.create 30000 0uy,[|yield!System.IO.File.ReadAllText a.[0]|],ref 0,ref 0,char>>printf"%c"
let rec g n c f a b=if c then f i;if B.[!i]=a then g(n+1)c f a b elif B.[!i]=b then(if n>0 then g(n-1)c f a b)else g n c f a b
while !i<B.Length do(let x=A.[!p]in match B.[!i]with|'>'->incr p|'<'->decr p|'+'->A.[!p]<-x+1uy|'-'->A.[!p]<-x-1uy|'.'->w x|','->A.[!p]<-byte<|stdin.Read()|'['->g 0(x=0uy)incr '['']'|']'->g 0(x>0uy)decr ']''['|_->());incr i
0
A nasty gotcha was that the primes.bf program chokes on windows newlines. In order to run it I had to save the input number to a UNIX formatted text document and feed it to the program with a pipe:
interpret.exe prime.bf < number.txt
Edit: entering Alt+010 followed by Enter also works in Windows cmd.exe
Here's the longer version:
[<EntryPoint>]
let Main args =
let memory = Array.create 30000 0uy
let source = [| yield! System.IO.File.ReadAllText args.[0] |]
let memoryPointer = ref 0
let sourcePointer = ref 0
let outputByte b = printf "%c" (char b)
let rec scan numBraces mustScan adjustFunc pushToken popToken =
if mustScan then
adjustFunc sourcePointer
if source.[!sourcePointer] = pushToken then
scan (numBraces + 1) mustScan adjustFunc pushToken popToken
elif source.[!sourcePointer] = popToken then
if numBraces > 0 then scan (numBraces - 1) mustScan adjustFunc pushToken popToken
else
scan numBraces mustScan adjustFunc pushToken popToken
while !sourcePointer < source.Length do
let currentValue = memory.[!memoryPointer]
match source.[!sourcePointer] with
| '>' -> incr memoryPointer
| '<' -> decr memoryPointer
| '+' -> memory.[!memoryPointer] <- currentValue + 1uy
| '-' -> memory.[!memoryPointer] <- currentValue - 1uy
| '.' -> outputByte currentValue
| ',' -> memory.[!memoryPointer] <- byte <| stdin.Read()
| '[' -> scan 0 (currentValue = 0uy) incr '[' ']'
| ']' -> scan 0 (currentValue > 0uy) decr ']' '['
| _ -> ()
incr sourcePointer
0
Windows PowerShell, 204
'$c=,0*3e4;'+@{62='$i++
';60='$i--
';43='$c[$i]++
';45='$c[$i]--
';44='$c[$i]=+[console]::ReadKey().keychar
';46='write-host -n([char]$c[$i])
';91='for(;$c[$i]){';93='}'}[[int[]][char[]]"$(gc $args)"]|iex
Fairly straightforward conversion of the instructions and then Invoke-Expression.
History:
- 2011-02-13 22:24 (220) First attempt.
- 2011-02-13 22:25 (218)
3e4is shorter than30000. - 2011-02-13 22:28 (216) Unnecessary line breaks. Matching on integers instead of characters is shorter.
- 2011-02-13 22:34 (207) Used indexes into a hash table instead of the
switch. - 2011-02-13 22:40 (205) Better cast to string removes two parentheses.
- 2011-02-13 22:42 (204) No need for a space after the argument to
Write-Host.
C, 374 368
Reads from a file. Passes PRIME.BF test.
Usage: ./a.out PRIME.BF
#include <stdio.h>
main(int c,char**v){int m[30000],s[99],p=0,i=0,n=0;char l[9999],d;FILE*f=fopen(v[1],"r");for(l[i]=0;i<9999&&l[i]!=EOF;l[i]=getc(f))i++;for(i=1;d=l[i];i++){if(!n){p+=d-62?0:1;p-=d-60?0:1;m[p]+=d-43?0:1;m[p]-=d-45?0:1;if(d==46)putchar(m[p]);if(d==44){m[p]=getchar();}if(d==93){i=s[c]-1;c--;n++;}}if(d==91){if(m[p]){c++;s[c]=i;}else{n++;}}n-=d-93?0:1;}}
Reformatted:
#include <stdio.h>
main(int c,char**v){
int m[3000],s[99],p=0,i=0,n=0;
char l[9999],d;
FILE*f=fopen(v[1],"r");
for(l[i]=0;i<9999&&l[i]!=EOF;l[i]=getc(f))i++;
for(i=1;d=l[i];i++){
if(!n){ // > < + - . , ] \n [ ]
p+=d-62?0:1;
p-=d-60?0:1;
m[p]+=d-43?0:1;
m[p]-=d-45?0:1;
if(d==46)putchar(m[p]);
if(d==44){m[p]=getchar();}
if(d==93){i=s[c]-1;c--;n++;}
}
if(d==91){if(m[p]){c++;s[c]=i;}else{n++;}}
n-=d-93?0:1;
}
}