Subsections

Conditional clauses

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

Pseudo-operators

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.


Exercises

4.5
Write a conditional clause which tests whether a REAL value is less than $ \pi$, and prints "Yes" if it is and "No" otherwise. Ans[*]
4.6
Write a conditional clause inside a loop clause to display the first 96 multiples of 3 (including 3) in lines of 16. Use the operator MOD for the test. Ans[*]
4.7
Replace the operator 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