Book Read Free

Michael Coughlan

Page 40

by Beginning COBOL for Programmers-Apress (2014) (pdf)

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

 

‹ Prev