MoreMathRPN
Note: unless otherwise specified, assume all "or" is the exclusive or.
MoreMathRPN (abbreviated MMRPN) is a stack based imperative language created in 2023, create by Calculus is fun (talk).
Originally for simple linear algebra, it has since grown to be turing complete. It is inspired by FALSE and its relatives, whilst also being more human friendly.
MMRPN is line independent, without labels or line numbers, and has no variable scoping.
Commands
Each line must have only one command or comment.
Literals
This language has rational and string literals, there are 4 ways to input a Rational:
- Integers e.g. 10
- Ratio of 2 integers e.g. 3/5
- Terminating decimal e.g. 3.894
- Recurring decimal e.g. 1.1[32] -or- 0.[3]
You can prepend a hyphen to negate the value, and periods can be substituted with commas.
String literals can only be in an instruction's parameters,
they are double quoted strings that allow spaces; most literal UTF-8 characters; along with \\, \", and \n escape characters.
Instructions
There are 2 types of input a command has, Parameters and Arguments. Parameters are integers placed after the command and deliminated by spaces. Arguments are from the stack and can be rational (R) or matrices (M), if needed; variables will be denoted [top] a, b, c, ... [bottom]
Standard operations
Operation symbol/name | Description / Formula | Parameters | Arguments |
---|---|---|---|
" | Comment (see examples below) | None | None |
+ | Addition | None | 2 R or 2 M |
- | Subtraction (b - a) | None | 2 R |
* | Multiplication | None | 2 R, 2 M, or 1 R and 1 M |
/ | Division (b / a) | None | 2 R |
% | Remainder (b % a) | None | 2 R |
int | Integer part | None | 1 R |
floor | Round down | None | 1 R |
ceil | Round up | None | 1 R |
den | Denominator | None | 1 R |
gcd | Greatest common divisor | None | 2 R |
lcm | Least common multiple | None | 2 R |
step | Greater than zero (a > 0 → 1, a <= 0 → 0) | None | 1 R |
compare | Comparison (b - a < 0 → -1, a == b → 0, b - a > 0 → 1) | None | 2 R |
# | Stack height | None | None |
>> | Copy | Depth | None |
Stack manipulation
Operation symbol/name | Description / Formula | Parameters | Arguments |
---|---|---|---|
-> | Pull | Depth | None |
<- | Push | Depth | None |
del | Delete | Depth | None |
Matrices
Operation symbol/name | Description / Formula | Parameters | Arguments |
---|---|---|---|
m | Matrix | Columns, rows | columns * row R |
addRow | Row addition | Row from, row to | 1 R and 1 M |
scaleRow | Row scaling | Row | 1 R and 1 M |
swapRows | Row swapping | Row from, row to | 1 M |
T | Transpose | None | 1 M |
inv | Inverse | None | 1 R or 1 M |
ref | Row echelon form | None | 1 M |
ind | Value at index | Column, row | 1 M |
rip | Rip last column | None | 1 M |
flip | Flip across rows | None | 1 M |
dim | Dimensions | None | 1 M |
dot | Dot product | None | 2 M |
hadamard | Hadamard product | None | 2 M |
kronecker | Kronecker product | None | 2 M |
outer | Outer product | None | 2 M |
Loops
Operation symbol/name | Description / Formula | Parameters | Arguments |
---|---|---|---|
jmp | Jump to | Offset | None |
repeat | Repeat loop | End Count | None |
next | Next iteration | None | None |
>>> | Iteration number | Loop Depth | None |
break | Break out of current loop | None | None |
leap | Break out of current loop, then jump | Offset | None |
Variables
Variable names can not have spaces nor start with ".
Operation symbol/name | Description / Formula | Parameters | Arguments |
---|---|---|---|
hold | Store top of stack as variable | Name | 1 R or 1 M |
place | Place copy of variable to stack | Name | None |
lose | Remove a variable | Name | None |
exists | Exists (does variable exist? yes → 1, no → 0) | Name | None |
IO & strings
Operation symbol/name | Description / Formula | Parameters | Arguments |
---|---|---|---|
chars | Converts a string's UTF-8 code points in reverse order (end is at the bottom), then tops it with the string's length. | String | None |
inputR | Prompts the user to input a number in a valid format as described above, if invalid, the program will ask again. The prompt message is an optional parameter, and not giving it should default to a generic message. | Prompt (optional) | None |
inputS | Prompts the user to input a string, converts the response's UTF-8 code points in reverse order (end is at the bottom), then tops it with the string's length The prompt message is an optional parameter, and not giving it should default to a generic message. | Prompt (optional) | None |
outputC | Outputs a single character whose code point is the parameter | Code point | None |
outputS | Outputs a string | String | None |
outputV | Pops and outputs a rational or matrix, format depends on implementation | None | 1 R or 1 M |
Dynamic parameters
You might be thinking how if-else statements are going to happen in this language; fortunately, parameters can be controlled by the program, these get rounded towards 0 if the rational is not an integer.
- ]n grabs the nth item from the top of the stack
- [n grabs the nth item from the bottom of the stack
- $name uses a variable
Behavior
Certain commands have specific actions given interesting conditions, here's a list of those conditions.
Repeat without next
If a repeat
is missing a corresponding next
, It is inferred to be at the end of the program, but the loop won't repeat. Either break
or leap
will end the program if run in an incomplete repeat
statement.
repeat 10 3 5 break 5 1 "next statement inferred here!
Nested loops
repeat ... next
blocks can be nested, helpful for simplifying advanced patterns
repeat 10 repeat 10 "outer >>> 1 "inner >>> 0 + 2 - next next m 10 10
Out of the loop
calling break
or leap
outside the active loop results in an error.
It is recommend to keep looping code in the repeat...next
block.
repeat 10 jmp 2 next "Error! break
Leaping back
leap
with a negative parameter are treated like breaks, this is to dissuade the act of jumping into the repeat you just left.
"You would expect this to be an infinite loop, but it isn't. repeat 1 "I'm now a break! leap -2 next
Zero jmp
When jmp
is given a parameter of 0, jmp
does nothing, this is so you don't have to write 1 +
every time you use it. See examples below.
Examples
More examples can be found here
Creating conditions
Conditions are often created via the step
or compare
instructions, then by evaluating an polynomial function and feeding that into a jmp
, complex branching behavior can appear.
5 0 "enter loop 5 -> 1 del 0 "more code here... 1 - >> 0 step "adjust this when you add instructions above! -7 * "if jmp is given a parameter of 0, it does nothing jmp ]0 del 0 "exit loop
You can also use repeat
with a parameter of 1 or 0, to run or skip a block of lines.
"0 or 1 0 repeat ]0 1 2 3 4 "dummy 1 next del 0
Fibonnaci
This program repeatedly adds the previous 2 numbers forever
0 1 >> 1 >> 1 + jmp -3
We can use the repeat instruction to limit the repetitions
0 1 "repeat 50 times... repeat 50 "indentation of code is optional, but preferred >> 1 >> 1 + next
Factorial
Calculating the factorial is also easy
"argument 5 1 repeat ]1 >>> 0 * next del 1 "120 should be alone
Coefficients of a cubic
Using the matrix commands, one can solve a linear system quickly.
"degree + 1 repeat 4 1 >>> 0 1 - "degree repeat 3 >> 1 >> 1 * -> 1 next del 0 m 1 4 next "degree repeat 3 aug next T flip inv "f(0) 0 "f(1) 1 "f(2) 4 "f(3) -13 m 1 4 * "x^3, x^2, x^1, x^0
Cat
Takes the input and returns it; Unless you send the empty string, then it terminates.
inputS hold len step 3 * jmp ]0 del 0 jmp 7 del 0 repeat $len outputC ]0 del 0 next jmp -13
99 bottles of beer
Use the new IO commands and get very hammered.
99 repeat 98 >> 0 >> 0 1 - >> 0 <- 3 <- 3 outputV outputS " bottles of beer on the wall,\n" outputV outputS " bottles of beer.\nTake one down pass it around,\n" outputV outputS " bottles of beer on the wall.\n" next del 0 1 1 outputV outputS " bottles of beer on the wall,\n" outputV outputS " bottles of beer.\nTake one down pass it around,\n" outputS "Oops, we ran out of beer!"
Fractran interpreter
It's fitting that a language based on rationals can run Fractran. Here's John Conway's prime program.
"program 17/91 78/85 19/51 23/38 29/33 77/29 95/23 77/19 1/17 11/13 13/11 15/14 15/2 55/1 # hold len del 0 m $len 1 "input 2 "loop -> 1 >> 1 repeat $len "read fraction >>> 0 1 - -> 2 ind ]1 0 -> 1 <- 3 del 1 "check validity >> 1 * >> 0 1 % step 2 * jmp ]0 "success leap 2 "failure del 0 del 0 next "exit jmp 4 "update input del 0 del 1 "iterate again jmp -27
Because we can run Fractran directly, this proves MMRPN is Turing-complete
Ackermann function
This function requires recursion; with a little planning however, you can use the stack as a call stack too!
"m 3 "n 3 "---- 43 jmp 3 "return path -> 1 jmp ]0 "begin A(m,n) form m, n, return location <- 2 "m==0 >> 1 step 6 * jmp ]0 "true del 0 "n + 1 del 1 1 + "return jmp -12 "false "n==0 del 0 >> 0 step 10 * jmp ]0 "true del 0 del 0 1 - 1 25 "A(m-1,1) jmp -23 del 0 "return jmp -27 "false del 0 >> 1 -> 1 1 - 34 "A(m, n-1) jmp -32 del 0 -> 1 1 - -> 1 41 "A(m-1,A(m,n-1)) jmp -39 del 0 "return jmp -43 "end A(m,n) del 0 outputV
Examples elsewhere on this site
- A+B problem
- FizzBuzz
- Looping counter
- Never gonna give you up
- Pi alpha function
- Shape machine
- User:XKCD_Random_Number#MoreMathRPN