Nevertheless, a step-by-step incremental approach can untangle even the messiest of loops.
PERFORM 3000-LOAD-TABLE THRU 3000-EXIT.
...
3000-LOAD-TABLE.
*
PERFORM 3100-GET-TABLE-RECORD.
*
IF TABLE-EOF
GO TO 3000-EXIT.
*
PERFORM 3200-LOAD-TABLE-ENTRY.
GO TO 3000-LOAD-TABLE.
*
3000-EXIT.
EXIT.
In this example, the exit is conditional; the return to the top of the
loop is unconditional. Some cases might be the other way around:
PERFORM 3300-GET-FIRST-TABLE-RECORD.
*
IF NOT TABLE-EOF
PERFORM 3000-LOAD-TABLE THRU 3000-EXIT.
...
3000-LOAD-TABLE.
*
PERFORM 3200-LOAD-TABLE-ENTRY.
PERFORM 3100-GET-NEXT-TABLE-RECORD.
*
IF NOT TABLE-EOF
GO TO 3000-LOAD-TABLE.
*
GO TO 3000-EXIT.
*
3000-EXIT.
EXIT.
(That last GO TO probably didn't occur in the original code. We added
it in an earlier stage of the rewrite, in
order to eliminate some fall-through logic.)
PERFORM 3000-LOOP THRU 3000-EXIT.
...
3000-LOOP. <----------------------+
* |
* do stuff #1. |
* |
IF NOT LOOP-FINISHED |
* do stuff #2 |
GO TO 3000-LOOP ---------+
ELSE
* do stuff #3
GO TO 3000-EXIT. ---------+
* |
3000-EXIT. <---------------------+
EXIT.
The "do stuff" parts may be trivial. They may be empty -- code CONTINUE
statements instead. They may be hideously complex, in which case you
should consider pulling them out into separate paragraphs. One way or
another, you can always rearrange any simple GO TO loop into the
Standard Canonical pattern.
PERFORM 3000-LOOP WITH TEST AFTER
UNTIL LOOP-FINISHED.
*
* do stuff #3.
*
...
3000-LOOP.
*
* do stuff #1.
*
IF NOT LOOP-FINISHED
* do stuff #2.
*
All you did was:
If your dialect of COBOL doesn't support WITH TEST AFTER, you can achieve the same end by other means. Perhaps you can explicitly set or clear some switch just before the PERFORM:
SET LOOP-NOT-FINISHED TO TRUE.
PERFORM 3000-LOOP WITH TEST AFTER
UNTIL LOOP-FINISHED.
Another trick is to use two PERFORMs, although it looks a little odd:
PERFORM 3000-LOOP.
PERFORM 3000-LOOP
UNTIL LOOP-FINISHED.
Before you read further, stare at the above example long enough to convince
yourself that it works. The new code behaves exactly the same as the
old code, but without GO TOs.
Once you get used to the Standard Canonical pattern, you won't have to do this kind of staring. The transformation just becomes another mindless mechanical manipulation.
Nevertheless, with a systematic, incremental attack, you can still untangle it. At least, you can eliminate the GO TOs. It may still be a ghastly mess, but you'll have a better chance of deciphering it when it is at least formally structured.
The strategy is to apply a series of transformations, step by step, until the complex loop becomes a simple loop. Then you transform it further as described above, and POOF! The GO TOs are gone.