150
\$\begingroup\$

Write the shortest program in your favourite language to interpret a brainfuck program. The program is read from a file. Input and output are standard input and standard output.

  1. Cell size: 8bit unsigned. Overflow is undefined.
  2. Array size: 30000 bytes (not circled)
  3. Bad commands are not part of the input
  4. Comments begin with # and extend to the end of line Comments are everything not in +-.,[]<>
  5. no EOF symbol

A very good test can be found here. It reads a number and then prints the prime numbers up to that number. To prevent link rot, here is a copy of the code:

compute prime numbers
to use type the max number then push Alt 1 0
===================================================================
======================== OUTPUT STRING ============================
===================================================================
>++++++++[<++++++++>-]<++++++++++++++++.[-]
>++++++++++[<++++++++++>-]<++++++++++++++.[-]
>++++++++++[<++++++++++>-]<+++++.[-]
>++++++++++[<++++++++++>-]<+++++++++.[-]
>++++++++++[<++++++++++>-]<+.[-]
>++++++++++[<++++++++++>-]<+++++++++++++++.[-]
>+++++[<+++++>-]<+++++++.[-]
>++++++++++[<++++++++++>-]<+++++++++++++++++.[-]
>++++++++++[<++++++++++>-]<++++++++++++.[-]
>+++++[<+++++>-]<+++++++.[-]
>++++++++++[<++++++++++>-]<++++++++++++++++.[-]
>++++++++++[<++++++++++>-]<+++++++++++.[-]
>+++++++[<+++++++>-]<+++++++++.[-]
>+++++[<+++++>-]<+++++++.[-]

===================================================================
======================== INPUT NUMBER  ============================
===================================================================
+                          cont=1
[
 -                         cont=0
 >,
 ======SUB10======
 ----------

 [                         not 10
  <+>                      cont=1
  =====SUB38======
  ----------
  ----------
  ----------
  --------

  >
  =====MUL10=======
  [>+>+<<-]>>[<<+>>-]<     dup

  >>>+++++++++
  [
   <<<
   [>+>+<<-]>>[<<+>>-]<    dup
   [<<+>>-]
   >>-
  ]
  <<<[-]<
  ======RMOVE1======
  <
  [>+<-]
 ]
 <
]
>>[<<+>>-]<<

===================================================================
======================= PROCESS NUMBER  ===========================
===================================================================

==== ==== ==== ====
numd numu teid teiu
==== ==== ==== ====

>+<-
[
 >+
 ======DUP======
 [>+>+<<-]>>[<<+>>-]<

 >+<--

 >>>>>>>>+<<<<<<<<   isprime=1

 [
  >+

  <-

  =====DUP3=====
  <[>>>+>+<<<<-]>>>>[<<<<+>>>>-]<<<

  =====DUP2=====
  >[>>+>+<<<-]>>>[<<<+>>>-]<<< <


  >>>


  ====DIVIDES=======
  [>+>+<<-]>>[<<+>>-]<   DUP i=div

  <<
  [
    >>>>>+               bool=1
    <<<
    [>+>+<<-]>>[<<+>>-]< DUP
    [>>[-]<<-]           IF i THEN bool=0
    >>
    [                    IF i=0
      <<<<
      [>+>+<<-]>>[<<+>>-]< i=div
      >>>
      -                  bool=0
    ]
    <<<
    -                    DEC i
    <<
    -
  ]

  +>>[<<[-]>>-]<<          
  >[-]<                  CLR div
  =====END DIVIDES====


  [>>>>>>[-]<<<<<<-]     if divides then isprime=0


  <<

  >>[-]>[-]<<<
 ]

 >>>>>>>>
 [
  -
  <<<<<<<[-]<<

  [>>+>+<<<-]>>>[<<<+>>>-]<<<

  >>




  ===================================================================
  ======================== OUTPUT NUMBER  ===========================
  ===================================================================
  [>+<-]>

  [
   ======DUP======
   [>+>+<<-]>>[<<+>>-]<


   ======MOD10====
   >+++++++++<
   [
    >>>+<<              bool= 1
    [>+>[-]<<-]         bool= ten==0
    >[<+>-]             ten = tmp
    >[<<++++++++++>>-]  if ten=0 ten=10
    <<-                 dec ten     
    <-                  dec num
   ]
   +++++++++            num=9
   >[<->-]<             dec num by ten

   =======RROT======
      [>+<-]
   <  [>+<-]
   <  [>+<-]
   >>>[<<<+>>>-]
   <

   =======DIV10========
   >+++++++++<
   [
    >>>+<<                bool= 1
    [>+>[-]<<-]           bool= ten==0
    >[<+>-]               ten = tmp
    >[<<++++++++++>>>+<-] if ten=0 ten=10  inc div
    <<-                   dec ten     
    <-                    dec num
   ]
   >>>>[<<<<+>>>>-]<<<<   copy div to num
   >[-]<                  clear ten

   =======INC1=========
   <+>
  ]

  <
  [
   =======MOVER=========
   [>+<-]

   =======ADD48========
   +++++++[<+++++++>-]<->

   =======PUTC=======
   <.[-]>

   ======MOVEL2========
   >[<<+>>-]<

   <-
  ]

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

  ===================================================================
  =========================== END FOR ===============================
  ===================================================================


  >>>>>>>
 ]
 <<<<<<<<



 >[-]<
  [-]
 <<-
]

