Searching a table:

There are several variations that could be used instead of the sample code that I handed out in the program called TABLSOUP.CBL.

Here is the relevant code from TABLSOUP.CBL:

Definition of the input field:

FD  INPUT-FILE
    DATA RECORD IS INPUT-REC.
01  INPUT-REC.
    05  ORDER-NO        PIC 9999.
    05  ITEM-NUMBER-IN  PIC 99.

WORKING-STORAGE entries:

01  INDICATORS.
    05  MORE-RECS               PIC XXX     VALUE "YES".
    05  MATCH-IND               PIC XXX     VALUE "NO".
01  SUBSCRIPTS.
    05  ITEM-SUB                PIC 99      VALUE 0.
01  TABLE-COMBINED.
    05  FILLER PIC X(17) VALUE "03SEAFOOD CHOWDER".
    05  FILLER PIC X(17) VALUE "12CORN CHOWDER   ".
    05  FILLER PIC X(17) VALUE "15CLAM CHOWDER   ".
    05  FILLER PIC X(17) VALUE "17TOMATO SOUP    ".
    05  FILLER PIC X(17) VALUE "24CHICKEN SOUP   ".
    05  FILLER PIC X(17) VALUE "25VEGETABLE SOUP ".
    05  FILLER PIC X(17) VALUE "27ONION SOUP     ".
    05  FILLER PIC X(17) VALUE "28GREEN PEA SOUP ".
    05  FILLER PIC X(17) VALUE "45WONTON SOUP    ".
01  RDF-TABLE-COMBINED REDEFINES TABLE-COMBINED.
    05  ENTRIES  OCCURS 9 TIMES.
        10  ITEM-NUMBER-TBL   PIC 99.
        10  ITEM-NAME-TBL     PIC X(15).

PROCEDURE DIVISION entries:

B-200-LOOP.
    IF LINE-CT > 55 OR PAGE-NO = 1
         PERFORM B-310-HDR-ROUT.
    MOVE SPACES TO PRINTZ.
    MOVE ORDER-NO TO ORDER-NO-PR.
    MOVE ITEM-NUMBER-IN TO ITEM-NUMBER-IN-PR.
    MOVE 1 TO ITEM-SUB.
    MOVE "NO " TO MATCH-IND.
    PERFORM B-300-SEARCH
        UNTIL ITEM-SUB > 9 OR MATCH-IND = "YES".
    IF MATCH-IND = "YES"
        MOVE ITEM-NAME-TBL (ITEM-SUB) TO ITEM-NAME-PR
    ELSE
        MOVE "*** INVALID ***" TO ITEM-NAME-PR.
    WRITE PRINTZ
	  AFTER ADVANCING 1 LINES.
    ADD 1 TO LINE-CT.
    READ INPUT-FILE
        AT END
            MOVE "NO " TO MORE-RECS.
B-300-SEARCH.
    IF ITEM-NUMBER-IN = ITEM-NUMBER-TBL (ITEM-SUB)
        MOVE "YES" TO MATCH-IND
    ELSE
        ADD 1 TO ITEM-SUB.

The output that this program generates is shown below.

09/09/99                        SOUP REPORT                     PAGE  1     
 ORDER       ITEM #        ITEM NAME                                            
                                                                                
 1111          12          CORN CHOWDER                                         
 1212          27          ONION SOUP                                           
 1224          45          WONTON SOUP                                          
 1225          28          GREEN PEA SOUP                                       
 2003          17          TOMATO SOUP                                          
 2027          28          GREEN PEA SOUP                                       
 3003          03          SEAFOOD CHOWDER                                      
 3010          34          *** INVALID ***                                      
 4012          15          CLAM CHOWDER                                         
 4078          50          *** INVALID ***                                      
 5000          19          *** INVALID ***                                      
 5012          24          CHICKEN SOUP
For the changes below assume that all of the DATA DIVISION entries remain the same (although MATCH-IND is not used in all of them) and that only the procedure division is changing.

The first and second examples illustrate two ways to code an early exit. Remember that the early exit can only be used if the numbers in the table that are being searched are in sequence. If the numbers are in random order, the whole table must be searched.

In the first early exit example, the early exit is including as one of the conditions in the search statement. I add the OR the item number in the table that the subscript is pointing to is greater than the item number from the input indicating that we have passed the point where the match would be found.

