Chapter 17 — Key Takeaways (Reading FORTRAN 77)

A one-page reference for reading fixed-form legacy code and mapping every old construct to its modern replacement. This is a reading chapter, so the "syntax" below is the syntax you must recognize, not write.

Fixed-form column rules (memorize)

Columns Meaning
1–5 statement label (a number, referenced by GO TO/DO/FORMAT)
6 continuation marker — nonblank = "continue the previous line"
7–72 the statement itself
73–80 ignored (historically the punch card's sequence number)
C or * in column 1 the whole line is a comment (no ! in strict F77)

The reflex: a baffling error in a .f file is a column nine times in ten — count columns before you suspect anything cleverer. Build old code with gfortran -std=legacy file.f.

The legacy → modern dictionary (the core of the chapter)

Legacy construct One-line "what it is" Modern replacement
COMMON /blk/ a, b, n shared memory, associated by position, unchecked a module with typed variables (Ch. 8)
BLOCK DATA the only unit that may initialize named COMMON a module parameter / declaration initializer
INCLUDE 'x.inc' raw textual paste to keep COMMON in sync use module, only: …
EQUIVALENCE (a, b) a and b are the same bytes (aliasing) allocatable (reuse), reshape (alias), transfer (bits)
GO TO 100 unconditional jump to a label do/exit/cycle, if
GO TO (l1,l2,l3), k computed GOTO — jump by integer index select case (with case default)
IF (e) l1,l2,l3 arithmetic IF — jump on sign(e) if … else if … end if
F(x) = expr statement function — inline one-liner internal pure function (Ch. 6)
ENTRY name second entry point sharing body/state separate module procedures
implicit typing first letter sets the type; IN are INTEGER implicit none + explicit declarations (Ch. 2)
DATA a, b /1.0, 2.0/ initialize via parallel value list declaration initializer (real :: a = 1.0)
nHtext (Hollerith) text named by length, pre-CHARACTER quoted character string

The two dangers to internalize

  • COMMON is a global untyped memory pool. Association is by position, and each routine is compiled separately, so a reordered or retyped declaration silently corrupts data with no error. Keeping the declaration in sync across files is what spawned INCLUDE.
  • EQUIVALENCE is deliberate aliasing. Two names, one storage: a write through one changes the other invisibly, type overlays are non-portable, and it defeats the optimizer (the opposite of Fortran's no-aliasing advantage). Find its intent — reuse, reshape, or bit-reinterpret — before you remove it.

Implicit typing, at a glance

First letter  I J K L M N   -> INTEGER
First letter  A-H, O-Z      -> REAL

Two bites: a typo invents a new garbage variable (no "undeclared" error), and a name you meant as real but that starts IN triggers silent integer division (1/N = 0). implicit none removes both.

The five-step reading method (any legacy file)

  1. Shape first — read the comments and routine names; get the job description before any logic.
  2. Shared state — find the COMMON blocks; that is the data model.
  3. Loops and exits — locate DO/GO TO loops and the IF (…) GO TO that leaves them.
  4. The kernel — find the few lines that do the math (often a statement function + one update).
  5. Hand-trace one step — confirm your reading against a concrete number before trusting it.

Panic comes from reading line 1 before line 2; calm comes from understanding the shape before any line.

The PLATE kernel (this chapter's legacy anchor)

  • What it is: about 100 lines of FORTRAN 77 (four program units, IMPLICIT DOUBLE PRECISION) solving steady-state heat conduction (Laplace's equation $\nabla^2 T = 0$) by Jacobi relaxation — repeatedly replacing each interior point with the average of its four neighbours until the largest change drops below TOL. Structure: PROGRAM PLATESETBC (boundaries) → RELAX (the GOTO convergence loop) → OUTPT.
  • The tell for Jacobi: the separate TNEW array — each sweep computes TNEW from the old T, then copies TNEW back into T. Updating from old neighbours is Jacobi; updating in place is Gauss–Seidel.
  • The four-line heart: the stencil TNEW(I,J) = AVG(T(I-1,J), T(I+1,J), T(I,J-1), T(I,J+1)) plus the DIFF/DMAX change-tracking. (PLATE uses no EQUIVALENCE or BLOCK DATA — the recipe is a menu.)
  • Why its answer is checkable: on the 4×4 test grid (top edge hot 100°, three edges cold 0°) the interior follows from symmetry — 3a - b = 100, a = 3bb = 12.5, a = 37.5 — dyadic and exact. It prints converged in 25 iterations and the interior 37.5000 / 12.5000.

Compile flag introduced

-std=legacy — accept obsolete features and read fixed-form source; how you build an inherited .f file.

Project piece added this chapter

Not solver code — a read, built, annotated, and output-pinned PLATE kernel. You compile it with -std=legacy, annotate each legacy construct with its modern replacement, and save its output as the regression reference for Chapter 18, where you modernize it step by step without changing the answer.

The ethic

Read before you rewrite; pin before you touch. Legacy scientific code is an inheritance — its validated numerics are worth more than its source. Reconstruct what it does, capture a reference output, and only then modernize — improving the engineering while proving you preserved the science.