Byte-based Instruction Jumping

From Esolang
Jump to navigation Jump to search

Byte-based Instruction Jumping (BIJ, pronounced Bee-Jay) is a self-modifying esoteric programming language created by me (User:Peter). It was created during the end of 2021 and the beginning of 2022, and is inspired by 2 Bits, 1 Byte. Pretty much any string of text is a valid BIJ program, as long as it doesn't include some really unusual letters.

Language Overview

BIJ programs consist of an array of bytes. A pointer (called the program pointer) moves around in this array and performs different instructions depending on which bits in the byte it's pointing to are toggled and which aren't. These instructions includes things like moving the pointer around, storing a byte in the accumulator (an 8-bit register that the program pointer "remembers") and printing things onto the console.

The array of bytes is no longer than the length of the program that is written. If the program pointer moves to an index lower than 0 in the array, the program returns 0. If it moves to an index higher than the length of the array, the program returns 1.

The program pointer executes one byte at a time, and doesn't stop executing a byte before it has went through all the bits in it. This means that if the program pointer is told to move away from the byte it's executing, it will keep executing the byte anyways. When it's done, it'll start executing the byte it ended up pointing to after executing the last byte. The bytes can be represented in 3 different ways:

1. Characters: BIJ uses a special ascii table where values like NULL and DEL are replaced with actual writeable characters.

