Keywords: pame

Subsections

- Pseudo-operators
- Exercises

# 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 , 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