Monky
- This is still a work in progress. It may be changed in the future.
Monky is yet another stack-based language developed over the course of a weekend by User:Menguinponky.
Overview
It draws inspiration from FORTH, FALSE and C, it also uses a data stack and reverse polish notation and is tailored for fast execution by a simple interpreter on a DIY 8-bit machine, while keeping the syntax somewhat readable.
- All values on the stack are 8-bit
- All keywords are single special characters
- All printable ASCII characters have a function
- Numeric literals are signed 8-bit integers covering
-128to+127 - Single characters and strings can also be pushed onto the stack
- Input tokens are separated by spaces
- Extra whitespaces and newline characters are ignored
- Stack underflow will terminate the program
- Named variables can be used through the letters
a-z - Functions can be defined and called using letters
A-Z - An additional 128 byte data array is available
Characteristics
Note that although most instructions in the table below have familiar equivalents in their predecessor languages, there are some important differences:
The comparison operations only consume the top item and leave the previous value on the stack, also the symbols for less < and greater > point to the mathematically correct direction, relative to the top value.
It is often necessary to compare a value to a range of other values, for example in a switch/case structure, keeping the previous value on the stack easily allows that without having to duplicate it for every comparison.
Neither the instruction to print the top value as an integer . nor the instruction to store the top value into a variable : consume the top value, but the instruction to print the top as char , does consume it. Chars are most likely to be printed and will therefor be popped from the stack while integers stay there for further calculation.
The logical value false is represented by 0 while true is nominally represented by -1, so that the ~ instruction can be used for logical inversion, though all non-zero values are interpreted as true.
The instruction character choices are supposed to make the symbols more intuitive to understand:
$ looks like the letter S that swap starts with
^ is above or over the other tokens
% shows two circles after duplication by dup
_ symbolizes the floor that we drop an item to
\ points back towards a value down in the stack to pick
@ symbolizes the rotation of the rot instruction
# is used to count the number of elements on the stack
Syntax
Stack effect notation, top of stack to the right:
stack before -- stack after execution (C syntax)
Example notation:
Input → Stack after execution ⇒ Output
| Op | Name | Stack effect | Meaning | Example |
|---|---|---|---|---|
n
|
push int
|
-- n
|
Push signed integer value onto stack | 1 → 1
|
c
|
push char
|
-- c
|
Push ASCII character onto stack | a → a
|
.
|
print int
|
n -- n
|
Print top of stack as signed integer | 3 . → 3 ⇒ 3
|
,
|
pop char
|
c --
|
Pop and print top of stack as ASCII character | a , → ⇒ a
|
'
|
get char
|
-- c
|
Get char from user input and push onto stack, 0 if none
|
' → c
|
_
|
drop
|
n --
|
Pop and discard top of stack | 2 3 _ → 2
|
+
|
add
|
n1 n2 -- n1+n2
|
Add two top items of stack | 1 2 + → 3
|
-
|
sub
|
n1 n2 -- n1-n2
|
Subtract top from previous item | 3 1 - → 2
|
*
|
mul
|
n1 n2 -- n1*n2
|
Multiply two top items | 2 3 * → 6
|
/
|
div
|
n1 n2 -- n1/n2
|
Integer divide previous item by top | 6 2 / → 3
|
%
|
dup
|
n -- n n
|
Duplicate top of stack | 3 % → 3 3
|
$
|
swap
|
n1 n2 -- n2 n1
|
Swap two top items | 1 2 $ → 2 1
|
^
|
over
|
n1 n2 -- n1 n2 n1
|
Copy previous item to top | 1 2 ^ → 1 2 1
|
@
|
rot
|
n1 n2 n3 -- n2 n3 n1
|
Rotate three top items to the left | 1 2 3 @ → 2 3 1
|
#
|
count
|
-- n
|
Count and push number of elements on stack | 4 5 6 # → 4 5 6 3
|
\
|
pick
|
n2 n1 i -- n2 n1 s[i]
|
Pick n-th element out of stack | 1 2 3 4 3 \ → 1
|
&
|
and
|
n1 n2 -- n1&n2
|
Bitwise AND two top items | 12 10 & → 8
|
|
|
or
|
n1 n2 -- n1|n2
|
Bitwise OR two top items | 12 10 | → 14
|
~
|
not
|
n -- ~n
|
Apply bitwise NOT to top item | 127 ~ → -128
|
=
|
equal
|
n1 n2 -- n1 n1==n2
|
Replace top by true if equal to previous, false if not
|
1 2 = → 1 0, 3 3 = → 3 -1
|
<
|
less
|
n1 n2 -- n1 n2<n1
|
Replace top by true if smaller than previous, false if not
|
1 2 < → 1 0, 2 1 < → 2 -1
|
>
|
greater
|
n1 n2 -- n1 n2>n1
|
Replace top by true if greater than previous, false if not
|
1 2 > → 1 -1, 2 1 > → 2 0
|
:
|
store
|
n i -- n
|
Store top value in variable a-z or array index -1..-128
|
4 a : → 4, 5 -10 : → 5
|
;
|
load
|
i -- v[i]
|
Load variable a-z or array index -1..-128 to top
|
a ; → 4, -10 ; → 5
|
"
|
string
|
-- 0 c..c
|
Push 0-terminated string onto stack in reverse order
|
"hi" → 0 105 104
|
The following instructions are unique to Monky and don't affect the stack directly (n -- n):
| Op | Name | Meaning | Example |
|---|---|---|---|
?
|
skip if true
|
Skip next instruction if top is true
|
0 ? % → 0 0 , 1 ? % → 1
|
!
|
skip if false
|
Skip next instruction if top is false
|
0 ! % → 0, 1 ! % → 1 1
|
[
|
loop start
|
Start of a loop, ] jumps to this symbol
|
[ a , ] ⇒ aaaaa...
|
]
|
loop end
|
End of a loop, jumps back to [ unless skipped
|
3 [ 1 - ! ] → 0
|
(
|
block start
|
Start of a block, jumps to ) unless skipped
|
3 ( 2 ) → 3, 0 ? ( 2 ) → 0
|
)
|
block end
|
End of a block, ( jumps here
|
1 ? ( 2 ) → 1 2
|
{
|
function start
|
Start definition of a function | { 1 + } I :
|
}
|
function end
|
End definition of a function | { 1 - } D :
|
Examples
Infinite loop
[ ]
Cat program
[ ' , ]
Looping counter
0 [ 1 + . ]
Truth-machine
' 48 - ? ( [ . ] ) .
Fibonacci sequence
0 . 1 . [ ^ ^ + . @ _ ]
Hello, world!
"hellorld" [ , ! ]
Comment
( "this is a comment" )
Other examples:
modulo(12,5) → 12 % 5 / 5 * - → 2
if(a==5){foo}else{bar} → a ; 5 = ? ( foo ) ! ( bar )
i=5; do{print(i--)}while(i) → 5 [ . 1 - ! ]
i=5; while(i){print(i—-)} → 5 [ ? ( . 1 - ] )
Note that blocks and loops are allowed to overlap, like in the last example above.
Interpreter
An interpreter is under development and can be found in a public GitHub repository: https://github.com/0xCAFEAFFE/Monky
Limitations
The language does not allow recursive function calls, this is by design because these structures are rarely indispensable in practical programs. The interpreter does currently not support nested loops or nested blocks but work is underway to implement that.