Scope terminators

6.10 Scope Terminators

In the section COBOL basics I mentioned the full stop (period). This is what can be described as a scope terminator. Many COBOL verbs have their own scope terminator, for example, END-IF, END-READ, END-PERFORM etc... The purpose of a scope terminator is to define when a verb's scope (i.e. associated logic) is finished.

For example:

   READ IN-FILE
     AT END MOVE 'Y' TO EOF FLAG
     NOT AT END
        IF REC-IN = 'Z' THEN
           PERFORM PROCEDURE-X
        END-IF
   END-READ
   [more code]

In the above example END-READ defines the scope of the READ statement since there is a condition involved (AT END of the file, or NOT AT END of the file), while END-IF defines then end of the IF condition, i.e. END-READ and END-IF define their scope. Any code that follows the read statement will apply regardless of the READ condition (which is what you would want in the above example). Without END-READ the subsequent code would only be performed while NOT AT END is true: some nasty bugs could ensue! Things become even more scary if you forget to use END-IF or END-PERFORM (especially when looping). There's a good chance the compiler might pick up the error.

However, a period is also a scope terminator. You might also code:

   READ IN-FILE
     AT END MOVE 'Y' TO EOF FLAG
     NOT AT END
        PERFORM UNTIL REC-IN = 'A'
          IF REC-IN = 'Z' THEN
             PERFORM PROCEDURE-X.
        END-PERFORM
   [more code]

This would have the same effect as the first example (assuming the compiler doesn't complain). Some people do use periods in place of END-IF etc (note: I'm not sure you allowed to replace END-PERFORM however). Problems may arise when you forget to use a scope terminator somewhere and there's a period somewhere further down the code then the compiler might just get confused.

It is important to realise that the period will terminate all ongoing conditions. So in the above example, the period will act as both an END-IF, END-PERFORM and END-READ.

Look at this paragraph:

000090*this works, using period scope terminators
000100 PARAGRAPH-ABC.
000200     MOVE 0 TO N
000300     PERFORM UNTIL N > 10
000400        COMPUTE N = N + 1
000500        DISPLAY N.
000600     
000700     PERFORM PROCEDURE-Y  N TIMES
000800     PERFORM UNTIL END-OF-FILE
000900       READ IN-FILE
001000         AT END MOVE 'Y' TO EOF-FLAG
001100         NOT AT END
001200           ADD VALUE-FROM-RECORD TO N GIVING X.
001300       
001400     END-PERFORM
001500     DISPLAY X.

In the first example, the code will display numbers 1 to 10. It will then perform PROCEDURE-Y 11 times. Finally, the numbers coming from the IN-FILE (VALUE-FROM-RECORD) will be added to 11 giving X, which is then displayed.

But what if we were to forget to put a period at the end of line 500?

000090*this has a syntax error
000100 PARAGRAPH-ABC.
000200     MOVE 0 TO N.
000300     PERFORM UNTIL N > 10
000400        COMPUTE N = N + 1
000500        DISPLAY N
000600     
000700     PERFORM PROCEDURE-Y  N TIMES.
000800     PERFORM UNTIL END-OF-FILE
000900       READ IN-FILE
001000         AT END MOVE 'Y' TO EOF-FLAG
001100         NOT AT END
001200           ADD VALUE-FROM-RECORD TO N GIVING X.
001300       
001400     END-PERFORM
001500     DISPLAY X.

Now, the period on line 700 will terminate the scope of the PERFORM statement on line 300. This means that PROCEDURE-Y gets performed 1+2+3+4+5+6+7+8+9+10+11 times (that's 66 times!). Oh dear.

In fact, when I tried to test these code fragments by compiling [on the Fujitsu COBOL v3] it complained bitterly! The compiler was particularly bothered by the lack of END-PERFORMS.

I was taught to only use 2 periods in any paragraph: the first after the paragraph name, the second (and last) at the end of the paragraph. So always use the verb's own scope terminator. More typing but less headaches in my humble opinion. Here's what the above code would look like when following this advice:

000090*using just 2 periods
000100 PARAGRAPH-ABC.
000200     MOVE 0 TO N
000300     PERFORM UNTIL N > 10
000400        COMPUTE N = N + 1
000500        DISPLAY N
000600     END-PERFORM
000700     PERFORM PROCEDURE-Y  N TIMES
000800     PERFORM UNTIL END-OF-FILE
000900       READ IN-FILE
001000         AT END MOVE 'Y' TO EOF-FLAG
001100         NOT AT END
001200           ADD VALUE-FROM-RECORD TO N GIVING X
001300       END-READ
001400     END-PERFORM
001500     DISPLAY X.

Ahh...that's better...