MoreMathRPN

:Unless otherwise specified, "or" is exclusive or.
MoreMathRPN (abbreviated MMRPN) is a stack based imperative language created in 2023, created 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.
Using relative offsets over absolute positions is the primary philosophy of MMRPN,
no labels, nor line numbers.
==Commands==
Each line must have only one command, breakpoint, or comment.
While not part of the standard, MMRPN reserves "!!!" to be a breakpoint, if you write an interpreter or compiler, your code should at least behave like a breakpoint and its line doesn't exist
===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 separated 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
====Checks and comparisons====
Operation symbol/name	Description / Formula 	Parameters	Arguments
# 	Stack height 	None 	None
step 	Greater than zero (a > 0 → 1, a <= 0 → 0) 	None 	1 R
hyperStep 	Divides by infinity, by cheating(a == -∞ → -1, a == ∞ → 1, otherwise → 0) 	None 	1 R
compare 	Comparison (a > b → -1, a == b → 0, a < b → 1) 	None 	2 R
query 	looks at an element in the stack whose depth is given by the parameter, if it's rational then outputs 0, if it's a matrix, outputs 1	Depth 	None
====Stack manipulation====
Operation symbol/name	Description / Formula	Parameters	Arguments
>> 	Copy 	Depth 	None
-> 	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
unzip 	Inverse of m command 	None 	1 M
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
inputSE 	Prompts the user to input a string potentially containing escaped characters (especially \n & \\), 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
error 	Outputs a string as an error message, and stops execution 	String 	None
====Lambda functions====
Operation symbol/name	Description / Formula 	Parameters	Arguments
run 	interprets a row matrix as a string, then interprets the string	None 	1 M (single row)
end 	Stops the current program, useful with run commands 	None 	None
halt 	Halt and catch fire 	none 	none
Tip: I recommend you write any code normally, place chars " before the first instruction then use a macro that presses the End, Delete, \, n keys in that order exactly once. AutoHotKey is great for this.
=====Notes on recursion=====
While recursion is allowed with run, please avoid deep recursion, instead use a system akin to the first #Ackermann function example, with a return path using jmp.
The run command should only be used if:
*You're calling a sequence of commands multiple times, in different contexts (i.e. both inside and outside a repeat...next block).
*You need to jump over a code block that can be changed by another person.
*A function is a parameter of another function, like Array.reduce().
===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.
===Infinity===
In normal mathematics, dividing by zero (0) is disallowed, due to inevitable paradoxes that occur, but guess what? This is a programming language, where having a value of greater magnitude is useful! so infinity is here:
 "Positive infinity
 1/0
 "Negative infinity
 "-1/0
While Infinity does work in other situations, it gets real weird. If you subtract infinity from infinity, multiply infinity by zero, or other zany operations, you'll run into a special "Indeterminate form" error, when MMRPN can't give a good answer.
===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 behaves like break, 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.
 "change me to 1, 2 or 3
 1
 "1 → "1", 2 → "21", 3 -> "31"
 >> 0
 >> 0
 *
 -2
 /
 -> 1
 2
 /
 4
 +
 +
 jmp ]0
 outputS "3"
 jmp 2
 outputS "2"
 outputS "1"
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 IO commands and get very hammered.
 99
 repeat 97
 >> 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
 "Deal with singular bottle.
 1
 2
 2
 outputV
 outputS " bottles of beer on the wall,\n"
 outputV
 outputS " bottles of beer.\nTake one down pass it around,\n"
 outputV
 outputS " bottle of beer on the wall.\n"
 1
 1
 outputV
 outputS " bottle of beer on the wall,\n"
 outputV
 outputS " bottle of beer.\nTake one down pass it around,\nOops, we ran out of beer!"
===Using run===
With the assistance of other commands, you can create functions with a similar syntax to FALSE.
 chars "outputS \"Hello, world!\""
 hold len
 del 0
 m $len 1
 flip
 hold hello
 del 0
 "...
 place hello
 run
You can also use aug in various ways to create dynamic functions, such as creating unique variable names
===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
===Brainfuck interpreter===
It is quite monstrous, at 356 lines, I put it in it's own section:
go view it →
===Quine===
I have 2 quines available for you, again they are big, so here's another section: go view it →
===Implicit plotter===
Want to use the worst plotter know to man? Yes? Ok then, take a look →
===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
If you want to use run:
 3
 3
 outputS "A("
 >> 1
 outputV
 outputS ", "
 >> 0
 outputV
 outputS ")"
 chars ">> 1\nstep\n6\n*\njmp ]0\ndel 0\ndel 1\n1\n+\nend\ndel 0\n>> 0\nstep\n9\n*\njmp ]0\ndel 0\ndel 0\n1\n-\n1\nplace Ackermann\nrun\nend\ndel 0\n1\n-\n>> 1\n1\n-\n<- 2\nrepeat 2\nplace Ackermann\nrun\nnext\nend"
 hold Ackermann
 del 0
 m $Ackermann 1
 flip
 hold Ackermann
 run
 outputS " = "
 outputV
===Examples elsewhere on this site===
*A+B problem
*FizzBuzz
*Half hearted
*Kolakoski sequence
*Looping counter
*Never gonna give you up
*Pi alpha function
*Shape machine
*User:XKCD_Random_Number#MoreMathRPN
==Implementations==
JavaScript MMRPN Interpreter by Calculus is fun (talk)!
Category:Languages
Category:2023
Category:Stack-based
Category:Turing complete
Category:IO
Category:Implemented
Category:High-level
Category:Flat-nested