148
\$\begingroup\$

Write the shortest program in your favourite language to interpret a brainfuck program.

You should take a string of source code, containing only valid brainfuck commands +-[]<>.,, and a string of ASCII input to the program, and return the output of the brainfuck program.

The program operates on a tape of at least 30000 cells each containing an unsigned 8-bit integer (i.e. 0 to 255). It has a tape pointer, which initially points to the first cell in the tape, and an instruction pointer which points to the first character of the source code.

Brainfuck has eight instructions:

  • + increments the cell at the tape pointer by 1.
  • - decrements the cell at the tape pointer by 1.
  • < moves the tape pointer left by one cell.
  • > moves the tape pointer right by one cell.
  • , reads a byte of input into the cell at the tape pointer. Reading past the end of input is undefined behaviour.
  • . prints the cell at the tape pointer as an ASCII character.
  • [ jumps to its matching ] if the cell at the tape pointer is zero.
  • ] jumps to the instruction before its matching [. You can assume [ and ] are balanced in the input.

After executing an instruction, the instruction pointer is moved forward by one character.

The cells should contain at least 8-bit unsigned integers (i.e. 0 to 255), and incrementing a cell containing 255 or decrementing 0 is undefined behaviour. Likewise, the tape should contain at least 30000 cellls, and going past these is undefined behaviour. This means that you can implement arbitrarily large integers and an arbitrarily large tape, but the program will never attempt to use values outside of 0...255 or more than 30000 cells.

Here's a test case that reads a decimal integer from input, followed by a newline, and outputs a list of primes up to that number:

>++++++++[<++++++++>-]<++++++++++++++++.[-]>++++++++++[<++++++++++>-]<++++++++++++++.[-]>++++++++++[<++++++++++>-]<+++++.[-]>++++++++++[<++++++++++>-]<+++++++++.[-]>++++++++++[<++++++++++>-]<+.[-]>++++++++++[<++++++++++>-]<+++++++++++++++.[-]>+++++[<+++++>-]<+++++++.[-]>++++++++++[<++++++++++>-]<+++++++++++++++++.[-]>++++++++++[<++++++++++>-]<++++++++++++.[-]>+++++[<+++++>-]<+++++++.[-]>++++++++++[<++++++++++>-]<++++++++++++++++.[-]>++++++++++[<++++++++++>-]<+++++++++++.[-]>+++++++[<+++++++>-]<+++++++++.[-]>+++++[<+++++>-]<+++++++.[-]+[->,----------[<+>-------------------------------------->[>+>+<<-]>>[<<+>>-]<>>>+++++++++[<<<[>+>+<<-]>>[<<+>>-]<[<<+>>-]>>-]<<<[-]<<[>+<-]]<]>>[<<+>>-]<<>+<-[>+[>+>+<<-]>>[<<+>>-]<>+<-->>>>>>>>+<<<<<<<<[>+<-<[>>>+>+<<<<-]>>>>[<<<<+>>>>-]<<<>[>>+>+<<<-]>>>[<<<+>>>-]<<<<>>>[>+>+<<-]>>[<<+>>-]<<<[>>>>>+<<<[>+>+<<-]>>[<<+>>-]<[>>[-]<<-]>>[<<<<[>+>+<<-]>>[<<+>>-]<>>>-]<<<-<<-]+>>[<<[-]>>-]<<>[-]<[>>>>>>[-]<<<<<<-]<<>>[-]>[-]<<<]>>>>>>>>[-<<<<<<<[-]<<[>>+>+<<<-]>>>[<<<+>>>-]<<<>>[>+<-]>[[>+>+<<-]>>[<<+>>-]<>+++++++++<[>>>+<<[>+>[-]<<-]>[<+>-]>[<<++++++++++>>-]<<-<-]+++++++++>[<->-]<[>+<-]<[>+<-]<[>+<-]>>>[<<<+>>>-]<>+++++++++<[>>>+<<[>+>[-]<<-]>[<+>-]>[<<++++++++++>>>+<-]<<-<-]>>>>[<<<<+>>>>-]<<<<>[-]<<+>]<[[>+<-]+++++++[<+++++++>-]<-><.[-]>>[<<+>>-]<<-]>++++[<++++++++>-]<.[-]>>>>>>>]<<<<<<<<>[-]<[-]<<-]++++++++++.[-] 

Its output will look something like this:

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 

Additionally, a few smaller test cases:

  • ++++++++[>++++[>++>+++>+++>+<<<<-]>+>+>->>+[<]<-]>>.>---.+++++++..+++.>>.<-.<.+++.------.--------.>>+.>++. should take no input and output Hello World!
  • ++++++++[->+>++++++<<]>++[->.+<] should output 0123456789
  • ,[.,] is a cat program - it should output the string given as input
\$\endgroup\$
27
  • 10
    \$\begingroup\$ You should clarify about 1) size of memory 2) is memory circled 4) maybe any other details \$\endgroup\$ Commented Jan 28, 2011 at 1:37
  • 3
    \$\begingroup\$ I wonder if there should be two categories: Those programs that use eval (or shell out to compile) -- and those that don't. \$\endgroup\$ Commented Feb 15, 2011 at 7:52
  • 48
    \$\begingroup\$ I'd love to see someone answer this in brainfuck. \$\endgroup\$ Commented Mar 14, 2011 at 19:15
  • 10
    \$\begingroup\$ What does "no EOF symbol" mean? That the cell value remains unchanged when trying , on EOF? Or that it's up to us to choose a value when trying , on EOF? Or is EOF undefined behaviour altogether? \$\endgroup\$ Commented Apr 1, 2016 at 14:07
  • 6
    \$\begingroup\$ Likewise, what should happen when someone tries to leave the 30k cells to either side? Should the tape head remain in place or is this undefined behaviour? \$\endgroup\$ Commented Apr 1, 2016 at 14:09

