Language constructs

The `loop` opcode takes one argument. If the argument evaluates
to something non-zero, the loop opcode will set the instruction
pointer of the virtual machine to point to the actual loop code (the
code that is inside the loop). If the argument evaluates to zero, the
instruction pointer is instead moved to the instruction immediately
following the loop construct.

A program approximating the machine precision could look like:

;; ;; Calculate machine precision ;; entry "prec" decl floating, ; r0 is floating point floating, ; r1 is floating point integer, ; r2 is a condition variable (integer) floating ; the previous older value is floating too move r0, 1. ; move a floating-point 1 into r0 move r2, 1 ; move an integer 1 into r2 loop r2 ; loop while r2 is nonzero move r3, r1 ; older <- old move r1, r0 ; old <- current div r0, 2. ; current <- current / 2 add r0, 1. add r0, -1. cmpgt r2, r1, r0 ; is old > current ? end ; if not, then older = precision return r3 end

The comments in the code should make it pretty clear what is going on. The algorithm is close to Malcolm's algorithm (see [3]), but not equivalent. Especially Malcolm took into account whether the machine rounded or truncated (``chopped'') values. His algorithm would add a few extra lines to the example above.

Note, we add and subtract to/from the value after we have divided it
by two. This is needed for the value not to evaluate to something
around ,
the smallest possible value in 64-bit IEEE
floating-point. The code isn't that important, but it demonstrates a
simple use of the `loop` construct.

The second construct is the `branch`. This is similar to the
if/then/else constructs of other languages. The `branch` opcode
takes one argument, just like the `loop`, and chooses one
branch if the argument evaluates to something non-zero, and the other
branch if the argument evaluates to zero. After executing any of the
two branches, the instruction pointer of the virtual machine is set to
point at the instruction immediately following the branch construct.

An example of a program using the `branch` construct, is the
following recursive factorial calculator. Yes, the following code may
not be a stunning example of expressive beauty, but it demonstrates
the use of the `branch` construct rather well.

;; ;; This snippet calculates the factorial ;; of the argument given. ;; entry "fact" decl integer, integer move r0, a0 decr r0 ; r0 = n-1 cmpgt r1, a0, 1 ; r1 = a0 > 1 branch r1 call r0, "fact", r0 ; if a0 > 1 then r0 = f(r0) else return 1 ; if a0 <= 1 then return 1 end mult r0,a0 ; r0 = a0 * f(r0) return r0 end

The code is given an argument in the `a`
register, this is
the number
of which want to calculate the factorial. If the
number is greater than 1, the routine makes a recursive call to
calculate the factorial of ,
to multiply that result with ,
and then return. If the number is not greater than 1, we just return
1. So we do not handle negative arguments, but both
and
should be covered.

One thing that should be noted about these constructs is, that we know
*exactly* which variables they depend upon, and which they have
the potential of changing. If a loop uses
as loop variable, the
instructions in the loop uses
,
the entire
loop construct uses .
The loop construct will touch (or
have the potential to touch) the union of the variables each of the
instructions inside the loop touches.

Branches can be looked at similarly. It is at all times extremely
easy to find out what variables may be used or touched by any
`loop` or `branch`, just as it is with single opcodes.

In fact, since we use balanced trees to actually represent the
*uses* and *touches* sets of instructions and
constructs, we can calculate the entire set of dependencies of a loop
in almost linear time wrt. the number of instructions in the loop.
This will be more thoroughly treated in chapter 4.