gur yvsr
- gur yvsr is typically stylized as all lowercase.
gur yvsr is the very first esolang created by User:Placeholding. It is inspired by Brainfuck and (slightly inspired by) Emmental, though it is not as confusing as either of them (still very confusing).
Overview
Syntax
gur yvsr's syntax consists of single-character commands as well as comments. A comment starts and ends with backticks (`
), like so:
`I will be ignored.`
In addition, gur yvsr will ignore all whitespace characters.
The Tape & the Pointers
Like Brainfuck, gur yvsr operates on a tape of integers; however, this tape can go in both the positive and negative directions and can hold negative numbers. gur yvsr also has a pointer (called the data pointer) that continues moving down the tape (it moves in the positive direction when the program starts) and can read and write to the tape. Certain commands can stop the data pointer from moving (e.g. #
, J
, and digits 0
through 9
), but it will continue moving after the next command is executed (unless that command also halts the data pointer temporarily). It's important to note that the data pointer will always move AFTER executing a command.
The code pointer is simply the pointer which reads and executes commands. It is only able to move to the right.
The Accumulator
In addition to the tape and data pointer, gur yvsr also has an accumulator which can only hold one signed integer value. All integers that are created first go into the accumulator, where they can then be put onto the tape.
Another thing that can be done with the accumulator is to clear it; this can be accomplished with the C
command.
Creating Integers
The #
command can be used to signify the creation of an integer. Please note that if the #
command is executed twice in a row or if the accumulator is full when executing the #
command, gur yvsr will raise an error.
Digits (0
-9
) can be placed after the #
command to start creating the integer. If the accumulator is empty, the digit's value will simply be stored into the accumulator; otherwise, the accumulator's value will be multiplied by 10, and then the digit's value will be added to the accumulator's value. An error will be raised if the digit appears without a previously executed #
command or without a previously executed digit.
An example of integer creation:
#134 `this will store the number 134 into the accumulator`
Remember that there's no need to worry about the data pointer moving; both executing the #
command and appending digits to the accumulator's value will temporarily halt the data pointer.
Writing to & Reading from the Tape
As stated before, all integers will first go into the accumulator. In order to get data out of the accumulator and onto the tape, you may use the U
command. The u
command may also be used to write to the tape, but it does not clear the accumulator. An error will be thrown if you use the U
or u
commands when the accumulator is empty. After executing either the U
or u
commands, the integer in the accumulator's value will be stored in the current cell (i.e. the cell being pointed to by the data pointer).
The opposites of the U
and u
commands also exist: R
and r
, respectively. The R
command will store the current cell's value into the accumulator, and then clears the current cell. If the current cell is empty when this command is executed, the program will throw an error. r
does the same thing, except that it does not clear the current cell's value.
Like the accumulator, the current cell can be cleared; the command for clearing the current cell is c
.
Control Flow
Conditionals
gur yvsr has seven conditional commands: ?
, !
, T
, t
, A
, a
, and @
. The first six commands will check if the current cell (?
and !
), a different cell (T
and t
), or the accumulator (A
and a
) are zero or empty. Depending on what these six commands are looking for, they will send the code pointer to the corresponding @
command if they are satisfied. If not, they will not do anything. Below is a table on what these six commands are looking for:
Command | Will be satisfied if: |
---|---|
? |
the current cell is 0 or empty |
! |
the current cell is neither 0 nor empty |
T |
the nth cell is 0 or empty, where n is the accumulator's value |
t |
the nth cell is neither 0 nor empty, where n is the accumulator's value |
A |
the accumulator's value is 0 or empty |
a |
the accumulator's value is neither 0 nor empty |
These conditionals MUST be paired with a corresponding @
command if they are satisfied. If no corresponding @
command is found, an error will be thrown.
Bad Examples
The following examples demonstrate uses of conditional commands which lead to an error being thrown:
#8 U ! .
This is not OK because the ?
conditional is satisfied, and there is no @
command to send the code pointer to.
? ? @ .
This is not OK because even though there is an @
command present, only one ?
conditional has a corresponding @
.
@ A .
Even though there is an @
command with the A
command, this is not OK because the @
command needs to go after the A
command. This applies to all other conditionals as well.
Good Examples
The following examples demonstrate uses of conditional commands which don't cause an error to be thrown:
? #12 U #44 U #2 - K i . @ #33 k .
The ?
command is satisfied and has a corresponding @
command.
! #77 .
The !
command is not satisfied, so it does not need a corresponding @
command.
? #0 U #2 - K = A C #77 . @ #100 U @ .
The ?
and A
commands are satisfied and each have a corresponding @
. Conditional structures like these are called nests, where a conditional and @
surround another conditional and @
.
The Stop Command & the No-op
gur yvsr programs must contain a stop command (.
) in order for them to end properly. If there is no stop command to stop the program, the program will throw an error complaining that the code pointer has been pushed out of bounds.
gur yvsr's no-op command is simply an underscore (_
). It simply does nothing, but it could be useful in a few cases since it doesn't halt the data pointer.
Pointer Commands
Both the data pointer and code pointer can be manipulated in similar ways. They can both be moved around, but only the data pointer may change direction. Below is a table of pointer commands:
Command | Does this: |
---|---|
J |
Makes the code pointer jump n commands to the right, where n is the accumulator's value, and clears the accumulator |
j |
Makes the code pointer jump to the command at index n, where n is the accumulator's value, and clears the accumulator (the command at index 0 is the first command) |
K |
Makes the data pointer jump n cells to the right, where n is the accumulator's value, clears the accumulator, and temporarily halts the data pointer |
k |
Makes the data pointer jump to the cell at index n, where n is the accumulator's value, clears the accumulator, and temporarily halts the data pointer (the cell at index 0 is the first cell) |
F or f |
Flips the data pointer's direction |
Do note that these commands can be easily used to push the data pointer and code pointer out of bounds. If that happens, an error will be thrown.
Math & Logic
gur yvsr has several math and logical commands which store something into the accumulator. Most of these commands take into account the cell to the left of the current cell and the current cell, meaning that they will cause an error to be thrown if either the cell to the left of the current cell is empty or the current cell is empty. Below is a table of every math and logical command:
c | current cell's value (i.e. the value of the cell being pointed to by the data pointer) |
l | the value of the cell to the left of the current cell |
a | accumulator's value |
Command | Stores this to accumulator: |
---|---|
+ |
l + c
|
- |
-a
|
* |
l × c
|
/ |
⌊l ÷ c⌋
|
% |
l mod c
|
= |
1 if l = c; otherwise 0
|
N or n |
1 if l ≠ c; otherwise 0
|
> |
1 if l > c; otherwise 0
|
G or g |
1 if l ≥ c; otherwise 0
|
< |
1 if l < c; otherwise 0
|
L or l |
1 if l ≤ c; otherwise 0
|
& |
l AND c
|
| |
l OR c
|
~ |
NOT c
|
^ |
l XOR c
|
IO
gur yvsr's IO functionality is super simple: it has 2 commands for input (I
and S
) and 2 for output (i
and s
).
The I
command is very simple: it simply gets integer input and stores that input into the accumulator, overwriting the accumulator's previous value; it also temporarily halts the data pointer. S
is more complicated: it takes in string input and then, starting from the current cell, places each byte onto the tape. If that sounds confusing, below is what the tape would look like after inputting "Hello" when the data pointer is at cell 0 (where it starts when the program starts):
Position | -4 | -3 | -2 | -1 | 0 | 1 | 2 | 3 | 4 |
---|---|---|---|---|---|---|---|---|---|
Data | 72 | 101 | 108 | 108 | 110 |
i
and s
are both very simple: the i
command simply prints out the current cell's value, while the s
command prints out the current cell's value as a UTF-8 character.
Errors
Below is a table of every error that can be thrown along with why they might be thrown:
Error | Why it would be thrown |
---|---|
FileError |
|
UnknownSymbolError |
There is an unrecognized symbol that is not commented out |
OpError |
|
AccumulatorError |
The accumulator was full when executing any one of these commands:
or empty when executing any one of these commands:
|
SyntaxError |
|
InputError |
|
OutOfBoundsError |
|
OverflowError |
|
CommandLineArgsError |
|
Example Programs
Hello World
#72U `H` #101U `e` #108uU `ll` #111U `o` #32U ` ` #87U `W` #111U `o` #114U `r` #108U `l` #100U `d` #0k `go to cell 0` sssssssssss. `print out characters`
Truth-machine
IU `get integer input and put it on the tape` #2-K! `check if the input is nonzero` #2-Ki. `if no, print a single 0` @#0ki#9-J `otherwise, print the input infinitely`
Cat program
S `get in integer from the user` #2-K? `repeatedly check if current cell is empty` #2-Ks#2-K#4j `if no: print current cell's value as character and move onto next cell` @. `if yes: end program`
Calculator
IUIUIU `get the first value, second value, and operator (1: addition, 2: subtraction, 3: multiplication, 4: division, 5: modulus)` #1U#3k=a `check if operator is addition` C#3k#2U#3k=a `check if operator is subtraction` C#3k#3U#3k=a `check if operator is multiplication` C#3k#4U#3k=a `check if operator is division` C#3k#5U#3k=a `check if operator is modulus` . @C#1k%U#2-Ki. `modulus` @C#1k/U#2-Ki. `division` @C#1k*U#2-Ki. `multiplication` @C#1kR-F_UF#1k+U#2-Ki. `gur yvsr does not have a basic subtraction operation, so subtraction is more complicated` @C#1k+U#2-Ki. `addition`
Appendix
This section will list extra information that you might want to keep in mind when programming in gur yvsr.
What halts the data pointer? What doesn't?
Only these commands temporarily halt the data pointer:
#
0
through9
K
k
I
Implementations
No implementation yet.