[net.lang.f77] primitive f77 xref program

jerry@ucbopal.CC.Berkeley.ARPA (02/06/85)

Here is a primitive xref program.  Just put the rest of this article
in a file (e.g. f77xref), make it executable (e.g. chmod a+x f77xref),
invoke it, and then follow the directions.

This is fairly primitive, hopefully worthwhile.  I'd be interested in
hearing comments and bugs.  However, this is not claimed to be a
sophisticated cross reference program.

	- Jerry Berkman
	  Computing Services, (415) 642-4804
	  ucbvax!ucbopal!jerry

#	/bin/csh -f
more << 'EOT'

		Cross References for F77 Programs

The f77 compiler does not produce listings or cross references.
This script generates a cross reference for an f77 program.
To get a corresponding listing of the program including line
numbers, use 'cat -n'.

The script is simple-minded and assumes:

1.  Blanks are significant, i.e. there are no blanks in the middle
    of variable names, command keywords, and statement numbers.
2.  Names, keywords, statement numbers and strings are not split
    across lines.

The script is easily confused by:

1.  Counted Holleriths outside of format statements.
2.  The presence of both " and ' in the same line outside of format
    statements.

All alphanumeric strings starting with a letter are tallied in the
cross reference.  The script can not tell the difference between
'do', 'if', ..  used as keywords or as variable names.  Since f77
allows 16 character names, even 'continue' and 'equivalence' could
be variable names.

Similarly, if a number is used both as a statement number and as an
integer, both uses are tallied.

The script is very slow, about 3 lines/second on a VAX 750.

'EOT'
echo -n "enter input file name, carriage return to exit: "
set in_file = $<
if( $in_file == '' ) then
	exit(0)
endif
echo -n "enter output file name, carriage return to exit: "
set out_file = $<
if( $out_file == '' ) then
	exit(0)
endif
if( $out_file !~ /* ) then
	set out_file = `pwd`/${out_file}
endif
echo -n "enter 'y' if input file has sequence information in columns 73-80: "
if( $< =~ y* ) then
	set sequencing = "yes"
else
	set sequencing = "no"
endif
#
unset time
set dir = /tmp/f77_xref$$
/bin/rm -f -r $dir
mkdir $dir
#
#	via 'sed': replace comment lines by null lines
#		replace 0 in col. 6 by " "
#		replace contin. char in col. 6 by '_' in col. 1
#		delete strings:  "..."  or  '...'
#		add spaces around "format" so it'll be separate awk field
#
cat << 'EOT'  >! $dir/sed1
/^[cC*]/s/^.*$//
/^     0/s// /
/^     [^ ]/s//_ /
/".*"/s/"[^"]*"/ /g
/'.*'/s/'[^']*'/ /g
/format/s// format /g
'EOT'
if( $sequencing == "yes" ) then
	colrm 73 < $in_file | sed -f $dir/sed1  >! $dir/step1
else
	sed -f $dir/sed1 < $in_file  >! $dir/step1
endif
#	now blank out format statements including continuation cards
#	also save numbers in statement number field in file 'labels'
cd $dir
cat << 'EOT'  >! awk1
{ if ( $2 == "format" ) {
	print $1;
	print "%" $1 >> "labels";
	prev = "format";
  } else if ( ( $1 == "&" || $1 == "_") && prev == "format" ) {
	print " ";
  } else if ( length == 0 ) {
	print ;
  } else {
	c1 = substr( $1, 1, 1 );
	if( c1 >= "0" && c1 <= "9" ) print "%" $1 >> "labels";
	print ;
	prev = " ";
  }
}
'EOT'
cat /dev/null >! labels
awk -f awk1  < step1 >! step2
#	tr: get rid of special characters
#	awk: add line number to each word and split into one word/line
#	then sort and get count of dups
cat << 'EOT' >! awk2
{ { for ( i = 1; i <= NF; i++ ) print $i , NR } }
'EOT'
tr  -cs 'A-Za-z0-9\012' ' ' < step2  | awk -f awk2 | sort +0 -1 +1n labels - |     uniq -c >! step3
#	print it out, one word + references per line
cat << 'EOT' >! awk3
{ c1 = substr($2,1,1);
  use = "y";
  if ( c1 == "%" ) {      		# label definition
	$2 = substr($2,2,length($2));
	labels[ $2 ] = "y";
	use = "";
  } else if ( c1 >= "0" && c1 <= "9" && labels[ $2 ] == "" )
	use = "";	# starts with digit, but not a label.
  if ( use != "" ) {
     if ( $2 == prev ) {
	if ( length(refs) > 66 ) {
		print refs;
		refs = prev " (cont.)	";
	}
     } else {
		prev = $2;
		print refs;
		refs = $2 "	";
     }
     refs = refs " " $3;
     if( $1 != 1 ) refs = refs "(" $1 ")";
  }
}
END { if( refs != "" ) print refs; }
'EOT'
awk -f awk3 < step3 | sort -n >! $out_file
/bin/rm -f -r $dir