Using Looping Instructions

There are two types of looping instructions, repetitive loops and conditional loops. Repetitive loops let you repeat instructions a certain number of times. Conditional loops use a condition to control repeating. All loops, regardless of the type, begin with the DO keyword and end with the END keyword.

Repetitive Loops

The simplest loop tells the language processor to repeat a group of instructions a specific number of times. It uses a constant after the keyword DO.

DO 5
  SAY 'Hello!'
END

When you run this example, it produces five lines of Hello!:

Hello!
Hello!
Hello!
Hello!
Hello!

You can also use a variable in place of a constant, as in the following example, which gives you the same results.

number = 5
DO number
  SAY 'Hello!'
END

A variable that controls the number of times a loop repeats is called a control variable. Unless you specify otherwise, the control variable increases by 1 each time the loop repeats.

DO number = 1 TO 5
  SAY 'Loop' number
  SAY 'Hello!'
END
  SAY 'Dropped out of the loop when number reached' number

This example results in five lines of Hello! preceded by the number of the loop. The number increases at the bottom of the loop and is tested at the top.

Loop 1
Hello!
Loop 2
Hello!
Loop 3
Hello!
Loop 4
Hello!
Loop 5
Hello!
Dropped out of the loop when number reached 6

You can change the increment of the control variable with the keyword BY as follows:

DO number = 1 TO 10 BY 2
  SAY 'Loop' number
  SAY 'Hello!'
END
  SAY 'Dropped out of the loop when number reached' number

This example has results similar to the previous example except the loops are numbered in increments of two.

Loop 1
Hello!
Loop 3
Hello!
Loop 5
Hello!
Loop 7
Hello!
Loop 9
Hello!
Dropped out of the loop when number reached 11

Infinite Loops

What happens when the control variable of a loop cannot attain the last number? For example, in the following program segment, count does not increase beyond 1.

DO count = 1 to 10
  SAY 'Number' count
  count = count - 1
END

The result is called an infinite loop because count alternates between 1 and 0, producing an endless number of lines saying Number 1.

If your program is in an infinite loop, contact the operator to cancel it. An authorized user can issue the CEMT SET TASK PURGE command to halt an exec.

DO FOREVER Loops

Sometimes you might want to write an infinite loop purposely; for instance, in a program that reads records from a file until it reaches the end of the file. You can use the EXIT instruction to end an infinite loop when a condition is met, as in the following example. More about the EXIT instruction appears in section EXIT Instruction.

Figure 20. Example Using a DO FOREVER Loop
/******************************* REXX ********************************/
/* This program processes strings until the value of a string is     */
/* a null string.                                                    */
/*********************************************************************/
   DO FOREVER
     PULL string                    /* Gets string from input stream */
     IF string = '' THEN
     PULL file_name
     IF file_name = '' THEN
       EXIT
     ELSE
       DO
        result = process(string)    /* Calls a user-written function */
                                    /* to do processing on string.   */
        IF result = 0 THEN SAY "Processing complete for string:" string
        ELSE SAY "Processing failed for string:" string
       END
   END

This example sends strings to a user-written function for processing and then issues a message that the processing completed successfully or failed. When the input string is a blank, the loop ends and so does the program. You can also end the loop without ending the program by using the LEAVE instruction. The following topic describes this.

LEAVE Instruction

The LEAVE instruction causes an immediate exit from a repetitive loop. Control goes to the instruction following the END keyword of the loop. An example of using the LEAVE instruction follows:

Figure 21. Example Using the LEAVE Instruction
/******************************** REXX *******************************/
/* This program uses the LEAVE instruction to exit from a DO         */
/* FOREVER loop.                                                     */
/*********************************************************************/
   DO FOREVER
     PULL string                 /* Gets string from input stream    */
     IF string = 'QUIT' then
        LEAVE
     ELSE
        DO
        result = process(string)    /* Calls a user-written function */
                                    /* to do processing on string.   */
        IF result = 0 THEN SAY "Processing complete for string:" string
        ELSE SAY "Processing failed for string:" string
        END
   END
   SAY 'Program run complete.'

ITERATE Instruction

The ITERATE instruction stops execution from within the loop and passes control to the DO instruction at the top of the loop. Depending on the type of DO instruction, the language processor increases and tests a control variable or tests a condition to determine whether to repeat the loop. Like LEAVE, ITERATE is used within the loop.

DO count = 1 TO 10
  IF count = 8
    THEN
      ITERATE
    ELSE
      SAY 'Number' count
END

This example results in a list of numbers from 1 to 10 with the exception of number 8.

