7.3 Flow Control
As in PASM, flow control in PIR is done entirely with
conditional and unconditional branches. This may seem simplistic, but
remember PIR is a thin overlay on the assembly language of a virtual
processor. For the average assembly language, the jump is the
fundamental unit of flow control.
Any PASM branch instruction is valid, but IMCC has some high-level
constructs of its own. The most basic is the unconditional branch:
goto.
.sub _main
goto L1
print "never printed"
L1:
print "after branch\n"
end
.end
The first print statement never runs because the
goto always skips over it to the label
L1.
The conditional branches combine if or
unless with goto.
.sub _main
$I0 = 42
if $I0 goto L1
print "never printed"
L1: print "after branch\n"
end
.end
In this example, the goto branches to the label
L1 only if the value stored in
$I0 is true. The
unless statement
is quite similar, but branches when the tested value is false. An
undefined value, 0, or an empty string are all false values. The
if ... goto statement is translated directly to
Parrot's if, and
unless translates to Parrot's
unless.
The comparison operators (<,
<=, = =,
!=, >,
>=) combine with if ...
goto. These branch when the comparison is true:
.sub _main
$I0 = 42
$I1 = 43
if $I0 < $I1 goto L1
print "never printed"
L1:
print "after branch\n"
end
.end
This example compares $I0 to
$I1 and branches to the label
L1 if $I0 is less than
$I1. The if $I0 < $I1 goto
L1 statement translates directly to the PASM
lt branch operation.
The rest of the comparison operators are summarized at the end of
this chapter.
PIR has no special loop constructs.
A combination of conditional and unconditional branches handle
iteration:
.sub _main
$I0 = 1 # product
$I1 = 5 # counter
REDO: # start of loop
$I0 = $I0 * $I1
dec $I1
if $I1 > 0 goto REDO # end of loop
print $I0
print "\n"
end
.end
This example calculates the factorial 5!. Each
time through the loop it multiplies $I0 by the
current value of the counter $I1, decrements the
counter, and then branches to the start of the loop. The loop ends
when $I1 counts down to 0 and the
if doesn't branch to
REDO. This is a do
while-style loop
with the condition test at the end, so the code always runs the first
time through.
For a while-style loop with the condition test at the
start, use a conditional branch together with an unconditional
branch:
.sub _main
$I0 = 1 # product
$I1 = 5 # counter
REDO: # start of loop
if $I1 <= 0 goto LAST
$I0 = $I0 * $I1
dec $I1
goto REDO
LAST: # end of loop
print $I0
print "\n"
end
.end
This example tests the counter $I1 at the start of
the loop. At the end of the loop, it unconditionally branches back to
the start of the loop and tests the condition again. The loop ends
when the counter $I1 reaches 0 and the
if branches to the LAST label.
If the counter isn't a positive number before the
loop, the loop never executes.
Any high-level flow control construct can be built from conditional
and unconditional branches.
|