8

FORTRAN had an 'assigned goto' statement. Firstly, a statement number is assigned to a variable:

ASSIGN 42 TO L

Subsequently, one can obey

GOTO L

which (given the preceding ASSIGN) would transfer control to the statement labelled 42.

But in actual fact, the assigned goto had to be given a list of statement numbers:

GOTO L, (17, 23, 42, 63, 99)

Why was that needed or chosen?

I would suppose that the affect of ASSIGN is to set the variable to the actual address corresponding to the labelled statement. That being so, the assigned goto is just an indirect jump through the variable. What purpose does the statement-label list serve?

Compare with the computed-goto, which is somewhat like the Algol switch statement: given an integer N, jump to the N'th label.

 GOTO (17, 23, 42, 63, 99), N

For this case it's clear the label list is needed. But not in the assigned-goto case.

2
  • Did the assigned label list restrict the values that could be used in L? Like in your example, could you ASSIGN 11 TO L and then execute the GOTO L statement with 11 not being in the list? That would at least give the poor reader some clue where the jump might go, rather than just anywhere. Aug 25 '20 at 3:35
  • With DEC's F77 compiler, a statement number not in the list causes fall-through. Ugly! Aug 27 '20 at 2:22
17

TL;DR:

That being so, the assigned goto is just an indirect jump through the variable.

Right.

But in actual fact, the assigned goto had to be given a list of statement numbers

No, it had not. The list was always an optional one. If not given, the GOTO was simply executed without any further check.

What purpose does the statement-label list serve?

It's a run time check for valid targets.

This is why literature often calls the variants as 'Unguarded' (without a list) or 'Guarded' (with a list) Assigned GOTO.

It's important to keep in mind that FORTRAN was missing next to all control structures we take for granted today. FORTRAN is the prototypical spaghetti code and Assigned GOTO was the way to create complex structures with jump targets hidden in variables.

Adding a list to check against was a way to make certain loop constructions spaghetti code manageable (kind of) as well as to catch pointer errors. Not really the best way for either, but these were the beginnings of HLL, one had to start somewhere.


In Detail:

Using assign basically turns an integer into a pointer and loads it with the address of the label, not its numeric value.

An Unguarded Assigned GOTO takes the pointer value of the integer and jumps. With a list added it checks if the Integer holds the address of any single label within the list and only jumps when it's among them.

Think of forming a loop with a various cases within, like a state machine. Remember, there was no switch/case like statement in FORTRAN, so it had to be done some other way. And assigned GOTO was the way to go. At the end of each state check the next state was loaded into an integer but control was returned (via unconditional GOTO) to the main loop, which picked the next data and switched accordingly.

All of this ends up with a vast number of targets. In addition storage, and thus variables, was limited, so variables get reused. Using a single variable (like IGO) for all/most Assigned GOTO in a program was quite common. So this variable might contain some value from outside the loop constructions one was in. Quite a good chance to ass programming errors ending up at a GOTO IGO with a leftover target from some prior construct.

Being able to name a list of all (at the point) valid targets seemed like a good idea to catch that and make sure all works as intended.

At that point it's once again important that we talk about a time when everything was barely invented, machines were small and compilers straightforward without much ability or even chance for checking. Not to mention that FORTRAN was on purpose kept simple to have users adopt it. Maybe hard to believe, but scientists were hardcore Assembly users at that time. So many concepts were tried, some of them might look strange from today's orderly landscape.

In addition, FORTRAN, as simple as it may seem today, was considered by many users as bloat. So making it work as straightforward as possible, so users can imagine the Assembly code while writing FORTRAN, was mandatory. There is a very nice interview with Frances Allen talking about this time.


Now, in a perfect world it could end here, but the real world also included implementation specific effects. The FORTRAN description did leave up a few grey areas:

For one it didn't define if and how an integer used to hold an integer is prevented against being used as target, nor if and how one holding a target is protected against being used as integer.

Using a Guarded Assigned GOTO one way to protect against such errors, by checking the values against legal values.

Second, it wasn't stated what happens if the integer is holding a target that is not within the list. Some implementation simply dropped to the next statement, while others threw an exception ending the program - which might be the most safe way.

Well, and some ignored the list at all.

Spaghetti code, implementation dependant behaviour, added, changed or missing instructions - everything we love and hate about BASIC was already present in FORTRAN, but on a much worse level.


With the introduction of additional loop control (WHILE, EXIT, etc.) in many FORTRAN-77 compilers (aka FORTRAN-78) the use of Assigned GOTO as well as computed GOTO or alternate returns became obsolete and finally removed in FORTRAN-90.

