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
FINISH
Ans
Sian Mountbatten 2012-01-19