B-200-LOOP.
    ...
    MOVE 1 TO ITEM-SUB.
    MOVE "NO " TO MATCH-IND.
    PERFORM B-300-SEARCH
        UNTIL ITEM-SUB > 9 OR MATCH-IND = "YES" OR 
              ITEM-NUMBER-TBL (ITEM-SUB) > ITEM-NUMBER-IN.
    IF MATCH-IND = "YES"
        MOVE ITEM-NAME-TBL (ITEM-SUB) TO ITEM-NAME-PR
    ELSE
        MOVE "*** INVALID ***" TO ITEM-NAME-PR.
    WRITE PRINTZ
	   AFTER ADVANCING 1 LINES.
    ADD 1 TO LINE-CT.
    READ INPUT-FILE
        AT END
           MOVE "NO " TO MORE-RECS.
B-300-SEARCH.
    IF ITEM-NUMBER-IN = ITEM-NUMBER-TBL (ITEM-SUB)
        MOVE "YES" TO MATCH-IND
    ELSE
        ADD 1 TO ITEM-SUB.
In the second early exit example, I will test for the exit within the search loop and set the indicator to NO meaning there can be no match. Because the indicator can be set to either YES or NO, I am changing the initialization to moving three spaces to the match indicator. If I do not find a match in the search paragraph, I then test to see if I have passed the spot where a match would be. If that is true, I set the match indicator to NO. Otherwise I add 1 to the subscript.

B-200-LOOP.
    ...
    MOVE 1 TO ITEM-SUB.
    MOVE "   " TO MATCH-IND.
    PERFORM B-300-SEARCH
        UNTIL ITEM-SUB > 9 OR MATCH-IND NOT = "   ".
    IF MATCH-IND = "YES"
        MOVE ITEM-NAME-TBL (ITEM-SUB) TO ITEM-NAME-PR
    ELSE
        MOVE "*** INVALID ***" TO ITEM-NAME-PR.
    WRITE PRINTZ
        AFTER ADVANCING 1 LINES.
    ADD 1 TO LINE-CT.
    READ INPUT-FILE
        AT END
           MOVE "NO " TO MORE-RECS.
B-300-SEARCH.
    IF ITEM-NUMBER-IN = ITEM-NUMBER-TBL (ITEM-SUB)
        MOVE "YES" TO MATCH-IND
    ELSE
        IF ITEM-NUMBER-TBL (ITEM-SUB) > ITEM-NUMBER-IN
            MOVE "NO " TO MATCH-IND
        ELSE
            ADD 1 TO ITEM-SUB.
The next example deals a different way to code the original program. It does not incorporate early exits. In this example instead of performing a paragraph, I have embedded the perform code in the perform statement itself.

B-200-LOOP.
    ...
    MOVE 1 TO ITEM-SUB.
    MOVE "NO " TO MATCH-IND.
    PERFORM 
        UNTIL ITEM-SUB > 9 OR MATCH-IND = "YES"
        IF ITEM-NUMBER-IN = ITEM-NUMBER-TBL(ITEM-SUB)
            MOVE "YES" TO MATCH-IND
        ELSE
            ADD 1 TO ITEM-SUB
        END-IF
    END-PERFORM
    IF  MATCH-IND= "YES"
         MOVE ITEM-NAME-TBL (ITEM-SUB) TO ITEM-NAME-PR
    ELSE
         MOVE "*** INVALID ***" TO ITEM-NAME-PR.
    WRITE PRINTZ
	  AFTER ADVANCING 1 LINES.
    ADD 1 TO LINE-CT.
    READ INPUT-FILE
       AT END
           MOVE "NO " TO MORE-RECS.
Finally, the last example shows the code without the match indicator. In this example the test for a match has been move to a condition in the until to avoid using the indicator. Since the test is being done, the search paragraph becomes a place where you simply add 1 to the subscript since you only go there when there is not a match. After the perform, the IF had to be changed because I could not test for the indicator and I could not test for the item number on the input equal to the item number in the table because the subscript might have reached 10 and the test would therefore be out of bounds. Instead I tested for the subscript greater than the size of the table and if it was, I handled the error processing. My personal preference is to use it because I think the code is more straightforward and does not involve coding if statements as part of the until clause.

B-200-LOOP.
    ...
    MOVE 1 TO ITEM-SUB.
    PERFORM B-300-SEARCH
        UNTIL ITEM-SUB > 9 OR
              ITEM-NUMBER-IN = ITEM-NUMBER-TBL (ITEM-SUB).
    IF ITEM-SUB > 9
        MOVE "*** INVALID ***" TO ITEM-NAME-PR
    ELSE
        MOVE ITEM-NAME-TBL (ITEM-SUB) TO ITEM-NAME-PR
    END-IF
    WRITE PRINTZ
        AFTER ADVANCING 1 LINES.
    ADD 1 TO LINE-CT.
    READ INPUT-FILE
        AT END
            MOVE "NO " TO MORE-RECS.
B-300-SEARCH.
    ADD 1 TO ITEM-SUB.