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

Ralph Carmichael (old NASA engineer) has several old NASA codes on his Public Domain Aeronautical software - PDAS site. He has translated several of them to Fortran 90 but also includes the original source code for many of the codes he has refactored as well as some he hasn’t completed. Some of the original code even includes OVERLAY statements :grinning_face_with_smiling_eyes:. There is a good chance most (all ?) of the original source is Fortran IV/66.

1 Like

I really appreciate all the replies here, thanks for taking the time to dig in and find and share these links and notes.

I find some of the details of the F66 spec fascinating. Extended range DO loops seems to be a relatively unique feature of F66, for instance, and implementing it was interesting to figure out.

As far as I can tell, though '$’ is listed in the character set for F66, it has no stated purpose in the language. I assume it was primarily used in Hollerith strings for output, I’ve seen it available as part of extensions, and I’ve seen it used in job control cards.

I read some of the Basic Fortran spec, but I haven’t seen it mentioned anywhere else. Does anyone know if it was used for certain systems more constrained hardware?

One thing I’ve been trying to figure out is what punchcard encoding system was most likely accurate towards the end of the 70s. I see a certain encoding in the F66 manual, and it seems that was possibly for the IBM 026 keypunch, which seems to have been replaced by the IBM 029 keypunch by the mid-70s (as per Doug Jones's punched card codes ).

Thanks again!

1 Like

GitHub - FrankLhota56/fortran66-flex: Flex grammar for Fortran 66 may be relevant.

1 Like

I think the first f77 compiler I used was in late 1981, and I didn’t really start to use new f77 features until maybe a year or two after that (because I wanted my code to continue to compile on the current compilers). I remember many compilers began to implement some of the f77 features several years before they claimed full f77 compliance, the same as occurs now with, for example, f2023 features. I think the g77 compiler and the Cray CF77 compiler were both available in 1991 to give a couple of reference points. So I would say that anything prior to 1981 was most likely still f66+extensions, and that even codes written in the mid 1980s might have been developed on pre-f77 compilers.

1 Like

I think the first compiler with F77 features I used was the DEC VAX 11-780 compilers circa 1983 but I could be wrong. Maybe @sblionel can shed some light on when F77 started appearing in the DEC compilers and other compilers at that time.

1 Like

As is usually the case, features from new standards gradually appear in new compiler versions. F77 standardized a lot of things that were already common extensions, so by the time VAX-11 FORTRAN-IV-PLUS V1 (a retargeting of PDP-11 FORTRAN-IV-PLUS for RSX-11) came out in 1978, it was missing just a few F77 features. I joined the project at that time and implemented the remaining features in the run-time library, including Open on a Connected Unit. VAX-11 FORTRAN V2, 1980, was full F77.

2 Likes

I should also mention that DEC had been tracking (and actively participating in) the F77 standardization effort and had added some F77 features in advance of the publication in 1978. This bit them in one way - the PARAMETER declaration changed syntax between the final draft and the published standard, and DEC had already implemented (and released a compiler with) the earlier syntax that did not use parentheses and had different semantics. This meant DEC had to support both variants, and this experience soured the team on adding features before a new standard was published.

I think Cray experienced the same thing with ENUM from the 2003 Standard. Cray had ENUM in their compiler in 2003 (might have been 04) but allowed it to be “named” like in C. ie.

ENUM, BIND(C) :: aname

By the time the 03 standard was officially released in 04, I think the Cray version became non-standard. This bit me with some code I wrote using the Cray compiler because it was the first one I had access to that supported most of 2003.

@rwmsu and @sblionel thank you, that’s very useful. Do you know when compilers started supporting F66?

Also, how widespread was FORTRAN I and FORTRAN II? Did Fortran became mostly widespread with FORTRAN IV?

It seems we can find some FORTRAN IV codes out there (see this thread). But so far I wasn’t able to find FORTRAN II and I codes, except a few examples in manuals. Wikipedia has the following timeline:

Year Version
1957 FORTRAN
1958 FORTRAN II
1958 FORTRAN III
1961 FORTRAN IV

I think FORTRAN III was internal, right? And so FORTRAN IV was just 4 years after FORTRAN I.

I never heard of FORTRAN III, though I suppose it must have existed. F66 was the first standardized Fortran. There were many variants of Fortran before then. FORTRAN IV and FORTRAN 66 are generally used interchangeably, though the standard was just called FORTRAN. I think FORTRAN IV was an IBM name. I’m very skeptical of a 1961 date for FORTRAN IV.

1 Like

My first computing was in FORTRAN II on an IBM 1620 at Bristol University, UK, in 1963. In 1964 I changed to Algol because they got an Elliott 503 machine. It was much faster than the IBM machine, and Algol was nicer to read and write than that Fortran dialect.

2 Likes

If you go to the NASA NTRS STI web site and search on FORTRAN II, you will find a few reports in PDF format that have FORTRAN II listings. These reports appear to start around 1964. Interestingly, the first report that pops up is Fortan II to Fortran IV translator UOM SFT for the IBM 7090/7094. This report was published in 1965 so already there was interest in moving from Fortran II to Fortran IV. Note says the translator was written in SNOBOL. Anybody know where we can find a SNOBOL compiler/interpolator :smiley:.

1 Like

@rwmsu thank you so much, this is really useful! I found for example A surface-fitting program for areally- distributed data from the earth sciences and remote sensing - NASA Technical Reports Server (NTRS), from 1965, with a program in Fortran II, and what appears to be its compilation to assembly. A lot of the reports there do not have a download, but some do. I found quite a few Fortran II codes.

I found reports there from 1970s, even from 1975 that have programs in Fortran IV.

It’s more like an archeology at this point, but it would be cool to get some of these codes working. It might be ironically easier than trying to compile some modern codes, especially C++ codes with tons of dependencies. :slight_smile:

Great. So now in addition to LFortran, LPython, etc. you are going to have to do a LSnobol. :smiley:

1 Like

SNOBOL4 Programming Language download | SourceForge.net

SNOBOL is one of my favorite programming languages - I used it a LOT in college.

2 Likes

My use of Fortran IV started in 1973. My recall is the main variations at that time related to
support for the LOGICAL data type, ( IBM was late to give this )
the use of files, especially BACKSPACE and
ENCODE/DECODE and storing character strings in integer and real*8

Random/direct access files were via unique library routines, although functionality was typical on most mini computers (Vax, Pr1me and Data General)
Compilers supporting Fortran IV typically supported numerous extensions, so portability was a big issue when F77 was being scoped. I limited my use of Vax Fortran for that reason.

I don’t recall when the lower case character set became generally available for Fortran code ? Was that in the F77 standard ?

1 Like

Fortran 77 specified only uppercase characters in the fortran standard, but it also stated that the mapping from the native character set (i.e. the bit patterns that represented characters) to the fortran character set was not covered by the standard. Different people interpreted that in different ways. For example, the DEC compilers I used in the 70s (pre-f77) and 80s (f77) allowed both lower case and upper case in the source code and treated the two characters as the same (outside of characters or hollerith). Some people argued that this was not an extension of the standard, and this two-to-one mapping was outside the standard. That was the convention eventually adopted in f90 when both upper and lower case were added to the fortran character set. I also used compilers (ABSOFT was one example) that by default allowed both upper and lower case characters in f77 and treated them as distinct (like in C). Most people considered this an extension of the standard. ABSOFT had an option to use the two-to-one mapping convention, and other compilers had options to use the C convention. I also remember seeing a lot of code written for Cray computers that was entirely in lower case, which seemed odd to me at the time, considering the CDC legacy of 6-bit upper-case only characters.

1 Like

FWIW, here’s a program in FORTRAN II. I have added only the second line. Note that a PROGRAM statement was not required.

Mike

C        SOLUTION OF QUADRATIC EQUATION                                         
C        (P. 122 OF A FORTRAN PRIMER BY E. ORGANICK)                            
    1 READ INPUT TAPE 5, 51, ANAME, N                                           
   51 FORMAT(A6,I2)                                                             
      WRITE OUTPUT TAPE 6,52, ANAME                                             
   52 FORMAT(1H1,33HROOTS OF QUADRATIC EQUATIONS FROM A6)                       
      DO 21 I = 1, N                                                            
      READ INPUT TAPE 5, 53, A, B, C                                            
   53 FORMAT(3F10.2)                                                            
      WRITE OUTPUT TAPE 6,54, I, A, B, C                                        
   54 FORMAT(1H0,8HSET NO. I2/5H A = F8.2,12X,4HB = F8.2,12X,4HC = F8.2)        
      IF(A) 10, 7, 10                                                           
    7 RLIN = -C/B                                                               
      WRITE OUTPUT TAPE 6, 55, RLIN                                             
   55 FORMAT(7H LINEAR,25X,4HX = F10.3)                                         
      GO TO 21                                                                  
   10 D = B**2 - 4.*A*C                                                         
      IF(D) 12, 17, 17                                                          
   12 COMPR = -B/(2.*A)                                                         
      COMP1 = SQRTF(-D)/(2.*A)                                                  
      COMP2= -COMP1                                                             
      WRITE OUTPUT TAPE 6, 56, COMPR, COMP1, COMPR, COMP2                       
   56 FORMAT(8H COMPLEX,21X,7HR(X1)= F10.3,11X,7HI(X1)= F10.3,/1H ,28X,         
     17HR(X2)= F10.3,11X,7HI(X2)= F10.3)                                        
   16 GO TO 21                                                                  
   17 REAL1 = (-B + SQRTF(D))/(2.*A)                                            
      REAL2 = (-B - SQRTF(D))/(2.*A)                                            
   20 WRITE OUTPUT TAPE 6, 57, REAL1, REAL2                                     
   57 FORMAT(6H REAL 25X,5HX1 = F10.3,13X,5HX2 = F10.3)                         
   21 CONTINUE                                                                  
      WRITE OUTPUT TAPE 6, 58, ANAME                                            
   58 FORMAT(8H0END OF A6)                                                      
      GO TO 1                                                                   
      END                                                                       

2 Likes

2 Likes

A short session with ChatGPT 5.2 translated the code by Organick to

! quadratic.f90
!
! list-directed input (repeats until eof):
!   header: aname n          (aname is a single token; no embedded spaces)
!   then n lines: a b c

program quadratic
use, intrinsic :: iso_fortran_env, only: real64, input_unit, output_unit, error_unit, iostat_end
implicit none

integer, parameter :: dp = real64

character(len=6) :: aname
integer :: n, i, ios
real(dp) :: a, b, c
real(dp) :: d, rlin, real1, real2
real(dp) :: compr, compi

call print_instructions()

do
  read(input_unit, *, iostat=ios) aname, n
  if (ios == iostat_end) exit
  if (ios /= 0) then
    write(error_unit, '(a,i0)') 'read error in header record (aname,n); iostat=', ios
    stop 1
  end if

  write(output_unit, '(/,"roots of quadratic equations from ",a6)') aname

  do i = 1, n
    read(input_unit, *, iostat=ios) a, b, c
    if (ios /= 0) then
      write(error_unit, '(a,i0)') 'read error in coefficient record (a,b,c); iostat=', ios
      stop 1
    end if

    write(output_unit, '(/,"set no. ",i2,5x,"a = ",f8.2,12x,"b = ",f8.2,12x,"c = ",f8.2)') &
         i, a, b, c

    if (a == 0.0_dp) then
      if (b == 0.0_dp) then
        if (c == 0.0_dp) then
          write(output_unit, '(a)') ' degenerate                 all x satisfy 0 = 0'
        else
          write(output_unit, '(a)') ' degenerate                 no solution (0*x + c = 0, c /= 0)'
        end if
      else
        rlin = -c / b
        write(output_unit, '(" linear",25x,"x = ",f10.3)') rlin
      end if
    else
      d = b*b - 4.0_dp*a*c
      if (d < 0.0_dp) then
        compr = -b / (2.0_dp*a)
        compi = sqrt(-d) / (2.0_dp*a)
        write(output_unit, '(" complex",21x,"r(x1)= ",f10.3,11x,"i(x1)= ",f10.3,/, &
                             28x,"r(x2)= ",f10.3,11x,"i(x2)= ",f10.3)') &
             compr, compi, compr, -compi
      else
        real1 = (-b + sqrt(d)) / (2.0_dp*a)
        real2 = (-b - sqrt(d)) / (2.0_dp*a)
        write(output_unit, '(" real",25x,"x1 = ",f10.3,13x,"x2 = ",f10.3)') real1, real2
      end if
    end if
  end do

  write(output_unit, '(/,"end of ",a6)') aname
end do

contains

subroutine print_instructions()
  write(output_unit, '(a)') 'quadratic: roots of quadratic equations'
  write(output_unit, '(a)') ''
  write(output_unit, '(a)') 'input is list-directed (free-form). enter repeating blocks, then eof:'
  write(output_unit, '(a)') '  header: aname n'
  write(output_unit, '(a)') '    - aname is a single word (no spaces); it will be stored in 6 chars'
  write(output_unit, '(a)') '  then n lines: a b c'
  write(output_unit, '(a)') ''
  write(output_unit, '(a)') 'example:'
  write(output_unit, '(a)') '  sample 3'
  write(output_unit, '(a)') '  1.00 -3.00 2.00'
  write(output_unit, '(a)') '  1.00  2.00 5.00'
  write(output_unit, '(a)') '  0.00  2.00 -8.00'
  write(output_unit, '(a)') ''
end subroutine print_instructions

end program quadratic

which for input file

   sample 03
      1.00      -3.00       2.00
      1.00       2.00       5.00
      0.00       2.00      -8.00

gave

quadratic: roots of quadratic equations

input is list-directed (free-form). enter repeating blocks, then eof:
  header: aname n
    - aname is a single word (no spaces); it will be stored in 6 chars
  then n lines: a b c

example:
  sample 3
  1.00 -3.00 2.00
  1.00  2.00 5.00
  0.00  2.00 -8.00


roots of quadratic equations from sample

set no.  1     a =     1.00            b =    -3.00            c =     2.00
 real                         x1 =      2.000             x2 =      1.000

set no.  2     a =     1.00            b =     2.00            c =     5.00
 complex                     r(x1)=     -1.000           i(x1)=      2.000
                            r(x2)=     -1.000           i(x2)=     -2.000

set no.  3     a =     0.00            b =     2.00            c =    -8.00
 linear                         x =      4.000

end of sample

The LLMs can revive old code.