## 3.6 Analysis of Loops

In some of the examples of repetition, REPEAT .. UNTIL was more appropriate than the WHILE loop, because it saved a few statements, and because the loop was to execute at least once. Which of the two types of loop one uses depends on whether the test for repetition is to be at the top of the loop or at the bottom, that is, whether one needs to have the loop execute at least once in all cases. This is, however, a minor design consideration, for as the examples showed, it is possible to use the WHILE construction all the time by initializing the value of the controlling variable before entering the loop. Because this is so, some teachers discourage or even forbid their students from using the REPEAT..UNTIL construction at all. That is, there may be considerations other than program design that determine the details of the code. Local customs should be followed in such matters. This text will use the WHILE construction most of the time, but REPEAT will be employed when it is more natural. Many of the comments made in this section about the WHILE loops apply to the REPEAT loop as well.

In any case, the principle of top-down-design as applied to this situation means that one should choose the type of loop before starting to code. There must be a reason for putting each statement on paper, and the programmer must know what that reason is and be able to explain it.

## 3.6.1 Loops and Boolean Flags

In some programs, it may be necessary to execute the code in the loop indefinitely until some special condition is reached. This was done in several of the earlier examples in this chapter when the bulk of the program code was surrounded by a REPEAT..UNTIL NOT again construction.

If a loop can be exited only on some special value of the boolean expression controlling it, that value is called a sentinel value. If a variable is used to hold the value, it may be called a sentinel variable.

### Example:

Write a module to simulate a simple four function calculator.

### Discussion:

Such calculators maintain two values called the x-register and the accumulator. The x-register holds the most recently entered value, and the accumulator holds the most recently obtained result. Here, the code will expect an alternating sequence of one-character symbols (the operations) and numbers (the new x-register each time). It will perform the binary operations as (x-register operation accumulator) ==> accumulator.

### Pseudocode:

```  Print an informative heading
Print the instructions
Zero the x-register and the accumulator
Repeat
Print the accumulator
Set the flag opOk if it is a valid operation
If the operation is not exit then
Set the numOk flag if the number was read correctly
If the number was not ok then
set the x-register to zero
If the operation was ok, then
If it was +, then
add the x-register to the accumulator
else if - then
subtract the x-register from the accumulator
else if * then
multiply the accumulator by the x-register
else if /, then
if the x-register was not zero, then
divide the accumulator by the x-register
else print an error message
else assume that the operation was = and
set the accumulator to the value of the x-register
until the operation is exit```
```MODULE FourBanger;

(* Written by R.J. Sutcliffe *)
(* to illustrate Boolean flags in loops *)
(* using P1 MPW Modula-2 for the Macintosh computer *)
(* last revision 1993 02 15 *)

FROM STextIO IMPORT
FROM SIOResult IMPORT
FROM SRealIO IMPORT

VAR
xReg, accum: REAL;
op : CHAR;
opOK, numOK : BOOLEAN;

BEGIN
(* write information *)
WriteString ("FourBanger was written by R.J. Sutcliffe");
WriteLn;
WriteString ("to illustrate Boolean flags in loops");
WriteLn;
WriteLn;
WriteString ("This program simulates a four function calculator.");
WriteLn;
WriteString ("You enter an operation and then a number");
WriteLn;
WriteString ("The running result will be displayed.");
WriteLn;
WriteString ("If you enter 'E' for the operation the program exits.");
WriteLn;
WriteString ("The default operation is = which means 'display number.'");
WriteLn;
WriteLn;

(* Initialize *)
accum := 0.0;
xReg := 0.0;

REPEAT
(* write out the accumulated value *)
WriteFixed (accum, 6 ,25);
WriteLn;
ReadChar (op); (* no end of line, expect number now *)
(* check for operation *)
opOK := (ReadResult() = allRight) AND
((op = "+") OR (op = "-") OR (op = "*") OR (op = "/"));
IF CAP (op) # "E"  (* not exit *)
THEN
(* obtain a number *)
SkipLine;
IF NOT numOK  (* num is bad for some reason *)
THEN
xReg := 0.0;
END;
IF opOK
THEN
(* go back and see what the operation was and do it *)
IF op = "+"
THEN
accum := accum + xReg;
ELSIF op = "-" THEN
accum := accum - xReg;
ELSIF op = "*" THEN
accum := accum * xReg;
ELSIF (op = "/") THEN
IF (xReg # 0.0)
THEN
accum := accum / xReg;
ELSE
WriteString ("*** Divide by zero error ***");
WriteLn;
END;
END;
ELSE
accum := xReg;
END;
END;
UNTIL CAP (op) = "E";

END FourBanger.```

NOTES: A new function procedure CAP has been introduced to replace such boolean expressions as (op = "e" ) OR (op = "E") by CAP (op) = "E". CAP is a standard identifier.

A run of FourBanger is recorded below, with some of the on-screen carriage returns deleted to save space.

```FourBanger was written by R.J. Sutcliffe
to illustrate Boolean flags in loops

This program simulates a four function calculator.
You enter an operation and then a number
The running result will be displayed.
If you enter 'E' for the operation the program exits.
The default operation is = meaning 'display number'.

0.000000
+9.0             9.000000
-8.8             0.200000
*789.0         157.799850
/8.0            19.724981
/0.0
*** Divide by zero error ***
19.724981
*777.0       15326.310547
e```

Observe the necessity of capturing the value returned by ReadResult before calling SkipLine. If this were not done, and SkipLine were called first, the latter would reset the state obtained by ReadResult and the actual result of the operation ReadReal would be lost.

Instead of having ReadResult in a separate module (as in the ISO standard) to indicate success in reading from the standard I/O channel, many older versions of Modula-2 have a boolean flag in the library module that is imported and checked after every read operation. This is true of both the classical InOut and RealInOut modules. In such versions, one might write:

```FROM InOut IMPORT

and then in the program, one could use the value of Done, set by InOut, to determine whether a correct integer had been typed. Indeed, one could so arrange things that Done served as a flag to the program to proceed. If it were not TRUE, the user could be forced to try again until it were. Code could look like this:

```REPEAT
WriteString ("Enter the number here ==> ");
numOK := Done;  (* non-ISO version *)
IF NOT Done
THEN
WriteString ("error in number typed ; please try again);
WriteLn;
END;
(* these versions read carriage return as a character *)
UNTIL numOK;```

The classical module RealInOut, where available separately from InOut, also has a variable Done that can be imported into a program module and used by it. The code

```      IF CAP (op) # "E"
THEN
SkipLine;
END;
IF NOT numOK```

in the example FourBanger would be written:

```      IF CAP (op) # "E"
THEN