88 Answers 88

6
\$\begingroup\$

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");}; 

Try it online!

-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.

\$\endgroup\$
1
  • 1
    \$\begingroup\$ 253 bytes \$\endgroup\$ Commented Aug 21, 2020 at 7:22
5
\$\begingroup\$

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 
\$\endgroup\$
5
\$\begingroup\$

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 bracket
  • x: describes the main loop, i.e. drives the state transitions
  • f: 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!

\$\endgroup\$
5
  • 4
    \$\begingroup\$ Welcome to the site! This is a very impressive first answer. Be sure to link to an external site such as Try It Online! in future answers, so that other users can run and verify your program. Hope you enjoy CGCC! \$\endgroup\$ Commented Jun 24, 2020 at 21:58
  • \$\begingroup\$ Hi @cairdcoinheringaahing, thanks for letting me know. 👍 I took a look at it and I am left worndering how one could add a default file for a code snippet to read in. My code takes the first provided argument as a filepath and then reads from said file, as such I am unsure how to set that up... \$\endgroup\$ Commented Jun 25, 2020 at 6:51
  • \$\begingroup\$ It isn’t usually the easiest way to take input on TIO, but you can put something in the Header section along the lines of open(“filename”).write(“bf code”) and have filename in the Arguments section: like this, but with your code in the Code section (the link is too long for a comment) \$\endgroup\$ Commented Jun 25, 2020 at 10:04
  • \$\begingroup\$ Sounds straight forward enough. Will do. 👍 \$\endgroup\$ Commented Jun 25, 2020 at 10:05
  • \$\begingroup\$ 696 bytes \$\endgroup\$ Commented Sep 6, 2020 at 1:05
5
\$\begingroup\$

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 
\$\endgroup\$
4
\$\begingroup\$

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; } } 
\$\endgroup\$
2
  • \$\begingroup\$ 3000 vs 30000. Your buffer is too small. The program size is too small also. \$\endgroup\$ Commented Jan 31, 2011 at 12:54
  • \$\begingroup\$ I made a typo, fixed. What do you mean by program size? If you mean max file size, you didn't specify a minimum it should handle. \$\endgroup\$ Commented Jan 31, 2011 at 15:27