Number 1
Number 2
Number 3
Number 4
Number 5
Number 6
Number 7
Number 9
Number 10

Exercises - Using Loops

  1. What are the results of the following loops?
    1. DO digit = 1 TO 3
        SAY digit
      END
      SAY 'Digit is now' digit
    2. DO count = 10 BY -2 TO 6
        SAY count
      END
      SAY 'Count is now' count
    3. DO index = 10 TO 8
        SAY 'Hup! Hup! Hup!'
      END
      SAY 'Index is now' index
  2. Sometimes an infinite loop can occur when input to end the loop does not match what is expected. For instance, in the example of using the LEAVE Instruction on page ***, what happens when the input is Quit and a PARSE PULL instruction replaces the PULL instruction?
    PARSE PULL file_name

ANSWERS

  1. The results of the repetitive loops are as follows:
    1.    1
         2
         3
         Digit is now 4
    2.    10
          8
          6
          Count is now 4
    3.     Index is now 10
  2. The program would be unable to leave the loop because Quit is not equal to QUIT. In this case, omitting the PARSE keyword is preferred because regardless of whether the input is quit, QUIT, or Quit, the language processor translates the input to uppercase before comparing it to QUIT.

Conditional Loops

There are two types of conditional loops, DO WHILE and DO UNTIL. One or more expressions control both types of loops. However, DO WHILE loops test the expression before the loop executes the first time and repeat only when the expression is true. DO UNTIL loops test the expression after the loop executes at least once and repeat only when the expression is false.

DO WHILE Loops

DO WHILE loops in a flowchart appear as follows:

dfhrx004

As REXX instructions, the flowchart example looks like:

DO WHILE  expression    /* expression must be true */
   instruction(s)
END

Use a DO WHILE loop when you want to execute the loop while a condition is true. DO WHILE tests the condition at the top of the loop. If the condition is initially false, the language processor never executes the loop.

You can use a DO WHILE loop instead of the DO FOREVER loop in the example of using the LEAVE instruction on page ***. However, you need to initialize the loop with a first case so the condition can be tested before you get into the loop. Notice the first case initialization in the first PULL of the following example.

Figure 22. Example Using DO WHILE
/******************************** REXX *******************************/
/* This program uses a DO WHILE loop to send a string to a           */
/* user-written function for processing.                             */
/*********************************************************************/
  PULL string                       /* Gets string from input stream */
  DO WHILE string \= 'QUIT'
        result = process(string)    /* Calls a user-written function */
                                    /* to do processing on string.   */
        IF result = 0 THEN SAY "Processing complete for string:" string
        ELSE SAY "Processing failed for string:" string
        PULL string
  END
  SAY 'Program run complete.'

Exercise - Using a DO WHILE Loop

Write a program with a DO WHILE loop that uses as input a list of responses about whether passengers on a commuter airline want a window seat. The flight has 8 passengers and 4 window seats. Discontinue the loop when all the window seats are taken. After the loop ends, produce the number of window seats taken and the number of responses processed.

ANSWER

Figure 23. Possible Solution
/******************************** REXX *******************************/
/* This program uses a DO WHILE loop to keep track of window seats   */
/* in an 8-seat commuter airline.                                    */
/*********************************************************************/

  window_seats = 0        /* Initialize window seats to 0 */
  passenger = 0           /* Initialize passengers to 0   */

  DO WHILE (passenger < 8) & (window_seats \= 4)

   /******************************************************************/
   /* Continue while the program has not yet read the responses of   */
   /* all 8 passengers and while all the window seats are not taken. */
   /******************************************************************/

    PULL window                /* Gets "Y" or "N" from input stream  */
    passenger = passenger + 1  /* Increase number of passengers by 1 */
    IF window = 'Y' THEN
      window_seats = window_seats + 1 /* Increase window seats by 1  */
    ELSE NOP
  END

  SAY window_seats 'window seats were assigned.'
  SAY passenger 'passengers were questioned.'

DO UNTIL Loops

DO UNTIL loops in a flowchart appear as follows:

dfhrx005

As REXX instructions, the flowchart example looks like:

DO UNTIL  expression    /* expression must be false */
   instruction(s)
END

Use DO UNTIL loops when a condition is not true and you want to execute the loop until the condition is true. The DO UNTIL loop tests the condition at the end of the loop and repeats only when the condition is false. Otherwise, the loop executes once and ends. For example:

Figure 24. Example Using DO UNTIL
/******************************** REXX ******************************/
/* This program uses a DO UNTIL loop to ask for a password.  If the */
/* password is incorrect three times, the loop ends.                */
/********************************************************************/
   password = 'abracadabra'
   time = 0
   DO UNTIL (answer = password) | (time = 3)
     PULL answer                  /* Gets ANSWER from input stream  */
     time = time + 1
   END

Exercise - Using a DO UNTIL Loop

Change the program in the previous exercise on page Exercise - Using a DO WHILE Loop from a DO WHILE to a DO UNTIL loop and achieve the same results. Remember that DO WHILE loops check for true expressions and DO UNTIL loops check for false expressions, which means their logical operators are often reversed.

ANSWER

Figure 25. Possible Solution
/******************************** REXX *******************************/
/* This program uses a DO UNTIL loop to keep track of window seats   */
/* in an 8-seat commuter airline.                                    */
/*********************************************************************/

  window_seats = 0        /* Initialize window seats to 0 */
  passenger = 0           /* Initialize passengers to 0   */

  DO UNTIL (passenger >= 8) | (window_seats = 4)

   /******************************************************************/
   /* Continue while the program has not yet read the responses of   */
   /* all 8 passengers and while all the window seats are not taken. */
   /******************************************************************/

    PULL window                /* Gets "Y" or "N" from input stream  */
    passenger = passenger + 1  /* Increase number of passengers by 1 */
    IF window = 'Y' THEN
       window_seats = window_seats + 1 /* Increase window seats by 1 */
    ELSE NOP
  END
  SAY window_seats 'window seats were assigned.'
  SAY passenger 'passengers were questioned.'

Combining Types of Loops

You can combine repetitive and conditional loops to create a compound loop. The following loop is set to repeat 10 times while the quantity is less than 50, at which point it stops.

quantity = 20
DO number = 1 TO 10 WHILE quantity < 50
  quantity = quantity + number
  SAY 'Quantity = 'quantity '  (Loop 'number')'
END

The result of this example is as follows:

Quantity = 21   (Loop 1)
Quantity = 23   (Loop 2)
Quantity = 26   (Loop 3)
Quantity = 30   (Loop 4)
Quantity = 35   (Loop 5)
Quantity = 41   (Loop 6)
Quantity = 48   (Loop 7)
Quantity = 56   (Loop 8)

You can substitute a DO UNTIL loop, change the comparison operator from < to >, and get the same results.

quantity = 20
DO number = 1 TO 10 UNTIL quantity > 50
  quantity = quantity + number
  SAY 'Quantity = 'quantity '  (Loop 'number')'
END

Nested DO Loops

Like nested IF...THEN...ELSE instructions, DO loops can contain other DO loops. A simple example follows:

DO outer = 1 TO 2
   DO inner = 1 TO 2
     SAY 'HIP'
   END
   SAY 'HURRAH'
END

The output from this example is:

HIP
HIP
HURRAH
HIP
HIP
HURRAH

If you need to leave a loop when a certain condition arises, use the LEAVE instruction followed by the name of the control variable of the loop. If the LEAVE instruction is for the inner loop, processing leaves the inner loop and goes to the outer loop. If the LEAVE instruction is for the outer loop, processing leaves both loops.

To leave the inner loop in the preceding example, add an IF...THEN...ELSE instruction that includes a LEAVE instruction after the IF instruction.

DO outer = 1 TO 2
   DO inner = 1 TO 2
     IF inner > 1 THEN
       LEAVE inner
     ELSE
       SAY 'HIP'
   END
   SAY 'HURRAH'
END

The result is as follows:

HIP
HURRAH
HIP
HURRAH

Exercises - Combining Loops

  1. What happens when the following program runs?
    DO outer = 1 TO 3
      SAY                   /* Produces a blank line */
      DO inner = 1 TO 3
        SAY 'Outer' outer 'Inner' inner
      END
    END
  2. Now what happens when the LEAVE instruction is added?
    DO outer = 1 TO 3
      SAY                   /* Produces a blank line */
      DO inner = 1 TO 3
        IF inner = 2 THEN
          LEAVE inner
        ELSE
          SAY 'Outer' outer 'Inner' inner
      END
    END

ANSWERS

  1. When this example runs, it produces the following:
    Outer 1  Inner 1
    Outer 1  Inner 2
    Outer 1  Inner 3
    
    Outer 2  Inner 1
    Outer 2  Inner 2
    Outer 2  Inner 3
    
    Outer 3  Inner 1
    Outer 3  Inner 2
    Outer 3  Inner 3
  2. The result is one line of output for each of the inner loops.
    Outer 1  Inner 1
    
    Outer 2  Inner 1
    
    Outer 3  Inner 1