Compaq COBOL
User Manual


Previous Contents Index

4.3.7.2 Incrementing an Index Value with the SET Statement

You can use the SET statement with the UP BY/DOWN BY clause to arithmetically alter the value of a index. A numeric literal is added to (UP BY) or subtracted from (DOWN BY) a table index. For example:


SET TABLE-INDEX UP BY 12. 
 
SET TABLE-INDEX DOWN BY 5. 

4.3.8 Identifying Table Elements Using the SEARCH Statement

The SEARCH statement is used to search a table for an element that satisfies a known condition. The statement provides for sequential and binary searches, which are described in the following sections.

4.3.8.1 Implementing a Sequential Search

The SEARCH statement allows you to perform a sequential search of a table. The OCCURS clause of the table description entry must contain the INDEXED BY phrase. If more than one index is specified in the INDEXED BY phrase, the first index is the controlling index for the table search unless you specify otherwise in the SEARCH statement.

The search begins at the current index setting and progresses through the table, checking each element against the conditional expression. The index is incremented by 1 as each element is checked. If the conditional expression is true, the associated imperative statement executes; otherwise, program control passes to the next procedural sentence. This terminates the search, and the index points to the current table element that satisfied the conditional expression.

If no table element is found that satisfies the conditional expression, program control passes to the AT END exit path; otherwise, program control passes to the next procedural sentence.

You can use the optional VARYING phrase of the SEARCH statement by specifying any of the following:

Regardless of which method you use, the index specified in the INDEXED BY phrase of the table being searched is incremented. This controlling index, when compared against the allowable number of occurrences in the table, dictates the permissible search range. When the search terminates, either successfully or unsuccessfully, the index remains at its current setting. At this point, you can reference the data in the table element pointed to by the index, unless the AT END condition is true. If the AT END condition is true, and if the -check flag (on Tru64 UNIX systems) or the /CHECK qualifier (on OpenVMS Alpha systems) has been specified, the compiler issues a run-time error message indicating that the subscript is out of range.

When you vary an index associated with the table being searched, the index name can be any index you specify in the INDEXED BY phrase. It becomes the controlling index for the search and is the only index incremented. Example 4-18 and Example 4-20 show how to vary an index other than the first index.

When you vary an index data item or an integer data item, either the index data item or the integer data item is incremented. The first index name you specify in the INDEXED BY phrase of the table being searched becomes the controlling index and is also incremented. The index data item or the integer data item you vary does not function as an index; it merely allows you to maintain an additional pointer to elements within a table. Example 4-18 and Example 4-21 show how to vary an index data item or an integer data item.

When you vary an index associated with a table other than the one you are searching, the controlling index is the first index you specify in the INDEXED BY phrase of the table you are searching. Each time the controlling index is incremented, the index you specify in the VARYING phrase is incremented. In this manner, you can search two tables in synchronization. Example 4-18 and Example 4-22 show how to vary an index associated with a table other than the one you are searching.

When you omit the VARYING phrase, the first index you specify in the INDEXED BY phrase becomes the controlling index. Only this index is incremented during a serial search. Example 4-18 and Example 4-23 show how to perform a serial search without using the VARYING phrase.

4.3.8.2 Implementing a Binary Search

You can use the SEARCH statement to perform a nonsequential (binary) table search.

To perform a binary search, you must specify an index name in the INDEXED BY phrase and a search key in the KEY IS phrase of the OCCURS clause of the table being searched.

A binary search depends on the ASCENDING/DESCENDING KEY attributes. If you specify an ASCENDING KEY, the data in the table must either be stored in ascending order or sorted in ascending order prior to the search. For a DESCENDING KEY, data must be stored or sorted in descending order prior to the search.

You can sort an entire table in preparation for a binary search. Use the SORT statement (Format 2, a Compaq extension), described in the Compaq COBOL Reference Manual.