ø%{

2. Hexadecimal numbers: Uses 2-digit lowercase hexadecimal numbers separated by spaces.

07 25 7b

3. Lists of instructions: Each line is a list of 8 instructions. Which instructions you write depends on which bits are toggled.

mvr ... ... red ... spc neq mvl
mvr ... jml red ... spc ... mvl
mvr jmr jml wrt cns ... neq mvl

Instructions

Here's a list of instructions. The first element of the list (mvr/mvl) is the left-most bit in the byte that is currently being executed. The second element is the second bit from the left, the third element the third bit, et cetera. The instruction before the slash is the instruction you write if the bit is not toggled, and the instruction after the slash is what you write if the bit is toggled.

The commands are executed in chronological order.

Index of bit Name of Instruction Meaning of name Description
1 mvr/mvl MoVe Right / MoVe Left If toggled, the program pointer moves 1 byte to the left. If not toggled, the program pointer moves 1 byte to the right.
2 .../jmr nothing / JuMp Right If toggled, the program pointer will move to the next byte in the program array that is equal to the current byte. If the program pointer is pointing to, for example, an 'A', it will move to the next byte that stores the character 'A'. If it doesn't find a byte equal to the current one by moving to the right, the program exits with code 1. If not toggled, nothing happens.
3 .../jml nothing / JuMp Left Just like the second instruction (jmr) except the program pointer moves to the previous byte equal to the current one and returns 0 if it can't find one.
4 red/wrt REaD / WRiTe If not toggled, the program pointer will store the byte it's pointing to in the accumulator (a special byte that the program pointer remembers without needing to point to it). If toggled, the program pointer copies the accumulator to the current byte. The accumulator is initialized to 0 at the beginning, so wrt will set the current byte to 0 if red hasn't been used yet.
5 .../cns nothing / CoNSole If toggled, the program pointer will read or write (see instruction 4) to the console instead for the accumulator. If used after wrt, the program pointer will print out the byte it's pointing to. If used after red, it will copy the user input to the byte it's pointing to. If this command is not toggled, the program pointer will read or write the way it's described for bit #4.
6 .../spc nothing / SPeCial If this command is toggled, red/wrt and .../cns will do completely different things than they usually would. If toggled after red ..., red won't be executed, and the last mvr/mvl won't be executed either. If toggled after wrt ..., it will copy the value of ~(accumulator & the byte that's being pointed to) to the byte that is being pointed to. red cns spc will simply do nothing, and the other commands will be executed normally. If spc is toggled after wrt cns, the program pointer will bitshift the byte that is being pointed to once to the left or right, depending on the last move command (mvr makes the byte bitshift to the right, and mvl to the left).
7 .../neq nothing / Not EQual If this command is toggled and the accumulator is not equal to the byte that is being pointed to, the last move command will execute once more than usually.
8 mvr/mvl MoVe Right / MoVe Left Same as instruction #1

Example instruction

An example of an instruction would be

mvr ... ... wrt cns ... ... mvr

This command can also be represented by the character ↑ or the hexadecimal number 18.

Here's what the program pointer does when encountering this byte, step by step:

  1. mvr (bit is not not toggled): It moves one step to the right
  2. ... (bit is not toggled): It does nothing
  3. ... (bit is not toggled): It does nothing
  4. wrt (bit is toggled): It writes ...
  5. cns (bit is toggled): ... the current character to the console (prints it, in other words)
  6. ... (bit is not toggled): It does nothing
  7. ... (bit is not toggled): It does nothing
  8. mvr (bit is not toggled): It moves one step to the right

Ascii Table

Knowing the ascii values of characters is never useful when writing programs due to the fact that you can use hexadecimal numbers or instructions instead. I will still leave a compact version of the ascii table here, just in case anyone would want to know what characters are and aren't used in BIJ.

 ‘☺☻♥♦♣♠øØ	
 ♂♀∞♫☼►◄↕‼¶§▬↨↑↓→←∟↔▲▼ !"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~⌂ÇüéâäàåçêëèïîìÄÅÉæÆôöòûùÿÖÜ¢£¥₧ƒáíóúñѪº¿⌐¬½¼¡«»░▒▓│┤╡╢╖╕╣║╗╝╜╛┐└┴┬├─┼╞╟╚╔╩╦╠═╬╧╨╤╥╙╘╒╓╫╪┘┌█▄▌▐▀αßΓπΣσµτΦΘΩδ∞φε∩≡±≥≤⌠⌡÷≈°∙—√ⁿ²■’

Example programs

Hello World!

Here's the classic "Hello World!" program in BIJ, represented by characters:

↑H↑e↑l↑l↑o↑ ↑W↑o↑r↑l↑d↑!

Here's the same program, represented by hexadecimal numbers:

18 48 18 65 18 6c 18 6c 18 6f 18 20 18 57 18 6f 18 72 18 6c 18 64 18 21

And here it is again, represented by lists of instructions:

mvr ... ... wrt cns ... ... mvr
mvr jmr ... red cns ... ... mvr
mvr ... ... wrt cns ... ... mvr
mvr jmr jml red ... spc ... mvl
mvr ... ... wrt cns ... ... mvr
mvr jmr jml red cns spc ... mvr
mvr ... ... wrt cns ... ... mvr
mvr jmr jml red cns spc ... mvr
mvr ... ... wrt cns ... ... mvr
mvr jmr jml red cns spc neq mvl
mvr ... ... wrt cns ... ... mvr
mvr ... jml red ... ... ... mvr
mvr ... ... wrt cns ... ... mvr
mvr jmr ... wrt ... spc neq mvl
mvr ... ... wrt cns ... ... mvr
mvr jmr jml red cns spc neq mvl
mvr ... ... wrt cns ... ... mvr
mvr jmr jml wrt ... ... neq mvr
mvr ... ... wrt cns ... ... mvr
mvr jmr jml red cns spc ... mvr
mvr ... ... wrt cns ... ... mvr
mvr jmr jml red ... spc ... mvr
mvr ... ... wrt cns ... ... mvr
mvr ... jml red ... ... ... mvl

Here's how it works:

  1. Move the program pointer to the right (mvr)
  2. Print the character (wrt cns)
  3. Move the program pointer to the right again (mvr)
  4. Now the program pointer has either moved out of program bounds (in which case it exits), or it's pointing to the same instruction again, in which case it goes back to step 1 and prints a new character.

Cat

This is an infinite loop that constantly prints out whatever the user inputs.

Characters:

Ø‘Ö

Hexadecimal:

08 00 99

Instructions:

mvr ... ... red cns ... ... mvr
mvr ... ... red ... ... ... mvr
mvl ... ... wrt cns ... ... mvl

Here's what each byte does:

1. Ø:

  1. Move the program pointer one step to the right (mvr)
  2. Copy one character from user input to the byte the program pointer is pointing to (red cns)
  3. Move the program pointer one step to the right again (mvr)

2. :

  • This byte is simply a placeholder for user input. It can be initialized to anything, but having it be equal to 0 keeps things clean.

3 Ö:

  1. Move the program pointer one step to the left (mvl). Now it's pointing to the byte where the input is stored.
  2. Print the current byte (wrt cns).
  3. Move the program pointer one step to the left again (mvl). Now it's back to the first byte (Ø).

Infinite loop

This prints "Hello! " over and over again forever.

Characters:

♀♦↑H↑e↑l↑l↑o↑!↑ -♦

Hexadecimal:

0c 04 18 48 18 65 18 6c 18 6c 18 6f 18 21 18 20 2d 04

Instructions:

mvr ... ... red cns spc ... mvr
mvr ... ... red ... spc ... mvr
mvr ... ... wrt cns ... ... mvr
mvr jmr ... red cns ... ... mvr
mvr ... ... wrt cns ... ... mvr
mvr jmr jml red ... spc ... mvl
mvr ... ... wrt cns ... ... mvr
mvr jmr jml red cns spc ... mvr
mvr ... ... wrt cns ... ... mvr
mvr jmr jml red cns spc ... mvr
mvr ... ... wrt cns ... ... mvr
mvr jmr jml red cns spc neq mvl
mvr ... ... wrt cns ... ... mvr
mvr ... jml red ... ... ... mvl
mvr ... ... wrt cns ... ... mvr
mvr ... jml red ... ... ... mvr
mvr ... jml red cns spc ... mvl
mvr ... ... red ... spc ... mvr

Here's how it works: 1. :

  1. Move the program pointer one step to the right (mvr)
  2. Do nothing (red cns spc)
  3. Move the program pointer one step to the right again (mvr)

2. ↑H↑e↑l↑l↑o↑!↑ :

  1. Move the program pointer one step to the right (mvr)
  2. Print the value (wrt cns)
  3. Move the program pointer one step to the right again (mvr). If the program pointer has reached the end of the string, execute -♦. If not, the program pointer is pointing to a byte with the same value as the current one, so go back to step 1.

3. -♦:

  1. Move the program pointer one step to the right (mvr).
  2. Jump back to the previous command that is equal to (jml)
  3. Move the program pointer one step to the left (mvl). Now it's pointing at , and we're back to where we started from.

Truth machine

This program accepts one character as input. If that character equals 1, it prints it forever. Otherwise, it prints it once and exits.

Characters:

‘1Ø‘Ü

Hexadecimal:

00 31 08 00 9a

Instructions:

mvr ... ... red ... ... ... mvr
mvr ... jml wrt ... ... ... mvl
mvr ... ... red cns ... ... mvr
mvr ... ... red ... ... ... mvr
mvl ... ... wrt cns ... neq mvr

Here's how it works:

1. :

  1. Move the program pointer one step to the right (mvr)
  2. Store the value the program pointer is pointing to in the accumulator (red)
  3. Move the program pointer one step to the right again (mvr)

2. 1:

  • This value is stored in the accumulator by the first .

3. Ø:

  1. Move the main program pointer one step to the right (mvr)
  2. Copy the input to the byte that is being pointed to (red cns)
  3. Move the main program pointer one step to the right again (mvr)

4. :

  • This is a placeholder for user input. It doesn't matter what character is initially stored here.

5. Ü:

  1. Move the main program pointer one step to the left (mvl). The character from user input is stored here.
  2. Print the value in the byte that is being pointed to (wrt cns)
  3. neq: If the byte that is being pointed to is not equal to the accumulator (in other words, if the user input is not equal to the character '1'), move the program pointer two steps to the right. This moves it out of program bounds, so the program exits, only printing the input once in the Ø command. If the input IS, however, equal to the character '1', the program pointer only moves to the right once. Now it's back to the same command (Ü), so it executes it again. Since no bytes are changed in the process, Ü will give the same result: Print the user input before executing Ü, which prints the user input before executing Ü et cetera.

Computational Class

It's not known whether BIJ is Turing complete or not. That's because I'm the only person to know about BIJ, and I'm not smart enough to figure such advanced things out.

External resources