Minimalist Joy language derivative.
Eric Bavier 446c7d9131 doc: Moar lolz. | 7 år sedan | |
---|---|---|
Makefile | 7 år sedan | |
README.md | 7 år sedan | |
build | 7 år sedan | |
mirth.c | 7 år sedan | |
prelude.mrth | 7 år sedan |
A minimalistic interpreter for a Joy-like esoteric language.
If you have a make
installed, simply type make
to build the
executable. Otherwise you can run the ./build
script. Then run
./mirth
.
Mirth programs consist of a sequences of ASCII characters and [
- and
]
-quoted sequences of characters (aka. "quotes").
Mirth passes intermediate computations on an implicit "data stack", much like Joy, Forth, and other stack-based languages. Operations may push values to the stack, pop values from the stack, reorder stack items, or a combination of the above.
Alphabetic characters in a program cause the ASCII codepoint of that character to be pushed to the top of the stack.
Digit characters in a program are recognized as such and cause the
corresponding digit to be pushed to the data stack. Consecutive
digits are treated as separate numbers. E.g. the input 123
causes
first the number 1 to be pushed onto the stack, followed by the number
2, then the number 3.
Most of the ASCII symbol characters are "primitive" operators that perform some action, perhaps consuming values from or producing values on the stack. Some of these operators are overloaded: the specific action they perform depends on whether the stack items they operate on are integers or quotes.
Whitespace is insignificant and ignored in Mirth programs.
The value at the Top Of the Stack is referred to as "TOS", and the value Second On the Stack is referred to as "SOS".
$
duplicates the TOS ("dup")>
duplicates the SOS and pushes it on top ("over")%
discards the TOS ("drop"/"pop")\
swaps the TOS and SOS ("swap")(
pushes a quoted copy of the contents of the data stack. ("stack"))
replaces the stack with the contents of the quoted TOS ("unstack")@
reorders stack values according to quoted indices at TOS ("shuffle")E.g.
13$
=> 1 3 3
13>
=> 1 3 1
13%
=> 1
13\
=> 3 1
13(
=> 1 3 [3 1]
hello[[world]])
=> [world]
helo[32110]@
=> o l l e h
The @
operator possibly needs some more explaining. It expects a
quote at TOS that contains zero-based character indices, where the
index 0 refers to the top of the stack and indices increase as you
head towards the bottom of the stack. The maximum index indicates the
extent of the shuffle operation, or how many stack items are dropped
from the stack. Those stack items are replaced with the indexed stack
items given in the list, where the front of the list becomes the TOS.
E.g. the classic "rot" operation from Forth could be expressed as
[201]@
, and $
is equivalent to [00]@
. The "nip" operation from
Forth could be expressed as [20]@
assuming there is a stack item at
index 2 to work with, but it could be better expressed as \%
.
Multi-digit integers must be formed on the stack using the primitive
arithmetic primitives +
, -
, *
, and /
applied to two integers.
E.g.
48*
=> 32
25*
=> 10
19+
=> 10
1356*$**+
=> 2701
Since there are many ways in which a single number can be represented in this way, Mirth encourages the programmer to express their own numeric individuality.
Note, however, that alphabetic character input causes the ASCII
codepoint of that character to be pushed to the stack, so one could
use those for inputing larger numbers if desired. E.g. d
leaves 100
on top of the stack, which may be more intuitive than 455**
,
depending on how comfortable you are with ASCII codepoints.
In Mirth true
is represented as the integer -1
, and false
as 0
.
<
pops TOS and SOS, pushes -1
if SOS is less than TOS, otherwise 0
=
pops TOS and SOS, pushes -1
if SOS is equal to TOS, otherwise 0
~
pops TOS, pushes the binary complement of TOS`
pushes -1
if TOS is a quote ("quote?")Some of the arithmetic and logic operators' behavior is overloaded when one of the operands is a quote:
+
conses SOS onto the front of TOS, if TOS is a quote ("cons")-
pops TOS, pushes the first element of TOS, then the rest, if TOS is a quote ("uncons")*
concatenates SOS and TOS, if TOS is a quote, assuming SOS is a quote ("concat")|
pops TOS, pushes the reverse of TOS, if TOS is a quote ("reverse")E.g.
h[ello]+
=>[hello]
[135][246]+
=>[[135]246]
[135]--
=>1 3 [5]
[0]-3\+
=>0 [3]
[hello][, world!]*
=>[hello, world!]
[12345]|
=>[54321]
The following operators provide for treating quotes as programs, they "execute" a quote from the stack in some way. A quote is executed by walking its contents from head to tail and executing each element in turn.
!
executes the TOS quote ("do")_
executes the TOS quote underneath SOS, i.e. SOS is temporarily
removed from the stack and returned after TOS is finished executing
("dip")?
execute TOS quote if SOS is non-zero ("do-if")E.g.
2[1+]!
=> 3
27[1+]_
=> 3 7
2[1+]$_!
=> 4
00=[7]?
=> 7
,
prints a quote as a flat sequence of characters, or prints the
single character at TOS..
prints TOS as a signed integer.^
pushes a single character read from standard input to the stackE.g.
hello,,,,,
=|olleh
[hello, world!],
=|hello, world!
[digit: ],^68*-.
=|digit: 3
[Y/n: ],^19+,Y=[[yes, of course],19+,]?
=|Y/n: Y
=|yes,of course
=|
Recall from the "Arithmetic" section that multi-digit integers cannot be formed on the stack without performing arithmetic. However, "integers" can be printed using a quote without limitation, of course, since they're just interpreted as characters:
[2049],
=|2049
There are 128 integer-indexed variables that may be used by Mirth programs.
:
Set variable TOS (an integer in [0,127]) to SOS. Discard both
from the stack. ("define");
Replace variable index at TOS with that variable's value. ("value")E.g.
37*f: 89+b: f;b;* 9b;+
=> 357 26
[[hello],48*,]g: g;!g;!g;! [!!!],
=|hello hello hello !!!
It may happen that :
encounters a quote at TOS. If this is the case
then it expects TOS to contain a single alphabetic character C
(i.e. in the set [a-zA-Z]) and expects SOS to also be a quote. It
then creates an "immediate" operator. If C is later encountered, its
quote is immediately executed, without needing to fetch and execute
(;!
). This allows one to define and use primitive-like operators
more concisely.
E.g.
[1+][i]:
[2*][d]:
0i 0ii 0iii 9iiii $d
=> 1 2 3 13 26
or to write self-documenting programs:
[[25*,]][h]:
[1.][n]: [2.][t]: [[red],][r]: [[blue],][b]:
[]$$$$$$$$ [o]:[e]:[w]:[d]:[l]:[u]:[f]:[i]:[s]:
one fish! two fish! red fish! blue fish!
=|1
2
red
blue
or to program in your preferred style while maintaining a formal outward interface:
[[25*,]]$[i]:[e]: [48*,][a]:
[[Name:],][z]: [%%%%0[]][m]: [%%][x]:
[^$ 19+=~[\+l]?][l]: [[]l%|][k]:
[[Hi],a][b]: [,[!],][y]:
hai! I can haz ur nam? kthxbye!
Mirth may have bugs. If you encounter any, please email the author.
Author: Eric Bavier bavier@member.fsf.org
License: GPL3+