XTRAN Example — Module/Function Cross-Reference of Pascal

The following example uses an XTRAN rules file comprising 176 non-comment lines of XTRAN's rules language ("meta-code") to analyze all declarations of, and calls to, functions in code, and output that information in the form of delimiter separated values (DSV).  This example uses Pascal code, but the XTRAN rules are not specific to Pascal; 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.

Note that the analysis identified a recursive call at line 23 of the file module2.pas, even though it was to an outer procedure.

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 429 total code 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.pas:

 1 PROCEDURE proc1; EXTERNAL;
 2
 3 FUNCTION func1(a : INTEGER; b : INTEGER) : INTEGER; EXTERNAL;
 4
 5 PROCEDURE proc2(a : INTEGER; b : ^INTEGER); EXTERNAL;
 6
 7 FUNCTION func2 : INTEGER; EXTERNAL;
 8
 9 PROCEDURE proc3;
10
11	VAR i, j : INTEGER;
12
13 BEGIN
14	proc1;					{procedure call}
15	i := func2;				{function call}
16	i := j;					{no procedure or function call}
17	func1(1, 2);				{function call}
18	j := func1(1, 2) + func2;		{2 function calls}
19	j := func1(func2, 2);			{function call as function arg}
20	proc3;					{recursive procedure call}
21	j := func1(1, 2) + func1(2, 1);		{2 calls to same function}
22	proc2(i, ^j)				{procedure call}
23 END.

File module2.pas:

 1 FUNCTION func1(a : INTEGER; b : INTEGER) : INTEGER; EXTERNAL;
 2
 3 PROCEDURE proc2(a : INTEGER; b : ^INTEGER); EXTERNAL;
 4
 5 FUNCTION func2 : INTEGER; EXTERNAL;
 6
 7 PROCEDURE proc3; EXTERNAL;
 8
 9 PROCEDURE proc4;
10
11	VAR i, j : INTEGER;
12
13	FUNCTION func5(arg : INTEGER) : INTEGER;
14
15	    VAR i : INTEGER;
16
17	    BEGIN
18	    IF arg = 1 THEN
19		func5 := 1;			{stop recursion}
20	    ELSE
21		BEGIN
22		i := func5(i - 1);		{recursive call}
23		j := proc4;			{recursive call to outer PROC}
24		func5 := i			{not a call}
25		END
26	    END;
27 BEGIN
28	proc3;					{procedure call}
29	i := func1(1, 2);			{function call}
30	func1(1, 2);				{function call}
31	i := j;					{no procedure or function call}
32	proc4;					{recursive procedure call}
33	i := func5(j);				{call to inner function}
34	j := func2 + func2;			{2 calls to same function}
35	j := func1(1, 2) + func1(2, 1);		{2 calls to same function}
36	j := func1(func2, 2);			{function call as function arg}
37	proc4;					{recursive procedure call}
38	proc2(i, ^j);				{procedure call}
39 END.


Output from XTRAN:


                  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.pas. . . . . . . . . . . . . . . . . . 3:E, 17:C, 18:C, 19:C, 21:C
    module2.pas. . . . . . . . . . . . . . . . . . 1:E, 29:C, 30:C, 35:C, 36:C
func2()
    module1.pas. . . . . . . . . . . . . . . . . . 7:E, 15:C, 18:C, 19:C
    module2.pas. . . . . . . . . . . . . . . . . . 5:E, 34:C, 36:C
func5()
    module2.pas. . . . . . . . . . . . . . . . . . 13:N, 22:R, 33:C
proc1()
    module1.pas. . . . . . . . . . . . . . . . . . 1:E, 14:C
proc2()
    module1.pas. . . . . . . . . . . . . . . . . . 5:E, 22:C
    module2.pas. . . . . . . . . . . . . . . . . . 3:E, 38:C
proc3()
    module1.pas. . . . . . . . . . . . . . . . . . 9:D, 20:R
    module2.pas. . . . . . . . . . . . . . . . . . 7:E, 28:C
proc4()
    module2.pas. . . . . . . . . . . . . . . . . . 9:D, 23:R, 32:R, 37:R

PROCEDURE/FUNCTION declarations & calls in each source file,
  by PROCEDURE/FUNCTION name:

module1.pas
    func1() . . . 3:E, 17:C, 18:C, 19:C, 21:C
    func2() . . . 7:E, 15:C, 18:C, 19:C
    proc1() . . . 1:E, 14:C
    proc2() . . . 5:E, 22:C
    proc3() . . . 9:D, 20:R
module2.pas
    func1() . . . 1:E, 29:C, 30:C, 35:C, 36:C
    func2() . . . 5:E, 34:C, 36:C
    func5() . . . 13:N, 22:R, 33:C
    proc2() . . . 3:E, 38:C
    proc3() . . . 7:E, 28:C
    proc4() . . . 9:D, 23:R, 32:R, 37:R