Blame test/xref.original

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