4
\$\begingroup\$

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 
\$\endgroup\$
3
  • \$\begingroup\$ What is 104 bytes? Compiled machine code? I don't think so, boilerplate in programs are huge. \$\endgroup\$ Commented Nov 26, 2017 at 2:05
  • \$\begingroup\$ Or the compiled function size? \$\endgroup\$ Commented Nov 26, 2017 at 2:06
  • 2
    \$\begingroup\$ the assembled code is 104 bytes long. It will compile and run any supplied bf code. \$\endgroup\$ Commented Nov 26, 2017 at 2:34
4
\$\begingroup\$

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.

\$\endgroup\$
4
\$\begingroup\$

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 
\$\endgroup\$
4
\$\begingroup\$

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

\$\endgroup\$
3
  • 1
    \$\begingroup\$ Shouldn't #define a 3000 be #define a 30000 since the array size is specified to be 30000 bytes in the challenge? \$\endgroup\$ Commented Nov 17, 2020 at 1:54
  • \$\begingroup\$ @ceilingcat sorry I would have added yours if I had seen it sooner, thanks for the solution tho! \$\endgroup\$ Commented Dec 16, 2020 at 15:51
  • \$\begingroup\$ Suggest 'u0' instead of 30000 \$\endgroup\$ Commented Apr 16, 2021 at 4:17
4
\$\begingroup\$

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 } 
\$\endgroup\$
1
  • 1
    \$\begingroup\$ Welcome to Code Golf, nice answer! user uses Scala a lot, you two would probably get along :p \$\endgroup\$ Commented Oct 6, 2021 at 17:11
4
\$\begingroup\$

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.bf32 if 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 u8 cells, non-wrapping
  • Expects the default Linux ELF startup state.
    • argv is an array at sp + 4
    • The unused stack memory is clear
    • All registers but sp and pc are zeroed
  • Segfaults to exit by leaving the end of the .text section like a true gigachad.
  • EOF leaves the cell unchanged.
\$\endgroup\$
4
\$\begingroup\$

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 

Try it online!

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...

\$\endgroup\$
4
\$\begingroup\$

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 ..(..<(..... 

Try it online!

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.
  • ]: ret
    • Return unconditionally to the pushed address of [ to test again
  • ! (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!input or 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? 🤓

\$\endgroup\$
4
\$\begingroup\$

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 

Try it online!

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) 
\$\endgroup\$
7
  • \$\begingroup\$ 666 bytes (see codegolf.stackexchange.com/a/272705/91267 for more information on why the } at the end can be removed) \$\endgroup\$ Commented May 21, 2024 at 7:34
  • \$\begingroup\$ 652 bytes \$\endgroup\$ Commented May 21, 2024 at 12:58
  • \$\begingroup\$ -6ish bytes by replacing 2^16 with 4^8 everywhere \$\endgroup\$ Commented Aug 4, 2024 at 11:28
  • \$\begingroup\$ Actually 631 with a lot of bitmask trickery \$\endgroup\$ Commented Aug 4, 2024 at 11:52
  • 1
    \$\begingroup\$ Actually 611 \$\endgroup\$ Commented Aug 4, 2024 at 20:33
3
\$\begingroup\$

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.

\$\endgroup\$
3
\$\begingroup\$

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.

\$\endgroup\$
2
  • 1
    \$\begingroup\$ @mbomb007 - Updated. Completely forgot I even did this one. (Didn't even realize anyone even read these old questions) \$\endgroup\$ Commented Aug 31, 2015 at 21:18
  • \$\begingroup\$ Not only do people still read them, they still answer and golf them. \$\endgroup\$ Commented Nov 15, 2016 at 17:08
3
\$\begingroup\$

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 
\$\endgroup\$
3
\$\begingroup\$

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 
\$\endgroup\$
3
\$\begingroup\$

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.

\$\endgroup\$
1
  • 1
    \$\begingroup\$ 160 bytes \$\endgroup\$ Commented Sep 6, 2020 at 2:06
3
\$\begingroup\$

[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]();} 

https://godbolt.org/z/7xxbqM

\$\endgroup\$
1
  • \$\begingroup\$ Nested loop bug fixed 301 bytes \$\endgroup\$ Commented Feb 25, 2022 at 10:07
3
\$\begingroup\$

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 

Try it online!

How it works

  • c - BF code to interpret
  • m - memory, not cyclic (32768 total cells, 3 reserved)
  • i - instruction pointer
  • d - data pointer
  • x - current command (-1 to 7)
  • s - stack of return addresses
  • k - depth at which execution is allowed
  • u - flag: is memory update required
  • e - 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, d is just a shortcut.
  • m[2] - depth counter, it increases on [ and decreases on ]. If depth is more than k, 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.

\$\endgroup\$
4
  • 2
    \$\begingroup\$ Welcome to Code Golf! \$\endgroup\$ Commented Jun 20, 2019 at 0:39
  • \$\begingroup\$ @Stephen thank you! I really appreciate you welcome comment, because at the moment I can communicate in my own answers only ;) \$\endgroup\$ Commented Jun 20, 2019 at 11:10
  • 1
    \$\begingroup\$ You can replace (1-x%2*2)*u with u-x%2*2*u to win 2 characters. :-) \$\endgroup\$ Commented Feb 5, 2021 at 22:34
  • \$\begingroup\$ @PârisDouady thanks! Alas, I found that my latest changes broke it a bit. Gonna fix it first and then apply your great suggestion. \$\endgroup\$ Commented Feb 8, 2021 at 23:52
