FTNCHEK(1)

πŸ“¦
version 3.3.1 Β· 2 versions
  • 3.3.1 Β· debian bookworm, debian trixie, ubuntu jammy, ubuntu noble, ubuntu questing, ubuntu resolute, ubuntu stonking (latest)
  • 3.3.1 Β· fedora 43, fedora 44
, in debian bookworm, debian trixie, ubuntu jammy, ubuntu noble, ubuntu questing, ubuntu resolute, ubuntu stonking

πŸ’– FTNCHEK 3.3 πŸ’– β€” the General Commands Manual page, but make it make sense

okay bestie, welcome to ftnchek version 3.3, living in section 1 of the General Commands Manual. this is the whole vibe, let's get into it ✨


🌸 NAME 🌸

ftnchek β€” a Fortran 77 program checker 🧚


πŸ¦‹ SYNOPSIS πŸ¦‹

ftnchek [ -arguments[=list] ] [ -array[=list] ]
     [ -[no]brief ] [ -calltree[=list] ] [ -[no]check ]
     [ -columns[=num] ] [ -common[=list] ]
     [ -[no]crossref[=list] ] [ -[no]declare ]
     [ -[no]division ] [ -errors[=num] ] [ -[no]extern ]
     [ -[no]f77[=list] ] [ -[no]f90[=list] ]
     [ -[no]f95[=list] ] [ -[no]help ]
     [ -[no]identifier-chars[=list] ] [ -include=str ]
     [ -intrinsic[=list] ] [ -[no]library ] [ -[no]list ]
     [ -makedcls[=list] ] [ -mkhtml[=list] ]
     [ -[no]novice ] [ -output=str ]
     [ -pointersize[=num] ] [ -[no]portability[=list] ]
     [ -[no]pretty[=list] ] [ -project[=list] ]
     [ -[no]pure ] [ -[no]quiet ] [ -[no]reference ]
     [ -[no]resources ] [ -[no]sixchar ] [ -[no]sort ]
     [ -source[=list] ] [ -style[=list] ] [ -[no]symtab ]
     [ -[no]truncation[=list] ] [ -usage[=list] ]
     [ -[no]vcg ] [ -[no]version ] [ -[no]volatile ]
     [ -wordsize[=num] ] [ -wrap[=num] ] [ files ...  ]

✨ DESCRIPTION ✨

so ftnchek (short for Fortran checker, iykyk) is designed to sniff out certain errors in a Fortran program that a compiler usually just… doesn't. and no, bestie, it's not primarily here to catch syntax errors β€” that's not the assignment. its whole purpose is to help you find semantic errors. semantic errors are legal in the Fortran language but they're wasteful, or they may cause your program to operate incorrectly 😭.

like, for example: variables that are never used might be a sign that something got omitted from the program somewhere. uninitialized variables contain straight-up garbage which may cause incorrect results to get calculated. and variables that aren't declared may not have the type you actually intended. so rude.

ftnchek is here to assist users in the debugging of their Fortran program. it is not intended to catch all syntax errors β€” that's the compiler's job, fr fr. so before you even use ftnchek, please verify that the program compiles correctly. πŸ’…

this document first summarizes how to invoke ftnchek β€” that section should be read before you start using it. later sections describe ftnchek's options in more detail, give an example of its use, and explain how to interpret the output. the final sections mention the limitations and known bugs in ftnchek. buckle up πŸŽ€


πŸ‘‘ INVOKING FTNCHEK πŸ‘‘

ftnchek is invoked through a command of the form:

$ ftnchek [-option -option ...] filename [filename ...]

the brackets indicate something which is optional β€” you do not actually type the brackets, bestie, they're just vibes. here, options are command-line switches or settings, which control the operation of the program and the amount of information that will be printed out. if no option is specified, the default action is to print error messages, warnings, and informational messages, but not the program listing or symbol tables.

every option begins with the - character. (on VAX/VMS or MS-DOS systems you may use either / or -.) and for the sake of conformity with an increasingly common convention, options can also begin with --. the options are described at greater length in the next section.

ftnchek options fall into two categories: switches, which are either true or false, and settings, which have a numeric or string value. the name of a switch is prefixed by no or no- to turn it off: e.g. -nopure would turn off the warnings about impure functions. the no prefix can also be used with numeric settings, having the effect of turning off the corresponding warnings. settings that control lists of warnings have a special syntax discussed below. only the first 3 characters of an option name (not counting the -) need to be provided. a colon may be used in place of an equals sign for numeric or string setting assignments; however, we show only the equals sign form below.

the switches and settings which ftnchek currently recognizes are listed below. for each option, the default is the value used if the option is not explicitly specified, while the turn-on is the value used if the option is given without assigning it a value.


  • -arguments=list β€” control warnings about subprogram type and argument mismatches. Default = turn-on = all.
  • -array=list β€” control warnings in checking array arguments of subprograms. Default = turn-on = all.
  • -brief β€” use shorter format for some error messages. Default = no.
  • -calltree=list β€” produce subprogram call hierarchy in one of 3 formats: text calltree, who-calls-who and VCG. Default = none, turn-on = tree,prune,sort.

if the -mkhtml option is invoked and tree is the applied calltree option, a file named CallTree.html, will be produced depicting the tree in HTML format. πŸ¦‹

  • -check β€” perform checking. Default = yes.
  • -columns=num β€” set maximum line length to num columns. (beyond this is ignored, so anything past the limit just gets ✨ yeeted ✨) Turn-on = max = 132. Default = 72.
  • -common=list β€” set degree of strictness in checking COMMON blocks. Default = turn-on = all.
  • -crossref=list β€” print cross-reference list of subprogram calls, label usage, and/or COMMON block use. Default = none.
  • -declare β€” print a list of all identifiers whose datatype is not explicitly declared. Default = no.
  • -division β€” warn wherever division is done (except division by a constant). Default = no.
  • -errors=num β€” set the maximum number of error messages per cascade. Default = turn-on = 3.
  • -extern β€” warn if external subprograms which are invoked are never defined. Default = yes.
  • -f77=list β€” control specific warnings about supported extensions to the Fortran 77 Standard. Default = none, turn-on = all.
  • -f90=list β€” control specific warnings about supported extensions to the Fortran 77 Standard that were not adopted as part of the Fortran 90 Standard. Default = none, turn-on = all.
  • -f95=list β€” control specific warnings about standard Fortran 77 features that were deleted from the Fortran 95 Standard. Default = none, turn-on = all.
  • -help β€” print command summary. Default = no.
  • -identifier-chars=list β€” define non-alphanumeric characters that may be used in identifiers. Default = turn-on = dollar sign and underscore.
  • -include=path β€” define a directory to search for INCLUDE files before searching in the system-wide directory. Cumulative. Default = turn-on = none.
  • -intrinsic=list β€” control treatment of nonstandard intrinsic functions. Default = all except vms for Unix version, all except unix for VMS version, all except unix and vms for other versions. Turn-on = all.
  • -library β€” begin library mode: do not warn about subprograms in file that are defined but never used. Default = no.
  • -list β€” print source listing of program. Default = no.
  • -makedcls=list β€” prepare a file of declarations. the list specifies options for the format of this file. Default = none, turn-on = declarations.
  • -mkhtml=list β€” create individual HTML document files from ftnchek analysis and code comments. usually you will also want to specify -call=tree to create the root HTML file CallTree.html. Default = none, turn-on = documents.
  • -novice β€” give output suitable for novice users. Default = yes.
  • -output=filename β€” send output to the given file. Default and turn-on sends output to the screen. (default filename extension is .lis).
  • -pointersize=num β€” set the size of ``Cray pointer'' variables to num bytes. Min = 1, max = 16. Default = turn-on = 4
  • -portability=list β€” warn about non-portable usages. Default = none, turn-on = all.
  • -pretty=list β€” give warnings for possibly misleading appearance of source code. Default = turn-on = all.
  • -project=list β€” create project file (see explanation below). Default = no.
  • -pure β€” assume functions are pure, i.e. have no side effects. Default = yes.
  • -quiet β€” produce less verbose output. Default = no.
  • -reference β€” print table of subprograms referenced by each subprogram. Default = no.
  • -resources β€” print amount of resources used in analyzing the program. Default = no.
  • -sixchar β€” list any variable names which clash at 6 characters length. Default = no.
  • -sort β€” print list of subprograms sorted in prerequisite order. Default = no.
  • -source=list β€” select source formatting options: fixed or free form, DEC Fortran tab-formatted lines, VMS-style INCLUDE statement, UNIX-style backslash escape sequences, and implicit typing of parameters. Default = none, turn-on = all.
  • -style=list β€” produce extra-picky warnings about obsolescent or old-fashioned programming constructions. Default = none, turn-on = all.
  • -symtab β€” print symbol table and label table for each subprogram. Default = no.
  • -truncation=list β€” check for possible loss of accuracy by truncation. Default = turn-on = all.
  • -usage=list β€” control warnings about unused or uninitialized variables, common blocks, etc. Default = turn-on = all.
  • -vcg β€” produce VCG format of call graph.
  • -version β€” print version number. Default = no.
  • -volatile β€” assume COMMON blocks lose definition between activations. Default = no. (Obsolete. use -common=volatile instead.) ⚠️
  • -wordsize=num β€” set the default word size for numeric quantities to num bytes. Default = turn-on = 4 bytes.
  • -wrap=num β€” set output column at which to wrap long error messages and warnings to the next line. if set to 0, turn off wrapping. Default = turn-on = 79.

when more than one option is used, they should be separated by a blank space, except on systems such as VMS where options begin with slash ( / ). no blank spaces may be placed around the equals sign ( = ) in a setting. ftnchek "?" will produce a command summary listing all options and settings. 🫢

okay so a whole bunch of these settings don't take just one lil value β€” they take a whole list of keywords, and that list is separated by commas or colons. πŸ’« The settings that work like this are: -arguments, -array, -calltree, -common, -crossref, -f77, -f90, -f95, -intrinsic, -makedcls, -mkhtml, -portability, -pretty, -project, -source, -style, -truncation, and -usage. ✨

If you just don't give a list at all, the effect is to set the option to its turn-on value (same as all in most cases, bestie). And also β€” if the list is omitted β€” you can prefix the setting name with no or no- to turn off everything it controls. So like, -f77 turns on all warnings about nonstandard constructions, while -nof77 turns them all off. πŸ’…

There are three special keywords, and they're giving main character energy:

  • help β€” print out all the option keywords controlled by the setting, with a brief explanation of their meanings. This one cannot be given in a list with other keywords. 🚫
  • all β€” set all options. This turns on all options controlled by the setting.
  • none β€” clear all options. This turns off all options controlled by the setting.

These three special keywords must be given in full (no abbreviating, sorry babe πŸŽ€). For all the other keywords though, you only need as many letters as necessary to identify it unambiguously, or you can throw a wildcard pattern in there. Including a keyword in the list turns the corresponding option on. For example, -f77=intrinsic would turn on only the warnings about use of nonstandard intrinsic functions. Prefixing a keyword by no- turns its option off. For example, -pretty=no-long-line turns off warnings about lines exceeding 72 columns in length while leaving all other warnings about misleading appearance in effect. πŸ¦‹

And here's a lil trick, iykyk: if a setting has default none, you can turn on all options except one or two by using all first. For example, -f77=all,no-include enables warnings about all nonstandard extensions except INCLUDE statements. And if a setting has default all, you can turn off all warnings except one or two by using none first. For example, -truncation=none,demotion would turn off all precision related warnings except about demotions. πŸ‘‘

Wildcard patterns contain an asterisk to stand for any string of characters. If a wildcard pattern is used, all the warnings that match it are affected. If no- is prefixed to the pattern, all the matching warnings are turned off, otherwise they're all turned on. The minimum unambiguous length rule does not apply to wildcard matching. For example, use -usage=no-*var* to turn off all warnings relating to variable usage (both local and common). 🌈

(Unix users may need to quote any options containing wildcards in order to prevent the shell from attempting to expand them.) πŸ’€

Wildcards are recognized only in lists of warning keywords, not in the top-level options themselves. periodt.


When ftnchek starts up, it looks for environment variables and also for a preferences file. Any options defined in the environment or in the preferences file are used as defaults in place of the built-in defaults. They are over-ridden by any command line options. See the section on changing the defaults for details about the environment options and the preferences file. πŸ“‚

When giving a name of an input file, the extension is optional. If no extension is given, ftnchek will first look for a project file with extension .prj, and will use that if it exists. If not, then ftnchek will look for a Fortran source file with the extension .for for VMS systems, .f for UNIX systems. More than one file name can be given to ftnchek, and it will process the modules in all files as if they were in a single file. 🫢

Wildcards are allowed in the specification of filenames on the command line for the VMS and MS-DOS versions, as also of course under UNIX and any other system that performs wildcard expansion in the command processor. ✨

If no filename is given, ftnchek will read input from the standard input. πŸ’…


✨ OPTIONS ✨

okay bestie, this section is the deep dive on ftnchek command-line options. πŸ’– Options and filenames may be interspersed on a command line. Most options are positional: each option remains in effect from the point it is encountered until it is overridden by a later change. So for example, the listing may be suppressed for some files and not for others. πŸŽ€

The exceptions (the ones that are not just positional) are:

  • the -intrinsic, -pointersize, and -wordsize settings, which cannot be changed once processing of input files has started;
  • the -arguments, -array, -calltree, -common, -crossref, -extern, -reference, -resources, -sort, -vcg, and -volatile options, where the action depends only on the value of the option after the processing of input files is finished;
  • and the -include setting, which is cumulative. πŸ”₯

The option names in the following list are in alphabetical order. πŸ¦‹


  • -arguments=list β€” Controls warnings about mismatches between actual and dummy subprogram arguments, and also about mismatches between expected and actual subprogram type. (An actual argument is an argument passed to the subprogram by the caller; a dummy argument is an argument received by the subprogram.) By default, all warnings are turned on. πŸ‘‘

The list consists of keywords separated by commas or colons. Since all these warnings are on by default, include a keyword prefixed by no- to turn off a particular warning. There are three special keywords: all to turn on all the warnings about arguments, none to turn them all off, and help to print the list of all the keywords with a brief explanation of each. If list is omitted, -arguments is equivalent to -arguments=all, and -noarguments is equivalent to -arguments=none. The warning keywords with their meanings are as follows:

  • arrayness: warn about inconsistent use of arguments that are arrays. These warnings can be further controlled by the -array option.
  • type: warn about dummy arguments of a different data type from the actual arguments.
  • function-type: warn if the invocation assumes the function's return value is a different type than it actually is. Also warns if a function is called as a subroutine, or vice-versa.
  • number: warn about invoking a subprogram with a different number of arguments than the subprogram expects.

For compatibility with previous versions of ftnchek, a numeric form of this setting is also accepted: the list is replaced by a number from 0 to 3. A value of 0 turns all the warnings off, 1 turns on only number, 2 turns on all except number, and 3 turns all the warnings on. πŸ”’

This setting does not apply to checking invocations of intrinsic functions or statement functions, which can only be turned off by the -nocheck option.

See also: -array, -library, -usage.


  • -array=list β€” Controls the degree of strictness in checking agreement between actual and dummy subprogram arguments that are arrays. The warnings controlled by this setting are for constructions that might legitimately be used by a knowledgeable programmer, but that often indicate programming errors. By default, all warnings are turned on. πŸŽ€

The list consists of keywords separated by commas or colons. Since all these warnings are on by default, include a keyword prefixed by no- to turn off a particular warning. There are three special keywords: all to turn on all the warnings about array arguments, none to turn them all off, and help to print the list of all the keywords with a brief explanation of each. If list is omitted, -array is equivalent to -array=all, and -noarray is equivalent to -array=none. The warning keywords with their meanings are as follows:

  • dimensions: warn if the arguments differ in their number of dimensions, or if the actual argument is an array element while the dummy argument is a whole array.
  • size: warn if both arguments are arrays, but they differ in number of elements.

For compatibility with previous versions of ftnchek, a numeric form of this setting is also accepted: the list is replaced by a number from 0 to 3. A value of 0 turns all the warnings off, 1 turns on only dimensions, 2 turns on only size, and 3 turns all the warnings on. πŸ”’

Note: A warning is always given regardless of this setting if the actual argument is an array while the dummy argument is a scalar variable, or if the actual argument is a scalar variable or expression while the dummy argument is an array. These cases are seldom intentional. (To turn off even these warnings, use -arguments=no-arrayness.) No warning is ever given if the actual argument is an array element while the dummy argument is a scalar variable. Variable-dimensioned arrays and arrays dimensioned with 1 or asterisk match any number of array elements. There is no check of whether multi-dimensional arrays agree in the size of each dimension separately. πŸ’€

See also: -arguments, -library, -usage.


  • -brief β€” Selects a shorter format for some warning messages. At present, the only warnings controlled by this flag are those that are printed at the end of processing each subprogram. These include warnings about variables that are set but not used or used before set, variable names that do not conform to the Fortran 77 standard, etc. (These warnings may be suppressed entirely depending on other flags, such as the -usage or -f77 flags.) In the default format each variable is listed on a separate line, along with the line number where the variable is declared, set or used, according to the nature of the warning. The briefer format simply lists all variables to which the warning applies, with up to 4 variables per line. 🌸

See also: -quiet.


  • -calltree=list β€” Causes ftnchek to print out the call structure of the complete program. 🌳

The list consists of keywords separated by commas or colons. There are two special keywords: none to turn off all the options, and help to print the list of all the keywords with a brief explanation of each. (The keyword all turns on all the options, but should not normally be used since only one format should be specified.) If list is omitted, -calltree is equivalent to -calltree=tree, and -nocalltree is equivalent to -calltree=none. By default no call graph is printed. ✨

If you turn on -mkhtml and the applied calltree option is tree, bestie, you also get a file named CallTree.html πŸ’– β€” it draws the tree in HTML format. This file is literally the cutest starting point for browsing the HTML files that describe each component of your program. Obsessed.

The keywords that control which format you get are:

  • tree β€” produce the call graph in tree format.
  • reference β€” produce the call graph in who-calls-who format (same as -reference switch).
  • vcg β€” produce the call graph in VCG format (same as -vcg switch).
Only one of tree, reference, or vcg may be specified. Pick your fighter, not all three πŸ’…

And these keywords control options that affect the output:

  • prune β€” prune repeated subtrees (only applies with tree). This is the default. βœ‚οΈ
  • sort β€” sort the children of each routine into alphabetical order. Also the default. πŸ”€

