LOOPS (Repetitive Structures)

Pascal supports three different loop structures based on the reserved
words WHILE DO, REPEAT UNTIL and FOR DO.  Without question, mastery of
loop structures is a key requirement of any programming environment. 
"With practice of key concepts comes mastery thereof!"

WHILE DO:     While  Do
                Statements in loop body

1.  Before the loop is executed, the Boolean expression must be
    properly initialized; otherwise the loop may be out of control
    and the statements in the loop body never executed.  Example:

              Sum := 0;
              While Sum > 0 Do
                etc.

2.  If the loop body consists of two or more statements, the loop
    body must be enclosed in a BEGIN .. END pair.  Otherwise, only
    the first statement will be considered part of the loop body. 
    Example:

              Sum := 0;
              Count := 1;
              While Count <= 10 Do
                Sum := Sum + Count;
                Count := Count + 1;
              Writeln(Sum);

    This is an example of a loop which is out of control.  The ONLY
    statement the compiler considers is in the loop body is the first
    statement "Sum := Sum + Count".  Since the value of Count is
    never altered while the loop executes, the computer is now in an
    infinite loop condition.  What was likely intended by the
    programmer was:

              Sum := 0;
              Count := 1;
              While Count <= 10 Do
                Begin
                  Sum := Sum + Count;
                  Count := Count + 1;
                End;
              Writeln(Sum);

3.  The programmer is required to ensure that the Boolean Expression
    controlling the WHILE DO loop is properly initialized before the
    loop begins and that the Boolean Expression is updated (or
    altered) sometime during loop execution.  Even so, it is a
    logical possibility that a WHILE DO loop will never execute.

EXAMPLE OF WHILE DO LOOP

The following problem is an example of a SENTINEL CONTROLLED PROCESS: 
Read in integers until a -1 is encountered.  The output is to consist
of (1) the number of integers entered; (2) their real average; (3) the
largest integer entered.  All variables are declared integer, except
Average is declared real.

Sentinel := -1;    { declare value of sentinel "flag" }
Sum := 0;          { initialize accumulator and counter }
Count := 0;

Read(Number);      { perform a so-called "priming read" }
Largest := Number; { initialize what will become largest value read }

While (Number <> Sentinel) Do
  Begin
    Sum := Sum + Number;
    Count := Count + 1;
    If Number > Largest
      Then Largest := Number;


    { read next number only after previous number has been completely
      processed }

    Read(Number)   
  End;

If Count > 0
  Then
    Begin
      Average := Sum / Count;
      Writeln('There were ', Count, 'numbers entered.');
      Writeln('Their average is: ', Average :0:2);
      Writeln('The largest number entered was: ', Largest)
    End
  Else
    Writeln('There was no data processed.');

The following example shows a COUNT CONTROLLED PROCESS:  Read in 50
numbers.  Print out the numbers, 5 to a line, and then their average.

Number_to_read := 50;
Count := 0;
Sum := 0;

While (Count < Number_to_read) Do
  Begin
    Read(Number);      { input a number }
    Sum := Sum + Number;{ update the accumulator }
    Count := Count + 1;{ update the counter }
    Write(Number :8)   { print the number }
    If Count Mod 5 = 0 { perform a line feed if needed }
      Then Writeln;
  End;

If Count > 0
  Then
    Begin
      Average := Sum / Count;
      Writeln('Their average is: ', Average :0:2)
    End
  Else
    Writeln('There was no data processed.');

Nested WHILE loops are certainly allowed.  For example, a well-known
example problem involves printing out a simple multiplication table
for the integers from 1 - 9:
Program Mult_table;

Uses
  Crt;

Const
  Max_row = 9;
  Max_col = 9;

Var
  Row, Column, Product: Integer;

Begin
  Clrscr;
  Row := 1;
  Writeln(' x |    1    2    3    4    5    6    7    8    9');
  Writeln('---|---------------------------------------------');
  While (Row <= Max_row) Do
    Begin
      Column := 1;
      Write(Row :2, ' |');
      While (Column <= Max_col) Do
        Begin
          Product := Row * Column;
          Write(Product :5);
          Column := Column + 1
        End;
      Writeln;
      Row := Row + 1
    End;
  Readln
End.


PROGRAM OUTPUT:


 x |    1    2    3    4    5    6    7    8    9
---|---------------------------------------------
 1 |    1    2    3    4    5    6    7    8    9
 2 |    2    4    6    8   10   12   14   16   18
 3 |    3    6    9   12   15   18   21   24   27
 4 |    4    8   12   16   20   24   28   32   36
 5 |    5   10   15   20   25   30   35   40   45
 6 |    6   12   18   24   30   36   42   48   54
 7 |    7   14   21   28   35   42   49   56   63
 8 |    8   16   24   32   40   48   56   64   72
 9 |    9   18   27   36   45   54   63   72   81


REPEAT UNTIL           Repeat
                         
                       Until Boolean

The Repeat loop is a bottom driven loop (i.e., the Boolean test follows the
execution of the loop body).  Notice that:

(1) The loop body will ALWAYS be executed at least once, since the Boolean test
    comes after carrying out the instructions in the loop.  Thus a REPEAT UNTIL
    loop should NEVER be used when it is a logical possibility that the loop
    should never execute.  REPEAT LOOPS ALWAYS EXECUTE AT LEAST ONCE!

(2) A BEGIN-END pair is not necessary around the loop body in a REPEAT UNTIL loop,
    since the key words REPEAT and UNTIL encapsulate the instructions in the loop
    body.

(3) Notice the primary distinction between WHILE and REPEAT loops:  a WHILE loop
    executes while (as long as) the Boolean test is TRUE.  A REPEAT loop executes
    until the Boolean becomes true (i.e., while the Boolean is FALSE).

A typical example of a REPEAT loop is synthesizing exponents in Pascal:

Count := 1;
Base := 4;
Power := 1;
REPEAT
  Power := Power * Base;
  Count := Count + 1;
UNTIL (Count = 5);
Writeln('Four to the fifth power is ', Power);

Another popular use of REPEAT loops in to control a menu of choices.  Refer to
problem #12, page 152.

Program Menu;

Uses
  Crt;

Var
  Count, Sum, Value, Largest: Integer;
  Average: Real;
  Choice: Char;

Begin
  Largest := 0;
  Count := 0;
  Sum := 0;
  Randomize;

  REPEAT
    Clrscr;
    Writeln('A.  Generate a new value.');
    Writeln('B.  Report average to this point.');
    Writeln('C.  Report highest value to this point.');
    Writeln('Q.  QUIT');
    Writeln;
    Write('Enter your selection ==> ');
    Readln(Choice);

    If NOT((Choice = 'Q') or (Choice = 'q'))
      Then
        Begin
          Case CHOICE of
            'A', 'a':  Begin
                         Value := Random(99);
                         Writeln('Value generated = ', Value);
                         If Value > Largest
                           Then Largest := Value;
                         Sum := Sum + Value;
                         Count := Count + 1;
                       End;
            'B', 'b':  If Count > 0
                         Then
                           Begin
                             Average := Sum / Count;
                             Writeln('Average so far is ', Average :0:2)
                           End
                         Else Writeln('No average possible to this point.');
            'C', 'c':  If Count > 0
                         Then Writeln('Largest value so far is ', Largest)
                         Else Writeln('No largest value to this point.');
            Else Writeln('Illegal value entered.')
          End;  { CASE }
          Writeln;
          Write('Press enter key to continue...');
          Readln
        End;
 Until (Choice = 'Q') or (Choice = 'q')
End.