During a binary search, the first (or only) index you specify in the INDEXED BY phrase of the OCCURS clause of the table being searched is the controlling index. You do not have to initialize an index in a binary search because index manipulation is automatic.

In addition to being generally faster than a sequential search, a binary search allows multiple equality checks.

The following search sequence lists the capabilities of a binary search. At program execution time, the system:

  1. Examines the range of permissible index values, selects the median value, and assigns this value to the index.
  2. Checks for equality in WHEN and AND clauses.
  3. Terminates the search if all equality statements are true. If you use the imperative statement after the final equality clause, that statement executes; otherwise, program control passes to the next procedural sentence, the search exits, and the index retains its current value.
  4. Takes the following actions if the equality test of a table element is false:
    1. Executes the imperative statement associated with the AT END statement (if present) when all table elements have been tested. If there is no AT END statement, program control passes to the next procedural statement.
    2. Determines which half of the table is to be eliminated from further consideration. This is based on whether the key being tested was specified as ASCENDING or DESCENDING and whether the test failed because of a greater-than or less-than comparison. For example, if the key values are stored in ascending order, and the median table element being tested is greater than the value of the argument, then all key elements following the one being tested must also be greater. Therefore, the upper half of the table is removed from further consideration and the search continues at the median point of the lower half.
    3. Begins processing all over again at Step 1.

A useful variation of the binary search is that of specifying multiple search keys. Multiple search keys allow you to select a specified table element from among several elements that have duplicate low-order keys. An example is a telephone listing where several people have the same last and first names, but different middle initials. All specified keys must be either ascending or descending. Example 4-24 shows how to use multiple search keys.

The table in Example 4-18 is followed by several examples (Examples 4-19, 4-20, 4-21, 4-22, and 4-23) of how to search it.

Example 4-18 Sample Table

DATA DIVISION. 
WORKING-STORAGE SECTION. 
01  TEMP-IND                            USAGE IS INDEX. 
01  FED-TAX-TABLES. 
    02  ALLOWANCE-DATA. 
        03  FILLER                      PIC X(70) VALUE 
            "0101440 
-           "0202880 
-           "0304320 
-           "0405760 
-           "0507200 
-           "0608640 
-           "0710080 
-           "0811520 
-           "0912960 
-           "1014400". 
    02  ALLOWANCE-TABLE REDEFINES ALLOWANCE-DATA. 
        03  FED-ALLOWANCES OCCURS 10 TIMES 
            ASCENDING KEY IS ALLOWANCE-NUMBER 
            INDEXED BY IND-1. 
            04  ALLOWANCE-NUMBER        PIC XX. 
            04  ALLOWANCE               PIC 99999. 
 
    02 SINGLES-DEDUCTION-DATA. 
        03  FILLER                      PIC X(112) VALUE 
            "0250006700000016 
-           "0670011500067220 
-           "1150018300163223 
-           "1830024000319621 
-           "2400027900439326 
-           "2790034600540730 
-           "3460099999741736". 
   02   SINGLE-DEDUCTION-TABLE REDEFINES SINGLES-DEDUCTION-DATA. 
        03  SINGLES-TABLE OCCURS 7 TIMES 
            ASCENDING KEY IS S-MIN-RANGE S-MAX-RANGE 
            INDEXED BY IND-2, TEMP-INDEX. 
            04  S-MIN-RANGE             PIC 99999. 
            04  S-MAX-RANGE             PIC 99999. 
            04  S-TAX                   PIC 9999. 
            04  S-PERCENT               PIC V99. 
 
    02  MARRIED-DEDUCTION-DATA. 
        03  FILLER                      PIC X(119) VALUE 
            "04800096000000017 
