Getchl
Getchl is an esoteric shell designed for WalrusOS that uses getch() as its primary form of input. Every time a keystroke occurs, Getchl executes a command. This makes it an esoteric shell in that it uses irregular forms of user interaction, coupled with the esoteric programming language used (which is really just a standard stack-based golfing language).
Data Model
In one of my favorite data model families, the model behind Getchl is a both-sides-infinite tape of byte stacks with a scalar accumulator.
Terminology
| Term | Meaning |
|---|---|
| Stack | LIFO queuing mechanism |
| Queue | FIFO queuing mechanism |
| Tape | A right-infinite array with an index |
| Pop | Take the value off the top of the stack and return it |
| Push | Put a value on the stack |
| Accumulator | A scalar that holds a value |
| 0gnirts | A null-terminated string on the stack (alternatively, if no null terminator is present, the entire stack as a string) (first character of string at top of stack for technical reasons) |
| Mode | Alternative interpreter modes |
| Default mode | The standard interpreter mode |
| String mode | The mode where commands are ord()ed and pushed on the stack
|
| Block mode | The mode where commands are saved to a block instead of executed (used for evaluating groups of commands later) |
| Prime mode | The mode where commands are slightly different for control purposes |
| Safe mode | The mode where commands do not execute when the stack is too short, instead returning 0 |
All values are modulo 256 (or not, for a unicode implementation).
Command List
All commands are subject to change. Feel free to suggest such changes yourself.
| Hex | Ch | Name | Meaning |
|---|---|---|---|
| 20 | ' ' | NOP | Do absolutely nothing |
| 21 | ! | NOT | Push the logical inversion of a popped value |
| 22 | " | STR | Enter string mode |
| 23 | # | DEFINE | Pop a value, map it to the previous command (or block) |
| 24 | $ | DROP | Pop a value and discard it |
| 25 | % | MOD | Pop a, pop b, push b%a |
| 26 | % | MOD | Pop a, pop b, push b%a |
| 27 | ' | PRIME | Enter prime mode for the following character |
| 28 | ( | START BLOCK | Start forming a block |
| 29 | ) | END BLOCK | Terminate a block |
| 2A | * | MULT | Pop a, pop b, push b*a |
| 2B | + | ADD | Pop a, pop b, push b+a |
| 2C | , | INP | Get a single character as input and pop its ASCII value on the stack (fail if EOF) |
| 2D | - | SUB | Pop a, pop b, push b-a |
| 2E | . | Print the character whose ascii value is on the ToS | |
| 2F | / | DIV | Pop a, pop b, push b//a |
| 30 | 0 | ZERO | Push 0 |
| 31 | 1 | ONE | Push 1 |
| 32 | 2 | TWO | Push 2 |
| 33 | 3 | THREE | Push 3 |
| 34 | 4 | FOUR | Push 4 |
| 35 | 5 | FIVE | Push 5 |
| 36 | 6 | SIX | Push 6 |
| 37 | 7 | SEVEN | Push 7 |
| 38 | 8 | EIGHT | Push 8 |
| 39 | 9 | NINE | Push 9 |
| 3A | : | DUP | Pop a, push a, push a |
| 3B | ; | TERMINATE | End session |
| 3C | < | LT | Pop a, pop b, push 1 if b<a, else push 0 |
| 3D | = | EQ | Pop a, pop b, push 1 if b=a, else push 0 |
| 3E | > | GT | Pop a, pop b, push 1 if b>a, else push 0 |
| 3F | ? | IF | Pop a, pop b, pop c, if a!=0 push b, else push c. |
| 40 | @ | REDUCE | Repeat the previous instruction (or block) until it fails |
| 41 | A | A | Push 10 |
| 42 | B | B | Push 11 |
| 43 | C | C | Push 12 |
| 44 | D | D | Push 13 |
| 45 | E | E | Push 14 |
| 46 | F | F | Push 15 |
| 47 | G | GLOBAL | Create a variable (pop v, pop 0gnirts name, map name to v) |
| 48 | H | ||
| 49 | I | INVERT | Invert the stack
st2 = Stack()
while len(stack) > 0:
st2.push(st.pop())
st = st2
|
| 4A | J | TAPE RELATIVE JUMP | Pop n, go n-127 cells to the left on the tape |
| 4B | K | ||
| 4C | L | LEFT | Go left on the tape |
| 4D | M | MAXIMIZE | Pop a, set maximum stack size to a (pushes fail when len(stack) = stack.max) (extraneous elements dropped) (0 means no bound) |
| 4E | N | ||
| 4F | O | ||
| 50 | P | ||
| 51 | Q | QUEUE | Toggle queuing mode (all PUSHes become ENQUEUEs, all POPs become DEQUEUEs) |
| 52 | R | RIGHT | Go right on the tape |
| 53 | S | ||
| 54 | T | ||
| 55 | U | ||
| 56 | V | ||
| 57 | W | ||
| 58 | X | ||
| 59 | Y | ||
| 5A | Z | ||
| 5B | [ | ROT | Pop a, pop b, pop c, push a, push c, push b |
| 5C | SWAP | Pop a, pop b, push a, push b | |
| 5D | ] | ROTCC | Pop a, pop b, pop c, push b, push a, push c |
| 5E | ^ | ACCUMULATE | Pop a and put it in the accumulator |
| 5F | _ | DECCUMULATE | Push value in the accumulator |
| 60 | ` | APPLY/ EVAL | Pop a value and evaluate it as ASCII |
| 61 | a | ||
| 62 | b | ||
| 63 | c | ||
| 64 | d | DIR | Change the current working directory (pop a 0gnirts s, cd to s) |
| 65 | e | ||
| 66 | f | FIND | Pop tf, Repeatedly pop a until a==tf, push a |
| 67 | g | GET | Inverse of G: Pop a 0gnirts, push the global with that name |
| 68 | h | ||
| 69 | i | IDENTITY | Pop a value and push it (NOP normally, but equivalent to ROLL in queueing mode) |
| 6A | j | JUMP | Pop a 0gnirts, jump back to that location and reexecute to the current point |
| 6B | k | ||
| 6C | l | LABEL | Get a 0gnirts, label this location as a jumpback location |
| 6D | m | ||
| 6E | n | ||
| 6F | o | OPEN | Pop a, get 0gnirts s from the stack, open the file s and associate it with value a |
| 70 | p | ||
| 71 | q | ||
| 72 | r | READ | Pop a, read the content of the file associated with a |
| 73 | s | REPLACE | Pop three strings off the stack, replace s[1] with s[2] in s[0], push s[0] onto the stack |
| 74 | t | ||
| 75 | u | ||
| 76 | v | ||
| 77 | w | WRITE | Pop a, pop 0gnirts s, write s to the file associated with a |
| 78 | x | ||
| 79 | y | ||
| 7A | z | ||
| 7B | { | COMMENT | Stop executing commands (??? do I need this for a shell?) |
| 7C | OR | a | |
| 7D | } | DECOMMENT | Resume executing commands |
| 7E | ~ | SAFE | Toggle safemode |
Prime Mode Commands
Prime mode is an interpreter mode where commands are executed with alternative meanings. Unless otherwise specified, the interpreter returns to default mode after execution.
| Character | Name | Meaning |
|---|---|---|
| '@ | CONDITIONAL REDUCE | Pop value, negate it, execute previous command (or block) until a certain type of failure, fail if it fails on another failure (complicated, I know) |
| '? | CONDITIONAL EXECUTE | Pop a, execute the previous instruction (or block) if a != 0 |
| '; | FAIL | Pop a value and fail with its negated value |
| '` | RUN | Pop a value and execute the function defined to it |
| '( | CONTINUED PRIME | Enter continued prime mode (terminates on \)). All commands are interpreted as prime (e.g. '(abc) is equivalent to 'a'b'c). |
| '' | DOUBLE PRIME | Enter double-prime mode (currently does nothing) |
| 'G | GLOBAL STRING | Pop a 0gnirts name, pop a 0gnirts s, map name to string s |
| 'g | GET STRING | Pop a 0gnirts, push the 0gnirts it's mapped to |
| 'L | RELATIVE LEFT JUMP | Pop n, go n cells to the left on the tape |
| 'R | RELATIVE RIGHT JUMP | Pop n, go n cells to the right on the tape |
| '| | XOR | Pop a, pop b, push b^a |
Failure Codes
Some commands can return failure codes when executed under certain conditions. Failure codes do not terminate the script. All failure codes are negative.
| Value | Meaning |
|---|---|
| -1 | Not enough values on stack |
| -2 | Attempted to push onto full stack |
| -3 | Divide or modulo by 0 |
| -4 | No previous command (start of script or block) |
| -5 | No input character |
| -6 | Attempt to print null character |
| -7 | Invalid varname |
| -8 | Invalid filename |
| -9 | Invalid label |
Useful Constructs and Mnemonics
| Construct | Meaning |
|---|---|
<op>@ |
Where op is any operator (+, -, *, /, %, &, |, '|), reduce the stack with that operation (+ sums the stack, * multiplies it, etc) |
,@ |
Get an input string, terminated by EOF |
.@ |
Print a 0gnirts |
$@ |
Clear the stack |
`@ |
Eval a 0gnirts |
&! |
NAND |
|! |
NOR |
'|! |
XNOR |
<n>:@ |
Fill the remainder of the stack with value n (exclude n for existing ToS) (Make sure the stack has a max, or it will hang forever) |
<n>(<coms>1-0\/$)@ [I think this is right] |
Execute coms n times (Push n on stack, then execute coms and push 1 and subtract 1 from n, push 1, swap, and divide it by n and drop. This means it fails when n is equal to 0, thus terminating the loop) (note that coms must not change the stack, or at least must bury their values under the values.) |