I have one that compiles up with fpm on Linux; totally unsupported but it is all free-format as well and has been mechanically modernized so there is a lot to do but if you use fpm you should be able to compile it up as a module (accept for five remaining procedures) in just a few minutes.
I plan on removing that in a few days unless somone wants to adopt it and continue development. Making it this far was instructive but I do not have the time and resources at the moment to do much else with it; but maybe it will be useful to someone else
Thanks. I started conversion to free-format last night of @Beliavsky’s code with my own refactoring tools. There are some interesting “features” in the code that I’ve not seen before. For instance, several of the source files have some continuations where the line being continued also has a character (always 0) in column 6. There is also frequent use of assigning 10E75 to a variable to indicate an error condition. ifort complains about this being a potential overflow. I assume this was a legal value on old 360s.
If you or @rwmsu could upload the scripts you used to modernize the code, that could be useful in dealing with other old codes. All I did to get more files to compile was use strsub, a tool that used to be distributed with Compaq Visual Fortran, to substitute huge(1.0) for large numeric literals such as 1.E75.
Strsub is convenient but is not distributed with Intel Fortran. It could probably be replicated with a mix of Unix tools. To demonstrate its options,
strsub /?
gives
STRSUB - Version: V1.16 Built: May 16 1996 11:04:04
Usage is: STRSUB [-sw -sw] infile findstr repstr
Switches are:
c Do string compare without regard for case
t Truncate lines if all param strings are found
r Remove beginning of line if all param strings are found
l Toggle display of operation logging information
w Display per line operations
p Swap '#' with '%' in find and replace strings
b Swap '!' with '\' in find and replace strings
a Swap '@' with '"' in find and replace strings
z Remove extra nulls from file
d Don't save .BAK file
q Suppress all console output
n NOP mode - don't actually do anything
s Iterate over subdirectories
v Display program version number
?/h Display this help message
I’m in the process of rewriting my conversion program. My interest in the SSP code was as a test case. The SSP source pointed out a fault in my current logic that caused a seg fault. This was tracked to the SSP files that had continuations in which the first continued line had a character in column six (see for example the first SUBROUTINE statement at line 302 in DLBVP.FOR). I’m somewhat intrigued that this was valid or at least accepted in IBM Fortran way back when. Give me a month or so to redo my code and I’ll gladly post it on Github. Note it just does the basics (change case and continuations etc) so if you want something that also removes GO TOs, arithmetic IFs etc. there are much better tools like fpt for that.
Edit. I also have a bash script that I use that calls sed to execute the sed commands in a user supplied file for all the files with a give file extension in a directory. This is what I will use to change the 1E75 values to HUGE(1).
The zero in column 6 was allowed via an interpretation from the Fortran Committee in the early 1970s, and treated as a blank. Then was disallowed again when Fortran 77 was published. I had a copy of that interpretation report way back when and played with it a bit. But a number of compilers objected, so I never tried it again.
I put together a small script to do some transformations on the files too. Namely, renaming them, getting rid of the double newlines, getting rid of the control/Z at the end of each file, getting rid of sequence numbers/trailing blanks, and replacing the huge values with huge(). It also calls the f2f program to convert to free form and modernize some DO loops. Here it is:
The f2f program doesn’t know about ‘0’ in column 6, so I fixed those by hand. (Should be an easy fix. I’ve been into f2f to fix a couple other bugs as well.) There are also a couple of places where significant blanks are an issue (e.g., splitting across a continued line) - which I also fixed by hand.
Unfortunately literally every IF statement is an arithmetic IF. The f2f program doesn’t even begin to attempt to do anything with them.
#!/bin/sh
# sedmod - A sed editor script
# Version 1 - Jan. 11, 2016 - initial version with if blocks
# Version 2 - Jan. 11, 2016 - replaced if blocks with case statmements
# by Richard Weed
# initialize values to false
SEDCMDFILE=false
FILEEXT=false
SEDCMD=false
NEWDIR=false
IFILE=false
OFILE=false
USESTDOUT=true
SEDNOPT=false
CMDTYPE=false
IFTYPE=false
OTYPE=stdout
# get current directory
THISDIR=`pwd`
export PATH=$THISDIR:$PATH
OFILEPATH=$THISDIR
# process command line options
while getopts he:d:f:i:o:x: OPTION
do
case $OPTION in
d)NEWDIR=$OPTARG
echo " Target directory = $NEWDIR"
USESTDOUT=false
;;
e)SEDCMD=$OPTARG
echo " Edit command = $SEDCMD"
CMDTYPE=cmd
;;
f)SEDCMDFILE=$OPTARG
echo " sed edit command file = $SEDCMDFILE"
CMDTYPE=cmdfile
;;
h)echo " "
echo " sedmod - a sed editor script"
echo " "
echo " Runs either single or multiple sed editor commands on a single"
echo " file or multiple files with a given file extension in the"
echo " current directory. Output can go to either STDOUT, a named file"
echo " for single file edits, a user specified directory with file names"
echo " preserved for multiple file edits, or the current directory with"
echo " an _new tag appended to the original file name"
echo " "
echo " Command line parameters and switches : "
echo " "
echo " -f filename - processes edit commands using an input file (filename)"
echo " -e 'sed command' - processes a single sed command. Command must"
echo " be enclosed in single quotes"
echo " -x file extension - processes all files in the current directory"
echo " with a given file extension. (ex. -x dat processes all .dat files)"
echo " -i filename - processes a single file with name filename"
echo " -o filename - Desired output filename"
echo " -d dirname - Path to a directory to hold multiple edited"
echo " files for multi file processing. The directory is created in"
echo " the current directory if it doesn't exist"
echo " -h - prints help"
echo " "
echo " output goes to standard output if neither -o or -x are specified"
echo " "
echo " Examples :"
echo " "
echo " sedmod -f ./mods.sed -x dat -d ./Temp"
echo " Runs commands in ./mods.sed on all files with a .dat extension"
echo " and places the edited files in ./Temp. Commands in mods.sed "
echo " should be placed one to a line in desired edit sequence without"
echo " quotes"
echo " "
echo " sedmod -e 's/ /, /' -x dat -d ./Temp"
echo " Replaces the first space in all .dat files with a comma"
echo " "
echo " sedmod -e 's/ /, /' -i this.dat -o that.dat"
echo " Replaces the first space in this.dat and writes the edited file"
echo " to that.dat"
echo " "
echo " sedmod -e 's/ /, /' -i this.dat"
echo " Replaces the first space in this.dat and writes the edited file"
echo " to stdout"
echo " "
exit 0
;;
i)IFILE=$OPTARG
echo " Single input file selected = $IFILE"
IFTYPE=single
;;
o)OFILE=$OPTARG
echo " Desired output file = $OFILE"
USESTDOUT=false
OTYPE=outfile
;;
x)FILEEXT=$OPTARG
echo " Processing all files in $THISDIR with extension = $FILEEXT"
USESTDOUT=false
IFTYPE=multiple
OTYPE=keepname
;;
esac
done
# perform error checks
if [ "$NEWDIR" = "$THISDIR" ]; then
echo " ERR : Can't specify output directory to be the same as current dir "
exit 1
fi
case $IFTYPE in
multiple)
if [ "$FILEEXT" = "false" ]; then
echo " "
echo " ERR : No file extension input"
exit 1
fi
if [ "$NEWDIR" = "false" ]; then
echo " "
echo " WARNING : Target directory for multiple file edits not specified"
echo " files will be processed into current directory with an _new added"
echo " to the file extension"
else
if [ ! -d $NEWDIR ]; then
echo " "
echo " ERR : Target directory doesnt exist - creating it in current dir"
mkdir $NEWDIR > /dev/null 2>&1
fi
OFILEPATH=$NEWDIR
fi
;;
single)
if [ "$IFILE" != "false" ]; then
if [ ! -f $IFILE ]; then
echo " "
echo " ERR : Can't find $IFILE in $THISDIR - Check PATH "
exit 1
fi if [ "$FILEEXT" != "false" ]; then
echo " "
echo " ERR : Can't select both single file and multi file editing - Try again"
exit 1
fi
fi
;;
*)
echo " "
echo " ERR : Neither single or multiple file processing specified - Try again"
exit 1
;;
esac
case $CMDTYPE in
cmdfile)
if [ "$SEDCMDFILE" != "false" ]; then
if [ ! -f $SEDCMDFILE ]; then
echo " "
echo " ERR : sed edit command file $SEDCMDFILE not found"
exit 1
fi
if [ "$SEDCMD" != "false" ]; then
echo " "
echo " ERR : Can't enter both a sed command and a command file - Try again"
exit 1
fi
fi
;;
cmd)
if [ "$SEDCMD" = "" ]; then
echo " "
echo " ERR: single edit command is blank"
echo " "
exit 1
fi
;;
*)
echo " "
echo " No edit commands specified - Try again"
exit 1
;;
esac
# process single edit commands first. Check for a single file edit and
# then multifile edits. Logic jumps to multiple edit commands read from
# a user specified file if -f is specified instead f -e
case $CMDTYPE in
cmd)
case $IFTYPE in
single)
case $OTYPE in
stdout)
sed "$SEDCMD" $IFILE
;;
outfile)
sed "$SEDCMD" $IFILE >$OFILEPATH/$OFILE
echo " Modifying $IFILE into $OFILEPATH/$OFILE"
;;
keepname)
if [ "$NEWDIR" != "false" ]; then
sed "$SEDCMD" $IFILE >$NEWDIR/$IFILE
echo " Modifying $IFILE into $NEWDIR/$IFILE"
else
sed "$SEDCMD" $IFILE >$IFILE"_new"
echo " Modifying $IFILE into ""$IFILE""_new"
fi
;;
esac
;;
multiple)
for f in *.$FILEEXT; do
if [ "$NEWDIR" != "false" ]; then
sed "$SEDCMD" $f > $NEWDIR/$f
echo " Modifying $f into $NEWDIR/$f"
else
sed "$SEDCMD" $f > $f"_new"
echo " Modifying $f into ""$f""_new"
fi
done
;;
esac
;;
cmdfile)
case $IFTYPE in
single)
case $OTYPE in
case $OTYPE in
stdout)
sed -f "$SEDCMDFILE" $IFILE
;;
outfile)
sed -f "$SEDCMDFILE" $IFILE >$OFILEPATH/$OFILE
echo " Modifying $IFILE into $OFILEPATH/$OFILE"
;;
keepname)
if [ "$NEWDIR" != "false" ]; then
sed -f "$SEDCMDFILE" $IFILE >$NEWDIR/$IFILE
echo " Modifying $IFILE into $NEWDIR/$IFILE"
else
sed -f "$SEDCMDFILE" $IFILE >$IFILE"_new"
echo " Modifying $IFILE into ""$IFILE""_new"
fi
;;
esac
;;
multiple)
for f in *.$FILEEXT; do
if [ "$NEWDIR" != "false" ]; then
sed -f "$SEDCMDFILE" $f > $NEWDIR/$f
echo " Modifying $f into $NEWDIR/$f"
else
sed -f "$SEDCMDFILE" $f > $f"_new"
echo " Modifying $f into ""$f""_new"
fi
done
;;
esac
;;
esac
exit
These commands will do some formatting to my personal programming style (leading caps for Fortran keywords etc), change real to real(wp), remove tabs and cntrl-Z
The following will run the sedmod script for all files with a file extension of f in a directory and copy the modified files into a ./Temp dir.
chmod 750 sedmod
sedmod -f sedcommands.txt -x f -d ./Temp
I think I got the script uploaded correctly but if someone tries it and has problems let me know.
Amazing. I wrote my first Fortran code in 1971 and this is the first time I’ve ever heard about 0 in column six being parsed as the first line in a continuation. Until, I looked at the IBM SSP code, I have never seen it used in the several hundreds of thousands of lines of code I’ve looked at since I first started my adventures in Fortran programming. I guess you are never too old to learn.
Hmm. Now I am trying to think of what was in that Interpretation…
My mistake. It was how to interpret characters in cols 1-5 when there is a (non-zero or blank) in column 6. The F77 section you quoted specifically says it is not allowed, vs F66 where it leaves the interpretation unanswered.
How often you see that zero in column six probably varies from organization to organization. It was a recommended practice to number the continuation lines starting with 0-9, and then A-Z, so the 0 issue has come up multiple times for us. . I see a lot of “fixed-to-free” converters that miss this;
Another common miss is that an asterisk is a valid character in column 1
to start a comment in f77, and also often missed is that blank characters at the end of a continued line are significant if occurring in a quoted string or Hollerith.
Most do not look for the common extension where lines are “dee’d” where lines beginning with a “D” are comments unless a compiler switch is used in which case the letter “D” in column 1 is ignored. This was usually used to allow for optionally compiled debug lines; particularly before cpp was commonly available.
The most obscure one was that in several F66 implementations this was OK:
real array(10)
array=1.2
which would set the FIRST element of the array, as if “array(1)=1.2” had been used. Those same lines
compile as standard array syntax post f90 of course. That has come up several times because where I work we are blessed/cursed with an archive system that goes back to the very beginning of Fortran, and reviews that often call for very old code to be resurrected
. Just about any extension that existed in Fortran is in there someplace, including Digital extensions so extensive Fortran was
quite a general system programming language on those systems. It has been several years since anyone was asking what some of those old procedure calls did, what ENCODE and DECODE did and what many CDC and Cray math functions did so I finally tossed a set of old manuals. Within six days I had three questions about the old routines. Murphy’s Law apparently has no expiration date.
I think this is one of the reasons that it is commonly suggested that when you convert to f90 you put an ampersand in both column 73 of the continued line and in column six of the following line. This will in most cases but not all handle the significant blanks issue.
Does anyone know the reason for treating zero in column six differently from any other character? It isn’t mentioned in the original IBM 704 Fortran manual. (page 7)
Yes. A convention (not a requirement) since initially 9 continuation cards were allowed was to use the digits 1 through 9 consecutively as the continuation character. This leads to zero naturally being the continuation character for starting the lines, and it was useful particularly when looking card-per-card through a deck of punch cards to mark the first line continued as well as you would not inadvertently think it was a complete card and perhaps move it. So although 1 through 9 were just a convention 0 was designated as a special character. In time it became apparent using digits that commonly appear in statements was not a good choice and using $ or other characters replaced the use of digits, particularly once more than 9 continuation cards were supported (first as an extension, but then in the standard as well). A “preferred practice” was also to end a line at a point where it was obvious it was not complete when easily done, such as a + or - or * character, and to not split symbols (which was allowed in f77 since blanks between columns 7 and 72 were not significant).
So experience had shown a good continuation character is one not used in statements for any other use. There were more characters to choose from as commonly available by the time free-format was introduced, and & fit all the lessons learned. Hard to miss (a period was not found to be a good choice) not used for anything else, and commonly available on most keyboards (the original problem was not even the USA keyboards were standardized, let alone ones supporting multiple languages).
For instance, < and > were not on many keyboards, hence FORTRAN using .GT. and .LT. was a necessary solution. A lot of keyboards had 1/4 and 1/2 keys, but not ~@|{} …
Some authors recommended that ‘$’ be used as a continuation character. “Elements of Programming Style” by Kernighan and Plauger, is one. Rationale was that it was the only character in the Fortran character set that didn’t have another syntactic meaning.
Thinking back on why I was playing with this, almost 50 years ago, was that after I read that interpretation, I was experimenting numbering continued lines something like:
program xyzzy
data array(12) /
1 1.0,
2 2.0,
3 3.0,
(and so on)
9 9.0,
1O 10.0, (note letter O, not digit 0 in col 6.)
11 11.0,
12 12.0/
print *, array
end
This would be legal under that interpretation. But a number of compilers objected. So I quickly abandoned the idea. Later F77 explicitly prohibited it.