SPAG is a multi-purpose tool for analyzing and improving Fortran programs. It combines restructuring and re-formatting with translation to Fortran 95, and both static and dynamic analysis in a single powerful package. But SPAG offers facilities which go beyond the sum of these parts. For example:
SPAG can unscramble spaghetti Fortran 66 code, and convert it to modern and structured Fortran 77 or Fortran 95.
When SPAG restructures a program, it does not change its meaning, or even the order in which statements are executed; it does change the way the program logic is written down, making it much easier to understand and maintain. Old-fashioned control constructs (such as GOTO, arithmetic IF, computed GOTO etc.) are eliminated, but that is only the beginning. SPAG also rearranges blocks of code so that logically related sections are physically close, and jumps in control flow are minimized. The algorithms used to do this draw on a deep analysis of the program structure.
Sometimes, rearrangement is not enough. Spaghetti programmers often made their programs more complex in order to re-use a few bytes of code - perhaps to avoid putting 'N=0' more than once! SPAG can undo the damage by replicating small code fragments where this improves the restructured code.
SPAG does not always remove all GOTOs. Sometimes, this could only be done by replicating large tracts of code, with a consequent reduction in readability and maintainability. SPAG concentrates on code rearrangement, with occasional replication of small code fragments. This is the approach programmers invariably take when faced with the task of restructuring by hand, and it works well in practice.
In addition to translating source form, declaration style, and control constructs to Fortran 95, SPAG can also translate COMMON blocks and INCLUDE files to Fortran 95 modules. SPAG can also create a module containing an INTERFACE block for each subprogram, and insert appropriate USE statements in calling subprograms. Fortran 95 compilers can use these constructs to perform argument checking.
Most older Fortran programs use IMPLICIT typing. That is to say that variables are not formally declared at the head of each subprogram, as they are in Pascal or C, but are simply assigned a type according to their initial letter when they are first used. SPAG provides the means to convert such programs to explicit typing, which in Fortran is usually enforced using the IMPLICIT NONE statement. It does this by adding explicit declarations for all undeclared variables at the head of each subprogram and INCLUDE file. Explicit typing allows your compiler to detect errors which might otherwise remain undetected for years.
SPAG can also rewrite your declarations from scratch using either Fortran 77 or Fortran 95 declaration style. When SPAG does this, it groups declarations in a logical order. For example, dummy argument declarations form a separate section. When using the Fortran 95 declaration style, arrays with the same dimension are grouped together.
Fortran 95 provides an ANSI standard alternative to the VAX Fortran STRUCTURE and RECORD statements. SPAG can translate between the two forms. Features, such as UNIONs, which are not available in standard Fortran 95 are left unchanged, in a form suitable for a compiler which provides them as an extension.
Old programs often contain 'dead code' which can never be executed, and variables which are declared but never used. SPAG identifies and, optionally, removes this clutter.
SPAG provides a simple and safe method for systematically changing the names of symbols within a program. SPAG guards against the danger of choosing a new name which is already in use, and re-formats the source code as required.
SPAG contains a powerful code beautifier, with dozens of options controlling spacing, labels, indentation, use of CONTINUE etc. There is also an 'AS-IS' option for preserving the format of painstakingly hand-formatted declaration statements. SPAG can help make programs self-documenting, by using case to distinguish different types of symbol. For example, local variables may be lower case, PARAMETERs upper case, dummy arguments capitalized etc. (e.g. local, PARAM, Dummyarg, COMvar). All this gives project leaders a powerful tool for defining and enforcing a corporate 'house programming style', making it easier for your programmers to work with each other's code, and with code from other sources.
SPAG also allows you to use many VAX and Fortran 95 features in your programs, and then, when necessary, to convert back to Fortran 77. This allows you to benefit from the use of DO WHILE, DO ENDDO, SELECT CASE etc. without compromising portability.
If a bug is defined as 'an incorrect value in a storage location', then there is a large subset (perhaps 30%) which can be defined as 'an undefined value in a storage location', and many of the remainder may cause that condition as a knock-on effect. The 'Dynamic Analysis' option of plusFORT is a tool for diagnosing these errors at run-time. Probes are inserted in the source code before any operation which depends on the value of a data item. If the data item is undefined, the probes write details of the error to a log-file for later analysis. Source code for the probes is supplied.
A static analyzer such as GXCHK can detect a few of these errors, but the majority can only be detected at run-time. In fact static and dynamic analysis complement each other well - each excels where the other is deficient.
The Dynamic Analysis feature of plusFORT was inspired by the /UNDEF option in the FTN77 compiler from Salford Software. A similar facility was also implemented in the WATFIV run-time system on IBM mainframe computers. Other implementations are surprisingly rare.
SPAG implements a form of dynamic analysis which is geared toward finding variables with a particular type of content at run-time. For example, variables containing dates can be identified, even if their name provides no clue as to their function. This unique capability makes SPAG an ideal tool for Year 2000 compliance and similar testing. A more conventional Year 2000 date variable scan is implemented in GXCHK.
In addition to testing for the definition status of variables and arrays, SPAG can insert probes to monitor what code is executed, and over a series of runs, to identify untested code blocks and computational hot-spots. The CVRANAL utility produces a report which summarizes these results, and, if required, inserts usage counts back into the original code as comments (e.g. in columns 73-80).
SPAG optionally generates symbol table files which provide valuable information about data usage within subprograms. These files are used by GXCHK, the global cross check program (see Chapter 3), to generate an overview of data usage within an entire program.
Symbol tables are plain ASCII text files, the format of which is described in detail in Appendix A. Users are encouraged to develop their own applications using these files as input. For example it would be a simple matter to write a program to check conformance to local variable naming conventions.
SPAG fully supports ANSI standard Fortran 77, DEC VAX Fortran and IBM VS Fortran. In addition, almost all the extensions supported by the major UNIX and PC compilers are supported.
Two minor exceptions to the above are:
In addition, SPAG supports almost all of Fortran 90 and 95. A summary of Fortran 95 features known to be unsupported may be found in the READ.ME file in the plusFORT installation release directory.
The following useful Fortran 95 features are almost universally available even in Fortran 77 compilers, and their use can be wholeheartedly recommended even to those not intending to switch to Fortran 95.
SPAG is designed to fit into any Fortran programming environment. However, in order to get the most from it, you may find it advantageous to observe the following guidelines:
To start a run, simply type spag followed by the name of the file(s) you wish to process. You can use wild-cards to specify more than one file. For example:
SPAG A*.FOR B*.f90 |
(DOS/Windows, VMS) |
spag a*.f b*.f90 |
(UNIX) |
processes the contents of all files in the current directory which fit either wildcard.
Under DOS/Windows and VMS, .for is assumed if no extension is specified (b* is treated as b*.for). The default file name is *.for. Thus, if you just type SPAG, all .for files in the current directory are processed.
Under UNIX, the extension must be specified, and there is no default file name.
The operation of SPAG may be modified by command line switches. Currently the following switches are available:
| FIG= |
specifies the configuration file name (see section 2.5). If you don't specify the configuration file name in this way, SPAG looks for a file called spag.fig. In either case, the search rules defined in section 1.4 are followed. SPAG halts with an appropriate message if no configuration file can be found. If a '?' is appended (e.g. FIG=TOF90.FIG? or FIG=?), SPAG lists the contents of the active configuration file to the screen, with a pause after each screen full. |
| LOG= |
specifies the name of a file to which a copy of all screen output is routed. If you don't specify a log-file name in this way, output is sent to a file called spag.log. |
| nnn= |
specifies the value of item nnn of the SPAG configuration data (see 2.6). Leading zeros should be omitted from the item number (enter 1=2 rather than 001=2). Items specified in this way over-ride those read from the configuration file. |
| TO= |
specifies the name of a single file for output of all modified source code. If TO= is not set, output may be routed to a single large file, to an output file for each input file, or to an output file for every sub-program, depending on items 10, 230 and 231 of the configuration data. |
| SYM= |
specifies the name of a single file for output of all symbol tables. If SYM= is not set, output may be routed to a single large file, to an output file for each input file, or to an output file for every sub-program, depending on items 10, 232 and 233 of the configuration data. |
| IFC= |
specifies the name of a single file for output of all Fortran 95 INTERFACE modules. If IFC= is not set, output may be routed to a single large file, to an output file for each input file, or to an output file for every sub-program, depending on items 11, 236 and 237 of the configuration data. |
For example
spag a*.f log=NEW.log fig=MARY.fig 1=1 60=1 sym=NEW.smb
This command causes SPAG to analyze all files in the current directory whose name fits the template a*.f. A copy of all screen output is sent to NEW.log. Configuration options are read from MARY.fig, but the controls on records 1 and 60 are both set to 1 (re-format only, and leave specification statements unchanged). All symbol tables are written to the file NEW.smb. The way modified source code is output depends on items 10, 231 and 232 of the configuration data.
The configuration file is a plain text file which provides the means by which users may customize SPAG to their own requirements and preferences. You can use an installation default configuration file, or create your own by copying one of the supplied versions and editing it using your standard editor.
The file consists of data records and comment records. Any record with a space in column 1 is a comment record; all others are data records. Data records consist of an integer item number, followed by an '=' character and a value. They are terminated by a space character (optionally followed by a comment) or by the end-of-record. For items 1 to 199, the value is a simple integer. For items 200 to 299, the value is a text string. Records may appear in any order. Items 300 and up are ignored.
A small section from a typical configuration file is shown below. The significant parts are 1=3, 2=2 and 3=3, which set configuration items 1, 2 and 3 to 3, 2 and 3 respectively. The reaminder is commentary.
#====================================#
#======== Global Run Control ========#
#====================================#
1=3 Type of Run
0=no source output
1=beautify only
2=and relabel
3=and restructure
4=dynamic analysis
5=Dynamic Memory Monitoring
2=2 Symbol Table Ouptut
-1=no symbol table
0=generate table
1=write to file
3=Verbose
3=3 Clutter Checks
0=no clutter checks
1=checks only
2-5=remove clutter
There are three sample configuration files in the plusFORT installation directory:
spag.fig |
may be used to process fixed format input code, and to produce restructured output which should be acceptable to a modern Fortran 77 compiler. |
tof90.fig |
may be used to process fixed format input code, and to produce restructured output which should be acceptable to a modern Fortran 90/95 compiler. SPAG uses Fortran 90/95 features wherever appropriate |
spag90.fig |
may be used to process free format Fortran 90/95 input code, and to produce restructured Fortran 90/95 output. |
The meaning of each data item is explained in detail in the next section.
Item 1 |
Source Code OutputSpecifies what source code output is required - possible values are:
|
||||||||||||||||||||||||||
Item 2 |
Symbol TablesSpecifies whether the symbol tables generated by SPAG are to be written to files - possible values are:
|
||||||||||||||||||||||||||
Item 3 |
Clutter ChecksSpecifies how SPAG should deal with clutter (unused variables, PARAMETERs, COMMON blocks etc.). Possible values are:
|
||||||||||||||||||||||||||
Item 4 |
Declaration StandardizationSpecifies whether and how SPAG should reorganize the declarations in a subprogram. Possible values are:
Note that SPAG does not insert or modify type declarations for variables which are defined in INCLUDEd files, unless it is converting them to modules. It does not insert declarations for INTRINSIC functions (item 210). See section 2.7.3 for more discussion of declaration standardization, and 2.7.5-6 for a description of the conversion of COMMON blocks and INCLUDE files to modules. |
||||||||||||||||||||||||||
Item 5 |
Variable RenamingSpecifies whether SPAG should change the name of symbols before writing the restructured output file. Possible values are:
|
||||||||||||||||||||||||||
Item 6 |
Test Coverage and Hot-spot AnalysisSpecifies whether SPAG should insert the statements specified in items 243-247 in such a way as to trace entries to and exits from subprograms and code blocks. The trace statements may be used to analyze test coverage (i.e. to identify parts of the program that have not been tested) and execution hot-spots. Possible values are:
See section 2.9 for further discussion of coverage analysis. |
||||||||||||||||||||||||||
Item 7 |
Complexity MetricsSpecifies whether SPAG should compute complexity metrics for each subprogram. Possible values are:
SPAG computes three metrics, each of which ranges in value from 0 to 100, with higher values indicating greater complexity. A target value is suggested for each metric, but it is accepted that there are circumstances when well written code exceeds the targets. The three metrics reported by SPAG are:
|
||||||||||||||||||||||||||
Item 8 |
Interface Summary ReportsSpecifies whether SPAG should prepare the ground for GXCHK to embed an interface summary as comments in the restructured source code. This summary enumerates calls in and out of each subprogram, and details arguments and COMMON data shared with the remainder of the program. SPAG inserts a marker in output code which GXCHK subsequently replaces with the interface summary. Interface summaries are described in detail in section 3.6. Possible values are:
|
||||||||||||||||||||||||||
Item 10 |
Output FilesSpecifies how output files (both restructured source and symbol tables) are to be created. Possible values are:
For the last two options, you may specify the directory in which the new files are created (see items 230 and 232) as well as the extensions used (see items 231 and 233). |
||||||||||||||||||||||||||
Item 11 |
Interface Module OutputSpecifies how newly created subprogram interface modules are to be written (item 4 controls whether SPAG creates new interface modules). Possible values are:
For the last two options, you may specify the directory in which the new files are created and the extension used (see items 236 and 237). |
||||||||||||||||||||||||||
Item 12 |
Safe FunctionsSpecifies whether functions whose names do not appear in the file specified using item 210 can be regarded as 'safe'. A 'safe' function is one which simply returns a value, dependent on its arguments; it does not modify its arguments or any COMMON or SAVEd variable, or perform any input or output operation. The file specified using item 210 contains a list of INTRINSIC functions, and a user specified list of safe functions. One point of the distinction is that the static analysis in SPAG and GXCHK is more informative if functions are known to be safe. Another is that, if SPAG restructuring produces code which executes a function more often than the original unstructured code, it can only be sure that the program logic is correct if the functions involved are 'safe'. This situation arises rarely in practice, and SPAG issues a warning message if there is any danger. Possible values are:
|
||||||||||||||||||||||||||
Item 18 |
Configuration Options in HeaderSpecifies whether a header section containing a summary of options specified in spag.fig is to be inserted at the head of each subprogram in the restructured output file. Possible values are:
|
||||||||||||||||||||||||||
Item 20 |
Computed GOTOSpecifies whether computed GOTOs are to be converted to IF..THEN..ELSE or SELECT CASE constructs. Possible values are:
Note that the translations deal correctly with the case where i is less than 1 or greater than 3. |
||||||||||||||||||||||||||
Item 21 |
SELECT CASESpecifies whether SPAG should convert SELECT CASE constructs to equivalent standard Fortran 77 block IF constructs. SELECT CASE is a Fortran 95 construct which is also supported by some Fortran 77 compilers. Possible values are:
|
||||||||||||||||||||||||||
Item 22 |
Arithmetic IFSpecifies whether arithmetic IFs are to be converted to IF..THEN..ELSE constructs. Possible values are:
|
||||||||||||||||||||||||||
Item 23 |
Logical IF + GOTOSpecifies whether logical IF followed by GOTO is to be converted to a block IF..THEN..ELSE construct. Possible values are:
|
||||||||||||||||||||||||||
Item 24 |
DO WHILESpecifies whether SPAG should make use of the DO WHILE construct to unscramble code containing backward pointing GOTOs. DO WHILE is a Fortran 95 construct which is also supported by almost all Fortran 77 compilers. SPAG can also convert the DO WHILE construct back to standard Fortran 77. Possible values are:
|
||||||||||||||||||||||||||
Item 25 |
EXIT and CYCLESpecifies whether SPAG should use the Fortran 95 style EXIT (GOTO statement after DO loop terminator) and CYCLE (GOTO end of loop) statements. Possible values are:
|
||||||||||||||||||||||||||
Item 26 |
Statement ReplicationSpecifies whether SPAG may replicate individual statements if this improves the readability of a section of code. Possible values are:
In this example, structure is improved by duplicating the statement n = n + 1. |
||||||||||||||||||||||||||
Item 27 |
Relocation into DO loopSpecifies whether blocks of code can be relocated into a DO loop from outside. This control does not apply to DO WHILE loops. Relocation into a DO WHILE loop is always allowed. Possible values are:
If you activate this option, and if the relocated code re-defines the DO loop variable (e.g. i = 0 instead of CALL sub1), then the resulting code violates the ANSI standard (code within a DO loop is not allowed to redefine the DO loop variable). This should not cause any errors at run time, as the DO loop redefinition is followed immediately by a GOTO which exits the DO loop. However, many compilers will, quite properly, report an error. To avoid this eventuality, set item 27 to 0, or hand check the output code. |
||||||||||||||||||||||||||
Item 28 |
Relocate RETURN or STOP followed by ENDSpecifies whether a block of code terminated by RETURN or STOP and followed by END may be relocated. Activating this option prevents SPAG from moving a RETURN or STOP which is the last executable statement in a subprogram. Possible values are:
|
||||||||||||||||||||||||||
Item 29 |
Remove Unreachable CodeSpecifies whether blocks of code which could never be executed are to be removed. Possible values are:
Unreachable Code Example
GOTO 200
! The following statement could never be executed
WRITE(22,100) a,b,c
100 FORMAT(3F5.3)
200 PRINT *,a,b,c
|
||||||||||||||||||||||||||
Item 30 |
Convert VAX StructuresSpecifies whether SPAG should translate VAX STRUCTURE and RECORD statements, and the corresponding structure references, to Fortran 95 derived types. Possible values are:
Fortran 95 has no equivalent to the VAX MAP and UNION constructs, which are used make different elements of a structure share the same memory. When SPAG encounters a MAP or UNION construct, it leaves it intact, in a form acceptable to compilers which provide MAP and UNION as an extension to standard derived types. An example of this follows:
|
||||||||||||||||||||||||||
Item 35 |
Dynamic Analysis Element SizeSpecifies the minimum element size (in bytes) for dynamic analysis. SPAG will not insert probes to check the definition status of numeric data items which are smaller than the specified minimum size. If this item is set to a small value (e.g. 1) there is a possibility of 'false positives' (i.e. the probe logs an error even though there is none). If it is set to a large value (e.g. 4), the probes may miss errors which could be found with a smaller value. The best approach is probably to set item 35 to 1, but to increase it to 2 or 4 if false positives are a problem. Note that this control applies to numeric and logical data, and NOT to character data. See section 2.8 for further discussion of dynamic analysis. |
||||||||||||||||||||||||||
Item 36 |
Static Local VariablesSpecifies whether local variables should be assumed to be static. The ANSI standard specifies that local data which is not specified in a SAVE or DATA statement becomes undefined when control is returned to the calling subprogram. However many compilers allocate local data statically, and many non-standard programs depend on static allocation of local data. Dynamic analysis of such programs is only possible if this item is set to 1. Possible values are:
See section 2.8 for further discussion of dynamic analysis. |
||||||||||||||||||||||||||
Item 40 |
Relocate FORMAT statementsSpecifies whether FORMAT statements are to be grouped together just before the END statement of each subprogram. Possible values are:
|
||||||||||||||||||||||||||
Item 41 |
Use of CONTINUESpecifies whether CONTINUE statements should be inserted whenever a label is required (except on FORMAT statements). Possible values are:
In general a value of 0 leads to code which is easier to understand, while a value of 1 gives code which is easier to modify.
This control is effective only for re-structuring runs (Item 1). |
||||||||||||||||||||||||||
Item 42 |
Single statement block IFsSpecifies whether block IFs are to be converted to logical IFs if the block contains only one statement. Possible values are:
|
||||||||||||||||||||||||||
Item 43 |
Logic Reversal in block IFSpecifies whether constructs of the form
IF ( a.EQ.b ) THEN
ELSE
X = Y
..
ENDIF
should be converted to
IF ( a.NE.b ) THEN
X = Y
..
ENDIF
Possible values are:
|
||||||||||||||||||||||||||
Item 44 |
Insert Redundant ELSESpecifies whether SPAG should add a null ELSE block to block IFs that have an ELSEIF but no ELSE. Possible values are:
|
||||||||||||||||||||||||||
Item 45 |
DO loopsSpecifies which style of DO loop is to be used. Possible values are:
DO..ENDDO is a Fortran 95 feature which is also supported by most current Fortran 77 compilers. |
||||||||||||||||||||||||||
Item 46 |
Character ConstantsSpecifies whether character constants are to be converted to a different format. In addition to the standard apostrophe delimited form (e.g. 'word'), SPAG recognizes Hollerith constants (of the form 4Hword), and quoted strings (of the form "word"). Hollerith constants need not be supported by an ANSI Fortran 77 (or 95) compiler, though in practice, most do. Quoted strings are standard Fortran 95, and are widely supported by newer Fortran 77 compilers. Possible values are:
Note that SPAG deals correctly with apostrophes within Holleriths and quoted strings. Thus "can't" and 5Hcan't are converted to 'can''t'. |
||||||||||||||||||||||||||
Item 47 |
Fortran 95 Relational OperatorsSpecifies whether the new Fortran 95 style relational operators are to be used. Possible values are:
Note that both styles of operator are permitted by the Fortran 95 standard. |
||||||||||||||||||||||||||
Item 48 |
Fortran 95 END SUBROUTINE statementsSpecifies whether SPAG should translate END statements to Fortran 95 END SUBROUTINE, END PROGRAM, END FUNCTION etc. Possible values are:
|
||||||||||||||||||||||||||
Item 49 |
Remove Redundant RETURN and STOPSpecifies whether SPAG should remove redundant RETURN statements which occur before the END statement in subprograms, and redundant STOP statements which occur before the END statement in a main program. Possible values are:
|
||||||||||||||||||||||||||
Item 51 |
Input Statement LengthSpecifies the input statement length. Any text after the specified position on input statement lines is discarded. A value of 72 is required if the input code contains sequence numbers in columns 73-80. Note that comments are not truncated. The maximum permitted value is 512. If you want to retain the sequence numbers in your restructured code, there are two approaches you might take. The first is to use item 60 and the *-ASIS directive to force SPAG to leave statements alone. However, this is not a safe procedure when applied to executable statements (see section 2.7.9). The second alternative is to convert sequence numbers to end-of-line comments by inserting a '!' in column 72 using a text editor. End-of-line comments using '!' are permitted in standard Fortran 95 but not in standard Fortran 77 though most current Fortran 77 compilers accept them. |
||||||||||||||||||||||||||
Item 52 |
Continued Character ConstantsSpecifies whether input records should be padded with spaces to the input statement length (item 51). This item only has an effect when a character or Hollerith literal is continued over more than one line in a fixed format source file. Possible values are:
For example, given
DATA zalph/'ABCDEFGHIJKLM
&NOPQRSTUVWXYZ'/
If item 52 is 1, and the input statement length is 72, SPAG assumes that there are 41 spaces between the M and N characters. If item 52 is 0, the number of spaces may be between 0 and 41 depending on the position of the end-of-line marker (carriage return) on the first record. |
||||||||||||||||||||||||||
Item 53 |
Old-style Direct AccessSpecifies whether unpaired apostrophes as used in old-style direct access (using DEFINE FILE, FIND etc.) are to be allowed. Possible values are:
|
||||||||||||||||||||||||||
Item 54 |
PDP style PARAMETERSpecifies whether PDP style PARAMETER statements, with no enclosing brackets, are to be allowed. Note that many compilers will interpret PDP style PARAMETER statements as assignment statements.
PARAMETER vdim=10
may be interpreted as
PARAMETERVDIM = 10
Possible values are:
PDP style PARAMETERs also differ from standard PARAMETERs in that the type of the constant determines the type of the PARAMETER. Thus in the above example, VDIM is of type INTEGER, because 10 is an integer. It would be an error to declare VDIM to be of a different type. If item 54 is set to 1, SPAG recognizes PDP style PARAMETER statements, but it treats them as entirely equivalent to standard Fortran PARAMETERs. This can lead to problems if SPAG is asked to insert declarations for IMPLICITly declared variables. For example, in the above case, SPAG might deduce, wrongly, that VDIM was REAL. The resulting output code will not compile. Currently, the only cure for this is to correct the inserted declarations, and convert the PDP style PARAMETERs to standard Fortran by hand. |
||||||||||||||||||||||||||
Item 55 |
FUNCTION with no ArgumentsSpecifies whether FUNCTIONs may be declared with no argument list. Note that many compilers will misinterpret such FUNCTION statements.
INTEGER FUNCTION random
may be interpreted as a declaration of an INTEGER variable
INTEGER functionrandom
Possible values are:
|
||||||||||||||||||||||||||
Item 56 |
INCLUDE file Search Rule (1)Specifies the default search rule for INCLUDE files. This is relevant when SPAG is processing files which are not in the current directory and which INCLUDE files with no specified path. Possible values are:
For most compilers, a value of 0 should be specified. However, others, including Microsoft Fortran, require a value of 1. If the INCLUDE file is not found using the above rule, the list of directories specified using item 215 is searched. |
||||||||||||||||||||||||||
Item 59 |
SQL StatementsSpecifies whether embedded EXEC SQL statements, as used with IBM's DB2 database are permitted. Possible values are:
|
||||||||||||||||||||||||||
Item 60 |
Reformat Declaration StatementsSpecifies whether SPAG should preserve the format of all statements in the declaration section of each subprogram (i.e. before the first executable statement). Possible values are:
|
||||||||||||||||||||||||||
Item 61 |
Tab CharactersSpecifies whether SPAG should use tab characters in the output file. If this option is activated, SPAG replaces repeated space characters by tabs where possible. Possible values are:
The use of tabs is an extension to ANSI standard Fortran which is supported by most, but not all, Fortran 77 compilers. Note that SPAG never replaces tab characters which are within character constants. |
||||||||||||||||||||||||||
Item 62 |
GOTO or GO TOSpecifies whether GOTO should be spelled with a space in the restructured output code. Possible values are:
|
||||||||||||||||||||||||||
Item 63 |
ENDIF or END IFSpecifies whether ELSEIF, ENDIF and ENDDO should be spelled with a space in the restructured output code. Possible values are:
The second usage (with spaces) often causes confusion to programmers more familiar with Pascal or C than Fortran. Both these languages lack an ELSEIF statement, and, unlike Fortran, both treat spaces as significant syntactic elements. As a result, ELSE IF is often read as an ELSE statement followed by an IF statement. This leads to confusion both over the number of ENDIF statements required to terminate a block IF, and over the way the code should be indented. The Fortran ELSEIF statement is in fact more like the elsif statements in ADA and Modula 2. |
||||||||||||||||||||||||||
Item 64 |
BLOCKDATA or BLOCK DATASpecifies whether BLOCKDATA should be spelled with a space in the restructured output code. Possible values are:
|
||||||||||||||||||||||||||
Item 65 |
DOUBLEPRECISION or DOUBLE PRECISIONSpecifies whether DOUBLEPRECISION should be spelled with a space in the restructured output code. Possible values are:
|
||||||||||||||||||||||||||
Item 66 |
Space after Fortran KeywordsSpecifies whether a space is required after Fortran keywords. Possible values are:
|
||||||||||||||||||||||||||
Item 67 |
Spaces around + and -Specifies whether a space is to be placed on either side of + or - operators. Possible values are:
For example
! Item 67 = 0
Y = X+(A*B-C)
! Item 67 = 1
Y = X + (A*B-C)
! Item 67 = 2
Y = X + (A*B - C)
SPAG does not place spaces around arithmetic operators (such as *, / and **) which bind more strongly than + and -. This ensures that spacing reinforces the Fortran standard precedence of arithmetic operators. For example, if SPAG were to produce
! Misleading use of spacing
Y = X+(A * B-C)
it would appear that (B-C) was multiplied by A and the result added to X. |
||||||||||||||||||||||||||
Item 68 |
Spaces around =Specifies whether a space is to be placed on either side of = (mainly in assignment and DO statements). Possible values are:
For example:
! Item 68 = 0
Z=X*Y
! Item 68 = 1
Z = X*Y
|
||||||||||||||||||||||||||
Item 69 |
Spaces around Logical OperatorsSpecifies whether a space is required on either side of logical operators (.AND., .OR., .EQV., .NEQV., .XOR. etc.). Possible values are:
For example
! Item 69 = 0
QSW = b.GT.a.AND.b.LT.c
! Item 69 = 1
QSW = b.GT.a .AND. b.LT.c
! Item 69 = -1
QSW = b .GT. a .AND. b .LT. c
In Fortran, relational operators (such as .LT., .EQ. etc.) bind more strongly than logical operators (.AND., .OR. etc.), and a value of n>0 makes this precedence clearer. |
||||||||||||||||||||||||||
Item 70 |
Spaces around CommasSpecifies whether a space is required on either side of commas. Possible values are:
|
||||||||||||||||||||||||||
Item 71 |
Spaces in IF statementSpecifies whether a space should be inserted on either side of the test expression in IF statements. Possible values are:
For Example
! Item 71 = 0
IF (Q1) THEN
! Item 71 = 1
IF ( Q1 ) THEN
|
||||||||||||||||||||||||||
Item 73 |
Spaces around Concatenation OperatorSpecifies whether a space is required on either side of the concatenation operator ('//'). Possible values are:
For example
! item 73 = 0
zname = '*.'//zextn
! item 73 = 1
zname = '*.' // zextn
|
||||||||||||||||||||||||||
Item 79 |
Separate Declaration for every variableSpecifies whether SPAG is to create a separate type declaration statement for every variable. This option is active only if item 4 is set to 3 or 4 (to invoke the declaration rewriting option). Possible values are:
|
||||||||||||||||||||||||||
Item 80 |
Preserve Statement LabelsSpecifies whether statement labels are to be preserved. Possible values are:
For example a value of -8000 would allow SPAG to discard all labels with a value of less than 8000, and where necessary, invent new ones according to the rules specified below. Labels with a value of 8000 or more are preserved in the unscrambled code, even if they are not referenced. The most commonly used values are 0 (to discard all pre-existing labels) and 1 (to preserve all non-redundant labels). Note that, in some circumstances, for example when several DO loops terminate at the same statement, SPAG may have to invent new labels, whatever setting is used. |
||||||||||||||||||||||||||
Item 81 |
New Label BaseInitial base counter for new labels (except those on FORMAT statements). When SPAG needs to generate a new label, it increments the base counter to the next higher multiple of the increment appropriate to the current indentation level (i.e. the number of open DO, IF or SELECT CASE blocks). For example, if the current base counter is 945, and a label is required on a statement which is indented 3 times, and if the increment for this degree of indentation is 20, then the label will be 960 (the next higher multiple of 20). |
||||||||||||||||||||||||||
Item 82 |
Label Increment 0Label increment for un-indented code - i.e. labelled statements which are not inside any DO or block IF constructs. |
||||||||||||||||||||||||||
Item 83 |
Label Increment 1Label increment for code at indentation level 1 - i.e. labelled statements inside only one DO or block IF construct. |
||||||||||||||||||||||||||
Item 84 |
Label Increment 2Label increment for code at indentation level 2. |
||||||||||||||||||||||||||
Item 85 |
Label Increment 3Label increment for code at indentation level 3. |
||||||||||||||||||||||||||
Item 86 |
Label Increment 4Label increment for code at indentation level 4. |
||||||||||||||||||||||||||
Item 87 |
Label Increment 5Label increment for code at indentation level 5 or above. |
||||||||||||||||||||||||||
Item 88 |
Format Label BaseInitial base counter for re-labelling FORMAT statements. When SPAG needs to generate a new label for a FORMAT statement, it increments the FORMAT statement base counter to the next higher multiple of the FORMAT statement increment. For example, if the current FORMAT statement base counter is 99010, and the FORMAT statement increment is 2, then the next FORMAT statement will have the label 99012. |
||||||||||||||||||||||||||
Item 89 |
Format Label IncrementFORMAT statement label increment to be used in conjunction with the FORMAT statement base counter as described above. If the FORMAT statement increment is set to 0, FORMAT statement labels are not treated specially, but are calculated using the base counter and increments defined in items 81 to 87. |
||||||||||||||||||||||||||
Item 90 |
Label JustificationSpecifies how statement labels are to be formatted. Possible values are:
In fixed format code, a value of 2 (left justified at column 2) has the advantage of separating labels visually both from comments (C or * in column 1) and continuation markers (column 6). SPAG will over-ride the specified rule if the label will not otherwise fit. For example if the label is 99001, it will start in column 1 regardless of how this control is set. |
||||||||||||||||||||||||||
Item 100 |
Case of Local VariablesSpecifies what case conversion is done for local variable names. Possible values are:
If SPAG has to insert new occurrences of the symbol (for example, when inserting declarations for implicitly typed variables), it will use upper case if the corresponding control is set to -1. Note that the use of lower case in variable names is not strictly standard Fortran 77, though all recent compilers accept it. |
||||||||||||||||||||||||||
Item 101 |
Case of COMMON variablesSpecifies what case conversion is done for COMMON variable names. Possible values are as detailed for item 100. |
||||||||||||||||||||||||||
Item 102 |
Case of Dummy ArgumentsSpecifies what case conversion is done for dummy argument names. Possible values are as detailed for item 100. |
||||||||||||||||||||||||||
Item 103 |
Case of PARAMETERsSpecifies what case conversion is done for PARAMETER names. Possible values are as detailed for item 100. |
||||||||||||||||||||||||||
Item 104 |
Case of other SymbolsSpecifies what case conversion is done for other user-defined symbols (COMMON block names, NAMELIST names, subprogram names etc.). If item 2 is set to -1 (no symbol tables generated), then this control applies to all user-defined symbols. Possible values are as detailed for item 100. |
||||||||||||||||||||||||||
Item 106 |
CASE of logical and relational operatorsSpecifies what case conversion is done for logical and relational operators (.AND., .NE. etc.). Possible values are:
|
||||||||||||||||||||||||||
Item 107 |
Case of Fortran keywordsSpecifies what case conversion is done for Fortran keywords (READ, THEN, INTEGER etc.). Possible values are:
An unusual feature of Fortran is that it does not have reserved names. Thus 'INTEGER' is a perfectly valid variable name, even though it is also a Fortran keyword. SPAG recognizes this distinction, and uses item 107 only if the context confirms that a word is used as a keyword. |
||||||||||||||||||||||||||
Item 108 |
Case of Character StringsSpecifies what case conversion is done for character strings. Possible values are:
|
||||||||||||||||||||||||||
Item 109 |
Case of CommentsSpecifies what case conversion is done for comments (from column 2 onwards). Possible values are:
|
||||||||||||||||||||||||||
Item 121 |
Right Margin for OutputThe right margin for source code - normally set to 72 for fixed format code. SPAG ensures that source code is not written past the right margin; if necessary, SPAG inserts continuation lines to hold the extra code. For conformance to the ANSI 77 standard, set the right margin to 72 or less. Most Fortran 77 compilers ignore any text after column 72, though some can be configured to accept it. The maximum permitted value for the right margin is 132. Note that comments are NOT truncated at the right margin. |
||||||||||||||||||||||||||
Item 122 |
Left Margin for OutputThe left margin for un-indented statements (excluding labels). Fortran 77 reserves the first six columns of each record for labels and continuation markers, so the value specified here must be at least 7, unless the new Fortran 95 source form is used (see item 141). |
||||||||||||||||||||||||||
Item 123 |
Unit of IndentationThe number of characters by which statements within active DO loop, block IF or SELECT CASE constructs are to be indented. For example if a value of 3 is specified, and un-indented statements start at column 7 (item 122) then statements which are inside 4 open block constructs will be started at column 19 (7 + 4x3). |
||||||||||||||||||||||||||
Item 124 |
Maximum IndentationThe maximum permitted left margin (after indentation). This item places a limit on the amount of indentation. Without it, programs with a lot of open blocks could be placed beyond the right margin. |
||||||||||||||||||||||||||
Item 125 |
Continuation CharacterThe character code of the continuation character. SPAG inserts CHAR(n) at column 6 of all continuation lines of fixed format source code. Use of the '&' character is recommended for compatibility with Fortran 95. If you specify that output is to be written using the free format Fortran 95 source form (see item 141), '&' is used as the continuation character, and this control has no effect. The character code for '&' is 38 on ASCII based machines (the vast majority), and 80 on EBCDIC machines (IBM mainframes). |
||||||||||||||||||||||||||
Item 126 |
Comment CharacterThe character code of the comment character. SPAG inserts CHAR(n) at column 1 of all comment lines (excluding lines with end of line comments). Suitable ASCII values for n are 33 (!), 42 (*), 67 (C) and 99(c). If the item is set to 0, the pre-existing comment character is retained. If you specify that output is to be written using the free format Fortran 95 source form (see item 141), '!' is used as the continuation character, and this control has no effect. |
||||||||||||||||||||||||||
Item 127 |
Comment JustificationSpecifies whether SPAG should reformat the text of comments. Possible values are:
|
||||||||||||||||||||||||||
Item 130 |
COMMON Block Alignment TestsSpecifies whether SPAG should check the alignment of variables in COMMON blocks. Possible values are:
|
||||||||||||||||||||||||||
Item 131 |
Floating Point Equality TestSpecifies whether SPAG should report the existence of unsafe tests for equality of floating point data. Possible values are:
|
||||||||||||||||||||||||||
Item 132 |
Variable Name ChecksSpecifies whether SPAG should issue a warning if a variable or array name is the same as a Fortran keyword or INTRINSIC function. Possible values are:
|
||||||||||||||||||||||||||
Item 133 |
Subprogram Argument ChecksSpecifies whether SPAG should check for consistency of subprogram arguments. If this option is selected, SPAG warns if the number or type of arguments varies between invocations of a subprogram. This is appropriate for Fortran 77 source code, but in Fortran 95 the number of arguments may vary if the callee has optional arguments, and the type may vary if the callee is overloaded. For this reason, it is recommended that this check be switched off when processing Fortran 95 input code. Possible values are:
|
||||||||||||||||||||||||||
Item 138 |
Conversion of #include to INCLUDESpecifies whether SPAG should convert C preoprocessor includes (using #include) to standard Fortran 95 format (using an INCLUDE statement). Possible values are:
|
||||||||||||||||||||||||||
Item 140 |
Input Source FormSpecifies the format of the input source code. Possible values are:
|
||||||||||||||||||||||||||
Item 141 |
Output Source FormSpecifies the required format of the output source code. Possible values are:
If this control is set greater than 0, item 125 (the continuation character) is set to '&' and item 126 (the comment character) is set to '!'. In addition the first characters of items 220-223 (various comments inserted by SPAG) are changed to '!'. |
||||||||||||||||||||||||||
Item 210 |
File containing Intrinsic Function NamesThe name of a file containing a list of INTRINSIC and 'safe' functions. The file is plain text and consists of a list of function names separated by spaces and/or new lines. Three sample files containing lists of intrinsic functions in standard Fortran 95 (f95func.txt), Fortran 77 (f77func.txt) and VAX Fortran (vaxfunc.txt) are supplied with SPAG. If the file contains a '/' character on a line by itself, then names before it are interpreted as intrinsic functions, and names after it are interpreted as non-intrinsic safe functions (see item 12). |
||||||||||||||||||||||||||
Item 211 |
File containing RenamesThe name of a file containing a list of renames for the current run. This file is read only if item 5 is set to 1 or more. See section 2.7.8 for further discussion. |
||||||||||||||||||||||||||
Item 213 |
Module for Translation INTEGER*2 etc.Specifies the name of a Fortran 95 source file containing a module (normally called F77KINDS) which is used to allow translation of non-standard Fortran types, such as INTEGER*2 and REAL*4 to standard Fortran 95 types. For example, INTEGER*2 is normally translated as INTEGER(I2KIND) where I2KIND is a PARAMETER, declared in F77KINDS with the appropriate value. Because different compilers use different KIND values, it is necessary to create a version of F77KINDS for the compiler in use. The program mkkind.f90, supplied with plusFORT does this automatically. Simply compile and run mkkind.f90 with your target compiler to create a version of f77kinds.f90 for use with SPAG. You will also need to use the module when compiling the restructured code. Item 212 is now redundant, and the kind.txt file included with version 5.00 of SPAG is no longer used. It's function is assumed by item 213. |
||||||||||||||||||||||||||
Item 215 |
INCLUDE file Search Path (2)A list of directories, separated by semicolons, which are to be searched if an INCLUDE file which is specified without a path is not found in the current directory (or the source directory - see item 56). For example, if, on a DOS/Windows system the list is C:\INCLUDE;C:\SYSIN, and if an included file name does not specify a path, SPAG looks first in the current directory (but see item 56), then in C:\INCLUDE and finally in C:\SYSIN. If it is not found in any of these directories, SPAG reports an error. For UNIX and VMS systems, the file naming conventions are different, but otherwise the mechanism is the same. |
||||||||||||||||||||||||||
Item 220 |
Header Record IdentifierFour characters used as header record identifiers in the output file. SPAG writes a header record before each subprogram in the output file. The header record consists of a 4 character identifier, followed by a file name. QSPLIT uses these file names to split output files created by SPAG into a single file for each subprogram. The default header record identifier is !*==. Standard Fortran 77 does not recognise lines beginning with ! as comments, though, in practice, most recent compilers do. If your compiler does not recognise ! as a comment character, it will be necessary to change the header record identifier (e.g. to **==). If the header record identifier is blank, no header records are written. For example: !*==TEST1.NEW It is very important to ensure that the header record identifier is not used in any other context, as SPAG removes pre-existing header records when it writes the output file. For example, it would be very unwise to use the character 'C' as the header record identifier, as SPAG would then delete any line which begins with a 'C' followed by three spaces. |
||||||||||||||||||||||||||
Item 221 |
Interface Description Header MarkerWhen GXCHK inserts an Interface Description block into the restructured source code (see Section 3.6), it inserts header and trailer marker comments. This is done so that it can remove any pre-existing interface description block before inserting a new one. This item specifies the four characters at the beginning of the header marker. The default is !*--. If your compiler does not recognise ! as a comment character, it will be necessary to change this item (e.g. to **--). As with item 220, it is very important to ensure that the marker is not used in any other context, or GXCHK might then remove comments which are not part of an old interface description block. |
||||||||||||||||||||||||||
Item 222 |
Interface Description Trailer MarkerSpecifies the four characters at the beginning of the Interface Description Trailer Marker (see item 221). The default is !*++. If your compiler does not recognise ! as a comment character, it will be necessary to change this item (e.g. to **++). |
||||||||||||||||||||||||||
Item 223 |
Marker for First Executable StatementIf this item is set, it is treated as a comment to be inserted before the first executable statement in every subprogram. For example: !***_Start_of_Executable_Program Before output, SPAG translates any underscore characters in the value to spaces. |
||||||||||||||||||||||||||
Item 230 |
Output File Directory (or prefix)Specifies a prefix for the names of restructured output files. This could be a directory name (the directory must exist), or simply a prefix to the filename. Under UNIX and DOS/Windows, a closing '/' or '\' is required if a directory is specified. If no prefix is specified, restructured source files are written in the same directory as the input source code. |
||||||||||||||||||||||||||
Item 231 |
Output File ExtensionThe filename extension to be used for restructured output files (e.g. .spg). The extension is also used as the filename extension on header records in the output file (see item 220). SPAG constructs the file name on the header records by appending the extension specified here to the subprogram name. |
||||||||||||||||||||||||||
Item 232 |
Symbol File Directory (or prefix)Specifies a prefix for the names of symbol table files. This could be a directory name (the directory must exist), or simply a prefix to the filename. Under UNIX and DOS/Windows, a closing '/' or '\' is required if a directory is specified. If no prefix is specified, symbol table files are written in the same directory as the input source code. |
||||||||||||||||||||||||||
Item 233 |
Symbol File ExtensionThe filename extension to be used for symbol table files (e.g. .smb ). |
||||||||||||||||||||||||||
Item 234 |
Coverage Data File Directory (or prefix)Specifies a prefix for the names of coverage data files. This could be a directory name (the directory must exist), or simply a prefix to the filename. Under UNIX and DOS/Windows, a closing '/' or '\' is required if a directory is specified. It is strongly recommended that an absolute path rather than a relative path be specified (e.g. C:\myprog\cover\ rather than ..\cover\), as this will allow the instrumented program to find the coverage data files in all cases. This item must be specified if item 6 is set to 2. |
||||||||||||||||||||||||||
Item 235 |
Coverage Data File ExtensionThe filename extension to be used for coverage data files. This is normally set to .cvr. |
||||||||||||||||||||||||||
Item 236 |
Module File Directory (or prefix)Specifies a prefix for the names of module files created by SPAG (includes INTERFACE modules, and modules to replace COMMON blocks and INCLUDE files). This could be a directory name (the directory must exist), or simply a prefix to the filename. Under UNIX and DOS/Windows, a closing '/' or '\' is required if a directory is specified. |
||||||||||||||||||||||||||
Item 237 |
Module File ExtensionThe filename extension (e.g. .ifc or .f90) to be used for the output files containing the source code for modules created by SPAG (includes INTERFACE modules, and modules to replace COMMON blocks and INCLUDE files). |
||||||||||||||||||||||||||
Item 240 |
Dynamic Analysis Probe Routine Root 1A 3 character root used at the start of the names of the dynamic analysis probe routines which check whether variables are defined or not. The three characters should be chosen so as to avoid clashes with other routines. If you change this item from the default value (QD$), you will also have to change the source for the probe routines (in the file probes.for or probes.f). See section 2.8 for further discussion of dynamic analysis. |
||||||||||||||||||||||||||
Item 241 |
Dynamic Analysis Probe Routine Root 2A 3 character root used at the start of the names of additional dynamic analysis probe routines. The three characters should be chosen so as to avoid clashes with other routines. Currently, this item is not used. |
||||||||||||||||||||||||||
Item 242 |
Dynamic Analysis Undefine Routine RootA 3 character root used at the start of the names of the dynamic analysis probe routines which set variables to the undefined value. The three characters should be chosen so as to avoid clashes with other routines. If you change this item from the default value (UD$), you will also have to change the source for the probe routines (in the file probes.for or probes.f). See section 2.8 for further discussion of dynamic analysis. |
||||||||||||||||||||||||||
Item 243 |
Program Entry Trace RoutineIf item 6 is set greater than 0, a statement is inserted in the output code so that it is executed immediately after the program starts. Item 243 specifies the main part of the text of the statement. Note that the text may not include spaces, because the first space marks the start of the comment field. However, you may include the underscore character '_'; SPAG translates underscores to spaces before writing the statement. If you change this item from the default value (CALL_PR$ENT), you will also have to change the source for the probe routines (in the file probes.for or probes.f). See section 2.9 for further discussion of coverage analysis. |
||||||||||||||||||||||||||
Item 244 |
Program Exit Trace RoutineIf item 6 is set greater than 0, a statement is inserted in the output code so that it is executed immediately before the program stops. Item 244 specifies the main part of the text of the statement. Use the underscore character '_', to mark the position of spaces. If you change this item from the default value (CALL_PR$EXI), you will also have to change the source for the probe routines (in the file probes.for or probes.f). See section 2.9 for further discussion of coverage analysis. |
||||||||||||||||||||||||||
Item 245 |
Subprogram Entry Trace RoutineIf item 6 is set greater than 0, a statement is inserted in the output code so that it is executed whenever a subprogram is invoked. Item 245 specifies the main part of the text of the statement. Use the underscore character '_', to mark the position of spaces. If you change this item from the default value (CALL_SB$ENT), you will also have to change the source for the probe routines (in the file probes.for or probes.f). See section 2.9 for further discussion of coverage analysis. |
||||||||||||||||||||||||||
Item 246 |
Subprogram Exit Trace RoutineIf item 6 is set greater than 0, a statement is inserted in the output code so that it is executed whenever control is returned from a subprogram. Item 246 specifies the main part of the text of the statement. Use the underscore character '_', to mark the position of spaces. If you change this item from the default value (CALL_SB$EXI), you will also have to change the source for the probe routines (in the file probes.for or probes.f). See section 2.9 for further discussion of coverage analysis. |
||||||||||||||||||||||||||
Item 247 |
Code Block Entry Trace RoutineIf item 6 is set greater than 1, statements are inserted in the output code at the start of every code block. These statements may be used to provide test coverage and execution hot-spot analysis. Item 247 specifies the main part of the text of the statement. Use the underscore character '_', to mark the position of spaces. If you change this item from the default value (CALL_BL$ENT), you will also have to change the source for the probe routines (in the file probes.for or probes.f). See section 2.9 for further discussion of coverage analysis. |
||||||||||||||||||||||||||
Most older Fortran programs are written in an 'implicitly typed' environment. That is to say that variables are not formally declared at the head of each procedure as they are in Pascal or C; instead, variables are implicitly declared simply by using them. The compiler determines the type of the variable from the first letter of its name. For example, variables whose name begins with the letter 'I' are normally of type INTEGER.
No doubt this appeared to the pioneers who created Fortran as an advantage, and at first sight it may appear that the compiler is simply doing automatically what the programmer would otherwise have to do by hand. We now know better; the problem is that it is all too easy for the compiler to create variables in a way not intended by the programmer. A simple example illustrates the point:
I0 = 0
DO 10 i = 1.100
READ *,j
IO = I0 + j
10 CONTINUE
In this example, the variable I0 is mis-typed as IO on line 4, and as a result a spurious new variable IO is created. Moreover, the second statement is, despite appearances, an assignment to the spurious REAL variable DO10I (spaces are not significant in Fortran). A language which requires explicit declarations would have spotted that IO and DO10I had not been declared, and reported an error at compile-time. But mis-spelling is not the only problem. Even commoner is confusion between local and COMMON variables. For example, if you INCLUDE a file which declares a COMMON variable named K, in a routine which has a local variable called K, all manner of obscure symptoms are possible.
Fortran can be made to require explicit typing. The IMPLICIT NONE statement, which disables implicit typing, is standard Fortran 95, but even Fortran 77 compilers generally accept it. Its use can be thoroughly recommended. As an alternative, some compilers have a compiler switch to disable implicit typing without resort to IMPLICIT NONE.
SPAG provides the means for converting existing, implicitly typed programs to explicitly typed programs for use with IMPLICIT NONE. It does this by adding explicit declarations for all undeclared variables at the head of each subprogram and INCLUDE file. Doing this by hand on a large program could take weeks - enough to make the switch impractical. However, the fact that SPAG can do it quickly doesn't mean it should be done carelessly; for example, there would be little point in doing it as a regular routine, as the benefits of explicit typing are then lost. Ideally, the declarations inserted by SPAG should be checked for spurious entries caused by past mistakes. However, explicit typing will help prevent future errors even if some past errors remain.
The 'auto-declarer' feature of SPAG is activated by setting item 4 of spag.fig greater than 0. If it is set to 1, declarations are inserted for all undeclared variables, parameters, dummy arguments and functions other than intrinsic functions (whose names are read from a file - see item 210 of spag.fig). Intrinsic functions are excluded because their type may vary (e.g. MIN may be REAL in one place and INTEGER in another). If item 4 of spag.fig is set to 2, SPAG also inserts an IMPLICIT NONE statement, and removes any pre-existing IMPLICITs (provided that they are not in an INCLUDEd file).
Declarations must be added to INCLUDEd files in a separate run. SPAG can process isolated INCLUDE files, though some warnings will be generated (no END statement, variables not used etc.).
When SPAG adds declarations to a subprogram, it has all the information required to determine the type and nature of every symbol in it. Some of this information may be contained in INCLUDEd files. However, when SPAG adds declarations to an incomplete source code, such as an INCLUDE file, it may find that some information is missing.
For example, if an INCLUDE file contains the single statement
COMMON /ABC/ XX(N),I,J,K
we cannot determine the type of any of the variables. We know that XX is an array, but I, J and K may be too. We can infer that N is an INTEGER PARAMETER, but we don't know its value, or whether it is a 1, 2 or 4 byte INTEGER. It is even possible that the same INCLUDE file means different things in different places.
In cases like this, it is best to insert extra statements to fill in the missing information. For example, if you insert the two lines:
IMPLICIT LOGICAL(A-J,O-Z),INTEGER*2 (K-N)
INCLUDE 'dims.inc'
where dims.inc contains PARAMETER definitions (including one for N), then SPAG will be able to do a much better job. You should remove the redundant IMPLICIT statement when SPAG has finished (we recommend that IMPLICIT statements should never be placed in INCLUDE files).
The objective is to ensure that before processing, each INCLUDE file is self-contained, and not reliant on context to define its meaning. In fact this is a good principle in general: if all INCLUDE files are constructed this way, many subtle bugs are eliminated (e.g. the size of XX varies because there are multiple non-identical definitions of N).
SPAG can also rewrite the declaration section of a subprogram from scratch, using either Fortran 77 or Fortran 95 declaration style. This is done by setting item 4 of the configuration data to 4 or 6 respectively. For example, given the following code fragment:
PARAMETER (MXOB=50)
PARAMETER (MXAT=MXOB)
PARAMETER (MXANG=80)
COMMON /ODDS / NNOBS,NATOMS,NANGLS,SC(2)
C comment 1
REAL*8 X(MXAT),Y(MXAT),Z(MXAT),CHGE(MXAT)
INTEGER IP(MXOB),IQ(MXOB),NAT(MXAT),ITYP(MXAT)
INTEGER ITA(3,MXANG)
REAL*8 AKT(MXOB),ALO(MXOB),AKA(MXANG),AAO(MXANG)
INTEGER IWORK(MXAT)
! comment 2
INTEGER*2 TOSPN(MXAT)
INTEGER MXIT,I
REAL*8 RMSMIN,ENGMIN,RMS,ENERG1,ENERGY
RMSMIN = 0.0
then, if item 4 is set to 4, SPAG produces:
C*** Start of declarations rewritten by SPAG
C
C PARAMETER definitions
C
INTEGER MXOB , MXAT , MXANG
PARAMETER (MXOB=50,MXAT=MXOB,MXANG=80)
C
C COMMON variables
C
INTEGER NANgls , NAToms , NNObs
REAL*8 SC(2)
COMMON /ODDS / NNObs , NAToms , NANgls , SC
C
C Dummy arguments
C
REAL*8 Energy , Engmin , Rmsmin
REAL*8 Alo(MXOB)
C
C Local variables
C
REAL*8 aao(MXANG) , aka(MXANG) , akt(MXOB) ,
& chge(MXAT) , energ1 , rms , x(MXAT) ,
& y(MXAT) , z(MXAT)
INTEGER i , ip(MXOB) , iq(MXOB) , ita(3,MXANG) ,
& ityp(MXAT) , iwork(MXAT) , mxit , nat(MXAT)
INTEGER*2 tospn(MXAT)
C
C*** End of declarations rewritten by SPAG
C
C comment 1
! comment 2
Rmsmin = 0.0
If item 4 is set to 36, SPAG produces:
!*** Start of declarations rewritten by SPAG
!
! PARAMETER definitions
!
INTEGER , PARAMETER :: MXOB = 50 , MXAT = MXOB , & & MXANG = 80
!
! COMMON variables
!
INTEGER :: NANgls , NAToms , NNObs
REAL(R8KIND) , DIMENSION(2) :: SC
COMMON /ODDS / NNObs , NAToms , NANgls , SC
!
! Dummy arguments
!
REAL(R8KIND) :: Energy , Engmin , Rmsmin
REAL(R8KIND) , DIMENSION(MXOB) :: Alo
INTENT (OUT) Rmsmin
!
! Local variables
!
REAL(R8KIND) , DIMENSION(MXANG) :: aao , aka
REAL(R8KIND) , DIMENSION(MXOB) :: akt
REAL(R8KIND) , DIMENSION(MXAT) :: chge , x , y , z
REAL(R8KIND) :: energ1 , rms
INTEGER :: i , mxit
INTEGER , DIMENSION(MXOB) :: ip , iq
INTEGER , DIMENSION(3,MXANG) :: ita
INTEGER , DIMENSION(MXAT) :: ityp , iwork , nat
INTEGER(I2KIND) , DIMENSION(MXAT) :: tospn
!
!*** End of declarations rewritten by SPAG
!
! comment 1
! comment 2
Rmsmin = 0.0
SPAG breaks the declarations into four labelled sections, any of which may be absent:
Because of the fundamental nature of the rewriting process, it is not possible to retain comments in their original relation to declarations. Thus, in the above example, comments which were attached to the old declarations are grouped together after the rewritten code.
INCLUDE statements from the original code are, depending on item 4 of spag.fig, rewritten as modules, or placed before the first rewritten declaration. As a result:
If item 4 of spag.fig is set appropriately, SPAG creates modules containing interfaces for every subroutine or function it processes. It also inserts appropriate USE statements at the head of the calling subprograms. Together, these changes make it possible for a Fortran 95 compiler to check that the arguments in every subprogram reference match the corresponding dummy arguments.
At first sight, this may seem a pointless exercise, as plusFORT manages the same checks, and more, without any help from the user! However the modules can also be passed to others, and this will allow them to check interfaces without having access to the source code.
If the called subprogram name is abc, the interface module name will be s_abc, and it will be stored in a file as specified by items 11, 236 and 237 of spag.fig.
If the program calls a subprogram that has not been processed by SPAG, there is no interface module to satisfy the reference in the calling subprogram's USE statement. In this case, the user must either provide an interface module to satisfy the reference, or remove the USE statement.
SPAG can also translate INCLUDE files to Fortran 95 modules. Each INCLUDE file is translated the first time it is encountered in a run,.
SPAG derives the module name from the INCLUDE file name by discarding the directory and extension, and prefacing the two characters i_. For example, an INCLUDE file called f:\include\abc.inc will be translated to a module called i_abc. This module is written to a file called \moddir\i_abc.xyz, where \moddir\ is the directory specified in item 236, and .xyz is the extension specified in item 237.
To be translated correctly, an INCLUDE file must:
COMMON /aaa/ x(n)
is not self-contained, because the type of x, and the type and value of n are undefined. In one context, x may be REAL, and n may be an INTEGER PARAMETER with a value of 100. In another, x may be a LOGICAL array, and n may be 2000. The module written by SPAG will assume that the context in the first occurrence of the INCLUDE file is universal.
To make the above INCLUDE file self-contained, one might add two statements as shown below:
REAL x
INCLUDE 'dims.inc'
COMMON /aaa/ x(n)
where the type and value of n are defined in dims.inc (which must itself be self-contained).
SPAG can also translate COMMON blocks which are not contained in an INCLUDE file to Fortran 95 modules. However it is strongly recommended that COMMON blocks be put into INCLUDE files before translation is attempted. This is because the conditions required for correct translation of an isolated COMMON are stricter than for INCLUDE files. For a COMMON block to be translated correctly:
SPAG derives the module name from the COMMON block name by discarding the '/'s, and prefacing the two characters c_. For example, an INCLUDE file called /HELLO/ will be translated to a module called c_hello. This module is written to a file called \moddir\c_hello.xyz, where \moddir\ is the directory specified in item 236, and .xyz is the extension specified in item 237.
As programs are developed, variables, parameters, COMMON blocks and code fragments fall into disuse. Programmers are often reluctant to remove such 'clutter' because of the possibility of un-looked for side effects. However over a period, clutter can make programs more obscure and difficult to maintain than they need be. SPAG can remove many types of clutter, and identify many others. Specifically, SPAG can remove the following (provided they are not defined in an INCLUDEd file):
If item 3 is set to 1, and item 29 to 0, SPAG identifies, but does not remove the above.
ANSI standard Fortran allows compilers to allocate memory for COMMON blocks dynamically. Theoretically, a COMMON block becomes undefined if it is not referenced by any executing subprogram. In practice, most, if not all current compilers treat COMMON blocks as static, and many users would be confused and dismayed if they did not!
If SPAG removes an unreferenced COMMON block, the point at which the COMMON theoretically becomes undefined may also be altered. If you wish to avoid this possibility, specify the COMMON block name in a SAVE statement, set item 3 of the SPAG configuration data to 3 or less, or ensure that all COMMONs are specified in the main PROGRAM (SPAG never removes COMMONs or INCLUDEs from a main program or BLOCK DATA).
SPAG identifies, but cannot remove
The GXCHK program which uses the symbol tables written by SPAG to construct a global symbol table for an entire program identifies clutter on a program-wide basis (e.g. globally unused COMMON variables).
SPAG provides a simple and safe method for systematically changing the names of symbols within a program. SPAG guards against the danger of choosing a new name which is already in use, and re-formats the source code appropriately. The rename facility is activated by setting item 5 of spag.fig to 1, and specifying the name of a file containing details of the required changes in item 211.
A sample rename file is shown below. The file consists of a series of sections, separated by blank lines. The first line of each section specifies the scope of the following instructions. The remaining lines in the section specify the before and after names, separated by spaces, of the symbol to be renamed. If the scope is '*', the changes are applied without restriction. This could be used, for example, to change specific function names, such as AMAX0, to the generic form (MAX). If the scope is a file-name surrounded by apostrophes, the changes are made only if the specified file is INCLUDEd in the current subprogram. Note that the INCLUDE file itself is not changed - only the references to it in the current subprogram. If the scope is a subprogram name, the changes are made only within the specified subprogram.
*
AMOD10 mod
AMIN1 min
'test1.prv'
fchsta firstc
zsyst zzzsys
/pkchAR/ /pkcomm/
swstx2
ityp jtyp
jtyp ityp
lopbr lclbr
lclbr lopbr
swfrag
oxo xox
In some circumstances, it may be desirable to suppress the re-formatting of statements. This is particularly true when a long declaration has been carefully aligned by hand to give a particular visual effect. SPAG allows you to suppress re-formatting by inserting a directive of the form
!-ASIS
in the source code. This directive governs only the immediately following statement. Note that compilers treat the directive as a comment. C-ASIS and *-ASIS are accepted as alternatives in fixed format source code.
For example
!-ASIS
DATA XOX / 1 , 0 , 1
& , 0 , 1 , 0
& , 1 , 0 , 1 /
!-ASIS can be used safely with any declaration statement. However it is, in general, not safe to use !-ASIS with executable statements or others, such as FORMAT, which may be labelled. In such cases SPAG leaves the statement label unchanged, even if the code is re-labelled. In other cases the original code may no longer be appropriate. For example, SPAG may reverse the logic in a block IF statement, or convert it to an ELSEIF. These changes will not be apparent in the output code if !-ASIS is used on executable statements. Despite these problems, we have, because of user demand, decided to retain the option of using !-ASIS on executable statements. SPAG issues a warning for every unsafe usage; it is up to the user to hand-check code when such a warning is issued.
Item 60 of the configuration file allows you to specify that all declaration statements should be treated as though prefaced by !-ASIS This switch is suppressed if item 4 specifies that declarations are to be rewritten.
Occasionally, it may be desirable to force SPAG to leave a particular statement in position. This can be done by inserting a !-ANCHOR directive immediately before the statement in question. C-ANCHOR and *-ANCHOR are accepted as alternatives in fixed format source code. The anchored statement must be an executable statement, and must have a label. Note that even when a statement is anchored, it is possible that surrounding code may be relocated in such a way that it appears to move.
Comments are presumed to be attached to the statement that follows them, and as the code is restructured, are moved around in the same way as that statement. End-of-line comments are an exception, and are attached to the statement with which they share a line. Another exception is comments preceding statements which are removed from the program (e.g. CONTINUE or GOTO statements which are not needed in the unscrambled code). These are attached to the statement following the redundant statement. The net result is that SPAG preserves comments and usually puts them in the right place.
Because of its antiquity, Fortran has always been an upper-case language. Even today, many Fortran programmers stick entirely to upper-case, even though mixed case is permitted by every major compiler (and is standard Fortran 95). This is a shame, because an important opportunity to make programs self-documenting is being missed. SPAG can be configured to make full use of case to distinguish different types of symbol. For example you can make special symbols (such as PARAMETERs and subprogram names) upper case; symbols which refer to global data (such as COMMON variables and dummy arguments) could be capitalized (e.g. Arg); and local variables could be lower case. A scheme like this helps programmers to know what they are looking at without constant reference to the declaration section.
If item 2 of spag.fig is set to 2, SPAG generates symbol table files which provide valuable information about data usage within subprograms. These files are used by GXCHK, the global cross check program, to generate an overview of data usage within an entire program. The process is analogous to the more familiar procedure of compiling and linking. The symbol tables are analogous to object files, and GXCHK works like a linker to combine them into a single global report. Indeed, the AUTOMAKE tool, which automates compiling and linking can also be used to rebuild the global report file.
Symbol tables are plain ASCII text files, the format of which is described in detail in Appendix A. Users are encouraged to develop their own applications using these files as input. For example it would be a simple matter to write a program to check conformance to local variable naming conventions.
VMS VAX Fortran permits source code to be INCLUDEd from VMS text libraries, using an INCLUDE statement of the form:
INCLUDE 'LIBNAME(MEMBER)'
Although SPAG cannot read text libraries, INCLUDE statements of this form can be used. SPAG interprets the above example as being equivalent to
INCLUDE 'MEMBER.FOR'
Thus, if the VMS command
LIBRARY/EXTRACT=MEMBER
/OUTPUT=MEMBER.FOR LIBNAME.TLB
is used before SPAG is run, SPAG will behave correctly. Note that the files containing the extracted library members may be in a separate directory, provided that the directory is specified in the INCLUDE file search list (see item 215 of the SPAG configuration data). Note too that a leading '$' in the member name is removed. Thus ($foriosdef) is treated as foriosdef.for.
IF ( A1*FUNC(X) ) 100,200,300
becomes
TEMP = A1*FUNC(X)
IF ( TEMP ) 100,200,300
Dynamic analysis is a simple procedure for validating the operation of a program at run-time. It involves setting up a test version of your program containing extra checking code. This test program is compiled and linked in the normal way. The executable code appears to the user to operate in exactly the same way as the original, though it is larger and slower. If the checking code detects an error, it writes details to a log-file, and continues execution. The programmer can then view the log-file at leisure after the run completes.
The example below shows how dynamic analysis works:
SUBROUTINE QKNUM(Ival,Pos)
INTEGER Ival , Pos , vals(50) , ios
READ(11,*,IOSTAT=ios) vals
IF ( ios.EQ.0 ) THEN
DO Pos = 1 , 50
IF ( Ival.EQ.vals(Pos) ) RETURN
ENDDO
ENDIF
100 Pos = 0
END
QKNUM is a simple routine which reads a list of 50 integers from a data file; the position of the first in the list with value Ival is returned in Pos. If none is equal to Ival, or if an error or end-of-line condition occurs while reading the list, Pos is returned as 0.
Most of the time, QKNUM will probably work well. Compilers and static analyzers are unlikely to find anything wrong with it, but nevertheless, it does contain a logical flaw. If the data file contains:
2,9,,11,20*44,26*
Then items 1, 2 and 4 to 24 are assigned values. Items 3 and 25 to 50 remain unchanged from their initial (undefined) value. The result of the test on line 6
IF ( Ival.EQ.vals(Pos) ) RETURN
is therefore undefined, and the program will behave unpredictably.
Whilst this particular bug is not common, it does illustrate, in a compact example, two features which are common to many bugs, and which defeat static analysis:
A version of QKNUM modified to perform a dynamic analysis might appear as follows:
SUBROUTINE QKNUM(Ival,Pos)
INTEGER Ival , Pos , vals(50) , ios
! insert 'undefined' value in ios
CALL UNDFI(ios)
! insert 'undefined' value in every element of vals
CALL UNDFIA(vals,50)
READ(11,*,IOSTAT=ios) vals
! check that ios is defined
IF ( ios.EQ.UNDEF ) CALL ERROR
IF ( ios.EQ.0 ) THEN
DO Pos = 1 , 50
! check that Ival and vals(Pos) are defined
IF ( Ival.EQ.UNDEF ) CALL ERROR
IF ( vals(pos).EQ.UNDEF ) CALL ERROR
IF ( Ival.EQ.vals(Pos) ) RETURN
ENDDO
ENDIF
100 Pos = 0
END
The modified code contains a new section which initializes all local variables to a special 'undefined' value. This section is executed immediately after QKNUM is entered. Note that dummy arguments and COMMON variables are NOT initialized - they are assumed to be initialized higher up the call tree.
In addition a test is inserted wherever the value of a variable is used. For example, the test
IF ( Ival.EQ.vals(Pos) ) RETURN
is meaningless if either Ival or vals(Pos) is undefined. The code therefore contains tests for both items. The variable Pos is also used, and, at first sight it may appear necessary to check Pos before testing vals(Pos). However, in this case we can deduce that Pos must be defined because it is a DO loop variable.
A version of QKNUM modified in this way will log an error when the input data leaves elements of vals undefined.
When the dynamic analysis option of SPAG is activated (by setting item 1 of the configuration data to 4), it modifies the program to perform a dynamic analysis. The details differ from the above example, but the principles are identical. The modifications are automatic and require no user intervention. SPAG knows about variables initialized in DATA or type statements, and does not re-initialize them. It also distinguishes static variables (specified using SAVE) from others. Static variables are initialized only once - when first entering the subprogram that defines them. Other local variables are re-initialized to the undefined value every time a subprogram is entered. If item 36 of the configuration data is set to 1, all local variables are assumed to be static. This is probably the safest starting point for programs of unknown history.
The SPAG Dynamic analysis tool works with Fortran 77 input code, and with some Fortran 95 extensions. Most programs which use Fortran 90 or 95 features cannot be instrumented. In particular, SPAG does not (in this context) deal correctly with derived types, pointers, allocatable arrays, and array language.
One area which may require a little attention from the user is the initialization of COMMON variables to the undefined value.
SPAG inserts code to initialize COMMON variables at the start of the main program immediately after the program starts. It follows that all COMMON variables must be available within the main program. This may require some hand-edits to your program, perhaps to insert some INCLUDE statements in the main program. SPAG does not do this automatically, but GXCHK (see Chapter 3) will tell you of any COMMON blocks which are not specified in the main program.
One final precaution is necessary: COMMON variables may be initialized using DATA statements in a BLOCKDATA subprogram. Many compilers also allow COMMON variables to be initialized in other ways, for example, in type statements within a subprogram. We must ensure that the initialization code generated by SPAG does not overwrite these genuine initializations in BLOCKDATAs or elsewhere.
This is achieved by running GXCHK (see Chapter 3) after SPAG has finished. If COMMON variables are initialized anywhere in the source code, GXCHK modifies the dynamic analysis version of the main program to remove the statements which would overwrite the initialization. This process is automatic, and requires no user intervention.
The steps required to perform a dynamic analysis of a Fortran program using SPAG and GXCHK are as follows:
It is possible, though extremely rare in practice, for the probes to report an error when there is none. This happens if the 'undefined' bit pattern occurs as the normal result of a calculation within the program. For 32 and 64 bit data items, this possibility is vanishingly small. Even for 8 and 16 bit data, it happens so infrequently that, for most users, the benefits of the test will outweigh the inconvenience of checking for false positives.
Item 35 of the SPAG configuration data specifies the minimum size (in bytes) of numeric and logical data items to be tested using dynamic analysis.
Item 35 does not apply to CHARACTER strings, because their length is not generally known until run-time. Instead, there is a test within the probe itself. Users may modify the source code of the probe as required (see Appendix B).
Code containing dynamic analysis probes can be mixed freely with normal code. Similarly, the use of external object files and libraries presents no problems. The only restriction is that GXCHK must process the source code of all subprograms that initialize COMMON data.
Dynamic analysis is not put off by EQUIVALENCEd data, or by COMMON blocks whose structure varies from one subprogram to another (provided that the version which appears in the main program includes the entire data area).
SPAG and GXCHK offer facilities for both static and dynamic analysis, and we are often asked which is best. The answer is that the two are complimentary. Each excels where the other is deficient.
A static analyzer checks all your code, whether it executes or not; it produces useful results without the need to perform test runs; it produces documentation which is of general use to managers and staff working on the program. On the other hand, a static analyzer cannot hope to predict the effect of external data on your program's execution, or to monitor the status of every byte of memory.
Dynamic analysis, on the other hand, operates when your program is running with real data, and can monitor memory at the byte level. The main disadvantage of dynamic analysis is that, unlike static analysis, it does not check all your code, only the parts that execute in a given run.
This disadvantage can be removed by using coverage analysis (see Section 2.9 and Chapter 4) to ensure that your test program exercises all of your source code.
Working together, static, dynamic, and coverage analysis provide an unrivalled health check for your programs.
SPAG contains facilities for inserting probes into Fortran source code for the purpose of analyzing the run-time performance. These probes may be used to detect execution hot-spots, identify untested code-blocks, or provide a profile of CPU usage.
If item 6 of the configuration data is set to 2, SPAG prepares your code for coverage analysis testing by:
A weaker form of program tracing is invoked by setting item 6 of the SPAG configuration data to 1. With this setting, tracing takes place only at the subprogram level, and no coverage analysis data files are produced. In conjunction with the plusFORT probe routines this is sufficient to produce a profile of CPU usage by subprogram (see Appendix B).
Either form of coverage analysis depends on data written when the test program finishes. If the program is interrupted, or if execution is halted by a routine which does not contain probes, the required data is not written, and coverage analysis fails for this run (though no damage is done to the data files). This can happen if you call a system routine (e.g. CALL EXIT) to halt execution. The problem may be avoided by inserting a call to the program termination probe, PR$EXI, just before the call to EXIT.
CALL PR$EXI
CALL EXIT(16)
If dynamic analysis (section 2.8) is activated, item 6 is automatically set to 1.
If SPAG Configuration item 1 is set to 5, SPAG prepares source code for a special sort of dynamic analysis, originally geared towards finding the date associated problems which were expected to occur on or around the year 2000. The instrumented program executes normally, but as it runs, every variable or array element, used in any way, is checked for data which could be date related. A report is written to the file probes.log. The same technique can be used for other similar tasks - for example, to find the parts of a program that deal with with currency transactions
Most tools for detecting Year 2000 problems rely largely on finding date references in the source code, for example in the form of variable or subprogram names such as IDATE or LEAP. This approach, which is implemented in GXCHK, may fail if the programmer has not chosen names which reflect the variable's usage. SPAG's analysis is different, and can detect date variables, even if their name is unrelated to their function. For example, if the programmer has used a variable called K2 to store a 2 digit year, SPAG will spot it, because it looks at the contents of the variable at run-time, rather than at the source code.
All that's required to perform a Year 2000 check is to instrument the source code using SPAG (with item 1 of the configuration data set to 5), and then compile and run the program as normal. An additional source file called probes.y2k must be compiled and linked with the instrumented code.
This form of dynamic analysis is much simpler than the standard type, because variables do not have to be initialized, and there is no need to run GXCHK before starting the analysis.
When the run is complete the file probes.log contains a summary of the variables which could be date related, together with their values, and the line in the source code where they are set. The probe routines contain logic to ensure that multiple reports of the same type are condensed to a single report.
Inevitably, many of the reports will be false positives; a variable may contain the value 1998, and yet not be a date variable. In practice, you'll probably need to do several runs, tuning the criteria to isolate problem code. There are two ways to eliminate these false positives:
The USE statement in Fortran 95 allows a subprogram to import data and interfaces from a separately compiled module. It is in many ways analagous to an INCLUDE statement, and is generally recommended as a superior replacement for both INCLUDE and COMMON. In order to interpret USE correctly, SPAG must import information about the external module. It does this by reading the symbol table generated when SPAG processed the module. This gives rise to 2 problems:-
To do this, SPAG maintains a ASCII text file called PFMODULE.KEY. This file contains records which specify the location of each module USEd by source code in the current directory. For example
TRAJECTORY : traject.smb
specifies that the symbol table for module TRAJECTORY is in the file traject.smb.
As SPAG processes source code, it automatically inserts records in PFMODULE.KEY for every module it encounters. When SPAG encounters a USE statement, it consults this file to find the module data.
An exception to this rule is that SPAG will not automatically find modules from a different directory. In this case it is recommended that the locations of modules be inserted in PFMODULE.KEY using a text editor.
GPS_COORDS : gps\coordmod.smb
When SPAG looks in PFMODULE.KEY to find the location of the symbol data for a particular module, it may find that there is no entry, because the module has not been processed yet. In this case SPAG reports an error. This is similar to the problem, familiar to most Fortran 90/95 programmers, that occurs when modules are not compiled before code that USEs them.
It is possible to overcome this problem by repeatedly re-running SPAG until the modules are all processed. However this can take some time, particularly if USEs are nested to any depth. In addition if a module is changed, SPAG may use an obselete symbol table, and produce incorrect results while appearing to work correctly.
The plusFORT AUTOMAKE tool provides a solution to this problem (just as it does for compilers). The plusFORT installation directory contains a batch/shell file called Autospag, which uses AUTOMAKE to run SPAG in such a way that the processing order requirements are satisfied. A small configuration file called autospag.fig should be placed in the source directory. A typical case, in which all .F90 files are to be processed, and the symbol table files have the .smb extension would be handled by the following configuration file:
COMPILE=@spag %fi
OBJEXT=SMB
FILES=*.f90
NOQUITONERROR
Then to run SPAG on all .F90 files in the current directory, simply type Autospag. More complicated cases can be handled with suitable changes to autospag.fig (see the AUTOMAKE documentation)