The Stack

zrpc is a "stack-oriented" language, meaning that all functions of the language implicitly involve the usage a stack data structure. Here's an example:

4 5 +

When the zrpc compiler parses this snippet, it will read the reverse-polish math from left-to-right, first seeing 4, then 5, and pushing them both onto the stack. When it reaches +, it will pop 4 and 5 off the stack, add them together, and push the result of the operation back onto the stack. Here's an example with an extra component:

4 5 + 10 *

In this case, 4 5 + resolves to 9, making the snippet into this:

9 10 *

which evaluates to 90.

The number of objects that a function (or operator; they are interchangeable in zrpc) pops off the stack is called its "arity". The arity of a function is usually the same as the number of arguments the function accepts.

Each function also has an arbitrary number assigned to it which determines how many objects it places back onto the stack after it returns, which is called its "pointer increment" value. In the reference pages for each built-in function, these will be referred to as a function's "incptr" value.

zrpc calculates the position of each object on the stack at compile time, aside from objects added to the stack via user input, which are handled at runtime. This results in some strange behavior regarding logic statements:

5 5 ?{
  6 4 3 + =
}

In this conditional statement, both instances of 5 will be popped off the stack by ?{, and 4 3 + will resolve to 7 and be printed and popped off the stack by =, but 6 will remain on the stack after the conditional finishes— however, if instead the statement was:

4 5 ?{
  6 4 3 + =
}

The conditional would not execute, but the compiler would still compute stack positions as if the conditional had executed— it can't tell which will happen, and with the current implementation, conditionals do not have their own local variable scope / local stack, in contrast to user-defined functions, which do. This results in the stack pointer incrementing and decrementing in the same manner regardless of conditional execution, meaning that a 0 will be added to the stack instead of a 6 in this case. For this reason, it is best practice to pop any unwanted variables off the stack prior to terminating a conditional, like so:

x 5 ?{
  6 4 3 + = pop
}

which prevents the ghost 0 from being pushed onto the stack, as the stack pointer is manually decremented at the end of the conditional, with the stack pointer neither being increased nor decreased as a result of the conditional body.

This behavior may be changed in a future version, as it is somewhat difficult to understand, despite being technically more flexible and easier to implement than individual stack scope for conditionals.