FORTRAN, an acronym for FORmula TRANslation, was developed in the 1950's by International Business Machines as a high-level programming environment for digital computers of moderate size (all modern PC's are of "moderate size" or better). It was particularly well adapted to the numerical calculations of science and engineering. Though originally intended for business applications as well, this role was assumed by COBOL (COmmon Business Oriented Language). By "high level" is meant that it uses ordinary words and algebraic notation instead of the machine commands. Nevertheless, its structure reflects the fundamental computer architecture in many ways. To develop a program, a text source file is created by an editor. In DOS, this source file has the default extension .FOR so that it is recognized as a FORTRAN source file. The source file is then submitted to a compiler, which interprets it in the form of machine language instructions, adding references to external machine language subroutines that actually perform most of the actions. The output file of the compiler is given the default extension .OBJ. The external machine language subroutines are then added by a program called a linker, which searches in library files for them, which have the default extension .LIB. The complete program is then assembled in relocatable form in an .EXE file. If the name of this executable file is submitted to DOS, DOS loads and executes it. The reader should note the sizes of the various files involved in this process. The source file is small, the .OBJ file somewhat larger, and the .EXE file is larger still, often very much larger. Compilers and linkers are relatively small programs, but the library .LIB is large. The details of this process are strongly influenced by DOS and by the processor (8086 family). However, similar facilities can be provided for any operating system and any processor. Most programming facilities now used hide much of the process from the user, decreasing flexibility but making it easy to use.
IBM extended and improved FORTRAN in FORTRAN II. In 1966, the American Standards Association issued a standard for FORTRAN IV (X3.9-1966) that was very widely used. This was further extended in ANSI X3.9-1977 to FORTRAN 77. Since then, there have been further extensions providing structured programming and graphical facilities, and FORTRAN is still in use for engineering applications. All versions of FORTRAN are mostly backwards-compatible and offer the same basic features. The FORTRAN that I will use here is Lahey Personal FORTRAN 77, ver. 1.00, as it appeared in 1987, and was intended for use in IBM PC's. It uses an 8087 coprocessor and requires 256KB of RAM. It runs very well at the MS-DOS prompt in Windows 98. Its speed with a modern processor is remarkable.
The original distribution diskette should be copied to a 1.44MB diskette. Also, the LINK program from an earlier version of DOS should also be copied. I used LINK ver. 2.4 supplied on the Supplementary Programs disk for DOS 3.2. Later versions of DOS did not include LINK, but it was supplied with most programming systems. The compiler is LP77.EXE. and the library is LP77.LIB. In Windows, at the MS-DOS prompt enter "cd \", then "md lp77", and finally "cd lp77" to get the prompt "c:\lp77>". Then copy all the files from the diskette with copy "a:\*.* .". That is all the installation that is needed; c:\lp77 may be added to the PATH in AUTOEXEC.BAT. This will allow you to compile and link in any directory.
There is a batch file T.BAT and a test program DEMO.FOR on the distribution disk. To test the installation, enter T DEMO. You should see banners from LP77 and LINK, and the program will run. The program finds factorials, prints a table of temperature conversions, and tells whether a number input is greater than, less than, or equal to zero. This will assure you that everything is working.
To make a Hello program, start Notepad and type the lines PROGRAM hello, PRINT *,'Hello, world!', and END, starting each line at the 7th character position (6 blanks leading). Don't press CR after END. Save the file as hello.for in \lp77. A source file may contain a maximum of 32,767 lines. Now, go to \lp77 and check that the program is there. You can even type it with "type hello.for" to see that it is okay. Compile it with lp77 hello /H, and then link it with link hello;. Don't forget to put the semicolon on the end. Now if you check the directory, you should see hello.exe, which is the executable file, and hello.lst, which is a listing of the program. If you make errors, they will be shown here. Type hello, and you will see Hello, world! on the screen. The switch /h turns on making a listing file.
The file LP77.FIG is a text file containing compiler options that is read when the compiler is started. Go ahead and "type" it to see what it is like. The default /o/n0/nh/nx means output compiler options, but don't turn off implicit typing (/n0), don't make a listing file (/nh), and don't make a cross-reference file (/nx). You can override these by switches on the command line, or you can change this file. We did this above with /h, and made a listing file.
The full linker command line is LINK hello,hello,NUL,lf77. The first operand defaults to .OBJ, the second is the name of the .EXE file, the third the .MAP file telling where LINK has put things; here it is NUL, and not created. Last is the library, defaulting to .LIB. To link several .OBJ files, join the names with +, and do the same if there are several .LIB files. A ; after any item accepts the defaults for the remaining items (.EXE name same as .OBJ, no map file, and .LIB in the same directory). Therefore, LINK hello; gets the job done for us.
FORTRAN programs were originally prepared on 80-column punched cards. The first five columns contained the label of up to five digits, if any. Any character in the sixth column, other than blank or zero, makes a card a continuation of the preceding card. The statement itself then occupied the next 66 columns (7-72). The 7th column of a continuation card came directly after the 72nd column of the preceding card. If a "C", "c" or "*" appears in the first column, the card is a comment. A trailing comment follows a ! and extends to the end of the line. The final 8 columns (73-80) were reserved for an identification serial number. This format is preserved in the lines of a source file, each of which is equivalent to a card. Cards were prepared most easily on an IBM keypunch (a large and expensive machine). A "deck" of cards held with an elastic band was submitted at the computer window. At a later time, the deck, with the ouput from a line printer wrapped around it, came out of the window. This procedure was iterated until satisfactory output was obtained. Now we can do all this in seconds at a console.
FORTRAN uses implicit typing, in which the type of a variable is determined by its first letter. By default, I,J,K,L,M,N begin Integer variables, while any other letter begins a Real variable. This can be changed by an IMPLICIT statement of the form IMPLICIT LOGICAL B, which would make any variable beginning with B a Boolean variable. IMPLICIT NONE turns off implicit typing, so that every variable would have to be declared. In LP77, the default Integer, Real or Logical are 4 bytes, and Complex is 8 bytes (two Reals). There are also REAL*8 or DOUBLE PRECISION, INTEGER*2 (16-bit integers), COMPLEX*16, LOGICAL*1, and CHARACTER. Default implicit typing only gives INTEGER*4 and REAL*4.
A variable declaration consists of a type, followed by the variable name, as "REAL*8 x, y", which declares x and y to be DOUBLE PRECISION. An array must be dimensioned in a DIMENSION statement, as well as typed. For example, DIMENSION a(1:10) creates an array with elements from a(1) to a(10). In this case, the 1: could be omitted, and DIMENSION a(10) would mean the same. FORTRAN indices usually start at 1, instead of 0 as in other programming languages. However, a FORTRAN array can start at 0, if dimensioned as a(0:9) for example. The array must also be typed, as by REAL a. Arrays may be multidimensional, as in a(i,j). Arrays are stored in the order in which the first index varies most rapidly, then the second, and so on. That is, a(2,2) is stored in the order a(1,1), a(2,1), a(1,2), a(2,2). An array may have up to 7 dimensions. The name of an array without indices can be used to represent the whole array, as in subroutine calls.
A COMPLEX constant is two reals in parentheses, as (0.0,1.0). The LOGICAL constants are .TRUE. and .FALSE. (T, F, true and false can be used on input). A constant with a "." is interpreted as REAL, while without a "." it is an INTEGER. FORTRAN converts between INTEGER and REAL whenever appropriate. A CHARACTER constant is delimited by ' ' or " ". A '' or a "" within a character constant are interpreted as one ' or one ", respectively. FORTRAN is not case-sensitive, and blanks are ignored except within character constants. There are no reserved words, but it is good practice not to redefine keywords. This means that the variable a b is the same as the variable ab. A CHARACTER variable has length 1, a CHARACTER*n has length n. if a variable C is declared as CHARACTER*80 C, the number of characters in C is LEN(C). A substring of C is C(m,n), consisting of the mth to the nth characters.
Variables may be initialized in a DATA statement. The list of variables is between slashes, followed by the values. There must be one value for each variable to be initialized. The DATA statement follows the declaration of the variables. It takes the form DATA /a,b/1.0,2.0. With this statement, a is given the value 1.0 and b the value 2.0. A value can be repeated with a repeat count like 4*1.0, which is equivalent to 1.0,1.0,1.0,1.0.
Numeric expressions involve **, *, /, + and -, as well as parentheses. If everything is INTEGER, then the value is INTEGER and / does integer division. If anything is REAL, then everything is converted to REAL. Expressions containing a complex number are complex. Modulus is an intrinsic function, not an operator like %. Exponentiation (**) is done first, and from right to left. Next in precedence is *,/ and after that, +,-, associating left to right. These operators are binary, except that + and - can be unary. Two operators cannot stand side by side.
The relational operators are .LT., .LE., .EQ., .NE., .GT., and .GE.. Note the leading and trailing dots. The logical (Boolean) operators are .NOT., .AND., .OR., .EQV. and .NEQV., in order of precedence. Exclusive-or is the same as .NEQV.. The only CHARACTER operator is //, which is concatenation.
Input and output at the console is rather simple. READ *, x will input x, while PRINT *, x will display it on the screen. the "*" refers to list-directed formatting. For greater flexibility, it can be replaced by the label of a FORMAT statement. If we use READ 10, x and 10 FORMAT('Enter x = ', F12.6) a prompt "Enter x = " will be printed. In the FORMAT statement, nX will skip n places, and / will go to the next line. For integers, Iw will print in a field of width w, and Iw.d will print at least d digits. Fw.d prints fixed point in a field of width w, with d digits after the decimal point. E will use exponential notation, while G will use either fixed point or exponential. Characters are formatted with A or Aw. When you use "*", the formats are I12 for INTEGER, I7 for INTEGER*2, G15.6E2 for REAL, G25.15D3 for DOUBLE PRECISION, L2 for LOGICAL, and ' (', G15.6E2, ',', G15.6E2, ')' for COMPLEX. Note that COMPLEX must be formatted to take two reals, and will not automatically come out in parentheses (except in list-directed formatting with *, or course). There are many details to data formatting, but this should be enough for casual use.
This is only a very brief introduction to I/O in FORTRAN, which is a rather elaborate subject in general. FORTRAN programs originally controlled access to sequential files on tape drives, that were such a prominent feature of mainframe computers, and often appeared in films, because they provided motion. A WRITE statement is, in full, WRITE (UNIT=5, ERR=10) v1, v2, ... , or just WRITE (5) v1, v2, ... if no action on error is specified (go to statement 10 in the first form). Unit 5 was the standard output, now the screen, and unit 6 was the standard input, now the keyboard. The use of unit numbers 5 and 6 is taken care of automatically in the * format. OPEN was used to prepare a unit for I/O, CLOSE to release it. INQUIRE, REWIND, BACKSPACE and ENDFILE controlled position on the file. These may be applied to disk files as well as to tape, but the details depend on the operating system. A filename is associated with a unit number in the OPEN statement.
Control structures in FORTRAN IV were only the DO loop for iteration, and the arithmetic and logical IF statements for branching. The DO loop consists of the statements between DO s i = n1,n2,n3 and s CONTINUE, where s is a label. One may jump out of a DO loop with a GO TO, but must not jump into a loop. The loop counter i begins at n1, is incremented by n3 at each iteration, and the loop terminates when it is greater than or equal to n2. The loop index must be integral, which is assured by implicit typing when it is chosen to be i.
An implied DO loop may appear in DATA and I/O statements. For example, DATA /(A(I), I = 1,10)/10*1.0 initializes the 10 elements of A(I) to 1.0. The first item in parentheses is the implied DO loop. The omission of the third DO parameter implies that the step is +1. The word DO is not used.
The arithmetic IF statement is IF (expr) s1,s2,s3. The numeric expression expr is evaluated. If it is less than 0, statement s1 is excuted, if it is equal to zero, statement s2 is executed, and if it is greater than 0 statement s3 is executed. This is the original FORTRAN decision statement, and is directly supported by the low-level machine instructions. It is actually a kind of GO TO instruction.
The logical IF statement is IF (bool) st. The Boolean expression bool is evaluated; if it is True, then statement st is executed. If it is False, st is ignored and execution goes to the next statement. st cannot be a DO or IF. In FORTRAN 77, the more general block IF statement appeared. This takes the form IF (bool) ... ELSE ... ENDIF. If bool is True, the block of statements between it and ELSE is executed. If it is False, the statements between ELSE and ENDIF are executed instead. After this, execution passes to the next statement. The ELSE can be omitted, and what results is like a logical IF with st expanded to a block. One may insert ELSE IF (bool) THEN to make a chain of IF statements that will perform a selection. IF statements may be nested, but this must be carefully done to assure that an ELSE is associated with the proper IF statement. DO loops may also be nested in IF ... ENDIF structures.
In FORTRAN 77 there is no way to delimit a block so that it can be used in the place of a single statement, as in C or Pascal. Later versions of FORTRAN include other program structures, like C or Pascal, so this problem may have been overcome. Since FORTRAN 77 has a full toolbox of GO TO's and the arithmetic IF, anything that can be done with control structures can also be done without them.
GO TO (this is written as two words, but FORTRAN does not recognize blanks or case, so it might be the same as goto) comes in three forms. GO TO n is an unconditional jump to statement label n. The computed GO TO is GO TO (s1, s2, ... ,sn) expr. First, expr is evaluated and converted to an integer. If the integer is i, then execution jumps to the ith label in the list in parentheses. The assigned GO TO takes the form GO TO i, (s1, s2, ..., sn). Before this statement is encountered, the integer i must have been assigned a value by a statement like ASSIGN s2 to i. Then there will be a jump to statment label s2.
The main program goes between PROGRAM name and END. A subroutine goes between SUBROUTINE name(v1, v2, ...) and END. The program may not contain a subroutine definition, and a subroutine definition may not contain another subroutine definition. This modularization is like that in C. Usually, the main program goes first, and is followed by the subroutines. There is no need to make a forward declaration of subroutines in the main program. A subroutine is executed by a CALL name(a1, a2, ..), where the actual arguments a1 and a2, etc., replace the formal arguments v1, v2, etc. The types must agree, but there is no checking at compile time. Variables are local to the main program and each subroutine. If the same variables are to be used in two modules, they must be declared in a COMMON statement that is placed in each module. A subroutine terminates when the END statement is reached, or a RETURN statement is executed. Variables in FORTRAN are passed by name, so that if a variable is modified in the subroutine, it is also modified in the caller. Values of variables in a subroutine disappear when the subroutine returns. If you want a variable to retain its value for the next time the subroutine is called, declare it in a SAVE statement. SAVE A will cause the value of A to be preserved between executions.
Additional entrance points to a subroutine may be declared by an ENTRY here(v1, v2, ...) statement, where v1, v2, etc. are formal parameters. The arbitrary name "here" can be CALLed with a real parameter list just like the subroutine itself. Execution will then proceed from this point in the subroutine up to the next RETURN or END. This really only makes parts of a subroutine subroutines themselves, without repeating the code elsewhere.
Statement functions can be defined in any program module. They have the form fname(v1, v2, ...) = expr. When the function is called by using its name with actual variables, expr is evaluated and the result is returned as the value of the function. Statement functions must appear before the first executable statement of a module, and must be defined before they are used.
An external function may be defined in a program module beginning with the heading: type FUNCTION fname(v1, v2, ...), and terminated by END. This is like a subroutine, but is executed by the use of the name with actual arguments instead of by a CALL. In the module, fname is assigned a value by fname = value. The intrinsic functions are predefined and can be used wherever necessary. The mathematical functions included in FORTRAN 77 are: abs, sqrt, exp, log, log10, sin, cos, tan, acos, asin, atan, atan2, sinh, cosh, tanh. All have one argument (except atan2(y/x)). For DOUBLE PRECISION, prefix a D to the name. For COMPLEX, cabs, conjg, csqrt, cexp, clog, csin, and ccos are available. Two reals are converted to complex by cmplx(x,y). The real part is obtained by real(c), the imaginary part by aimag(c).
Subroutine and function names may be passed as actual arguments to subroutines and functions, so the procedures can do different things at different times. Whenever the name of a procedure is used this way, it must be declared in an EXTERNAL or INTRINSIC statement, so it is not confused with a variable. The EXTERNAL statement takes the form EXTERNAL myfunc. The procedure myfunc is defined in another module. The INTRINSIC statement takes the form INTRINSIC sin,cos if you wish to use the intrinsic functions sin and cos as actual arguments. Statement functions defined in a module are known, and need not be declared.
The COMMON statement is a means of including the same variables in different program modules. It was originally a way of conserving valuable RAM space. A COMMON block may be given a name, placed between slashes, and its contents are given by a list of variables. The statement COMMON v1,v2,/up/ v3,v4 defines two blocks of COMMON, the "blank common" containing variables v1 and v2, and the "up" block, containing v3 and v4. If this appears in the main module, and COMMON v1,v2 appears in a subroutine, only the variables v1 and v2 may be used in the subroutine as well as in the main program. Another subroutine may contain COMMON /up/v3,v4. Here, variables v3 and v4 can be used and will be the same as the variables of the same name in the main rogram. COMMON has the same function as global variables in C. Blank common should be the same size as the largest blank common in any module. Variables are stored in the order listed in each module. All the variables need not be defined in every module that uses blank common, and the variable names need not be the same. It is easy to get into trouble with COMMON. Values are determined by where they are stored, not by the variable name. The safest method of using it is to use the same COMMON statement in all modules that use it.
Variables may share the same storage locations by means of the EQUIVALENCE statement. If EQUIVALENCE (X,Y) is declared, then X and Y share the same memory location. This does not cause any type conversion, and various rules are involved in the use of EQUIVALENCE. The PARAMETER statement gives names to constants. The parameter names are typed variable names. For example, if REAL i, COMPLEX c and PARAMETER (i = 1, c = i + 1), then PRINT *, i,c will produce 1.000000 (2.000000,0.000000). Note that the integer 1 is cast to a REAL, and the REAL 2.0 is cast to COMPLEX. The effects of EQUIVALENCE and PARAMETER can be obtained in other ways, so it is not necessary to use them. They should be understandable, however, in programs that you have to read.
I have mentioned most of the features of FORTRAN 77 here, but only a small number of them are really necessary for writing useful programs with input and output to the console. If you have access to a FORTRAN, by all means try to write some programs, perhaps to perform mathematical calculations.
Lahey Personal Fortran 77, Reference Manual (Incline Village, NV: Lahey Computer Systems, 1987).
Both of the following references describe FORTRAN programming in the age of punched cards and FORTRAN IV, and are well-written. They would still be good introductions to the subject, and contain many examples. Of course, they are long out of print, but should be preserved.
D. D. McCracken, FORTRAN With Engineering Applications (New York: John Wiley & Sons, 1967).
B. S. Gottfried, Programming With FORTRAN IV (New York: Quantum Publishers, 1972).
Composed by J. B. Calvert
Created 30 August 2004