Porting EM/32 Programs to LF90

From the Lahey Solutions Staff

1.  Introduction

This porting guide recommends steps to move Fortran programs from F77L-EM/32 to Lahey Fortran 90, LF90.  The intended audience is the EM/32 user; however, the suggestions should work when porting from any Lahey language system.

For the most part, compiled object and library program units are incompatible between EM/32 and LF90.  Therefore, we strongly recommended all program units and libraries be recompiled.

LF90 is a 32-bit high-performance Fortran 90 language system targeted for Intel's Pentium and Pentium Pro Processors.  LF90 also generates quality code for the 80386 and 80486 chips.  LF90 does not support EM/32 features that reduce performance nor does it support technology that has not kept up with Intel's chip evolution.  In general, all currently non-documented (accidental) extensions are not supported in LF90

The steps detailed below begin with setting a goal and finish with the program executing under LF90. Section 8 is an inventory of incompatibilities between EM/32 and LF90 and the associated actions to correct them.

If you believe something should be a part of this guide, please call Lahey Solutions and let us know - it will be appreciated.

For more detailed information towards adopting Fortran 90, Lahey offers Migrating to Fortran 90, by James F. Kerrigan for $27.95 plus shipping and handling.

2.  Porting Procedure

This guide is intended more as a guide than a cookbook; individuals should feel free to make changes (possibly even ignore suggestions) appropriate to their way of doing things.

2.1  Decide upon a goal.  1) Cleaner, more portable, FORTRAN 77 source code (which could also be used for EM/32) or 2) moving code towards Fortran 90 by beginning to introduce Fortran 90 features into the code.

Your goal affects, see below, what changes are made to EM/32 source files.

2.2  Make backup copies of all EM/32 source and data files.

2.3  Choose an extension for fixed-format source files, .for (same as EM/32) is suggested.  The extension can be anything but .f90 which is the default to denote the other Fortran 90 source form: free.  Rename the EM/32 fixed-format source files to the chosen extension.

2.4  Using FFTOSTD.EXE (provided with EM/32), convert EM/32 free-format source files to Fortran 90 fixed-format source (same as FORTRAN 77) using the extension decided upon above.  This is necessary because the Fortran 90 Standard supports a free-format source format that conflicts with the free form EM/32 supports.
2.5  If the source file contains conditional compilation, use FPP (provided with EM/32) and the set of variables to create the LF90 source file(s).  Alternatively, create a .BAT file to run FPP to generate the LF90 source file each time an LF90 compile is required.

2.6  Using EM/32, compile the fixed-format files using the /C/H/L/X options.  These options cause a source listing with cross-reference information to be generated and non-conformance with the FORTRAN 77 Standard noted.  Non-standard features are noted with one of the following messages:

WARNING - Non-standard FORTRAN 77 usage (see FORTRAN 77 extensions in Lahey Language Reference Manual index).

WARNING - Non-standard Fortran 77 usage, a Fortran 90 feature (see Fortran 90 features in Lahey Language Reference Manual index).

Since the compiler is unable to report every incompatibility, see "FORTRAN 77 extensions" and "Fortran 90 features" in the EM/32 Language Reference.

2.7  Link and execute the EM/32 program.  Then execute the program with redirection of output, e.g.,

 program >filename.77

This .77 file will be used to compare with LF90 output to help ensure the program has been ported successfully.

2.8  Make backup copies of all the new (if any) EM/32 source files.

2.9  Install LF90, follow the directions on the screen.

2.10  Port and compile the source files.

2.11  Create the executable file and capture the output; use the extension ".90".

2.12  Compare the .77 and .90 files.  Due to different code generation algorithms in EM/32 and LF90, numbers might not compare due to round off.  Other than this, the files should compare.  If not, carefully review the changes that have been made and repeat these last three steps until the port has been accomplished.

3.  Driver (LF90.EXE)

Depending on the command-line options, the driver invokes the compiler, library manager, and linker to compile source files, create module libraries, and bind objects and libraries to create an executable file. More than one source file and/or object file may be specified.  To use the driver to compile a source file to an object file without invoking the linker, use the -c option.

Type "LF90" with no arguments to list the command-line syntax and optional arguments.  See the LF90 User's Guide for the complete description of the Driver.

