Documentation for the RPN expression engine in OverLua
======================================================

For some graphics processing operationg, OverLua provides an RPN (Reverse
Polish Notation) to do fast calculations. This expression engine is designed
primarily to have very fast execution and be multithreading-safe in the
runtime.

The language is meant to support multi-variable calculations, so apart from
the usual arithmetic operators there is also an assignment operator. Finally
there is a limited number of temporary registers.

There is no explicit Lua interface to the expression engine, rather it is
implicitly used by some image processing functions. In those cases, a
program is passed as a string to the image processing function.


Stack machine execution model
-----------------------------

The expression evaluator is implemented as a stack machine with a number
of registers. Some of these registers are used for input and/or output
values and some are freely usable for temporary storage.

The stack holds numbers in 'double' precision, this is the only data type
supported by the machine. There are no practical limits on stack depth.

The registers also hold numbers in 'double' precision. Depending on the
function using the expression evaluator, different input/output registers
will be available. The input/output registers will usually be single-letter
names using uppercase letters. There are always exactly ten temporary
registers available, named "t0" to "t9", ie. lowercase "t" followed by
a digit. The contents of the temporary registers are undefined at the start
of program execution.


The program consists of a number of instructions executed sequentially. There
are three basic types of instructions:
 - push
 - call
 - store

A 'push' instruction pushes a single number to the top of the stack. The
source of the number can either be a constant or a register.

A 'call' instruction pops some numbers from the stack, performs an operation
on them and pushes a single number back onto the stack. This includes basic
arithmetic operations such as addition, mulitiplication, but also functions
such as sinus, rounding and logarithms. How many numbers are popped from the
stack depends on the function.

The 'store' instruction pops one number from the stack and stores it into
a register, overwriting the previous number in the register.


After every instruction in the program has been executed, any remaining numbers
on the stack are discarded, and the numbers in the output registers are passed
to the function using the expression evaluator.


If a program operation attempt to pop a number from the stack when the stack
is empty, the machine halts with an error state, and the result of the program
is undefined.


Expression syntax
-----------------

The syntax used to specify programs is very straightforward.

The program consists of a number of tokens separated by whitespace. Each token
translates into one instruction.


A token can be a number. This translates into a 'push' instruction, pushing
that number as a constant. The format for numbers is the same as in C.

Examples: "1", "-5", "3.14", ".5" "2.998e8"


A token can be a register name. This translates into a 'push' instruction,
pushing the number in the register.

Examples: "X", "Y", "t0", "t6"


A token can be a basic arithmetic operator. These translate into 'call'
instructions. Each of these represent a function that pops two numbers,
performs the calculation and pushes the result.

The basic arithmetic operators are: + - * / ^

Examples:
Suppose the two previous instructions were "A B" where A and B are registers.
This means that now the stack contains B at the top and A just below.
Operator "+" will then calculate "A + B". Operator "-" will calculate "A - B".
Operator "*" will calculate "A * B". Operator "/" will calculate "A / B".
Operator "^" will calculate "A ^ B", ie. A raised to the power of B.

The result of illegal operations is undefined. It will most likely result in
an invalid number being pushed onto the stack, and operating on that number
will cause the error to propagate.


A token matching the name of a defined function will translate into a 'call'
instruction for the given function. A number of standard functions are always
available, see below for details.


An equal sign followed by the name of a register translated into a 'store'
instruction, that will pop the number at the top of the stack and store it
into the named register. There must not be any whitespace between the equal
sign and the register name.

Examples: "=X", "=t0"


Standard function library
-------------------------

The following functions are always available in the machine.


~  (tilde character)
Takes one argument, produces one result.
Unary minus. (Negate the argument.)

abs
Takes one argument, produces one result.
Return the absolute value.

floor
Takes one argument, produces one result.
Round towards negative infinity.

ceil
Takes one argument, produces one result.
Round towards positive infinity.


log
Takes one argument, produces one result.
Natural (base e) logarithm.

exp
Takes one argument, produces one result.
Natural exponentiation. (e to the power of x.)

sqrt
Takes one argument, produces one result.
Square root.

e
Takes no arguments, produces one result.
Push the value of e.


min
Takes two arguments, produces one result.
Return the smallest of the arguments.

max
Takes two arguments, produces one result.
Return the largest of the arguments.


pi
Takes no arguments, produces one result.
Push the value of pi.

sin
Takes one argument, produces one result.
Sinus function. Argument in radians.

cos
Takes one argument, produces one result.
Cosine function. Argument in radians.

tan
Takes one argument, produces one result.
Tangent function. Argument in radians.

asin
Takes one argument, produces one result.
Arc sinus function.

acos
Takes one argument, produces one result.
Arc cosine function.

atan
Takes one argument, produces one result.
Arc tangent function.


mod
Takes two arguments, produces one result.
Modulo operation.


rand
Takes no arguments, produces one result.
Return a random value in range 0..1.


ifgtz
Takes three arguments, produces one result.
If the first argument is greater than zero, return the second argument,
else return the third argument.

ifeqz
Takes three arguments, produces one result.
If the first argument is equal to zero, return the second argument,
else return the third argument.


Sample programs
---------------

For raster.pixel_value_map:

"rand =t0 t0 =R t0 =G t0 =B"
Create a field of random gray-values.

"0 =R 1 G - =G"
Zero out the red channel and invert the green channel.


For raster.pixel_coord_map:

"X .5 rand - + =X  Y .5 rand - + =Y"
Create some jitter in the pixels.
