4. FORTRAN Coding Standards

4.1 Introduction

The purpose of a FORTRAN standard is to ensure that the FORTRAN code will be as portable as possible as well as be consistent throughout the system. This standard covers information on how to write code.

The following material is based substantially on a summary by the author of Chapters 8 and 9 of the book Effective FORTRAN 77, Michael Metcalf, Oxford University Press, 1985, ISBN 0198537093.

This section follows the scheme of classifying each point according to its position in the language and its relevance, either to portability or to programming style. Points marked with two asterisks should be regarded as mandatory for readable, portable code; one asterisk indicates that the point is important; unmarked points are to be considered only as desirable. In general, exceptions are allowable where either an external convention, such as a mathematical notation, is regarded as more relevant or where automatic tools are available to transform nonstandard code into standard form.

4.2 Lexical Entities

4.2.1 Portability

  ** (a) Use standard FORTRAN-77. Avoid compiler dependent features.

  *  (b) Use only the standard character set, avoiding lower case
         characters except in comment lines.  The only permitted
         special characters are:

             blank , . ' : = +  * / ( ) $

  *  (c) Do not use any nonblank characters in columns 1 through 5
         of a continuation line.

  ** (d) Do not use any other source format than the standard one
         (1 through 5: label, 6: continuation, 7 through 72;
         statement).

  *  (e) Do not write more than one statement per line.

  *  (f) Do not use blank lines. 

  *  (g) Leave column 2 of comment lines blank to avoid problems with
         some source code management systems.

  ** (h) Do not use inline comments following an exclamation mark (!).

  ** (i) Do not use more than six characters in a name.  Always use a
         letter as the first character and only letters or numerals for
         the remaining five possible characters.

  ** (j) Do not use the currency symbol ($) in a name.

  ** (k) Do not use more than 19 continuations for any one line of code.

4.2.2 Style

     (a) Do not insert comment lines between continuation lines or
         between program units.

  *  (b) Do not split a name between two lines.

     (c) Use an asterisk (*) in column 1 of comment lines, in order to
         distinguish FORTRAN 77 code from code of previous versions.

  ** (d) If a statement consists of an initial line and one or more
         continuation lines, only the last line should appear to
         terminate the statement legally.  (For example, all lines
         but the last should terminate in an operator or comma.)

  *  (e) Do not use FORTRAN key words as symbolic names.

     (f) Use blanks freely to improve the appearance of the code,
         especially to separate syntactic elements, e.g., on either
         side of equal signs, separators, and operators.

4.3 Syntactic Entities