-           "09600173000081620 
-           "17300264000235617 
-           "26400346000390325 
-           "34600433000595328 
-           "43300500000838932 
-           "50000999991053336". 
    02  MARRIED-DEDUCTION-TABLE REDEFINES MARRIED-DEDUCTION-DATA. 
        03 MARRIED-TABLE OCCURS 7 TIMES 
           ASCENDING KEY IS M-MIN-RANGE M-MAX-RANGE 
           INDEXED BY IND-0, IND-3. 
           04  M-MIN-RANGE              PIC 99999. 
           04  M-MAX-RANGE              PIC 99999. 
           04  M-TAX                    PIC 99999. 
           04  M-PERCENT                PIC V99. 

Example 4-19 shows how to perform a serial search.

Example 4-19 A Serial Search

01   TAXABLE-INCOME PIC 9(6) VALUE 50000. 
01   FED-TAX-DEDUCTION PIC 9(6). 
PROCEDURE DIVISION. 
BEGIN. 
       PERFORM SINGLE. 
       DISPLAY FED-TAX-DEDUCTION. 
       STOP RUN. 
SINGLE. 
       IF TAXABLE-INCOME < 02500 
               GO TO END-FED-COMP. 
       SET IND-2 TO 1. 
       SEARCH SINGLES-TABLE AT END 
               GO TO TABLE-2-ERROR 
          WHEN TAXABLE-INCOME = S-MIN-RANGE(IND-2) 
               MOVE S-TAX(IND-2) TO FED-TAX-DEDUCTION 
          WHEN TAXABLE-INCOME < S-MAX-RANGE(IND-2) 
               COMPUTE FED-TAX-DEDUCTION = 
                   S-TAX(IND-2) + (TAXABLE-INCOME - S-TAX(IND-2)) * 
                   S-PERCENT(IND-2). 
   .
   .
   .

Example 4-20 shows how to use SEARCH while varying an index other than the first index.

Example 4-20 Using SEARCH and Varying an Index Other than the First Index

01   TAXABLE-INCOME PIC 9(6) VALUE 50000. 
01   FED-TAX-DEDUCTION PIC 9(6). 
PROCEDURE DIVISION. 
BEGIN. 
       PERFORM MARRIED. 
       DISPLAY FED-TAX-DEDUCTION. 
       STOP RUN. 
MARRIED. 
       IF TAXABLE-INCOME < 04800 
               MOVE ZEROS TO FED-TAX-DEDUCTION 
               GO TO END-FED-COMP. 
       SET IND-3 TO 1. 
       SEARCH MARRIED-TABLE VARYING IND-3 AT END 
               GO TO TABLE-3-ERROR 
          WHEN TAXABLE-INCOME = M-MIN-RANGE(IND-3) 
               MOVE M-TAX(IND-3) TO FED-TAX-DEDUCTION 
          WHEN TAXABLE-INCOME < M-MAX-RANGE(IND-3) 
               COMPUTE FED-TAX-DEDUCTION = 
                   M-TAX(IND-3) + (TAXABLE-INCOME - M-TAX(IND-3)) * 
                   M-PERCENT(IND-3). 
   .
   .
   .

Example 4-21 shows how to use SEARCH while varying an index data item.

Example 4-21 Using SEARCH and Varying an Index Data Item

01   TAXABLE-INCOME PIC 9(6) VALUE 50000. 
01   FED-TAX-DEDUCTION PIC 9(6). 
PROCEDURE DIVISION. 
BEGIN. 
       PERFORM SINGLE. 
       DISPLAY FED-TAX-DEDUCTION. 
       STOP RUN. 
SINGLE. 
       IF TAXABLE-INCOME < 02500 
               GO TO END-FED-COMP. 
       SET IND-2 TO 1. 
       SEARCH SINGLES-TABLE VARYING TEMP-IND AT END 
               GO TO TABLE-2-ERROR 
          WHEN TAXABLE-INCOME = S-MIN-RANGE(IND-2) 
               MOVE S-TAX(IND-2) TO FED-TAX-DEDUCTION 
          WHEN TAXABLE-INCOME < S-MAX-RANGE(IND-2) 
               MOVE S-TAX(IND-2) TO FED-TAX-DEDUCTION 
               SUBTRACT S-MIN-RANGE(IND-2) FROM TAXABLE-INCOME 
               MULTIPLY TAXABLE-INCOME BY S-PERCENT(IND-2) ROUNDED 
               ADD TAXABLE-INCOME TO FED-TAX-DEDUCTION. 
   .
   .
   .

Example 4-22 shows how to use SEARCH while varying an index not associated with the target table.

Example 4-22 Using SEARCH and Varying an Index not Associated with the Target Table

01   TAXABLE-INCOME PIC 9(6) VALUE 50000. 
01   FED-TAX-DEDUCTION PIC 9(6). 
PROCEDURE DIVISION. 
BEGIN. 
       PERFORM SINGLE. 
       DISPLAY FED-TAX-DEDUCTION. 
       STOP RUN. 
SINGLE. 
        IF TAXABLE-INCOME < 02500 
               GO TO END-FED-COMP. 
        SET IND-2 TO 1. 
        SEARCH SINGLES-TABLE VARYING IND-0 AT END 
               GO TO TABLE-2-ERROR 
          WHEN TAXABLE-INCOME = S-MIN-RANGE(IND-2) 
               MOVE S-TAX(IND-2) TO FED-TAX-DEDUCTION 
 
          WHEN TAXABLE-INCOME < S-MAX-RANGE(IND-2) 
               MOVE S-TAX(IND-2) TO FED-TAX-DEDUCTION 
               SUBTRACT S-MIN-RANGE(IND-2) FROM TAXABLE-INCOME 
               MULTIPLY TAXABLE-INCOME BY S-PERCENT(IND-2) ROUNDED 
               ADD TAXABLE-INCOME TO FED-TAX-DEDUCTION. 
   .
   .
   .

Example 4-23 shows how to perform a serial search without using the VARYING phrase.

Example 4-23 Doing a Serial Search Without Using the VARYING Phrase

01   NR-DEPENDENTS     PIC 9(2)  VALUE 3. 
01   GROSS-WAGE        PIC 9(6)  VALUE 50000. 
01   TAXABLE-INCOME    PIC 9(6)  VALUE 50000. 
01   FED-TAX-DEDUCTION PIC9(6). 
01   MARITAL-STATUS    PIC X     VALUE "M". 
PROCEDURE DIVISION. 
BEGIN. 
       PERFORM FED-DEDUCT-COMPUTATION. 
       DISPLAY TAXABLE-INCOME. 
       STOP RUN. 
FED-DEDUCT-COMPUTATION. 
          SET IND-1 TO 1. 
          SEARCH FED-ALLOWANCES AT END 
                 GO TO TABLE-1-ERROR 
            WHEN ALLOWANCE-NUMBER(IND-1) = NR-DEPENDENTS 
                 SUBTRACT ALLOWANCE(IND-1) FROM GROSS-WAGE 
                     GIVING TAXABLE-INCOME ROUNDED. 
          IF MARITAL-STATUS = "M" 
                 GO TO MARRIED. 
MARRIED. 
   .
   .
   .

Example 4-24 shows how to perform a multiple-key, binary search.

Example 4-24 A Multiple-Key, Binary Search

