Brian & Chuck

From Esolang
Jump to: navigation, search

Brian & Chuck is an esoteric programming language with two mutually modifying Brainfuck-like programs developed by user:Martin Ender. The language was remotely inspired by RubE on Conveyor Belts and Self-modifying Brainfuck.

The design goals were to make the language Turing-complete while each of its parts individually are not Turing-complete. Furthermore, even both of them together should not be Turing-complete without generating code at runtime. I (the author) think I've succeeded with that, but I haven't proven any of those things formally yet.

Overview

Brian and Chuck are two brainfuck-like programs. Only one of them is being executed at any given time, starting with Brian. The catch is that Brian's memory tape is also Chuck's source code. And Chuck's memory tape is also Brian's source code. Furthermore, Brian's tape head is also Chuck's instruction pointer and vice versa. The tapes are semi-infinite (i.e. infinite to the right) and can hold signed arbitrary-precision integers, initialised to zero (unless specified otherwise by the source code).

Since the source code is also a memory tape, commands are technically defined by integer values, but they correspond to reasonable characters. The following commands exist:

  • , (44): Read a character from STDIN into the current memory cell. Only Brian can do this. This command is a no-op for Chuck.
  • . (46): Write the current memory cell, modulo 256, as a character to STDOUT. Only Chuck can do this. This command is a no-op for Brian.
  • + (43): Increment the current memory cell.
  • - (45): Decrement the current memory cell.
  • ? (63): If the current memory cell is zero, this is a no-op. Otherwise, hand control over to the other program. The tape head on the program which uses ? will remain on the ?. The other program's tape head will move one cell to the right before executing the first command (so the cell which is used as the test is not executed itself).
  • < (60): Move the tape head one cell to the left. This is a no-op if the tape head is already at the left end of the tape.
  • > (62): Move the tape head one cell to the right.
  • { (123): Repeatedly move the tape head to the left until either the current cell is zero or the left end of the tape is reached.
  • } (125): Repeatedly move the tape head to the right until the current cell is zero.

The overall program terminates when the active program's instruction pointer reaches a point where there are no more instructions to its right.

Source Code

The source file is processed as follows:

  • If the file contains the string ```, the file will be split into two parts around the first occurrence of that string. All leading and trailing whitespace is stripped and the first part is used as the source code for Brian and the second part for Chuck.
  • If the file does not contain this string, the first line of the file will be used as the source for Brian and the second part for Chuck (apart from the delimiting newline, no whitespace will be removed).
  • All occurrences of _ in both programs are replaced with NULL bytes. This allows you to insert zero cells more easily into the source.
  • The two memory tapes are initialised with the character codes corresponding to the resulting string.

As an example, the following source file

  abc
```
0_1
23

Would yield the following initial tapes:

Brian: [97 98 99 0 0 0 0 ...]
Chuck: [48 0 49 10 50 51 0 0 0 0 ...]

Examples

This prints Hello, World!:

?Hello, World!
!>.>.>.>.>.>.>.>.>.>.>.>.>.

This is a cat program:

?_{<{<{}<,+?>>}>}>}<?_{<-?+>>}<?__{<?
!}>}>}+{<{<{?_{<{<}>}>}<+{<?_}<--.>_{<-?+{<{<?

External Resources

  • GitHub repository including language spec, reference implementation in Ruby (with some additional debug features, see README.md) and example programs.
  • Online interpreter at Try It Online.