International Phonetic Esoteric Language
The International Phonetic Esoteric Language, abbreviated to IPEL, is a stack-based esoteric programming language by User:Bigyihsuan based on the idea of using the Wikipedia:International Phonetic Alphabet (IPA) as the primary instruction set. Its interpreter can be found here
Overview
IPEL uses 2 stacks to store values, named the unvoiced
and voiced
stacks, as well as a general-use register. There is a pointer to the current stack that gets switched with a set of instructions, further detailed below.
An additional execution stack is used by the interpreter for loops and control flow.
IPEL has three types: numbers, strings, and lists. Numbers represent both integers and floats and act as such. Strings are chains of characters stored as a single value. Lists are a container type that can contain any combination of the three types.
IPEL has a large instruction set that consists solely of single-character strings taken from the IPA.
IPEL also has a labeling system that allows for arbitrary jump points. There is a function system as well that supports recursion.
The Three Stacks
The three stacks consist of 2 data stacks and 1 execution stack. The data stacks, named "Unvoiced" and "Voiced", are directly worked on by most instructions. The current data stack, as well as which one it is currently, can be changed by some instructions as detailed below.
The execution stack has only the top element exposed by certain instructions. It is used for both storing loop index counters, as well as points for execution to return to when using loops and functions.
The Register
A general-use register is available. It holds a single value that is set by an instruction, gotten by a different instruction.
It is colloquially called the w
egister.
Character | Stack Effect | Mnemonic | Description |
---|---|---|---|
w |
(ele -- ) |
SETREG | Pops a value off the stack and sets the register to it. |
ʍ |
( -- ele) |
GETREG | Pushes a copy of the register onto the stack. |
Types
The three types when encountered by the interpreter are pushed onto the currently selected stack.
Code | Type | Explanation |
---|---|---|
0-9 |
Number | Single digit. |
{...} |
Number | Number with more than 1 digit, or a float. |
"..." |
String | String |
[...] |
List | List elements separated by periods .
|
Numbers
Numbers represent both integers and floats. Numbers are defined in one of two ways: digit form and multidigit form. The digit form is any digit in 0-9A-Za-z
. The multidigit form consists of a whole number, then an optional decimal point with fractional part. They are surrounded by curly braces {}
. Floats and negative numbers can only be declared using the multidigit form.
If you use the multi-digit form containing A-Za-z
, the number is interpreted as a base-36 integer.
Examples
7 ( -- 7) 78 ( -- 7 8) {123} ( -- 123) {1.23} ( -- 1.23) 1{3.3}0 ( -- 1 3.3 0) {3.5} ( -- 3.5) {abc} ( -- 13368)
Strings
Strings are a sequence of characters. They are delimited by double quotes "..."
Strings can be considered a "pseudo-list" of integers, with each integer representing the ASCII/Unicode value. This lets it be treated like a list with list-manipulating instructions.
Escape sequences are allowed for strings; they can be one of the following subset of the Python escape sequences:
Escape Sequence | Meaning |
---|---|
\newline |
Backslash and newline ignored |
\\ |
Backslash (\) |
\' |
Single quote (') |
\" |
Double quote (") |
\a |
ASCII Bell (BEL) |
\b |
ASCII Backspace (BS) |
\f |
ASCII Formfeed (FF) |
\n |
ASCII Linefeed (LF) |
\r |
ASCII Carriage Return (CR) |
\t |
ASCII Horizontal Tab (TAB) |
\v |
ASCII Vertical Tab (VT) |
Examples
"abc" ( -- "abc") "a""b""c" ( -- "a" "b" "c") "" ( -- "" ) "a \ b" ( -- "a b") "\n" ( -- "\n") "\"<>" ( -- "\"<>") "'hello'" (-- "'hello'")
Lists
Lists are a type that stores other types, specifically any combination of numbers, strings, or lists. They are delimited by square brackets []
.
List elements are separated by periods .
. Lists can be nested inside each other by creating a list inside a list.
Examples
[] (empty list) [1.2.3] [{1.2}."string".3] [["nested"].["list".["in list"]]."it is"]
Type Truthiness
IPEL primarily implements the concept of booleans by using numbers: non-zero is truthy, and zero is falsy. In the same vein, strings and lists are also truthy and falsy; empty strings and lists are falsy.
Comments
Comments are modelled after Forth: text surrounded by parentheses (...)
are comments. Just like Forth comments, you can't next comments; (com(com)ment)
would terminate the comment at the first )
.
Examples
(this is a comment) (This is a comment (not nested) (comment with (a newline and tab)
Labels, Jump, and Skip
Labels are characters representing the label name surrounded by pipes |...|
. These are used in conjunction with the goto instruction ɔ
. When a label is placed after ʟ
, execution will jump to the label, then continue execution.
The skip instruction ʌ
pops the stack, checks for truthiness, and skips the next instruction if it is truthy. This allows for conditional jumps by placing instructions to check a condition before the skip, and jumping if the condition is falsey.
Code | Stack Effect | Description |
---|---|---|
|label| |
( -- ) |
Defines a label. |
ɔ|label| |
( -- ) |
Jump to the specified label. |
ʌ |
(con -- ) |
Pop the stack. If con is truthy, skip the next instruction.
|
Functions
Functions are possible in IPEL by doing the following:
<name>/code\ (function definition) <name> (function call)
Function bodies can contain any code at all: values, instructions, function calls, labels, anything. The ending symbol for a function boundary \
for the interpreter does nothing when execution did not come from a function. Expect undefined behavior or errors if you jump into a function body from a different function, such as <f>/abc|l|def\ <g>/ʟ|l|\
.
Recursion is possible by calling the function from within itself: <f>/code <f> code\
. It is up to you to set base cases.
For-Loops
For loops are similar to Forth DO-LOOPs. The general structure is as follows:
(value: end start -- ) (exec: -- end start) ɑ (code) ɒ
When ɑ
is encountered, 2 numbers are popped from the current value stack and pushed onto the execution stack. When ɒ
is encountered, it checks the execution stack. If index < end
, jump to the associated ɑ
.
index
is manipulated by the 2 instructions e
and ø
. e
pushes a copy of index
onto the current value stack. ø
pops a value from the current value stack and sets index
to that value. This is the same with the limit
with æ
and œ
, respectively.
Note that, unlike Forth, ɒ
does nothing with index
other than compare it against end
.
There is also the ɛ
instruction, which clears the execution stack of index
and end
, and exits the loop.
Character | Stack Effect | Mnemonic | Description |
---|---|---|---|
ɑ |
(end start -- ) |
FOR | Pops 2 values for index bounds. Loop jumps back to here if index < end .
|
ɒ |
( -- ) |
LOOP | If index < limit , jump to associated For. Else, continue.
|
e |
( -- index) |
GETIDX | Pushes the current loop's index. NOP if not in a loop. |
ø |
(index -- ) |
SETIDX | Sets the current loop's index to index .
|
æ |
( -- limit) |
GETLIM | Pushes the current loop's limit. NOP if not in a loop. |
œ |
(limit -- ) |
SETLIM | Sets the current loop's limit to limit .
|
ɛ |
( -- ) |
EXIT | Discards the current loop's data from the loop stack, and exits the loop. NOP if not in a loop. |
A note on GETIDX, SETIDX, GETLIM, SETLIM
As of interpreter version v1.4.0, GETIDX, SETIDX, GETLIM, and SETLIM access the execution stack directly and run if and only if there is a valid value for it to get or set. The *IDX instructions use the top value, while the *LIM use the 2nd to top.
Because both loops and function calls use the same execution, it's possible to change where a running function will return to using *IDX and *LIM.
<f>/"Yes"o e2sø\ <f> "No"o "Skipped no"o (Will print "Yes" then "Skipped no". Note that "No"o counts as 2 instructions.)
Instructions
Bilabials: Voicings
Bilabial consonants handle the selection of the current stack.
Character | Stack Effect | Mnemonic | Comment |
---|---|---|---|
ɸ
|
- | UNVOICED | Sets the voicing to Unvoiced .
|
β
|
- | VOICED | Sets the voicing to Voiced .
|
ɓ
|
( -- voicing)
|
VOICING | Pushes the current voicing. 0 for unvoiced, 1 for voiced.
|
Plosives: Stack Operations
Plosives modify the stack.
Character | Stack Effect | Mnemnomic | Comment |
---|---|---|---|
p
|
(a -- )
|
POP | Pop and discard the top element of the stack. |
b
|
(a -- a a)
|
DUP | Duplicate the top element of the stack. |
t
|
( -- size)
|
SIZE | Push the size of the stack. |
d
|
(a b -- b a)
|
SWAP | Swap the first and second elements of the stack. |
ʈ
|
(c b a -- a c b)
|
RCW | Rotate the top 3 elements clockwise (upwards). |
ɖ
|
(c b a -- b a c)
|
RCC | Rotate the top 3 elements counterclockwise (downwards). |
c
|
(d b a c -- d c b a)
|
SORT | Sort the stack. Numbers before Strings before Lists. Order of lists in the stack is preserved. Lower values on top. |
ɟ
|
(a b c d -- d c b a)
|
REV | Reverses the stack. |
k
|
A(a -- ) B( -- a)
|
GIVE | Pop the top of the current stack and push it onto the other one. |
g
|
A( -- a) B(a -- )
|
TAKE | Pop the top of the other stack and push it onto the current one. |
q
|
(a b -- a b a)
|
OVER | Push the 2nd element from the top of the stack. |
Central Vowels: Comparisons and Logical Operators
Approximates and laterals represent comparisons. For all instructions, 1
is pushed if true, and 0
if false.
ASCII/Unicode order is used for strings. Empty strings are first, followed by shorter stings.
Comparing lists does not work except for the ə
"Equal to" operator, where it will check for equality. The interpreter will NOP the instruction if it isn't the case
Character | Stack Effect | Mnemnomic | Comment |
---|---|---|---|
ɨ
|
(a b -- a>b)
|
GT | Greater than |
ʉ
|
(a b -- a>=b)
|
GE | Greater than or equal to |
ə
|
(a b -- a==b)
|
EQ | Equal to |
ɘ
|
(a b -- a<b)
|
LT | Less than |
ɵ
|
(a b -- a<=b)
|
LE | Less than or equal to |
ɜ
|
(a b -- a and b)
|
LAND | Logical AND |
ɞ
|
(a b -- a or b)
|
LOR | Logical OR |
ɐ
|
(a -- not a)
|
LNOT | Logical NOT |
Frontal Fricatives, Taps/Flaps, Trills: Mathematics
Fricatives, taps, flaps, and trills represent mathematical instructions.
These only apply to numbers. Otherwise, the interpreter will NOP the instruction.
Character | Stack Effect | Mnemnomic | Comment |
---|---|---|---|
s
|
(a b -- a+b)
|
ADD | Addition |
z
|
(a b -- a-b)
|
SUB | Subtraction |
f
|
(a b -- a*b)
|
MULT | Multiplication |
v
|
(a b -- a/b)
|
DIV | Division; will return 0 if b == 0 . Always returns a float.
|
ⱱ
|
(a b -- a%b)
|
MOD | Modulo (Labiodental Tap ⱱ) |
ʃ
|
(a b -- a**b)
|
EXP | Exponent; Base a , exponent b
|
ʒ
|
(a b -- log(a, b))
|
LOG | Logarithm; Base a , exponent b
|
θ
|
(a b -- a>>b)
|
RSH | Bit shift a to the right b bits
|
ð
|
(a b -- a<<b)
|
LSH | Bit shift a to the left b bits
|
ʂ
|
(a b -- a&b)
|
BAND | Bitwise AND |
ʐ
|
(a b -- a|b)
|
BOR | Bitwise OR |
r
|
(a -- !a)
|
BNOT | Bitwise NOT |
ɾ
|
(a -- -a)
|
INV | Inverts the sign of a .
|
ɽ
|
(a -- ceil(a))
|
CEIL | Rounds a to the largest integer
|
ʙ
|
(a -- floor(a))
|
FLOOR | Rounds a to the smallest integer
|
ɬ
|
(a b -- max)
|
MIN | Minimum |
ɮ
|
(a b -- min)
|
MAX | Maximum |
Back Fricatives, Taps/Flaps, Trills: List and String operations
Back fricatives, taps, flaps, and trills represent operations on lists. String operations are also in this section.
Character | Stack Effect | Mnemnomic | Comment |
---|---|---|---|
x
|
(abc def -- abcdef)
|
CAT | Concatenation. Implicitly casts its arguments into strings, then lists if they are not lists. |
ɣ
|
(a ... z n -- list)
|
NCAT | Concatenates the next n elements popped off the stack into a list of length n . Will NOP if n is not a number and does ceil(n) if it is.
|
ħ
|
(a -- a n)
|
LEN | List length. Pushes the length of the element peeked. Casts a to a list to get its length. a 's type is retained.
|
ʀ
|
(list -- a b ...)
|
LSPLIT | Splits a list into its individual elements. Implicitly casts list to a list.
|
h
|
(list n -- list e)
|
GET | Returns the element e at n , 0-indexed. Will NOP if n is not a number and does ceil(n) if it is
|
χ
|
(num -- str)
|
CHR | Converts a number to a single-character string, based on its ASCII/Unicode value. Will NOP if num is not a number, and ceil(num) if it is.
|
ʁ
|
(str -- n1 n2 n3)
|
SSPLIT | Converts a string to a list of integers representing their ord() values. Will NOP if str is not a list of single-character strings or a string.
|
ʕ
|
(list -- str)
|
LTOSTR | Converts a list to a string. |
ʔ
|
(list ele -- list in?)
|
IN? | Peeking at a list and consuming an element, returns if the list contains that element. |
IO
Input and output is handled by the frontal closed vowels and the back central vowels.
Character | Stack Effect | Mnemnomic | Comment |
---|---|---|---|
i |
( -- str) |
LINE | Pushes a line from STDIN as a single string. |
y |
( -- str str str) |
WORD | Pushes a line from STDIN as multiple strings, separated by whitespace. |
ɪ |
( -- ele) |
DATA | Pushes an IPEL value onto the stack. Can push numbers, strings, and lists. Defaults to pushing strings if no valid numbers or lists are found. |
o |
(ele -- ) |
Pops and outputs to STDOUT with trailing newline. | |
ɤ |
(ele -- ) |
LPRINT | Pops and outputs to STDOUT. Will cast lists to strings. |
u |
(ele -- ) |
CPRINT | Pops and outputs to STDOUT, with no trailing characters. |
ɯ |
(ele trail -- ) |
TPRINT | Pops and outputs ele to STDOUT with a trailing string trail .
|
Examples
Hello, World!
"Hello, World!"o
Cat
io
Factorial
The function expects a number n
on the stack and leaves n!
.
<factorial>/b1əɐʌɔ|end||loop|b1zb1əʌɔ|loop||mult|ft1əʌʟ|mult||end|\
Fibonacci
The function expects a number n
on the stack and leaves the n
-th Fibonacci number. Recursive implementation.
<fib>/b1ɨʌɔ|end|1zb1z<fib>d<fib>s|end|\