Now we can discuss clauses which choose between alternatives. We have
met the enclosed clause consisting of at least
one phrase enclosed by BEGIN and END (or
parentheses) in the structure of an Algol 68 program, and also
in the DO
... OD
loop of a FOR
or
FORALL
clause. The part of the enclosed clause inside the
parentheses (or BEGIN
and END
) is called a
serial clause because,
historically, sequential elaboration used to be called “serial
elaboration”. The value of the serial clause is the value of the
last phrase which must be a unit.
There are two kinds of clause which enable programs to modify
their behaviour. They are called choice clauses. The
conditional clause allows a program to
elaborate code depending on the value of a boolean serial
clause, called a BOOL
enquiry
clause. Here is a simple example:
IF salary < 5000 THEN 0 ELSE (salary-allowances)*rate FI
The enquiry clause consists of the formula
salary < 5000
which yields a value of mode BOOL
. Two serial clauses,
both containing a single unit can be elaborated. If the value yielded
by salary
is less than 5000
, the value
0
is yielded. Otherwise, the program calculates the tax.
That is, if the BOOL
enquiry clause yields
TRUE
, the serial clause following
THEN is elaborated, otherwise the serial
clause following ELSE is elaborated. The
FI following the ELSE
serial
clause must be there.
The enquiry clause and the serial clauses may consist of single
units or possibly declarations and formulæ and loops. However,
the last phrase in an enquiry clause must be a unit yielding
BOOL
. The range of any identifiers
declared in the enquiry clause extends to the serial clauses as well.
The range of any identifiers declared in either serial clause is
limited to that serial clause. For example, assuming that
a
and i
are predeclared, we could write:
IF INT ai = a[i]; ai < 0 THEN print((ai," is negative",newline)) ELSE print((ai," is non-negative",newline)) FI
The conditional clause can be written wherever a unit is permitted, so the previous example could also be written
INT ai = a[i]; print((ai,IF ai < 0 THEN "is negative" ELSE "is non-negative" FI,newline))
The value of each of the serial clauses following THEN
and ELSE
in this case is []CHAR
. Here is an
example with a conditional clause inside a
loop:
FOR i TO 100 DO IF i MOD 10 = 0 THEN print((i,newline)) ELSE print((i,blank)) FI OD
The ELSE
part of a conditional clause can be omitted.
Thus the above example could also be written
FOR i TO 100 DO print((i,blank)); IF i MOD 10 = 0 THEN print(newline) FI OD
The whole conditional clause can appear as a formula or as an
operand. The short form of the clause is often
used for this: IF
and FI
are replaced by
( and )
respectively, and THEN
and ELSE
are both
replaced by the vertical bar
|5.1. For
example, here is an identity declaration which assumes a previous
declaration for x
:
REAL xx = (x < 3.0|x**2|x**3)
If the ELSE
part is missing then its serial clause is
regarded as containing the single unit
SKIP. In this case, SKIP
will yield an undefined value of the mode yielded by the
THEN
serial clause. This is an example of
balancing (explained in chapter 10).
This is particularly important if a conditional clause is used as an
operand.5.2
Since the right-hand side of an identity declaration is in a strong context, widening is allowed. Thus, in
REAL x = (i < j|3|4)
whichever value the conditional clause yielded would be widened to
a value of mode REAL
.
Since the enquiry clause is a serial clause, it
can have any number of phrases before the THEN
. For
example:
IF []CHAR line = "a growing gleam glowing green"; INT sz = UPB line - LWB line + 1; sz > 35 THEN ...
Conditional clauses can be nested
IF a < 4.1 THEN IF b >= 35 THEN print("yes") ELSE print("no") FI ELSE IF c <= 20 THEN print("perhaps") ELSE print("maybe") FI FI
The ELSE IF in the above clause could
be replaced by ELIF, and the final
FI FI
with a single FI
, giving:
IF a < 4.1 THEN IF b >= 35 THEN print("yes") ELSE print("no") FI ELIF c <= 20 THEN print("perhaps") ELSE print("maybe") FI
Here is another contracted example:
INT p = IF c = "a" THEN 1 ELIF c = "h" THEN 2 ELIF c = "q" THEN 3 ELSE 4 FI
The range of any identifier declared in an enquiry clause extends to any serial clause beyond its declaration but within the overall conditional clause. Consider this conditional clause:
IF INT p1 = ABS(c="a"); p1=1 THEN p1+2 ELIF INT p2 = p1-ABS(c="h"); p2 = -1 THEN INT i1 = p1+p2; i1+p1 ELSE INT i2 = p1+2*p2; i2-p2 FI
The range of p1
extends to the enclosing
FI
; likewise the range of p2
. The ranges of
i1
and i2
are confined to their serial
clauses.
In the abbreviated form, |: can be
used instead of ELIF
. For example, the above identity
declaration for p
could be written
INT p = (c="a"|1|:c="h"|2|:c="q"|3|4)
In both identity declarations, the opening parenthesis is an
abbreviated symbol for IF
.
Sometimes it is useful to include a conditional clause in the
IF
part of a conditional clause. In other words, a
BOOL
enquiry clause can be a conditional clause yielding
a value of mode BOOL
. Here is an example with
a
and b
predeclared with mode
BOOL
:
IF IF a THEN NOT b ELSE b FI THEN print("First possibility") ELSE print("Second possibility") FI
As was mentioned in chapter 2, both the operands of an operator are
elaborated before the operator is elaborated. The a68toc
compiler implements the pseudo-operator
ANDTH
which although it looks like an operator, has its
right-hand operand elaborated only if its left-hand operand yields
TRUE
. Compare ANDTH
(which is read
“and then”) with the operator
AND. The priority of ANDTH
is 1. The phrase IF p ANDTH q THEN ... FI
is
equivalent to
IF IF NOT p THEN FALSE ELIF q THEN TRUE ELSE FALSE FI THEN ... FI
You should be chary of using ANDTH
in a compound boolean
expression. For example, given the condition
UPB s > LWB s ANDTH s[UPB s]="-" AND (CHAR c=s[UPB s-1]; c>="a" & c<="z")
the intention of the compound condition is to determine whether a
terminating hyphen is preceded by a lower-case letter. Clearly,
testing for a character which precedes the hyphen can only be
elaborated if there are at least two characters in s
.
The first boolean formula (the left operand of ANDTH
)
ensures that the second formula (the right operand of
ANDTH
) is only elaborated if s
identifies at
least two characters. Unfortunately, because the priority of
AND
is greater than the priority of ANDTH
and because both operands of an operator must be elaborated before the
operator is elaborated, the right-hand operand of AND
will be elaborated whatever the value of the left operand of
ANDTH
. In order to achieve the above aim, the compound
condition should be written
UPB s > LWB s ANDTH (s[UPB s]="-" AND (CHAR c=s[UPB s-1]; c>="a" & c<="z"))
Note the additional parentheses which ensure that the boolean formula
containing AND
is treated as a whole as the right-hand
operand of the pseudo-operator ANDTH
.
There is another pseudo-operator OREL
(read “or else”) which is similar to the operator
OR except that its right-hand operand is
only elaborated if its left-hand operand yields FALSE
.
Like ANDTH
, the priority of OREL
is 1.
The remarks given above about the use of ANDTH
in
compound boolean formulæ apply equally to OREL
.
Neither ANDTH
nor OREL
are part of Algol
68.
REAL
value is less than OREL
in the following program with
a suitable conditional clause:
PROGRAM p CONTEXT VOID USE standard IF INT a=3, b=5, c=4; a > b OREL b > c THEN print("Ok") ELSE print("Wrong") FI FINISHAns
Sian Mountbatten 2012-01-19