AlPhAbEt (or ABC for short) is an esoteric programming language designed by Kevin Niehage. All variables consist of single bits, but some advanced structures such as looping and subprocedures (with local copies of registers) are supported. A double-ended queue of bits known as a queack (or, for normal people, a deque) is also present.
This entry is based on a specification of AlPhAbEt 0.14. The specification is available only in German, and the description below is based on a translation by Safalra (User:Safalra), who accepts full responsibility for any errors in translation.
- 1 Registers
- 2 Source format
- 3 Operators
- 3.1 Assignment operators
- 3.2 Comparison operators
- 3.3 Looping operators
- 3.4 Logical operators
- 3.5 Queack operators
- 3.6 Blocks and their operators
- 4 External resources
AlPhAbEt programs can access 63 registers, of which one is a flag register, ten are function registers, and fifty-two are data registers. Registers are nominally binary, but can in reality contain one of three values:
- . (a period) represents 0, with which all registers are initialised
- , (a comma) represents 1
- ? (question mark) represents randomly 0 or 1
To aid readability, the period and comma values are referred to as 0 and 1, respectively, throughout this article.
The flag register, $, is used to indicate the success or failure of the previous read or write operation, with 0 representing failure and 1 representing success.
The function registers are named 0 to 9, and control input and output. Register 0 controls the medium to use, with 0 representing a file and 1 representing the screen. Registers 1 to 8 contains the byte to be written, or the byte read, depending on the operation to perform. Register 9 controls the operation performed, with 0 representing read and 1 representing write.
The data registers are named A to Z and a to z, and contain data for use in other operations.
AlPhAbEt source code consists of ASCII text. Whitespace (other than newlines) has no effect other than to aid readability. Comments start with the 'at' character (@) and last until the end of the line on which they feature. Instructions each consist of a set of three characters, of which the first and last represent registers, and the middle represents the operation to be performed.
AlPhAbEt has two assignment operators, represented by the left and right angle brackets. The latter assigns a value to a register, while the former assigns the logical NOT of a value to register. The specification does not define the logical NOT of the random value. Examples of usage:
A>. @ store 0 in A A>, @ store 1 in A A>? @ store the random value in A A>B @ store the value of B in A A<. @ store 1 (NOT 0) in A A<, @ store 0 (NOT 1) in A A<? @ stores the logical NOT of the random value in A A<B @ store the logical NOT of the value of B in A
AlPhAbEt has two comparison operators, represented by the equals sign and exclamation mark. The former tests for equality, while the latter tests for inequality. If the test returns true, execution continues at the next instruction. If the text returns false, execution continues after the next matching pipe character. Example of usage:
A=, B>, | A!, B>? | @ sets B to 1 if A equals 1, and otherwise sets B to the random value
The following example assigns a random value to A. We first set A to 0, test whether a randomly chosen number equals 1 (is not 0) and if so, we set A to 1:
A>. A!? A>, | @ assigns a random value generated by ? to A
AlPhAbEt has two looping operators, represented by the asterisk and stroke. The former loops while its parameters are equal, while the latter loops while its parameters are unequal. Whilst the test returns true, execution continues at the next instruction. Once the test returns false, execution continues after the next matching tilde character. Example of usage:
0>, $>, $*, 9>. $=, 9>, ~ @ reads and writes user-input until action is canceled
0<. $<. $/. 9<, $!. 9<. ~ @ the same as above but with NOT-operators instead
The code above implements a simple cat program that waits for user input and then echos the input that the user provides, halting once no further input is available.
AlPhAbEt represents the logical AND, OR and XOR operators by the plus, minus and percentage signs respectively. These operators perform the logical operation on the two specified registers and store the result in the first register. Examples of usage:
A+B @ sets A to A AND B A-B @ sets A to A OR B A%B @ sets A to A XOR B
A+, @ sets A to A AND 1 A-, @ sets A to A OR 1 A%, @ sets A to A XOR 1
AlPhAbEt programs can also access a single linear data structure called a queack, a deque of bits.
Bits can be popped/dequeued using the memory read operator, represented by a colon. The first parameter specifies the register to which to write the bit, and the second parameter specifies from which end of the queack the bit should be read - 0 for the front, and 1 for the back. When a bit is dequeued through this way, the information of its insertion time (e.g. whether it was the first bit enqueued) is lost. Examples of usage:
A:. @ reads a bit from the front of the queack A:, @ reads a bit from the back of the queack
Bits can be pushed/enqueued using the memory write operator, represented by a semicolon. The first parameter specifies the register from which to read the bit, and the second parameter specifies to which end of the queack the bit should be written - 0 for the front, and 1 for the back. Examples of usage:
A;. @ writes a bit to the front of the queack A;, @ writes a bit to the back of the queack
Pop/dequeue and push/enqueue operations can be combined using two further operations, represented by brackets. The left bracket represents the operation of reading an item from the front of the queack, and the right bracket represents the operation of reading an item from the back of the queack. The first parameter of each specifies the register into which to write the bit, and the second parameter specifies whether the bit should be written back to the front (0) or back (1) of the queack. When a bit is dequeued through this way, the information of its insertion time (e.g. whether it was the first bit enqueued) is NOT lost. Examples of usage:
A(. @ reads a bit from the front of the queack and places it back at the front A(, @ reads a bit from the front of the queack and places it at the back A). @ reads a bit from the back of the queack and places it at the front A), @ reads a bit from the back of the queack and places it back at the back
Checking for emptiness
The current status of the queack (whether or nor it contains bits) can be obtained using the operator represented by an underscore. Emptiness is represented by 0, and the presence of bits is represented by a 1. This value is logically XORed with the second parameter, and the result stored in the specified register. Examples of usage:
A_. @ 0 if the queack is empty, 1 otherwise A_, @ 1 if the queack is empty, 0 otherwise
The queack remembers the order in which bits were inserted. The operator represented by a hash sign returns whether the bit at the front (0) or back (1) of the queack is the oldest bit in the queack, with 1 representing true. If the queack is empty, the operator returns true. Examples of usage:
A#. @ 1 if the bit at the front of the queack is oldest, 0 otherwise A#, @ 1 if the bit at the back of the queack is oldest, 0 otherwise
Blocks and their operators
AlPhAbEt allows subprocedures known as blocks (German Blöcke) to be defined. Each block has a name, taken from the set of register names. Blocks can have local copies of the registers.
A block is delimited by the register name followed by a left square bracket at the start, and a right square bracket followed by the register name at the end. For example, this code defines a block called A:
A[A>.]A @ defines a new block called A, which stores 0 in the register A
Note that the register name used inside the block is independent of the name of the block.
Blocks can be redefined, meaning that the old definition is replaced by the new one.
a[a>.]a @ defines a new block called a, which stores 0 in the register a a[a>,]a @ redefines the block a, which now stores 1 in the register a
Note that a block can't redefine itself.
a[a>. a[a>,]a]a @ ERROR
The call operator, represented by an ampersand, allows a block to be called. It is preceded by the name of the block. Blocks may call themselves recursively, or even call other blocks which in turn call the original block. Example of usage:
0>, A[9>.9>,]A A& A& A& @ reads three characters from the input and outputs them
Now an example in which we additionally overwrite a given block. Note that when a block is called, its CURRENT definition will be used:
0>, A[9>.9>,]A A& A[9>,]A A& @ call block A two times, first time it reads a character and outputs it, second time it just outputs it
Global and local registers
Blocks can access both local and global copies of registers. By default blocks access the global registers, but the local operator, represented by a caret, switches to local copies. The global operator, represented by a back tick, switches back to global copies. Example of usage:
A[^A>.`B>.]A A& @ changes the global B, but only a local copy of A
- AlPhAbEt home page (in German)