Go read the discussion of the -reference and -vcg flags for the deets on those formats.

For tree format: the call graph prints out starting from the main program, which sits on the first line at the left margin. Then on the lines after that, each routine the main program calls is listed, indented a few spaces, followed by the subtree starting at that routine. 🌳

In the default mode, if a routine is called by more than one other routine, its call subtree is printed only the first time it's encountered. Later calls just give you the routine name plus the notice (see above). Wanna have the subtree printed for every single occurrence of the routine? Use option no-prune.

Heads up though 😭 the call tree will be incomplete if any of the input files are project files containing more than one module that were created in -library mode. See the discussion of project files below.

Technical points, because we're being thorough, periodt: each list of routines called by a given routine is printed in alphabetical order unless the no-sort option is given. If multiple main programs are found, the call tree of each one is printed separately. If no main program is found, a report saying exactly that gets printed out, and the call trees of any top-level non-library routines are printed. This flag only controls the printing of the call tree β€” ftnchek constructs the call tree in any case, because it uses it to determine which library modules will be cross-checked. See the discussion of the -library flag.

For compatibility with previous versions of ftnchek, a numeric form of this setting is also accepted: the list is replaced by a number from 0 to 15. That number is formed from 1 for tree format, 2 for reference format, or 3 for vcg format, plus 4 for no-prune, and 8 for no-sort. ✨

See also: -crossref, -library, -reference, -sort, -symtab, -vcg.


🌸 -check 🌸

This switch exists so that errors and warning messages can be turned off when ftnchek is being used for purposes other than finding bugs β€” like making declarations or printing the call tree, iykyk. It's positional, so after turning all the checks off, you can turn selected checks back on. πŸ’…

The effect of -nocheck is to put all switches, numeric settings, and settings controlling lists of warnings to their turn-off values, as if they'd all been specified with the -no prefix. Switches and settings that specify options and modes of operation β€” rather than controlling warnings β€” are unaffected. Those are: -columns, -crossref, -include, -intrinsic, -library, -list, -makedcls, -novice, -output, -pointersize, -project, -quiet, -reference, -resources, -sort, -source, -symtab, -vcg, -version, -wordsize, and -wrap. Default = yes.

Parse errors (syntax errors due to unrecognized or malformed statements) are not suppressed by this switch, because the results may be incorrect if ftnchek hasn't parsed the program correctly. 🫠

There are also some miscellaneous errors and warning messages that aren't controlled by any other switch, so this switch is the only way to turn them off. And note: using -check after -nocheck only turns these special warnings back on β€” it does not restore all the checks it turned off. No cap. These warnings are:

  • Module contains no executable statements.
  • In free source form, missing space where space is required (e.g. between a keyword and an identifier) or space present where none is allowed (e.g. within an identifier).
  • Zero or negative length specification in a data type declaration of the form type*len.
  • Invalid operand(s) in an expression.
  • Array assigned to scalar.
  • Type mismatch between DO index and bounds.
  • Undefined common block declared in SAVE statement.
  • Intrinsic function explicitly declared with an incompatible type.
  • Unknown intrinsic function explicitly declared in an INTRINSIC statement.
  • Intrinsic function passed as a subprogram argument is not declared in an INTRINSIC statement.
  • Intrinsic function or statement function invoked incorrectly.
  • Function does not set return value prior to RETURN statement.
  • Parameter constant value not evaluated (this is ftnchek's fault, and it's just informing you of the fact).
  • Entry point of a subprogram is later used as a different subprogram's name.
  • Unknown keyword used in an I/O statement.
  • Illegal label reference (e.g. GOTO refers to a non-executable statement; I/O statement refers to a non-format statement).

See also: -errors.


πŸŽ€ -columns=num πŸŽ€

Set the maximum statement length to num columns. (Anything beyond that is ignored.) This setting is here so you can check programs that might violate the Fortran standard limit of 72 columns for the length of a statement. Per the standard, every character past column 72 is ignored. If you use this setting while the -f77=long-line option is in effect, you'll get a warning for any lines where characters past column 72 actually get processed. Turn-on = max = 132. Default = 72.

This setting does not suppress warnings about the presence of characters beyond column 72. To process code with meaningful program text beyond column 72, use this setting and make sure the -f77 long-line option is off. To process code with sequence numbers in columns 73 to 80, leave the columns setting at the default value and use the -pretty=no-long-line flag. πŸ¦‹

See also: -f77, -pretty.


πŸ’– -common=list πŸ’–

This setting controls how strict the checking of COMMON blocks is. By default, all warnings except volatile are turned on.

The list is made of keywords separated by commas or colons. Since most of these warnings are on by default, include a keyword prefixed by no- to turn off a particular warning. There are three special keywords: all to turn on all the warnings, none to turn them all off, and help to print the list of all the keywords with a brief explanation of each. If list is omitted, -common is equivalent to -common=dimensions,exact,length,type, and -nocommon is equivalent to -common=none. The warning keywords with their meanings are:

  • dimensions β€” corresponding arrays in each declaration of a block must agree in size and number of dimensions. This option only has an effect when used together with exact.
  • exact β€” the comparison of two blocks is done variable-by-variable rather than simply requiring agreement between corresponding storage locations. Use this if all declarations of a given COMMON block are supposed to be identical, which is a good programming practice. πŸ‘‘
  • length β€” warn if different declarations of the same block are not equal in total length. The Fortran 77 Standard requires each named common block β€” but not blank common β€” to be the same length in all modules of the program.
  • type β€” in each declaration of a given COMMON block, corresponding memory locations (words or bytes) must agree in data type. If used together with exact, this will require that corresponding variables agree in data type.
  • volatile β€” Assume that COMMON blocks are volatile.

Okay so this next bit is a whole vibe check on how Fortran actually works πŸ’€. Many Fortran programmers assume that variables, whether local or in COMMON, are static β€” i.e. that once they're assigned a value, they retain that value permanently until the program assigns a different value. But ngl, the Fortran 77 Standard does not actually require this to be the case. Local variables may become undefined between activations of a module in which they're declared. Similarly, COMMON blocks may become undefined if no module in which they're declared is active. (The technical term for entities with this behavior is automatic'', but ftnchek uses the word volatile'' since it's clearer to the nonspecialist.) Only COMMON blocks declared in a SAVE statement, or declared in the main program or in a block data subprogram, remain defined as long as the program is running. Variables and COMMON blocks that can become undefined at some point are called volatile. 🌈

If the -common=volatile flag is on, ftnchek will straight up warn you when it spots a volatile COMMON block. And if at the same time -usage=com-block-volatile is also on (which, btw, it is by default πŸ’…), ftnchek tries to check whether a block like that can lose its defined status between activations of the modules where it's declared.

Not gonna lie bestie, ftnchek does not do a very good job of this 😭 the rule it uses is just: is the block declared in two separated subtrees of the call tree? Like if two modules, both called from the main program, share a volatile COMMON block β€” yeah, that case. A block can also become undefined between two successive calls of the same subprogram, but ftnchek isn't smart enough to tell whether a subprogram can be called more than once, so that case just… isn't checked for. πŸ™ˆ

The -common=volatile flag does not affect the way ftnchek checks usage of local variables. Periodt.

For compatibility with previous versions of ftnchek, a numeric form of this setting is also accepted: the list gets replaced by a number from 0 to 3. Here's the tea:

  • 0 turns all the warnings off
  • 1 or greater turns on type
  • 2 or greater turns on length
  • 3 turns on dimensions and exact also

The numeric form cannot turn on the volatile option, so don't even try it ✨

See also: -library, -usage.


  • -crossref=list β€” prints cross-reference tables. Default = none.

The list is keywords separated by commas or colons. The keywords and their meanings are giving:

  • calls β€” table lists each subprogram followed by a list of routines that call it. This listing omits library modules that are not in the call tree of the main program. The list is alphabetized. πŸ‘‘
  • common β€” table lists each COMMON block followed by a list of the routines that access it. These listed routines are the ones where some variables in the COMMON block are actually accessed, not just the routines that declare the block. (Wanna find out what routines declare a COMMON block but never use it? That's the -usage flag's whole thing.)
  • labels β€” table lists each label followed by a list of all references to it. A label reference is denoted by the line number and statement type of the referring statement. The label list is in sequential order. The references are listed in the order they are encountered in the program.

See also: -calltree, -reference, -sort, -symtab, -vcg.

  • -declare β€” if this flag is set, all identifiers whose datatype is not declared in each module get listed. Super useful for hunting down misspelled variable names and stuff like that πŸ•΅οΈ The same listing shows up if the module contains an IMPLICIT NONE statement. Default = no.

See also: -sixchar, -usage.

  • -division β€” this switch is here to help you spot potential division-by-zero situations πŸ’€ If it's selected, every division except division by a constant gets flagged. (The assumption is that you're intelligent enough not to divide by a constant that equals zero, bestie 😌) Default = no.

See also: -portability, -truncation.

  • -errors=num β€” sets the max number of error messages in a "cascade". So when ftnchek is checking agreement of subprogram arguments, common block declarations, and so forth, sometimes one single case generates a whole long string of warnings. Usually that just means something else is going on rather than a genuine item-by-item mismatch β€” like, say, a variable missing from one list. So in those cases ftnchek stops printing warnings once the cascade limit is hit, and the trailer etc... gets printed to show there were more errors it didn't print. If you think those warnings are probably genuine, use this setting to see more of them. Turn-on = default = 3, max = 999. A value of 0 means no limit.

Heads up: this setting does not set an overall limit on how many error messages get printed β€” only the number printed in any one cascade. Most types of warnings and error messages aren't subject to the cascade effect, so this setting doesn't touch them. Wanna turn off warnings generally? Use the individual warning control options or the -nocheck option.

See also: -check.

  • -extern β€” makes ftnchek report whether any subprograms invoked by the program are never defined. Normally, if ftnchek is running on a complete program, every subprogram other than the intrinsic functions should be defined somewhere. Turn this switch off if you just wanna check a subset of files that form part of a larger complete program. Subprogram arguments still get checked for correctness either way. Default = yes.

The -extern flag is now superseded by the -usage=ext-undefined option. For convenience's sake, the -extern flag is retained, so -noextern is equivalent to the -usage=no-ext-undefined option. The -extern switch may be retired eventually. πŸ‘‹

See also: -library.

  • -f77=list β€” use this setting to catch language extensions that violate the Fortran 77 Standard. Those extensions can make your program not portable. Examples include using underscores in variable names; variable names longer than six characters; statement lines longer than 72 characters; and nonstandard statements like the DO ... ENDDO structure. ftnchek does not report on the use of lowercase letters. By default, all warnings are turned off.

This setting gives you detailed control over warnings about supported extensions to the Fortran 77 Standard. (More details about the extensions themselves live below in the section on Extensions.) The list is keywords separated by commas or colons. There are three special keywords: all to turn on all the warnings about nonstandard extensions, none to turn them all off, and help to print the list of all the keywords with a brief explanation of each. If list is omitted, -f77 is equivalent to -f77=all, and -nof77 is equivalent to -f77=none. The warning keywords and their meanings are as follows:

  • accept-type β€” ACCEPT and TYPE I/O statements.
  • array-bounds β€” expressions defining array bounds that contain array elements or function references.
  • assignment-stmt β€” assignment statements involving arrays. In Fortran 90, an array can be assigned to another array of compatible shape, or a scalar can be assigned to an array. Neither of these assignments is permitted in Fortran 77.