IDENTIFICATION DIVISION. 
PROGRAM-ID. MULTI-KEY-SEARCH. 
DATA DIVISION. 
WORKING-STORAGE SECTION. 
01 DIRECTORY-TABLE. 
   05 NAMES-NUMBERS. 
      10 FILLER                PIC X(30) 
         VALUE "SMILEY    HAPPY     T.213-4332". 
      10 FILLER                PIC X(30) 
         VALUE "SMITH     ALAN      C.881-4987". 
      10 FILLER                PIC X(30) 
         VALUE "SMITH     CHARLES   J.345-2398". 
      10 FILLER                PIC X(30) 
         VALUE "SMITH     FREDERICK   745-0223". 
      10 FILLER                PIC X(30) 
         VALUE "SMITH     HARRY     C.573-3306". 
      10 FILLER                PIC X(30) 
         VALUE "SMITH     HARRY     J.295-3485". 
      10 FILLER                PIC X(30) 
         VALUE "SMITH     LARRY     X.976-5504". 
      10 FILLER                PIC X(30) 
         VALUE "SMITHWOOD ALBERT    J.349-9927". 
   05 PHONE-DIRECTORY-TABLE REDEFINES NAMES-NUMBERS OCCURS 8 TIMES 
                                  ASCENDING KEY IS LAST-NAME 
                                                   FIRST-NAME 
                                                   MID-INIT 
                                  INDEXED BY DIR-INDX. 
         15 LAST-NAME          PIC X(10). 
         15 FIRST-NAME         PIC X(10). 
         15 MID-INIT           PIC XX. 
         15  PHONE-NUM         PIC X(8). 
PROCEDURE DIVISION. 
MULTI-KEY-BINARY-SEARCH. 
    SEARCH ALL PHONE-DIRECTORY-TABLE 
           WHEN LAST-NAME(DIR-INDX) = "SMITH" 
           AND FIRST-NAME(DIR-INDX) = "HARRY" 
           AND MID-INIT(DIR-INDX) = "J." 
               NEXT SENTENCE. 
DISPLAY-RESULTS. 
    DISPLAY LAST-NAME(DIR-INDX)"," 
            FIRST-NAME(DIR-INDX) 
            MID-INIT(DIR-INDX) " " 
            PHONE-NUM(DIR-INDX). 


Chapter 5
Using the STRING, UNSTRING, and INSPECT Statements

The STRING, UNSTRING, and INSPECT statements give your Compaq COBOL programs the following capabilities:

5.1 Concatenating Data Using the STRING Statement

The STRING statement concatenates the contents of one or more sending items into a single receiving item.

The statement has many forms; the simplest is equivalent in function to a nonnumeric MOVE statement. Consider the following example:


STRING FIELD1 DELIMITED BY SIZE INTO FIELD2. 

If the two items are the same size, or if the sending item (FIELD1) is larger, the statement is equivalent to the following statement:


MOVE FIELD1 TO FIELD2. 

If the sending item of the string is shorter than the receiving item, the compiler does not replace unused positions in the receiving item with spaces. Thus, the STRING statement can leave some portion of the receiving item unchanged.

The receiving item of the string must be an elementary alphanumeric item with no JUSTIFIED clause or editing characters in its description. Thus, the data movement of the STRING statement always fills the receiving item with the sending item from left to right and with no editing insertions.

5.1.1 Multiple Sending Items

The STRING statement can concatenate a series of sending items into one receiving item. Consider the following example:


STRING FIELD1A FIELD1B FIELD1C DELIMITED BY SIZE 
                           INTO FIELD2. 

In this sample STRING statement, FIELD1A, FIELD1B, and FIELD1C are all sending items. The compiler moves them to the receiving item (FIELD2) in the order in which they appear in the statement, from left to right, resulting in the concatenation of their values.

If FIELD2 is not large enough to hold all three items, the operation stops when it is full. If the operation stops while moving one of the sending items, the compiler ignores the remaining characters of that item and any other sending items not yet processed. For example, if FIELD2 is filled while it is receiving FIELD1B, the compiler ignores the rest of FIELD1B and all of FIELD1C.

If the sending items do not fill the receiving item, the operation stops when the last character of the last sending item (FIELD1C) is moved. It does not alter the contents nor space-fill the remaining character positions of the receiving item.

The sending items can be nonnumeric literals and figurative constants (except for ALL literal). Example 5-1 sets up an address label by stringing the data items CITY, STATE, and ZIP into ADDRESS-LINE. The figurative constant SPACE and the literal period (.) are used to separate the information.

