I'm writing a toy Fortran 66 interpreter for fun -- want accuracy

I’m writing a toy Fortran 66/IV interpreter for fun. My goal has been to recreate some specific astronomical programs from the 70s and run them using the interpreter. I have this basically working now.

As a next step, for accuracy’s sake, I’m looking to get advice from anyone who has had experience using older versions of Fortran. Would also like to get advice if you programmed with punchcards – I realize this was a while ago.

Thanks!

4 Likes

I used F66 and punch cards long ago. I rewrote some programs in F77 when it became available. Is your interpreter translating your F66 code into a modern dialect of Fortran (F2023 or earlier? fixed or free source form?) or something else?

3 Likes

My Fortran IV experience goes back to 1973. At than time the F66 standard was not commonly used. Rather it was the manufacturer Fortran versions, which differed significantly.

My recollection of the biggest change from F66 (or rather McCracken Fortran IV) to F77 was for DO loops, with the introduction of many new definitions and restrictions on changing DO loop indices and limits, such as for:
DO 10 i = n1,n2,n3

10 CONTINUE
In this old loop usage, “i” or “n2” could be changed during the loop operation to vary the number of cycles. Also the value of “i” was not defined on exit from the loop, but took different values depending on the compilers I used.

There were also extensive variation between I/O and especially how files were opened/linked to Fortran unit numbers. ENCODE, DECODE, BACKSPACE and REWIND all behaved differently and were typically supported by “system” libraries.

The Fortran intrinsic routines were much more limited, with no such thing as generic routines.
There were basically SIN, COS, TAN, ATAN, IFIX and FLOAT; also EXP, LOG10, LOG or LN, together with their double precision equivalents. There was some support for COMPLEX. but no support for character, but only holerith constants stored in integer or real variables.
(Mixing the precision in these functions was a frequent source of coding errors.)

You really had to know which compiler was used and how many bits in an integer, real or double precision variable. You had to know this !
Knowing how many characters in a double precision real was key to using mixed mode computation and providing practical solutions, which many did achieve.

Oh, and there was no ALLOCATE (I think we can blame IBM for that one)

3 Likes

I’m writing the interpreter in C. It would be straightforward to output free-form given the fixed form input I am parsing.

Right now I’m focused on a subset of the full language sufficient to run some specific programs.

It sounds like each compiler had its own extensions and choices that differed from the spec.

It’s interesting the note about the DO loop restrictions added in F77 – the spec for F66 says that the iterator, end, and step values could not change during the course of the loop, though I do understand it was common practice to allow for that in F66 implementations.

It seems that character support was also a common extension on top of the F66 spec.

I’ve read some about punchcards and the 12 punch (“bit”) encodings they used, and how that was also system-dependent, with some systems extending the base character set with additional characters.

I’ll reach out directly with some additional questions – thanks for your responses.

The goal of the Fortran 66 committee seemed to be mostly to harmonize existing practice, and not develop the language. At that point in time, most were using some variation of IBM FORTRAN II, and moving towards their FORTRAN IV. So Fortran 66 was a large subset of FORTRAN IV.

I certainly punched cards back then, both on IBM 026 and 029 card punches. (Each with slightly different character sets than the other…) Then fed into the wonderfully fast CDC 405 card readers. IIRC, the 405 could read cards at a blindingly fast 1200 cards/minute!

There was no character data type in Fortran 66. So one had to suffer using packed Hollerith constants in integer “numeric storage units”. (Yes, one could use reals or logicals. But beware of your characters getting ‘normalized’, wierdness during comparisons, etc…) The number of characters per integer, and number of bits per character varied quite a bit. We found for best space vs portability to use 4 characters/integer. A little inefficient on machines that allowed more. E.g., the DEC-10 with 5 7-bit characters/word or the 60-bit CDC machines with 10 6-bit characters/word. On the other end of the spectrum, the PFORT guys at AT&T recommended 1 character/integer - which we considered pretty wasteful of memory. Packed characters meant that to process individual characters, non-standard bit manipulation needed to be done to unpack/repack, extract, replace, search, etc. To say the character data type in Fortran 77 was a huge improvement is an understatement!

DO loops were restricted compared to F77 and were commonly allowed to be extended in various incompatible ways. Also a related and big pain point was the restriction on subscript expressions - again commonly extended.