A related warning happens when an array is assigned to a scalar. Since that's illegal in Fortran 90 too, it's always warned about regardless of the -f77 setting (unless all checking is turned off with the -nocheck flag).

  • attribute-based-decl β€” type declarations in the new Fortran 90 attribute-based style. This style is distinguished by the use of a double colon (::) between the list of attributes and the list of declared variables. This option also controls warnings for use of Fortran 90 length or kind specifiers in type declarations. (Even though those specifiers can be used in non-attribute-based declarations, they're controlled by this option to avoid a proliferation of -f77 options.)
  • automatic-array β€” local (not dummy) arrays that have variable size. These correspond to arrays whose storage would have to be dynamically allocated at run time.
  • backslash β€” Unix backslash escape in strings. This warning is given only if the -source=unix-backslash setting is specified to cause the escape interpretation of backslash.
  • byte β€” BYTE data type declaration.
  • case-construct β€” the SELECT CASE construct.
  • character β€” extensions to the Fortran 77 standard regarding character data. At present this only controls warnings about character variables declared with zero or negative length. In Fortran 77, all character variables must be of positive length. In Fortran 90, they can be zero length, and declarations that specify negative lengths are permitted, turning into zero for the declared length. Note: because negative length specifiers may indicate a programming error, the warning about them is given even if this option is turned off, and is suppressed only by the -nocheck flag. 🚨
  • common-subprog-name β€” common block and subprogram having the same name.
  • construct-name β€” use of a construct-name to label a control statement.
  • continuation β€” more than 19 successive continuation lines.
  • cpp β€” Unix C preprocessor directives in the source code.
  • cray-pointer β€” "Cray pointer" syntax.
  • cycle-exit β€” the CYCLE and EXIT statements.
  • d-comment β€” debugging comments starting with D in the source code.
  • dec-tab β€” DEC Fortran style tab-formatted source code. This warning is given only if the -source=dec-tab setting is specified to cause interpretation of tabs in this style.
  • do-enddo β€” DO loop extensions: terminal statement label omitted, END DO, and WHILE.
  • double-complex β€” double precision complex datatype.
  • format-dollarsign β€” dollar sign control code in FORMAT statements.
  • format-edit-descr β€” nonstandard edit descriptors in FORMAT statements.
  • function-noparen β€” function definition without parentheses.
  • implicit-none β€” IMPLICIT NONE statement.
  • include β€” INCLUDE statement.
  • inline-comment β€” inline comments that kick off with an exclamation point. πŸ’…
  • internal-list-io β€” list-directed I/O going to or coming from an internal file. ✨
  • intrinsic β€” nonstandard intrinsic functions. πŸ¦‹
  • io-keywords β€” nonstandard keywords hanging out inside I/O statements. bestie, these split into three little cliques:

the first group is keywords that Fortran 90 actually accepts:

ACTION    PAD        READWRITE
ADVANCE   POSITION   SIZE
DELIM     READ       WRITE
EOR

the second group is the VMS Fortran squad:

BLOCKSIZE         EXTENDSIZE       READONLY
BUFFERCOUNT       INITIALSIZE      RECORDSIZE
CARRIAGECONTROL   MAXREC           RECORDTYPE
DEFAULTFILE       NAME (in OPEN)   SHARED
DISP              NOSPANBLOCK      TYPE
DISPOSE           ORGANIZATION

and yeah β€” (NAME is standard only in the INQUIRE statement, so don't come for it anywhere else πŸ’€).

the third group is literally one IBM/MVS keyword:

NUM

this flag also runs a warning about the use of ACCESS='APPEND', which some compilers just… accept?? 😭 the value 'APPEND' is not valid for any I/O specifier in standard Fortran 77, and in Fortran 90 you're supposed to use 'APPEND' as a value of the POSITION specifier, not ACCESS. so like, don't do that. periodt.

  • long-line β€” statements with meaningful code past column 72. this warning only shows up if you used the -columns setting to bump the statement field width out. πŸ‘‘
  • long-name β€” identifiers longer than 6 characters. iconic but illegal, fr fr.
  • mixed-common β€” mixed character and noncharacter data chillin' together in a COMMON block. πŸ™ˆ
  • mixed-expr β€” nonstandard type combos in expressions, like DOUBLE PRECISION with COMPLEX, assigning hollerith to an integer, or logical operations on integers. it's giving chaos. πŸ’€
  • name-dollarsign β€” dollar sign used as a character in identifiers.
  • name-underscore β€” underscore used as a character in identifiers.
  • namelist β€” the NAMELIST statement. 🌸
  • param-implicit-type β€” implicit typing of a parameter based on the data type of the value you assigned it. this warning can only happen if implicit parameter typing was turned on by the -source=param-implicit-type option, or if the PARAMETER statement is in that nonstandard form without parentheses. if this option is on, then every single instance of implicit parameter typing gets called out. if you only want to be warned when the implicit data type is different from the default type, use -portability=param-implicit-type instead. ngl the Fortran 77 standard says the data type of a parameter follows the exact same rules as for a variable, and if necessary a type conversion is done when the value gets assigned. ✨
  • param-intrinsic β€” an intrinsic function or exponentiation by a real being used to define the value of a PARAMETER definition.
  • param-noparen β€” PARAMETER statement without parentheses. ⚠️ okay so you need to know that the semantics of this form are different from the standard form: here, the parameter takes its data type from the value assigned, instead of having its default data type based on the first letter of the parameter name. (this form was introduced by DEC before the Fortran 77 standard was even defined, and it should be avoided. like, respectfully, avoid it. 🚩)
  • pointer β€” Fortran 90 standard pointer-related syntax, which includes POINTER, TARGET and ALLOCATABLE type declarations, ALLOCATE, DEALLOCATE and NULLIFY statements, and pointer assignment using =>. πŸ’…
  • quad-constant β€” quad precision real constants, e.g. of the form 1.23Q4. πŸ”₯
  • quotemark β€” strings delimited by quote marks instead of apostrophes. πŸ™ˆ
  • relops β€” relational (comparison) operators made out of punctuation, namely: < <= == /= > >=.
  • semicolon β€” semicolon used as a statement separator.
  • statement-order β€” statements out of the sequence the Standard mandates. the allowed sequence is illustrated in Table 1 in the section on Interpreting the Output. go look, iykyk. πŸ‘‘
  • typeless-constant β€” typeless constants, for example Z'19AF'.
  • type-size β€” type declarations that specify a size, for example REAL*8. πŸ’–
  • variable-format β€” variable repeat specification or field size in FORMAT. these are of the form < expr >.
  • vms-io β€” obsolete, bestie. 🫠 now it means exactly the same thing as the io-keywords keyword.

See also: -f77, -f95, -portability, -pretty, -style, -wordsize.


  • -f90=list β€” this setting gives you detailed control over the warnings about supported extensions to the Fortran 77 Standard that were not adopted as part of the Fortran 90 Standard. quick note: ftnchek does not support the full Fortran 90 language. but it does support some common extensions to Fortran 77 that were already a thing before Fortran 90 got defined. some of those extensions became part of the Fortran 90 Standard, and others did not. the -f90 setting only warns about the ones that didn't. which is to say, this flag covers stuff that is neither legal Fortran 77 nor legal Fortran 90. so basically, the warnings this flag controls are a subset of the warnings controlled by -f77. there are a few cases, described below, where the circumstances in which the warning fires are slightly different between the two flags. 🌈

the list is keywords separated by commas or colons. there are three special keywords: all to turn on every warning about nonstandard extensions, none to turn them all off, and help to print the list of all the keywords with a brief explanation of each. if list is omitted, -f90 is equivalent to -f90=all, and -nof90 is equivalent to -f90=none.

the following keywords have identical meanings for -f90 as they do for -f77. the reader is referred to the explanations under -f77.

accept-type   double-complex        param-noparen
backslash     format-dollarsign     cray-pointer
byte          format-edit-descr     quad-constant
cpp           function-noparen      type-size
d-comment     name-dollarsign       variable-format
dec-tab       param-implicit-type   vms-io

and the keywords that differ somewhat from their corresponding -f77 keyword are as follows. πŸ‘‡

  • continuation β€” the limit on the number of continuation lines for a statement in fixed source form is the same, namely 19, in Fortran 90 as it is in Fortran 77. for free source form the limit is 39 continuation lines, and a line containing a continuation mark cannot be otherwise empty or contain only a comment. ✨
  • intrinsic β€” same as for -f77, except for the intrinsic functions defined in MIL-STD 1753, which are all included in Fortran 90, and so are not warned about. (see -intrinsic for a list.) πŸ¦‹
  • io-keywords β€” same as for -f77, except that no warnings are given for the I/O keywords that are standard in Fortran 90.
  • long-line β€” even though the Fortran 90 Standard allows lines longer than 72 characters in free source form, this restriction still applies to fixed source form. in free source form the line length limit is 132 characters, and unlike fixed form, ftnchek does not allow this limit to be increased. 🚫
  • mixed-expr β€” same as for -f77, except for expressions mixing extended precision real with complex data types, which are permitted in Fortran 90.
  • statement-order β€” similar to the corresponding -f77 warning, but it applies the somewhat looser restrictions on statement order from the Fortran 90 Standard. in particular, Fortran 90 allows DATA statements and statement-function definitions to be intermixed with specification statements. πŸ’…
  • typeless-constant β€” in Fortran 90, binary, octal, and hexadecimal constants of the form B'ddd', O'ddd', and Z'ddd', respectively, are permitted. here 'ddd' represents a string of digits. ftnchek recognizes these forms, as well as a variant of the form X'ddd' for a hexadecimal constant, and other variants in which the base indicator B, O, Z, or X follows the digit string. these variants were not adopted in Fortran 90, so only they get warned about when this flag is turned on. πŸ”₯

See also: -f77, -f95, -portability, -pretty, -style, -wordsize.


  • -f95=list β€” this setting gives you detailed control over warnings about standard Fortran 77 features that were deleted from the Fortran 95 Standard. unlike the -f77 and -f90 settings, these warnings apply to syntax which is legal Fortran 77. but since these features got deleted from the Standard, it's possible that programs containing them will be unacceptable to some newer compilers. 😭 so like… you've been warned, bestie.

Okay so the list is just keywords, and you separate them with commas or colons β€” pick your fighter, bestie πŸ’…

Three of them are extra special though:

  • all β€” turns on every single warning about nonstandard extensions
  • none β€” turns them all off, bye
  • help β€” prints out the whole keyword list with a lil explanation of each one 🫢

And if you just leave list off entirely? Then -f95 is doing the exact same thing as -f95=all, and -nof95 is -f95=none. Simple as that ✨

Here are the warning keywords and what they mean:

  • real-do β€” a DO variable of any real numeric type πŸ‘€
  • pause β€” the PAUSE statement
  • assign β€” the ASSIGN statement, assigned GOTO, or assigned format
  • h-edit β€” the H edit descriptor in a format

Now, there's one other Fortran 77 syntax feature that got deleted in Fortran 95, namely branching to an ENDIF from outside the IF block. BUT β€” and this is the tea β€” ftnchek literally cannot analyze program flow, so it does not warn you about this one. Not its fault, it's just built different 🫠

See also: -f77, -f90, -portability, -pretty, -style, -wordsize.


✨ -help ✨

Prints a list of all the command-line options with a short description of each, plus its default value. This one is functionally identical to the ? argument β€” it's here as a convenience for those systems where the question mark means something special to the command interpreter. Default = no.

The help listing also prints the version number and patch level of ftnchek, plus a copyright notice πŸ‘‘

Note: those "default" values printed in square brackets in the help listing are, strictly speaking, not the built-in defaults. They're the current values β€” after any environment options and any command-line options that came before the -help option have already been processed. Sneaky but true πŸ™ˆ

See also: -novice, -version, and the help option of all settings that take a list of keywords.


✨ -identifier-chars=list ✨

Defines the non-alphanumeric characters that are allowed in identifiers. By default, ftnchek only accepts the dollar sign and underscore as non-alphanumeric characters in identifier names. The characters in list replace whatever set of accepted non-alphanumeric characters was in effect before β€” so if you don't include dollar sign or underscore in the list, they lose their status as acceptable characters. Periodt.

This option exists so ftnchek can handle source files with non-standard identifier names that might be needed, like, to access certain operating system services, for example. Peep the section on Limitations and Extensions for how identifiers containing these characters get treated in implicit typing.

Using -noidentifer-chars turns off acceptance of non-alphanumeric characters entirely. (Yes, that spelling is exactly what's in the original β€” copy it character for character, bestie πŸŽ€)

See also: -source.


✨ -include=path ✨

Specifies a directory to be searched for files named by INCLUDE statements. Unlike other command-line options, this one is cumulative β€” if you give it more than once on the command line, all the directories you specify get placed on a list that'll be searched in the same order you gave them. 🌈

Here's the order ftnchek searches for a file to be included:

  1. the current directory
  2. the directory specified by environment variable FTNCHEK_INCLUDE, if any
  3. the directories specified by any -include options
  4. the directory specified by environment variable INCLUDE
  5. and finally a standard system-wide directory (/usr/include for UNIX, SYS$LIBRARY for VMS, and \include for MSDOS)

See also: -f77, -source.


✨ -intrinsic=list ✨

Controls whether ftnchek recognizes certain nonstandard intrinsic functions as intrinsic. The list is keywords separated by commas or colons. Some keywords control whether to recognize certain groups of functions, and others control the expected syntax for invoking some nonstandard intrinsics. Include a keyword to turn on recognition of the corresponding set of intrinsics or to allow the corresponding syntax. Include a keyword prefixed by no- to turn that recognition off.

Three special keywords here too:

  • all β€” turns on recognition of all the nonstandard intrinsics (listed below) and accepts either syntax for those that have variations
  • none β€” turns off recognition of all nonstandard intrinsics except those noted below
  • help β€” prints the list of all the keywords with a brief explanation of each

If list is omitted, -intrinsic is equivalent to -intrinsic=all, and -nointrinsic is equivalent to -intrinsic=none.

The nonstandard intrinsic functions needed to support the nonstandard extended precision data types (double complex and quad precision) are always recognized. The intrinsics for the double complex data type are:

CDABS   CDSQRT   DREAL   ZLOG
CDCOS   DCMPLX   IMAG    ZSIN
CDEXP   DCONJG   ZABS    ZSQRT
CDLOG   DIMAG    ZEXP    ZCOS
CDSIN

And the intrinsics for the quad precision and quad complex types are:

CQABS    QARCOS   QEXT     QNINT
CQCOS    QARSIN   QEXTD    QPROD
CQEXP    QATAN    QFLOAT   QREAL
CQLOG    QATAN2   QIMAG    QSIGN
CQSIN    QCMPLX   QINT     QSIN
CQSQRT   QCONJG   QLOG     QSINH
DBLEQ    QCOS     QLOG10   QSQRT
IQINT    QCOSH    QMAX1    QTAN
IQNINT   QDIM     QMIN1    QTANH
QABS     QEXP     QMOD     SNGLQ

The keywords controlling recognition of other nonstandard intrinsic functions are as follows:

  • extra β€” recognize the following commonly available nonstandard intrinsics (all except EXIT and LOC are defined in MIL-STD 1753):
BTEST   IBCLR   IEOR    ISHFTC
EXIT    IBITS   IOR     LOC
IAND    IBSET   ISHFT   NOT
  • unix β€” recognize these common Unix-specific intrinsic functions:
ABORT    GMTIME   LTIME    SRAND
AND      IARGC    OR       SYSTEM
GETARG   IRAND    RAND     TIME
GETENV   LSHIFT   RSHIFT   XOR
  • vms β€” recognize these common VMS-specific intrinsic functions:
DATE     IDATE   SECNDS   TIME
ERRSNS   RAN     SIZEOF
  • iargc-no-argument β€” specify that IARGC may be invoked with no arguments
  • iargc-one-argument β€” specify that IARGC may be invoked with one argument
  • rand-no-argument β€” specify that RAND and IRAND may be invoked with no arguments
  • rand-one-argument β€” specify that RAND and IRAND may be invoked with one argument

So here's how the no-argument and one-argument keywords actually work: turning the option on makes ftnchek accept the corresponding syntax for invoking the function, without excluding the possibility of the alternative syntax. Turning it off means that corresponding syntax is not accepted. If both options are on at once (which is the default), then either syntax is accepted. Turning both off at once would not be meaningful. Also, these options have no effect if recognition of Unix intrinsics has been turned off. 🧚

Heads up: this setting does not control whether non-standard warnings get issued about these functions. It controls whether the functions are assumed to be intrinsic or not, which determines how their usage gets checked. When functions in any of these sets are included, their invocations get checked according to the rules for intrinsic functions; otherwise they get checked as normal (user-written) external functions. The non-standard warnings are controlled by the -f77=intrinsic option. iykyk πŸ’…

The default value of this setting is equivalent to -intrinsic=all followed by -intrinsic=no-vms for the Unix version, -intrinsic=no-unix for the VMS version, and -intrinsic=no-unix,no-vms for other versions.

Note: In versions of ftnchek prior to 2.10, the -intrinsic flag took a numeric argument instead of a list of options. For the sake of users who may have written scripts invoking ftnchek this way, the numeric form is still accepted. The numeric form consists of three digits: - The ones digit selects the set of intrinsic functions to be supported. Digit 0 selects only Fortran 77 standard intrinsics plus those needed to support the nonstandard extended precision data types. Digit 1 is equivalent to extra, 2 is equivalent to extra,unix, and 3 is equivalent to extra,vms. - The tens digit controls the syntax of the RAND intrinsic function. - The hundreds digit controls the syntax of the IARGC function. For these digits, specify 0 to require invocation with no argument, 1 to require one argument, and 2 to allow either form.

See also: -f77.


✨ -library ✨

This switch is for when a bunch of subprograms live in one file, but not all of them are actually used by the application. Normally ftnchek warns you if any subprograms are defined but never used β€” this switch suppresses those warnings. Default = no.

It also controls which subprogram calls and COMMON block declarations get checked πŸ‘€

  • If a file is read with the -library flag in effect, the subprogram calls and COMMON declarations inside a routine in that file get checked only if that routine is in the main program's call tree.
  • If the -library switch is turned off, then ftnchek checks the calls of every routine by every other routine, regardless of whether those routines could ever actually be invoked at run time β€” and likewise, all COMMON block declarations get compared for agreement.

Slay πŸ’–

The difference between this switch and the -usage=no-ext-unused option for subprograms? Okay so, bestie, listen: the -usage=no-ext-unused thing only shuts up the warning about routines getting declared but never used. The -library switch goes way further β€” it straight-up excludes unused routines that got processed while it was in effect from all the cross-checking of arguments and COMMON block declarations too. It's giving "you're not part of this family rn." πŸ’…

(And if there's literally no main program anywhere in the set of files ftnchek has read β€” so like, no call tree at all β€” then ftnchek will go hunting for any non-library routines that aren't called by any other routine, and use those as stand-ins for the main program when it builds the call tree and decides what to check. And if it finds no such top-level non-library routines either? Then every inter-module call and every COMMON declaration gets checked. No escape. 😭)

See also: -arguments, -calltree, -common, -extern, -usage.

  • -list β€” bestie this one says: print out a listing of the Fortran program, with line numbers. And when ftnchek catches an error, the error message follows the program line with a caret ( ^ ) pointing at exactly where the error is. Iconic detective energy. πŸ•΅οΈβ€β™€οΈ And even if you didn't ask for a source listing, ftnchek will still print out any line containing an error, so you can figure out where the heck it went wrong. Default = no.

See also: -output, -symtab, -quiet.


🌸 -makedcls 🌸

  • -makedcls=list β€” okay so this one prepares a neatly-formatted file of declarations of variables, common blocks, and namelist lists, so you can merge them into your source code if you want. The declarations get stored in a file with the same name as the source code, but the extension changes to .dcl. And if no declarations got written to the file at all, the file gets deleted, so you're not drowning in a sea of empty files. Clutter? Not on our watch. 🧹✨

And if the input comes from standard input instead of a named file? Then the declarations get written to standard output. Simple as that.

Variables get declared in alphabetical order within each declaration class and type, with integer variables first β€” because of their later possible use in array dimensions. Integer girls stay winning. πŸ‘‘

PARAMETER statements are the exception to the alphabetical-order rule, because the Fortran 77 Standard requires that the expressions defining parameter values refer only to constants and already-defined parameter names. So the original source file order of such statements has to be preserved in the declaration files. Rules are rules. πŸ“œ

Explicit declaration of all variables is considered good modern programming practice. By using compiler options to reject undeclared variables, misspelled variable names (or names extending past column 72) can be caught at compile time. Explicit declarations also greatly facilitate changing floating-point precision with filters such as dtoq(1L), dtos(1L), fd2s(1L), fs2d(1L), qtod(1L), and stod(1L). Those programs are capable of changing types of explicit floating-point type declarations, intrinsic functions, and constants β€” but because they do not carry out rigorous lexical and grammatical analysis of the Fortran source code, they cannot provide modified type declarations for undeclared variables. Default setting = 0, turn-on = 1.

The form of the declarations file is controlled by list, which is just keywords separated by commas or colons. And there are three special keywords: all to turn on every option, none to turn them all off, and help to print the list of all the keywords with a brief explanation of each. So helpful of it. 🫢

If list is omitted, -makedcls is equivalent to -makedcls=declarations (i.e. produce the declarations file using the default options), and -nomakedcls is equivalent to -makedcls=none.

For compatibility with previous versions of ftnchek, a numeric form of this setting is also accepted: the list gets replaced by a number which is the sum of the numbers in parentheses beside the keywords in the following list. The warning keywords with their meanings are as follows:

  • declarations (1): Write a declaration file. (This is implied by any of the other options, and can be omitted if any other options are given.)
  • undeclared-only (2): By default, all variables are included in the declaration file. With this option, include only undeclared variables. This setting is useful if you want to check for undeclared variables, since Fortran source files with all variables properly declared will not result in a .dcl file. With this option, common blocks and namelist lists will not be included in the declaration file, since by their nature they cannot be undeclared. Facts only. πŸ’…
  • compact (4): The declarations are normally prettyprinted to line up neatly in common columns, as in the declaration files output by the Extended PFORT Verifier, pfort(1L). This option value selects instead compact output, without column alignment.
  • use-continuation-lines (8): Causes continuation lines to be used where permissible. The default is to begin a new declaration on each line. This option is appropriate to use together with compact. They're besties fr fr. πŸ«‚
  • keywords-lowercase (16): Output Fortran keywords in lowercase, instead of the default uppercase.
  • vars-and-consts-lowercase (32): Output variables and constants in lowercase, instead of the default uppercase. Character string constants are not affected by this option.
  • exclude-sftran3 (64): Omit declarations of internal integer variables produced by the SFTRAN3 preprocessor, xsf3(1L), as part of the translation of structured Fortran statements to ordinary Fortran. These variables have six-character names of the form NPRddd, NXdddd, N2dddd, and N3dddd, where d is a decimal digit. Because they are invisible in the SFTRAN3 source code, and will change if the SFTRAN3 code is modified, such variables should not be explicitly declared. Instead, they should just assume the default Fortran INTEGER data type based on their initial letter, N. Leave them alone, they're doing great. πŸ™ˆ
  • asterisk-comment (128): Use an asterisk as the comment character; the default is otherwise 'C'.
  • comment-char-lowercase (256): Use 'c' instead of 'C' or '*' as the comment character.
  • suppress-array-dimensions (512): Suppress dimensioning of arrays in the generated declarations. This option is for use with code lacking type declarations, to allow the declaration files to be inserted without change into the code. Since the code will have dimension statements already, dimensioning the array variables in the type statements of the declaration file is redundant. > This option should be used only in conjunction with option 2 = undeclared-only because otherwise any arrays that were dimensioned in a type statement will lose their dimensioning. That's a yikes, bestie. 😭
  • free-form (1024): Produce declarations in free source form. This mode is automatically used if the input source is free form. Use this option to produce declarations in free form even if the input is in fixed form. Free form declarations are indented only 2 columns instead of 6, use the exclamation mark as the comment character, and indicate continuation lines by an ampersand at the end of the line to be continued.

The declaration files contain distinctive comments that mark the start and end of declarations for each program unit, to facilitate using text editor macros for merging the declarations back into the source code. So you can just vibe and merge. πŸ¦‹

The ftnchek distribution includes a program, dcl2inc, which processes declaration files to produce files containing declarations of all COMMON blocks, in a form suitable for use as INCLUDE files. See the dcl2inc(1L) man page for the details of its use.

See also: -mkhtml.


πŸŽ€ -mkhtml πŸŽ€

  • -mkhtml=list β€” produce HTML documentation from source. Creates individual HTML files from ftnchek analysis and code comments. All comments immediately preceding and following the function or subroutine definition are captured to the HTML file. No reformatting of source comments is performed other than stripping of FORTRAN comment characters. In addition, the HTML file lists the local variables declared, common block variables used, functions and subroutines called, I/O unit usage, and other information about each subprogram. Usually you will also want to specify -call=tree to create the root HTML file CallTree.html. (Perhaps this file should be named index.html.) She's giving main character documentation energy, periodt. πŸ‘‘

The form of the HTML files is controlled by list, which is just keywords separated by commas or colons. And again, three special keywords: all to turn on every option, none to turn them all off, and help to print the list of all the keywords with a brief explanation of each.

If list is omitted, -mkhtml is equivalent to -mkhtml=documents (i.e. produce the HTML document files using the default options), and -nomkhtmls is equivalent to -mkhtml=none.

For the sake of simplicity, the options for -mkhtml are the same as those for -makedcls except for those that are inapplicable. Likewise, a numeric form of this setting can be used, formed as the sum of the numbers in parentheses in the list below. The warning keywords with their meanings are as follows:

  • documents (1): Create the HTML documents. (This is implied by any of the other options, and can be omitted if any other options are given.)
  • compact (4): The declarations are normally prettyprinted to line up neatly in common columns. This option value selects instead compact output, without column alignment.
  • use-continuation-lines (8) β€” makes the generator use continuation lines instead of starting a fresh declaration on every single line. Bestie, this one loves to be paired with compact 🫢
  • keywords-lowercase (16) β€” spits out Fortran keywords in lowercase instead of the default uppercase ✨
  • vars-and-consts-lowercase (32) β€” outputs variables and constants in lowercase instead of the default uppercase. Heads up tho: character string constants are not touched by this option, they stay exactly as they are πŸ’…
  • exclude-sftran3 (64) β€” skips declarations of the internal integer variables that the SFTRAN3 preprocessor, xsf3(1L), makes. (peep -makedcls for the whole discussion on this one)
  • suppress-array-dimensions (512) β€” suppresses dimensioning of arrays in the declarations it generates. This is normally not the move, but it's there in case you for some reason don't want array dimensions showing up in the HTML πŸ™ˆ
  • free-form (1024) β€” produces variable declarations in free source form. This mode kicks in automatically if the input source is free form. Mostly it's about the shape of the continuation lines, if continuation lines are even used 🌸

See also: -calltree, -makedcls.


-novice

Okay so this flag exists to give beginners more helpful output πŸ’– It does two things:

  • (a) it adds an extra message saying that a function which is used but never defined anywhere might actually be an array that the user forgot to declare in a DIMENSION statement β€” because the syntax of an array reference is literally the same as a function reference, so yeah, easy to get twisted 😭
  • (b) it changes the form of the error messages and warnings. If you turn it off with -nonovice, those messages get printed in a style that looks way more like UNIX lint.

Default = yes.

-output=filename

This setting is pure convenience for systems that don't let you easily redirect program output πŸŽ€ When you give it, the output that would normally hit your screen gets sent to the named file instead. BUT β€” and this is important β€” operational errors of ftnchek itself (like out of space, or cannot open file) will still go to the screen, no cap.

The extension on filename is optional, and if you don't give one, the extension .lis gets used ✨

-pointersize=num

Sets the size of a "Cray pointer" variable to num bytes. Default = turn-on = 4 bytes.

The pointer size is what feeds the precision mismatch warnings that involve pointer variables β€” think a pointer being assigned a value from an allocation routine, or passed as a subprogram parameter πŸ‘‘

See also: -f77, -portability, -truncation, -wordsize.

-portability=list

ftnchek will hand you warnings for all kinds of non-portable usages. Examples include: tabs used anywhere except in comments or inside strings, Hollerith constants, and equivalencing variables of different data types 🌈

Quick note tho: this option does not warn about supported extensions to the Fortran 77 Standard, even though those can cause portability problems too. To catch those, use the -f77 setting instead. By default, all warnings are turned off.

This setting is your detailed control panel for the warnings about possible portability problems. The list is keywords separated by commas or colons. Three special keywords exist: all to turn on all the warnings about nonportable usages, none to turn them all off, and help to print the list of all the keywords with a brief explanation of each. If you just leave list off, -portability equals -portability=all, and -noportability equals -portability=none πŸ’«

The warning keywords and what they mean:

  • backslash β€” Backslash character in strings. Some compilers treat the backslash as an escape character, so its presence can cause problems even when it's used in a standard-conforming way.
  • common-alignment β€” COMMON block variables that are not in descending order of storage size. Some compilers require this ordering because of storage alignment requirements.
  • hollerith β€” Hollerith constants (other than within FORMAT specifications). The Hollerith data type is a Fortran IV feature that got deleted in the Fortran 77 standard πŸ’€ It's superseded by the character data type. And storing Hollerith data in variables of a numeric or logical data type is nonportable, because word sizes differ.
  • long-string β€” String constants, variables, or expressions over 255 chars long.
  • mixed-equivalence β€” Variables of different data types equivalenced.
  • mixed-size β€” Variables declared with default precision used with variables given explicit precision, in expressions, assignments, or as arguments. For example, if a variable declared as REAL*8 is treated as equivalent to DOUBLE PRECISION.
  • real-do β€” Non-integer DO loop index and bounds. These can make a program's results depend on the hardware characteristics of whatever computer it's running on 😬
  • param-implicit-type β€” Implicit typing of a parameter by the data type of the value assigned, if that differs from the default type. This warning can only happen if implicit parameter typing has been turned on by the -source=param-implicit-type option, or if the PARAMETER statement is in the nonstandard form without parentheses. If this option is on, then any instances where implicit parameter typing occurs and where the implicit type differs from the default type based on the first letter of the parameter name will get warned about. Implicit parameter typing can change the semantics of statements where the parameter is used, which causes portability problems.
  • tab β€” Tabs in source code. Tabs get interpreted differently by different compilers. This warning is given only once, at the end of the file.

See also: -f77, -f90, -f95, -pretty, -style, -wordsize.

-pretty=list

Controls certain messages related to how the source code looks πŸŽ€ These warn about stuff that might make a program less readable or that could be deceptive to the reader. By default, all warnings are turned on.

This setting gives you detailed control over the appearance warnings. The list is keywords separated by commas or colons. Since everything's on by default, you include a keyword prefixed by no- to turn off a particular warning. Three special keywords: all to turn on all the warnings about misleading appearances, none to turn them all off, and help to print the list of all the keywords with a brief explanation of each. If list is omitted, -pretty equals -pretty=all, and -nopretty equals -pretty=none ✨

The warning keywords and their meanings:

  • alternate-return β€” A RETURN statement has a constant specifying an alternate return point that is not between 0 and the number of dummy arguments that are labels. This is legal, and has the same effect as a RETURN with no alternate return expression β€” but it suggests the programmer meant to use an alternate return label that isn't provided πŸ™ˆ
  • embedded-space β€” Space embedded in variable names, or in multi-character operators such as **.
  • continuation β€” Continuation mark following a comment line.
  • long-line β€” Lines (except comments) over 72 columns in width (anything beyond 72 is normally ignored by the compiler).
  • missing-space β€” Lack of space between a variable and a preceding keyword.
  • multiple-common β€” COMMON block declared in multiple statements. No warning is given if the statements are consecutive except for comment lines.
  • multiple-namelist β€” NAMELIST declared in multiple statements. No warning is given if the statements are consecutive except for comment lines.
  • parentheses β€” Parentheses around a variable by itself. As a subprogram argument, this makes the argument an expression, so it's not modifiable by the subprogram πŸ‘‘
Note that in free source form, extra space and missing space are forbidden by the Fortran 90 Standard β€” they're not mere style violations. In that case the warnings get replaced by syntax error messages, and can be turned off only by using -nocheck 🚨

See also: -f77, -portability, -style.

-project=list

ftnchek will create a project file from each source file that's input while this option is turned on πŸ’– The project file gets the same name as the input file, but with the extension .f or .for replaced by .prj. (If the input comes from standard input, the project file is named ftnchek.prj.) Default = none.

The list is keywords separated by commas or colons. Three special keywords: all to turn on all the options, none to turn them all off, and help to print the list of all the keywords with a brief explanation of each. If list is omitted, -project equals -project=all, and -noproject equals -project=none 🌟

The keywords and their meanings:

  • create β€” Produce a project file. The default is not to produce a project file. If this option isn't turned on, the other options have no effect 🫢
  • trim-calls β€” this one trims down how much info about subprogram declarations and calls gets stashed in the project file βœ‚οΈ. It's the default, bestie. Only turn it off in rare situations (there's a whole discussion below, we'll get there). How much actually gets trimmed depends on the -library flag β€” turn that flag on and more stuff gets trimmed.
  • trim-common β€” trims the number of common block declarations saved in the project file. Also the default, also only turn it off in rare situations (yes, discussion below πŸ‘‡). And heads up: this option does absolutely nothing if -library is off β€” when you're not in library mode, no trimming of common block declarations happens at all, no matter what you set this to.

Okay so let's talk project files, because they're kinda the main character here πŸ’…

A project file holds a summary of the info from a source file, and it's used for checking that FUNCTION, SUBROUTINE, and COMMON usages agree across your other files. It's what makes incremental checking possible, which saves you soooo much time when you've got a big pile of files with shared subroutines and most of them basically never change πŸ¦‹

Here's the vibe:

  1. Run ftnchek once on each file with the -project flag set β€” boom, project files created ✨. Usually you'd also set -library and -noextern at this point, so messages about consistency with other files get suppressed. At this stage only the error messages that are about each file by itself get printed.
  2. After that, run ftnchek without those flags, on all the project files together, to check consistency between the different files. Now all the messages internal to the individual files get omitted.
  3. Only when a file changes do you need to make a fresh project file for it πŸ”

Naturally β€” and this is important β€” when -project is turned on, ftnchek will not read project files as input. Nope. Not happening.

Ordinarily, the trim options should be left ON when you're making project files that'll be fed back into ftnchek later. Since trimming is on by default, that means just giving the command -project with no option list is the recommended mode, periodt. The trim options exist purely as a lil convenience for people who wanna use project files for something other than checking their program with ftnchek. For the intended purpose? Leave the trim options alone, don't turn them off πŸ™ˆ

Also: project files only contain info needed for checking agreement between files. Which means a project file is completely useless if every module of your complete program lives in a single file πŸ’€

There's a more detailed discussion in the section on Using Project Files, if you want the full tea.


  • -pure β€” assume functions are "pure", i.e. they will not have side effects by modifying their arguments or variables in a COMMON block 🧚. When this flag is on, ftnchek figures out the set/used status of the actual arguments based on the assumption that arguments passed to a function don't get altered. It'll also throw a warning if a function does turn out to modify any of its arguments or any COMMON variables. Default = yes.

When you turn this flag off, actual arguments passed to functions get handled the exact same way as actual arguments passed to subroutines β€” meaning ftnchek assumes arguments can be modified by the functions. No warnings get issued if a function turns out to have side effects. And since stricter checking is possible when functions are assumed pure, you should only turn this off if your program actually uses functions with side effects, bestie 🫢

  • -quiet β€” cuts down the output relating to normal operation so the error messages pop out more. This one's for the girlies checking huge suites of files 😭. What gets eliminated: the names of project files, and the message saying no syntax errors were found. It also kills some blank lines that are normally there for clarity. (Some of that output gets turned back on by the -list and -symtab options, fyi.) Default = no.
Note: the way to remember the difference between -quiet and -brief is that -quiet doesn't suppress any warning-related information, whereas -brief does. That's the whole trick πŸ’‘

See also: -brief.

  • -reference β€” says you want a who-calls-who table printed πŸ•΅οΈ. This table lists each subprogram followed by a list of the routines it calls. This switch is equivalent to -calltree=reference. Default = no.

The reference list omits routines called by unused library modules. So it's got the same info as the call-tree format β€” namely the hierarchy of subprogram calls β€” just printed a different way. This prints a breadth-first traversal of the call tree, whereas -calltree=tree prints a depth-first traversal.

See also: -calltree, -crossref, -library, -sort, -symtab, -vcg.

  • -resources β€” prints how many resources ftnchek used while processing the program πŸ“Š. This listing is lowkey useful for analyzing the size and complexity of a program, and it can also help you pick bigger sizes for ftnchek's internal tables if they're too small to analyze a particular program. Default = no.

In this listing, the term chunk size means the size of the blocks of memory allocated to store the item in question, in units of the size of one item β€” not necessarily in bytes. When the initially allocated space fills up, more memory gets allocated in chunks of this size. Here's the breakdown of every item that gets printed:

  • Source lines processed: β€” total number of lines of code, with separate totals for statement lines and comment lines. Comment lines include lines with 'C' or '*' in column 1, plus blank lines and lines containing only an inline comment. Statement lines are all other lines, including lines that have an inline comment following some code. Continuation lines are counted as separate lines. Lines in include files are counted each time the file is included.
  • Total executable statements: β€” number of statements in the program, other than specification, data, statement-function, FORMAT, ENTRY, and END statements.
  • Total number of modules: β€” a module is any external subprogram, including the main program, subroutines, functions, and block data units. This count is of modules defined within the source, not modules referenced. Statement functions are not included. A subprogram with multiple entry points only gets counted once.
  • Total statement labels defined β€” number of labels attached to statements (often called statement numbers). You get the total label count for the entire program, plus the maximum number in any single subprogram.
  • Max identifier name chars: β€” number of characters used for storing identifier names. An identifier is a variable, subprogram, or common block name. Local names are those of local variables in a subprogram, whereas global names refer to subprogram and common block names, as well as dummy argument names and common variable names. Actual argument text (up to 15 characters for each argument) is also included here. The space used for local names is not recovered at the end of each module, so this number, like global space, just grows until the whole program is analyzed 😭. Unfortunately, this figure may include some text stored more than once, although a heuristic is used that avoids duplicates in many cases.
  • Max token text chars: β€” a token is the smallest syntactic unit of the FORTRAN language above the level of individual characters. For instance a token can be a variable name, a numerical constant, a quoted text string, or a punctuation character. Token text is stored while a module is being processed. For technical reasons, single-character tokens are not included in this total. Items that aren't represented in the symbol table may be duplicated. The space for token text is recovered at the end of each module, so this figure represents the maximum for any one module.
  • Max local symbols: β€” the largest number of entries in the local symbol table for any module. Local symbol table entries include all variables and parameters, common block names, statement functions, external subprograms and intrinsic functions referenced by the module. Literal constants are not stored in the local symbol table.
  • Max global symbols: β€” the number of entries in the global symbol table at the end of processing. Global symbol table entries include external subprogram and common block names. Intrinsic functions and statement functions are not included.
  • Max number of tokenlists: β€” a token list is a sequence of tokens representing the actual or dummy argument list of a subprogram, or the list of variables in a common block or namelist. So this number represents the largest sum of COMMON, CALL, NAMELIST and ENTRY statements and function invocations for any one module. The space is recovered at the end of each module.
  • Max token list/tree space β€” the biggest number of tokens across all the token lists AND token trees of any single module. Bestie, a token tree is what happens when an expression gets analyzed: every operand is a leaf πŸ“, and the operators are the nodes. So this number = how complex your most extra module is. A module with a million long arithmetic expressions? Sky-high number. And lowkey important: unlike the token text we talked about up there, this count doesn't care how long your variable names or literal constants are. A token is a token, periodt.
  • Number of subprogram invocations β€” the sum over all modules of the number of CALL statements and function invocations. (Intrinsic functions and statement functions do NOT count, okay? They're exempt πŸ’…)
  • Number of common block decls β€” the sum over all modules of the number of common block declarations. Like, each declaration of a block in a different module counts separately. (The standard does allow multiple declarations of a block inside the same module β€” those count as just ONE declaration, because they're equivalent to a single long declaration. Slay, standardization.)
  • Number of array dim & param ptrs β€” the sum over all modules of the number of array dimension and parameter definition text strings saved so the -makedcls option can use them. The length of those text strings is not counted, bestie, just the count. And every dimension of a multidimensional array is counted separately. Iconic.

These numbers are obviously not the same when project files are used instead of the original source code. And ngl, even the numbers for global entities can be different, because some redundant info gets eliminated in project files. πŸ€·β€β™€οΈ


-sixchar πŸŽ€

Okay so one of the whole goals of ftnchek is helping you write portable Fortran programs. And one sneaky source of nonportability is variable names longer than six characters. Some compilers just straight up ignore the extra characters. 😭 Which means two different variables could get treated as the SAME variable. For instance, variables named AVERAGECOST and AVERAGEPRICE are identical in their first six characters. If you want to catch these potential conflicts, use this flag. Default = no.

Use the -f77=long-names if you want to list all variables longer than six characters, not just those pairs that match in the first six.

See also: -f77, -portability.


-sort πŸ¦‹

Specifies that a sorted list of all modules used in the program gets printed. This list is in "prerequisite" order β€” meaning each module is printed only after all the modules from which it's called have been printed. That's also called a "topological sort" of the call tree. Each module gets listed only once. Routines that aren't in the call tree of the main program are omitted. And if there are any cycles in the call graph (which is, btw, illegal in standard Fortran) they'll be detected and diagnosed. Default = no.

See also: -calltree, -crossref, -reference, -symtab, -vcg.


-source=list ✨

This setting controls certain options about the form of the Fortran source code. The list is keywords separated by commas or colons. There are three special keywords, bestie, memorize these: all turns on all the options, none turns them all off, and help prints the list of all the keywords with a brief explanation of each. If list is omitted, -source is equivalent to -source=all, and -nosource is equivalent to -source=none.

For compatibility with previous versions of ftnchek, a numeric form of this setting is also accepted: the list gets replaced by a number which is the sum of the numbers in parentheses beside the keywords in the following list. (The fixed and free options do not have numeric values.) The warning keywords and their meanings are as follows:

fixed

Interpret the source as fixed form (with supported extensions such as exclamation mark for comments). Statements must be in columns 7 to 72 (unless the -cols setting has been used to change this), and blanks are not significant outside character context (but they get warned about under the -pretty option). This is the default mode unless the source file extension is .f90 or .F90. this option cannot be given together with -source=free.

free

Interpret the source as free form. Statements may be anywhere in columns 1 to 132, comments can only begin with an exclamation mark, and blanks are required in some places, like between identifiers and keywords. This is the default mode if the source file extension is .f90 or .F90. This option cannot be given together with -source=fixed or -source=dec-tab.

dec-tab (1)

Accept DEC-style tab-formatted source. A line beginning with an initial tab will be treated as a new statement line β€” unless the character after the tab is a nonzero digit, in which case it's treated as a continuation line. The next column after the tab or continuation mark is taken as column 7. A warning will be given in the case where the line is a continuation, if -f77=dec-tab is in effect.

vms-include (2)

Accept VMS-style INCLUDE statements. These follow the normal syntax, but with these extra features: (1) the file extension, if not given, defaults to the same as a normal source file extension; and (2) the option /LIST or /NOLIST can be appended to the include-file name, to control listing of its contents.

unix-backslash (4)

Handle UNIX-style backslash escapes in character strings. The escape sequence following the backslash gets evaluated according to the ANSI standard for strings in C: up to three digits signify an octal value, an x signifies the start of a hexadecimal constant, any of the letters a b f n r t signify special control codes, and any other character (including newline) signifies the character itself. When this source code option is in effect, a warning will be given if the -f77=backslash setting is specified.

The default behavior is to treat the backslash like any other normal character, but a warning about portability will be generated if the -portability flag is set. Because of the fact that some compilers treat the backslash in a nonstandard way, it is possible for standard-conforming programs to be non-portable if they use the backslash character in strings. πŸ™ˆ

Since ftnchek does not do much with the interpreted string, it's seldom necessary to use this option. It's needed in order to avoid spurious warnings only if (a) the program being checked uses backslash to embed an apostrophe or quote mark in a string instead of using the standard mechanism of doubling the delimiter; (b) the backslash is used to escape the end-of-line in order to continue a string across multiple source lines; or (c) a PARAMETER definition uses an intrinsic string function such as LEN with such a string as argument, and that value is later used to define array dimensions, etc.

param-implicit-type (8)

Implicit typing of a parameter by the data type of the value assigned. Some non-standard compilers may allow the data type of the value to override the Fortran 77 default type of a parameter that's based on the first letter of the parameter name. This option only applies to PARAMETER statements of the standard form which has parentheses. A parameter that has been explicitly declared in a type statement prior to the PARAMETER statement is not affected by this option. A warning will be given under the -f77=param-implicit-type or -portability=param-implicit-type option.

Note that this implicit typing is treated as equivalent to an explicit type declaration for the parameter. Therefore, if you use -makedcls=undeclared-only to generate declarations only of undeclared variables, these parameters will not be included. πŸ‘‘

dec-param-standard-type (16)

Follow the Fortran 77 rule for data typing of DEC Fortran style parameters. These are declared using a nonstandard form of the PARAMETER statement which lacks parentheses. According to DEC Fortran, parameters defined by this form of the statement have their data type given by the data type of the value assigned. Use this option to tell ftnchek not to follow this rule but instead to use the same rule as for standard PARAMETER statements. This option does not apply to PARAMETER statements of the standard form.

By default, all these source code options are turned off, except for the vms-include option, which is on by default in the VMS version..

See also: -f77, -include, -portability.


-style=list πŸ’…

Provides extra-picky warnings about obsolescent or old-fashioned programming constructions. This option is helpful for efforts to follow a modern programming style. (Most of the things complained about under this option are forbidden in the F subset language.) By default, all warnings are turned off.

The list is literally just keywords, bestie β€” separate them with commas or colons, whatever vibes. ✨

And there are three special keywords:

  • all β€” turns every single option on
  • none β€” turns them all off
  • help β€” prints the whole list of keywords plus a lil' brief explanation of each one 🫢

If you just... don't give a list at all? Then -style = -style=all, and -nostyle = -style=none. Easy.

Here's the warning keywords and what they're actually saying:

  • block-if β€” complains about the arithmetic IF statement. It's fine with block IF or logical IF (those control a single statement).
  • construct-name β€” complains when block constructs are unnamed: IF, DO, and SELECT CASE. ⚠️ Note this: if a construct name is there on the opening statement of a construct, then it's required on all the other component statements (ELSE, END IF, etc.) of that construct. In that case a missing construct name on those statements is a syntax error no matter what this option says. So this option's whole job is just warning you if the construct has no name at all.
  • distinct-do β€” complains if two DO loops are sharing a common terminator statement. Rude of them.
  • do-construct β€” complains if a DO loop's terminator is anything other than an END DO or CONTINUE statement. That's the requirement for the loop to count as a do-construct under the Fortran 90 definition, iykyk.
  • do-enddo β€” complains if a DO loop's terminator is anything other than an END DO statement. (This one overrides the do-construct option, since it's even stricter. πŸ’…)
  • end-name β€” complains when the subprogram name is missing from structured END statements.
  • format-stmt β€” complains about FORMAT statements existing at all. Only the FORMAT statements themselves get flagged, not the references to them in I/O lists.
  • goto β€” complains about unconditional, computed, or assigned GOTO statements. Also complains about alternate returns (but not about labels as subprogram arguments).
  • labeled-stmt β€” complains about labels (numbers) on statements that aren't FORMAT statements. (FORMAT statements are arguably convenient and not readily abused, so complaints about those are controlled by the separate format-stmt keyword instead.)
  • program-stmt β€” complains when there's no PROGRAM statement at the head of the main program.
  • structured-end β€” complains when you use a plain END statement to end a subprogram instead of a structured END statement (END PROGRAM, END SUBROUTINE, END FUNCTION, or END BLOCK DATA).

See also: -f77, -f90, -f95, -pretty, -portability.


πŸ¦‹ -symtab

A symbol table gets printed out for each module, listing every identifier mentioned in the module. This table gives you the name of each variable, its datatype, and the number of dimensions for arrays. An asterisk (*) means the variable was implicitly typed rather than named in an explicit type declaration statement. πŸ‘€ The table also lists all subprograms invoked by the module, all COMMON blocks declared, etc. Default = no.

Also, for each module, a label table gets printed. It lists each label defined in the module, the line where that statement label is defined, and the statement type (executable, format, or specification). Labels are listed in sequential order. ✨

Also printed: a table describing the I/O units used by the module, plus info about how they're used β€” what operations are performed, whether the access is sequential or direct, and whether the I/O is formatted or unformatted. So much tea. β˜•

See also: -calltree, -crossref, -list, -reference, -sort, -vcg.


πŸ’€ -truncation=list

Warns about possible truncation (or roundoff) errors. Most of these are tied to integer arithmetic. By default, all warnings are turned on.

This setting gives you detailed control over the warnings about possible truncation errors. The list is keywords separated by commas or colons. Since all warnings are on by default, include a keyword prefixed with no- to turn a particular warning off. Three special keywords again: all turns on all the truncation warnings, none turns them all off, and help prints the list of all keywords with a brief explanation of each. 🫢 If the list is omitted, -truncation = -truncation=all, and -notruncation = -truncation=none.

The warning keywords and their meanings:

  • int-div-exponent β€” using the result of integer division as an exponent. This suggests a real quotient was intended. Example: writing X**(1/3) to evaluate the cube root of X. The correct expression is X**(1./3.). πŸ™ˆ
  • int-div-real β€” converting an expression involving an integer division to real. This suggests a real quotient was intended.
  • int-div-zero β€” division in an integer constant expression that yields a result of zero. πŸ’€
  • int-neg-power β€” exponentiating an integer by a negative integer (which yields zero unless the base integer is 1 in magnitude). This suggests a real base was intended.
  • promotion β€” automatic conversion of a lower precision quantity to one of higher precision. The loss of accuracy for real variables in this process is comparable to the corresponding demotion. No warning is given for promotion of integer quantities to real, since that's ordinarily exact.
  • real-do-index β€” using a non-integer DO index in a loop with integer bounds. An integer DO index with real bounds is always warned about regardless of this setting, no cap.
  • real-subscript β€” using a non-integer array subscript.
  • significant-figures β€” overspecifying a single precision constant. This may mean a double precision constant was intended.
  • size-demotion β€” automatic conversion of a higher precision quantity to one of lower precision of the same type. This warning only happens when an explicit size is used in declaring the type of one or both operands in an assignment. For example, a warning will be issued where a REAL*8 variable is assigned to a REAL variable, if the default wordsize of 4 is in effect. A warning is also issued if a long integer is assigned to a shorter one β€” for example, if an INTEGER expression is assigned to an INTEGER*2 variable. There's one exception to that last case, namely if the right hand side of the assignment is a small literal constant (less than 128).
  • type-demotion β€” automatic conversion of a higher precision quantity to one of lower precision of different type. This warning includes conversion of real quantities to integer, double precision to single precision real, and assignment of a longer character string to a shorter one.

The warnings about promotion and demotion also apply to complex constants, considering the precision to be that of the real or imaginary part. Warnings about promotions and demotions are given only when the conversion is done automatically β€” e.g. in expressions of mixed precision or in an assignment statement. If intrinsic functions such as INT are used to do the conversion, no warning is given. πŸ’…

See also: -portability, -wordsize.


🌈 -usage=list

Warns about unused or possible uninitialized variables, unused common blocks, undefined or unused statement labels, and unused or undefined subprograms. By default, all warnings are turned on.

This setting gives detailed control over the warnings about possible usage errors. The list is keywords separated by commas or colons. Since all warnings are on by default, throw a no- prefix on a keyword to turn a particular warning off. Three special keywords: all turns on all the usage warnings, none turns them all off, and help prints the list of all keywords with a brief explanation of each. If the list is omitted, -usage = -usage=all, and -nousage = -usage=none. ✨

These warnings cover four main categories of objects: subprogram dummy arguments, common blocks and variables, subprograms and functions, and local variables. Warnings include undefined items, multiply defined items, unused items, etc. Here's the keywords and what they mean:

  • arg-alias β€” a scalar dummy argument is actually the same as another one and is (or may be) modified. The Fortran 77 standard (section 15.9.3.6) prohibits modifying an argument that is aliased to another. Periodt.
  • arg-array-alias β€” a dummy argument that's an array or array element is in the same array as another one and gets modified. This flag is similar to arg-alias but gives you separate control over array arguments. It's harder to tell if aliasing is happening with arrays, so if ftnchek gives you too many false warnings, this flag lets you turn off the array-related ones without suppressing the warnings for scalars. πŸŽ€
  • arg-common-alias β€” a scalar dummy argument is literally the same thing as a common variable in that subprogram, and one of them gets modified. Fortran 77 says no πŸ’€. And if common checking isn't exact (peep the -common setting), it's lowkey harder to tell if aliasing is even happening, so ftnchek just throws the warning if the variable is anywhere in a common block declared by the subprogram.
    • arg-common-array-alias β€” a dummy argument that's an array or an array element lives in the same array as a common variable, and one of them gets modified. If common checking isn't exact, the variable can be anywhere in a common block declared by the subprogram.
    • arg-const-modified β€” a subprogram modifies an argument that's a constant or an expression. Yeah, that could make your program behave in anomalous ways. Not the vibe. πŸ™ˆ
    • arg-unused β€” a dummy argument is declared but never used. It's giving var-unused (that one's below πŸ‘‡) but it only applies to arguments.
    • com-block-unused β€” a common block is declared but literally none of the variables in it are used by any subprogram. This warning gets suppressed if the common strictness setting is 0.
    • com-block-volatile β€” a common block may lose the definition of its contents if common blocks are volatile. This one only does anything if the -common=volatile flag is in effect. Go read the -common discussion above bestie.
    • com-var-set-unused β€” a common variable gets assigned a value, but no subprogram ever uses that value. Suppressed if the common strictness setting is 0.
    • com-var-uninitialized β€” a common variable's value is used in some subprogram, but it's not set anywhere. Sadly ftnchek does not do a thorough enough analysis of the calling sequence to know which routines get called before others, so warnings for this type of error only show up for cases where a variable is used in some routine but not set in any other routine. Individual COMMON variable checking only happens if the -common setting is 3 (variable by variable agreement). Suppressed if the common strictness setting is 0.
    • com-var-unused β€” a common variable is declared but not used by any subprogram. Suppressed if the common strictness setting is 0.
    • do-index-modified β€” a variable that's the index of a DO loop gets modified by some statement inside the range of the loop. The Standard permits an active DO variable to be modified only by the incrementation mechanism of the DO statement. That's the whole point of the incrementation mechanism, bestie. 😀
    • ext-multiply-defined β€” an external (a subroutine or function) is defined more than once. Defining an external means providing the body of its source code.
    • ext-declared-only β€” a name is declared in an EXTERNAL statement in some module, but it's not defined or used anywhere.
    • ext-undefined β€” an external is used (invoked) but not defined anywhere. This option is equivalent to the -external flag. If the subprogram is invoked more than once, those invocations still get checked for consistency.
    • ext-unused β€” an external is defined (its subprogram body is present) but it's not used. A subprogram counts as unused even if it's invoked by some other subprogram, if it can't be called from any thread of execution starting with the main program. The agreement of the subprogram's arguments with its invocations is still checked even if this warning is turned off. If there's no main program, then this warning is issued only if the subprogram isn't invoked anywhere. This warning is suppressed in library mode, but library mode has the extra effect of suppressing argument checking for unused routines.
    • label-undefined β€” a statement refers to a label that has not been defined. 🚩
    • label-unused β€” a statement label is defined, but never referred to.
    • var-set-unused β€” a local variable is assigned a value, but that value is not used.
    • var-uninitialized β€” a local variable's value may be used before it's assigned. Sometimes ftnchek makes a mistake in the warnings about local variable usage. Usually it errs on the side of giving a warning where no problem exists, but in rare cases it may fail to warn where the problem does exist. Peep the section on Bugs for examples. If variables are equivalenced, the rule ftnchek uses is that a reference to any variable implies the same reference to all variables it's equivalenced to. For arrays, the rule is that a reference to any array element is treated as a reference to all elements of the array.
    • var-unused β€” a local variable is declared (for instance, in a type declaration) but is not used in the module. Does not apply to dummy arguments: warnings about those are controlled by the keyword arg-unused described above.
Note: In versions of ftnchek prior to 2.10, the -usage flag took a numeric argument instead of a list of options. For the sake of users who may have written scripts invoking ftnchek in this way, the numeric form is still accepted. The numeric setting is composed of three digits. The first digit (hundreds place) controls warnings about subprograms (functions and subroutines), the second digit (tens place) warnings about common blocks and common variables, and the third digit (ones place) warnings about local variables. Each digit controls warnings according to the convention that a 1 means warn about undefined items and variables that are used before set, a 2 means warn about items that are unused, and a 3 means warn about both types. These numbers are now converted to the appropriate values for the above-listed keywords, except for com-block-volatile, which is not affected by the numeric argument.

See also: -common, -declare, -extern, -library.


πŸ’… -vcg

Produce the call graph in the form of a VCG graph description. This description is written to a separate file, with the same stem as the file containing the main program, and suffix .vcg. This file is able to be given directly to xvcg(1L) to visualize the call graph. (If input is from the standard input, then the graph description is sent to standard output.) This switch is equivalent to -calltree=vcg. Default = no.

The VCG description as created is more complex than it need be. VCG allows graphs and nested subgraphs: each subroutine is created as a subgraph nested inside its calling routines. This lets you interactively display subgraphs or summarise them. Obsessed actually. ✨

The -vcg option for ftnchek was written by Dr. Philip Rubini of Cranfield University, UK.

xvcg is a graph visualisation tool which runs under the X windows system. It is freely available from ftp.cs.uni-sb.de. It was written by G. Sander of the University of Saarland, Germany.

See also: -calltree, -crossref, -reference, -sort.


πŸŽ€ -version

This option causes ftnchek to print a line giving the version number, release date, and patch level of the program. If no files are given, it then exits. If files are given, the effect of this option is to include the patch level (normally omitted) in the version information printed at the start of processing. Default = no.

See also: -help.


🌸 -volatile

Assume that COMMON blocks are volatile. Default = no.

This flag is superseded by -common=volatile, and should no longer be used. It may be eliminated in a future release of ftnchek. πŸ‘‹

See also: -common, -usage.


πŸ¦‹ -wordsize=num

Specifies the default word size to be num bytes. This is the size of logical and single-precision numeric variables that are not given explicit precisions. (Explicit precisions for non-character variables are an extension to the Fortran 77 Standard, and are given by type declarations such as REAL*8 X.) Double-precision and complex variables will be twice this value, and double complex variables four times. Quad-precision constants and intrinsic function results will be four times this value. Note that variables declared as REAL*16 will be regarded as quad precision only if the word size is 4 bytes. Default = turn-on = 4 bytes.

The word size value does not matter for checking standard-conforming programs that do not declare explicit precisions for non-character variables or store Hollerith data in variables. This setting also does not affect the default size of character variables, which is always 1 byte. Hollerith constants also are assumed to occupy 1 byte per character.

So like, the word size? It's used to determine whether truncation occurs in assignment statements, and to catch precision mismatches in subprogram argument lists and common block lists. ✨

The exact warnings that are issued will depend on the status of other flags. Lowkey, it's all connected. πŸ’…

Under both the -portability=mixed-size and the -nowordsize flag, any mixing of explicit with default precision objects (character expressions not included) is warned about. Not the character expressions though, they're exempt. πŸ’–

This applies to arithmetic expressions containing both types of objects, and to subprogram arguments and COMMON variables.

Under control of the -truncation=demotion and promotion options, a warning is given for assignment of an expression to a shorter variable of the same type, or for promotion of a lower precision value to higher precision in an arithmetic expression or an assignment statement.

Giving a word size of 0, or equivalently, using -nowordsize means that no default value will be assumed. This is equivalent to specifying -portability=mixed-size. Use it to find cases of mixing default and explicit precision, for example to flag places where REAL*8 is treated as equivalent to DOUBLE PRECISION. 🫢

See also: -pointersize, -portability, -truncation.
  • -wrap=col β€” Controls the wrapping of error messages. Long error messages that would run past the specified column will be broken up into separate lines between the words of the message for better readability. If turned off with -nowrap, each separate error message will be printed on one line, leaving it up to the display to wrap the message or truncate it. Default = turn-on = 79.

✨ CHANGING THE DEFAULTS ✨

Bestie, ftnchek includes two mechanisms for changing the default values of all options: by defining environment variables or by creating a preferences file. πŸ‘‘

When ftnchek starts up, it looks in its environment for any variables whose names are composed by prefixing the string FTNCHEK_ onto the uppercased version of the option name. If such a variable is found, its value is used to specify the default for the corresponding switch or setting. In the case of settings (for example, the -common strictness setting) the value of the environment variable is read as the default setting value. In the case of switches, the default switch will be taken as true or yes unless the environment variable has the value 0 or NO.

Note that the environment variable name must be constructed with the full-length option name, which must be in uppercase. No shortcuts, bestie. For example, to make ftnchek print a source listing by default, set the environment variable FTNCHEK_LIST to 1 or YES or anything other than 0 or NO. The names FTNCHEK_LIS (not the full option name) or ftnchek_list (lower case) would not be recognized. πŸ’€

Here are some examples of how to set environment variables on various systems. For simplicity, all the examples set the default -list switch to YES. 🌈

  1. UNIX, Bourne shell:
$ FTNCHEK_LIST=YES
$ export FTNCHEK_LIST
  1. UNIX, C shell:
% setenv FTNCHEK_LIST YES
  1. VAX/VMS:
$ DEFINE FTNCHEK_LIST YES
  1. MSDOS:
$ SET FTNCHEK_LIST=YES

After processing any environment variables, ftnchek looks for a preferences file containing options and settings. It will search in the following order, using only the first file found: (1) .ftnchekrc in the current directory, (2) ftnchek.ini in the current directory, (3) .ftnchekrc in the user's home directory, (4) ftnchek.ini in the home directory. First one wins, periodt. ✨

If such a file is found, the options defined in it are used as defaults in place of the built-in defaults and overriding any defaults set in the environment..

Each option or setting in the preferences file must be on a separate line. One per line, bestie. They are given in the same form as on the command line, except without the initial dash. So no - at the start. The preferences file can contain blank lines and comments. Comments are introduced at any point in a line by a space character (blank or tab) or the '#' character, and are terminated by the end of the line.

Command-line options override the defaults set in the environment or in the preferences file, in the same way as they override the built-in defaults. So CLI is the boss. πŸ‘‘

πŸ’– USING PROJECT FILES πŸ’–

okay bestie, this section is the deep dive on how to actually use project files well β€” like, effectively β€” and how to dodge the lil traps that'll trip you up. buckle in. πŸŽ€


the tea on local vs global checking β˜•

so ftnchek's checks split into two categories: local and global. periodt.

Local checking stays inside a single routine. it catches stuff like uninitialized variables, unintended loss of precision in arithmetic expressions, etc. the vibe is: you can do this on each subprogram all by itself, no friends needed. AND β€” iconique behaviour β€” you don't have to redo the local check on a subprogram when some other subprogram changes. it just stays valid. πŸ’…

Global checking is the social butterfly. it catches things like calling a subroutine with the wrong argument types, or disagreeing in common block declarations. it needs to look at the whole squad of subprograms interacting with each other. no solo runs. πŸ¦‹


why project files exist 🧚

the whole point of project files is to let you separate the local-checking step from the global-checking step. so assuming each subprogram lives in its own source file, here's the plan:

  1. run ftnchek once on each one to do local checking, while suppressing global checking
  2. then run ftnchek once on all the project files together to do the global checking

the sample makefile below shows how to automate this. the .f.prj target updates a project file for a particular file any time the source file changes. the info needed for global checking gets saved into the project file. the check target does the combined global checking. typically make check would repeat the ftnchek -project step only on changed source files, then do the global check. and ngl, that's a big advantage for large programs, when many subprograms seldom if ever change. 🫢


one subprogram per file, pls πŸ™

best practice when using project files: put each subprogram in a separate source file. like, just do it.

if each source file may contain more than one subprogram, it complicates the definition of "local" and "global" checking, because there's some inter-module checking that's contained within a file. ftnchek tries to do the right thing in this case, but there are some complications (described below) due to the trade-off between avoiding re-doing cross-checks and preserving information about the program's structure. it's giving "we tried our best". 😭


library mode & trimming: the optimal setup ✨

ordinarily, to do the least amount of re-checking, project files should be created with the -library flag in effect and trimming turned on. in this mode, the info saved in the project file is:

  • all subprogram declarations
  • all subprogram invocations not resolved by declarations in the same file
  • one instance of each COMMON block declaration

that's the minimum amount of information needed to check agreement between files. lean. clean. minimal. πŸ’œ


but wait… the multi-routine plot twist 😳

if the source file contains more than one routine, there are some possible problems that can arise from creating the project file in library mode, because the calling hierarchy among routines defined within the file is lost. gone. evaporated.

also, if the routines in the file make use of COMMON blocks that are shared with routines in other files, there will not be enough information saved for the correct checking of set and used status of COMMON blocks and COMMON variables according to the -usage setting.

so therefore: if you plan to use project files when -usage checking is turned on (which is the default situation), and if multiple routines in one project file share COMMON blocks with routines in other files, the project files should be created with the -library flag turned off. πŸ”₯

in that mode, ftnchek saves, besides the information listed above:

  • one invocation of each subprogram by any other subprogram in the same file
  • all COMMON block declarations

which means the project file will be larger than necessary, and that when it's read in, ftnchek may repeat some inter-module checks that it already did when the project file was created. extra work, but correct work.

if each project file contains only one module, there is no loss of information in creating the project files in library mode. slay. πŸ‘‘


the sticky flag situation πŸ“

because of the possible loss of information entailed by creating a project file with the -library flag in effect, whenever that project file is read in later, it will be treated as a library file regardless of the current setting of the -library flag. the file remembers what it is. main character energy, honestly.

on the other hand, a project file created with library mode turned off can be read in later in either mode. flexible. 🌈


trim vs no-trim πŸŽ€

the foregoing discussion assumes that the trimming options of the -project setting are turned on when the project file is created. that's the normal situation.

the no-trim options of the -project setting are provided in case one wants to use the project files for purposes other than checking the program with ftnchek. for instance, one could write a Perl script to analyze the project files for information about how the different subprograms are called. cute! πŸ¦‹

⚠️ but do not use the no-trim options to deal with the issues of information loss discussed above, since they cause more information than necessary to be stored. that makes the project files bigger and causes ftnchek to do more work later when it reads them to check your complete program. 🫠

ordinarily, you should use the -library option to control how much information to store for later use by ftnchek in checking your program. periodt.


the makefile glow-up πŸ› οΈβœ¨

here's an example of how to use the UNIX make utility to automatically create a new project file each time the corresponding source file is altered, and to check the set of files for consistency. add these lines to your makefile.

the example assumes that a macro OBJS has been defined which lists all the names of object files to be linked together to form the complete executable program.

πŸ™ˆ (in this makefile, the indented lines should each begin with a tab, not blanks. we do not make the rules, we just get yelled at by make.)

if any source file contains multiple routines that share common blocks among themselves, then the no-com-\* option should be removed from NOGLOBAL, and/or drop the -library flag.

# tell make what a project file suffix is
.SUFFIXES: .prj

# these options suppress global checks.
NOGLOBAL=-usage=no-ext-undefined,no-com-\*

# tell make how to create a .prj file from a .f file
.f.prj:
        ftnchek -project $(NOGLOBAL) -library $<

# set up macro PRJS containing project filenames
PRJS= $(OBJS:.o=.prj)

# "make check" will check everything that has been changed.
check: $(PRJS)
        ftnchek $(PRJS)

big-library energy: concatenating project files πŸ“š

when a program uses many routines defined in a large number of different source files in different directories, it can be cumbersome to specify all the different project files needed to check the program properly. so annoying.

to deal with such cases, ftnchek allows project files to be concatenated into a single large file. this single file can then be given to ftnchek to provide the information for checking the use of any or all of the routines defined in the combined project files. πŸ’–

when using such a "library" project file, you may want ftnchek's error reports to document precisely the name of the file where the specific function is defined. if the various source files are in several directories, an error report that gives only the file name may be ambiguous, and rather should include the path to the file.

the solution: create each of the individual project files by giving the complete path to the source file. then this complete path will appear in the error reports. 🌟

for example, suppose that all of the library subprogram source files are in subdirectories of a directory named /util/lib. then the individual project files could first be created by a command such as:

find /util/lib -name '*.f' -exec ftnchek -project '{}' ';'

(possibly other options would be provided to ftnchek as discussed above. also, this step could be handled instead by a revised makefile rule that would provide the complete source file path instead of just the local name when invoking ftnchek.)

next, concatenate all of these project files manually:

find /util/lib -name '*.prj' -exec cat '{}' ';' > ourlib.prj

then a program source file can be checked by using the command:

ftnchek prog.f ... -lib ourlib.prj

and an error message related to any library routine will include the full path to the routine's source file. chef's kiss. πŸ’…


no ar for project files (yet) 😭

at present, there is no archive utility like ar to manage the contents of a concatenated project file like the one in the illustration above. so if changes are made to one of the library routines, the only way to update the combined project file is to concatenate all the individual project files once again. rip.

such a utility would be quite easy to write. someone should do so and contribute it to the ftnchek effort. πŸ‘€ like, calling all devs. this is your moment. go be the main character. πŸ’œ

πŸŽ€ AN EXAMPLE πŸŽ€

ok bestie, picture this: a sweet innocent little Fortran program that's supposed to read in an array of test scores and then compute the average for the series. Iconic concept, questionable execution. πŸ’–

C       AUTHORS: MIKE MYERS AND LUCIA SPAGNUOLO
C       DATE:    MAY 8, 1989

C       Variables:
C               SCORE -> an array of test scores
C               SUM ->   sum of the test scores
C               COUNT -> counter of scores read in
C               I ->     loop counter

        REAL FUNCTION COMPAV(SCORE,COUNT)
            INTEGER SUM,COUNT,J,SCORE(5)

            DO 30 I = 1,COUNT
                SUM = SUM + SCORE(I)
30          CONTINUE
            COMPAV = SUM/COUNT
        END

        PROGRAM AVENUM
C
C                       MAIN PROGRAM
C
C       AUTHOR:   LOIS BIGBIE
C       DATE:     MAY 15, 1990
C
C       Variables:
C               MAXNOS -> maximum number of input values
C               NUMS    -> an array of numbers
C               COUNT   -> exact number of input values
C               AVG     -> average returned by COMPAV
C               I       -> loop counter
C

            PARAMETER(MAXNOS=5)
            INTEGER I, COUNT
            REAL NUMS(MAXNOS), AVG
            COUNT = 0
            DO 80 I = 1,MAXNOS
                READ (5,*,END=100) NUMS(I)
                COUNT = COUNT + 1
80          CONTINUE
100         AVG = COMPAV(NUMS, COUNT)
        END

The compiler gives no error messages when this program is compiled. Yet here is what happens when it is run:

$ run average
70
90
85
<EOF>
$

What happened?? Why didn't the program do anything? 😭 The following is the output from ftnchek when it is used to debug the above program:

$ ftnchek -list -symtab average

FTNCHEK Version 3.3 November 2004

File average.f:

      1 C       AUTHORS: MIKE MYERS AND LUCIA SPAGNUOLO
      2 C       DATE:    MAY 8, 1989
      3
      4 C       Variables:
      5 C               SCORE -> an array of test scores
      6 C               SUM ->   sum of the test scores
      7 C               COUNT -> counter of scores read in
      8 C               I ->     loop counter
      9
     10         REAL FUNCTION COMPAV(SCORE,COUNT)
     11             INTEGER SUM,COUNT,J,SCORE(5)
     12
     13             DO 30 I = 1,COUNT
     14                 SUM = SUM + SCORE(I)
     15 30          CONTINUE
     16             COMPAV = SUM/COUNT
                           ^
Warning near line 16 col 20: integer quotient expr SUM/COUNT  converted to
 real
     17         END

Module COMPAV: func: real

Variables:

      Name Type Dims     Name Type Dims     Name Type Dims     Name Type Dims
    COMPAV real         COUNT intg             I intg*            J intg
     SCORE intg  1        SUM intg

* Variable not declared. Type has been implicitly defined.

Warning in module COMPAV: Variables declared but never referenced:
    J declared at line 11

Warning in module COMPAV: Variables may be used before set:
    SUM used at line 14
    SUM set at line 14

Statement labels defined:

    Label   Line  StmtType
     <30>     15      exec

     18
     19
     20         PROGRAM AVENUM
     21 C
     22 C                       MAIN PROGRAM
     23 C
     24 C       AUTHOR:   LOIS BIGBIE
     25 C       DATE:     MAY 15, 1990
     26 C
     27 C       Variables:
     28 C               MAXNOS -> maximum number of input values
     29 C               NUMS    -> an array of numbers
     30 C               COUNT   -> exact number of input values
     31 C               AVG     -> average returned by COMPAV
     32 C               I       -> loop counter
     33 C
     34
     35             PARAMETER(MAXNOS=5)
     36             INTEGER I, COUNT
     37             REAL NUMS(MAXNOS), AVG
     38             COUNT = 0
     39             DO 80 I = 1,MAXNOS
     40                 READ (5,*,END=100) NUMS(I)
     41                 COUNT = COUNT + 1
     42 80          CONTINUE
     43 100         AVG = COMPAV(NUMS, COUNT)
     44         END

Module AVENUM: prog

External subprograms referenced:

    COMPAV: real*

Variables:

      Name Type Dims     Name Type Dims     Name Type Dims     Name Type Dims
       AVG real         COUNT intg             I intg        MAXNOS intg*
      NUMS real  1

* Variable not declared. Type has been implicitly defined.

Warning in module AVENUM: Variables set but never used:
    AVG set at line 43

I/O Operations:

     Unit ID Unit No. Access Form Operation   Line
             5          SEQ  FMTD READ         40

Statement labels defined:

    Label   Line  StmtType    Label   Line  StmtType
     <80>     42      exec    <100>     43      exec

 0 syntax errors detected in file average.f
 6 warnings issued in file average.f

Warning: Subprogram COMPAV argument data type mismatch at position 1:
    Dummy arg SCORE in module COMPAV line 10 file average.f is type intg
    Actual arg NUMS in module AVENUM line 43 file average.f is type real

According to ftnchek, the program contains variables which may be used before they are assigned an initial value, and variables which are not needed. ftnchek also warns the user that an integer quotient has been converted to a real. This may assist the user in catching an unintended roundoff error. Since the -symtab flag was given, ftnchek prints out a table containing identifiers from the local module and their corresponding datatype and number of dimensions. Finally, ftnchek warns that the function COMPAV is not used with the proper type of arguments.

With ftnchek's help, we can debug the program. We can see that there were the following errors:

  1. SUM and COUNT should have been converted to real before doing the division.
  2. SUM should have been initialized to 0 before entering the loop.
  3. AVG was never printed out after being calculated.
  4. NUMS should have been declared INTEGER instead of REAL.

We also see that I, not J, should have been declared INTEGER in function COMPAV. Also, MAXNOS was not declared as INTEGER, nor COMPAV as REAL, in program AVENUM. These are not errors, but they may indicate carelessness. As it happened, the default type of these variables coincided with the intended type. πŸ¦‹

Here is the corrected program, and its output when run:

C       AUTHORS: MIKE MYERS AND LUCIA SPAGNUOLO
C       DATE:    MAY 8, 1989
C
C       Variables:
C               SCORE -> an array of test scores
C               SUM ->   sum of the test scores
C               COUNT -> counter of scores read in
C               I ->     loop counter
C
       REAL FUNCTION COMPAV(SCORE,COUNT)
            INTEGER SUM,COUNT,I,SCORE(5)
C
            SUM = 0
            DO 30 I = 1,COUNT
                SUM = SUM + SCORE(I)
30          CONTINUE
            COMPAV = FLOAT(SUM)/FLOAT(COUNT)
        END
C
C
        PROGRAM AVENUM
C
C                       MAIN PROGRAM
C
C       AUTHOR:   LOIS BIGBIE
C       DATE:     MAY 15, 1990
C
C       Variables:
C               MAXNOS -> maximum number of input values
C               NUMS    -> an array of numbers
C               COUNT   -> exact number of input values
C               AVG     -> average returned by COMPAV
C               I       -> loop counter
C
C
            INTEGER MAXNOS
            PARAMETER(MAXNOS=5)
            INTEGER I, NUMS(MAXNOS), COUNT
            REAL AVG,COMPAV
            COUNT = 0
            DO 80 I = 1,MAXNOS
                READ (5,*,END=100) NUMS(I)
                COUNT = COUNT + 1
80          CONTINUE
100         AVG = COMPAV(NUMS, COUNT)
            WRITE(6,*) 'AVERAGE =',AVG
        END
$ run average
70
90
85
<EOF>
AVERAGE =   81.66666
$

With ftnchek's help, our program is a success! πŸ‘‘


πŸ” INTERPRETING THE OUTPUT πŸ”

The messages given by ftnchek include not only syntax errors but also warnings and informational messages about things that are legal Fortran but that may indicate errors or carelessness. Most of these messages can be turned off by command-line options. Which option controls each message depends on the nature of the condition being warned about. See the descriptions of the command-line flags in the previous sections, and of individual messages below. Each message is prefixed with a word or phrase indicating the nature of the condition and its severity.

Error means a syntax error. The simplest kind of syntax errors are typographical errors, for example unbalanced parentheses or misspelling of a keyword. This type of error is caught by the parser and appears with the description parse error or syntax error (depending on the version of the parser generator and whether it is GNU bison or UNIX yacc). This type of error message cannot be suppressed. Be aware that this type of error often means that ftnchek has not properly interpreted the statement where the error occurs, so that its subsequent checking operations will be compromised. You should eliminate all syntax errors before proceeding to interpret the other messages ftnchek gives.

fr fr bestie, fix the syntax errors first or everything downstream is giving chaos πŸ’€

Warning: Nonstandard syntax indicates an extension to Fortran that ftnchek supports but that is not according to the Fortran 77 Standard. The extensions that ftnchek accepts are described in the section on Extensions below. One example is the DO ... ENDDO construction. If a program uses these extensions, warnings will be given according to specifications under the -f77 setting. The default behavior is to give no warnings.

Warning in other cases means a condition that is suspicious but that may or may not be a programming error. Frequently these conditions are legal under the standard. Some are illegal but do not fall under the heading of syntax errors. Usage errors are one example. These refer to the possibility that a variable may be used before it has been assigned a value (generally an error), or that a variable is declared but never used (harmless but may indicate carelessness). The amount of checking for usage errors is controlled by the -usage flag, which specifies the maximum amount of checking by default.

Truncation warnings cover situations in which accuracy may be lost unintentionally, for example when a double precision value is assigned to a real variable. These warnings are controlled by the -truncation setting, which is on by default. ✨

Nonportable usage is the little siren 🚨 that goes off when something might not fly on every compiler β€” even though it's not actually against the Fortran 77 Standard β€” or when the program could straight-up behave differently on different platforms. Classic example bestie: equivalencing real and integer variables together? That's usually a non-portable move πŸ’€. Using extensions to the standard language is also a source of non-portability, but that's a whole separate case, we handle it elsewhere. So if you wanna check a program for true portability, you need BOTH the -portability and -f77 flags running. Both of them are off by default, jsyk. And the -wordsize setting exists so you can check only those nonportable usages that depend on a particular machine wordsize. πŸ‘‘

Possibly misleading appearance is for legal constructions that maybe don't mean what they look like at first glance. Example: Fortran does not care about blank space at all, so extra space inside a variable name, or no space between a keyword and a variable, can give the reader the totally wrong impression. You can suppress these messages by turning off the -pretty flag β€” which is on by default. ✨

There's another group of messages that show up after all the files are processed, and they're all about agreement between modules. These don't use the word "warning" but honestly they're in that category. Examples: type mismatches between corresponding variables in different COMMON block declarations, or between dummy and actual arguments of a subprogram. These are controlled by the -common and -arguments settings respectively, and by default both are set for maximum strictness of checking. 😀

Another group β€” warnings about conditions that are often totally harmless β€” covers cases where the array properties of a variable passed as a subprogram argument differ between the two routines. Like, an array element might get passed to a subroutine that's expecting a whole array. That's actually a super common technique for processing single rows or columns of two-dimensional arrays πŸ“. But it could also be a programming error. The -array setting lets you adjust how strict the checking is for this kind of agreement between actual and dummy array arguments. Default strictness is maximum. πŸ’…

Oops means there's a technical problem β€” either a bug in ftnchek itself, or its resources have been exceeded. Not us, not you, it's giving glitch. πŸ™ˆ

The syntax error messages and warnings include the filename along with the line number and column number. ftnchek has two different options for how these error messages look. If -novice is in effect β€” which is the default β€” the messages are in a style approximating normal English. (In default style, the filename is not printed in messages within the body of the program if -list is in effect.) The other style is selected by the -nonovice option, and in that style the messages look similar to the UNIX lint program. πŸ”

Now, real talk: ftnchek is still blind to some kinds of syntax errors. The two most important ones are:

  • detailed checking of FORMAT statements, and
  • almost anything to do with control of execution flow by means of IF, DO, and GOTO statements β€” namely correct nesting of control structures, matching of opening statements such as IF ... THEN with closing statements such as ENDIF, and the proper use of statement labels (numbers).

Most compilers will catch these errors. See the section on Limitations for a more detailed discussion.

If ftnchek gives you a syntax error message when the compiler does not, it may be because your program contains an extension to standard Fortran which is accepted by the compiler but not by ftnchek. (See the section on Extensions.) On a VAX/VMS system, you can use the compiler option /STANDARD to cause the compiler to accept only standard Fortran. On most UNIX or UNIX-like systems, this can be accomplished by setting the flag -ansi. πŸŽ€

Many of the messages given by ftnchek are self-explanatory. Those that need some additional explanation are listed below in alphabetical order. πŸ‘‡


Common block NAME: data type mismatch at position n

The n-th variable in the COMMON block differs in data type in two different declarations of the COMMON block. By default (-common strictness level 3), ftnchek is very picky about COMMON blocks: the variables listed in them must match exactly by data type and array dimensions. That is, the legal pair of declarations in different modules:

COMMON /COM1/ A,B

and

COMMON /COM1/ A(2)

will cause ftnchek to give warnings at strictness level 3. These two declarations are legal in Fortran since they both declare two real variables. At strictness level 1 or 2, no warning would be given in this example, but the warning would be given if there were a data type mismatch β€” for instance, if B were declared INTEGER. Controlled by -common setting.

Common block NAME has long data type following short data type

Some compilers require alignment of multi-byte items so that each item begins at an address that is a multiple of the item size. So if a short item (e.g. single-precision real) is followed by a long item (e.g. double precision real), the latter may not be aligned correctly. Controlled by -portability=common-alignment option. ⚠️

Common block NAME has mixed character and non-character variables

The ANSI standard requires that if any variable in a COMMON block is of type CHARACTER, then all other variables in the same COMMON block must also be of type CHARACTER. Controlled by -f77=mixed-common option.

Common block NAME: varying length

For -common setting level 2, this message means that a COMMON block is declared to have different numbers of words in two different subprograms. A word is the amount of storage occupied by one integer or real variable. For -common setting level 3, it means that the two declarations have different numbers of variables, where an array of any size is considered one variable. This is not necessarily an error, but it may indicate that a variable is missing from one of the lists. Note that according to the Fortran 77 Standard, it is an error for named COMMON blocks (but not blank COMMON) to differ in number of words in declarations in different modules. Given for -common setting 2 or 3.

Error: Badly formed logical/relational operator or constant

Error: Badly formed real constant

The syntax analyzer has found the start of one of the special words that begin and end with a period (e.g. .EQ.), or the start of a numeric constant, but did not succeed in finding a complete item of that kind. 😭

Error: cannot be adjustable size in module NAME

A character variable cannot be declared with a size that is an asterisk in parentheses unless it is a dummy argument, a parameter, or the name of the function defined in the module.

Error: cannot be declared in SAVE statement in module NAME

Only local variables and common blocks can be declared in a SAVE statement.

Error: No path to this statement

ftnchek will detect statements which are ignored or by-passed because there is no foreseeable route to the statement. For example, an unnumbered statement (a statement without a statement label), occurring immediately after a GOTO statement, cannot possibly be executed. πŸ’€

Error: Parse error

This means that the parser, which analyzes the Fortran program into expressions, statements, etc., has been unable to find a valid interpretation for some portion of a statement in the program. If your compiler does not report a syntax error at the same place, the most common explanations are: (1) use of an extension to ANSI standard Fortran that is not recognized by ftnchek, or (2) the statement requires more lookahead than ftnchek uses (see section on Bugs).

NOTE: This message means that the affected statement is not interpreted. Therefore, it is possible that ftnchek's subsequent processing will be in error, if it depends on any matters affected by this statement (type declarations, etc.).

Error: Syntax error

This is the same as ``Error: Parse error'' (see above). It is generated if your version of ftnchek was built using the UNIX yacc parser generator rather than GNU bison.

Identifiers which are not unique in first six chars

Warns that two identifiers which are longer than 6 characters do not differ in the first 6 characters. This is for portability: they may not be considered distinct by some compilers. Controlled by -sixchar option.

Nonportable usage: argument precision may not be correct for intrinsic function

The precision of an argument passed to an intrinsic function may be incorrect on some computers. Issued when a numeric variable declared with explicit precision (e.g. REAL*8 X) is passed to a specific intrinsic function (e.g. DSQRT(X)). Controlled by -portability=mixed-size and -wordsize.

Nonportable usage: character constant/variable length exceeds 255

Some compilers do not support character strings more than 255 characters in length. Controlled by -portability=long-string.

Nonportable usage: File contains tabs

ftnchek expands tabs to be equivalent to spaces up to the next column which is a multiple of 8. Some compilers treat tabs differently, and also it is possible that files sent by electronic mail will have the tabs converted to blanks in some way. Therefore files containing tabs may not be compiled correctly after being transferred. ftnchek does not give this message if tabs only occur within comments or character constants. Controlled by -portability=tab. πŸ¦‹

Nonportable usage: non-integer DO loop bounds

This warning is only given when the DO index and bounds are non-integer. Use of non-integer quantities in a DO statement may cause unexpected errors, or different results on different machines, due to roundoff effects. Controlled by -portability=real-do. πŸ”₯

Possibly it is an array which was not declared

okay so this one gets tacked onto warnings about a function invocation or an argument type mismatch β€” basically whenever there's a chance that the thing looking like a function is actually meant to be an array. Bestie, if the programmer forgot to dimension an array, every reference to it gets read as a function call, and that's the whole vibe here. 🫠

  • This message gets suppressed if the name in question shows up in an EXTERNAL or INTRINSIC statement.
  • Controlled by the -novice option.

Possibly misleading appearance: characters past 72 columns

So the program is being processed with the statement field width at its standard value of 72, and somebody left some nonblank characters hanging out past column 72. ftnchek is not processing those characters β€” it's just flagging that the statement might not mean what it looks like it means. πŸ™ˆ

  • Those characters might be super intentional on the programmer's part, but the compiler will ignore them. Periodt.
  • Controlled by -pretty=long-line.

Possibly misleading appearance: Common block declared in more than one statement

These multiple declarations are legal, no cap, and they do the same thing as just continuing the original declaration of the block. ✨

  • This warning only fires if the two declarations are separated by one or more intervening statements.
  • Controlled by -pretty=multiple-common.

Possibly misleading appearance: Continuation follows comment or blank line

ftnchek drops this one to alert you that a continuation of a statement is interspersed with comments β€” which makes it so easy to overlook. πŸŽ€

  • Controlled by -pretty=continuation.

Possibly misleading appearance: Extraneous parentheses

Warns about parentheses surrounding a variable all by itself in an expression. πŸ’…

  • When a parenthesized variable is passed as an argument to a subprogram, it's treated as an expression, not as a variable whose value can be modified by the called routine.
  • Controlled by -pretty=parentheses.

Subprogram NAME: argument data type mismatch at position n

The subprogram's n-th actual argument (in the CALL or the usage of a function) differs in datatype or precision from the n-th dummy argument (in the SUBROUTINE or FUNCTION declaration).

Like, say the user defines a subprogram by

SUBROUTINE SUBA(X)
REAL X

and elsewhere invokes SUBA by

CALL SUBA(2)

ftnchek will detect the error. The reason? The number 2 is integer, not real. The user should have written

CALL SUBA(2.0)

Now when checking an argument that is a subprogram, ftnchek has to figure out whether it's a function or a subroutine. The rules it uses are:

  • If the subprogram, besides being passed as an actual argument, is also invoked directly elsewhere in the same module, then its type is determined by that usage.
  • If not, then if the name of the subprogram does not appear in an explicit type declaration, it's assumed to be a subroutine; if it is explicitly typed, it's taken as a function.
  • Therefore: subroutines passed as actual arguments only need an EXTERNAL statement in the calling module, whereas functions must also be explicitly typed to avoid generating this error message.

Controlled by -arguments setting.


Subprogram NAME: argument arrayness mismatch at position n

Same energy as the one above, but the subprogram dummy argument differs from the corresponding actual argument in its number of dimensions or number of elements. 🌸

  • Controlled by -array together with -arguments settings.

Subprogram NAME: argument mismatch at position n

A character dummy argument is larger than the corresponding actual argument, or a Hollerith dummy argument is larger than the corresponding actual argument.

  • Controlled by -arguments setting.

Subprogram NAME: argument usage mismatch

ftnchek caught a possible conflict between the way a subprogram uses an argument and the way the argument is supplied to the subprogram. It can be one of two types, bestie:

Dummy arg is modified, Actual arg is const or expr

A dummy argument is an argument as named in a SUBROUTINE or FUNCTION statement and used within the subprogram. An actual argument is an argument as passed to a subroutine or function by the caller. ftnchek is saying a dummy argument is modified by the subprogram β€” which implies its value is changed in the calling module. So the corresponding actual argument should not be a constant or expression, but rather a variable or array element that can be legitimately assigned to.

  • Controlled by the -usage=arg-const-modified option.

Dummy arg used before set, Actual arg not set

Here a dummy argument may be used in the subprogram before the subprogram has assigned it a value. The corresponding actual argument should have a value assigned to it by the caller before invoking the subprogram. 🫢

  • Controlled by the -usage=var-uninitialized option.
  • This warning is not affected by the -arguments setting.

Subprogram NAME invoked inconsistently

Here the mismatch is between the datatype of the subprogram itself as used and as defined. For instance, if the user declares

INTEGER FUNCTION COUNT(A)

and invokes COUNT in another module as

N = COUNT(A)

without declaring its datatype, it'll default to real type, based on the first letter of its name. πŸ’€ The calling module should have included the declaration

INTEGER COUNT
  • Given for -arguments setting 2 or 3.

Subprogram NAME: varying length argument lists:

An inconsistency was found between the number of dummy arguments (parameters) a subprogram has and the number of actual arguments given to it in an invocation. ftnchek keeps track of all invocations of subprograms (CALL statements and expressions using functions) and compares them against the definitions of the subprograms elsewhere in the source code. πŸ”₯

  • The Fortran compiler normally does not catch this type of error.
  • Given for -arguments setting 1 or 3.

Variable not declared. Type has been implicitly defined

When printing the symbol table for a module, ftnchek flags with an asterisk all identifiers that aren't explicitly typed, and shows the datatype that got assigned through implicit typing. This is for the users who wanna declare every variable like Pascal or some other languages make you do. πŸ‘‘

  • This message appears only when the -symtab option is in effect.
  • Alternatively, use the -declare flag if you want a list of all undeclared variables.

Variables declared but never referenced

Detects any identifiers declared in your program but never used β€” neither to be assigned a value nor to have their value accessed. Variables in COMMON are excluded. 🌈

  • Controlled by the -usage=var-unused option.

Variables set but never used

ftnchek will let you know when a variable got assigned a value but is not otherwise used in the program. Usually this is just an oversight. πŸ™ˆ

  • Controlled by the -usage=var-set-unused option.

Variables used before set

This one means an identifier is used to compute a value before its initialization. That kind of usage can lead to an incorrect value being computed, since its initial value is not controlled. 😭

  • Controlled by the -usage=var-uninitialized option.

Variables may be used before set

Similar to used before set, except ftnchek can't determine its status with certainty. It assumes a variable may be used before set if the first usage of the variable occurs prior in the program text to its assignment.

  • Controlled by the -usage=var-uninitialized option.

Warning: DO index is not integer

This warning is only given when the DO bounds are integer, but the DO index is not. It may indicate a failure to declare the index to be an integer. πŸŽ€

  • Controlled by -truncation=real-do option.

Warning: integer quotient expr ... converted to real

The quotient of two integers results in an integer type result, where the fractional part gets dropped. If such an integer expression involving division is later converted to a real datatype, it might be that a real type division had been intended. πŸ’…

  • Controlled by -truncation=int-div-real option.

Warning: Integer quotient expr ... used in exponent

Same deal β€” the quotient of two integers gives an integer result with the fractional part dropped. But if such an integer expression is used as an exponent, it's quite likely that a real type division was intended. ✨

  • Controlled by -truncation=int-div-exponent option.

Warning: NAME not set when RETURN encountered

The way functions in Fortran return a value is by assigning the value to the name of the function. This message means the function was not assigned a value before the point where a RETURN statement was found. So it's possible the function could return an undefined value. yikes.


Warning: Nonstandard syntax: adjustable size cannot be concatenated here

The Fortran 77 Standard (sec. 6.2.2) forbids concatenating character variables whose size is an asterisk in parentheses, except in an assignment statement. 🚫

  • Controlled by -f77=mixed-expr.

Warning: Nonstandard syntax : significant characters past 72 columns

This warning is given under the -f77=long-line setting if the -columns setting has been used to increase the statement field width, and a statement has meaningful program text beyond column 72. Standard Fortran ignores all text in those columns, but some compilers do not. So the program may be treated differently by different compilers. πŸ‘€

Warning: Nonstandard syntax : Statement out of order. πŸ’€

okay so bestie, ftnchek is gonna clock you when your statements are out of the sequence that ANSI standard Fortran 77 says they should be in. Table 1 right below shows you the allowed sequence of statements in the Fortran language. And here's the sweet part β€” statements that are out of order still get interpreted by ftnchek, because otherwise you'd get like a whole avalanche of "cascades" of error messages and that's just not the vibe. The sequence counter also gets rolled back so the same error message doesn't repeat for a whole block of similar statements. This one's controlled by the -f77=statement-order option.

              --------------------------------------------------------
                                |               | implicit
                                |  parameter    |---------------------
                                |               | other specification
                      format    |---------------|---------------------
                       and      |               | statement-function
                      entry     |  data         |---------------------
                                |               | executable
              --------------------------------------------------------

                                    Table 1

Warning: Possible division by zero πŸ“

This one pops up literally wherever division happens (the one exception: division by a constant). Use it to help you hunt down a runtime division by zero situation. Controlled by -division option.

Warning: real truncated to intg

so ftnchek caught an assignment statement with a real expression on the right but an integer variable on the left 😭. The fractional part of the real value is gonna be lost, periodt. If you explicitly convert that real expression to integer using the INT or NINT intrinsic function, no warning gets printed. A similar message shows up if a double precision expression gets assigned to a single precision variable, etc. Controlled by -truncation=demotion option.

Warning: subscript is not integer

Since array subscripts are normally integer quantities, using a non-integer expression here might be signalling an error πŸ‘€. Controlled by -truncation=real-subscript option.

Warning: Unknown intrinsic function

This message warns you that a name declared in an INTRINSIC statement is unknown to ftnchek. Probably it's a nonstandard intrinsic function, which means your program will not be portable, ngl. The function gets treated by ftnchek as a user-defined function. This warning is not suppressed by any option, since it affects ftnchek's analysis of the program. However, if the intrinsic function is in one of the supported sets of nonstandard intrinsics, you can use the -intrinsic setting to cause ftnchek to recognize it. 🫢


LIMITATIONS AND EXTENSIONS 🌈

ftnchek accepts ANSI standard Fortran-77 programs with some minor limitations and numerous common extensions. ✨

Limitations

  • The dummy arguments in statement functions are treated like ordinary variables of the program. That is, their scope is the entire subprogram, not just the statement function definition.
  • The checking of FORMAT statements is lax, tolerating missing separators (comma, etc.) between format descriptors in places where the Standard requires them, and allowing .d fields on descriptors that should not have them. It does warn under -f77=format-edit-descr about nonstandard descriptor types (like O), and supported extensions.
  • There are some syntactic extensions and Fortran 90 elements that ftnchek accepts but does very little checking on. For instance, pointer usage (whether the nonstandard Cray syntax or the Fortran 90 syntax) is not checked other than for set and used status. It is hoped that some day more thorough checking will be implemented, but for now the user should regard the acceptance of these syntactic features simply as a convenience to enable checking of other aspects of code that contains them. See the section Extensions for specifics about what features are accepted but not fully checked.
  • If a user-supplied subprogram has the same name as one of the nonstandard intrinsic functions recognized by ftnchek, it must be declared in an EXTERNAL statement in any routine that invokes it. Otherwise it will be subject to the checking normally given to the intrinsic function. Since the nonstandard intrinsics are not standard, this EXTERNAL statement is not required by the Fortran 77 Standard. Using the -intrinsic=none setting, recognition of most nonstandard intrinsics (excepting only those needed to support the double complex data type) can be turned off. See the lists of supported nonstandard intrinsic functions under the discussion of the -intrinsic setting above.

Extensions πŸ¦‹

All of these extensions (except lower-case characters) will generate warnings if the relevant -f77 option is set. Some of the extensions listed below are part of the Fortran-90 Standard. These are indicated by the notation (F90).

  • Tabs are permitted, and translated into equivalent blanks which correspond to tab stops every 8 columns. The standard does not recognize tabs. Note that some compilers allow tabs, but treat them differently. The treatment defined for DEC FORTRAN can be achieved using the -source=dec-tab setting.
  • Strings may be delimited by either quote marks or apostrophes. A sequence of two delimiter characters is interpreted as a single embedded delimiter character. (F90)
  • Strings may contain UNIX-style backslash escape sequences. They will be interpreted as such if the -source=unix-backslash setting is given. Otherwise the backslash character will be treated as a normal printing character.
  • Source code can be in either Fortran 90 free format or traditional fixed format. (F90)
  • A semicolon is allowed as a statement separator. (F90)
  • Lower case characters are permitted, and are converted internally to uppercase except in character strings. The standard specifies upper case only, except in comments and strings. (F90)
  • Hollerith constants are permitted, in accordance with the Fortran 77 Standard, appendix C. They should not be used in expressions, or confused with datatype CHARACTER.
  • The letter D (upper or lower case) in column 1 is treated as the beginning of a comment. There is no option to treat such lines as statements instead of comments.
  • Statements may be longer than 72 columns provided that the setting -columns was used to increase the limit. According to the standard, all text from columns 73 through 80 is ignored, and no line may be longer than 80 columns.
  • Variable names may be longer than six characters. The standard specifies six as the maximum. ftnchek permits names up to 31 characters long (F90).
  • Variable names may contain underscores and dollar signs (or other non-alphabetic characters as specified by the -identifier-chars option). These characters are are treated the same as alphabetic letters. The default type for variables beginning with these characters is REAL. In IMPLICIT type statements specifying a range of characters, the dollar sign follows Z and is followed by underscore. (Any other user-defined characters are treated the same as the dollar sign.) Fortran 90 permits underscores in variable names.
  • The UNIX version tolerates the presence of preprocessor directives, namely lines beginning with the pound sign (#). These are treated as comments, except for #line directives, which are interpreted, and are used to set the line number and source file name for warnings and error messages. Note that #include directives are not processed by ftnchek. Programs that use them for including source files should be passed through the preprocessor before being input to ftnchek. As noted below, ftnchek does process INCLUDE statements, which have a different syntax. An optional program, ftnpp(1L) (available separately) provides preprocessing that properly handles INCLUDE files.
  • The Fortran 90 DO ... ENDDO control structure is permitted. The CYCLE and EXIT statements are accepted. All of these may have an optional do-construct name, but construct names are not checked for consistency. (F90)
  • The Fortran 90 SELECT CASE construct is accepted. (F90)
  • Construct names are also accepted on IF, THEN, ELSE, ENDIF and SELECT CASE statements. (F90)
  • The ACCEPT and TYPE statements (for terminal I/O) are permitted, with the same syntax as PRINT.
  • The so-called ``Cray pointer'' syntax is tolerated. It is not the same as the Fortran 90 POINTER statement. There is no real checking of the statement other than basic syntax. The form of this statement is
POINTER (pointer, pointee) [,(pointer, pointee)]

The pointer variables are assigned a data type of INTEGER *4. Usage checking of the pointee variables is suppressed, since in practice they are accessed indirectly via the pointers.

  • The following Fortran 90 pointer related syntaxes are accepted: ALLOCATABLE, POINTER, and TARGET statements and the same attributes in type declarations; ALLOCATE, DEALLOCATE, and NULLIFY executable statements; pointer assignment using => operator; and the intrinsic functions ALLOCATED and ASSOCIATED. Little semantic checking of pointer variables and operations is done beyond basic set and used status. For instance, there is no checking for such errors as dangling pointers, or use of unallocated arrays.
  • Statements may have any number of continuation lines. The Fortran 77 and Fortran 90 standards allow a maximum of 19 in fixed source form. The Fortran 90 standard allows a maximum of 39 in free source form.
  • Relational (comparison) operators composed of punctuation, namely: < <= == /= > >= are allowed. (F90)
  • Inline comments, beginning with an exclamation mark, are permitted. (F90)
  • NAMELIST I/O is supported. The syntax is the same as in Fortran 90.

FORMAT statements can have a dollar sign in them to say "suppress that carriage-return", okay bestie? πŸ’… And you can drop an integer expression wrapped in angle brackets basically anywhere in a FORMAT statement where the Fortran 77 Standard would let you put an integer constant β€” the one ✨exception✨ being the length of a Hollerith constant β€” so you can feed in a run-time value for a repeat specification or a field width. Slay. πŸŽ€

Nonstandard keywords are allowed in I/O statements, matching up with the ones in VMS Fortran. 🫢

The IMPLICIT NONE statement is supported. What it means is that every single variable has to have its data type explicitly declared, no exceptions, no vibes-based typing. And instead of flagging every occurrence with syntax error messages, ftnchek is patient β€” it waits till the end of the module and then prints out a list of all the undeclared variables, exactly like it does for the -declare option. (F90) πŸ’–

Data types INTEGER, REAL, COMPLEX, and LOGICAL are allowed to have an optional precision specification in type declarations. For instance, REAL*8 means an 8-byte floating point data type. But listen: REAL*8 is not necessarily considered equivalent to DOUBLE PRECISION β€” it depends on your -wordsize setting. And the Fortran 77 Standard allows a length specification only for CHARACTER data. πŸ™ˆ

ftnchek supports the DOUBLE COMPLEX type specification, for a complex quantity whose real and imaginary parts are double precision. Mixed-mode arithmetic involving single-precision complex with double-precision real data β€” which is prohibited under the Standard β€” yields a double complex result. 😭

Combined type declarations and data-statement-like initializers are accepted. These have the form of a standard Fortran 77 type declaration, followed by a slash-delimited list of constants like the one used in a DATA statement. An example of the syntax is

     INTEGER  N / 100 /

This bastard form of initializing declaration was not adopted in Fortran 90. Such declarations should be written using the standard form described below, which is accepted by ftnchek.


There's limited support for Fortran 90 attribute-based type declarations. This style of declaration is distinguished by the use of a double colon (::) between the list of attributes and the list of declared variables. The features supported may be adequate for novice programmers, but are not yet sufficient for professional-quality Fortran 90 programs. I hope to add support for more features in future releases. I invite volunteers to assist in this task. See the ToDo file in the source code distribution for details. πŸ‘‘

The attributes currently accepted, besides all the usual data types, are DIMENSION, EXTERNAL, INTRINSIC, PARAMETER, and SAVE. The new form of declaration also allows assignment of values to the variables declared. At present, the (LEN=value) form of specifying character lengths is also accepted. Kind specifications, using (KIND=value), are parsed but are not processed: all kinds are treated as default kind. Also, there is little checking of these declarations beyond basic syntax. 🧚

Many commonly found nonstandard intrinsic functions are provided. See the discussion of -intrinsic for a list of functions and how to control which ones are recognized.

Argument checking is not tight for those nonstandard intrinsics that take arrays or mixed argument types. πŸ’€

ftnchek permits the INCLUDE statement, which causes inclusion of the text of the given file. The syntax is

     INCLUDE 'filename'

This is compatible with Fortran 90. If the -source=vms-include option is given, ftnchek follows VMS conventions with respect to this statement: it assumes a default extension of .for if no filename extension is given, and allows the qualifier /[NO]LIST following the filename, to control the listing of the included file. There is no support for including VMS text modules. 🌸

In diagnostic output relating to items contained in include files, the location of the error is specified by both its location in the include file and the location in the parent file where the file was included. πŸ¦‹

ftnchek accepts PARAMETER statements which lack parentheses. These will be warned about if the -f77=param-noparen flag is given.

ftnchek accepts PARAMETER definitions that involve intrinsic functions and exponentiation by a non-integer exponent. Both of these cases are prohibited by the Fortran 77 Standard, and will be warned about if the -f77=param-intrinsic flag is given. If an intrinsic function value is a compile-time integer constant, ftnchek will evaluate it. This allows better checking if the parameter is used in declaring array sizes. Fortran 90 allows intrinsic functions in PARAMETER definitions.

The intrinsic functions that are evaluated are:

  • ABS, IABS, DIM, IDIM, MAX
  • MAX0, MIN, MIN0, MOD, SIGN
  • ISIGN, LEN, ICHAR, INDEX

The functions of integer arguments are evaluated only if the arguments are integer constant expressions. (These may involve integer constants, parameters, and evaluated intrinsic functions.) The function LEN is evaluated if its argument is an expression involving only character constants and variables whose length is not adjustable. The functions ICHAR and INDEX are evaluated only if the arguments are character constants. ftnchek gives a warning if it needs the value of some intrinsic function that is not evaluated. ⭐


🌈 NEW FEATURES 🌈

Here are the changes from Version 3.2 to Version 3.3, bestie, get comfy:

  1. Front-end has been rewritten for unlimited lookahead, eliminating the longstanding bug that caused incorrect interpretation of statements whose ambiguity was not resolved in the first line. ✨
  2. The -mkhtml option is now available in the MS-DOS version. πŸ’…
  3. Added support for Fortran 90 pointer related syntax: ALLOCATE, DEALLOCATE, and NULLIFY statements; the ALLOCATABLE, POINTER and TARGET attributes in type declarations; the pointer assigment operator => and intrinsic functions ALLOCATED and ASSOCIATED; and deferred-shape array declarations. At present these new syntax features are accepted but not properly checked. This feature was added by Robert Landrito. 🫢
  4. The -f77 and -f90 pointer option controlling warnings about ``Cray pointers'' has been renamed to cray-pointer. The -f77=pointer option now instead controls warnings for code containing Fortran 90 pointer-related syntax. πŸ‘‘
  5. Re-implemented -mkhtml processing so it is now much faster on source files containing many routines. πŸ”₯
  6. Changed the arrangement of the test directory so there is no longer any need to modify the distribution in order to run the test suite (check.bat) under MS-DOS. πŸŽ€
  7. Fixed bug in reading numeric settings on command line when setting name abbreviated to 3 characters. πŸ›
  8. Fixed bug causing spurious warning for a GOTO referring to a labeled END statement when the statement before END was a FORMAT. 😌
  9. New flag -f77=character to control warnings about extensions to the Fortran 77 character data type. Accompanying this new flag is support for Fortran 90 rules for character variable declarations that evaluate to zero or negative length, allowing them and treating negative length values as zero. πŸ’–
  10. Fixed minor bug in printing of comments and blank lines following last END statement in -list mode. πŸ¦‹

πŸ› BUGS πŸ›

okay bestie, real talk: ftnchek still has so much room to grow, and we want your feedback, like genuinely. Tell us about any bugs you spot. And "bug" is a whole spectrum here, bestie β€” it counts if ftnchek yells at you when there's no error at all, AND it counts if it stays silent when it should have warned you. Both are tea. β˜•

but like, quick heads up πŸ’€ β€” ftnchek is not trying to catch every syntax error ever (go read the Limitations section for that). And also, it is not a bug if a variable gets reported as used-before-set just because the usage appears earlier in the text than where it's set. That happens, for example, when a GOTO loops execution backward to some statements that got skipped earlier. ftnchek does not analyze program flow β€” it just assumes statements earlier in the text run before the ones after them. That's the vibe, that's the design. 🫢

We ESPECIALLY want to know if ftnchek crashes. ✨ It is not supposed to crash, ever, not even on programs full of syntax errors. Periodt.

Also welcome: suggestions for extra features you'd find useful πŸŽ€, complaints if any of ftnchek's messages are incomprehensible 😭, and comments on how readable and accurate this very document is. Yes, critique the docs, we can take it πŸ’….

You can also suggest support for additional extensions to the Fortran language β€” but those only get in if it's felt the extensions are sufficiently widely accepted by compilers. No random niche stuff, sorry bestie.

πŸ•΅οΈ so you found a bug β€” now what

First: check the known-bugs list below to see if someone already reported it. Also check the section called ``Limitations and Extensions'' up above, because a restriction there might be the actual culprit. If it's not documented in either place, send a report that includes:

  1. The operating system and CPU type on which ftnchek is running. πŸ’»
  2. The version of ftnchek and values of any environment options or settings defined in startup file. (Capturing the output of ftnchek -help is useful for this.)
  3. A brief description of the bug.
  4. If possible, a small sample program showing the bug.

Send that report to Dr. Robert Moniot (contact info lives in the section called ``Installation and Support''). πŸ“¬

Highest priority goes to bugs that make ftnchek crash. Obviously. πŸ”₯


πŸ› οΈ when your big program breaks stuff

Some problems that pop up when checking large programs can be fixed by increasing the sizes of the data areas in ftnchek. (These problems usually announce themselves with error messages starting with ``Oops''.) The simplest fix: recompile ftnchek with the LARGE_MACHINE macro name defined. Go consult the makefile and README file for how to do that. πŸ“š


πŸ“‹ the known bugs list (the receipts)

  1. Bug: Used-before-set message is suppressed for any variable which is used as the loop index in an implied-do loop, even if it was in fact used before being set in some earlier statement. For example, consider J in the statement
WRITE(5,*) (A(J), J=1,10)

Here ftnchek parses the I/O expression, A(J), where J is used, before it parses the implied loop where J is set. Normally this would cause ftnchek to report a spurious used-before-set warning for J. Since this report is usually in error and occurs fairly commonly, ftnchek suppresses the warning for J altogether. πŸ™ˆ

Prognosis: A future version of ftnchek is planned which will handle implied-do loops correctly. 🌈

  1. Bug: Variables used (not as arguments) in statement-function subprograms do not have their usage status updated when the statement function is invoked.

Prognosis: To be fixed in a future version of ftnchek.

  1. Bug: VAX version does not expand wildcards in filenames on the command line if they are followed without space by an option, e.g. ftnchek *.f/calltree would not expand the *.f. This is because VMS-style options without intervening space are not supported by the GNU shell_mung routine that is used to expand wildcards.

Prognosis: unlikely to be fixed. πŸ’€

  1. Bug: checking for nonstandard format edit descriptors is done only in FORMAT statements, not in character strings used as formats.

Prognosis: may be fixed someday. ✨


πŸ‘‘ ACKNOWLEDGEMENTS πŸ‘‘

ftnchek was designed by Dr. Robert Moniot, professor at Fordham University. During the academic year of 1988-1989, Michael Myers and Lucia Spagnuolo developed the program to perform the variable usage checks. During the following year it was augmented by Lois Bigbie to check subprogram arguments and COMMON block declarations. Brian Downing assisted with the implementation of the INCLUDE statement. John Quinn wrote the common block usage checks. Heba Elsayed wrote the label table printout and label usage checks. Nelson H. F. Beebe of the University of Utah added most of the new code to implement the -makedcls feature and wrote the dcl2inc script. The -mkhtml feature was contributed by Mark McVeigh of Framatome ANP, Inc. The -reference feature was contributed by Gerome Emmanuel, Ecole des mines, U. Nancy (slightly modified). The -vcg option was contributed by Dr. Philip Rubini of Cranfield University, UK. The support for Cray pointer syntax was provided by John Dannenhoffer of United Technologies Research Center. John C. Bollinger of Indiana University added the parser syntax for the SELECT CASE construct. Robert Landrito added the parser syntax for F90 pointer-related features. Additional features will be added as time permits. As of Version 2.5, the name was changed from forchek to ftnchek, to avoid confusion with a similar program named forcheck, developed earlier at Leiden University. πŸŽ€


We would like to thank John Amor of the University of British Columbia, Reg Clemens of the Air Force Phillips Lab in Albuquerque, Markus Draxler of the University of Stuttgart, Victor Eijkhout of the University of Tennessee at Knoxville, Greg Flint of Purdue University, Daniel P. Giesy of NASA Langley Research Center, Fritz Keinert of Iowa State University, Judah Milgram of the University of Maryland College Park, Hugh Nicholas of the Pittsburgh Supercomputing Center, Dan Severance of Yale University, Phil Sterne of Lawrence Livermore National Laboratory, Larry Weissman of the University of Washington, Warren J. Wiscombe of NASA Goddard, and Nelson H. F. Beebe of the University of Utah, for pointing out bugs and suggesting some improvements. πŸ’–

Stefan A. Deutscher, Gunnar Duus, Clive Page of the University of Leicester, Stephan Wefing of Heidelberg University, and Bob Wells of Oxford University were extremely helpful as alpha testers. 🧚

We also thank Jack Dongarra for putting ftnchek into the netlib library of publicly available software. 🌟


πŸ’Ύ INSTALLATION AND SUPPORT πŸ’Ύ

The ftnchek program is free software. 🫢 It can be obtained by anonymous ftp from many software servers, including ftp://netlib.org/fortran.

heads up bestie β€” on Netlib the distribution is named ftnchek.tar.gz whereas on most other servers the file name includes the version number, e.g. ftnchek-3.3.0.tar.gz.

If the file extension is .Z, uncompress with the Unix uncompress(1) utility. If the file extension is .gz, uncompress with the GNU gunzip(1L) program. Then use tar(1) to unpack the files into a subdirectory. πŸ“¦

Installation requires a C compiler for your computer. See the INSTALL file provided with the distribution for instructions on installing ftnchek on your system. Executable binary for particular systems such as IBM PC or Macintosh, as available, can be obtained by anonymous ftp from ftp://ftp.dsm.fordham.edu/pub/ftnchek. Assistance in preparing such executable binary forms is welcome. πŸ™Œ

The nroff version of this document is named ftnchek.man. On UNIX systems, this file can be used as the man page, but actually it is a multi-purpose source file which is used to produce the other forms of the documentation. The cleaned-up man page document, created during installation of ftnchek, is named ftnchek.1. The distribution also includes a plain ASCII version named ftnchek.doc, a PostScript version named ftnchek.ps, an HTML version in directory html, and a VMS HELP version named ftnchek.hlp. πŸ“š

Info about the latest version and the status of the project can be obtained by visiting ftnchek's home page, http://www.dsm.fordham.edu/~ftnchek. For further information and to report bugs, you may contact Dr. Robert Moniot, whose contact information can be found by a Web search for his name and Fordham University. (E-mail address is not provided here because it attracts unsolicited commercial e-mail, but it is easily constructed by combining his last name with the name of the university and the edu domain.) πŸ•΅οΈβ™€οΈ


πŸ‘€ SEE ALSO πŸ‘€

dcl2inc(1L), dtoq(1L), dtos(1L), f77(1), fd2s(1L), fs2d(1L), ftnpp(1L), pfort(1L), qtod(1L), sf3(1L), stod(1L). xsf3(1L), xvcg(1L).


aaaand that's a wrap on the whole page bestie, you made it to the end πŸŽ‰βœ¨ This edition is FTNCHEK 3.3(1), dated November 2004 β€” iconic, timeless, still slaying. Go forth and lint your Fortran, you absolute legend. πŸ’…πŸ¦‹πŸ’–