(SIASL)²
Paradigm(s) | imperative |
---|---|
Designed by | User:K.avi |
Appeared in | 2023 |
Memory system | Cell-based |
Dimensions | one-dimensional |
Computational class | Turing complete |
Reference implementation | (SIASL)² interpreter |
Influenced by | Brainfuck 2DFuck Befunge |
File extension(s) | .siasl .siasl2 |
(SIASL)² is an Esolang belonging to the Turing tarpit family of languages. It takes inspiration from Brainfuck.The most simple way to descripe (SIASL)² would be as a 2d Brainfuck see Generic 2D Brainfuck and 2DFuck for reference. The main thing separating (SIASL)² from these languages is that a (SIASL)² instruction is a combination of two characters instead of one.
The name SIASL stands for "Siasl Is a Silly Language". The ()² part comes from the fact that each (SIASL)² instruction is two SIASL instructions.
Crucially (SIASL)² instructions are commutative which means that
+#
and #+
are the exact same instructions.
This limits the amount of instructions that can be created in (SIASL)² but makes the language easier to understand.
(SIASL)² is also quite "over the top" (for a turing tarpit) because it supports a lot of predefined instructions makes it possible to define custom instructions and supports a little bit of meta-programming.
Environment
Similarly to brainfuck (SIASL)² does operation on cells containing numbers. However the structure containing these cells is a square matrix instead of an array. This allows movement in 4 directions instead of two (see < , > , v , ^ related operations).
Each cell contains a signed integer. It's value can be modified by a lot of different operations. When reaching the end of a "line" in the matrix and trying to go to the right the data pointer will be move to the start of the next line. Similar behavior occurs when reaching the start and trying to go to the left from the start of the line or when reaching the first/last line of the matrix and going up or down.
Supported instructions
(SIASL)² supports a lot of predefined instruction with different effects. It is important to remember that (SIASL)² instruction are commutative. Thus v♯
is the same as ♯v
It also supports multi-line comments. everything written in between {
and }
will be ignored by the interpreter.
NB: The behavior of preset instruction cannot be changed.
Default instructions
instruction containing a ♯
are very similar to traditionnal Brainfuck instructions. They are simple and straightforward operations. They are called the "default" family of instruction.
Command | Description |
---|---|
♯>
|
Move the pointer to the right |
♯<
|
Move the pointer to the left |
♯^
|
Move the pointer upwards |
♯v
|
Move the pointer downwards |
♯+
|
Increment the memory cell under the pointer |
♯-
|
Decrement the memory cell under the pointer |
.♯
|
prints the value stored in the cell under the pointer as a character |
,♯
|
Input a character and store it's ASCII value in the cell under the pointer |
[♯
|
Jump past the matching ♯] if the cell under the pointer is 0
|
♯]
|
Jump back to the matching [♯ if the cell under the pointer is nonzero
|
♯*
|
multiply the cell under the pointer by the current mult/div value (default 2) |
♯/
|
sets the cell under the pointer to the result the integer division between it's value and the current mult/div value (default 2) |
Arithmetic instructions
(SIASL)² supports a number of instructions that are variations on the defaults *♯
+♯
-♯
and /♯
instructions.
NB: /
related operations won't try to divide by zero. When called in a context where they would have to calculate a division by zero they are ignored
Command | Description |
---|---|
+>
|
adds the value stored in the cell under the pointer to the one stored in the cell on it's right and stores it in the cell under the pointer |
+<
|
adds the value stored in the cell under the pointer to the one stored in the cell on it's left and stores it in the cell under the pointer |
+v
|
adds the value stored in the cell under the pointer to the one stored in the cell downwards and stores it in the cell under the pointer |
+^
|
adds the value stored in the cell under the pointer to the one stored in the cell upwards and stores it in the cell under the pointer |
>-
|
substracts the value stored in the cell on the right from the one in the cell under the pointer and stores it in the cell under the pointer |
<-
|
substracts the value stored in the cell on the left from the one in the cell under the pointer and stores it in the cell under the pointer |
^-
|
substracts the value stored in the cell downwards from the one in the cell under the pointer and stores it in the cell under the pointer |
v-
|
substracts the value stored in the upwards from the one in the cell under the pointer and stores it in the cell under the pointer |
*>
|
multiplies the value stored in the cell under the pointer with the one stored in the cell on it's right and stores it in the cell under the pointer |
*<
|
multiplies the value stored in the cell under the pointer with the one stored in the cell on it's left and stores it in the cell under the pointer |
*^
|
multiplies the value stored in the cell under the pointer with the one stored in the cell upwards and stores it in the cell under the pointer |
*v
|
multiplies the value stored in the cell under the pointer with the one stored in the cell downwards and stores it in the cell under the pointer |
>/
|
calculates the result of the integer division of the value stored in the cell under the pointer by the one stored in the cell on it's right and stores it in the current cell. |
</
|
calculates the result of the integer division of the value stored in the cell under the pointer by the one stored in the cell on it's left and stores it in the current cell. |
^/
|
calculates the result of the integer division of the value stored in the cell under the pointer by the one stored in the cell upwards and stores it in the current cell. |
v/
|
calculates the result of the integer division of the value stored in the cell under the pointer by the one stored in the cell downwards and stores it in the current cell. |
Loop variations
(SIASL)² supports a number of instructions that are variations on the defaults[♯
and ♯]
instructions.
Command | Description |
---|---|
[+
|
increments the value of the cell under the pointer at the beginning of each execution of the loop |
+]
|
increments the value of the cell under the pointer at the end of each execution of the loop |
[-
|
decrements the value of the cell under the pointer at the beginning of each execution of the loop |
-]
|
decrements the value of the cell under the pointer at the end of each execution of the loop |
[>
|
moves the pointer to the right at the beginning of each execution of the loop |
>]
|
moves the pointer to the right at the end of each execution of the loop |
[<
|
moves the pointer to the left at the beginning of each execution of the loop |
<]
|
moves the pointer to the left at the end of each execution of the loop |
[^
|
moves the pointer to the upwards at the beginning of each execution of the loop |
^]
|
moves the pointer upwards at the end of each execution of the loop |
[v
|
moves the pointer downwards at the beginning of each execution of the loop |
v]
|
moves the pointer downwards at the end of each execution of the loop |
Meta instructions
(SIASL)² supports a number of instructions that modify the effects of other instructions and/or the way the language behaves and can thus be seen as "meta instructions"
Command | Description |
---|---|
?>
|
This instruction sets the flow of the execution of the program from the right to the left. The way this is implemented is that when given a program the interpreter will execute the current instruction then the "next" one until it reaches the end of the program. ie: it will read the program from right to left and stop at the end.
NB: this is the default behavior of (SIASL)² |
?<
|
This instruction sets the flow of the execution of the program from the left to the right. The way this is implemented is that when given a programthe interpreter will execute the current instruction then the "previous" one until it reaches the beginning of the program. ie: it will read the program from left to right and stop at the beginning. Also reverses the role of [* and *] so that open bracket are seen as closing ones and vice-versa
NB: this can be used at the end of a program to execute it again "backwards" NB: in the interactive interpreter; the flow of execution is set to default after each line evaluated this is done to avoid problems with loops. |
?,
|
this instruction reads a character and sets the value of the number used in the *♯ and /♯
instructions to the ASCII value of the character read. |
(♯
|
(♯ combined with ♯) makes defining behavior for unused symbols possible. The syntax to do so is (♯ [symbol] [symbols] ♯)
Once this expression has been evaluated [symbol] will be replaced by [symbols] when evaluated. |
♯)
|
♯) combined with (♯ makes defining behavior for unused symbols possible. The syntax to do so is (♯ [symbol] [symbols] ♯)
Once this expression has been evaluated [symbol] will be replaced by [symbols] when evaluated. |
Misc instructions
(SIASL)² supports other instructions. They are regrouped in this category since they don't fit in any other one. These instructions are grouped into two families : the "print formatters" and the "movement" instructions.
Command | Description |
---|---|
.+
|
prints the value stored in the cell under the pointer as a signed decimal integer |
.-
|
prints the value stored in the cell under the pointer as an hexadecimal integer |
.*
|
prints the value stored in the cell under the pointer as an octal integer |
./
|
prints the value stored in the cell under the pointer as an unsigned decimal integer |
.?
|
prints the value stored in the cell under the pointer as a floating point number |
>>
|
goes to the last cell of the current row |
<<
|
goes to the first cell of the current row |
^^
|
goes to the first cell of the matrix |
vv
|
goes to the last cell of the matrix |
Settable instructions
Presentation
(SIASL)² allows you to define behavior for every unused symbol/instruction
(a symbol/instruction being two (SIASL)² characters). Like regular instructions;
definable ones are commutative which means that
?+
and +?
are the same instruction.
At the start of (SIASL)² none of the unused symbols has an effect. To define them you can use (# and #). The syntax for symbol definition is :
(# unused_symbol symbol(s) #)
Once such an expression has been evaluated unused_symbol will be replaced by symbol(s) when it is evaluated.
NB : EVERY symbol that ISN'T documented is settable.
Behavior specificity
This sections describes the specific behavior of redefinition of symbols.
- Symbol defining is NOT compatible with the
<?
instruction. When flow of execution is reversed, redefinition statements are ignored.
- Defining a symbol with itself and then trying to evaluate it will cause a stack overflow. For example evaluating
??
after this definition(♯?? ?? ♯)
will cause a stack overflow.
- Similarly if the definition of 2 or more symbols mutually relies on each other trying to evaluate them will cause a stack overflow. example:
(#??..#) (#..??#)
After these definitions calling ??
or ..
will cause a stack overflow as their definition relies on the other ones definition. This example is simple but more complex cases could be easily found with 3 or more symbols.
- When defining a symbol with another unused symbol, for example :
(#??..#)
the behavior of ??
will change if you redefine ..
later.
example:
(#??..#) ?? (#..+#.+#) ??
here the first ??
will not do anything but after the redefinition of ..
it will increment the current cell and print it as an integer.
- Once a symbol is defined, you can redefine it. It's behavior will be the one of the last definition.
example:
(#??#-#<#) ?? (#??.+#) ??
the first call to ??
will substract 1 from the current cell and go to the cell on the left the second one will print the value of the current cell as an integer.
- you can use symbol definition "recursively"
example:
(#??(#..>#**#v#)#)
is a valid definition of ??
. When interpreted the definition of ..
is not evaluated before ??
is called. Which means that ..
will keep it's default (or previously defined behavior) until ??
is called.
Example programs
- cat:
,#[#.#,##] {a traduction of the brainfuck cat program in (SIASL)²}
- copy:
[-#]<+.+ {sets the value cell under the pointer cell to the value stored in the cell on its left and prints it as a signed integer}
- Silly:
+#+#*#*#+#**+#+#.#>#+#+#+#+#+#*#**+#+#+#+#+#.#>#<++#+#+#.#.#>#<++#+#+#+#+#+#+#+#+#+#+#+#+#.# {prints Silly}
- even counter:
^#+#+#*****#.#v#?>.+^#.#v#+#<? { uses ?> and <? to make an infinite loop by changing the flow of execution and prints every even number}
- multi-layered symbol definition :
(#??+#..#) ?? (#..**+#.+#) ?? (#(+(#??.+#)#) ?? (+ ??
explanation of the previous program :
line 1 defines ??
as +#..
when evaluated. The default behavior of +#
is to increment the cell under the pointer and the default behavior of ..
is to do nothing.
This means that after ??
is called on line 2 it only increments the cell under the pointer.
line 3 defines ..
as **+#.+
which means that it calculates the square of the cell under the pointer and sets
it as the new value of the cell. (**
instruction) ; it then increments it (+♯
instruction) and prints it as an integer (.+
instruction)
this means that when ??
is called again on line 4 it now executes the +♯
instruction but also every
instruction associated with ..
on line 5 (+
is defined as (♯??.+♯)
this means that callling (+
will now redefine
??
as .+
line 6 is here to show that ??
hasn't been redefined yet.
line 7 redefines ??
line 8 demonstrates the new behavior of ??
External resources
interpreter written in C with flex/bison parser (the repo also contains a more detailed documentation of the language)