I/O was another big area of incompatibility. No OPEN/CLOSE/INQUIRE in Fortran 66. Remember that a lot of computers at that time didn’t even have a disk operating system. Or an operating system at all. By the time Fortran 77 was finally standardized, disk operating systems had become mainstream. Related to this was random access (access=‘direct’) I/O. FORTRAN IV had the beginnings of this, and each manufacturer had their own take. But it wasn’t standardized until Fortran 77.

Fortran 77 also gave us IF/ELSE IF/ELSE/ENDIF. But strangely, no END DO for DO loops. A Mil-spec extension was published shortly thereafter which required END DO, DO … WHILE, INCLUDE, and a set of bit manipulation intrinsics. But the Mil-spec extensions were not universally implemented until they went into Fortran 90.

One other aspect of ancient Fortran programs was that core memory was small and expensive. So larger programs often used overlaying techniques to cram more stuff into less memory. Every vendor had different ways of doing overlays. And even on a given system there might be multiple ways of doing them… And on a similar note, I remain astonished that local memory in procedures was allowed to be either static or on a stack. ALGOL 60 paved the way on this by requiring stack based allocation (and overridable via OWN). Fortran 66 should have learned that lesson. Would have saved a lot of overlaying hassle.

1 Like

I was unaware of these restrictions until recently when I was reading through the f66 standard looking for some other information. The fortran compilers I used (starting about 1973) all allowed more general subscript expressions. First, the f66 standard allowed 1D, 2D and 3D arrays only (higher dimensions were an extension until f77). Then second, the index values were restricted to only a small set of allowed expressions: c*v+k, c*v-k, c*v, v+k, v-k, v, and k. In those allowed subscript expressions, c and k are integer literal constants and v is an integer variable. Note that there is at most only one v allowed in each of those expressions. This is described in section 5.1.3.3 of the f66 standard.

I would say that it allowed (rather than required) ENDDO. Also, this extension with ENDDO still required a statement label. The unlabeled form was only standardized in f90. The practical difference is when you copy and paste code from one place to another, you had to be careful to avoid duplicating statement labels.

The problem here was that there were a competing set of bit functions defined by the f2c compiler, and those were used as the extensions in many compilers rather than the MIL-spec functions. Anyone writing portable code in the 1980s had to accommodate both conventions, and since fortran had no standard preprocessor or conditional compilation ability built-in, it was just another big PITA for fortran programmers.

1 Like

It allowed unlabeled DO…WHILE loops. But for regular indexed DO, END DO still required statement labels.

Back in the '70s I wrote my own preprocessor to do conditional compilation. I used it to keep track of the various differences between compilers/systems in the ‘machine dependent’ portion of our code. In retrospect, I should have also included an ‘include’ capability. Keeping COMMON blocks consistent everywhere was also a major PITA.

In case you don’t have it, the F66 standard can be found here.

Also, and to be honest I’m just discovering this today, there was a separate standard called “Basic FORTRAN”, X3.10-1966. It was essentially a more limited version of the language - five character identifiers instead of six, four-digit statement labels, no functions nor labeled COMMON blocks, etc. The differences are laid out in Appendix C of the F66 standard.

FORTRAN 77 had a “subset” language, but as far as I know nobody ever bothered with it.

1 Like

In 1978-79 I worked for a group that was doing development on a Data General Eclipse running AOS. The Fortran compiler was pretty much full Fortran 66, but had a 5 character limit on external names. We had to maintain a second version of the code with shortened names until DG finally shipped a compiler that supported longer names.

The Eclipse was a 16-bit mini with limited addressing - so of course we had to do a lot of overlaying to make things fit. Same when I ported our codes to the PDP-11 (IAS, which ran on top of RSX-11). There I could not get things to fit until I told the loader to split instructions/data into separate address spaces.

I also ported the code to the VAX - VMS v1.0. There our major problem was sending data transparently to/from our Tektronix 401x graphics terminals. The run-time kept gobbling up the special characters, and even the people I called at DEC couldn’t help me. Finally someone at Tektronix figured it out via direct WTQIO calls, and shared it with us.

1 Like

They were such an innovation. I learnt to write better Fortran by copying the Tektronix Fortran software library that was provided for Pr1me computers. (no recollection of special character problems?)

