3 ways to write bugs with FORTRAN 77

I learned FORTRAN 77 programming when I was an undergraduate physics student in the early 1990s. While the Fortran 90 version of the language had been defined since 1990, and accepted by ANSI shortly after, my university didn’t have a Fortran 90 compiler on our VAX systems. And because FORTRAN 77 was long known as the standard FORTRAN, I never bothered to learn the newer variations.

I used FORTRAN 77 throughout my undergraduate career to analyze lab data. I also programmed in FORTRAN 77 during a summer internship at a research laboratory; when the other researchers realized I “knew FORTRAN,” they asked me to update an older program that was originally written in FORTRAN IV, then updated to FORTRAN 66, and later to FORTRAN 77. This really gave me a “deep dive” into some weird corners of FORTRAN.

FORTRAN 77 introduced the familiar IF and END IF blocks, with optional ELSE IF and ELSE statements, but earlier editions supported some strange IF variations to create conditional branches. In fact, three structures from the original FORTRAN (version 1 from the mid 1950s) were interesting solutions, but can cause endless headaches if used in modern times.

These structures will be very unfamiliar for new programmers, so I wanted to share this short list of 3 ways you can use these features to add interesting bugs to your FORTRAN programs:

1. Arithmetic IF

Classic FORTRAN has a three-way IF statement that can jump to different statement labels (labels are similar to line numbers, but not really) depending on the value of a variable. It looks like a normal IF statement, but you give an expression or value inside parentheses, then a list of three statement labels.

      IF (N) 20, 90, 30

The IF jumps to the first label if the value is less than zero, to the second label if the value is equal to zero, and the third label if greater than zero. Since that covers all possible values, the program should never just continue to the next statement; it should always jump to a new statement.

Here’s a sample program that shows the Arithmetic IF in action. This reads an integer from the user, and prints if it is less than zero, equal to zero, or greater than zero. Enter 0 to quit:

      PROGRAM ARITHIF
      INTEGER N
10    PRINT *, 'ENTER N: (0=STOP)'
      READ *, N
      IF (N) 20, 90, 30
      PRINT *, 'ERROR?'
      GOTO 10
20    PRINT *, '.LT.0'
      GOTO 10
30    PRINT *, '.GT.0'
      GOTO 10
90    PRINT *, '.EQ.0'
      END

Note that the two lines immediately after the Arithmetic IF should never be executed; that’s why I printed an error message, then looped back to the start:

      PRINT *, 'ERROR?'
      GOTO 10

Compile and run this program, then type in a few values to experiment with the Arithmetic IF. I’m compiling with GNU Fortran on Linux; if you don’t have the gfortran program, you can install it as the gcc-gfortran package. The -Wall option prints any warnings, and -std=legacy tells the compiler to assume legacy code syntax (such as FORTRAN 77) when it compiles the program:

$ gfortran -Wall -std=legacy -o aif aif.f

$ ./aif
 ENTER N: (0=STOP)
2
 .GT.0
 ENTER N: (0=STOP)
1
 .GT.0
 ENTER N: (0=STOP)
-2
 .LT.0
 ENTER N: (0=STOP)
-1
 .LT.0
 ENTER N: (0=STOP)
0
 .EQ.0

You can see that for 1 or 2, the program prints .GT.0 which is “FORTRAN-speak” for greater than zero. For -1 or -2, the program prints .LT.0, and for zero is prints .EQ.0 then quits.

2. Computed GOTO

The Computed GOTO is a strange beast that still gives me nightmares. It uses a list of statement labels in parentheses, plus a value or expression. If the value is 1, the GOTO jumps to the first label; if 2, it jumps to the second label; if 3, the third label; and so on.

      GOTO (10, 20, 30) N

If the value is zero or less, or if the value is greater than the count of labels, then control passes to the next statement in the program. If the value is well controlled and you know it will always be in a specific range, then this is a neat solution. But beware any programmer that does not put a “catch-all” statement after the Computed GOTO to trap any errant values.

Here’s a sample program that demonstrates how to use the Computed GOTO. This reads an integer from the user, then prints ONE if the value is 1, TWO if the value is 2, and THREE if it’s 3. For other values, the program prints a message and loops back to the start; enter zero to quit.

      PROGRAM COMPGOTO
      INTEGER N
1     PRINT *, 'ENTER N: (0=STOP)'
      READ *, N
      GOTO (10, 20, 30) N
      IF (N.LT.1) PRINT *, '.LT.1'
      IF (N.GT.3) PRINT *, '.GT.3'
      IF (N.EQ.0) GOTO 90
      GOTO 1
10    PRINT *, 'ONE'
      GOTO 1
20    PRINT *, 'TWO'
      GOTO 1
30    PRINT *, 'THREE'
      GOTO 1
90    END

If you compile and run the program, you can test it with a few values to see how the Computed GOTO jumps to each statement:

$ gfortran -Wall -std=legacy -o cgoto cgoto.f

$ ./cgoto
 ENTER N: (0=STOP)
1
 ONE
 ENTER N: (0=STOP)
2
 TWO
 ENTER N: (0=STOP)
3
 THREE
 ENTER N: (0=STOP)
4
 .GT.3
 ENTER N: (0=STOP)
-2
 .LT.1
 ENTER N: (0=STOP)
-1
 .LT.1
 ENTER N: (0=STOP)