16
  • 2
    My experiments show that even a 1973 BESM-6 FORTRAN compiler directly recoded from a (much older) CDC 1604 compiler does not require the list of potential labels, and when it is present but does not include the assigned label, the GOTO is still performed. In other words, not all compilers honored the list to perform the runtime check.
    – Leo B.
    Aug 25 '20 at 4:00
  • 2
    I should perhaps add, I didn't acquire the IBSYS FORTRAN manual as an "historical document" :-) Aug 25 '20 at 22:25
  • 1
    @Raffzahn The first one is FORTRAN-BESM-6 (1973), transcoded from CDC 1604. The second one is FORTRAN-GDR (I'm not sure in what organization it was written), 1981. The third one is FOREX by Keldysh Institute of Applied Mathematics, 1985. If a scalar variable is used in the GOTO, none of the three require a list. FORTRAN-GDR wants to see a comma if it sees a parenthesis in a GOTO statement.
    – Leo B.
    Aug 26 '20 at 7:42
  • 1
    The DEC F77 compiler (RSX-11M-PLUS) supports an optional label list. Without the list, an arbitrary ASSIGN stmt TO N; GOTO N will succeed. With a list not containing N, the GOTO simply falls through. That last seems to be a particularly ugly choice. Aug 27 '20 at 2:13
  • 1
    @WalterMitty in another question pointed us at the DEC PDP-10 FORTRAN IV manual. It explicitly describes fall-through for label not in list. Aug 27 '20 at 12:21
10

First of all, the accepted answer is wrong; the statement list was not optional in the "original" FORTRANs (I and II). Here is a listing of the routine used to read GO TO statements:

       REM * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
       REM
       REM C0200/ CALLS=GETIFN,DIAG,TEST..,C0190,C0180,TET00,C0160,
       REM CIT00,SS000(CSA000).
       REM C0200 PROCESSES GO TO STATEMENTS.
C0200  TSX GETIFN,4                * GET INTERNAL FORMULA NUMBER IN 1C
       STO 1C+2                      AND IN 1C+2.
       TSX C0190,4                 * OBTAIN IN ACC NEXT NB CHARACTER
       CAS L(9)                      AND COMPARE IT WITH 9.
       TXI C0205,0                   IF NON-NUMERIC, GO COMPARE WITH (.
       NOP                           IF NUMERIC, THEN
       TSX C0180,2                 * OBTAIN IN 1G THE BINARY EQUV BETA.
       TSX TESTD0,4                * THE AC SHOULD CONTAIN AN ENDMARK.
       CLA 1G                        STORE BETA IN 1C+1 TO CONSTRUCT
       STO 1C+1                      THE 2ND WORD OF TIFGO TABLE ENTRY.
       TXI C0202,0                   GO  TO ENTER 1C,1C+1 INTO TIFGO.
C0205  CAS ALPAR                     TEST CHARACTER FOR ALPHABETIC.
       TXI C0210,0                   IF NOT ALPHABETIC, THEN
       TXI C0212,0                   THIS IS TYPE= GO TO ( ), I.
C0210  TSX C0160,2                 * TYPE= GO TO N,(),SO OBTAIN IN 1G N
       TSX TESTG0,4                * WHICH SHOULD BE FOLLOWED BY COMMA.
       CLA 1G                        SAVE THE SYMBOL N IN 1C+3
       STO 1C+3                      FOR COMPILED INSTRUCTION.
       TSX C0190,4                 * OBTAIN IN ACC NEXT NB CHARACTER,
       TSX TESTE0,4                * WHICH SHOULD BE A LPARAN.
       CLA L(1)                      PREPARE TO SET ADDRESS PART OF 1C
       TRA C0213                     TO 1 TO INDICATE CLASS OF TRANSFER.
C0212  CLA L(2)                      PREPARE TO SET ADDR OF 1C TO 2.
C0213  STA 1C                        STORE 1 OR 2 IN ADDR OF 1C.
       LXD CTRAD,2                   OBTAIN 250-(NO. TRAD ENTRIES), AND
       PXD ,2                        PLACE IN THE DECREMENT OF THE AC
       STO 1C+1                      AND STORE IN 1C+1.
C0215  TSX C0190,4                 * OBTAIN IN ACC NEXT NB CHAR.
       TSX C0180,2                 * OBTAIN IN 1G THE BIN EQU OF BETA.
       STO 2G                        SAVE CHAR IN ACC.
       TSX TET00,1                 * GO TO ENTER 1G
       PZE 3                         INTO TRAD TABLE (TABLE 3).
       LXD CTRAD,2                   REDUCE COUNTER
       TIX C0216,2,1                 CTRAD
C0216  SXD CTRAD,2                   BY 1.
       CLA 2G                        RESTORE CHAR TO ACC.
       TSX TESTB0,4                * TEST FOR COMMA OR RPAREN.
       TNZ C0215                     IF RIGHT PARENTHESIS, THEN
       CLA CTRAD                     OBTAIN IN ADDR OF ACC 250-NO. OF
       ARS 18                        ENTRIES IN TRAD TABLE,AND STORE
       STA 1C+1                      IN ADDR OF 1C+1.
       CLA 1C                        OBTAIN 1C IN ACC
       LBT                           AND TEST LOW ORDER BIT.
       TRA C0220                     THIS IS A TYPE GO TO (),I FORMULA.
       TSX C0190,4                 * OBTAIN NEXT NB CHAR AND
       TSX TESTD0,4                * TEST FOR ENDMK.
       TSX CIT00,4                 * GO MAKE THE FOLLOWING CIT ENTRY=
       PZE 1C+2                      WORD 1--DECR= INTFORMNN (LOCATION)
       PZE L(TRA)                    WORD 2--TRA00P (OP AND DECR)
       PZE 1C+3                      WORD 3--VARIABLE N (ADDRESS)
       PZE L(0)                      WORD 4--00000 (REL ADDR AND TAG).
       TRA C0202                     GO TO ENTER 1C,1C+1 INTO TIFGO.
C0220  TSX C0190,4                 * EXAMINE NEXT NB CHARACTER,
       TSX TESTG0,4                * WHICH SHOULD BE A COMMA.
       TSX C0190,4                 * OBTAIN IN ACC NEXT NB CHAR, AND
       TSX C0160,2                 * OBTAIN IN 1G THE FXF-PT. VARIABLE.
       TSX TESTD0,4                * WHICH SHOULD BE FOLLOWED BY ENDMK.
       CLA L(1)                      PREPARE PROPER FORM OF SUBSCRIPT
       STO E+3                       COMBINATION AS
       STO DIMCTR                    INPUT TO SUBSCRIPT ANALYSIS=
       CLA 1G                        E+3 = 1ST COEFFICIENT.
       STO E+4                       E+4 = 1ST SUBSCRIPT VARIABLE,
       STZ E+9                       E+9 = ADDEND OF SUBSCRIPT,
       TSX CSA000,4                * DIMCTR = DIMENSION OF VARIABLE.
       CLA E                         OUTPUT FROM CSA IS FOUND IN
       ARS 24                        E = I--TAUTAG (GENERAL TAG) 1-11.
       STO 2G                        ADJUST AND SAVE FOR COMP. INSTR.
       TSX CIT00,4                 * GO MAKE THE FOLLOWING CIT ENTRY=
       PZE 1C+2                      WORD 1--DECR-INTFORMNO(LOCATION)
       PZE L(TRA)                    WORD 2--TRA000(OP AND DECR)
       PZE L(0)                      WORD 3--000000(ADDRESS)
       PZE 2G                        WORD 4--ADDR = TAUTAG FOR I
       REM C0200= ENTRY POINT USED BY C0400,C1000.
C0202  TSX TET00,1                 * GO TO TET TO ENTER 1C AND 1C+1
       PZE 2                         INTO TIFGO TABLE (TABLE 2).
 CTRAD TXI CA010,0,250             * EXIT TO PROCESS NEXT STATEMENT.
       REM  END OF PROGRAM C0200.

(See the end of this answer for the source of the code.)

Clearly a comma and a statement list is expected when GO TO is not followed by a number.

But why was it required? Well, the reason is a little complicated. It certainly wasn't for the benefit the programmer or for safety. The concept of a run-time error check generated by a compiler was, after all, a silly idea at the time. The following discussion pertains to IBM's FORTRAN I and II for the 704/709/7090/7094.

In actuality, the list was necessary for the compiler. During the flow analysis phase, the user's program is divided into basic blocks, and control transfers between the blocks are recorded. Then a simulation of the program is carried out to determine the relative frequency of execution of blocks. (Naturally, any information provided in FREQUENCY specifications is taken into account here.) The knowledge gained in this process is used by the register allocation algorithm, which tries to minimize the use of load/store operations in "hot" portions of the user's code.

Because ASSIGN statements can occur anywhere in a FORTRAN program, the compiler couldn't know where control might be sent by a GO TO statement with a non-numeric operand unless the entire program has been read and all ASSIGNs have been seen. Upon seeing GO TO N, (...), the compiler makes a table entry saying "at this point, we might transfer to any one of these statements"; a similar thing happens for computed GO TO statements as well. The determination of basic blocks is based on these table entries, and not on accumulated constants in ASSIGN statements, since this way is more straightforward and avoids creating a symbol table exclusively for ASSIGNed variables. Also, the list of targets lets the compiler produce a diagnostic if an illegal transfer (e.g., one leading into the range of a DO loop that has not yet been entered) might happen.

Consider also how the form of computed and ASSIGNed GO TO allows for a micro-optimization. Here are excerpts from a real FORTRAN program (from 1965, but these parts use nothing that wasn't available in FORTRAN II; regardless, this is just an example for illustration, and the source is linked at the end of this answer):

  216 ASSIGN 224 TO KADD1
      ASSIGN 250 TO KADD2
      ...
      ASSIGN 240 TO KADD2
      ...
      ASSIGN 223 TO KADD1
      ...
      ASSIGN 223 TO KADD1
      ...
      GO TO KADD2,(240,250)
 240  PRINT 1017
 1017 FORMAT(1H0,10X,84H** INDICATES THAT THIS VALUE IS TOO HIGH DUE TO
     XSAMPLING ERROR. IT WILL BE SET EQUAL/14X,71HTO THE MAXIMUM VALUE O
     XF THE REMAINING COHERENCES FOR PLOTTING PURPOSES.)
  250 GO TO KADD1,(223,224)
 223  PRINT 1018
 1018 FORMAT(1H0,10X,91HX INDICATES THIS VALUE IS NOT COMPUTABLE DUE TO
     XA NEGATIVE OR ZERO POWER SPECTRAL ESTIMATE./13X,82HIT WILL BE SET
     XEQUAL TO THE MAXIMUM OF THE REMAINING VALUES FOR PLOTTING PURPOSES
     X.)
 224  IF(IPRNT3(KIT+1)-IB)231,232,231

and later

      ASSIGN 442 TO KADD1
      ASSIGN 433 TO KADD2
      ...
  432 GO TO KADD2,(433,434)
  433 SPMAX=-9999999.0
      ...
      ASSIGN 440 TO KADD1
      ASSIGN 434 TO KADD2
  434 SPX(I)=SPMAX
      ...
      GO TO KADD1,(440,442)
 440  PRINT 1405

If the analysis were based on ASSIGN statements, then the compiler would have to treat a GO TO KADD1 as potentially transferring to any of the statements 223, 224, 440, and 442, even though such a four-way transfer isn't actually possible. A "sufficiently smart compiler" could determine this itself, but this was 1958.

Note that the LLVM indirectbr instruction, which performs an indirect transfer of control much like FORTRAN's assigned GO TO, also requires a list of potential locations "so that dataflow analysis has an accurate understanding of the CFG [control-flow graph]".

The level of optimization achieved by IBM's FORTRAN I and FORTRAN II was not matched by another FORTRAN compiler for quite a long time, according to what I've read. Compilers that didn't do sophisticated flow analysis did not have the same need for the target list in ASSIGNed GO TO statements. Therefore it became optional.


Sources (credit for most of them goes to the Software Preservation Group's fantastic History of FORTRAN and FORTRAN II page):

The main source is the Systems Manual for 704 FORTRAN and 709 FORTRAN. Applied Programming Department, International Business Machines Corporation, April 1960. This is a must-read if you're interested in FORTRAN I/II's internals.

The next source is a listing of FORTRAN II's source code. The GO TO processing routine C0200 begins at sequence number 4F11844, which is on page 70 of the PDF of Volume I (according to the handwritten page number in the bottom right, this is logically page 66).

The FORTRAN example came from the fabulous B5500 Software repository. The specific source was file BMD02T/T800016, which is headed "AUTOCOVARIANCE AND POWER SPECTRAL ANALYSIS". The dialect of FORTRAN here is B5500 FORTRAN IV; a manual for it from 1968 (three years after the quoted code was written) is available here.

Jack Harper's website on the IBM 7090/7094 computers is a great resource when studying old programs like FORTRAN II and the LISP 1.5 interpreter.

1

As an example, the PDP-11 FORTRAN (UNIX V5) had a runtime check, if the label list had been provided. An attempt to jump to a label not equivalent to those mentioned on the list would result in a runtime error.

Using an online emulator,

Paul Nankervis - paulnank@hotmail.com

Boot> boot rk0
@unix

login: root
# chdir /tmp
# cat > test.f
      assign 10 to l
      goto l,(20)
      stop
  10  print 1
   1  format(' label 10')
      stop
  20  print 2
   2  format(' label 20')
      stop
      end
Ctrl/D
# fc test.f
# ./a.out
Runtime error 14

Whereas the program with just goto l prints label 10, as expected.

However, this works:

      assign 10 to l
      goto l,(20)
   10 continue
   20 continue
      end

because both labels resolve to the same offset in the compiled executable, and the check succeeds.

1

I'm posting my own answer as a summary, just prior to accepting someone else's.

  1. The statement list is not necessary. If present, it may be used for validation of the jump target. If absent, the GOTO will jump regardless.

  2. The statement list is optional in some implementations. We have not yet proven whether it was/wasn't optional in the original FORTRAN.

  3. If the statement list is supplied on the GOTO, and the variable is assigned a statement not in the list, the results vary between implementations.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.