4.  Fig Converter (CNVFIG.EXE)

Lahey FORTRAN 77 compilers (*.FIG) and LF90 (LF90.FIG) have different sets of options with different syntax for specifying the option.  To facilitate this change, LF90 includes CNVFIG, an executable that converts existing *.FIG files into an LF90.FIG in the same directory.  CNVFIG either

maps each option into the corresponding LF90 option or the option is eliminated.  The first list of options (from all the Lahey compilers) below are eliminated; the second list are converted as noted.

4.1  Eliminated Options
/2, /3, /a, /a1, /c1, /d1, /e1, /e2, /i, /h, /k, /kh, /q1, /q2, /q3, /t, /u

4.2  Translated Options

From         To
/[n]0      -[n]in
/4         -t4
/[n]7      -[n]ap
/[n]a2     -[n]dal
/[n]b      -[n]chk
/[n]c      -[n]f90
/[]h       -[n]lst
/d         -nhed
/f         -nfix
/[n]o      -[n]co
/[n]p      -[n]pca
/[n]r      -[n]sav
/[n]s      -[n]g
/[n]v      -[n]vax
/[n]w      -[n]w
/[n]x      -[n]xref
/z1        -o3

Three /n options are not listed above: /nd (maps to -hed), /nf (maps to -fix), and /nz1 (maps to -o1).

For a complete description of the LF90 options, including the default values, see the LF90 User's Guide.

5.  Make Utilities and makefiles

Make utilities and makefiles are used for managing larger software projects where there are many source files, header files, and libraries, often scattered among different directories.  While the compiler itself will unconditionally compile all files, the Make utility will only compile files that have been changed recently (along with other files that depend on them), resulting in considerable time savings. Beginning with version 3.50, the LF90 compiler is being distributed with a new Make utility called Automake, written by Polyhedron Software Ltd. Automake has certain advantages over the old Make utility written by Opus Software, but some users may wish to retain their use of the old Make.  Note that the .f90.exe inference rules are already known to both Make utilities.

5.1  Opus MAKE (MAKE.EXE)
If you wish to continue using Opus MAKE, you'll need to change the following lines in your makefile:

From                                      To
FC      = F77L3                           FC      = LF90
LINKER  = 386LINK                         LINKER  = LF90
FFLAGS  = <EM/32 options>                 FFLAGS  = -c <other LF90 options>
LDFLAGS = -SYMBOLS <other link options>   LDFLAGS = <link options>

If your makefile uses compiler response files, you'll need to change the following lines as well:

DEL F77L3.RSP                         DEL LF90.RSP
ECHO $<,$@ $(FFLAGS) >>F77L3.RSP      ECHO $< $(FFLAGS) >>LF90.RSP
!IF -e F77L3.RSP                      !IF -e LF90.RSP
   $(FC) @F77L3.RSP                      $(FC) @LF90.RSP

Automake was chosen for its ability to handle Fortran 90 module dependencies. It is also, on average, easier to use than Opus Make for most applications.  Unfortunately, complex makefiles developed under Opus Make are not easily ported to Automake (it is usually easier to start from scratch). There is nothing wrong with continuing to use Opus Make; just be sure that MAKE.EXE, MAKEL.EXE and MKMF.EXE are on your path, and be sure that MAKE.INI, MAKEFILE.LIB, and MAKEFILE.PRG reside in the same directory as these EXE files.

To set up Automake for a large project with components in multiple directories, it is easiest to copy all components of the project into a single (temporary) directory and run AM so it can figure out the dependencies.  You can then copy the resulting AUTOMAKE.DEP file over to your working directory. You will also need to copy the file \LF9035\BIN\AUTOMAKE.FIG into the working directory and edit it so that the placemarkers for the various components describe the actual paths of those components.

Chapter 6 of the LF90 User's Guide and the file AUTOMAKE.FIG provide sufficient information on using Automake should you choose to use it.


Under LF90, the linker is automatically run by the driver unless you specify -c, compile only.

If you submit filenames to the driver with the extension .obj, the driver will only run the linker.