4.3.1 Portability

  ** (a) Use only the standard data types, avoiding reduced and
         extended precision data types as well as octal, hexadecimal
         and Hollerith unless essential for the application.  The only
         standard types are real, integer (no size specification),
         logical, character, double precision,  and complex.

  ** (b) Do not use abbreviations for .true and .false.

  ** (c) Use only the apostrophe (') to delimit character strings.

  *  (d) Do not compare arithmetic expressions of different types.

  *  (e) Do not use the operators .eq.i and .ne. with
         floating-point expressions as operands.  

  ** (f) Use the relational operators .lt., .le., .gt., and .ge.
         only to compare character strings of equal length and character
         strings composed of either all letters or all digits.  In all
         other cases, use the intrinsic functions llt, lle, lgt, and lge
         to compare character strings.

  ** (g) Do not use any other logical operator than the standard
         .not., .and., .or., .eqv. and .neqv., nor any abbreviated form.
         Do not use these operators on operands of any type other
         than logical.

  *  (h) Arrays should be addressed such that their first indices vary
         the fastest and their last indices vary the slowest.  This can
         avoid dramatic losses in efficiency on certain computers under
         certain conditions.

  ** (i) Subscript expressions should be of type integer only.

  ** (j) Array references should always contain the same number of
         subscripts as in the array declarations.

  ** (k) All common block names should be different from all
         subprogram names.

4.3.2 Style

  ** (a) Do not override the FORTRAN type defaults for real and
         integer variables, constants, or functions.

  ** (b) Use mnemonic names.

  ** (c) Array subscripts should not assume values outside the lower and
         upper bounds of the declared dimensions.

  ** (d) Array references should always contain the same number of
         subscripts as in the array declaration.  Also array references
         should not assume values outside the lower and upper bounds
         of the declared dimensions.

     (e) In mixed mode expressions and assignments, the type conversions
         should be written explicitly where this helps readability.

  ** (f) Statement numbers should be in ascending order.

  ** (g) Statement numbers should be right-adjusted.

4.4 Initialization and Assignments

4.4.1 Style

     (a) Limit the use of include files to define symbolic constants.
         On systems that do not allow include files, a preprocessor
         will be required to insert the include file into the source code.

  ** (b) Make as much use as possible of symbolic constants (parameter
         statements) for true constants.  Use only the standard form of
         this statement:

              PARAMETER (PI=22./7., ONE=1.0)

         In particular, do not place function calls inside constant
         expressions in parameter statements.

     (c) Do not combine variable initialization with type declarations
         in one statement as is allowed by many compilers.

  *  (d) Where data statements are used for initialization of
         common variables, use a block data subroutine.
         The method by which block data is loaded is system
         dependent and must be understood on a given processor. Be 
         careful: When used in a library, some systems require explicit
         linking of the block data subroutine.

  *  (e) Initialize all variables.  Do not assume machine default value
         assignments.  Do not initialize variables of one type with
         values of another (except possibly a single-precision floating-
         point variable with a double-precision constant to allow easy
         type promotion).  

  ** (f) Use "implicit undefined (a - z)" statement to ensure all
         variables are declared.  The syntax of this statement may vary
         on different systems.

4.5 Control Structures

4.5.1 Portability


  ** (a) Do-loop control parameters should be of type integer only.

  ** (b) Do not use nonstandard control constructs such as do...while.

  ** (c) Do not pass control into a do-loop, if-block, or else-clause
         other than by the normal initial statement.

4.5.2 Style


  **  (a) Each do-loop should terminate on a separate continue
          statement.  The body of the loop should be indented.

  *   (b) The block-if should be used in preference to the
          arithmetic or logical-if.  The body should be indented
          (see previous item).

  *   (c) Avoid the use of the stop statement.

      (d) Use gotos only to implement control structures not provided
          by FORTRAN.  Thoroughly document any use of gotos.

4.6 Program Units

4.6.1 Portability


  **  (a) Main programs should always begin with the statement:

                      PROGRAM name

          which should have no associated parameter list.

  **  (b) Use only those intrinsic functions which appear in the
          standard (and are indicated as such in most compiler
          manuals).  Do not call host system services directly.

      (c) Note that the values returned by char and ichar are
          processor dependent.  If this is likely to lead to a
          portability problem, a solution should be adopted in which a
          portable lookup table of values is implemented.

  *   (d) Declare in an external statement all external functions.

  **  (e) Functions should not alter any of their arguments, nor any
          common variable, nor perform I/O, nor have any other
          side effect.

      (f) Place double precision and complex variables at the
          beginning of any common block in which they appear.

  *   (g) Avoid the use of the equivalence statement, especially
          for variables of different types.

  **  (h) Do not mix variables of type character with variables of
          other types in common blocks.

  **  (i) Do not pass as arguments any variables which are contained in
          a common block referenced by both the calling and the called
          routines.  

      (j) Use the save declaration where appropriate, as this might
          be required on certain processors.

4.6.2 Style

      (a) Statement functions should be contained between comment lines
          in a manner which makes clear that they are not the first
          executable statements.

      (b) The names of formal parameters of statement functions should
          not occur elsewhere in the same subprogram.

  *   (c) Do not use an entry in a function subprogram.

  *   (d) Terminate all subprograms by an end statement rather than
          a return.   

  **  (e) Throughout a complete program, all end statements should
          bear the same label (or none).

  **  (f) Do not define external functions having the same name as
          intrinsic functions.

      (g) Use the alternate return facility only for exception handling.

      (h) Declare variables and arrays in the order: those used as formal
          arguments, those appearing in common blocks, those used only in
          the subprogram itself.  Within the classifications, explicitly
          declare all variables in order of decreasing data size.

  *   (i) Avoid the dimension statement; use type declarations
          including dimension declarations, e.g., real a(100), b(10).

  **  (j) An array in a common block should have its dimensions declared
          in the common statement.  

  **  (k) A common statement should define only one common block; 
          a common block should be defined in a single common 
          statement.  

      (l) The name of a common block should not occur otherwise as a name
          in any subprogram in which it is referenced.

  **  (m) Ensure that each common block is defined identically in all
          subprograms in which it appears.

      (n) Use the save declaration where appropriate because this
          might be required on certain processors.

  *   (o) The arguments in a list should normally be ordered: input,
          output, control, external names, alternate returns.

      (p) Use the asterisk (*) notation to declare the last dimension
          of arrays passed as arguments if the extent in that dimension
          is unknown to the called routine.  

      (q) Use the asterisk (*) notation to declare the length of character
          variables passed as arguments if their length is unknown to the
          called routine.

  *   (r) Where equivalence statements are used, they should be
          grouped with the array declarations concerned.  

  **  (s) Within a program module (group of subprograms), the subprograms
          should be ordered alphanumerically.  

  *   (t) Within a program unit, the common declarations should be
          ordered alphanumerically.

      (u) Use parentheses at all times to control evaluation order in
          expressions. 

  **  (v) Do not use equivalence or common statements to assign
          two different data types to the same location in memory and
          then take advantage of how values are represented.

      (w) Data statements should appear after all other specification
          statements and before any statement function and executable
          statements.  

4.7 Input/Output

4.7.1 Portability

      (a) Do not use nonstandard I/O statements such as encode/decode
          (use internal files), define file (use open),
          namelist, punch, buffer in/buffer out and other asynchronous
          operations.

      (b) Read and write statements should have parameters which
          are either positional or keyword but not a mixture of the two.

  **  (c) Logical unit numbers should be symbolic constants or variables;
          they should never be asterisks (*) except for trivial I/O.

  **  (d) If a format specification is stored in an array, the array
          should be of type character.

      (e) Format specifiers should always be separated by a comma.

   ** (f) Do not make use of any numerical value of the iostat
          parameter; use only its sign.

4.7.2 Style

      (a) I/O statements on external files should contain the error
          recovery parameters err=, end=, iostat=, as appropriate.

      (b) Use write rather than print statements for nonterminal I/O.

   *  (c) Where appropriate, group format statements at the end of
          each subprogram.  Format statement labels should have their
          own numbering sequence.