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.) |