I celebrated when I stoped using the overlay linker on the PC (I think it was called Plink) The only benefit was it made the concept of scope a very real issue.

1 Like

Maybe of use for building the interpreter:

What is the largest program in FORTRAN IV (or FORTRAN II or FORTRAN I) from that era where we can find the source code? I found these: HistoricAerospaceSoftware/src/PropagationControl at c1f4009220e15c6b7a08ceea50f4e94f66a23330 · n7275/HistoricAerospaceSoftware · GitHub, but they are still relatively short functions in FORTRAN IV. Is there anything longer than that out there?

Regarding F66, what is the largest program out there?

There are lots of codes in F77, so plenty of examples there.

P.S. I was able to find this very nice pdf with code (over 1000 lines) from 1963: https://ntrs.nasa.gov/api/citations/19640000265/downloads/19640000265.pdf, n-body integration, including multipole moments of Earth, etc. The code itself is I am guessing FORTRAN IV? @csmoak you should try to get that code working in your interpreter!

IIRC, characters on the PR1ME had the high order bit set oddity. May have also been the system which didn’t have ENCODE/DECODE statements, so one had to call special entry points into the run-time. The folks at the PR1ME office were really nice. Sent us a whole pile of manuals without question.

The finite element code I was working on at the time was ~50k lines - divided into about a dozen programs and a library that was shared amongst them. We isolated everything machine-dependent we could into the library. But that was small compared to something like NASTRAN that was 10x larger.

1 Like

Not sure if it is the largest, but PFORT would be a good one: https://doi.org/10.1002/spe.4380040405. I’m not sure if it has any extensions. I have a feeling, the PFORT authors may have used it to test their own program.

A mirror can be found here: pfort: Portable Fortran Verifier
Also J. Burkardt has a copy (might be modified): PFORT - FORTRAN66 Verifier


The M3RK ODE integrator (https://dl.acm.org/doi/10.1145/355887.355897) has been verified by PFORT, and is hence F66.


ALTRAN would also be a good one (https://dl.acm.org/doi/10.1145/800204.806280). But I don’t know if the sources are available anywhere.


Estimation Subroutine Library (ESL), see A naive question about single precision - #5 by ivanpribec, would also be F66, probably with some extensions.

1 Like

If you are looking for a large Fortran IV/66 code to test LFortran, you might try the NASA NASTRAN-95 code. This is the 1995 release (not Fortran 95). Most of the source looks like its Fortran IV/66.

1 Like

I’m not sure about finding the source code, but in my field of molecular electronic structure, the large programs in the 1970s were GAUSSIAN, GAMESS, and GAMESS-UK. These codes are sometimes implemented as a monolithic single program (using overlays on 1970s era hardware), and sometimes they were implemented as a sequence of separate programs that communicate through external files. The first version of COLUMBUS was written in 1980 (based on earlier codes), and that was the approach that we took. All total, these programs were typically in the 50k to 100k lines of code range. The current versions of these codes are about 10x larger than those early versions.

1 Like

Thanks @ivanpribec, good pointers. I tried pfort with GFortran, got it to compile and run. I guess any paper we can find before 1977 must be F66 or older, unless they used some extensions.

The code looks like F77, no? I guess if it is a subset it could be F66. Yes, once we are done with modern Fortran, I was going to see if we can compile some of these old codes before F77, but they are surprisingly hard to find!

Thanks @RonShepard, yes, those are all famous programs, but even the first GAUSSIAN 70 source code doesn’t seem to be available. I wasn’t able to find the old sources for GAMESS either.

1 Like

Actually looks like a mix of some F77 but mostly Fortran IV to me. The F77 part is as best as I can see limited to INCLUDE and replacing hollerith constants. I don’t see any DO/ENDDO of IF/ENDIF constructs. Probably your only chance of seeing pure F66/IV is listings in some old NASA reports. As a side note. NASTRAN-95 looks like a good candidate for a test case for fpm also since there is no formal make or cmake files to build it, just some shell scripts. I got it all to compile about 6 years ago (with ifort if I remember correctly) with only one mod to a COMMON block file that had a weird extra non-printing character embedded in it. I might have an old copy of some NASA codes laying around in my archives that might be F66. I’ll look.

1 Like