Doctor Fortran in "Lest Old Acquaintance Be Forgot"

In some of my earlier posts I've discussed new features in the Fortran language that might be unfamiliar to some.  But this time I'm going to go the other way and describe some really old language features - so old that many newer Fortran programmers are mystified when they see them - but these features are still supported by many current compilers, including Intel Fortran.  So let's set the Wayback Machine to the 1960s and have a look around.

Computed GO TO

This feature remained in the standard through Fortran 95, not deleted until Fortran 2003. but you don't see it very often.  The syntax is:

GO TO (label-list), expr

where expr is an integer expression.  If the expression is 1, control transfers to the first label in the list, if 2, the second label, etc.  If the value is less than 1 or greater than the number of labels, execution "falls through" to the next statement.  For example:

GO TO (10,20,20,30), I

Nowadays the SELECT CASE construct is a preferred replacement.



Arithmetic IF

This is the one I see popping up most often in comp.lang.fortran posts where the author has come across it and has no idea what it does. The syntax is:

IF (expr) label1, label2, label3


Here, expr can be integer or real.  If the value is less than zero, control transfers to label1; if zero, label2; and if greater than zero, label 3. As with Computed GO TO, you can repeat labels if you wish.  Arithmetic IF was declared obsolescent in Fortran 90 and deleted in Fortran 95. The usual recommendation here is to use IF-THEN-ELSE (which was new in Fortran 77).

ASSIGNed GO TO and FORMAT

So let's say you had some common piece of code that needed access to your local variables and that was used in several places in a routine. Nowadays we'd use internal procedures, but before that, there was ASSIGNed GO TO.  The way it would work is you'd declare some integer variable, we'll call it IDEST here, and do something like this:

ASSIGN 30 TO IDEST
GO TO 900
30 CONTINUE
...
ASSIGN 40 TO IDEST
GO TO 900
40 CONTINUE
...
900 CONTINUE
... Do common stuff
GO TO IDEST


The jump to 900 would occur, the common code would execute, and then control would transfer to the label that had been assigned to the IDEST variable.  You could use ASSIGNed variables in place of FORMAT labels too in an I/O statement.

Back when I was working on VAX Fortran, I occasionally encountered programs written by customers who had cleverly noticed that the compiler implemented ASSIGNed GOTOs by simply storing the 32-bit address of the instruction at the assigned label into the variable.  They could then use this address in various ways, perhaps implementing some sort of array of pointers to statements.  (The compiler had to support 16-bit integer variables too, so what it stored there were offsets from the routine start address.)  This unraveled, though, when these applications were ported to the DEC Alpha processors, as the compiler there simply stored an index into a table rather than an instruction address.

ASSIGNed GO TO and FORMAT was declared obsolescent in Fortran 90 and deleted in Fortran 95.

Alternate Return

Here's one that actually stayed in the language through Fortran 95, though it had been named obsolescent in Fortran 90.  Let's say you wanted to call a subroutine but wanted, on return, to branch to some other label if some condition was met, rather than continuing after the CALL. So you'd do something like this:

CALL SUB (arg1, arg2, *10, *20)
...
SUBROUTINE SUB (arg1, arg2, *, *)


In subroutine SUB, you could return normally if you wanted.  But if you wanted to instead return and branch to the first alternate return label, you'd do:

RETURN 1


Similarly, if you wanted to return to the second alternate label, you'd write:

RETURN 2


The value could be any numeric expression that got converted to an integer.  If the value was less than 1 or more than the number of alternate return labels, a normal RETURN would be done.  Some compilers, as an extension, accepted the use of & in the CALL instead of * (but not in the subroutine argument list.)  Intel Fortran also supports that.

Hollerith Constants

FORTRAN 66 didn't have a character data type nor did it have character literals.  Instead, you could use Hollerith constants to assign values to numeric variables.  The form of a Hollerith constant is an integer specifying the number of characters, the letter H, and then however many characters were specified.  For example:

4HABCD


Hollerith constants were odd in that they had no intrinsic data type - they assumed the numeric (remember, no character type!) type based on the context in which they were used.  You could assign Hollerith constants to integer and real variables and the bytes of the characters would be stored directly.  If the constant's length were too short, it would be padded with blanks, and truncated if too long.  Many compilers had the extension of using apostrophe delimited strings as a substitute for Hollerith, so you might see something like:

INTEGER I
I = 'WHAT'


and be perplexed that the compiler accepted it.

Hollerith constants were not carried over from Fortran 66 to Fortran 77, though the 77 standard did have an appendix describing how they should work if a compiler chose to support them.  Note that there is also a Hollerith edit descriptor in formats, but those are treated like character strings and were still in the language through Fortran 90.

Writable FORMAT

This is the language feature that prompted me to write this post.  A user recently complained, in our user forum, that the output of his program was being corrupted by a READ.  In one part of a subroutine he had something like this:

WRITE (6,100) MM,DD,YY
100 FORMAT (I2,'/',I2,'/',I2)


and then later in this same routine:

READ (5,100) I



The first time through the routine, everything was fine, but on the second call, the WRITE had a blank in place of the first slash! What was going on here?

If you're familiar with the interaction between formats and I/O lists, you'll know that once an I/O list item has been "consumed" by an edit descriptor, processing of the format continues until it reaches another data-consuming edit descriptor, a colon, or the end of the format is reached.  So on the READ, processing continues and the '/' is seen.  What does this do on a READ?

In Fortran 77, this is not legal - you are not allowed to have an "apostrophe edit descriptor" in a format used by a READ.  But Fortran 66 did allow this, sort of.  Remember what I wrote above that compilers would treat quoted literals the same as Hollerith constants, so the format was treated as if it had 1H/ instead of the '/'.  Ok, but so what?

Here's where the ancient magic comes in.  Fortran 66 allowed you to READ into a Hollerth edit descriptor, changing the characters for future uses of that FORMAT.  This was usually done to provide titles for reports - you'd read the title from the input card deck (remember cards?) and then the title would appear when the FORMAT was used on subsequent WRITEs.  So what happened here is that a character was read from the input record and it replaced the slash.  In this customer's case, there were no more characters so the input record was padded with a blank.  The FORMAT effectively turned into:

100 FORMAT (I2,' ',I2,'/',I2)


for subsequent calls!  The fix I recommended was to use a separate FORMAT for the READ, rather than sharing the earlier one.

Well, that's enough for today.  Happy New Year, everyone!

For more complete information about compiler optimizations, see our Optimization Notice.
Categories: