|
Packit Service |
f629e6 |
XREF(AWK) Philip L. Bewig XREF(AWK)
|
|
Packit Service |
f629e6 |
|
|
Packit Service |
f629e6 |
NAME
|
|
Packit Service |
f629e6 |
|
|
Packit Service |
f629e6 |
xref(awk) - produce a cross reference listing of an awk program
|
|
Packit Service |
f629e6 |
|
|
Packit Service |
f629e6 |
SYNOPSIS
|
|
Packit Service |
f629e6 |
|
|
Packit Service |
f629e6 |
awk -f xref.awk [ file ... ]
|
|
Packit Service |
f629e6 |
|
|
Packit Service |
f629e6 |
DESCRIPTION
|
|
Packit Service |
f629e6 |
|
|
Packit Service |
f629e6 |
XREF(AWK) takes as input a valid awk program and produces as out-
|
|
Packit Service |
f629e6 |
put a cross-reference listing of all variables and function calls
|
|
Packit Service |
f629e6 |
which appear in the program.
|
|
Packit Service |
f629e6 |
|
|
Packit Service |
f629e6 |
For ordinary variables and array variables, a line of the form
|
|
Packit Service |
f629e6 |
|
|
Packit Service |
f629e6 |
count var(func) lines ...
|
|
Packit Service |
f629e6 |
|
|
Packit Service |
f629e6 |
is produced, where "count" is the number of times the variable is
|
|
Packit Service |
f629e6 |
used, "var" is the name of the variable, "func" is the function
|
|
Packit Service |
f629e6 |
name to which the variable is local (a null "func" indicates that
|
|
Packit Service |
f629e6 |
the variable is global), and "lines" is the number of each line
|
|
Packit Service |
f629e6 |
where the variable appears. Appearances of the variable in a
|
|
Packit Service |
f629e6 |
function's parameter list are ignored. The number of lines shown
|
|
Packit Service |
f629e6 |
may differ from "count" if the variable appears more than once on
|
|
Packit Service |
f629e6 |
the same line.
|
|
Packit Service |
f629e6 |
|
|
Packit Service |
f629e6 |
For functions, a line of the form
|
|
Packit Service |
f629e6 |
|
|
Packit Service |
f629e6 |
count func(define) lines ...
|
|
Packit Service |
f629e6 |
|
|
Packit Service |
f629e6 |
is produced, where "count" is the number of times the function is
|
|
Packit Service |
f629e6 |
called, "func" is the name of the function, "define" is the lime
|
|
Packit Service |
f629e6 |
number where the function is defined, and "lines" is the number of
|
|
Packit Service |
f629e6 |
each line where the function is called. As for variables, the
|
|
Packit Service |
f629e6 |
number of lines shown may differ from "count."
|
|
Packit Service |
f629e6 |
|
|
Packit Service |
f629e6 |
Output lines for variables and functions are intermixed and are
|
|
Packit Service |
f629e6 |
sorted by name. Though terse, the output is informative, easy to
|
|
Packit Service |
f629e6 |
read, and amenable to further processing.
|
|
Packit Service |
f629e6 |
|
|
Packit Service |
f629e6 |
EXAMPLE
|
|
Packit Service |
f629e6 |
|
|
Packit Service |
f629e6 |
The cross-reference listing produced by running xref.awk against
|
|
Packit Service |
f629e6 |
itself is shown below:
|
|
Packit Service |
f629e6 |
|
|
Packit Service |
f629e6 |
5 NR() 39 45 50 53 68
|
|
Packit Service |
f629e6 |
8 RLENGTH() 119 120 123 124 127 128 132 133
|
|
Packit Service |
f629e6 |
10 act() 31 34 36 40 51 54 56 63 65 67
|
|
Packit Service |
f629e6 |
1 arr(asplit) 90
|
|
Packit Service |
f629e6 |
2 arr(inarray) 93 94
|
|
Packit Service |
f629e6 |
1 asplit(89) 6
|
|
Packit Service |
f629e6 |
3 braces() 55 57 58
|
|
Packit Service |
f629e6 |
2 flines() 53 79
|
|
Packit Service |
f629e6 |
1 fs(asplit) 89
|
|
Packit Service |
f629e6 |
3 funcname() 42 52 61
|
|
Packit Service |
f629e6 |
16 i() 76 77 78 79 81 82 83 84 90
|
|
Packit Service |
f629e6 |
3 inarray(92) 37 43 48
|
|
Packit Service |
f629e6 |
6 j() 82 83 84
|
|
Packit Service |
f629e6 |
3 j(inarray) 93 94
|
|
Packit Service |
f629e6 |
3 keywords() 10 125 129
|
|
Packit Service |
f629e6 |
1 lex(97) 29
|
|
Packit Service |
f629e6 |
31 line() 103 104 107 108 109 110 112 113 114 115 116 117 118
|
|
Packit Service |
f629e6 |
119 120 122 123 124 126 127 128 131 132 133
|
|
Packit Service |
f629e6 |
6 lines() 39 45 50 83 84
|
|
Packit Service |
f629e6 |
4 local() 41 59 60 64
|
|
Packit Service |
f629e6 |
3 machine() 17 30 31
|
|
Packit Service |
f629e6 |
2 n(asplit) 89 90
|
|
Packit Service |
f629e6 |
15 names() 37 38 43 44 48 49 77 78 79 81 82 83 84
|
|
Packit Service |
f629e6 |
3 nextstate() 30 62 73
|
|
Packit Service |
f629e6 |
4 nnames() 38 44 49 76
|
|
Packit Service |
f629e6 |
4 state() 23 30 31 73
|
|
Packit Service |
f629e6 |
1 str(asplit) 89
|
|
Packit Service |
f629e6 |
3 symb() 29 30 31
|
|
Packit Service |
f629e6 |
2 temp() 59 60
|
|
Packit Service |
f629e6 |
2 temp_asplit() 89 90
|
|
Packit Service |
f629e6 |
31 tok() 37 38 39 41 42 43 44 45 47 48 49 50 52 53 64 101 105
|
|
Packit Service |
f629e6 |
113 115 117 119 123 125 127 129 132
|
|
Packit Service |
f629e6 |
1 val(inarray) 94
|
|
Packit Service |
f629e6 |
5 xnames() 39 45 50 77 82
|
|
Packit Service |
f629e6 |
|
|
Packit Service |
f629e6 |
For readability, some lines have been folded.
|
|
Packit Service |
f629e6 |
|
|
Packit Service |
f629e6 |
SOURCE CODE
|
|
Packit Service |
f629e6 |
|
|
Packit Service |
f629e6 |
# xref.awk - cross reference an awk program
|
|
Packit Service |
f629e6 |
|
|
Packit Service |
f629e6 |
BEGIN {
|
|
Packit Service |
f629e6 |
|
|
Packit Service |
f629e6 |
# create array of keywords to be ignored by lexer
|
|
Packit Service |
f629e6 |
asplit("BEGIN:END:atan2:break:close:continue:cos:delete:" \
|
|
Packit Service |
f629e6 |
"do:else:exit:exp:for:getline:gsub:if:in:index:int:" \
|
|
Packit Service |
f629e6 |
"length:log:match:next:print:printf:rand:return:sin:" \
|
|
Packit Service |
f629e6 |
"split:sprintf:sqrt:srand:sub:substr:system:while",
|
|
Packit Service |
f629e6 |
keywords,":")
|
|
Packit Service |
f629e6 |
|
|
Packit Service |
f629e6 |
# build the symbol-state table
|
|
Packit Service |
f629e6 |
split("00:00:00:00:00:00:00:00:00:00:" \
|
|
Packit Service |
f629e6 |
"20:10:10:12:12:11:07:00:00:00:" \
|
|
Packit Service |
f629e6 |
"08:08:08:08:08:33:08:00:00:00:" \
|
|
Packit Service |
f629e6 |
"08:44:08:36:08:08:08:00:00:00:" \
|
|
Packit Service |
f629e6 |
"08:44:45:42:42:41:08",machine,":")
|
|
Packit Service |
f629e6 |
|
|
Packit Service |
f629e6 |
# parse the input and store an intermediate representation
|
|
Packit Service |
f629e6 |
# of the cross-reference information
|
|
Packit Service |
f629e6 |
|
|
Packit Service |
f629e6 |
# set up the machine
|
|
Packit Service |
f629e6 |
state = 1
|
|
Packit Service |
f629e6 |
|
|
Packit Service |
f629e6 |
# run the machine
|
|
Packit Service |
f629e6 |
for (;;) {
|
|
Packit Service |
f629e6 |
|
|
Packit Service |
f629e6 |
# get next symbol
|
|
Packit Service |
f629e6 |
symb = lex()
|
|
Packit Service |
f629e6 |
nextstate = substr(machine[state symb],1,1)
|
|
Packit Service |
f629e6 |
act = substr(machine[state symb],2,1)
|
|
Packit Service |
f629e6 |
|
|
Packit Service |
f629e6 |
# perform required action
|
|
Packit Service |
f629e6 |
if ( act == "0" )
|
|
Packit Service |
f629e6 |
; # do nothing
|
|
Packit Service |
f629e6 |
else if ( act == "1" ) {
|
|
Packit Service |
f629e6 |
if ( ! inarray(tok,names) )
|
|
Packit Service |
f629e6 |
names[++nnames] = tok
|
|
Packit Service |
f629e6 |
lines[tok,++xnames[tok]] = NR }
|
|
Packit Service |
f629e6 |
else if ( act == "2" ) {
|
|
Packit Service |
f629e6 |
if ( tok in local ) {
|
|
Packit Service |
f629e6 |
tok = tok "(" funcname ")"
|
|
Packit Service |
f629e6 |
if ( ! inarray(tok,names) )
|
|
Packit Service |
f629e6 |
names[++nnames] = tok
|
|
Packit Service |
f629e6 |
lines[tok,++xnames[tok]] = NR }
|
|
Packit Service |
f629e6 |
else {
|
|
Packit Service |
f629e6 |
tok = tok "()"
|
|
Packit Service |
f629e6 |
if ( ! inarray(tok,names) )
|
|
Packit Service |
f629e6 |
names[++nnames] = tok
|
|
Packit Service |
f629e6 |
lines[tok,++xnames[tok]] = NR } }
|
|
Packit Service |
f629e6 |
else if ( act == "3" ) {
|
|
Packit Service |
f629e6 |
funcname = tok
|
|
Packit Service |
f629e6 |
flines[tok] = NR }
|
|
Packit Service |
f629e6 |
else if ( act == "4" )
|
|
Packit Service |
f629e6 |
braces++
|
|
Packit Service |
f629e6 |
else if ( act == "5" ) {
|
|
Packit Service |
f629e6 |
braces--
|
|
Packit Service |
f629e6 |
if ( braces == 0 ) {
|
|
Packit Service |
f629e6 |
for ( temp in local )
|
|
Packit Service |
f629e6 |
delete local[temp]
|
|
Packit Service |
f629e6 |
funcname = ""
|
|
Packit Service |
f629e6 |
nextstate = 1 } }
|
|
Packit Service |
f629e6 |
else if ( act == "6" ) {
|
|
Packit Service |
f629e6 |
local[tok] = 1 }
|
|
Packit Service |
f629e6 |
else if ( act == "7" )
|
|
Packit Service |
f629e6 |
break
|
|
Packit Service |
f629e6 |
else if ( act == "8" ) {
|
|
Packit Service |
f629e6 |
print "error: xref.awk: line " NR ": aborting" \
|
|
Packit Service |
f629e6 |
> "/dev/con"
|
|
Packit Service |
f629e6 |
exit 1 }
|
|
Packit Service |
f629e6 |
|
|
Packit Service |
f629e6 |
# finished with current token
|
|
Packit Service |
f629e6 |
state = nextstate }
|
|
Packit Service |
f629e6 |
|
|
Packit Service |
f629e6 |
# finished parsing, now ready to print output
|
|
Packit Service |
f629e6 |
for ( i = 1; i <= nnames; i++ ) {
|
|
Packit Service |
f629e6 |
printf "%d ", xnames[names[i]] |"sort +1"
|
|
Packit Service |
f629e6 |
if ( index(names[i],"(") == 0 )
|
|
Packit Service |
f629e6 |
printf "%s(%d)", names[i], flines[names[i]] |"sort +1"
|
|
Packit Service |
f629e6 |
else
|
|
Packit Service |
f629e6 |
printf "%s", names[i] |"sort +1"
|
|
Packit Service |
f629e6 |
for ( j = 1; j <= xnames[names[i]]; j++ )
|
|
Packit Service |
f629e6 |
if ( lines[names[i],j] != lines[names[i],j-1] )
|
|
Packit Service |
f629e6 |
printf " %d", lines[names[i],j] |"sort +1"
|
|
Packit Service |
f629e6 |
printf "\n" |"sort +1" }
|
|
Packit Service |
f629e6 |
|
|
Packit Service |
f629e6 |
} # END OF PROGRAM
|
|
Packit Service |
f629e6 |
|
|
Packit Service |
f629e6 |
function asplit(str,arr,fs, n) { n = split(str,temp_asplit,fs)
|
|
Packit Service |
f629e6 |
for ( i = 1; i <= n; i++ ) arr[temp_asplit[i]]++ }
|
|
Packit Service |
f629e6 |
|
|
Packit Service |
f629e6 |
function inarray(val,arr, j) {
|
|
Packit Service |
f629e6 |
for ( j in arr )
|
|
Packit Service |
f629e6 |
if ( arr[j] == val ) return j
|
|
Packit Service |
f629e6 |
return "" }
|
|
Packit Service |
f629e6 |
|
|
Packit Service |
f629e6 |
function lex() {
|
|
Packit Service |
f629e6 |
|
|
Packit Service |
f629e6 |
for (;;) {
|
|
Packit Service |
f629e6 |
|
|
Packit Service |
f629e6 |
if ( tok == "(eof)" ) return 7
|
|
Packit Service |
f629e6 |
|
|
Packit Service |
f629e6 |
while ( length(line) == 0 )
|
|
Packit Service |
f629e6 |
if ( getline line == 0 ) {
|
|
Packit Service |
f629e6 |
tok = "(eof)"; return 7 }
|
|
Packit Service |
f629e6 |
|
|
Packit Service |
f629e6 |
sub(/^[ \t]+/,"",line) # remove white space,
|
|
Packit Service |
f629e6 |
sub(/^"([^"]|\\")*"/,"",line) # quoted strings,
|
|
Packit Service |
f629e6 |
sub(/^\/([^\/]|\\\/)+\//,"",line) # regular expressions,
|
|
Packit Service |
f629e6 |
sub(/^#.*/,"",line) # and comments
|
|
Packit Service |
f629e6 |
|
|
Packit Service |
f629e6 |
if ( line ~ /^function/ ) {
|
|
Packit Service |
f629e6 |
tok = "function"; line = substr(line,9); return 1 }
|
|
Packit Service |
f629e6 |
else if ( line ~ /^{/ ) {
|
|
Packit Service |
f629e6 |
tok = "{"; line = substr(line,2); return 2 }
|
|
Packit Service |
f629e6 |
else if ( line ~ /^}/ ) {
|
|
Packit Service |
f629e6 |
tok = "}"; line = substr(line,2); return 3 }
|
|
Packit Service |
f629e6 |
else if ( match(line,/^[A-Za-z_][A-Za-z_0-9]*\[/) ) {
|
|
Packit Service |
f629e6 |
tok = substr(line,1,RLENGTH-1)
|
|
Packit Service |
f629e6 |
line = substr(line,RLENGTH+1)
|
|
Packit Service |
f629e6 |
return 5 }
|
|
Packit Service |
f629e6 |
else if ( match(line,/^[A-Za-z_][A-Za-z_0-9]*\(/) ) {
|
|
Packit Service |
f629e6 |
tok = substr(line,1,RLENGTH-1)
|
|
Packit Service |
f629e6 |
line = substr(line,RLENGTH+1)
|
|
Packit Service |
f629e6 |
if ( ! ( tok in keywords ) ) return 6 }
|
|
Packit Service |
f629e6 |
else if ( match(line,/^[A-Za-z_][A-Za-z_0-9]*/) ) {
|
|
Packit Service |
f629e6 |
tok = substr(line,1,RLENGTH)
|
|
Packit Service |
f629e6 |
line = substr(line,RLENGTH+1)
|
|
Packit Service |
f629e6 |
if ( ! ( tok in keywords ) ) return 4 }
|
|
Packit Service |
f629e6 |
else {
|
|
Packit Service |
f629e6 |
match(line,/^[^A-Za-z_{}]/)
|
|
Packit Service |
f629e6 |
tok = substr(line,1,RLENGTH)
|
|
Packit Service |
f629e6 |
line = substr(line,RLENGTH+1) } } }
|
|
Packit Service |
f629e6 |
|
|
Packit Service |
f629e6 |
TECHNICAL DISCUSSION
|
|
Packit Service |
f629e6 |
|
|
Packit Service |
f629e6 |
Broadly, XREF(AWK) parses an awk program using a symbol-state
|
|
Packit Service |
f629e6 |
table, in much the same way as a yacc-generated parser. The
|
|
Packit Service |
f629e6 |
lexical analyzer recognizes seven distinct symbols: the word
|
|
Packit Service |
f629e6 |
"function", the left brace, the right brace, identifiers used
|
|
Packit Service |
f629e6 |
as variables, identifiers used as arrays, identifiers used as
|
|
Packit Service |
f629e6 |
functions, and end of file. The type of symbol is returned to
|
|
Packit Service |
f629e6 |
the parser as the value of the "lex" function, and the global
|
|
Packit Service |
f629e6 |
variable "tok" is set to the text of the current token.
|
|
Packit Service |
f629e6 |
|
|
Packit Service |
f629e6 |
The symbol-state table is stored in the "machine" array. The
|
|
Packit Service |
f629e6 |
table can be represented as follows:
|
|
Packit Service |
f629e6 |
|
|
Packit Service |
f629e6 |
symbol | 1 2 3 4 5 6 7
|
|
Packit Service |
f629e6 |
|
|
|
Packit Service |
f629e6 |
state | "function" { } var array func eof
|
|
Packit Service |
f629e6 |
-- -- -- -- -- -- -- -+- -- -- -- -- -- -- -- -- -- -- -- -- --
|
|
Packit Service |
f629e6 |
1 any | 20 10 10 12 12 11 07
|
|
Packit Service |
f629e6 |
2 "function" | 08 08 08 08 08 33 08
|
|
Packit Service |
f629e6 |
3 "function" name | 08 44 08 36 08 08 08
|
|
Packit Service |
f629e6 |
4 "function" name "{" | 08 44 45 42 42 41 08
|
|
Packit Service |
f629e6 |
|
|
Packit Service |
f629e6 |
where the first digit is the state to be entered after process-
|
|
Packit Service |
f629e6 |
ing the current token and the second digit is an action to be
|
|
Packit Service |
f629e6 |
performed. The actions are listed below:
|
|
Packit Service |
f629e6 |
|
|
Packit Service |
f629e6 |
1 found a function call
|
|
Packit Service |
f629e6 |
2 found a variable or array
|
|
Packit Service |
f629e6 |
3 found a function definition
|
|
Packit Service |
f629e6 |
4 found a left brace
|
|
Packit Service |
f629e6 |
5 found a right brace
|
|
Packit Service |
f629e6 |
6 found a local variable declaration
|
|
Packit Service |
f629e6 |
7 found end of file
|
|
Packit Service |
f629e6 |
8 found an error
|
|
Packit Service |
f629e6 |
|
|
Packit Service |
f629e6 |
Each of the first six actions causes some information about the
|
|
Packit Service |
f629e6 |
target program to be stored for later processing; the structures
|
|
Packit Service |
f629e6 |
used will be discussed below. The seventh action causes the
|
|
Packit Service |
f629e6 |
parser to exit. The eighth action causes errors to be reported
|
|
Packit Service |
f629e6 |
to standard error and the program to abort.
|
|
Packit Service |
f629e6 |
|
|
Packit Service |
f629e6 |
Before describing the intermediate data structures, we will
|
|
Packit Service |
f629e6 |
discuss some of the more interesting points in the action calls.
|
|
Packit Service |
f629e6 |
The "braces" variable keeps track of whether we are currently
|
|
Packit Service |
f629e6 |
within a functions; it is positive within a function and zero
|
|
Packit Service |
f629e6 |
without. When the right brace which causes the value of "braces"
|
|
Packit Service |
f629e6 |
to go from one to zero is found, the value of "nextstate" is
|
|
Packit Service |
f629e6 |
changed from four (scanning a function) to one (any) and the
|
|
Packit Service |
f629e6 |
names of local variables are forgotten. The "local" array is
|
|
Packit Service |
f629e6 |
accumulated from the variables found after the function name but
|
|
Packit Service |
f629e6 |
before the opening left brace of the function; action two care-
|
|
Packit Service |
f629e6 |
fully checks whether a variable is global or local before writing
|
|
Packit Service |
f629e6 |
to the intermediate data structure. The variable "funcname" is
|
|
Packit Service |
f629e6 |
the name of the current function when within a function and null
|
|
Packit Service |
f629e6 |
without.
|
|
Packit Service |
f629e6 |
|
|
Packit Service |
f629e6 |
The following arrays store an intermediate representation of the
|
|
Packit Service |
f629e6 |
variable and function identifiers of the target program:
|
|
Packit Service |
f629e6 |
|
|
Packit Service |
f629e6 |
names[1..nnames] = list of all identifiers, both variable and
|
|
Packit Service |
f629e6 |
function names; for variables, the name has the form
|
|
Packit Service |
f629e6 |
var(func), but for functions, there are no parentheses
|
|
Packit Service |
f629e6 |
|
|
Packit Service |
f629e6 |
xnames[names[i]] = number of times names[i] is used
|
|
Packit Service |
f629e6 |
|
|
Packit Service |
f629e6 |
lines[names[i],1..xnames[names[i]]] = list of line numbers
|
|
Packit Service |
f629e6 |
where names[i] is used
|
|
Packit Service |
f629e6 |
|
|
Packit Service |
f629e6 |
flines[names[i]] = line number where function names[i] is
|
|
Packit Service |
f629e6 |
defined
|
|
Packit Service |
f629e6 |
|
|
Packit Service |
f629e6 |
These arrays are created as the parser reads the input; when the
|
|
Packit Service |
f629e6 |
parser is finished, the arrays are output in user-readable form.
|
|
Packit Service |
f629e6 |
|
|
Packit Service |
f629e6 |
PORTABILITY
|
|
Packit Service |
f629e6 |
|
|
Packit Service |
f629e6 |
XREF(AWK) will work with any implementation of nawk. The MKS
|
|
Packit Service |
f629e6 |
ToolKit implementation requires the large-model version of awk.
|
|
Packit Service |
f629e6 |
|
|
Packit Service |
f629e6 |
HISTORY
|
|
Packit Service |
f629e6 |
|
|
Packit Service |
f629e6 |
Written by Phil Bewig on February 10, 1990. Inspired by
|
|
Packit Service |
f629e6 |
Exercise 3-16 of the book "The Awk Programming Language" by
|
|
Packit Service |
f629e6 |
Alfred V. Aho, Brian W. Kernighan and Peter J. Weinberger
|
|
Packit Service |
f629e6 |
(Addison-Wesley: 1988).
|
|
Packit Service |
f629e6 |
|
|
Packit Service |
f629e6 |
COPYRIGHT
|
|
Packit Service |
f629e6 |
|
|
Packit Service |
f629e6 |
This program is placed in the public domain. However, the
|
|
Packit Service |
f629e6 |
author requests credit when distributed.
|
|
Packit Service |
f629e6 |
|