The driver will read linker command files except for the following imcompatibilities:

     - Comment lines must begin with a # in column one.
     - Object file names must include the extension .obj and be separated by white space (no commas).

7.  Library Manager (LM.EXE)

The Library Manager (LM.EXE, distributed with LF90 v3.50 and above) provides the same functionality as the PharLap Librarian (386LIB.EXE), although command syntax and options are different.   The following is a list of differences and/or equivalences between 386LIB and LM.

7.1 Command Files
LM uses command files (or response files) in much the same way as 386LIB, albeit with differences in syntax and structure.  For example, an ampersand (&) is used to continue a line in an LM response file, and a new line is treated as a comma on the LM command line.  LM also has an interactive command mode that is activated when LM is invoked without arguments.

7.2 386LIB Environment Variable
There are no environment variables pertaining to LM operations.  Options that were specifed by the 386LIB environment variable will have to be explicitly specified for LM on the command line or in a response file.

7.3 Command Line Syntax
While the Pharlap Librarian is invoked as 386LIB followed by a list of filenames and switches, LM is invoked as LM [old-library-name][switches][commands][,[list-filename][,[new-library-name]];
old-library-name is the name of an existing library, or the library to be created if it does not exist.
switches is zero or more command-line switches.
list-filename is the name of the listing file (same as the 386LIB -map file).
new-library-name is the name of a new library to create if you want to preserve the old library.

7.4 Switches
The following is a list of 386LIB switches, accompanied by LM equivalents wherever possible.
386LIB Switch  Example LM Replacement
-Add  386lib mylib -add mod1, mod2... LM mylib +mod1+mod2...
-(NO)Backup 386lib myilb -delete mod4 -backup specify new-library-name in command line above.
-Create 386lib newlib -create mod1, mod2... LM newlib +mod1+mod2...
-Delete 386lib mylib -delete mod4 LM mylib -mod4
-Extract 386lib mylib -extract trigfunc LM mylib *trigfunc
-ExtractALL 386lib mylib -extractall LM mylib/extractall
-(NO)Map 386lib mylib -map mymap
(outputs a listing to file mymap)
LM mylib, mymap.map
-PAGESIZE 386lib mylib -pagesize 64 LM mylib/pa:64 (note: -pagesize option for lf90 driver remains in effect when creating libraries using lf90)
-Replace 86lib mylib -replace newmod LM mylib -+newmod
-TwoCase  386lib mylib -add trigfunc -twocase No equivalent

8. User Actions

What follows is an inventory of incompatibilities between EM/32 and LF90.  Actions must be taken to remedy each of them.  There are six sections below; each section requires a different action for the group of incompatibilities.

8.1  Hardware Not Supported

8.1.1  80287 coprocessor
Note -- since the 80287 is not supported, SETUNDR0.OBJ is not provided.

8.1.2  Weitek coprocessor

8.2  RPC interface
This feature requires the source programs be recompiled or reassembled using a 32-bit compiler compatible with the Phar Lap DOS-Extender.

8.3  Source Code Extension Changes
This group of changes requires source code changes from an EM/32 FORTRAN 77 extension to a Fortran 90 feature, i.e., the new source program will not be backward compatible with EM/32 but is Fortran 90 standard conforming.

8.3.1  NARGS, number of arguments passed to a program unit.
Action:  Assuming the EM/32 code is something like

REAL a, b, c
IF ( NARGS() .GT. 2 ) THEN
    a = c
    a = b

change the code to use the Fortran 90 intrinsic PRESENT

REAL a, b, c

8.3.2  VAX Extensions
Action:  Use the -vax switch, i.e., LF90 filename -vax
Action, Fortran 90 Solution:  change the intrinsics to use generic Fortran 90 code, e.g., INT2 and INT4 to INT, and CDSIN to SIN.

8.3.2  NAMELIST Statement
In Fortran 90, a namelist group object must  have its type and/or shape specified by previous specification statements or implicit typing rules in effect.  This differs from the statement order allowed in EM/32.  For example, with IMPLICIT NONE in effect, the following two lines would work in EM/32:

NAMELIST /mylist/ a, b, c
INTEGER a, b, c

But would have to be changed in LF90:

INTEGER a, b, c
NAMELIST /mylist/ a, b, c

8.4  Source Code Extension Eliminations
This group requires the source code be modified to eliminate EM/32 extensions that are not in LF90 but the resulting code conforms to the FORTRAN 77 Standard.  In addition, where appropriate, suggestions are given to port to Fortran 90.

8.4.1  Hollerith constants.  LF90 support is limited to within the FORMAT Statement.
Action:  Convert each nH to CHARACTER constants and change the source code accordingly.

8.4.2  Character declaration.  LF90 does not support ch*5(10).
Action: Change to CHARACTER*5 ch(10) or CHARACTER (LEN=5), DIMENSION(10) :: ch

8.4.3  EM/32 allows statement function actual arguments to differ in type from the dummy arguments.
For example,

real x
f(x) = x + 1.
print*, f(1)

LF90 doesn't allow it.
Action:  Use same type arguments

8.4.4  Generic intrinsics.  LF90 does not allow SIN (int), etc., and mixed types with MAX, MIN, MOD, etc.
Action:  Convert arguments to appropriate type using INTRINSIC functions REAL, DOUBLE, ...

8.4.5 Non-Integer Numerics.  LF90 does not allow non-integers in computed goto, subscripts, substrings, unit numbers, etc.
Action:  Using the INTRINSIC function INT, convert non-integer expressions to INTEGER.

8.4.6  ALLOCATE Statement.  STAT= specifier
Action:  If the optional STAT= Specifier is present it must be the last item in the list.

8.4.7  IF (nonCOMPLEX numeric exp) [label],[label],[label]
Where:   Missing statement labels reference the immediately following executable statement Action, simplest solution:  convert to IF (non-COMPLEX numeric exp) label,label,label
Action, better solution:  replace the Arithmetic IF with the FORTRAN 77 LOGICAL IF THEN ELSE construct

Arithmetic IF may be removed from the Fortran Standard

8.4.8 Statement label without an executable statement
Action, FORTRAN 77 solution:  place  word "CONTINUE" after column 6
Action, Fortran 90 solution:  if the label identifies a DO loop, use END DO and eliminate the label

8.4.9  Substring of parenthetical expressions and function results
Action:  Replace the code charexpression(from:to) with:

char_temp = charexpression
 ... char_temp(from:to)

Where:  char_temp is a CHARACTER scalar of appropriate length

8.4.10  Declarations appearing after the first executable statement
Action:  Move the declaration(s) to the declaration statements section of the program unit.

8.4.11  .XOR
Action:  Change .XOR. to .NEQV.

Action:  Delete "HC" so the statement becomes an EXTERNAL statement.

8.4.13  OPEN Statement.  ACTION=READ/WRITE
Action:  Change READ/WRITE to READWRITE.

8.4.14  IOSTAT/STAT numbers are different.

8.5  Non-Standard Changes
This group of statements requires changes that results in code that does not meet either the FORTRAN 77 or the Fortran 90 Standard, i.e., the Fortran Standard Committees have not standardized these features.

8.5.1  %val
Action:  Convert all instances of %val to val, i.e., eliminate the percent sign.

8.5.2  OPTION BREAK(label), OPTION BREAK[(logical variable)] and OPTION NBREAK
Action:  This code must be redone since only CALL BREAK(logical variable), CALL BREAK, and CALL NBREAK are available in LF90.

8.6  Changes That are not required
This group of changes, although recommended, are not required since LF90 has these subprograms as undocumented features.  Alternatively, the source below may be utilized in programs resulting in code that meets the Fortran 90 standard.

8.6.1  CALL TIME(result)
Action:  Convert the code to:

result = char_temp(1:2) // ':' // char_temp(3:4) // ':' &  //  char_temp(5:9)

Where:   char_temp is a CHARACTER scalar of at least length 9

8.6.2  CALL DATE(result)
Action:  Convert the code to:

result = char_temp(5:6) // '/' // char_temp(7:8) // '/' &  //  char_temp(3:4)

Where:  char_temp is a CHARACTER scalar of at least length 8

8.6.3  NBLANK(char_exp)
Action:  Convert the code to:  LEN_TRIM(char_exp)

8.6.4  CHARNB(char-exp)
Action:  Convert the code to:  TRIM(char-exp)