# xref.awk - cross reference an awk program
# 12/2010: Modified for gawk test suite to use a variable
# for the sort command and to use `sort -k1' instead of `sort +1'
BEGIN {
if (sortcmd == "") sortcmd = "sort" # "sort -k1"
# create array of keywords to be ignored by lexer
asplit("BEGIN:END:atan2:break:close:continue:cos:delete:" \
"do:else:exit:exp:for:getline:gsub:if:in:index:int:" \
"length:log:match:next:print:printf:rand:return:sin:" \
"split:sprintf:sqrt:srand:sub:substr:system:while",
keywords,":")
# build the symbol-state table
split("00:00:00:00:00:00:00:00:00:00:" \
"20:10:10:12:12:11:07:00:00:00:" \
"08:08:08:08:08:33:08:00:00:00:" \
"08:44:08:36:08:08:08:00:00:00:" \
"08:44:45:42:42:41:08",machine,":")
# parse the input and store an intermediate representation
# of the cross-reference information
# set up the machine
state = 1
# run the machine
for (;;) {
# get next symbol
symb = lex()
nextstate = substr(machine[state symb],1,1)
act = substr(machine[state symb],2,1)
# perform required action
if ( act == "0" )
; # do nothing
else if ( act == "1" ) {
if ( ! inarray(tok,names) )
names[++nnames] = tok
lines[tok,++xnames[tok]] = NR }
else if ( act == "2" ) {
if ( tok in local ) {
tok = tok "(" funcname ")"
if ( ! inarray(tok,names) )
names[++nnames] = tok
lines[tok,++xnames[tok]] = NR }
else {
tok = tok "()"
if ( ! inarray(tok,names) )
names[++nnames] = tok
lines[tok,++xnames[tok]] = NR } }
else if ( act == "3" ) {
funcname = tok
flines[tok] = NR }
else if ( act == "4" )
braces++
else if ( act == "5" ) {
braces--
if ( braces == 0 ) {
for ( temp in local )
delete local[temp]
funcname = ""
nextstate = 1 } }
else if ( act == "6" ) {
local[tok] = 1 }
else if ( act == "7" )
break
else if ( act == "8" ) {
print "error: xref.awk: line " NR ": aborting" \
> "/dev/con"
exit 1 }
# finished with current token
state = nextstate }
# finished parsing, now ready to print output
for ( i = 1; i <= nnames; i++ ) {
printf "%d ", xnames[names[i]] | sortcmd
if ( index(names[i],"(") == 0 )
printf "%s(%d)", names[i], flines[names[i]] | sortcmd
else
printf "%s", names[i] | sortcmd
for ( j = 1; j <= xnames[names[i]]; j++ )
if ( lines[names[i],j] != lines[names[i],j-1] )
printf " %d", lines[names[i],j] | sortcmd
printf "\n" | sortcmd }
close(sortcmd)
} # END OF PROGRAM
function asplit(str,arr,fs, n) { n = split(str,temp_asplit,fs)
for ( i = 1; i <= n; i++ ) arr[temp_asplit[i]]++ }
function inarray(val,arr, j, tmp) {
for ( j in arr )
tmp[arr[j]]++
return (val in tmp) }
function lex() {
for (;;) {
if ( tok == "(eof)" ) return 7
while ( length(line) == 0 )
if ( getline line == 0 ) {
tok = "(eof)"; return 7 }
sub(/^[ \t]+/,"",line) # remove white space,
sub(/^"([^"]|\\")*"/,"",line) # quoted strings,
sub(/^\/([^\/]|\\\/)+\//,"",line) # regular expressions,
sub(/^#.*/,"",line) # and comments
if ( line ~ /^function/ ) {
tok = "function"; line = substr(line,9); return 1 }
else if ( line ~ /^{/ ) {
tok = "{"; line = substr(line,2); return 2 }
else if ( line ~ /^}/ ) {
tok = "}"; line = substr(line,2); return 3 }
# change regexes to use posix character classes
else if ( match(line,/^[[:alpha:]_][[:alnum:]]*\[/) ) {
tok = substr(line,1,RLENGTH-1)
line = substr(line,RLENGTH+1)
return 5 }
else if ( match(line,/^[[:alpha:]_][[:alnum:]]*\(/) ) {
tok = substr(line,1,RLENGTH-1)
line = substr(line,RLENGTH+1)
if ( ! ( tok in keywords ) ) return 6 }
else if ( match(line,/^[[:alpha:]_][[:alnum:]]*/) ) {
tok = substr(line,1,RLENGTH)
line = substr(line,RLENGTH+1)
if ( ! ( tok in keywords ) ) return 4 }
else {
match(line,/^[^[:alpha:]_{}]/)
tok = substr(line,1,RLENGTH)
line = substr(line,RLENGTH+1) } } }