Michael Coughlan
Page 18
UNTIL Letter = "s"
Notes on PERFORM..UNTIL
If you use the WITH TEST BEFORE phrase, PERFORM behaves like a while loop and the condition is tested before the loop body is entered. If you use the WITH TEST AFTER phrase, PERFORM behaves like a do..while loop and the condition is tested after the loop body is entered. The WITH TEST BEFORE phrase is the default and so is rarely explicitly stated.
How PERFORM..UNTIL Works
Although flowcharts are generally derided as a program-design tool, they are very useful for showing flow of control.
The flowcharts in Figure 6-4 and Figure 6-5 show how the WITH TEST BEFORE and WITH TEST AFTER variations of PERFORM..UNTIL work.
Figure 6-4. Pre-test loop
119
Chapter 6 ■ Control StruCtureS: IteratIon
Figure 6-5. Post-test loop
Note that the terminating condition is checked only at the beginning of each iteration (PERFORM WITH TEST
BEFORE) or at the end of each iteration (PERFORM WITH TEST AFTER). If the terminating condition is reached in the middle of the iteration, the rest of the loop body is still executed. The terminating condition cannot be checked until all the statements in the loop body have been executed. COBOL has no equivalent of the break command that allows control to break out of a loop without satisfying the terminating condition.
PERFORM..VARYING
PERFORM..VARYING (see Figure 6-6) is the final format of the PERFORM verb.
Figure 6-6. Metalanguage for PERFORM format 4
120
Chapter 6 ■ Control StruCtureS: IteratIon
PERFORM..VARYING is used to implement counting iteration. It is similar to the for construct in languages like Pascal, C, and Java. However, there are some differences:
• Most languages permit only one counting variable per loop instruction. COBOL allows up to
three. Why only three? Before ANS 85 COBOL, tables were allowed only a maximum of three
dimensions, and PERFORM..VARYING was used to process them.
• Both pre-test and post-test variations of counting iteration are supported.
• The terminating condition does not have to involve the counting variable. For instance:
PERFORM CountRecordsInFile
VARYING RecordCount FROM 1 BY 1 UNTIL EndOfFile
Notes on PERFORM..VARYING
The inline version of PERFORM..VARYING cannot take the AFTER phrase. This means only one counter may be used with an inline PERFORM.
When you use more than one counter, the counter after the VARYING phrase is the most significant, that after the first AFTER phrase is the next most significant, and the last counter is the least significant. Just like the values in an odometer, the least-significant counter must go through all its values and reach its terminating condition before the next-most-significant counter can be incremented.
The item after the word FROM is the starting value of the counter (initialization). An index item is a special data item. Index items are examined when tables are discussed.
The item after the word BY is the step value of the counter (increment). It can be negative or positive. If you use a negative step value, the counter should be signed (PIC S99, for instance). When the iteration ends, the counters retain their terminating values.
The WITH TEST BEFORE phrase is the default and so is rarely specified.
How PERFORM..VARYING Works
Figure 6-7 shows the flowchart for PERFORM..VARYING..AFTER. Because there is no WITH TEST phrase, WITH TEST
BEFORE is assumed. The table shows the number of times the loop body is processed and the value of each counter as displayed in the loop body. The terminating values of the counters are also given.
121
Chapter 6 ■ Control StruCtureS: IteratIon
Figure 6-7. PERFORM..VARYING..AFTER
Note how the counter Idx2 must go through all its values and reach its terminating value before the Idx1 counter is incremented. An easy way to understand this is to think of it as an odometer. In an odometer, the units counter must go through all its values 0–9 before the tens counter is incremented.
Many of the example programs in this book provide a gentle preview of language elements to come. Listing 6-3
previews edited pictures. Examine the description of PrnRepCount provided by its picture, and review the output produced. Can you figure out how the edited picture works? Why do you think it was necessary to move RepCount to PrnRepCount? Why not just use the edited picture with RepCount?
Listing 6-3. Using PERFORM..VARYING for Counting
IDENTIFICATION DIVISION.
PROGRAM-ID. Listing6-3.
AUTHOR. Michael Coughlan.
DATA DIVISION.
WORKING-STORAGE SECTION.
01 RepCount PIC 9(4).
01 PrnRepCount PIC Z,ZZ9.
01 NumberOfTimes PIC 9(4) VALUE 1000.
PROCEDURE DIVISION.
Begin.
PERFORM VARYING RepCount FROM 0 BY 50
UNTIL RepCount = NumberOfTimes
MOVE RepCount TO PrnRepCount
DISPLAY "counting " PrnRepCount
END-PERFORM
MOVE RepCount TO PrnRepCount
DISPLAY "If I have told you once, "
DISPLAY "I've told you " PrnRepCount " times."
STOP RUN.
122
Chapter 6 ■ Control StruCtureS: IteratIon
■ Answer RepCount can’t be an edited picture because an edited picture contains non-numeric characters (spaces, in this case), and you can’t do computations with non-numeric characters. You have to do the computations with the numeric RepCount and then move it to the edited field PrnRepCount when you want it printed.
The explanation of the operation of PERFORM..VARYING..AFTER compares the construct to an odometer.
The program in Listing 6-4 reinforces this idea by using PERFORM..VARYING to emulate an odometer. The program uses both out-of-line and inline versions of PERFORM..VARYING. Notice that when the inline variation is used, you cannot have an AFTER phrase but must instead use nested PERFORMs just as in Java or Pascal. Because the output is voluminous, only the final part is shown here.
Listing 6-4. Odometer Simulation
IDENTIFICATION DIVISION.
PROGRAM-ID. Listing6-4.
AUTHOR. Michael Coughlan.
DATA DIVISION.
WORKING-STORAGE SECTION.
01 Counters.
02 HundredsCount PIC 99 VALUE ZEROS.
02 TensCount PIC 99 VALUE ZEROS.
02 UnitsCount PIC 99 VALUE ZEROS.
01 Odometer.
02 PrnHundreds PIC 9.
02 FILLER PIC X VALUE "-".
02 PrnTens PIC 9.
02 FILLER PIC X VALUE "-".
02 PrnUnits PIC 9.
PROCEDURE DIVISION.
Begin.
DISPLAY "Using an out-of-line Perform".
PERFORM CountMileage
VARYING HundredsCount FROM 0 BY 1 UNTIL HundredsCount > 9
AFTER TensCount FROM 0 BY 1 UNTIL TensCount > 9
AFTER UnitsCount FROM 0 BY 1 UNTIL UnitsCount > 9
DISPLAY "Now using in-line Perform"
PERFORM VARYING HundredsCount FROM 0 BY 1 UNTIL HundredsCount > 9
PERFORM VARYING TensCount FROM 0 BY 1 UNTIL TensCount > 9
PERFORM VARYING UnitsCount FROM 0 BY 1 UNTIL UnitsCount > 9
MOVE HundredsCount TO PrnHundreds
MOVE TensCount TO PrnTens
MOVE UnitsCount TO PrnUnits
DISPLAY "In - " Odometer
END-PERFORM
END-PERFORM
END-PERFORM
123
Chapter 6 ■ Control StruCtureS: IteratIon
DISPLAY "End of odometer simulation."
STOP RUN.
CountMileage.
MOVE HundredsCount TO PrnHundreds
MOVE TensCount TO PrnTens
MOVE UnitsCount TO PrnUnits
DISPLAY "Out
- " Odometer.
You might be wondering why the word FILLER is used in the description of Odometer. In COBOL, instead of
having to make up dummy names, you can use FILLER when you need to reserve an area of storage but are never going to refer to it by name. For instance, in the data item Odometer, you want to separate the digits with hyphens, so you declare a character of storage for each hyphen and assign it the value -. But you will never refer to this part of Odometer by name. The hyphens only have significance as part of the group item.
Summary
This chapter examined the iteration constructs supported by COBOL. You learned the differences between COBOL’s version of pre-test and post-test iteration and those of other languages. I contrasted counting iteration in its PERFORM..VARYING..AFTER implementation, which has both pre-test and post-test variations, with the offerings of other languages. You also explored the ability to create open subroutines in COBOL, and I provided a rationale for using them.
LaNGUaGe KNOWLeDGe eXerCISe
unleash your 2B pencil. It is exercise time again.
In the columns provided, write out what you would expect to be displayed on the computer screen if you ran the program shown in listing 6-5. use the Continue run column to show what happens after the statement DISPLAY
"STOP RUN should be here". has been executed.
Listing 6-5. Program to Test Your Knowledge of the PERFORM Verb
DATA DIVISION.
Start Run
Continue Run
IDENTIFICATION DIVISION.
PROGRAM-ID. Listing6-5.
AUTHOR. Michael Coughlan.
DATA DIVISION.
WORKING-STORAGE SECTION.
01 LoopCount PIC 9 VALUE 1.
01 LoopCount2 PIC 9 VALUE 1.
124
Chapter 6 ■ Control StruCtureS: IteratIon
PROCEDURE DIVISION.
Start Run
Continue Run
P1.
DISPLAY "S-P1"
PERFORM P2
PERFORM P3
MOVE 7 TO LoopCount
PERFORM VARYING LoopCount
FROM 1 BY 1 UNTIL LoopCount = 2
DISPLAY "InLine - " LoopCount
END-PERFORM
DISPLAY "E-P1".
DISPLAY "STOP RUN should be here".
P2.
DISPLAY "S-P2"
PERFORM P5 WITH TEST BEFORE VARYING LoopCount
FROM 1 BY 1 UNTIL LoopCount > 2
DISPLAY "E-P2".
P3.
DISPLAY "S-P3"
PERFORM P5
PERFORM P6 3 TIMES
DISPLAY "E-P3".
P4.
DISPLAY "P4-" LoopCount2
ADD 1 TO LoopCount2.
P5.
DISPLAY "S-P5"
DISPLAY LoopCount "-P5-" LoopCount2
PERFORM P4 WITH TEST AFTER UNTIL LoopCount2 > 2
DISPLAY "E-P5".
P6.
DISPLAY "P6".
prOGraMMING eXerCISe 1
In this programming exercise, you amend the program you wrote for the programming exercise in Chapter 5
(or amend the answer provided in listing 5-11). that programming exercise required you to create a calculator program, but the program halted after only one calculation.
amend the program so it runs until the user enters the letter s instead of an operator (+ - / *). the result of running the program is shown in the sample output in example 6-9.
125
Chapter 6 ■ Control StruCtureS: IteratIon
Example 6-9. Sample Run (User Input Shown in Bold)
Enter an arithmetic operator (+ - * /) (s to end) : *
Enter a single digit number - 4
Enter a single digit number - 5
Result is = 20.00
Enter an arithmetic operator (+ - * /) (s to end) : +
Enter a single digit number - 3
Enter a single digit number - 3
Result is = 06.00
Enter an arithmetic operator (+ - * /) (s to end) : -
Enter a single digit number - 5
Enter a single digit number - 3
Result is = -02.00
Enter an arithmetic operator (+ - * /) (s to end) : /
Enter a single digit number - 5
Enter a single digit number - 3
Result is = 00.60
Enter an arithmetic operator (+ - * /) (s to end) : s
End of calculations
prOGraMMING eXerCISe 2
Write a program that gets the user’s name and a countdown value from the keyboard and then displays a
countdown before displaying the name that was entered. use PERFORM..VARYING to create the countdown.
the program should produce results similar to those shown in example 6-10. For purposes of illustration,
user input is in bold.
Example 6-10. Sample Run
Enter your name :- Mike Ryan
Enter the count-down start value :- 05
Getting ready to display your name.
05
04
03
02
01
Your name is Mike Ryan
126
Chapter 6 ■ Control StruCtureS: IteratIon
LaNGUaGe KNOWLeDGe eXerCISe—aNSWer
DATA DIVISION.
Start Run
Continue Run
IDENTIFICATION DIVISION.
S-P1
S-P2
PROGRAM-ID. Listing6-5.
S-P2
S-P5
AUTHOR. Michael Coughlan.
S-P5
1-P5-5
DATA DIVISION.
1-P5-1
P4-5
WORKING-STORAGE SECTION.
P4-1
E-P5
01 LoopCount PIC 9 VALUE 1.
P4-2
S-P5
01 LoopCount2 PIC 9 VALUE 1.
E-P5
2-P5-6
S-P5
P4-6
PROCEDURE DIVISION.
2-P5-3
E-P5
P1.
P4-3
E-P2
DISPLAY "S-P1"
E-P5
S-P3
PERFORM P2
E-P2
S-P5
PERFORM P3
S-P3
3-P5-7
MOVE 7 TO LoopCount
S-P5
P4-7
PERFORM VARYING LoopCount
3-P5-4
E-P5
FROM 1 BY 1 UNTIL LoopCount = 2
P4-4
P6
DISPLAY "InLine - " LoopCount
E-P5
P6
END-PERFORM
P6
P6
DISPLAY "E-P1".
P6
E-P3
DISPLAY "STOP RUN should be here".
P6
P4-8
E-P3
S-P5
P2.
InLine - 1
3-P5-9
DISPLAY "S-P2"
E-P1
P4-9
PERFORM P5 WITH TEST BEFORE VARYING LoopCount
STOP RUN should be here
E-P5
FROM 1 BY 1 UNTIL LoopCount > 2
P6
DISPLAY "E-P2".
P3.
DISPLAY "S-P3"
PERFORM P5
PERFORM P6 3 TIMES
DISPLAY "E-P3".
P4.
DISPLAY "P4-" LoopCount2
ADD 1 TO LoopCount2.
P5.
DISPLAY "S-P5"
DISPLAY LoopCount "-P5-" LoopCount2
PERFORM P4 WITH TEST AFTER UNTIL LoopCount2 > 2
DISPLAY "E-P5".
P6.
DISPLAY "P6".
127
Chapter 6 ■ Control StruCtureS: IteratIon
prOGraMMING eXerCISe 1—aNSWer
Listing 6-6. The Full Calculator Program
IDENTIFICAT
ION DIVISION.
PROGRAM-ID. Listing6-6.
AUTHOR. Michael Coughlan.
*> Continually calculates using two numbers and an operator
*> Ends when "s" is entered instead of an operator.
DATA DIVISION.
WORKING-STORAGE SECTION.
01 Num1 PIC 9 VALUE ZERO.
01 Num2 PIC 9 VALUE ZERO.
01 Result PIC --9.99 VALUE ZEROS.
01 Operator PIC X VALUE SPACE.
88 ValidOperator VALUES "*", "+", "-", "/", "s".
88 EndOfCalculations VALUE "s".
PROCEDURE DIVISION.
Begin.
PERFORM GetValidOperator UNTIL ValidOperator
PERFORM UNTIL EndOfCalculations OR NOT ValidOperator
PERFORM GetTwoNumbers
EVALUATE Operator
WHEN "+" ADD Num2 TO Num1 GIVING Result
WHEN "-" SUBTRACT Num2 FROM Num1 GIVING Result
WHEN "*" MULTIPLY Num1 BY Num2 GIVING Result
WHEN "/" DIVIDE Num1 BY Num2 GIVING Result ROUNDED
END-EVALUATE
DISPLAY "Result is = ", Result
MOVE SPACE TO Operator
PERFORM GetValidOperator UNTIL ValidOperator
END-PERFORM
DISPLAY "End of calculations"
STOP RUN.
GetValidOperator.
DISPLAY "Enter an arithmetic operator (+ - * /) (s to end) : "
WITH NO ADVANCING
ACCEPT Operator.
GetTwoNumbers.
DISPLAY "Enter a single digit number - " WITH NO ADVANCING
ACCEPT Num1
DISPLAY "Enter a single digit number - " WITH NO ADVANCING
ACCEPT Num2.
128
Chapter 6 ■ Control StruCtureS: IteratIon
prOGraMMING eXerCISe 2—aNSWer
Listing 6-7. Uses PERFORM..VARYING to Display a Countdown from XX to 01
IDENTIFICATION DIVISION.
PROGRAM-ID. Listing6-7.
AUTHOR. Michael Coughlan.
DATA DIVISION.
WORKING-STORAGE SECTION.
01 UserName PIC X(20).
01 StartValue PIC 99 VALUE ZEROS.
01 Countdown PIC 99 VALUE ZEROS.
PROCEDURE DIVISION.
DisplayCountdown.
DISPLAY "Enter your name :- " WITH NO ADVANCING
ACCEPT UserName
DISPLAY "Enter the count-down start value :- " WITH NO ADVANCING
ACCEPT StartValue