0
 .LT.1

When you enter zero, that’s still less than 1, so the program prints .LT.1 before it exits.

3. Assigned GOTO

The Assigned GOTO statement is actually a two-part solution: first you use the ASSIGN statement to save a statement label in a variable, then use GOTO with the variable to jump to it.

10    ASSIGN 10 TO L

…and…

      GOTO L

This can be an interesting way to create a callback so you can jump back to some previous instruction, such as before the SUBROUTINE was added with FORTRAN II in 1958. But I never found a good reason to use this in a FORTRAN 77 program.

Here’s an example of an Assigned GOTO to see how to use it. This program reads an integer from the user, then prints ONE if the value is 1, or TWO if the value is 2, or THREE if 3. It prints nothing for other values, and quits when the user enters zero:

      PROGRAM AGOTO
      INTEGER N,L
10    ASSIGN 10 TO L
      PRINT *, 'ENTER N: (0=STOP)'
      READ *, N
      IF (N.EQ.0) ASSIGN 90 TO L
      IF (N.EQ.1) ASSIGN 1 TO L
      IF (N.EQ.2) ASSIGN 2 TO L
      IF (N.EQ.3) ASSIGN 3 TO L
      GOTO L
1     PRINT *, 'ONE'
      GOTO 10
2     PRINT *, 'TWO'
      GOTO 10
3     PRINT *, 'THREE'
      GOTO 10
90    END

Notice that statement label 10 has the initial ASSIGN statement, which sets the label 10 to the L variable. Later, the program can assign another label to the variable, which means we can use a simple GOTO L statement to jump to whatever label is stored in the L variable at the time.

You can see the Assigned GOTO in action if you compile the program and test it with a few values. While I usually use the -Wall option to print all warnings, I skipped that option here because otherwise the compiler complains that my statement labels are never used; the GNU Fortran compiler doesn’t track the labels with the different values in the ASSIGN and Assigned GOTO statements:

$ gfortran -std=legacy -o agoto agoto.f

$ ./agoto
 ENTER N: (0=STOP)
1
 ONE
 ENTER N: (0=STOP)
2
 TWO
 ENTER N: (0=STOP)
3
 THREE
 ENTER N: (0=STOP)
4
 ENTER N: (0=STOP)
-1
 ENTER N: (0=STOP)
0

Test them with Countdown

It might be helpful to compare these methods by writing several programs that do the same thing but in different ways. This program is just a “Countdown” program; it counts from 10 to 1, and prints each number. The simplest example of this program uses the DO loop, introduced to the language in FORTRAN 66. The basic concept of DO is the same as a for loop in other programming languages; you specify the start, stop, and increment values, and the program iterates a variable’s value through the loop:

      PROGRAM COUNT
      INTEGER I
      DO 10 I= 10, 1, -1
10    PRINT *, I
      END

If you compile and run the program, you will get a list of numbers counting down from 10 to 1:

$ gfortran -Wall -std=legacy -o count count.f

$ ./count
          10
           9
           8
           7
           6
           5
           4
           3
           2
           1

Now let’s make the program a little more complicated by using the Computed GOTO instead of the DO loop. This uses a trivial example of the Computed GOTO with just one statement label, so the GOTO will only jump to statement 20 (the END statement) when N has reached the value 1. Otherwise, control passes to the next statement, which decrements the N variable and restarts the loop:

      PROGRAM COUNT
      INTEGER N
      N = 10
10    PRINT *, N
      GOTO (20) N
      N = N - 1
      GOTO 10
20    END

A slightly more unnecessarily complex version of the program uses the Arithmetic IF. This restructures the program a little bit, by initializing the N variable to 10, then entering a kind of “manual loop.” The Arithmetic IF jumps to label 10 (the start of the loop) as long as the N counter variable is greater than zero. When the count reaches zero, the Arithmetic IF jumps to line 30 (the END statement). This program should never have N less than zero, so I’ve added an error statement as a fallback:

      PROGRAM COUNT
      INTEGER N
      N = 10
10    PRINT *, N
      N = N - 1
      IF (N) 20, 30, 10
20    PRINT *, 'LESS THAN ZERO .. SHOULD NOT GET HERE'
30    END

Walk through the program yourself to see what it does: On the first pass, N starts at 10, the program prints it, and then decrements the N variable. The new value (9) is greater than zero, so the program starts the loop over again. On the final pass when N is 1, the program prints it, then decrements the variable to zero. Since N is now zero, the Arithmetic IF jumps to line 30, which ends the program.

One more way to write this in the old-style syntax is with the Assigned GOTO. This uses a separate variable called L to store a line label. Before starting the loop, the program assigns label 10 to the L variable; this allows the program to simply use GOTO L to jump back to 10 by default. In the last pass of the loop when N is 1, the program assigns label 20 (the END statement) to the L variable, so the program can exit.

      PROGRAM COUNT
      INTEGER N, L
      ASSIGN 10 TO L
      N = 10
10    PRINT *, N
      IF (N.EQ.1) ASSIGN 20 TO L
      N = N - 1
      GOTO L
20    END

Each of these variations of the program do the same thing: count down from 10 to 1, and print each value. Writing the same program in four different ways helps us to compare what the program is doing so we can see Arithmetic IF, Assigned GOTO, and Computed GOTO in action.

Leave a Reply