OGEL
OGEL stands for Open Grid Execution Language (the fact that, backwards, it happens to spell the name of a certain famous manufacturer of coloured blocks (LEGO®) is a complete coincidence). It was designed by GreyKnight in August of 2006.
Elements of an OGEL program
An OGEL program consists of a grid-like arena, each cell of which can contain a stack of coloured blocks. Processors wander this grid, climbing up certain stacks and executing their contents as code.
The regular blocks are coloured black(K), red(R), yellow(Y), green(G), blue(B), and white(W). There is also a glass(s) block used as a separator.
Each processor has an associated stack somewhere on the arena on which it can keep data. Processors can also be instructed to address one other stack on the arena and manipulate it, although the commands for doing so are not quite as numerous. These "processor stacks" are not protected specially, and can be executed and manipulated just like any other.
Stacks as data
When reading an addressed stack, or a processor stack, the contents are interpreted as integers or the special nil value in the following manner. First, the number of glass (s) blocks which separate a number from the previous one is examined. If it is an odd number, a positive (or zero) number is being described; if an even number, a negative number (or nil) is present. The first item on a stack can optionally leave out its leading s blocks and start directly on a colour, in which case the value is assumed to be positive. Values are specified in base-6, with the following digits:
K | (black) | 0 |
R | (red) | 1 |
Y | (yellow) | 2 |
G | (green) | 3 |
B | (blue) | 4 |
W | (white) | 5 |
If you specify a negative number and a value of zero, the item will be interpreted as "nil". This is used as the boolean false value, and often used to signal errors. Any non-nil value (including 0) is boolean true.
For instance, a stack containing the values (1, 2, 12, -12, nil, 27) could be represented:
RsYsYKssYKssKsBG
The "top" of the stack
Values that are popped from a stack are taken from the bottom, and pushed values also appear on the bottom. Note that this is upside-down from the usual visualization of a stack. Unless otherwise specified, in this article the phrase "top of the stack" will refer to the point where push/popping takes place; that is, its physical bottom.
Processors
Each processor, upon arriving in an arena cell, will begin executing any stack found there from the bottom up; if there is no stack, it will idle in the cell until given further instructions. Upon reaching the top of the stack, or exiting it by some other means, it will pop an x and y offset from its processor stack and move by that amount to a new cell. If either value popped is nil then the processor will not move anywhere, but idle in the current cell. If an offset of <0, 0> was popped, the current stack is executed again from the bottom.
Niceness
Processors can have different "niceness" values (a priority), in which the lowest-niceness processor gets the highest share of actual execution time. Specifically, the niceness indicates the number of clock ticks the processor waits between steps. A niceness of 0 means that the processor executes a step every tick. All processors created at the start of the execution have the default niceness of 8.
Instructions
Instructions are sequences of coloured blocks separated by s blocks. The number of s blocks used to separate one instruction from the next is not normally significant (exceptions are noted below). Any value not recognized as a valid instruction will be treated as a "no-operation" instruction; however, when you wish to explicitly insert a no-op, you should use the instruction reserved for this use: (5)WWWWWK
Notation
Instructions are separated into tiers by the number of W blocks in their prefix. For clarity, the sequence WWWWK could be written as (4)WWWWK, or even shortened to (4)WK or (4)K. This is easier to read than long strings of Ws.
Tier-0 Instructions
mnemonic | sequence | action |
---|---|---|
push |
K | Skip next item in program and push it onto the processor stack |
jump |
R | Pop $n from proc stack and jump to $nth next program item ($n==1 => move to next as normal); jumps out if too few remaining |
add |
Y | Pop $a, $b from processor stack, then push $a+$b |
mul |
G | Pop $a, $b from processor stack, then push $a*$b |
ina |
B | Read in a single character from the user and push its Unicode value to the proc stack |
n/a | W | <prefix for tier 1> |
Tier-1 Instructions
mnemonic | sequence | action |
---|---|---|
pop |
(1)WK | Pop frame from processor stack |
jumpb |
(1)WR | Jump over next $n glass blocks; is equal to R if there are no extraneous s blocks |
sub |
(1)WY | Pop $a, $b from processor stack, then push $a-$b |
div |
(1)WG | Pop $a, $b from processor stack, then push $a/$b |
outa |
(1)WB | Print a single character from its popped Unicode value |
n/a | (1)WW | <prefix for tier 2> |
Tier-2 Instructions
mnemonic | sequence | action |
---|---|---|
dupl |
(2)WWK | Duplicate the item on the top of the proc stack |
jumpout |
(2)WWR | Jump out of this command stack prematurely |
not |
(2)WWY | Pop $a from proc stack and push the bitwise not $a |
mod |
(2)WWG | Pop $a, $b from processor stack, then push $a mod $b |
inn |
(2)WWB | Read in an integer from the user and push it |
n/a | (2)WWW | <prefix for tier 3> |
Tier-3 Instructions
mnemonic | sequence | action |
---|---|---|
roll |
(3)WWWK | Rotate the top $b stack elements ($a mod $b) times |
daddr |
(3)WWWR | Address the stack at co-ordinates <$a, $b> (default none, nil addresses none) |
or |
(3)WWWY | Pop $a, $b from processor stack, then push bitwise $a or $b |
and |
(3)WWWG | Pop $a, $b from processor stack, then push bitwise $a and $b |
outn |
(3)WWWB | Pop an integer and print it |
n/a | (3)WWWW | <prefix for tier 4> |
Tier-4 Instructions
mnemonic | sequence | action |
---|---|---|
dpush |
(4)WWWWK | Push a frame onto the addressed stack, popped from the proc stack. |
dpop |
(4)WWWWR | Pop a frame from the addressed stack and push it onto the proc stack. |
ddupl |
(4)WWWWY | Duplicate the top frame on the addressed stack |
droll |
(4)WWWWG | Roll the top $b stack elements ($a mod $b) times ($a,$b from proc stack) |
dcord |
(4)WWWWB | Push the addressed stack's co-ordinates onto the proc stack. |
n/a | (4)WWWWW | <prefix for tier 5> |
Tier-5 Instructions
mnemonic | sequence | action |
---|---|---|
morep |
(5)WWWWWK | Pop $a,$b from proc stack and push the boolean ($a>$b) (1 for true, nil for false) |
equalp |
(5)WWWWWR | Pop $a,$b from proc stack and push the boolean ($a==$b) (1 for true, nil for false) |
fork |
(5)WWWWWY | Fork the current processor. The new proc stack will be allocated in the first free cell after the parent's stack in the x-direction. The child's proc stack has a 0 pushed onto it; the parent's has the child's processor ID pushed (or nil on failure). |
kill |
(5)WWWWWG | Pop a value from the stack; if nil, destroys the processor but leaves the proc stack as data. If non-nil, also destroys the proc stack. |
system |
(5)WWWWWB | Pop $a, $n, then $n more items; execute system call $a with the $n arguments. See below for system call list. |
n/a | (5)WWWWWW | <prefix for tier 6> |
Tier-6 Instructions
mnemonic | sequence | action |
---|---|---|
nop |
(6)WWWWWWK | Reserved no-operation instruction |
n/a | (6)WWWWWWR | <reserved> |
n/a | (6)WWWWWWY | <reserved> |
n/a | (6)WWWWWWG | <reserved> |
n/a | (6)WWWWWWB | <reserved> |
n/a | (6)WWWWWWW | <reserved from here on> |
System Calls
For use with (5)WWWWWB. If too few arguments are specified, the remaining are set to nil. If too many, the excess are thrown away. On error, the call returns its usual number of arguments, but all set to nil.
Arguments after ';' in the argument lists shown below have default values and can be unspecified if you wish; unless otherwise stated, the default is 'nil'.
call number | number (base 6) | mnemonic | arguments | return | description |
---|---|---|---|---|---|
0 | K | EXIT | 1 ($code) | 0 | Stops all processors and terminates execution, returning $code in an appropriate manner. |
1 | R | NPROCS | 0 () | 1 | Pushes the number of processors currently alive. |
2 | Y | PID | 0 () | 1 | Pushes the processor ID of the calling processor. |
3 | G | PKILL | 2 ($pid; $s) | 1 | Kills processor #$pid; if $s, also destroys its stack. Pushes success (true/false) |
4 | B | TIME | 0 () | 1 | Pushes the number of seconds since the UNIX epoch (1970 Jan 1st, 00:00:00) |
5 | W | PROCSTAT | 1 ($pid) | 4 | Pushes $sy,$sx, $py,$px (positions of proc stack and processor for proc #$pid) |
6 | RK | PROCTELL | 5 ($pid,$px,$py; $sx,$sy) | 1 | Tells processor #$pid to go to <$px,$py> and use <$sx,$sy> as its proc stack. Default for <$sx,$sy> is current stack. Pushes success (true/false). |
7 | RR | HEIGHTB | 2 ($x, $y) | 1 | Push the height of the stack at <$x,$y> in blocks. |
8 | RY | HEIGHT | 2 ($x, $y) | 1 | Push the height of the stack at <$x,$y> in functional units (between 's' separators). |
9 | RG | GETNICE | 1 ($pid) | 1 | Pushes the "niceness" (number of clock ticks between execution steps) of #$pid. |
10 | RB | SETNICE | 2 ($pid, $nice) | 1 | Resets the "niceness" of #$pid (nil sets to the default of 8). Pushes new actual niceness, or nil on error. |
11 | RW | FOPEN | 4 ($nx,$ny, $mode; $flags) | 1 | Read the stack at <$nx,$ny> as a string pathname to open and push a file handle. $mode: {1=read, 2=write, 3=readwrite} $flags: {1=append, 2=truncate, 4=create, 8=binarymode, 16=xcreate} In read mode, flags defaults to 0; in write mode, 6; in readwrite, 4. With the xcreate flag, fails if file already exists. |
12 | YK | FOPENTEMP | 2 (;$mode, $flags) | 1 | Pushes a handle for a temporary file; $mode defaults to 3 (readwrite). The tempfile will be removed automatically after use. |
13 | YR | FCLOSE | 1 ($file) | 1 | Closes $file and pushes true on success. |
14 | YY | FSEEK | 3 ($file, $pos; $whence) | 1 | Moves pointer of $file to [$whence]+$pos. $whence defaults to '0' (start), and can also be '1' (current pos), or '2' (end of file). Pushes new location. |
15 | YG | FREAD | 4 ($file, $x,$y; $n) | 1 | Read $n (default: all) bytes and store them as a stack at <$x,$y>. Push amount read. |
16 | YB | FWRITE | 4 ($file, $x,$y; $n) | 1 | Write $n (default: all) bytes read from <$x,$y> and push success. |
17 | YW | FREADCH | 1 ($file) | 1 | Reads a single byte from $file and pushes it. |
18 | GK | FWRITECH | 2 ($file, $char) | 1 | Writes $char to file and pushes $char on success. |
19 | GR | FREADLINE | 4 ($file, $x,$y; $n) | 1 | As FREAD, but stops when it hits any line break (then skips past the break) |
20 | GY | FWRITELINE | 4 ($file, $x,$y; $n) | 2 | As FWRITE, but writes a line break afterwards. |
21 | GG | FLOCK | 2 ($file; $unlock) | 1 | Either lock or unlock the file (depending on $unlock) for access by this processor. Pushes success; if false, file is already locked. |
22 | GB | FFLUSH | 1 ($file) | 1 | For writeable files, matches the disk representation to that in memory. Push success. |
23 | GW | <reserved> | n/a | n/a | <reserved> |
24 | BK | <reserved> | n/a | n/a | <reserved> |
25 | BR | REVERSEB | 2 ($x, $y) | 1 | Reverses the stack at <$x, $y> by blocks and pushes numblocks on success. |
26 | BY | REVERSE | 2 ($x, $y) | 1 | Reverses the stack at <$x, $y> by units and pushes numunits on success. |
27 | BG | SLEEP | 1 ($secs) | 0 | Sleeps for at least $secs seconds. When there are many processors, may overshoot. |
28 | BB | EXECUTE | 2 ($x, $y) | 1 | Executes a string stored in stack <$x,$y> in the OS shell and pushes the return code. |
29 | BW | PEXECUTE | 4 ($x,$y, $ox,$oy) | 1 | As EXECUTE, but stores any command output at <$ox,$oy> |
30 | WK | GETENV | 4 ($x,$y, $ox,$oy) | 1 | Gets the value of an environment variable, pushes success. |
31 | WR | GETARG | 3 ($n, $x,$y) | 1 | Stores command-line argument $n at <$x,$y>, push success. If $n is nil, push number of arguments and store nothing. |
32 | WY | PPID | 0 () | 1 | Pushes the processor ID of the calling processor. |
33 | WG | <reserved> | n/a | n/a | <reserved> |
34 | WB | <reserved> | n/a | n/a | <reserved> |
35 | WW | <reserved> | n/a | n/a | <reserved> |
36 | RKK | EDITSTACK | 4 ($x,$y; $z,$v) | 1 | If $z nil, push length of stack. If $v nil, push blockvalue at $z position (0 is bottom-most block); else set $z position to $v blockvalue and return $v. Blockvalues are as for digits, and '6' represents an 's' block. Other blockvalues are erroneous. You can set the block just above the top one, but no higher. {0=black, 1=red, 2=yellow, 3=green, 4=blue, 5=white, 6=glass} |