AnyPL
AnyPL is an esoteric programming language created by Peter Larsen in 2011.
AnyPL stands for Any Programming Language. The most current version of AnyPL is 0001.
Characteristics
This programming language is not esoteric in the means it is minimalistic. One goal was actually to create a programming language that was handy and easy to create applications with, but the result is kind of difficult to program in. The main purpose with AnyPL is to experiment with new concepts. The esoteric characteristics of this programming language is:
- Mostly single character commands
- The strict structure of the sourcecode which lacks many freedoms other programming languages gives you
- Every command has a position as a result of the strict rules for the sourcecode
- A way to execute a variable length of commands in a preset direction using a single character command
- Targets for conditional jumps can be any command since every single command has a position
- You can preset what commands to execute and what commands to be ignored by altering the 8 bits in a 1 byte variable
Memory
As in Brainfuck it operates on an array of memory cells, also referred to as the tape, each initially set to zero. The tape is infinite in both directions. The memory cells of the tape uses bytes (0-255, wrapping around). There is a tape pointer, initially pointing at the first memory cell.
Additionally there is 8 variables (refered to as: m1 ... m8), all initially set to zero. And there is also one Stack. The 8 variables and the stack also uses bytes (0-255, wrapping around).
Sourcecode
The sourcecode must be structured in a strict way. All commands is case sensitive. All rows must be exactly 90 characters long. One line of code is 10 blocks (2 octasets and 8 quadrasets) with 8 respectively 4 commands each + one 32 character long comment block. The blocks is separated by blankspaces.
The meaning of the commands depends on what horizontal position the command has. This means that the same command character can mean different things depending on what position the command is typed. In this definition of the programming language we will refer to a command position as:
<qs>:<cn> where <qs> is the quadraset (1-8) and <cn> is the command number (1-4).
The 1st block and the 10th block contains no commands, only labels. They are 8 characters long, the 8 quardrasets inbetween are all 4 commands each.
The 1st quadraset and the last (8th) quadraset is unique. Quadraset 2-7 is executed in the same way.
It's in the 8th quadraset, and only in the 8th quadraset, that you can control program flow with conditional jumps. You specify a condition and a target row (relative to the current line), a target quadraset (absolute) and a target command number (absolute). You can also specify to jump to a label specified in the 10th block of code in the line, the targeted label is defined in the first block.
All rows of sourcecode must be entered in the following way:
LLLLLLLL nnnn cccc cccc cccc cccc cccc cccc jjjj TTTTTTTT [ ............................ ]
- L = Labeldefinition. Set a unique label on this line of code, or simply enter "........" for a line of code that has no label.
Labels can only contain characters a-z, A-Z, 0-9, or any of the following characters :;-.,!"#¤%&/()=?+-[]
- n = This is 1:1 - 1:4, set execution-limit on a line of code
- c = Standard commands
- j = This is 8:1 - 8:4, here you can define conditional jumps.
- T = This is a target label for a conditional jump involving a label as a target line of code.
- . = Comment, replace the dots with your comments. Must start and end with brackets and spaces, "[ " and " ]"
The first 8 characters on every line ("LLLLLLLL") can also be used as a string in your application. The first 8 characters on the first line is where you can name your application.
Since each command has a specific coordinate one can say that the programming language has some 2D functionality. Although this programming language has many similarities with other single character 2D esoteric programming languages it differs quite much at other points. The 2D-commands available in position 8:4 let you take advantage of the strict 2D structure of the sourcecode in combination with the labeled lines and the use of variable m8 to gain realtime control over what code to execute and what code to ignore.
Execution exception
Before every command is executed a check against the value in variable m8 is done to decide whether the command should be executed of if it should be ignored. The 8 bits of the m8 value is used to decide what should be ignored or executed. A bit value of one (1) means that the code should be ignored, a bit value of zero (0) means that the code should be executed. The least significant bit states if code in the first quadraset should be executed or ignored, ... , and the most significant bit states if the last quadraset should be executed or ignored.
Parse
Parsing the sourcecode to check if it is valid is done in the following way:
- Every line must be exactly 90 characters long (not counting new line char)
- Every line must have a blankspace at column: 9, 14, 19, 24, 29, 34, 39, 44, 49, 58, 60, 89. Blankspaces is also allowed on column 61-88 (comment) but isn't allowed anywhere else in the sourcecode
- Every line must have brackets [ and ] at column 59 and 90
- Every line must have a new line character at column 91, exception: last line must have EOF on column 91
- The string on column 1-8 must be unique, or "........"
- The string on column 50-57 must be equal to exactly 1 string on column 1-8 on any line, or "........"
- The characters on column 10-13 must be numerical
- The characters on column 15-18, 20-23, 25-28, 30-33, 35-38, 40-43 must be any of the commands defined below in the 2nd - 7th quadraset
- The characters on column 61-88 can only contain characters a-z, A-Z, 0-9, or any of the following characters :;-.,!"#¤%&/()=?+-[] and blankspace
Quadraset/Command definitions
1st quadraset (1:)
versioncontrol (1st line), execution limits and other stuff.
If this is line #1 then 1:1 - 1:4 must contain a number that states what version of the programming language this sourcecode is created for. Must be a value between 0001 and 9999 (0001 translates to "version 0001 of anyPL). This means that the first line can't have any of the commands/functionality that a normal 1st quadraset can have, as defined below.
1:1 - 1:4 1st quadraset - 1st to 4th command 0000 - 9998 Execution limit. Define how many times this line of code is allowed to execute. If the value is exceeded then this line of code is ignored and execution is passed to the next line of code. The counter for a line of code can be reset using command "k", "l" or "n" in x:4 (see below) 9999 unlimited execution. 0000 Line is ignored. Useful for dedicated 2D programming lines of code.
2nd - 7th quadraset (2: - 7:)
2nd - 7th quadraset (refered to as x: below) - All standard commands.
x:1 x'th quadraset, 1st command - Tape and string commands < decrease tape pointer (move 1 step to the left) > increase tape pointer (move 1 step to the right) d decrease tape pointer (move m1 steps to the left) i increase tape pointer (move m1 steps to the right) | lock the tape pointer. If the tape pointer is already locked this command will be ignored. Every following attempts to move the tape pointer will be ignored until the pointer is released again. - release the tape pointer. If the tape pointer is not locked this command will be ignored. 1-8 Copy current tape cell value to variable (1 = m1 ... 8 = m8) and increase tape pointer (move 1 step to the right) p Pop 8 values from the stack, store into m1 - m8 u Push all variables m1 - m8 to the stack S Store a string to the tape. Use string on m1 lines above the current line. Copy characters from m2 to m3 to the tape increasing tape pointer 1 step for each character. If m3 is 0 or more than 8 then it is automatically 8. If m2 is 0 or more than m3 then it is automatically equal to m3. T Same as command "S" above except use string on m1 lines below the current line. R Same as command "S" above but you push the characters to the stack instead of to the tape. I Same as command "T" above but you push the characters to the stack instead of to the tape. . Nop. No operand.
x:2 x'th quadraset, 2nd command - Variable commands a...h decrease variable (a = m1 ... h = m8) by current tape cell value A...H increase variable (A = m1 ... H = m8) by current tape cell value 1...8 increase variable (1 = m1 ... 8 = m8) by 1 < decrease m1 by 1 = set variable m1 to value at current tape cell & set value at current tape cell to value in m1 i...o copy value in m1 to variable (i = m2 ... o = m8) I...O copy value in variable (I = m2 ... O = m8) to m1 p, q, r, s, t, u, v (if m2=0) Set m1 to, (if m2>0) increase m1 by a value: p = 2 q = 4 r = 8 s = 16 t = 32 u = 64 v = 128 P, Q, R, S, T, U, V (if m2=0) Set m1 to, (if m2>0) decrease m1 by a value: P = 2 Q = 4 R = 8 S = 16 T = 32 U = 64 V = 128 . NOP. No operand.
x:3 x'th quadraset, 3rd command - IO, variable locks and selfmodifying code commands i input, get a char input and store character value in m1 o output, print char value stored in m1 1-8 Put a lock on a variable preventing it from being overwritten. (1 = m1, 8 = m8) a-h Unlock a variable if it is locked (a = m1, h = m8) L Get current tape cell value. Use bits in value to lock variables (least significant bit = m1, most significant bit = m8) U Get current tape cell value. Use bits in value to unlock variables (least significant bit = m1, most significant bit = m8) S Switch 2 quadrasets on the current line: <m1>: is switched with <m2>:, if m1 or m2 is other than 2-7 then this command is ignored. W Switch 2 quadrasets on another line: <m1>: is switched with <m2>:, the line the switch is done is m3 number of line(s) up I Switch 2 quadrasets on another line: <m1>: is switched with <m2>:, the line the switch is done is m3 number of line(s) down T Switch 2 quadrasets on another line: <m1>: is switched with <m2>:, the line the switch is done is m3 number of line(s) up from "TTTTTTTT" C Switch 2 quadrasets on another line: <m1>: is switched with <m2>:, the line the switch is done is m3 number of line(s) down from "TTTTTTTT" H Switch 2 quadrasets on the current line: <m2>: is switched with <m3>:, if m2 or m3 is other than 2-7 then this command is ignored. . NOP. No operand
x:4 x'th quadraset, 4th command - Math, stack and other s push current tape cell value to the stack m push value in m1 to the stack p pop value from stack and store/overwrite current tape cell value 1...8 pop value from stack and store/overwrite value in variable (1 = m1, 8 = m8) A Addition. m1 = m1 + m2 S Substraction. m1 = m1 - m2 D Division. m1 = m1 / m2 M Multiplikation. m1,m2 = m1 * m2. m1 stores resulting value 0-255, m2 stores resulting upper 0-255 a If m1 = 0 then decrease tape pointer (move 1 step to the left) else do nothing b If m1 = 0 then decrease tape pointer (move 1 step to the left) else increase tape pointer (move 1 step to the right) c decrease tape pointer (move m1 steps to the left) d increase tape pointer (move m1 steps to the right) e If m1 = current tape cell then push zero else push 1 f If m1 = m2 then push zero else push 1 g Stack-reverse. Pop 2 values from the stack and push them back in reverse order h Stack-invert. Pop a value from stack, calculate inverted value (255-value) and push the result back into the stack i memory-roll. copy m1 to m2. Copy tape-value to m1, pop a value from the stack to tape, push m2 to the stack j memory-roll. copy m1 to m2. Pop stack-value to m1, push tape value to the stack, copy m2 to the tape k reset the execution-limit for the previous line of code that was executed before this one l reset the execution-limit for the line of code m1 lines above the current line (if m1 is 0 then do nothing) n reset the execution-limit for the line of code m1 lines below the current line (if m1 is 0 then do nothing) P pop 8 values from the stack, store into m8 - m1 U push all variables m8 - m1 to the stack B ROL m1, bit rotate left m1 C ROR m1, bit rotate right m1 E Bitwise AND m1, m2 Result is stored in m1, overwriting the current value. F Bitwise OR m1, m2 Result is stored in m1, overwriting the current value. G Bitwise NAND m1, m2 Result is stored in m1, overwriting the current value. H Bitwise NOT m1 Invert m1 and the result is stored in m1, overwriting the current value. I Bitwise XOR m1, m2 Result is stored in m1, overwriting the current value. J Bitwise NOR m1, m2 Result is stored in m1, overwriting the current value. K Bitwise XNOR m1, m2 Result is stored in m1, overwriting the current value. . NOP. No Operand.
8th quadraset (8:)
Conditional jumps ("----" means no jump, execution continues to the next row)
8:1 8th quadraset, 1st command - Define condition for conditional jump If the condition is not met, execution will continue to the next line of code ignoring the jump. If the condition is met execution will continue to what is declared in 8:2 - 8:4 - Do not perform any jump 0 No condition, just perform the jump 1...8 If value in variable m1-m8 is other than 0 N If current tape value is 0 Y If current tape value is 1 M If current tape value is more than m1 L If current tape value is less than m1 a...h If current tape value is more than variable (a = m1, h = m8) A...H If current tape value is less than variable (A = m1, H = m8)
8:2 8th quadraset, 2nd command - Select target <qs> for conditional jump Must result in a value of 1-8. Any other number will End program execution resulting in an error message passed to the command prompt 1...8 Hardcode target quadraset a...h Get value from variable (a = m1, h = m8). Any number in the variable other than 1-8 will be replaced with a "1" before the value is used as target <qs>
8:3 8th quadraset, 3rd command - Select target <cn> for conditional jump Must result in a value of 1, 2, 3 or 4. Any other number will End program execution resulting in an error message passed to the command prompt. If <qs> in 8:2 is 8, then <cn> is automatically 1. 1...4 Hardcode target command number a...h Get value from a variable (a = m1, h = m8). Any number in the variable other than 1-4 will be replaced with a "1" before the value is used as target <cn>
8:4 8th quadraset, 4th command - Select target row for conditional jump The lines of code wrap up on itself, connecting the last line with the first line. If execution end up above line #1 you continue from the last line counting down. Likewise if execution pass last line you end up on the first line counting up. > Continue to the row after the next row. Same as the command "2" < Jump to previous row = Jump to this row. Same as the command "0" 0...8 Jump # of rows down. a...h Jump # of rows up. (a = 1, h = 8) U Jump m1 number of rows up D Jump m1 number of rows down L Jump to label written in 9:1 - 9:8 I Jump to label written in 9:1 - 9:8 + m1 number of rows up. J Jump to label written in 9:1 - 9:8 + m1 number of rows down. - Use the min value found in variable m1-m8 (all zeroes is ignored), and jump up that number of rows. If all cells is zero, the function will jump to previous row. / Use the max value found in variable m1-m8 (all zeroes is ignored), and jump up that number of rows. If all cells is zero, the function will jump to previous row. + Use the min value found in variable m1-m8 (all zeroes is ignored), and jump down that number of rows. If all cells is zero, the function will jump to the next row. * Use the max value found in variable m1-m8 (all zeroes is ignored), and jump down that number of rows. If all cells is zero, the function will jump to the next row. . End program execution (ignoring 8:1-8:3)
2D-execution. The following commands pass execution to a target place (8:2-8:3 + 9:1-9:8), executes a variable number of commands, and when done execution returns to the next line of code after this line. Only 2:1 - 7:4 is considered, if execution is passed outside of this area it is wrapped around. The m8 variable still decides what commands to execute and what commands to ignore, but even if one command is ignored it still counts as 1 command. Execution is done in a 2D direction (0 = East, 1 = South, 2 = West, 3 = North, 4 = SE, 5 = SW, 6 = NW, 7 = NE). If any value other than 0-7 is used as direction then south will be the direction. i Execute a 2d-line of code. Starting at the target place, execute m2 number of commands in direction m3 j Same as "i" above. Repeat m6 times. k Execute a 2d-area of code. Starting at the target place, first execute m2 number of commands in direction m3. When done, move execution in direction m5 from target place, then start over executing m2 number of commands in direction m3. Continue for m4 number of steps in direction m5. l Same as "k" above. Repeat m6 times. m Pop m2 * 2 number of values from the stack, execute m2 number of commands. Use the values to jump to the commands that should be executed. Find the target commands by starting from the target place. First and every odd number of values is used as a direction. Second number and every following even value is used as a step count. n Execute two 2d-lines of code both starting at the target place, execute m2 number of commands from each line of code. Use direction m3 and m4. Alternate between the two lines every command, the first command is always shared between the two lines of code and is executed only ones. o Same as "o" above, Repeat m6 times
Example code:
Hello, World!
HelloWor 0001 .2.. S1.. .3.. .3.. Tr.. .1.c ---- ........ [ Put the strings to the tape. ] ld...... 0010 .<.. 1.0. .<.. .... .... .... 121= ........ [ Output. ] ........ 0001 .... .... .... .... .... .... -11. ........ [ End execution. ]
Cat
Cat..... 0001 ..i. ..o. .... .... .... .... ---- ........ [ Cat program ]
Future plans
Plans for future versions of Any Programming Language is better String handling commands.