Loops with Multiple Paragraphs
Your goal is to transform a GO TO loop into a PERFORM UNTIL loop,
in a mechanical rearrangement. You can't do that until the loop
consists of a single paragraph. If control passes through several
paragraphs before returning the the top of the loop, you must find
a way to collect the loop into a single paragraph.
(Strictly speaking that's not true. In some cases you could transform
the code directly into an in-line PERFORM UNTIL which
PERFORMs several paragraphs. However, this approach requires
ingenuity, and ingenuity is error-prone. I'm trying to minimize the
need for ingenuity by applying a series of changes, each of which is
simple and reliable.)
In large part you can apply the same techniques I've described before:
These techniques may not be enough. Read on.
Trading GO TOs for Flags
Each of several paragraphs may GO TO multiple destinations, depending on
various conditions. Such a situation calls for further trickery:
-
Identify all the GO TOs within the loop, and all their
destinations.
-
Create a flag with a series of values, one value
for each of the destinations. Assign an 88-level to each value. Since
these 88-levels are entirely artificial, you might as well give them
blatantly artificial names. If loop A contains GO TO 3960-POST-WTN,
you could name the 88-level LOOP-A-DEST-3960.
-
Create an ending paragraph for the loop. It will
test the flag you created in the previous step, and GO TO the
corresponding destination. For instance, it might look like this:
2299-LOOP-A-END.
*
EVALUATE TRUE
WHEN LOOP-A-DEST-2240
GO TO 2240-FINISH-WTN
WHEN LOOP-A-DEST-2250
GO TO 2250-FINISH-ORDER
WHEN LOOP-A-DEST-2200
GO TO 2200-START-LOOP
WHEN OTHER
CONTINUE
* (or some appropriate error handling)
END-EVALUATE.
-
Replace each GO TO in the original paragraphs with (1)
a SET statement for the appropriate 88-level, and (2) a GO TO with the
end paragraph as the destination. For example,
IF ORDER-NUMBER NOT = PREV-ORDER-NUMBER
GO TO 2250-FINISH-ORDER.
...becomes:
IF ORDER-NUMBER NOT = PREV-ORDER-NUMBER
SET LOOP-A-DEST-2250 TO TRUE
GO TO 2299-LOOP-A-END.
- Shift the GO TOs to the end of each paragraph.
Since they all have the same destination, and you have already
eliminated all fall-through logic, each paragraph now ends with an
unconditional GO TO.
This part is tricky because in its original position, each GO TO may
have made some of the later code unreachable. Add IFs and ELSEs as
needed to bypass the formerly unreachable code.
-
Percolate these unconditional GO TOs up into the first
paragraph of the loop.
At this point the loop has been reduced to two paragraphs. The first
one always exits by a GO TO to the second one. The second one is a
case structure selecting from a series of GO TOs on the basis of the
flag you created earlier. The other paragraphs are now PERFORMED. You
have removed them from the GO TO regime.
-
Collect the GO TOs in the first paragraph into a single
GO TO at the end. As before, add IFs and ELSEs as needed to bypass
formerly unreachable code.
-
Paste the second paragraph to the end of the first one.
Delete the GO TO and the paragraph label which separate them. Now the
loop is confined to a single paragraph.
There are many minor variations of this approach, and in a given case you
may find some short cuts along the way. My point is to suggest a general
plan of attack: defer all GO TOs until the end of the loop, at which
point you can choose your destination according to a previously set flag.
Whenever possible, isolate the main work of the loop in other paragraphs,
so that it doesn't clutter up the loop itself with distracting details.
By the time you finish this stage, the loop paragraph will do little else
but:
- PERFORM other paragraphs, and
- decide where to go next.
If you can't find a way to percolate all the GO TOs into the first
paragraph, it's probably because there's an inner loop nested within
an outer loop. Clean up the inner loop first. Then it will be just
another component of the outer loop, which you can clean up later.
Caveats
By the time we finish this stage, the new code may be about as ugly as
the old. Or worse. Particularly ugly is the use of a flag to instruct
a later paragraph where to GO TO.
However, we can tolerate this ugliness for now, for two reasons:
- The code was ugly to start with.
- It won't stay ugly.
In these pages I have concentrated on getting rid of GO TOs, but that
goal is only part of your task. At every stage you may find other
ways to simplify the code and improve the style. As you continue to
eliminate GO TOs, other kinds of improvements become easier to
find and implement.
Cobol Home
Cobol Style Forum
Spaghetti code