4.3 A more complex example, an RPN calculator

We create a small stack-based RPN calculator which applies a series
of operators to a given parameter and to other numeric operands.
Unlike previous examples, the code generator is fully parameterized
and is able to compile different formulas to different functions.
Here is the code for the expression compiler; a sample usage will
follow.

Since GNUlightning does not provide push/pop instruction, this
example uses a stack-allocated area to store the data. Such an
area can be allocated using the macro allocai, which
receives the number of bytes to allocate and returns the offset
from the frame pointer register FP to the base of the
area.

Usually, you will use the ldxi and stxi instruction
to access stack-allocated variables. However, it is possible to
use operations such as add to compute the address of the
variables, and pass the address around.

The principle on which the calculator is based is easy: the stack top
is held in R0, while the remaining items of the stack are held in the
memory area that we allocate with allocai. Compiling a numeric
operand or the argument x pushes the old stack top onto the
stack and moves the operand into R0; compiling an operator pops the
second operand off the stack into R1, and compiles the operation so
that the result goes into R0, thus becoming the new stack top.

This example allocates a fixed area for 32 ints. This is not
a problem when the function is a leaf like in this case; in a full-blown
compiler you will want to analyze the input and determine the number
of needed stack slots—a very simple example of register allocation.
The area is then managed like a stack using stack_push and
stack_pop.

Source code for the client (which lies in the same source file) follows:

Providing the formula as an argument to compile_rpn effectively
parameterizes code generation, making it possible to use the same code
to compile different functions; this is what makes dynamic code
generation so powerful.