Grok
Grok is a two-dimensional, stack-based language inspired by Befunge, ><>, and the Vim editor. It was invented by User:AarMil42 in 2021.
Concepts
Grok is a two-dimensional language, meaning that instructions can be read going up, down, left, or right. It is also stack-based, so information is stored and read in a stack. The commands in Grok are based off of the Vim editor. While they are not one-to-one matches, the goal is that those who know Vim can easily understand the functions of commands in Grok.
The Wordbox
A Grok program is laid out in the wordbox, which extends infinitely in all directions. The instruction pointer, or IP, moves through the wordbox, executing any instructions it encounters. The IP starts at coordinates (0,0), in the top-left of the program, and starts off moving to the right. The IP's direction can be changed, and if it goes off the edge of the wordbox, it wraps around to the other side.
Movement
The movement commands are h j k l
. These correspond to left
, down
, up
, right
, respectively. When the IP executes one of these commands, it will start moving in that direction, continuing until its direction is changed again or the program is terminated with the q
command.
The direction of the IP can also be changed conditionally with the { }
commands. They rotate the direction of the IP 90° counterclockwise or clockwise, respectively. This allows for conditional statements and conditional loops.
The Document and the Register
Grok is stack-based, so most commands do something to the stack, either writing to it or reading from it. The stack is usually referred to as the Document. Grok also has several commands for manipulating the register, which can be used to store a single value for later use or to store a value that you want constant access to. If a value is pushed to the register when a value is already stored there, the old value will be discarded.
As a general rule, the capitalized form of a command indicates register manipulation. For example, x
discards the top value on the Document, whereas X
discards the value in the register.
Insert Modes
To push characters and numbers more easily, Grok has an insert mode and a register insert mode (regin mode). Insert mode and regin mode are similar, but regin mode acts on the register instead of the document.
Insert Mode
The command to enter insert mode is i
. While in insert mode, any characters encountered will be pushed to the Document as their corresponding ASCII values. The program exits insert mode when the escape character `
is encountered. Characters are held until the escape character is encountered. They are then pushed to the stack in reverse order so that they can be easily outputted in the correct order. For example, iabcd`
will push d c b a
to the stack, so that the first outputted character is a
.
Alternatively, if the insert contains only numbers, a single integer of arbitrary length can be pushed. For example, i123`
will push the number 123 to the stack. However, if there are both characters and numbers, then the rules for characters apply. For example, i12ab`
will push b a 2 1
to the stack, so that the first outputted character is 1
.
Regin Mode
Regin mode is similar to insert mode, but with some key differences. The command to enter regin mode is I
. Since it acts on the register, it can only push a single value. This can be either a single character, or a single integer of arbitrary length. Because it can only push a single value, regin mode will auto-escape. After a character or number has been pushed, the next character will be executed as a command. For example, Iaq
will push the ASCII value of a
to the register, then q
terminates the program. Similarly, I123q
will push the number 123
to the register, then q
terminates the program.
Input / Output
Grok has several commands for input and output. The command to take input from the user is :
. When input is requested, the program will prompt with >
and wait for input. Input can also be piped into the interpreter beforehand:
$ echo input | ./PyGrok.py program.grok
Is functionally equivalent to:
$ ./PyGrok.py program.grok > input
Input works very similarly to insert mode. If the input is entirely numeric, it will be interpreted as a single integer of arbitrary length. If the input contains characters, all characters and numbers will be pushed in reverse order as their corresponding ASCII values.
Output comes in several different forms. The w
command pops a value from the Document and outputs it as a character. The z
command pops a value from the Document and outputs it as a number. Since characters are stored as ASCII values, the character a
could be outputted as a character or a number: w ‑> a
or z ‑> 97
. The capitalized forms of these commands, W
and Z
, will output a value from the register instead.
Errors
The following will cause errors in Grok:
- Attempting to divide by 0.
- Attempting to execute an invalid instruction.
- Overflows if the implementation does not support arbitrary-precision integers.
Regardless of the error, the error message displayed will be "You don't grok Grok." In the official PyGrok.py interpreter, the command line argument ‑e
, or ‑‑show‑errors
, will show a more detailed error message instead.
Instructions
- For clarity, capitalized commands are preceded by
↑ +
. - As a general rule, the capitalized form of a command indicates register manipulation.
Command | Function |
---|---|
h j k l |
Move IP left, down, up, right, respectively. |
x |
Pop the top value off the Document and discard. |
↑ + X |
Pop the value saved in the register and discard. |
d |
Pop a off the Document, then pop a values off the Document and discard.1d will discard the top value. 0d will push the top value to the register. |
y |
Pop a off the Document, then duplicate the a th value on the Document and push it to the register.The top value on the stack is the 0th value. |
↑ + Y |
Duplicate the top value from the Document to the register. |
p |
Pop the value saved in the register, then push it to the Document. |
↑ + P |
Duplicate the value saved in the register to the Document. |
i |
Enter insert mode. |
↑ + I |
Enter regin mode. |
` |
Escape. Exit insert mode and return to command mode. If used outside of insert mode, it acts as a trampoline. |
w |
Pop the top value off the Document and output it as a character. |
↑ + W |
Pop the value stored in the Register and output it as a character. |
z |
Pop the top value off the Document and output it as an integer. |
↑ + Z |
Pop the value stored in the Register and output it as an integer. |
q |
Stop execution. |
: |
Get input from the user and push it. |
{ |
Pop a off the Document. If a is 0, rotate IP direction left (counterclockwise) 90°.
|
} |
Pop a off the Document. If a is 0, rotate IP direction right (clockwise) 90°.
|
+ - |
Addition, Subtraction, Multiplication, Division, Modulo. Pop a and b off the Document, then do b <operator> a and push the result to the Document.
|
> |
Pop a and b off the Document. If b > a , push 1 to the Document, otherwise, push 0.
|
= |
Pop a and b off the Document. If b = a , push 1 to the Document, otherwise, push 0.
|
! |
Logical NOT. Pop a off the Document. If a is 0, push 1 to the Document. Otherwise, push 0.
|
0-9 |
Push the corresponding number to the Document. |
Examples
All examples are executed using the PyGrok.py interpreter.
Hello, world!
iHello world!`lY!}q kwph
$ ./PyGrok.py helloworld.grok Hello, world!
Cat program
:lY!}q kwph
$ ./PyGrok.py cat.grok > Hello, Waffles! Hello, Waffles!
Truth-machine
:Y}l1j qZhkzh
$ echo 0 | ./PyGrok.py truthmachine.grok 0 $ echo 1 | ./PyGrok.py truthmachine.grok 11111111111111111111111111...
Implementaions
Currently, the only implementation of Grok is the official PyGrok.py interpreter. PyGrok.py is also hosted online at pythonanywhere.com.