UNTIL PROGRAM-COUNTER = 0 DO
CASE PROGRAM-COUNTER OF
1: BEGIN
IF NOT (OLD-PC = 3
OR OLD-PC = 7
OR OLD-PC = 8)
THEN ERROR;
OLD-PC := PROGRAM-COUNTER;
PERFORM MODULE1;
END;
2: ...
...
23: BEGIN
IF NOT (OLD-PC = 20
OR OLD-PC = 21)
THEN ERROR;
OLD-PC := PROGRAM-COUNTER;
PERFORM MODULE23;
END;
ENDCASE;
The code for each module must end with a statement that assigns a new value to PROGRAM-COUNTER
. The use of a number to identify the next module to execute obscures the code, so let us assume that we can use symbolic names (defined by a PARAMETER
statement, for example). Let us also assume the trivial syntactic sugar:
JUMP x
means PROGRAM-COUNTER := X
Then at the end of each module we can write a JUMP
statement to the next module. For example:
PROCEDURE MODULE23;
BEGIN
<do processing>;
IF <testl> THEN JUMP MODULE10
ELSE IF <test2> THEN JUMP MODULE15
ELSE JUMP MODULE20;
END;
Let us pause for a few observations. First, the outer loop of our program may be compared to a hardware CPU, and the modules to the instructions of that CPU. It has a program counter which takes us from instruction to instruction. (For an example of this style of programming in LISP, see [Sus75].) Second, our nice program has become a rat's nest of JUMP
statements (which might look more familiar had we used the keyword GOTO
instead of JUMP
). This is not at all surprising, since the structure of our program merely reflects the structure of our problem as exhibited in the state-transition diagram, and that too is a rat's nest. Third, our attempt to improve the program by using a nice, structured approach has resulted in the effective use of GOTO
all over the place!
We note that the use of symbolic names in JUMP
statement reduces the probability of errors in describing state transitions, and so we may feel confident in removing the error-checking code from the main loop. (Moreover, a cross-indexing program can find all the references to each module for us, which could not easily be done when numbers were used.) We furthermore can