I have some old F77 code (nleq1, horrible-looking but very effective) that I am using in F90 programs. Currently I'm keeping the files separate, with a F90 file that defines a module, and several F77 files (*.f), one of which USEs the module. It's all a bit messy. I'm wondering if there is a way to collect the *.f files together in a module, and/or can a F90 file contain both free-form and fixed-form procedures.
Well, the simplest way to achieve that is to use the fixed-form altogether and replace the END statement by END SUBROUTINE or END FUNCTION. Then you can join the files into a module:
module my_old_ugly_f77_code contains ... contents of file 1 ... contents of file 2 ... end module
It is possible to format code in such a way that it is acceptable as both fixed-form and free-form, modulo a few nasty aspects of fixed-form (notably the fact that spaces are not really significant - I 20 = 1 is the same as I20 = 1), but why bother? Fixed-form is still acceptable as a way to write Fortran 90 style code. And it makes life quite a bit easier.
Gib, consider whether the FREEFORM and NOFREEFORM compiler directives will help. These directives allow mixing blocks of free form code and blocks of fixed form code in the same source file.
Thanks to Arjen and mecej4. I'll need to think about which method makes most sense in this case. It looks as if the compiler directives (which I was unaware of) provide most flexibility.
Using the NOFREEFORM directive I put all the nleq1 files into a module, replacing all the EXTERNAL statements, declaring many undeclared variables, fixing END statements etc. I'm now handling the call-back with procedure(func), another capability that I just learned of. The result is much neater, and I'm very pleased. Thanks.
Yes, that is a risk with any non-standard features. I do not know if gfortran has an equivalent feature, but it may be worth trying to find out. The alternative is to separate the fixed-form and free-form parts into separate files. Fixed-form still allows all the benefits of modern Fortran. the only thing you cannot do is make a single module, although you can combine modules into a single one (joining the interfaces, not the modules as such)
You may try the Silverfrost FTN95 compiler's /CONVERT option and do a one-time conversion from fixed source form to free form, see http://www.silverfrost.com/ftn95-help/options/quick_reference.aspx . There are tools such as SPAG that also do code conversions.
One of my students is using gfortran. Unfortunately the !DIR$ directives do not appear to be supported by gfortran :(
Students should all be trained to use SUBMODULEs, PRONTO! And to use standard language features as much as possible and consider minimal use of compiler directives and options.
See if the fixed-form code can be wrapped in SUBMODULEs and be provided with the MODULE prefix, as follows:
module collect_m interface module subroutine fugly1( a1, a2, ..) ! Interface to fixed-form procedure fugly1 <type> a1 <type> a2 end subroutine fugly1 module function fugly2( b1, b2, ..) ! Interface to fixed-form procedure fugly2 <type> b1 <type> a2 end function fugly2 end interface contains subroutine sub1( .. ) .. end subroutine function f1( .. ) .. end function f1 end module
SUBMODULE(COLLECT_M) FUGLY1_SM IMPLICIT NONE CONTAINS MODULE SUBROUTINE FUGLY1(A1, A2, ..) <TYPE> A1 <TYPE> A2 .. RETURN END SUBROUTINE FUGLY1 END SUBMODULE FUGLY1_SM
SUBMODULE(COLLECT_M) FUGLY2_SM IMPLICIT NONE CONTAINS MODULE FUNCTION FUGLY2(B1, B2, ..) <TYPE> B1 <TYPE> B2 .. RETURN END SUBROUTINE FUGLY2 END SUBMODULE FUGLY2_SM
So note the fixed-form code represented by FUGLY1 and FUGLY2 above are pretty retained as-is, all that is done is standard attributes to wrap such code.
On Silverfrost /CONVERT - I installed it and ran the conversion on a fixed-form .f file. The result is if anything even uglier than the original. Interestingly, the .f file has this line
PARAMETER (ZERO = 0.0 D0)
which is accepted by ifort. The same line appears in the converted free-form .f90 file, but now in ifort the space creates an error. When the space is removed the file compiles, so that's success. Obviously a change between f77 and f90. It still needs some attention before being packaged in a module (END statements need to be completed), but that is relatively minor. It also strips out all the comments, which is not very friendly.
Note there are other such programs available (Alan Miller and Michael Metcalfe have written and published such programs for instance). Whether they produce something in the style you want will depend.
As for PARAMETER (ZERO = 0.0 D0) not being accepted in free-form: that is one of the few incompatibilities between the two source forms. In fixed form spaces essentially have no particular meaning, in free form they do.
That's not a very appealing solution, FortranFan, because there are so many subroutines and functions.
Suit yourself, but anyone else interested in refactoring their code will note:
- the compiler option /gen-interfaces (https://software.intel.com/en-us/fortran-compiler-18.0-developer-guide-and-reference-gen-interfaces) can be used to achieve a decent initial state of interfaces of all the existing legacy code that is usually in fixed-form source format and without explicit interfaces.
- Then one can use any of the scripting options (e.g., Perl) to quickly absorb the interfaces into a module and to wrap the legacy code in SUBMODULEs. Note with SUBMODULEs one does not materially need to change the legacy code in any way; it can even remain in fixed-format source form which is also supported by the current Fortran standard. One only prepends and appends 'stuff' to the source.