Minimalist Joy language derivative.

Eric Bavier 446c7d9131 doc: Moar lolz. 7 éve
Makefile 6704819bba Initial commit 7 éve
README.md 446c7d9131 doc: Moar lolz. 7 éve
build 0300fb70b7 Add simple build script. 7 éve
mirth.c 47cc2b9eef Retain whitespace inside quotes. 7 éve
prelude.mrth 6704819bba Initial commit 7 éve

README.md

Mirth

A minimalistic interpreter for a Joy-like esoteric language.

Running

If you have a make installed, simply type make to build the executable. Otherwise you can run the ./build script. Then run ./mirth.

Programming in 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.

Stack operators

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 \%.

Arithmetic

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.

Logic and Control Operators

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?")

Quote manipulation

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

Input and Output

  • , 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 stack

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

Variables

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!

Limitations and Future Work

  • Currently Mirth has no garbage collection. Long running programs that use a lot of quotes and quote-manipulating operators may exhaust Mirth's fixed-size cons-pool.

Mirth may have bugs. If you encounter any, please email the author.


Author: Eric Bavier bavier@member.fsf.org

License: GPL3+