3
\$\begingroup\$

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`) 

Try it online!

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 (JS MAX_SAFE_INTEGER)
  • Negative numbers: allowed
  • EOF: 0 (solution with -2 bytes possible by letting EOF corrupt the tape with a NaN)
\$\endgroup\$
1
  • \$\begingroup\$ This program works even if non-commands are added to the input. If you don't mind losing that functionality, 192 bytes. \$\endgroup\$ Commented Jun 26 at 9:16
3
\$\begingroup\$

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``` 
\$\endgroup\$
1
  • \$\begingroup\$ Welcome to Code Golf, and nice answer! \$\endgroup\$ Commented Sep 20, 2023 at 16:37
3
\$\begingroup\$

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 

Try it online!

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 
\$\endgroup\$
1
  • \$\begingroup\$ function g(n::String)c=readchomp(open(n));b="a[k]";j="a=zeros(UInt8,30000);k=1;";for i=1:length(c) z=c[i];j*=z=='<'?"k-=1;":z=='>'?"k+=1;":z=='+'?"$b+=1;":z=='-'?"$b-=1;":z=='['?"while $b>0 ":z==']'?"end;":z=='.'?"print(Char($b));":z==','?"s=readline();$b=s==\"\"?10:s[1];":"";end;@eval$(parse(j));end \$\endgroup\$ Commented Nov 18, 2023 at 19:11
3
\$\begingroup\$

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.

\$\endgroup\$
2
  • 1
    \$\begingroup\$ you don't need to initialize variables to zero and fill the lists with zeros, since you can assume a fresh environment \$\endgroup\$ Commented May 17, 2024 at 17:32
  • \$\begingroup\$ @MarcMush ah! I didn't know I could do that. I'll try to fix it once my calculator starts working again since its been having temper tantrums as of late and not turning on =c \$\endgroup\$ Commented May 20, 2024 at 13:32
3
\$\begingroup\$

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 flip and 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.
\$\endgroup\$
3
\$\begingroup\$

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.

Try it online!

\$\endgroup\$
3
\$\begingroup\$

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;} 

Try it online!

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--;}}} 
\$\endgroup\$
0
3
\$\begingroup\$

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)

\$\endgroup\$
3
\$\begingroup\$

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); } 
\$\endgroup\$

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.