Example 5-1 Using the STRING Statement and Literals

01 ADDRESS-GROUP. 
   03 CITY           PIC X(20). 
   03 STATE          PIC XX. 
   03 ZIP            PIC X(5). 
01 ADDRESS-LINE      PIC X(31). 
      . 
      . 
      . 
PROCEDURE DIVISION. 
BEGIN. 
   STRING CITY SPACE STATE ". " SPACE ZIP 
        DELIMITED BY SIZE INTO ADDRESS-LINE. 
   .
   .
   .

5.1.2 Using the DELIMITED BY Phrase

Although the sending items of the STRING statement are fixed in size at compile time, they are frequently filled with spaces. For example, if a 20-character city item contains the text MAYNARD followed by 13 spaces, the STRING statement using the DELIMITED BY SIZE phrase would move the text (MAYNARD) and the unwanted 13 spaces (assuming the receiving item is at least 20 characters long). The DELIMITED BY phrase, written with a data name or literal, eliminates this problem.

The delimiter can be a literal, a data item, a figurative constant, or the word SIZE. It cannot, however, be ALL literal, since ALL literal has an indefinite length. When the phrase contains the word SIZE, the compiler moves each sending item in total, until it either exhausts the characters in the sending item or fills the receiving item.

If you use the code in Example 5-1, and CITY is a 20-character item, the result of the STRING operation might look like Figure 5-1.

Figure 5-1 Results of the STRING Operation


A more attractive and readable report can be produced by having the STRING operation produce this line:


AYER, MA. 01432 

To accomplish this, use the figurative constant SPACE as a delimiter on the sending item:


MOVE 1 TO P. 
STRING CITY DELIMITED BY SPACE 
        INTO ADDRESS-LINE WITH POINTER P. 
STRING ", " STATE ". " ZIP 
        DELIMITED BY SIZE 
        INTO ADDRESS-LINE WITH POINTER P. 

This example makes use of the POINTER phrase (see Section 5.1.3). The first STRING statement moves data characters until it encounters a space character---a match of the delimiter SPACE. The second STRING statement supplies the literal, the 2-character STATE item, another literal, and the 5-character ZIP item.

The delimiter can be varied for each item within a single STRING statement by repeating the DELIMITED BY phrase after each of the sending item names to which it applies. Thus, the shorter STRING statement in the following example has the same effect as the two STRING statements in the preceding example. (Placing the operands on separate source lines has no effect on the operation of the statement, but it improves program readability and simplifies debugging.)


STRING CITY DELIMITED BY SPACE 
        ", " STATE ". " 
        ZIP DELIMITED BY SIZE 
        INTO ADDRESS-LINE. 

The sample STRING statement cannot handle 2-word city names, such as San Francisco, because the compiler considers the space between the two words as a match for the delimiter SPACE. A longer delimiter, such as two or three spaces (nonnumeric literal), can solve this problem. Only when a sequence of characters matches the delimiter does the movement stop for that data item. With a 2-character delimiter, the same statement can be rewritten in a simpler form:


STRING CITY ", " STATE ". " ZIP 
        DELIMITED BY "  " INTO ADDRESS-LINE. 

Because only the CITY item contains two consecutive spaces, the delimiter's search of the other items will always be unsuccessful, and the effect is the same as moving the full item (delimiting by SIZE).

Data movement under control of a data name or literal generally executes more slowly than data movement delimited by SIZE.

Remember, the remainder of the receiving item is not space-filled, as with a MOVE statement. If ADDRESS-LINE is to be printed on a mailing label, for example, the STRING statement should be preceded by the statement:


MOVE SPACES TO ADDRESS-LINE. 

This statement guarantees a space-fill to the right of the concatenated result. Alternatively, the last item concatenated by the STRING statement can be an item previously set to SPACES. This sending item must either be moved under control of a delimiter other than SPACE or use the value of POINTER and reference modification.


Previous Next Contents Index