Michael Coughlan
Page 40
END-IF
WHEN CountryCode(Cidx) = FUNCTION UPPER-CASE(CountryCodeIn)
DISPLAY CountryCodeIn " is " CountryName(Cidx)
END-SEARCH
DISPLAY SPACES
END-PERFORM
END-PERFORM
STOP RUN.
318
Chapter 13 ■ SearChing tabular Data
LoadCountryCodeTable.
* Loads table with HIGH-VALUES so the SEARCH ALL works when the table is partially loaded
MOVE HIGH-VALUES TO CountryCodeTable
OPEN INPUT CountryCodeFile
READ CountryCodeFile
AT END SET EndOfCountryCodeFile TO TRUE
END-READ
PERFORM VARYING Cidx FROM 1 BY 1 UNTIL EndOfCountryCodeFile
MOVE CountryCodeRec TO Country(Cidx)
READ CountryCodeFile
AT END SET EndOfCountryCodeFile TO TRUE
END-READ
END-PERFORM
CLOSE CountryCodeFile.
Variable-Length Tables
All the examples you have seen so far have used fixed-length tables. You may have wondered if COBOL supports variable-length tables. The answer is that it does support variable-length tables—of a sort.
You can declare variable-length tables using extensions to the OCCURS clause, as shown in Figure 13-10. Although you can dynamically alter the number of element occurrences in a variable-length table, the amount of storage allocated is fixed. It is defined by the value of LargestSize#i and is assigned at compile time. Standard COBOL has no mechanism for dynamically changing the amount of storage allocated to a table.
Figure 13-10. Full OCCURS metalanguage, including the entries required for variable-length tables and the SEARCH
and SEARCH ALL verbs
Note that this format of the OCCURS clause may only be used to vary the number of elements in the first dimension of a table.
An example declaration is shown in Example 13-6.
Example 13-6. Example Variable-Length Table Declaration
01 BooksReservedTable.
02 BookId PIC 9(7) OCCURS 1 TO 10
DEPENDING ON NumOfReservations.
The program in Listing 13-5 fills the table with HIGH-VALUES in order to get SEARCH ALL to work correctly, because the table was only partially populated (250 elements in size but only 243 countries). You could achieve the same effect by declaring the table as a variable-length table.
Although variable-length tables are not dynamic (the storage allocated is defined by the table’s maximum size), they are treated by COBOL verbs as if they were dynamic. For instance, when you use SEARCH or SEARCH ALL with the table, only the elements between SmallestSize#i and TableSize#i are interrogated.
319
Chapter 13 ■ SearChing tabular Data
Listing 13-6 revisits the program from Listing 13-5 to emphasize these points.
Listing 13-6. SEARCH ALL Used with a Variable-Length Table
IDENTIFICATION DIVISION.
PROGRAM-ID. Listing13-6.
AUTHOR. Michael Coughlan.
ENVIRONMENT DIVISION.
INPUT-OUTPUT SECTION.
FILE-CONTROL.
SELECT CountryCodeFile ASSIGN TO "Listing13-6.dat"
ORGANIZATION IS LINE SEQUENTIAL.
DATA DIVISION.
FILE SECTION.
FD CountryCodeFile.
01 CountryCodeRec.
88 EndOfCountryCodeFile VALUE HIGH-VALUES.
02 CountryCodeCF PIC XX.
02 CountryNameCF PIC X(25).
WORKING-STORAGE SECTION.
01 CountryCodeTable.
02 Country OCCURS 1 TO 300 TIMES
DEPENDING ON NumberOfCountries
ASCENDING KEY IS CountryCode
INDEXED BY Cidx.
03 CountryCode PIC XX.
03 CountryName PIC X(25).
01 CountryCodeIn PIC XX.
88 EndOfInput VALUE SPACES.
01 FILLER PIC 9 VALUE ZERO.
88 ValidCountryCode VALUE 1.
01 NumberOfCountries PIC 999.
PROCEDURE DIVISION.
Begin.
PERFORM LoadCountryCodeTable
PERFORM WITH TEST AFTER UNTIL EndOfInput
PERFORM WITH TEST AFTER UNTIL ValidCountryCode OR EndOfInput
DISPLAY "Enter a country code (space to stop) :- "
WITH NO ADVANCING
ACCEPT CountryCodeIn
PERFORM SearchCountryCodeTable
DISPLAY SPACES
END-PERFORM
END-PERFORM
320
Chapter 13 ■ SearChing tabular Data
MOVE 244 TO NumberOfCountries
MOVE "ZZ" TO CountryCodeIn
PERFORM SearchCountryCodeTable
STOP RUN.
SearchCountryCodeTable.
SEARCH ALL Country
AT END IF NOT EndOfInput
DISPLAY "Country code " CountryCodeIn " is not valid"
END-IF
WHEN CountryCode(Cidx) = FUNCTION UPPER-CASE(CountryCodeIn)
DISPLAY CountryCodeIn " is " CountryName(Cidx)
END-SEARCH.
LoadCountryCodeTable.
OPEN INPUT CountryCodeFile
READ CountryCodeFile
AT END SET EndOfCountryCodeFile TO TRUE
END-READ
PERFORM VARYING NumberOfCountries FROM 1 BY 1 UNTIL EndOfCountryCodeFile
MOVE CountryCodeRec TO Country(NumberOfCountries)
READ CountryCodeFile
AT END SET EndOfCountryCodeFile TO TRUE
END-READ
END-PERFORM
MOVE "ZZ **** FOUND ****" TO Country(244)
CLOSE CountryCodeFile.
The program in Listing 13-6 is the same as Listing 13-5, with the following changes:
• Variable-length tables are used. When the country data is loaded into the table from the file,
the table increases in size as each record is read (see VARYING NumberOfCountries).
• Once the table has been loaded from the file, the value "ZZ **** FOUND ****" is loaded
into element 244. The purpose of this is to prove that SEARCH ALL recognizes the table size
specified in NumberOfCountries.
• In this program, I moved SEARCH ALL to its own paragraph because I need to use it in two
different parts of the program and I don’t want to repeat the code.
• When the program runs, the user enters a number of country codes, and the country names
are returned. Note that this all works correctly even though the table has not had HIGH-VALUES
moved to it.
• Then user enters ZZ. This is the country code of the entry I placed beyond the end of the table (as identified by NumberOfCountries). SEARCH ALL reports that it can’t find this country code.
• When the loop exits, the program increases NumberOfCountries to 244, and the search is
attempted again. This time SEARCH ALL does find the ZZ country code, because this time the
code is the table.
321
Chapter 13 ■ SearChing tabular Data
Summary
This chapter examined SEARCH and SEARCH ALL, the COBOL verbs that allow you to search tabular data. The chapter introduced the INDEXED BY and KEY IS extensions to the OCCURS clause. These extensions are required when you want to use SEARCH and SEARCH ALL to search a table. You saw how to use SEARCH for linear searches of single-dimension tables and how, by controlling one of the indexes yourself, you can even use SEARCH to search a multidimensional table. The chapter showed how a binary search works and demonstrated how to use SEARCH ALL to search a table.
Finally, you were introduced to the topic of variable-length tables and learned to declare and use them.
The next chapter introduces the SORT and MERGE verbs. SORT is generally used to sort files, but it may also be used to sort a table. As I noted when discussing sequential files in Chapter 7, many operations on sequential files are not p
ossible unless the files are ordered. For this reason, many programs begin by sorting the file into the required order.
prOGraMMING eXerCISe 1
prepare your 2b pencil; it’s exercise time again. in this program, you will use your knowledge of variable-length tables and the SEARCH verb.
a program is required that will report the frequency of all the words in a document. to make the problem easier, the document has been split into individual words, one word per record. the program should be able to report on a maximum of 1,000 words.
the document words are held in an unordered sequential file called DocWords.dat. each record has the following description:
Field
Type
Length
Value
Word
X
20
-
Write a program to read a file of document words and produce a report that shows the top ten words in
descending order of frequency. the report template is as follows:
Top Ten Words In Document
Pos Occurs Document Word
1. XXX XXXXXXXXXXXXXXXXXXXX
2. XXX XXXXXXXXXXXXXXXXXXXX
3. XXX XXXXXXXXXXXXXXXXXXXX
4. XXX XXXXXXXXXXXXXXXXXXXX
5. XXX XXXXXXXXXXXXXXXXXXXX
6. XXX XXXXXXXXXXXXXXXXXXXX
7. XXX XXXXXXXXXXXXXXXXXXXX
8. XXX XXXXXXXXXXXXXXXXXXXX
9. XXX XXXXXXXXXXXXXXXXXXXX
10. XXX XXXXXXXXXXXXXXXXXXXX
322
Chapter 13 ■ SearChing tabular Data
prOGraMMING eXerCISe 2
the task in this exercise is to write a program that accepts ten numbers from the user, places them in a table, and then detects and reports on the following states:
• no zeros found in the table
• Only one zero found in the table
• two zeros found, but no numbers between the two zeros
• two zeros, and between them an even number of non-zeros
• two zeros, and between them an odd number of non-zeros
prOGraMMING eXerCISe 1: aNSWer
Listing 13-7. Program to Find the Top Ten Words in a Document
IDENTIFICATION DIVISION.
PROGRAM-ID. Listing13-7.
AUTHOR. Michael Coughlan.
ENVIRONMENT DIVISION.
INPUT-OUTPUT SECTION.
FILE-CONTROL.
SELECT DocWordsFile ASSIGN TO "Listing13-7.DAT"
ORGANIZATION IS LINE SEQUENTIAL.
DATA DIVISION.
FILE SECTION.
FD DocWordsFile.
01 WordIn PIC X(20).
88 EndOfDocWordsFile VALUE HIGH-VALUES.
WORKING-STORAGE SECTION.
01 WordFreqTable.
02 Word OCCURS 0 TO 2000 TIMES
DEPENDING ON NumberOfWords
INDEXED BY Widx.
03 WordFound PIC X(20).
03 WordFreq PIC 9(3).
01 TopTenTable.
02 WordTT OCCURS 11 TIMES
INDEXED BY TTidx.
03 WordFoundTT PIC X(20) VALUE SPACES.
03 WordFreqTT PIC 9(3) VALUE ZEROS.
01 NumberOfWords PIC 9(4) VALUE ZERO.
323
Chapter 13 ■ SearChing tabular Data
01 ReportHeader PIC X(27) VALUE " Top Ten Words In Document".
01 SubjectHeader PIC X(29) VALUE "Pos Occurs Document Word".
01 DetailLine.
02 PrnPos PIC Z9.
02 FILLER PIC X VALUE ".".
02 PrnFreq PIC BBBBBZZ9.
02 PrnWord PIC BBBBBX(20).
01 Pos PIC 99.
PROCEDURE DIVISION.
Begin.
OPEN INPUT DocWordsFile
READ DocWordsFile
AT END SET EndOfDocWordsFile TO TRUE
END-READ
PERFORM LoadWordFreqTable UNTIL EndOfDocWordsFile
PERFORM FindTopTenWords
VARYING Widx FROM 1 BY 1 UNTIL Widx > NumberOfWords
PERFORM DisplayTopTenWords
CLOSE DocWordsFile
STOP RUN.
LoadWordFreqTable.
* The AT END triggers when Widx is one greater than the current size of the
* table so all we have to do is extend the table and write into the new table
* element
SET Widx TO 1
SEARCH Word
AT END ADD 1 TO NumberOfWords
MOVE 1 TO WordFreq(Widx)
MOVE FUNCTION LOWER-CASE(WordIn) TO WordFound(Widx)
WHEN FUNCTION LOWER-CASE(WordIn) = WordFound(Widx)
ADD 1 TO WordFreq(Widx)
END-SEARCH
READ DocWordsFile
AT END SET EndOfDocWordsFile TO TRUE
END-READ.
FindTopTenWords.
PERFORM VARYING TTidx FROM 10 BY -1 UNTIL TTidx < 1
IF WordFreq(Widx) > WordFreqTT(TTidx)
MOVE WordTT(TTidx) TO WordTT(TTidx + 1)
MOVE Word(Widx) TO WordTT(TTidx)
END-IF
END-PERFORM.
DisplayTopTenWords.
324
Chapter 13 ■ SearChing tabular Data
DISPLAY ReportHeader
DISPLAY SubjectHeader
PERFORM VARYING TTidx FROM 1 BY 1 UNTIL TTIdx > 10
SET Pos TO TTidx
MOVE Pos TO PrnPos
MOVE WordFoundTT(TTidx) TO PrnWord
MOVE WordFreqTT(TTidx) TO PrnFreq
DISPLAY DetailLine
END-PERFORM
prOGraMMING eXerCISe 2: aNSWer
Listing 13-8. Program to Find the Number of Zeros in a List of Ten Numbers
IDENTIFICATION DIVISION.
PROGRAM-ID. Listing13-8.
AUTHOR. Michael Coughlan.
DATA DIVISION.
WORKING-STORAGE SECTION.
01 NumberArray.
02 Num PIC 99 OCCURS 10 TIMES
INDEXED BY Nidx.
01 FirstZeroPos PIC 99 VALUE ZERO.
88 NoZeros VALUE 0.
01 SecondZeroPos PIC 99 VALUE ZERO.
88 OneZero VALUE 0.
01 ValuesBetweenZeros PIC 9 VALUE ZERO.
88 NoneBetweenZeros VALUE 0.
PROCEDURE DIVISION.
Begin.
DISPLAY "Enter 10 two digit numbers "
PERFORM VARYING Nidx FROM 1 BY 1 UNTIL Nidx > 10
DISPLAY "Enter number - " SPACE WITH NO ADVANCING
ACCEPT Num(Nidx)
END-PERFORM
SET Nidx TO 1
SEARCH Num
AT END SET NoZeros TO TRUE
WHEN Num(Nidx) = ZERO
SET FirstZeroPos TO Nidx
SET Nidx UP BY 1
SEARCH Num
AT END SET OneZero TO TRUE
WHEN Num(Nidx) = ZERO
325
Chapter 13 ■ SearChing tabular Data
SET SecondZeroPos TO Nidx
COMPUTE ValuesBetweenZeros = (SecondZeroPos - 1) - FirstZeroPos
END-SEARCH
END-SEARCH
EVALUATE TRUE
WHEN NoZeros DISPLAY "No zeros found"
WHEN OneZero DISPLAY "Only one zero found"
WHEN NoneBetweenZeros DISPLAY "No numbers between the two zeros"
WHEN FUNCTION REM(ValuesBetweenZeros, 2)= ZERO
DISPLAY "Even number of non-zeros between zeros"
WHEN OTHER DISPLAY "Odd number of non-zeros between zeros"
END-EVALUATE
STOP RUN.
326
Chapter 14
Sorting and Merging
If there is one thing you should have learned from the chapters on sequential files, it is that your processing options are very limited if a sequential file is not ordered. Solutions based on control breaks, and the file-update problem, are impossible unless the file is ordered on some key field. In previous chapters, I mentioned the very useful program design technique called beneficial wishful thinking in which, when you a
re confronted by a difficult programming problem, you imagine a set of circumstances under which the difficulty would be greatly reduced and then try to bring about that set of circumstances. In the context of sequential files, you will often find yourself confronted with problems that would be much easier to solve if the file was ordered. A solution based on the beneficial wishful thinking approach first puts the file into the required order.
In this chapter, you discover how to use the SORT verb to sort a sequential file in ascending or descending order.
You learn how to use an INPUT PROCEDURE to filter or modify the records presented for sorting and how to use an OUTPUT PROCEDURE to process the sorted records instead of sending them directly to an output file. In addition, you see how to use the MERGE verb to merge the records in two or more ordered files to create a combined file with the records in the correct order.
SORTING
I noted in previous chapters that it is possible to apply processing to an ordered sequential file that is difficult, or impossible, when the file is unordered. In cases where you need to apply ordered processing to an unordered sequential file, part of the solution must be to sort the file. COBOL provides the SORT verb for this purpose.
The SORT verb is usually used to sort sequential files. Some programmers claim that the SORT verb is unnecessary, preferring to use an implementer-provided or “off-the-shelf” sort. However, one major advantage of using the SORT
verb is that it enhances the portability of COBOL programs. Because the SORT verb is available in every COBOL
compiler, when a program that uses SORT has to be moved to a different computer system, it can make the transition without requiring any changes to the SORT. This is rarely the case when programs rely on an implementer-supplied or bought-in sort.
Simple Sorting
The syntax for the simple SORT is given in Figure 14-1. This version of SORT takes the records in the InFileName file, sorts them on the WorkSortKey#$i key or keys, and writes the sorted records to the OutFileName file.
327
Chapter 14 ■ Sorting and Merging
Figure 14-1. Metalanguage for the simple version of SORT
Some example SORT statements are given in Example 14-1.
Example 14-1. Example SORT Statements