Abc!?
Abc!? is a simple, procedural, unstructured (esoteric) programming language that I made up. I would describe it as a slightly higher-level assembly language. One big limitation is that it is impossible to refer to addresses of the program code, so built-in returns from procedure calls are impossible.
Program syntax
A program file consists of a data section and then a code section. All text in the program file is data by default. The code section does not start until a line with only "Abc!?" written on it appears. So, a file consists of an optional data section, followed by the line "Abc!?", and then an optional code section. An example:
Sample text in the data section. Abc!? 1 line of code; 0>!
Each line in the program section begins with a comment/label, then a semicolon, then optional whitespace, and finally a statement/operation. This forces every single line of code to be documented (or you could take the lazy path and just label each line with a number like in BASIC).
Text in the data section also processes escape codes. An escape code is a backslash followed by a the ascii number for the character you want.
The statement/operation must ignore whitespace on the line. See the "Statement" section below for more information.
There are 3 kinds of number literals in the code section:
decimal, hexadecimal, and un-escaped characters.
Decimal numbers are just written out normally with the digits 0-9, and hexadecimal numbers are prefixed with the dollar sign. An "un-escaped character" is a character literal, which is any character preceded by a backslash (like \H in the hello world example).
Variables
There are 3 categories of variables: lower case, upper case, and special. Every variable named with a lower case letter holds 1 byte, every variable named with an upper case letter holds 8 bytes, and both special variables hold 1 byte. All values (variables and literals) are treated as 2's complement signed integers within arithmetic operations. All values are converted to characters via truncation for input and output. The only variables that are available are the 26 upper case letters and the 26 lower case letters of the Latin alphabet. Case matter, so A ≠ a.
There are also two special variables: "?" and "!", which only hold 1 byte each. The "?" question mark variable represents program input, and it can be read from. When the value of "?" is needed, the value is obtained by reading 1 character of program input. The "!" exclamation mark variable represents program output, and it can be written to. When the value of "!" is written to, it writes 1 character of program output. These two special variables, "?" and "!" can be used anywhere a normal variable can be used, and they may appear multiple times on one line. When the special variables appear multiple times, they follow the rule for variable evaluation.
The rule for variable evaluation is that on a single line of code, the value of a variable will be read either 0 or 1 times and will be written to either 0 or 1 times. This has important implications for the values of the special variables. Consider the 2 lines of code below:
1; [?#0]?>a 2; [!#a]!>!
Line #1 takes an input character and stores it in a
unless the value was 0.
Line #2 takes a random value and writes it out unless it is equal to a
.
The following table summarizes the variable types.
Variable type | Size (bytes) | Read behavior | Write behavior |
---|---|---|---|
Lower case a-z | 1 | get the stored value | set the stored value |
Upper case A-Z | 8 | get the stored value | set the stored value |
Special "?" | 1 | get a byte of input | terminate the program |
Special "!" | 1 | get a uniform random value | write a byte of output |
Statements
A statement must be on one line. It begins with a comment, followed by a semicolon, optionally followed by a condition, and finally followed by the operation. There are 2 kinds of operations: move and jump.
Unconditional | Conditional | |
---|---|---|
Move | a+b>c |
[a=1]b+c>c
|
Jump | :La |
[a=1]:Lb
|
Any operation may be made conditional by preceding the operation code with a condition.
A condition is a binary comparison enclosed in square brackets.
The valid comparison operators are: =
, #
, >
, and >
.
The operator #
means "not equal".
Examples of conditional statements
Set b to a unless a=1; [a#1]a>b
Most complicated statement possible; [a=b]c+d>>e
.
Memory
Memory addresses can be written as integer literals within the source code. Memory is byte-addressed, so when reading memory into a lower case variable, 1 byte is read, while 8 bytes are read when reading memory into an upper case variable. The addresses start at zero, and address zero points to the beginning of the data section. Note that memory addresses are not guaranteed to fit within a lower case variable.
Operators
There are only two kinds of operations: move and jump. Both may optionally be preceded by one condition.
Conditional operators
The 4 conditions are:
- equal:
=
- not equal:
#
- less than:
<
- more than:
>
Move operation
A move operations, or statement, moves the value computed on the left hand side into a variable or a memory address on the right hand side. A move can contain a calculation on the left hand side. The syntax for a move is the left hand side followed by a greater-than sign followed by a destination, which can be any variable or a number, which signifies a memory address. If the destination is a non-special variable, then you may repeat the greater-than-sign to signify that the address referred to by the variable is meant to be written to rather than the variable itself.
Move operations have many sub-operations that can be used to compute values: binary and unary.
Binary operators
- add:
+
- subtract:
-
- multiply:
*
- divide:
/
- bitwise and:
&
- bitwise or:
|
Unary operators
- bitwise complement:
~
- address dereference:
*
Examples of "move" lines
Example 1; a+b>c
Example 2; a+b>>c
Example 3; ~a>b
Example 4; ~a>>b
Example 5; a>b
Example 6; a>>b
Jump operation
A jump operation, or statement, jumps to the line with the given label. A jump statement begins with a colon and the rest of the line is devoted to specifying the label of the line to jump to. The line the jump statement jumps to is the first line that appears in the code that has all of the same first characters as the label. Note that letter case does matter for labels, but the labels do not have to match the full text.
Examples of "jump" lines
Infinite loop; :Inf
Jump to line starting with abc; :abc
Example Programs
Hello world (long and straightforward)
Abc!? H; \H>! e; \e>! l; \l>! l; \l>! o; \o>! ,; \,>! space; \ >! w; \w>! o; \o>! r; \r>! l; \l>! d; \d>! !; \!>! newline; 10>! exit; 0>?
Hello world (shorter)
This program prints out its data section until it reaches a sentinel value, which is the null character (0) in this case.
Hello, world!\0 Abc!? Start; 0>i Get data; *i>x Check end; [x=0]:Done Increment; i+1>i Print char; x>! Loop back; :Get data Done; 0>?
Cat
Abc!? I/O; ?>! Rep; :I/O
Truth-machine
Abc!? Get; ?>x Check; [x=\0]:False True; \1>! Loop; :True False; \0>! Exit; 0>?
Fibonacci Sequence
Calculates the Fibonacci sequence until for values under N. Abc!? Setup N; 99999 > N Setup A; 1 > A Setup B; 0 > B begin PrintInt; 0 > M 30; A > D loop1 PrintInt; D/10 > Q 35; Q * 10 > S 40; D - S > R 50; Q > D 60; R + 48 >> M 70; M+1 > M 80; [D#0] :loop1 PrintInt yy; M - 1 > M loop2 PrintInt; *M > ! 90; [M=0] :xx 100; M - 1 > M 110; :loop2 PrintInt xx; 32 > ! 01; A > T 10; A+B > A 20; T > B Repeat?; [A<N] :begin PrintInt Quit1; 10 > ! Quit2; 0 > ?
Implementations
- Abc!?/Python Compiler made by the original author of Abc!?