Michael Coughlan
Page 14
88 CityCodeNotValid VALUE 0, 7 THRU 9.
Table 5-7 shows the Boolean value of the condition names for each value of CityCode.
86
Chapter 5 ■ Control StruCtureS: SeleCtion
Table 5-7. Results for Each Value of CityCode
Data Item / Condition Name
Data Value / Condition Name Result
CityCode
0
1
2
3
4
5
6
7 - 9
CityIsDublin
False
TRUE
False
False
False
False
False
False
CityIsLimerick
False
False
TRUE
False
False
False
False
False
CityIsCork
False
False
False
TRUE
False
False
False
False
CityIsGalway
False
False
False
False
TRUE
False
False
False
CityIsSligo
False
False
False
False
False
TRUE
False
False
CityIsWaterford
False
False
False
False
False
False
TRUE
False
UniversityCity
False
TRUE
TRUE
TRUE
TRUE
False
False
False
CityCodeNotValid
TRUE
False
False
False
False
False
False
TRUE
Values Can Be Alphabetic or Numeric
The list of values specified for a condition name can be numeric or alphabetic, as shown in Listing 5-3.
Listing 5-3. Multiple Condition Names with Overlapping Values
IDENTIFICATION DIVISION.
PROGRAM-ID. Listing5-3.
AUTHOR. Michael Coughlan.
DATA DIVISION.
WORKING-STORAGE SECTION.
01 InputChar PIC X.
88 Vowel VALUE "A","E","I","O","U".
88 Consonant VALUE "B" THRU "D", "F","G","H"
"J" THRU "N", "P" THRU "T"
"V" THRU "Z".
88 Digit VALUE "0" THRU "9".
88 ValidChar VALUE "A" THRU "Z", "0" THRU "9".
PROCEDURE DIVISION.
Begin.
DISPLAY "Enter a character :- " WITH NO ADVANCING
ACCEPT InputChar
IF ValidChar
DISPLAY "Input OK"
ELSE
DISPLAY "Invalid character entered"
END-IF
IF Vowel
DISPLAY "Vowel entered"
END-IF
IF Digit
DISPLAY "Digit entered"
END-IF
STOP RUN.
87
Chapter 5 ■ Control StruCtureS: SeleCtion
List Values Can Be Whole Words
Although I have used single characters in the examples so far, condition names are not restricted to values with only single characters. Whole words can be used if required, as shown in Listing 5-4.
Listing 5-4. Words as Value Items
IDENTIFICATION DIVISION.
PROGRAM-ID. Listing5-4.
AUTHOR. Michael Coughlan.
DATA DIVISION.
WORKING-STORAGE SECTION.
01 MakeOfCar PIC X(10).
88 VolksGroup VALUE "skoda", "seat",
"audi", "volkswagen".
88 GermanMade VALUE "volkswagen", "audi",
"mercedes", "bmw",
"porsche".
PROCEDURE DIVISION.
Begin.
DISPLAY "Enter the make of car - " WITH NO ADVANCING
ACCEPT MakeOfCar
IF VolksGroup AND GermanMade
DISPLAY "Your car is made in Germany by the Volkswagen Group."
ELSE
IF VolksGroup
DISPLAY "Your car is made by the Volkswagen Group."
END-IF
IF GermanMade
DISPLAY "Your car is made in Germany."
END-IF
END-IF
STOP RUN.
Using Condition Names Correctly
A condition name should express the true condition being tested. It should not express the test that sets the condition name to true. For instance, in Listing 5-2, a value of 1 in the data item CityCode indicates that the city is Dublin, a value of 2 means the city is Limerick, and so on. These condition names allow you to replace conditions such as IF CityCode = 1
and
IF CityCode = 2
with the more meaningful statements
IF CityIsDublin
and
IF CityIsLimerick.
88
Chapter 5 ■ Control StruCtureS: SeleCtion
Many COBOL beginners would use condition names such as CityCodeIs1 or CityCodeIs2 to express these
conditions. Those condition names are meaningless because they express the value that makes the condition name true instead of expressing the meaning or significance of CityCode containing a particular value. A value of 1 or 2 in CityCode is how you detect that the city is Dublin or Limerick. It is not the value of CityCode that ultimately interests you; it is the meaning or significance of that value.
Example Program
Listing 5-5 is a small but complete program showing how the BritishCountry and CurrencyIsPound condition names might be defined and used. There is something unusual about this example, however. What do you imagine happens to the associated data item when the CurrencyIsPound condition name is set to true?
Listing 5-5. Detecting BritishCountry and Setting and Using CurrencyIsPound
IDENTIFICATION DIVISION.
PROGRAM-ID. Listing5-5.
AUTHOR. Michael Coughlan.
DATA DIVISION.
WORKING-STORAGE SECTION.
01 CountryCode PIC 999 VALUE ZEROS.
88 BritishCountry VALUES 3, 7, 10, 15.
01 CurrencyCode PIC 99 VALUE ZEROS.
88 CurrencyIsPound VALUE 14.
88 CurrencyIsEuro VALUE 03.
88 CurrencyIsDollar VALUE 28.
PROCEDURE DIVISION.
Begin.
DISPLAY "Enter the country code :- " WITH NO ADVANCING
ACCEPT CountryCode
IF BritishCountry THEN
SET CurrencyIsPound TO TRUE
END-IF
IF CurrencyIsPound THEN
DISPLAY "Pound sterling used in this country"
ELSE
DISPLAY "Country does not use sterling"
END-IF
STOP RUN.
89
Chapter 5 ■ Control StruCtureS: SeleCtion
Setting a Condition Name to True
In Listing 5-5, the SET verb is used to set CurrencyIsPound to true. The way condition names normally work is that a value placed into the associated data item automatically sets the condition names that list that value to true. When a condition name is manually set to true using the SET verb, the value listed for that condition name is forced into the associated data item. In Listing 5-5, when the SET verb is used to set CurrencyIsPound to true, the value 14 is forced into CurrencyCode.
When a condition name that lists more than one value is set to true, the first of the values listed is forced into the associated data item. For instance, if BritishCountry w
ere set to true, then the value 3 would be forced into CountryCode.
■ ISO 2002 in standard anS 85 CoBol, the SET verb cannot be used to set a condition name to false. this can be done in iSo 2002 CoBol, but in that case the level 88 entry must be extended to include the phrase
When Set to FalSe iS literalValue$#
To set a condition name to true, you use the SET verb. You might think, therefore, that the SET verb is used only for manipulating condition names. But the SET verb is a strange fish. It is used for a variety of unconnected purposes.
For instance, it is used to set a condition name to true. It is used to increment or decrement an index item. It is used to assign the value of an index to an ordinary data item and vice versa. It is used to set On or Off the switches associated with mnemonic names. In ISO 2002 COBOL, it is used to manipulate pointer variables (yes, ISO 2002 COBOL has pointers) and object references. It is often the target of implementer extensions.
Because the SET verb has so many different unrelated uses, instead of dealing with it as a single topic I discuss each format as you examine the construct to which it is most closely related.
SET Verb Metalanguage
Figure 5-7 shows the metalanguage for the version of the SET verb that is used to set a condition name to true. When the SET verb is used to set a condition name, the first condition value specified after the VALUE clause in the definition is moved to the associated data item. So setting the condition name to true changes the value of the associated data item. This can lead to some interesting data-manipulation opportunities.
Figure 5-7. Metalanguage for the SET verb condition name version
In summary, any operation that changes the value of the data item may change the status of the associated
condition names, and any operation that changes the status of a condition name will change the value of its associated data item.
SET Verb Examples
In ANS 85 COBOL, you cannot use the SET verb to set a condition name to false. But you can work around this restriction. Consider Example 5-9. This is more a pattern for processing sequential files than real COBOL code, but it serves to illustrate the point.
90
Chapter 5 ■ Control StruCtureS: SeleCtion
Example 5-9. Setting the EndOfFile Condition Name
01 EndOfFileFlag PIC 9 VALUE ZERO.
88 EndOfFile VALUE 1.
88 NotEndOfFile VALUE 0.
: : : : : : : :
READ InFile
AT END SET EndOfFile TO TRUE
END-READ
PERFORM UNTIL EndOfFile
Process Record
READ InFile
AT END SET EndOfFile TO TRUE
END-READ
END-PERFORM
Set NotEndOfFile TO TRUE.
In this example, the condition name EndOfFile has been set up to flag that the end of the file has been
reached. You cannot set EndOfFile to false, but you can work around this problem by setting another condition name associated with the same data item to true. When EndOfFile is set to true, 1 is forced into the data item EndOfFileFlag, and this automatically sets NotEndOfFile to false. Similarly, when NotEndOfFile is set to true, 0 is forced into EndOfFileFlag, and this automatically sets EndOfFile to false.
Design Pattern: Reading a Sequential File
Because this is your first look at how COBOL processes sequential (as opposed to direct access) files, it might be useful to preview some of the material in Chapter 7 by providing a brief explanation now. The READ verb copies a record (a discrete package of data) from the file on backing storage and places it into an area of memory set up to store it. When the READ attempts to read a record from the file but discovers that the end of the file has been reached, it activates the AT END clause and executes whatever statements follow that clause.
Example 5-9 shows the pattern you generally use to process a stream of items when you can only discover that you have reached the end of the stream by attempting to read the next item. In this pattern, a loop processes the data in the stream. Outside the loop, you have a read to get the first item in the stream or to discover that the stream is empty. Inside the loop, you have statements to process the stream item and get the next item in the stream.
Why do you have this strange arrangement? The chief reason is that this arrangement allows you to place the read at the end of the loop body so that as soon as the end of the file is detected, the loop can be terminated. If you used a structure such as
PERFORM UNTIL EndOfFile
READ InFile
AT END SET EndOfFile TO TRUE
END-READ
Process Record
END-PERFORM
then when the end of file was detected, the program would still attempt to process the nonexistent record.
Of course, the last valid record would still be in memory, so that last record would be processed twice. Many COBOL
beginners make this programming error.
91
Chapter 5 ■ Control StruCtureS: SeleCtion
Many beginners attempt to solve this problem by only processing the record if the end of file has not been PERFORM UNTIL EndOfStudentFile
detected. They use a structure like this:
DISPLAY StudentName SPACE StudentId SPACE CourseCode
READ StudentFile
PERFORM UNTIL EndOfFile
AT END SET EndOfStudentFile TO TRUE
READ InFile
END-READ
AT END SET EndOfFile TO TRUE
END-PERFORM
END-READ
CLOSE StudentFile
IF NOT EndOfFile
STOP RUN.
Process Record
END-IF
In Listing 5-6, the condition name EndOfStudentFile is associated with the group item (which also happens to END-PERFORM
be a record) StudentDetails. When EndOfStudentFile is set to true, the entire StudentDetails area of storage (38 characters) is flushed with highest possible character value.
The problem with this arrangement is that the IF statement will be executed for every record in the file. Because This arrangement has two major advantages:
COBOL often deals with very large data sets, this could amount to the execution of millions, maybe even hundreds
•
of millions, of unnecessary statements. It is more elegant and more efficient to use what is called the read-ahead The EndOfStudentFile condition name is kept with its associated file.
technique. The read-ahead has a read outside the loop to get the first record and a read inside the loop to get the
• Flushing the record with HIGH-VALUES at the end of the file eliminates the need for an explicit
remaining records. This approach has the added advantage of allowing the empty file condition to be detected before condition when doing a key-matching update of a sequential file.
the loop is entered.
Group Item Condition Names
Condition Name Tricks
In Example 5-9, stand-alone condition names were used to flag the end-of-file condition. Because the EndOfFile When you become aware that setting a condition name forces a value into the associated data item, it is tempting to condition name is closely related to the file, it would be better if the declaration of the condition name were kept with see just how far you can take this idea. Listing 5-7 takes advantage of the way condition names work to automatically the file declaration. The example program in Listing 5-6 shows how that might be done. It also demonstrates how a move an appropriate error message into a message buffer. The program is just a stub to test this error-messaging idea; condition name can be used with a group (as opposed to elementary) data item.
it doesn’t actually validate the date. Instead, the user manually enters one of the codes that would be returned by the date-validation routine.
Listing 5-6. Reading a File and Setting the EndOfStudentFile Condition Name
Listing 5-7. Using Condition Names to Se
t Up a Date-Validation Error Message
IDENTIFICATION DIVISION.
PROGRAM-ID. Listing5-6.
IDENTIFICATION DIVISION.
AUTHOR. Michael Coughlan.
PROGRAM-ID. Listing5-7.
ENVIRONMENT DIVISION.
AUTHOR. Michael Coughlan.
INPUT-OUTPUT SECTION.
FILE-CONTROL.
DATA DIVISION.
SELECT StudentFile ASSIGN TO "Listing5-6-TData.Dat"
WORKING-STORAGE SECTION.
ORGANIZATION IS LINE SEQUENTIAL.
01 ValidationReturnCode PIC 9.
88 DateIsOK VALUE 0.
DATA DIVISION.
88 DateIsInvalid VALUE 1 THRU 8.
FILE SECTION.
88 ValidCodeSupplied VALUE 0 THRU 8.
FD StudentFile.
01 StudentDetails.
01 DateErrorMessage PIC X(35) VALUE SPACES.
88 EndOfStudentFile VALUE HIGH-VALUES.
88 DateNotNumeric VALUE "Error - The date must be numeric".
02 StudentId PIC X(8).
88 YearIsZero VALUE "Error - The year cannot be zero".
02 StudentName PIC X(25).
88 MonthIsZero VALUE "Error - The month cannot be zero".
02 CourseCode PIC X(5).
88 DayIsZero VALUE "Error - The day cannot be zero".
88 YearPassed VALUE "Error - Year has already passed".
PROCEDURE DIVISION.
88 MonthTooBig VALUE "Error - Month is greater than 12".
Begin.
88 DayTooBig VALUE "Error - Day greater than 31".
OPEN INPUT StudentFile
88 TooBigForMonth VALUE "Error - Day too big for this month".
READ StudentFile
AT END SET EndOfStudentFile TO TRUE
END-READ
92
Chapter 5 ■ Control StruCtureS: SeleCtion