We are currently working on new rules for what content should and shouldn't be allowed on this website, and are looking for feedback! See Esolang:2026 topicality proposal to view and give feedback on the current draft.

Talk:Immutable Brainfuck

From Esolang
Jump to navigation Jump to search

Input EOF

What should , do in case of EOF? --Blashyrkh (talk) 09:30, 25 August 2026 (UTC)

Thanks for pointing that out. The tape should remain unchanged. I added it to the spec. --Rainwave (talk) 09:41, 25 August 2026 (UTC)
Actually, nevermind. That'd break reversibility. I changed it to EOF = 0 instead. --Rainwave (talk) 09:44, 25 August 2026 (UTC)
If reversibility is mandatory, you may insert 9 bits ('0', ascii-code) or single '1' bit in case of EOF.--Blashyrkh (talk) 09:51, 25 August 2026 (UTC)
Possible, but I personally think EOF = 0 is cleaner for the language spec. It's also the way Reversible Brainfuck handles EOF. --Rainwave (talk) 10:00, 25 August 2026 (UTC)

Shorter "Hello, world!"

It prints "Hello, world!" string with newline (U+000A) at the end:

0010100011000010100100111001101110100111111110111111011110000010100110101111101110011011100110111101001110001001[0>.>>>>>>>>]

Thinking about quine... --Blashyrkh (talk) 22:40, 26 August 2026 (UTC)

"Tape"?

Should it be called "tape" due to insertion principle? It's rather far from how real (physical) tape works. Probably, it's two stacks: left stack and right stack. < pops value from the left stack and pushes to the right stack. > does the opposite. 0 and 1 pushes the corresponding value to the right stack. [ and ] examine the top value of the left stack. . combines 8-bit value from the top of the left stack and 7 top values from the right stack, and outputs it. , pushes 8 bits to the right stack. --Blashyrkh (talk) 08:13, 27 August 2026 (UTC)

And looking from this perspective, one can notice how weird and asymmetric . operation is. --Blashyrkh (talk) 08:59, 27 August 2026 (UTC)
Usually, tape (self-extending)=queue=two stacks. --None1 (Nope.) 11:58, 27 August 2026 (UTC)
I understand that, it became clear to me when I'd been writing brainfuck interpreter in Lazy K. But for tape (usually) a distance between any two cells is constant (push to one stack is always accompanied by pop from another one), and here it's not. --Blashyrkh (talk) 12:06, 27 August 2026 (UTC)
Shouldn't it be linked-list? I originally intended it to be some sort of growing array, so I used the standard BF terminology which is tape. --Rainwave (talk) 12:12, 27 August 2026 (UTC)
Originally, the word "tape" comes from Turing Machine. Urban Muller didn't use the word, he called it "array" (https://gist.github.com/rdebath/0ca09ec0fdcf3f82478f, not sure whether it's the original code and not fake). So, it may be called neutrally "memory" or less-neutrally "linked list". --Blashyrkh (talk) 12:19, 27 August 2026 (UTC)
Of course, it's only an opinion. You're the author, you choose terms. --Blashyrkh (talk) 12:25, 27 August 2026 (UTC)

Shorter Truth-machine

,>.>>>>>>>[1]>[<<<<<<<<.>>>>>>>1>]

--Blashyrkh (talk) 20:37, 27 August 2026 (UTC)

Behavior of the . command

Read eight contiguous cells starting from the current cell, interpret them as a byte, and output them as a single ASCII character. Note that the pointer's position remains unchanged.

What if there are less than 8 cells starting from the current cell?

  • They are considered as 0.
  • Errors.
  • UB
  • Or...?

--None1 (Nope.) 08:09, 28 August 2026 (UTC)

the language operates on a right-unbounded tape, where the initial cells are all 0.

--Blashyrkh (talk) 08:18, 28 August 2026 (UTC)

Interpreter

#! /usr/bin/env python3

import sys


if __name__=="__main__":
    tape = [0]
    pos = 0

    prog = open(sys.argv[1], "rt").read()
    ip = 0

    while ip<len(prog):
        match prog[ip]:
            case ">":
                pos += 1
                if pos>=len(tape):
                    tape.append(0)
            case "<":
                pos -= 1
                if pos<0:
                    tape.insert(0, 0)
                    pos += 1
            case "[":
                if tape[pos]==1:
                    d = 1
                    new_ip = ip+1
                    while d>0 and new_ip<len(prog):
                        if prog[new_ip]=="[":
                            d += 1
                        elif prog[new_ip]=="]":
                            d -= 1
                        new_ip += 1
                    if d>0:
                        sys.exit("Unmatched [")
                    ip = new_ip-1
            case "]":
                if tape[pos]==1:
                    d = 1
                    new_ip = ip-1
                    while d>0 and new_ip>=0:
                        if prog[new_ip]=="]":
                            d += 1
                        elif prog[new_ip]=="[":
                            d -= 1
                        new_ip -= 1
                    if d>0:
                        sys.exit("Unmatched ]")
                    ip = new_ip+1
            case "1":
                tape.insert(pos+1, 1)
            case "0":
                tape.insert(pos+1, 0)
            case ".":
                value = 0
                for i in range(8):
                    if pos+i>=len(tape):
                        break
                    value |= (tape[pos+i]<<(7-i))
                sys.stdout.buffer.write(bytes((value,)))
            case ",":
                inp = sys.stdin.buffer.read(1)
                value = inp[0] if inp else 0
                for _ in range(8):
                    tape.insert(pos+1, value&1)
                    value >>= 1
#            case "#":
#                print()
#                print(" ".join("{0}{1}{2}".format("[" if i==pos else " ", tape[i], "]" if i==pos else " ") for i in range(len(tape))))
            case _:
                pass
        ip += 1

The only difference with the specification (or clarification of UB if you like) is that my tape is unbounded in both directions. --Blashyrkh (talk) 08:23, 28 August 2026 (UTC)

I wrote one in C++, too. --None1 (Nope.) 09:25, 28 August 2026 (UTC)
Using ordinary std::list would be faster (O(1) vs O(logn)), but would introduce huge memory overhead (single std::list element with two 64-bit pointers, 1 byte payload and padding to hold 1 bit). --Blashyrkh (talk) 10:17, 28 August 2026 (UTC)
Oh, I forgot that this esolang doesn't require random access memory. --None1 (Nope.) 10:20, 28 August 2026 (UTC)
I'll add a version with std::list for the sake of portability. --None1 (Nope.) 10:40, 28 August 2026 (UTC)
Done. --None1 (Nope.) 11:04, 28 August 2026 (UTC)