======LF========

++++++++++.[-]
@

Example run:

$ python2 bf.py 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\$
27
  • 10
    \$\begingroup\$ You should clarify about 1) size of memory 2) is memory circled 4) maybe any other details \$\endgroup\$
    – Nakilon
    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
  • 47
    \$\begingroup\$ I'd love to see someone answer this in brainfuck. \$\endgroup\$
    – Hannesh
    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

83 Answers 83

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\$
    – timfi
    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\$
    – timfi
    Commented Jun 25, 2020 at 10:05
  • \$\begingroup\$ 696 bytes \$\endgroup\$
    – ceilingcat
    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\$
    – Alexandru
    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\$
    – jtjacques
    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\$
    – DELETE_ME
    Commented Nov 26, 2017 at 2:05
  • \$\begingroup\$ Or the compiled function size? \$\endgroup\$
    – DELETE_ME
    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\$
    – Shipof123
    Commented Dec 16, 2020 at 15:51
  • \$\begingroup\$ Suggest 'u0' instead of 30000 \$\endgroup\$
    – ceilingcat
    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\$

sed 4.2.2 -rn, 992 580 554 540 bytes

s/[^][<>+.,-]//g;x                         #delete non-bf chars
s/.*/        /;s//&&&&&&/;s//&&&&&/
s//&&&&&/;s//&&&&&/;s//&&&&&/              #initilize 30000-char array
s/^/ !/;x;G;s//!/                          #format into '!code\n !a r r a y'
:                                          #label ''
/!\+/{s//+!/;s/ !/&a/;t}                   #if +, move forward, add one to array at pos, return to ''
/!-/{s//-!/;s/ !a?/ !/;t}                  #if -, move forward, (if array>0, subtract one from array at pos), return to ''
/!\./{s//.!/;h;s/.* !(a*).*/\1/p;x;t}      #if ., move forward, print value at array pos, return to ''
/!,/{s//,!/;N;s/ !a*(.*)\n(.*)/ !\2\1/;t}  #if ,, move forward, get input, replace value at array pos, return to ''
/!</{s//<!/;s/ (a* )?!/ !\1/;t}            #if <, move forward, move array pos one closer to the start, return to ''
/!>/{s//>!/;s/!(a* )/\1!/;t}               #if >, move forward, move array pos one closer to the end, return to ''
/!\[/{s//[!/;h;s/.* !(a*).*/\1/            #if [, move forward, load value at array pos
/^$/{x;:[;s/!([%-?])/\1!/;t[               #    if 0, load code, label [, (if non-][ char, move forward, return to [,)
/!]/{s//]!/;T;x;s/a//;x;T;T[}              #        if [, move forward, i++, return to [
s/!./[!/;x;s/|/a/;x;t[}                    #        else, move forward, (if i--, return to [,) return to ''
x;t}                                       #    else, load code, return to ''
/!]/{h;s/.* !(a*).*/\1/                    #if ], load value at array pos
/^$/!{z;x;:];s/([%-?])!/!\1/;t]            #    if not 0, i=0, load code, label ], (if non-][ char, move backward, return to ],)
/]!/{s//!]/;x;s/|/a/;x;t]}                 #        if ], move backward, i++, return to ]
s/.!/![/;T;x;s/a//;x;T;T]}                 #       else, move backward, (if i--, return to ],) return to ''
x;s/!]/]!/;t}                              #    else, load code, move forward, return to ''

Try it online! (can print primes up to 8) or, here's without the Primes up to: text and with an array size of 48 which can print primes up to 20 and still exit properly: try it online!

input and output are strings of unary as. no evals in this version! to run it yourself on bash, put the whole thing in quotes like sed -rn '${code}' or save as a file and run like sed -rnf code.sed (no piping allowed; running sed without any input lets you have interactive I/O). the first line of input is the bf code, and it will consume as many lines after that as it needs to for ,s in the code. once the program finishes, you can put in another bf program or ^D to exit. if your bf program has newlines in it, add a -z to the sed call and a ^@ to the end of your code; but that also means that each input has to end with a ^@ instead of ^J as well. if you have a sed newer than 4.2.2, add a p after the : sitting on its own line and after all the t/Ts followed by a semicolon, newline, or closing curly brace.

to this interpreter, 0-1=0 and 255+1=256. there is no theoretical upper bound to what can be stored in a cell but the computer you run this sed script on likely has less than infinite memory so it'll crash eventually.

changes from v2 to v3:

  • 450+ bytes off!
  • no more numeric pointer, uses a ! to track where it currently is in the array
  • much faster; the Primes up to: 'text' can be printed without shortening the array in ~10 seconds on TIO compared to previously taking a minute to print just Pr even after shortening the array to 8.
  • no more evals
  • a bit of future proofing for v4 which may take io as characters instead of unary (that'll bring a couple new e flags in though)
  • instead of !code\npointer\narray it's now just !code\n !a r r a y where ! is a 'current position' marker.
  • using //{} conditional notation for the easy functions instead of :a;ta jumps, which means fewer labels but more slashes.
version with chars as i/o instead of unary:

sed 4.2.2 -r, 844 789 bytes

s/[^][<>+.,-]//g;x
s/.*/        /;s//&&&&&&/#;s//&&&&&/;s//&&&&&/;s//&&&&&/;s//&&&&&/
s/^/ !/;x;G;s/^/\n!/
:
/!\+/{s//+!/;s/ !/&a/;t}
/!-/{s//-!/;s/ !a?/ !/;t}
/!\./{s//.!/;h;s/.* !(a*).*/\1/;s/.*/sed ':;s%^7*a%0\&%;s%.7*a%_\&%;h;y%01234567%12345670%;x;G;s%_.*_%%;s%a%%;t;s%\\n.*%%;s%.*%sed "s}.*}\\\\o\&}"<<<""%e'<<<&/e;x;G;t}
/!,/{s//,!/;h;N;s%.*\n(.*)%dc -e"8i2o`od -bAn<<<'\1'`rp"|sed ':;s/1/1a/g;y/1/0/;s/a0/1a/;t;s/0//g'%e;G;s/(a*)\n(.* !)a*/\2\1/;t}
/!</{s//<!/;s/ (a* )?!/ !\1/;t}
/!>/{s//>!/;s/!(a* )/\1!/;t}
/!\[/{s//[!/;h;s/.* !(a*).*/\1/
/^$/{x;:[;s/!([%-?])/\1!/;t[
/!]/{s//]!/;T;x;s/a//;x;T;T[}
s/!./[!/;x;s/|/a/;x;t[}
x;t}
/!]/{h;s/.* !(a*).*/\1/
/^$/!{z;x;:];s/([%-?])!/!\1/;t]
/]!/{s//!]/;x;s/|/a/;x;t]}
s/.!/![/;T;x;s/a//;x;T;T]}
x;s/!]/]!/;t}
s/.* ![a ]*\n//
s/(.)./\1/g

Try it online!

it doesn't really change anything except for there's an eval in front of input and output that convert to chars, and output goes to a buffer that gets collected together and printed at the end of the program instead of as it goes along.

\$\endgroup\$
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\$
    – theB
    Commented Aug 31, 2015 at 21:18
  • \$\begingroup\$ Not only do people still read them, they still answer and golf them. \$\endgroup\$
    – mbomb007
    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
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\$
    – ceilingcat
    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\$
    – Stephen
    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\$

C (gcc), (Try it online!) 194 187 176 175 bytes (thanks to @ceilingcat)

char t['u0'],*p=t;c;l;f(char*b){for(;c=*b;b++)if(c-=43,read(write(l=1,p+=c==19,c==3),p-=c==17,!~c),*p+=!c-(c==2),c-=48,!c|c==2)for(;l&&!*p^c/2;l-=*b==93-c)l+=0[b-=c-1]==91+c;}

C (gcc), (Try it online!) 231 bytes

char t['u0'],*p=t;c;l;f(char*b){for (;c=*b;b++) {l=1;c-43||++*p;c-45||--*p;c-60||p--;c-62||p++;c-46||putchar(*p);c-44||(*p=getchar());for(;l&&!*p&&c==91;){++b;*b-91||l++;*b-93||l--;}for(;l&&*p&&c==93;){--b;*b-93||l++;*b-91||l--;}}}
\$\endgroup\$
1
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\$
    – ceilingcat
    Commented Nov 18, 2023 at 19:11
3
\$\begingroup\$

C (gcc) Linux AArch64, 483 461 449 439 424 413 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&33554431|22<<24,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\$
3
\$\begingroup\$

Acc!!, 678 652 bytes

-26 bytes thanks to @Mukundan314

Count i while _/256^(8+i)-33 {
_+N*256^(9+i)+2^32
}
Count i while (_-_/2^32)%2^16 {
_-(_/2^48%256-_/256^(9+_%2^16)%256)*2^48-(_/2^64%256-_/256^(9+(_/2^16+_/2^32)%2^16)%256)*2^64
Count j while 0^(_/2^48%256-91-j)^2*0^(_/2^64%256)^2+_/2^64%256*0^(_/2^48%256-93-j)^2+_/2^56%256 {
_+(92-_/2^48%256)*0^0^j
_+2^56*(0^(_/256^(9+_%2^16)%256-91)^2-0^(_/256^(9+_%2^16)%256-93)^2)*(92-_/2^48%256)
}
Count j while 0^(_/2^48%256-44)^2-j {
_-(_/2^64%256-N)*256^(9+(_/2^16+_/2^32)%2^16)
}
Count j while 0^(_/2^48%256-46)^2-j {
Write _/2^64%256
}
_+256^(9+(_/2^16+_/2^32)%2^16)*(0^(_/2^48%256-43)^2-0^(_/2^48%256-45)^2)+2^16*(0^(_/2^48%256-62)^2-0^(_/2^48%256-60)^2)+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%2^16)%256)
# code[r]       (_/256^(9+_%2^16)%256)
# memory[p]     (_/256^(9+(_/2^16+_/2^32)%2^16)%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)%2^16 {
    # 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+_%2^16)%256) * 2^48
      - (_/2^64%256 - _/256^(9+(_/2^16+_/2^32)%2^16)%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 * 0^(_/2^64%256)^2 # (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 / ]
        _ + 2^56
            * (0^(_/256^(9+_%2^16)%256-91)^2 - 0^(_/256^(9+_%2^16)%256-93)^2)
            * (92-_/2^48%256)
    }
    
    # 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+(_/2^16+_/2^32)%2^16)
    }

    # Handle . instruction - code[r] == 46
    Count j while 0^(_/2^48%256-46)^2-j {
        Write _/2^64%256 # Print memory[p]
    }

    # 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++
    _ + 256^(9+(_/2^16+_/2^32)%2^16)
        * (0^(_/2^48%256-43)^2 - 0^(_/2^48%256-45)^2)
      + 2^16
        * (0^(_/2^48%256-62)^2 - 0^(_/2^48%256-60)^2)
      + 1

# } for this count block can be omitted as i is never used (interpreter bug)
\$\endgroup\$
2
2
\$\begingroup\$

golfscript, partial solution only, 150 chars

:i;[0]30000*[]0 "#{File.open('f').read}"{{\(@=\''if}+['>+\\(@\\' '<@+\\)' '+1+256%' '-1- 256%' ".[0$]''+print " ',;i(\:i;' '[{.}{' ']}while']\%}%~;;;;

i am greatly indebted to the pattern of generating your own source and then eating it, as others have already posted.

misfeatures:

  • only parses brainfuck code from the file 'f'.
  • all input you want to read with ',' must be piped in at the beginning.
  • runs hello world, yet dies somewhere during prime.bf. i'm not sure why. i did read somewhere that golfscript is broken for nested while loops, so that might be it.
  • stores a char=>string map in a way that is entertainingly horrible, at least to me.

I've tried loading arbitrary files with constructions like "#{File.open(" "some_file.bf" ").read}" + + but Ruby seems to helpfully escape the "#" for me so i dont accidentally load the file im trying to load. On the other hand, embedding "#{getc}" works okay for reading from stdin, but there's still the restriction that input is non-interactive - only stuff piped in at the start is read. Anyone know a way around one or more of these input issues?

\$\endgroup\$
1
  • \$\begingroup\$ The way round the first problem is to build a string consisting of a string literal and then ~ it. See my blog post on using this for debugging. \$\endgroup\$ Commented Sep 10, 2012 at 12:34
2
\$\begingroup\$

From sepp2k solution - 148

eval"a=[i=0]*3e4;"+$<.bytes.map{|b|{?.,"putc a[i]",?,,"a[i]=getc",?[,"while a[i]>0",?],"end",?<,"i-=1",?>,"i+=1",?+,"a[i]+=1",?-,"a[i]-=1"}[b]}*";"

eval"a=[i=0]*3e4;"+$<.bytes.map{ can be replaced with a=[i=0]*3e4;eval$<.bytes.map{ -3 bytes

*";" => *$/ -1 bytes

"while a[i]>0" and"end" => "(" and ")while(a[i]>0)" -1 bytes

And we get 143 (5 bytes less)

a=[i=0]*3e4;eval$<.bytes.map{|b|{?.,"putc a[i]",?,,"a[i]=getc",?[,"(",?],")while a[i]>0",?<,"i-=1",?>,"i+=1",?+,"a[i]+=1",?-,"a[i]-=1"}[b]}*$/

And what if there aren't any comments in input (only +-<>[],.) http://codepad.org/EihHsoJO

we can write like this:

a=[i=0]*3e4;eval$<.bytes.map{|b|%w{putc(a[i]) a[i]=getc ( )while(a[i]>0) i-=1 i+=1 a[i]+=1 a[i]-=1}[".,[]<>+-\n".index b]}*$/

And this is 126 bytes, if there wouldn't be "\n" at the end, we can skip it in this part ".,[]<>+-\n" => ".,[]<>+-" saving 2 bytes

And this can be shorten to:

a=[i=0]*3e4;eval$<.bytes.map{|b|%w{i-=1 ( i+=1 )while(0<a[i]) a[i]+=1 a[i]=getc a[i]-=1 putc(a[i])}[b%30%9]}*$/

which is 112 bytes

where b%30%9 is a mapping from ascii code to array index

How to find this formula?

Very easy:

c="<[>]+,-."
(1..99).each do |i|
    (1..99).each do |j|
        r = c.each_byte.map {|a| a%i%j}.select {|x| x < c.size}.uniq
        puts "#{r} #{i} #{j} " if r.size==c.size
    end
end

>>> 
[0, 1, 2, 3, 4, 5, 6, 7] 30 9  
[4, 5, 6, 7, 0, 1, 2, 3] 43 13  
[4, 3, 6, 5, 7, 0, 1, 2] 44 12  
[0, 7, 2, 1, 3, 4, 5, 6] 52 8  
[0, 7, 2, 1, 3, 4, 5, 6] 60 8

So if only we can assume, that there would be only <>+-[],. whe can shorten the solution to 112 bytes

\$\endgroup\$
2
\$\begingroup\$

VB.net, 730 bytes

If P.Aggregate(Of Int32)(0,Function(s,i)If(s<0,s,If(i="["c,s+1,If(i="]"c,s-1,s))))=0 Then Dim C=0,O=0,M(30000)As Int32:Dim J As Func(Of Int32,Int32,Int32,Char,Char,Int32)=Function(x,n,l,g,t)If(P(x)=g,J(x+n,n,l+1,g,t),If(P(x)=t,If(l=1,x,J(x+n,n,l-1,g,t)),J(x+n,n,l,g,t))):Dim Q As New Dictionary(Of Char,Action)From{{"+"c,Sub()M(O)=If(M(O)=255,255,M(O)+ 1)},{"-"c,Sub()M(O)=If(M(O)=0,0,M(O)-1)},{"<"c,Sub()O=If(O=0,M.Length,O-1)},{">"c,Sub()O=If(O=M.Length-1,0,O+1)},{"["c,Sub()C=If(M(O)=0,J(C,+1,0,"["c,"]"c),C)},{"]"c,Sub()C=If(M(O)=0,C,J(C,-1,0,"]"c,"["c))},{","c,Sub()M(O)=Console.Read()},{"."c,Sub()Console.Write(Convert.ToChar(M(O)))}}:For C=0To P.Length-1:Dim a=If(Q.ContainsKey(P(C)),Sub()Q(P(C))(),Sub()Exit Sub):a():Next
\$\endgroup\$
1
  • \$\begingroup\$ The C# version has the potential to be smaller I think. \$\endgroup\$ Commented Dec 11, 2013 at 3:31
2
\$\begingroup\$

PynTree, 123 bytes

Æp+"Dw[0]Dy0"Ƭ+"æ#wy%+1#wy256"-"æ#wy%_#wy1 256"."ƤȮ#wy","æ#wy%OĊ256">";ß+y1æSwy"<"¿yß_y1æIw0 0"["¡#wy¤"]'}}JfxSėx"+-.,[]<>"

Try it online!

Transpiles Brainfuck to PynTree and then calls pyntree_eval on it. PynTree transpiles directly to Python.

\$\endgroup\$
2
\$\begingroup\$

Powershell, 175 195 183 175 173 bytes, Transpiler

,'$p=0
$c=@{}'+(gc $args|% t*y|%{(-split'$p++
$p--
$c.$p++
$c.$p--
$c.$p=[console]::Read()
write-host([char]$c.$p)-n
for(;$c.$p){
}
#')[('><+-,.[]'|% i*f $_)]
})-join'
'|iex

Explanation:

The script is transpiler from a brainfuck source code to a powershell source code. Finally, the script evaulates the result powershell code by command iex.

  • init commands $p=0 and $c=@{}
  • gc $args|% t*y|%{ - for each character from file
  • ('><+-,.[]'|% i*f $_)+1 - treats a current char as index in the array of code snippets. If character match no code snippet, the script uses the comment char #.
  • and iex evaulates the result powershell code

Compared to Joey's answer, this script fixes a bug "Index operation failed; the array index evaluated to null" ($p=0 in the init block)

Known issues:

  • [console]::Read() eats first char in VSCode. This expression work correct in a powershell window.

Less golfed test script:

$f = {

'$p=0',
'$c=@{}'+
(gc $args|% t*y|%{
    $bfcmd_Idx='><+-,.[]'.IndexOf($_)     # IndexOf returns -1 if char $_ does not found.
    @(  '$p++',
        '$p--',
        '$c.$p++',
        '$c.$p--',
        '$c.$p=[console]::Read()',
        'write-host([char]$c.$p)-n',
        'for(;$c.$p){',
        '}',
        '#'
    )[$bfcmd_Idx]      # push to pipe an element. -1 means last element
})-join"`n"|Invoke-Expression

}

&$f interpret-brainf-hello.bf
&$f interpret-brainf-prime.bf

Output:

Hello World!
Primes up to: 100
2 3 5 7 11 13 17 19 23 29 31 37 41 43 47 53 59 61 67 71 73 79 83 89 97

File interpret-brainf-prime.bf contains a test script from the question.

File interpret-brainf-hello.bf (from wiki):

[ This program prints "Hello World!" and a newline to the screen, its
  length is 106 active command characters. [It is not the shortest.]

  This loop is an "initial comment loop", a simple way of adding a comment
  to a BF program such that you don't have to worry about any command
  characters. Any ".", ",", "+", "-", "<" and ">" characters are simply
  ignored, the "[" and "]" characters just have to be balanced. This
  loop and the commands it contains are ignored because the current cell
  defaults to a value of 0; the 0 value causes this loop to be skipped.
]

++++++++               Set Cell #0 to 8
[
    >++++               Add 4 to Cell #1; this will always set Cell #1 to 4
    [                   as the cell will be cleared by the loop
        >++             Add 2 to Cell #2
        >+++            Add 3 to Cell #3
        >+++            Add 3 to Cell #4
        >+              Add 1 to Cell #5
        <<<<-           Decrement the loop counter in Cell #1
    ]                   Loop till Cell #1 is zero; number of iterations is 4
    >+                  Add 1 to Cell #2
    >+                  Add 1 to Cell #3
    >-                  Subtract 1 from Cell #4
    >>+                 Add 1 to Cell #6
    [<]                 Move back to the first zero cell you find; this will
                        be Cell #1 which was cleared by the previous loop
    <-                  Decrement the loop Counter in Cell #0
]                       Loop till Cell #0 is zero; number of iterations is 8

The result of this is:
Cell No :   0   1   2   3   4   5   6
Contents:   0   0  72 104  88  32   8
Pointer :   ^

>>.                     Cell #2 has value 72 which is 'H'
>---.                   Subtract 3 from Cell #3 to get 101 which is 'e'
+++++++..+++.           Likewise for 'llo' from Cell #3
>>.                     Cell #5 is 32 for the space
<-.                     Subtract 1 from Cell #4 for 87 to give a 'W'
<.                      Cell #3 was set to 'o' from the end of 'Hello'
+++.------.--------.    Cell #3 for 'rl' and 'd'
>>+.                    Add 1 to Cell #5 gives us an exclamation point
>++.                    And finally a newline from Cell #6

Powershell, 257 bytes, Interpreter

$c=@{}
$p=$i=0
$m={for(;($b+=($s[$i]-92)|?{$_-in-1,1})){$i+=$args[0]}}
for($s=gc $args -ra;$i-lt$s.Length){switch($s[$i]-40){22{$p++}20{$p--}3{$c.$p++}5{$c.$p--}4{$c.$p=[console]::Read()}6{write-host([char]$c.$p)-n}51{if(!$c.$p){.$m 1}}53{.$m -1;$i--}}$i++}

Less golfed test script:

$f = {

$c=@{}                                      # $c - hashtable
$p=$i=0                                     # $p - ptr (a key in the hashtable), $i - IC (Instruction Counter)
$m={
    for(;($b+=($s[$i]-92)|?{$_-in-1,1})){   # $b - balance of the brackets
        $i+=$args[0]                        # move IC forward or backward
    }                                       # while balance of the brackets is not 0
}
for($s=gc $args -ra;$i-lt$s.Length){        # -ra is shortcut for -raw parameter = get-content as char array
    switch($s[$i]-40){                      # '-40' needs to convert into [int] and to reduce cases 43 44 45 46 into 3 4 5 6 (-2 bytes)
        22{$p++}
        20{$p--}
        3{$c.$p++}
        5{$c.$p--}
        4{$c.$p=[console]::Read()}          # it eats a first char in a VSCode, it works correct in a Powershell terminal
        6{write-host([char]$c.$p)-n}
        51{if(!$c.$p){.$m 1}}               # dot source the script block m
        53{.$m -1;$i--}                     # dot sourcing does not create a new scope https://docs.microsoft.com/en-us/powershell/module/microsoft.powershell.core/about/about_scripts
    }
    $i++
}

}

&$f interpret-brainf-hello.bf
&$f interpret-brainf-prime.bf

Output:

Hello World!
Primes up to: 20
2 3 5 7 11 13 17 19
\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.