XTRAN Example — C, C++, Java, or C# Module/Function Cross-Reference

The following example uses an XTRAN rules file comprising 177 non-comment lines of XTRAN's rules language ("meta-code") to analyze all declarations of, and calls to, procedures in code, and output that information in the form of delimiter separated values (DSV).  This example uses C / C++ / Java / C# code, but the XTRAN rules are not specific to those languages; they are language-independent, and can therefore be used to analyze any language that allows declaration of, and calls to, procedures or functions.

We then use another XTRAN rules file comprising 259 non-comment lines of XTRAN's rules language to process the DSV module/function data accumulated across modules and create a module/function cross-reference, both directions.  Because this process reads and manipulates only DSV data, we use a rules-only version of XTRAN.

The DSV output from the code mining rules for this example can also be interactively queried, using existing XTRAN rules.

How can such powerful and generalized code analysis and reporting be automated in only 436 total lines of XTRAN rules?  Because there is so much capability already available as part of XTRAN's rules language.  These rules take advantage of the following functionality:

The input to and output from XTRAN are untouched, except for the addition of line numbers to the input files for reference.


Process Flowchart

Here is a flowchart for this process, in which the elements are color coded:

process flowchart

Input to XTRAN:

File module1.c:

 1      extern void proc1(void);
 2      extern int  func1(int a, int b);
 3      extern void proc2(int a, int *b);
 4      extern int  func2(void);
 5
 6 void proc3(void)
 7 {
 8      int i, j;
 9
10      proc1();                        /*procedure call*/
11      i = func2();                    /*function call*/
12      i = j;                          /*no procedure or function call*/
13      func1(1, 2);                    /*function call*/
14      i = unksym1;                    /*reference to undeclared symbol*/
15      j = func1(1, 2) + func2();      /*2 function calls*/
16      j = func1(func2(), 2);          /*function call as function arg*/
17      proc3();                        /*recursive procedure call*/
18      j = func1(1, 2) + func1(2, 1);  /*2 calls to same function*/
19      proc2(i, &j);                   /*procedure call*/
20 }

File module2.c:

 1      extern int  func1(int, int);
 2      extern void proc2(int, int *);
 3      extern int  func2(void);
 4      extern void proc3(void);
 5
 6 static int func5(int arg)
 7 {
 8      int i;
 9
10      if (arg == 1)
11          return (1);                 /*stop recursion*/
12      else if (unksym2 == 1)          /*reference to undeclared symbol*/
13          proc3();                    /*procedure call*/
14      else
15          {
16          i = unksym3;                /*reference to undeclared symbol*/
17          i = func5(i - 1);           /*recursive call*/
18          i = func6();                /*recursive call via other func*/
19          }
20      return (i);
21 }
22
23 int func6(void)
24 {
25      int i, j;
26
27      proc3();                        /*procedure call*/
28      i = func1(1, 2);                /*function call*/
29      func1(1, 2);                    /*function call*/
30      i = j;                          /*no procedure or function call*/
31      i = func6();                    /*recursive procedure call*/
32      i = func5(j);                   /*call to function in same module*/
33      j = func2() + func2();          /*2 calls to same function*/
34      j = func1(func2(), 2);          /*function call as function arg*/
35      i = func6();                    /*recursive procedure call*/
36      proc2(i, *j);                   /*procedure call*/
37      return;
38 }

Output from XTRAN:


module1.c(14):  ?XTRAN nonfatal error; status = -121:
        i = unksym1;                    /*reference to undeclared symbol*/
                   ^
%Undeclared symbol encountered!


module2.c(12):  ?XTRAN nonfatal error; status = -121:
        else if (unksym2 == 1)          /*reference to undeclared symbol*/
                        ^
%Undeclared symbol encountered!


module2.c(16):  ?XTRAN nonfatal error; status = -121:
            i = unksym3;                /*reference to undeclared symbol*/
                       ^
%Undeclared symbol encountered!

                       PROCEDURE/Function Cross-Reference

Legend:
        C => call
        D => declaration
        E => external globaldeclaration
        I => internal global declaration
        N => nested declaration
        R => recursive call
        S => "static" declaration

Declarations & calls for each procedure/function, by source file:

func1()
    module1.c. . . . . . . . . . . . . . . 2:E, 13:C, 15:C, 16:C, 18:C
    module2.c. . . . . . . . . . . . . . . 1:E, 28:C, 29:C, 34:C
func2()
    module1.c. . . . . . . . . . . . . . . 4:E, 11:C, 15:C, 16:C
    module2.c. . . . . . . . . . . . . . . 3:E, 33:C, 34:C
func5()
    module2.c. . . . . . . . . . . . . . . 6:D, 17:R, 32:C
func6()
    module2.c. . . . . . . . . . . . . . . 18:C, 23:D, 31:R, 35:R
proc1()
    module1.c. . . . . . . . . . . . . . . 1:E, 10:C
proc2()
    module1.c. . . . . . . . . . . . . . . 3:E, 19:C
    module2.c. . . . . . . . . . . . . . . 2:E, 36:C
proc3()
    module1.c. . . . . . . . . . . . . . . 6:D, 17:R
    module2.c. . . . . . . . . . . . . . . 4:E, 13:C, 27:C

Procedure/function declarations & calls in each source file,
  by procedure/function name:


module1.c
    func1() . . . 2:E, 13:C, 15:C, 16:C, 18:C
    func2() . . . 4:E, 11:C, 15:C, 16:C
    proc1() . . . 1:E, 10:C
    proc2() . . . 3:E, 19:C
    proc3() . . . 6:D, 17:R
module2.c
    func1() . . . 1:E, 28:C, 29:C, 34:C
    func2() . . . 3:E, 33:C, 34:C
    func5() . . . 6:D, 17:R, 32:C
    func6() . . . 18:C, 23:D, 31:R, 35:R
    proc2() . . . 2:E, 36:C
    proc3() . . . 4:E, 13:C, 27:C