The generic compilation component: a tree interpreter

The program
The Input
Setting up the environment
The command file
The Output

Sample tree-walking routine: traverse the tree created by a previous compilation, and identify some of the components of the program. In this case, list the kind of all nodes traversed, and list the names of the subprograms declared in the visible part of package declarations, both for the main unit and for the units that appear in its context clause. ('withed' units).
The program
with Ada.Command_Line; use Ada.Command_Line;
with Atree; use Atree;
with GNAT.OS_Lib; use GNAT.OS_Lib;
with GNAT.Io;
with Lib;
with Nlists; use Nlists;
with Sinfo; use Sinfo;
with Sinput;
with Namet; use Namet;
with Tree_In;
with Types; use Types;

procedure Test_Walker is
   N              : Node_Id;
   Tree_File_Name : String    := Argument (1) & Ascii.Nul;
   Error_Msg      : String    := " had unhandled exception"
                                  & Ascii.LF & Ascii.Nul;
   Result         : Integer;
   FD             : File_Descriptor;
   
   procedure Walk (N : Node_Id);
   --  Recursive procedure that does the work.
   
   procedure Walk (N : Node_Id) is
      Line       : Integer;
      Loc        : Source_Ptr;
      Kind       : Node_Kind;
      Kids       : List_Id;
      L          : Node_Id;
      F          : Node_Id;

   begin
      Kind := Nkind (N);
      Gnat.IO.Put ("Encountered Node Kind : ");
      Gnat.IO.Put_Line (Node_Kind'Image (Kind));

      case Kind is
	 when N_Compilation_Unit =>
	    Walk (Unit (N));
	    Kids := Context_Items (N);        --  list of withed units
	    F := First (Kids);
	    L := F;

	    while L /= Empty loop
	       Walk (L);
	       L := Next (L);
	    end loop;

	 when N_With_Clause =>
	    Walk (Library_Unit(N));

	 when N_Package_Declaration =>
	    Walk (Specification (N));

	 when N_Package_Specification =>
	    Kids := Visible_Declarations (N);
	    F := First (Kids);
	    L := F;

	    while L /= Empty loop
	       Walk (L);
	       L := Next (L);
	    end loop;

	 when N_Subprogram_Declaration =>
	    declare 
 	       Subprog_Id : Node_Id := Defining_Unit_Name (Specification (N));
	       Subprog_Name_Id : Name_Id := Chars (Subprog_Id);
            begin
	       Loc := Sloc (Subprog_Id);
	       Line := Integer (Sinput.Get_Line_Number (Loc));
	       Get_Name_String (Chars (Subprog_Id));
	       Gnat.IO.Put ("Declaration of ");
	       Gnat.IO.Put (Name_Buffer (1 .. Name_Len));
	       Gnat.IO.Put (" found on Line ");
	       Gnat.IO.Put (Line);
	       GNAT.IO.New_Line;
	       end;

	 when others =>
	    null;
      end case;
   end Walk;

begin

   FD := Open_Read (Tree_File_Name'Address, Binary);
   Tree_In (FD);
   N := Lib.Cunit (Types.Main_Unit);
   Walk (N);

exception
   when others =>
      Result := GNAT.OS_Lib.Write (Standerr, Tree_File_Name'Address,
				   Tree_File_Name'Length - 1);
      Result := GNAT.OS_Lib.Write (Standerr, Error_Msg'Address,
				   Error_Msg'Length - 1);
end Test_Walker;


test program for tree walker

package Tiny is I: Integer; procedure Foo (J : Integer); procedure Bar; end Tiny;

Setting Up the environment

The GNAT compiler is accessible on the NYU machines courses1 and courses2, on which all MS students have accounts. a) Create a directory walk, which will hold the tree_walking routine and the test cases. b) Modify your path so that the GNAT commands are ahead of others: set path=(/usr/local/pkg/gnat-3.12p/bin $path) c) The compiler needs the definitions of several environment variables to locate the sources and binaries of the compiler and the library. These definitions are kept in the file env-vals in the home page directory. You can introduce these definitions in your environment by executing: source /usr/httpd/htdocs_cs/courses/spring00/G22.2130-001/env-vals or by copying this file into your own directory and executing source env-vals which you might just do from you .login file. For reference, here is are its contents: setenv GCC_EXEC_PREFIX /usr/local/pkg/gnat-3.12p/lib/gcc-lib/sparc-sun-solaris2.5.1/2.8.1/ setenv ADA_INCLUDE_PATH /usr/local/pkg/gnat-3.12p/lib/gcc-lib/sparc-sun-solaris2.5.1/2.8.1/adainclude:/usr/local/pkg/gnat-3.12p/src/ada setenv ADA_OBJECTS_PATH /usr/local/pkg/gnat-3.12p/lib/gcc-lib/sparc-sun-solaris2.5.1/2.8.1/adalib setenv C_INCLUDE_PATH /usr/local/pkg/gnat-3.12p/lib/gcc-lib/sparc-sun-solaris2.5.1/2.8.1/include If you are working on your own installation at home, you need to use the names of the directories on you disk. GCC_EXEC_PREFIX is the directory that contains the compilation commands gnatmake, gcc, etc. ADA_INCLUDE_PATH has two components: the first is the adainclude directory, that includes the sources for the ada run-time components (e.g. IO routines). The second component is the directory that includes the sources of the compiler. This component is needed because the Tree_Walker program uses several components from the compiler itself. The typical Ada user does not need this. ADA_OBJECT_PATH is the adalib directory, that includes the binaries for the run-time libraries. C_INCLUDE_PATH is the include directory that contains the C header files neededffor the run-time. d) Go into the walk directory, and compile the tree-walker routine: gnatmake test_walker A number of .o files and .ali files will appear in that directory. These will be created the first time you build test_walker. You will notice that subsequent compilations will be much faster. e) place the example provided above into file tiny.ads f) Build the tree for this ada program: gcc -c -gnatt tiny.ads g) Run tree-walker on the tree file you just created: test_walker tiny.adt h) Modify the tree-walker routine and have it do something more useful. Apply it to a larger program.

File-Naming rules

A package specification appears in a file with extension .ads (ada specification), a package body appears in a file with extension .adb (ada body). The tree for any compilation unit appears in a file with extension .adt Note that tree files are not text files, you cannot edit them directly.

Command file

#!/bin/csh source ../env-vals gcc -c -gnatv -gnatt tiny.ads gnatmake -gnatv test_walker ./test_walker tiny.adt

Output of tree walker

spunky% ./test_walker tiny.ats Encountered Node Kind : N_COMPILATION_UNIT Encountered Node Kind : N_PACKAGE_DECLARATION Encountered Node Kind : N_PACKAGE_SPECIFICATION Encountered Node Kind : N_OBJECT_DECLARATION Encountered Node Kind : N_SUBPROGRAM_DECLARATION Declaration of foo found on Line 3 Encountered Node Kind : N_SUBPROGRAM_DECLARATION Declaration of bar found on Line 4