mirror of
https://github.com/autc04/Retro68.git
synced 2024-09-27 12:57:21 +00:00
2306 lines
67 KiB
Ada
2306 lines
67 KiB
Ada
------------------------------------------------------------------------------
|
|
-- --
|
|
-- GNAT COMPILER COMPONENTS --
|
|
-- --
|
|
-- T R E E P R --
|
|
-- --
|
|
-- B o d y --
|
|
-- --
|
|
-- Copyright (C) 1992-2022, Free Software Foundation, Inc. --
|
|
-- --
|
|
-- GNAT is free software; you can redistribute it and/or modify it under --
|
|
-- terms of the GNU General Public License as published by the Free Soft- --
|
|
-- ware Foundation; either version 3, or (at your option) any later ver- --
|
|
-- sion. GNAT is distributed in the hope that it will be useful, but WITH- --
|
|
-- OUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY --
|
|
-- or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License --
|
|
-- for more details. You should have received a copy of the GNU General --
|
|
-- Public License distributed with GNAT; see file COPYING3. If not, go to --
|
|
-- http://www.gnu.org/licenses for a complete copy of the license. --
|
|
-- --
|
|
-- GNAT was originally developed by the GNAT team at New York University. --
|
|
-- Extensive contributions were provided by Ada Core Technologies Inc. --
|
|
-- --
|
|
------------------------------------------------------------------------------
|
|
|
|
with Aspects; use Aspects;
|
|
with Atree; use Atree;
|
|
with Debug; use Debug;
|
|
with Einfo; use Einfo;
|
|
with Einfo.Entities; use Einfo.Entities;
|
|
with Einfo.Utils; use Einfo.Utils;
|
|
with Elists; use Elists;
|
|
with GNAT.Dynamic_HTables; use GNAT.Dynamic_HTables;
|
|
with Lib; use Lib;
|
|
with Namet; use Namet;
|
|
with Nlists; use Nlists;
|
|
with Output; use Output;
|
|
with Seinfo; use Seinfo;
|
|
with Sem_Eval; use Sem_Eval;
|
|
with Sinfo; use Sinfo;
|
|
with Sinfo.Nodes; use Sinfo.Nodes;
|
|
with Sinfo.Utils; use Sinfo.Utils;
|
|
with Snames; use Snames;
|
|
with Sinput; use Sinput;
|
|
with Stand; use Stand;
|
|
with Stringt; use Stringt;
|
|
with System.Case_Util; use System.Case_Util;
|
|
with SCIL_LL; use SCIL_LL;
|
|
with Uintp; use Uintp;
|
|
with Urealp; use Urealp;
|
|
with Uname; use Uname;
|
|
with Unchecked_Conversion;
|
|
|
|
package body Treepr is
|
|
|
|
----------------------------------
|
|
-- Approach Used for Tree Print --
|
|
----------------------------------
|
|
|
|
-- When a complete subtree is being printed, a trace phase first marks
|
|
-- the nodes and lists to be printed. This trace phase allocates logical
|
|
-- numbers corresponding to the order in which the nodes and lists will
|
|
-- be printed. The Node_Id, List_Id and Elist_Id values are mapped to
|
|
-- logical node numbers using a hash table. Output is done using a set
|
|
-- of Print_xxx routines, which are similar to the Write_xxx routines
|
|
-- with the same name, except that they do not generate any output in
|
|
-- the marking phase. This allows identical logic to be used in the
|
|
-- two phases.
|
|
|
|
-- Note that the hash table not only holds the serial numbers, but also
|
|
-- acts as a record of which nodes have already been visited. In the
|
|
-- marking phase, a node has been visited if it is already in the hash
|
|
-- table, and in the printing phase, we can tell whether a node has
|
|
-- already been printed by looking at the value of the serial number.
|
|
|
|
----------------------
|
|
-- Global Variables --
|
|
----------------------
|
|
|
|
Print_Low_Level_Info : Boolean := False with Warnings => Off;
|
|
-- Set True to print low-level information useful for debugging Atree and
|
|
-- the like.
|
|
|
|
function Hash (Key : Int) return GNAT.Bucket_Range_Type;
|
|
-- Simple Hash function for Node_Ids, List_Ids and Elist_Ids
|
|
|
|
procedure Destroy (Value : in out Nat) is null;
|
|
pragma Annotate (CodePeer, False_Positive, "unassigned parameter",
|
|
"in out parameter is required to instantiate generic");
|
|
-- Dummy routine for destroing hashed values
|
|
|
|
package Serial_Numbers is new Dynamic_Hash_Tables
|
|
(Key_Type => Int,
|
|
Value_Type => Nat,
|
|
No_Value => 0,
|
|
Expansion_Threshold => 1.5,
|
|
Expansion_Factor => 2,
|
|
Compression_Threshold => 0.3,
|
|
Compression_Factor => 2,
|
|
"=" => "=",
|
|
Destroy_Value => Destroy,
|
|
Hash => Hash);
|
|
-- Hash tables with dynamic resizing based on load factor. They provide
|
|
-- reasonable performance both when the printed AST is small (e.g. when
|
|
-- printing from debugger) and large (e.g. when printing with -gnatdt).
|
|
|
|
Hash_Table : Serial_Numbers.Dynamic_Hash_Table;
|
|
-- The hash table itself, see Serial_Number function for details of use
|
|
|
|
Next_Serial_Number : Nat;
|
|
-- Number of last visited node or list. Used during the marking phase to
|
|
-- set proper node numbers in the hash table, and during the printing
|
|
-- phase to make sure that a given node is not printed more than once.
|
|
-- (nodes are printed in order during the printing phase, that's the
|
|
-- point of numbering them in the first place).
|
|
|
|
Printing_Descendants : Boolean;
|
|
-- True if descendants are being printed, False if not. In the false case,
|
|
-- only node Id's are printed. In the true case, node numbers as well as
|
|
-- node Id's are printed, as described above.
|
|
|
|
type Phase_Type is (Marking, Printing);
|
|
-- Type for Phase variable
|
|
|
|
Phase : Phase_Type;
|
|
-- When an entire tree is being printed, the traversal operates in two
|
|
-- phases. The first phase marks the nodes in use by installing node
|
|
-- numbers in the node number table. The second phase prints the nodes.
|
|
-- This variable indicates the current phase.
|
|
|
|
----------------------
|
|
-- Local Procedures --
|
|
----------------------
|
|
|
|
function From_Union is new Unchecked_Conversion (Union_Id, Uint);
|
|
function From_Union is new Unchecked_Conversion (Union_Id, Ureal);
|
|
|
|
function To_Mixed (S : String) return String;
|
|
-- Turns an identifier into Mixed_Case. For bootstrap reasons, we cannot
|
|
-- use To_Mixed function from System.Case_Util.
|
|
|
|
function Image (F : Node_Or_Entity_Field) return String;
|
|
|
|
procedure Print_Init;
|
|
-- Initialize for printing of tree with descendants
|
|
|
|
procedure Print_End_Span (N : Node_Id);
|
|
-- Print contents of End_Span field of node N. The format includes the
|
|
-- implicit source location as well as the value of the field.
|
|
|
|
procedure Print_Term;
|
|
-- Clean up after printing of tree with descendants
|
|
|
|
procedure Print_Char (C : Character);
|
|
-- Print character C if currently in print phase, noop if in marking phase
|
|
|
|
procedure Print_Name (N : Name_Id);
|
|
-- Print name from names table if currently in print phase, noop if in
|
|
-- marking phase. Note that the name is output in mixed case mode.
|
|
|
|
procedure Print_Node_Header (N : Node_Id);
|
|
-- Print header line used by Print_Node and Print_Node_Briefly
|
|
|
|
procedure Print_Node_Kind (N : Node_Id);
|
|
-- Print node kind name in mixed case if in print phase, noop if in
|
|
-- marking phase.
|
|
|
|
procedure Print_Str (S : String);
|
|
-- Print string S if currently in print phase, noop if in marking phase
|
|
|
|
procedure Print_Str_Mixed_Case (S : String);
|
|
-- Like Print_Str, except that the string is printed in mixed case mode
|
|
|
|
procedure Print_Int (I : Int);
|
|
-- Print integer I if currently in print phase, noop if in marking phase
|
|
|
|
procedure Print_Eol;
|
|
-- Print end of line if currently in print phase, noop if in marking phase
|
|
|
|
procedure Print_Node_Ref (N : Node_Id);
|
|
-- Print "<empty>", "<error>" or "Node #nnn" with additional information
|
|
-- in the latter case, including the Id and the Nkind of the node.
|
|
|
|
procedure Print_List_Ref (L : List_Id);
|
|
-- Print "<no list>", or "<empty node list>" or "Node list #nnn"
|
|
|
|
procedure Print_Elist_Ref (E : Elist_Id);
|
|
-- Print "<no elist>", or "<empty element list>" or "Element list #nnn"
|
|
|
|
procedure Print_Entity_Info (Ent : Entity_Id; Prefix : String);
|
|
-- Called if the node being printed is an entity. Prints fields from the
|
|
-- extension, using routines in Einfo to get the field names and flags.
|
|
|
|
procedure Print_Field (Val : Union_Id; Format : UI_Format := Auto);
|
|
procedure Print_Field
|
|
(Prefix : String;
|
|
Field : String;
|
|
N : Node_Or_Entity_Id;
|
|
FD : Field_Descriptor;
|
|
Format : UI_Format);
|
|
-- Print representation of Field value (name, tree, string, uint, charcode)
|
|
-- The format parameter controls the format of printing in the case of an
|
|
-- integer value (see UI_Write for details).
|
|
|
|
procedure Print_Node_Field
|
|
(Prefix : String;
|
|
Field : Node_Field;
|
|
N : Node_Id;
|
|
FD : Field_Descriptor;
|
|
Format : UI_Format := Auto);
|
|
|
|
procedure Print_Entity_Field
|
|
(Prefix : String;
|
|
Field : Entity_Field;
|
|
N : Entity_Id;
|
|
FD : Field_Descriptor;
|
|
Format : UI_Format := Auto);
|
|
|
|
procedure Print_Flag (F : Boolean);
|
|
-- Print True or False
|
|
|
|
procedure Print_Node
|
|
(N : Node_Id;
|
|
Prefix_Str : String;
|
|
Prefix_Char : Character);
|
|
-- This is the internal routine used to print a single node. Each line of
|
|
-- output is preceded by Prefix_Str (which is used to set the indentation
|
|
-- level and the bars used to link list elements). In addition, for lines
|
|
-- other than the first, an additional character Prefix_Char is output.
|
|
|
|
function Serial_Number (Id : Int) return Nat;
|
|
-- Given a Node_Id, List_Id or Elist_Id, returns the previously assigned
|
|
-- serial number, or zero if no serial number has yet been assigned.
|
|
|
|
procedure Set_Serial_Number;
|
|
-- Can be called only immediately following a call to Serial_Number that
|
|
-- returned a value of zero. Causes the value of Next_Serial_Number to be
|
|
-- placed in the hash table (corresponding to the Id argument used in the
|
|
-- Serial_Number call), and increments Next_Serial_Number.
|
|
|
|
procedure Visit_Node
|
|
(N : Node_Id;
|
|
Prefix_Str : String;
|
|
Prefix_Char : Character);
|
|
-- Called to process a single node in the case where descendants are to
|
|
-- be printed before every line, and Prefix_Char added to all lines
|
|
-- except the header line for the node.
|
|
|
|
procedure Visit_List (L : List_Id; Prefix_Str : String);
|
|
-- Visit_List is called to process a list in the case where descendants
|
|
-- are to be printed. Prefix_Str is to be added to all printed lines.
|
|
|
|
procedure Visit_Elist (E : Elist_Id; Prefix_Str : String);
|
|
-- Visit_Elist is called to process an element list in the case where
|
|
-- descendants are to be printed. Prefix_Str is to be added to all
|
|
-- printed lines.
|
|
|
|
----------
|
|
-- Hash --
|
|
----------
|
|
|
|
function Hash (Key : Int) return GNAT.Bucket_Range_Type is
|
|
function Cast is new Unchecked_Conversion
|
|
(Source => Int, Target => GNAT.Bucket_Range_Type);
|
|
begin
|
|
return Cast (Key);
|
|
end Hash;
|
|
|
|
-----------
|
|
-- Image --
|
|
-----------
|
|
|
|
function Image (F : Node_Or_Entity_Field) return String is
|
|
begin
|
|
case F is
|
|
when F_Alloc_For_BIP_Return =>
|
|
return "Alloc_For_BIP_Return";
|
|
when F_Assignment_OK =>
|
|
return "Assignment_OK";
|
|
when F_Backwards_OK =>
|
|
return "Backwards_OK";
|
|
when F_Conversion_OK =>
|
|
return "Conversion_OK";
|
|
when F_Forwards_OK =>
|
|
return "Forwards_OK";
|
|
when F_Has_SP_Choice =>
|
|
return "Has_SP_Choice";
|
|
when F_Is_Elaboration_Checks_OK_Node =>
|
|
return "Is_Elaboration_Checks_OK_Node";
|
|
when F_Is_Elaboration_Warnings_OK_Node =>
|
|
return "Is_Elaboration_Warnings_OK_Node";
|
|
when F_Is_Known_Guaranteed_ABE =>
|
|
return "Is_Known_Guaranteed_ABE";
|
|
when F_Is_SPARK_Mode_On_Node =>
|
|
return "Is_SPARK_Mode_On_Node";
|
|
when F_Local_Raise_Not_OK =>
|
|
return "Local_Raise_Not_OK";
|
|
when F_SCIL_Controlling_Tag =>
|
|
return "SCIL_Controlling_Tag";
|
|
when F_SCIL_Entity =>
|
|
return "SCIL_Entity";
|
|
when F_SCIL_Tag_Value =>
|
|
return "SCIL_Tag_Value";
|
|
when F_SCIL_Target_Prim =>
|
|
return "SCIL_Target_Prim";
|
|
when F_Shift_Count_OK =>
|
|
return "Shift_Count_OK";
|
|
when F_Split_PPC =>
|
|
return "Split_PPC";
|
|
when F_TSS_Elist =>
|
|
return "TSS_Elist";
|
|
|
|
when F_BIP_Initialization_Call =>
|
|
return "BIP_Initialization_Call";
|
|
when F_Body_Needed_For_SAL =>
|
|
return "Body_Needed_For_SAL";
|
|
when F_CR_Discriminant =>
|
|
return "CR_Discriminant";
|
|
when F_DT_Entry_Count =>
|
|
return "DT_Entry_Count";
|
|
when F_DT_Offset_To_Top_Func =>
|
|
return "DT_Offset_To_Top_Func";
|
|
when F_DT_Position =>
|
|
return "DT_Position";
|
|
when F_DTC_Entity =>
|
|
return "DTC_Entity";
|
|
when F_Has_Inherited_DIC =>
|
|
return "Has_Inherited_DIC";
|
|
when F_Has_Own_DIC =>
|
|
return "Has_Own_DIC";
|
|
when F_Has_RACW =>
|
|
return "Has_RACW";
|
|
when F_Ignore_SPARK_Mode_Pragmas =>
|
|
return "Ignore_SPARK_Mode_Pragmas";
|
|
when F_Is_Constr_Subt_For_UN_Aliased =>
|
|
return "Is_Constr_Subt_For_UN_Aliased";
|
|
when F_Is_CPP_Class =>
|
|
return "Is_CPP_Class";
|
|
when F_Is_CUDA_Kernel =>
|
|
return "Is_CUDA_Kernel";
|
|
when F_Is_DIC_Procedure =>
|
|
return "Is_DIC_Procedure";
|
|
when F_Is_Discrim_SO_Function =>
|
|
return "Is_Discrim_SO_Function";
|
|
when F_Is_Elaboration_Checks_OK_Id =>
|
|
return "Is_Elaboration_Checks_OK_Id";
|
|
when F_Is_Elaboration_Warnings_OK_Id =>
|
|
return "Is_Elaboration_Warnings_OK_Id";
|
|
when F_Is_RACW_Stub_Type =>
|
|
return "Is_RACW_Stub_Type";
|
|
when F_LSP_Subprogram =>
|
|
return "LSP_Subprogram";
|
|
when F_OK_To_Rename =>
|
|
return "OK_To_Rename";
|
|
when F_Referenced_As_LHS =>
|
|
return "Referenced_As_LHS";
|
|
when F_RM_Size =>
|
|
return "RM_Size";
|
|
when F_SPARK_Aux_Pragma =>
|
|
return "SPARK_Aux_Pragma";
|
|
when F_SPARK_Aux_Pragma_Inherited =>
|
|
return "SPARK_Aux_Pragma_Inherited";
|
|
when F_SPARK_Pragma =>
|
|
return "SPARK_Pragma";
|
|
when F_SPARK_Pragma_Inherited =>
|
|
return "SPARK_Pragma_Inherited";
|
|
when F_SSO_Set_High_By_Default =>
|
|
return "SSO_Set_High_By_Default";
|
|
when F_SSO_Set_Low_By_Default =>
|
|
return "SSO_Set_Low_By_Default";
|
|
|
|
when others =>
|
|
declare
|
|
Result : constant String := To_Mixed (F'Img);
|
|
begin
|
|
return Result (3 .. Result'Last); -- Remove "F_"
|
|
end;
|
|
end case;
|
|
end Image;
|
|
|
|
-------
|
|
-- p --
|
|
-------
|
|
|
|
function p (N : Union_Id) return Node_Or_Entity_Id is
|
|
begin
|
|
case N is
|
|
when List_Low_Bound .. List_High_Bound - 1 =>
|
|
return Nlists.Parent (List_Id (N));
|
|
|
|
when Node_Range =>
|
|
return Parent (Node_Or_Entity_Id (N));
|
|
|
|
when others =>
|
|
Write_Int (Int (N));
|
|
Write_Str (" is not a Node_Id or List_Id value");
|
|
Write_Eol;
|
|
return Empty;
|
|
end case;
|
|
end p;
|
|
|
|
---------
|
|
-- par --
|
|
---------
|
|
|
|
function par (N : Union_Id) return Node_Or_Entity_Id renames p;
|
|
|
|
procedure ppar (N : Union_Id) is
|
|
begin
|
|
if N /= Empty_List_Or_Node then
|
|
pp (N);
|
|
ppar (Union_Id (p (N)));
|
|
end if;
|
|
end ppar;
|
|
|
|
--------
|
|
-- pe --
|
|
--------
|
|
|
|
procedure pe (N : Union_Id) renames pn;
|
|
|
|
--------
|
|
-- pl --
|
|
--------
|
|
|
|
procedure pl (L : Int) is
|
|
Lid : Int;
|
|
|
|
begin
|
|
Push_Output;
|
|
Set_Standard_Output;
|
|
|
|
if L < 0 then
|
|
Lid := L;
|
|
|
|
-- This is the case where we transform e.g. +36 to -99999936
|
|
|
|
else
|
|
if L <= 9 then
|
|
Lid := -(99999990 + L);
|
|
elsif L <= 99 then
|
|
Lid := -(99999900 + L);
|
|
elsif L <= 999 then
|
|
Lid := -(99999000 + L);
|
|
elsif L <= 9999 then
|
|
Lid := -(99990000 + L);
|
|
elsif L <= 99999 then
|
|
Lid := -(99900000 + L);
|
|
elsif L <= 999999 then
|
|
Lid := -(99000000 + L);
|
|
elsif L <= 9999999 then
|
|
Lid := -(90000000 + L);
|
|
else
|
|
Lid := -L;
|
|
end if;
|
|
end if;
|
|
|
|
-- Now output the list
|
|
|
|
Print_Tree_List (List_Id (Lid));
|
|
Pop_Output;
|
|
end pl;
|
|
|
|
--------
|
|
-- pn --
|
|
--------
|
|
|
|
procedure pn (N : Union_Id) is
|
|
begin
|
|
Push_Output;
|
|
Set_Standard_Output;
|
|
|
|
case N is
|
|
when List_Low_Bound .. List_High_Bound - 1 =>
|
|
pl (Int (N));
|
|
when Node_Range =>
|
|
Print_Tree_Node (Node_Id (N));
|
|
when Elist_Range =>
|
|
Print_Tree_Elist (Elist_Id (N));
|
|
when Elmt_Range =>
|
|
declare
|
|
Id : constant Elmt_Id := Elmt_Id (N);
|
|
begin
|
|
if No (Id) then
|
|
Write_Str ("No_Elmt");
|
|
Write_Eol;
|
|
else
|
|
Write_Str ("Elmt_Id --> ");
|
|
Print_Tree_Node (Node (Id));
|
|
end if;
|
|
end;
|
|
when Names_Range =>
|
|
Namet.wn (Name_Id (N));
|
|
when Strings_Range =>
|
|
Write_String_Table_Entry (String_Id (N));
|
|
when Uint_Range =>
|
|
Uintp.pid (From_Union (N));
|
|
when Ureal_Range =>
|
|
Urealp.pr (From_Union (N));
|
|
when others =>
|
|
Write_Str ("Invalid Union_Id: ");
|
|
Write_Int (Int (N));
|
|
Write_Eol;
|
|
end case;
|
|
|
|
Pop_Output;
|
|
end pn;
|
|
|
|
--------
|
|
-- pp --
|
|
--------
|
|
|
|
procedure pp (N : Union_Id) renames pn;
|
|
|
|
---------
|
|
-- ppp --
|
|
---------
|
|
|
|
procedure ppp (N : Union_Id) renames pt;
|
|
|
|
----------------
|
|
-- Print_Char --
|
|
----------------
|
|
|
|
procedure Print_Char (C : Character) is
|
|
begin
|
|
if Phase = Printing then
|
|
Write_Char (C);
|
|
end if;
|
|
end Print_Char;
|
|
|
|
---------------------
|
|
-- Print_Elist_Ref --
|
|
---------------------
|
|
|
|
procedure Print_Elist_Ref (E : Elist_Id) is
|
|
begin
|
|
if Phase /= Printing then
|
|
return;
|
|
end if;
|
|
|
|
if E = No_Elist then
|
|
Write_Str ("<no elist>");
|
|
|
|
elsif Is_Empty_Elmt_List (E) then
|
|
Write_Str ("Empty elist, (Elist_Id=");
|
|
Write_Int (Int (E));
|
|
Write_Char (')');
|
|
|
|
else
|
|
Write_Str ("(Elist_Id=");
|
|
Write_Int (Int (E));
|
|
Write_Char (')');
|
|
|
|
if Printing_Descendants then
|
|
Write_Str (" #");
|
|
Write_Int (Serial_Number (Int (E)));
|
|
end if;
|
|
end if;
|
|
end Print_Elist_Ref;
|
|
|
|
-------------------------
|
|
-- Print_Elist_Subtree --
|
|
-------------------------
|
|
|
|
procedure Print_Elist_Subtree (E : Elist_Id) is
|
|
begin
|
|
Print_Init;
|
|
|
|
Next_Serial_Number := 1;
|
|
Phase := Marking;
|
|
Visit_Elist (E, "");
|
|
|
|
Next_Serial_Number := 1;
|
|
Phase := Printing;
|
|
Visit_Elist (E, "");
|
|
|
|
Print_Term;
|
|
end Print_Elist_Subtree;
|
|
|
|
--------------------
|
|
-- Print_End_Span --
|
|
--------------------
|
|
|
|
procedure Print_End_Span (N : Node_Id) is
|
|
Val : constant Uint := End_Span (N);
|
|
|
|
begin
|
|
UI_Write (Val);
|
|
Write_Str (" (Uint = ");
|
|
Write_Str (UI_Image (Val));
|
|
Write_Str (") ");
|
|
|
|
if Present (Val) then
|
|
Write_Location (End_Location (N));
|
|
end if;
|
|
end Print_End_Span;
|
|
|
|
-----------------------
|
|
-- Print_Entity_Info --
|
|
-----------------------
|
|
|
|
procedure Print_Entity_Info (Ent : Entity_Id; Prefix : String) is
|
|
begin
|
|
Print_Str (Prefix);
|
|
Print_Str ("Ekind = ");
|
|
Print_Str_Mixed_Case (Entity_Kind'Image (Ekind (Ent)));
|
|
Print_Eol;
|
|
|
|
Print_Str (Prefix);
|
|
Print_Str ("Etype = ");
|
|
Print_Node_Ref (Etype (Ent));
|
|
Print_Eol;
|
|
|
|
if Convention (Ent) /= Convention_Ada then
|
|
Print_Str (Prefix);
|
|
Print_Str ("Convention = ");
|
|
|
|
-- Print convention name skipping the Convention_ at the start
|
|
|
|
declare
|
|
S : constant String := Convention_Id'Image (Convention (Ent));
|
|
|
|
begin
|
|
Print_Str_Mixed_Case (S (12 .. S'Last));
|
|
Print_Eol;
|
|
end;
|
|
end if;
|
|
|
|
declare
|
|
Fields : Entity_Field_Array renames
|
|
Entity_Field_Table (Ekind (Ent)).all;
|
|
Should_Print : constant Entity_Field_Set :=
|
|
-- Set of fields that should be printed. False for fields that were
|
|
-- already printed above.
|
|
(F_Ekind
|
|
| F_Basic_Convention => False, -- Convention was printed
|
|
others => True);
|
|
begin
|
|
-- Outer loop makes flags come out last
|
|
|
|
for Print_Flags in Boolean loop
|
|
for Field_Index in Fields'Range loop
|
|
declare
|
|
FD : Field_Descriptor renames
|
|
Field_Descriptors (Fields (Field_Index));
|
|
begin
|
|
if Should_Print (Fields (Field_Index))
|
|
and then (FD.Kind = Flag_Field) = Print_Flags
|
|
then
|
|
Print_Entity_Field
|
|
(Prefix, Fields (Field_Index), Ent, FD);
|
|
end if;
|
|
end;
|
|
end loop;
|
|
end loop;
|
|
end;
|
|
end Print_Entity_Info;
|
|
|
|
---------------
|
|
-- Print_Eol --
|
|
---------------
|
|
|
|
procedure Print_Eol is
|
|
begin
|
|
if Phase = Printing then
|
|
Write_Eol;
|
|
end if;
|
|
end Print_Eol;
|
|
|
|
-----------------
|
|
-- Print_Field --
|
|
-----------------
|
|
|
|
-- Instantiations of low-level getters and setters that take offsets
|
|
-- in units of the size of the field.
|
|
|
|
use Atree.Atree_Private_Part;
|
|
|
|
function Get_Flag is new Get_1_Bit_Field
|
|
(Boolean) with Inline;
|
|
|
|
function Get_Node_Id is new Get_32_Bit_Field
|
|
(Node_Id) with Inline;
|
|
|
|
function Get_List_Id is new Get_32_Bit_Field
|
|
(List_Id) with Inline;
|
|
|
|
function Get_Elist_Id is new Get_32_Bit_Field_With_Default
|
|
(Elist_Id, No_Elist) with Inline;
|
|
|
|
function Get_Name_Id is new Get_32_Bit_Field
|
|
(Name_Id) with Inline;
|
|
|
|
function Get_String_Id is new Get_32_Bit_Field
|
|
(String_Id) with Inline;
|
|
|
|
function Get_Uint is new Get_32_Bit_Field_With_Default
|
|
(Uint, Uint_0) with Inline;
|
|
|
|
function Get_Valid_Uint is new Get_32_Bit_Field
|
|
(Uint) with Inline;
|
|
-- Used for both Valid_Uint and other subtypes of Uint. Note that we don't
|
|
-- instantiate Get_Valid_32_Bit_Field; we don't want to blow up if the
|
|
-- value is wrong.
|
|
|
|
function Get_Ureal is new Get_32_Bit_Field
|
|
(Ureal) with Inline;
|
|
|
|
function Get_Node_Kind_Type is new Get_8_Bit_Field
|
|
(Node_Kind) with Inline;
|
|
|
|
function Get_Entity_Kind_Type is new Get_8_Bit_Field
|
|
(Entity_Kind) with Inline;
|
|
|
|
function Get_Source_Ptr is new Get_32_Bit_Field
|
|
(Source_Ptr) with Inline, Unreferenced;
|
|
|
|
function Get_Small_Paren_Count_Type is new Get_2_Bit_Field
|
|
(Small_Paren_Count_Type) with Inline, Unreferenced;
|
|
|
|
function Get_Union_Id is new Get_32_Bit_Field
|
|
(Union_Id) with Inline;
|
|
|
|
function Get_Convention_Id is new Get_8_Bit_Field
|
|
(Convention_Id) with Inline, Unreferenced;
|
|
|
|
function Get_Mechanism_Type is new Get_32_Bit_Field
|
|
(Mechanism_Type) with Inline, Unreferenced;
|
|
|
|
procedure Print_Field (Val : Union_Id; Format : UI_Format := Auto) is
|
|
begin
|
|
if Phase /= Printing then
|
|
return;
|
|
end if;
|
|
|
|
if Val in Node_Range then
|
|
Print_Node_Ref (Node_Id (Val));
|
|
|
|
elsif Val in List_Range then
|
|
Print_List_Ref (List_Id (Val));
|
|
|
|
elsif Val in Elist_Range then
|
|
Print_Elist_Ref (Elist_Id (Val));
|
|
|
|
elsif Val in Names_Range then
|
|
Print_Name (Name_Id (Val));
|
|
Write_Str (" (Name_Id=");
|
|
Write_Int (Int (Val));
|
|
Write_Char (')');
|
|
|
|
elsif Val in Strings_Range then
|
|
Write_String_Table_Entry (String_Id (Val));
|
|
Write_Str (" (String_Id=");
|
|
Write_Int (Int (Val));
|
|
Write_Char (')');
|
|
|
|
elsif Val in Uint_Range then
|
|
UI_Write (From_Union (Val), Format);
|
|
Write_Str (" (Uint = ");
|
|
Write_Int (Int (Val));
|
|
Write_Char (')');
|
|
|
|
elsif Val in Ureal_Range then
|
|
UR_Write (From_Union (Val));
|
|
Write_Str (" (Ureal = ");
|
|
Write_Int (Int (Val));
|
|
Write_Char (')');
|
|
|
|
else
|
|
Print_Str ("****** Incorrect value = ");
|
|
Print_Int (Int (Val));
|
|
end if;
|
|
end Print_Field;
|
|
|
|
procedure Print_Field
|
|
(Prefix : String;
|
|
Field : String;
|
|
N : Node_Or_Entity_Id;
|
|
FD : Field_Descriptor;
|
|
Format : UI_Format)
|
|
is
|
|
Printed : Boolean := False;
|
|
|
|
procedure Print_Initial;
|
|
-- Print the initial stuff that goes before the value
|
|
|
|
-------------------
|
|
-- Print_Initial --
|
|
-------------------
|
|
|
|
procedure Print_Initial is
|
|
begin
|
|
Printed := True;
|
|
Print_Str (Prefix);
|
|
Print_Str (Field);
|
|
|
|
if Print_Low_Level_Info then
|
|
Write_Str (" at ");
|
|
Write_Int (Int (FD.Offset));
|
|
end if;
|
|
|
|
Write_Str (" = ");
|
|
end Print_Initial;
|
|
|
|
-- Start of processing for Print_Field
|
|
|
|
begin
|
|
if Phase /= Printing then
|
|
return;
|
|
end if;
|
|
|
|
case FD.Kind is
|
|
when Flag_Field =>
|
|
declare
|
|
Val : constant Boolean := Get_Flag (N, FD.Offset);
|
|
begin
|
|
if Val then
|
|
Print_Initial;
|
|
Print_Flag (Val);
|
|
end if;
|
|
end;
|
|
|
|
when Node_Id_Field =>
|
|
declare
|
|
Val : constant Node_Id := Get_Node_Id (N, FD.Offset);
|
|
begin
|
|
if Present (Val) then
|
|
Print_Initial;
|
|
Print_Node_Ref (Val);
|
|
end if;
|
|
end;
|
|
|
|
when List_Id_Field =>
|
|
declare
|
|
Val : constant List_Id := Get_List_Id (N, FD.Offset);
|
|
begin
|
|
if Present (Val) then
|
|
Print_Initial;
|
|
Print_List_Ref (Val);
|
|
end if;
|
|
end;
|
|
|
|
when Elist_Id_Field =>
|
|
declare
|
|
Val : constant Elist_Id := Get_Elist_Id (N, FD.Offset);
|
|
begin
|
|
if Present (Val) then
|
|
Print_Initial;
|
|
Print_Elist_Ref (Val);
|
|
end if;
|
|
end;
|
|
|
|
when Name_Id_Field =>
|
|
declare
|
|
Val : constant Name_Id := Get_Name_Id (N, FD.Offset);
|
|
begin
|
|
if Present (Val) then
|
|
Print_Initial;
|
|
Print_Name (Val);
|
|
Write_Str (" (Name_Id=");
|
|
Write_Int (Int (Val));
|
|
Write_Char (')');
|
|
end if;
|
|
end;
|
|
|
|
when String_Id_Field =>
|
|
declare
|
|
Val : constant String_Id := Get_String_Id (N, FD.Offset);
|
|
begin
|
|
if Val /= No_String then
|
|
Print_Initial;
|
|
Write_String_Table_Entry (Val);
|
|
Write_Str (" (String_Id=");
|
|
Write_Int (Int (Val));
|
|
Write_Char (')');
|
|
end if;
|
|
end;
|
|
|
|
when Uint_Field =>
|
|
declare
|
|
Val : constant Uint := Get_Uint (N, FD.Offset);
|
|
function Cast is new Unchecked_Conversion (Uint, Int);
|
|
begin
|
|
if Present (Val) then
|
|
Print_Initial;
|
|
UI_Write (Val, Format);
|
|
Write_Str (" (Uint = ");
|
|
Write_Int (Cast (Val));
|
|
Write_Char (')');
|
|
end if;
|
|
end;
|
|
|
|
when Valid_Uint_Field | Unat_Field | Upos_Field
|
|
| Nonzero_Uint_Field =>
|
|
declare
|
|
Val : constant Uint := Get_Valid_Uint (N, FD.Offset);
|
|
function Cast is new Unchecked_Conversion (Uint, Int);
|
|
begin
|
|
Print_Initial;
|
|
UI_Write (Val, Format);
|
|
|
|
case FD.Kind is
|
|
when Valid_Uint_Field => Write_Str (" v");
|
|
when Unat_Field => Write_Str (" n");
|
|
when Upos_Field => Write_Str (" p");
|
|
when Nonzero_Uint_Field => Write_Str (" nz");
|
|
when others => raise Program_Error;
|
|
end case;
|
|
|
|
Write_Str (" (Uint = ");
|
|
Write_Int (Cast (Val));
|
|
Write_Char (')');
|
|
end;
|
|
|
|
when Ureal_Field =>
|
|
declare
|
|
Val : constant Ureal := Get_Ureal (N, FD.Offset);
|
|
function Cast is new Unchecked_Conversion (Ureal, Int);
|
|
begin
|
|
if Val /= No_Ureal then
|
|
Print_Initial;
|
|
UR_Write (Val);
|
|
Write_Str (" (Ureal = ");
|
|
Write_Int (Cast (Val));
|
|
Write_Char (')');
|
|
end if;
|
|
end;
|
|
|
|
when Node_Kind_Type_Field =>
|
|
declare
|
|
Val : constant Node_Kind := Get_Node_Kind_Type (N, FD.Offset);
|
|
begin
|
|
Print_Initial;
|
|
Print_Str_Mixed_Case (Node_Kind'Image (Val));
|
|
end;
|
|
|
|
when Entity_Kind_Type_Field =>
|
|
declare
|
|
Val : constant Entity_Kind :=
|
|
Get_Entity_Kind_Type (N, FD.Offset);
|
|
begin
|
|
Print_Initial;
|
|
Print_Str_Mixed_Case (Entity_Kind'Image (Val));
|
|
end;
|
|
|
|
when Union_Id_Field =>
|
|
declare
|
|
Val : constant Union_Id := Get_Union_Id (N, FD.Offset);
|
|
begin
|
|
if Val /= Empty_List_Or_Node then
|
|
Print_Initial;
|
|
|
|
if Val in Node_Range then
|
|
Print_Node_Ref (Node_Id (Val));
|
|
|
|
elsif Val in List_Range then
|
|
Print_List_Ref (List_Id (Val));
|
|
|
|
else
|
|
Print_Str ("<invalid union id>");
|
|
end if;
|
|
end if;
|
|
end;
|
|
|
|
when others =>
|
|
Print_Initial;
|
|
Print_Str ("<unknown ");
|
|
Print_Str (Field_Kind'Image (FD.Kind));
|
|
Print_Str (">");
|
|
end case;
|
|
|
|
if Printed then
|
|
Print_Eol;
|
|
end if;
|
|
|
|
-- If an exception is raised while printing, we try to print some low-level
|
|
-- information that is useful for debugging.
|
|
|
|
exception
|
|
when others =>
|
|
declare
|
|
function Cast is new Unchecked_Conversion (Field_Size_32_Bit, Int);
|
|
begin
|
|
Write_Eol;
|
|
Print_Initial;
|
|
Write_Str ("exception raised in Print_Field -- int val = ");
|
|
Write_Eol;
|
|
|
|
case Field_Size (FD.Kind) is
|
|
when 1 => Write_Int (Int (Get_1_Bit_Val (N, FD.Offset)));
|
|
when 2 => Write_Int (Int (Get_2_Bit_Val (N, FD.Offset)));
|
|
when 4 => Write_Int (Int (Get_4_Bit_Val (N, FD.Offset)));
|
|
when 8 => Write_Int (Int (Get_8_Bit_Val (N, FD.Offset)));
|
|
when others => -- 32
|
|
Write_Int (Cast (Get_32_Bit_Val (N, FD.Offset)));
|
|
end case;
|
|
|
|
Write_Str (", ");
|
|
Write_Str (FD.Kind'Img);
|
|
Write_Str (" ");
|
|
Write_Int (Int (Field_Size (FD.Kind)));
|
|
Write_Str (" bits");
|
|
Write_Eol;
|
|
exception
|
|
when others =>
|
|
Write_Eol;
|
|
Write_Str ("double exception raised in Print_Field");
|
|
Write_Eol;
|
|
end;
|
|
end Print_Field;
|
|
|
|
----------------------
|
|
-- Print_Node_Field --
|
|
----------------------
|
|
|
|
procedure Print_Node_Field
|
|
(Prefix : String;
|
|
Field : Node_Field;
|
|
N : Node_Id;
|
|
FD : Field_Descriptor;
|
|
Format : UI_Format := Auto)
|
|
is
|
|
pragma Assert (FD.Type_Only = No_Type_Only);
|
|
-- Type_Only is for entities
|
|
begin
|
|
if not Field_Is_Initial_Zero (N, Field) then
|
|
Print_Field (Prefix, Image (Field), N, FD, Format);
|
|
end if;
|
|
end Print_Node_Field;
|
|
|
|
------------------------
|
|
-- Print_Entity_Field --
|
|
------------------------
|
|
|
|
procedure Print_Entity_Field
|
|
(Prefix : String;
|
|
Field : Entity_Field;
|
|
N : Entity_Id;
|
|
FD : Field_Descriptor;
|
|
Format : UI_Format := Auto)
|
|
is
|
|
NN : constant Node_Id := Node_To_Fetch_From (N, Field);
|
|
begin
|
|
if not Field_Is_Initial_Zero (N, Field) then
|
|
Print_Field (Prefix, Image (Field), NN, FD, Format);
|
|
end if;
|
|
end Print_Entity_Field;
|
|
|
|
----------------
|
|
-- Print_Flag --
|
|
----------------
|
|
|
|
procedure Print_Flag (F : Boolean) is
|
|
begin
|
|
if F then
|
|
Print_Str ("True");
|
|
else
|
|
Print_Str ("False");
|
|
end if;
|
|
end Print_Flag;
|
|
|
|
----------------
|
|
-- Print_Init --
|
|
----------------
|
|
|
|
procedure Print_Init is
|
|
begin
|
|
Printing_Descendants := True;
|
|
Write_Eol;
|
|
|
|
pragma Assert (not Serial_Numbers.Present (Hash_Table));
|
|
Hash_Table := Serial_Numbers.Create (512);
|
|
end Print_Init;
|
|
|
|
---------------
|
|
-- Print_Int --
|
|
---------------
|
|
|
|
procedure Print_Int (I : Int) is
|
|
begin
|
|
if Phase = Printing then
|
|
Write_Int (I);
|
|
end if;
|
|
end Print_Int;
|
|
|
|
--------------------
|
|
-- Print_List_Ref --
|
|
--------------------
|
|
|
|
procedure Print_List_Ref (L : List_Id) is
|
|
begin
|
|
if Phase /= Printing then
|
|
return;
|
|
end if;
|
|
|
|
if No (L) then
|
|
Write_Str ("<no list>");
|
|
|
|
elsif Is_Empty_List (L) then
|
|
Write_Str ("<empty list> (List_Id=");
|
|
Write_Int (Int (L));
|
|
Write_Char (')');
|
|
|
|
else
|
|
Write_Str ("List");
|
|
|
|
if Printing_Descendants then
|
|
Write_Str (" #");
|
|
Write_Int (Serial_Number (Int (L)));
|
|
end if;
|
|
|
|
Write_Str (" (List_Id=");
|
|
Write_Int (Int (L));
|
|
Write_Char (')');
|
|
end if;
|
|
end Print_List_Ref;
|
|
|
|
------------------------
|
|
-- Print_List_Subtree --
|
|
------------------------
|
|
|
|
procedure Print_List_Subtree (L : List_Id) is
|
|
begin
|
|
Print_Init;
|
|
|
|
Next_Serial_Number := 1;
|
|
Phase := Marking;
|
|
Visit_List (L, "");
|
|
|
|
Next_Serial_Number := 1;
|
|
Phase := Printing;
|
|
Visit_List (L, "");
|
|
|
|
Print_Term;
|
|
end Print_List_Subtree;
|
|
|
|
----------------
|
|
-- Print_Name --
|
|
----------------
|
|
|
|
procedure Print_Name (N : Name_Id) is
|
|
begin
|
|
if Phase = Printing then
|
|
if N = No_Name then
|
|
Print_Str ("<No_Name>");
|
|
|
|
elsif N = Error_Name then
|
|
Print_Str ("<Error_Name>");
|
|
|
|
elsif Is_Valid_Name (N) then
|
|
Get_Name_String (N);
|
|
Print_Char ('"');
|
|
Write_Name (N);
|
|
Print_Char ('"');
|
|
|
|
else
|
|
Print_Str ("<invalid name>");
|
|
end if;
|
|
end if;
|
|
end Print_Name;
|
|
|
|
----------------
|
|
-- Print_Node --
|
|
----------------
|
|
|
|
procedure Print_Node
|
|
(N : Node_Id;
|
|
Prefix_Str : String;
|
|
Prefix_Char : Character)
|
|
is
|
|
Prefix : constant String := Prefix_Str & Prefix_Char;
|
|
|
|
Sfile : Source_File_Index;
|
|
|
|
begin
|
|
if Phase /= Printing then
|
|
return;
|
|
end if;
|
|
|
|
-- If there is no such node, indicate that. Skip the rest, so we don't
|
|
-- crash getting fields of the nonexistent node.
|
|
|
|
if not Is_Valid_Node (Union_Id (N)) then
|
|
Print_Str ("No such node: ");
|
|
Print_Int (Int (N));
|
|
Print_Eol;
|
|
return;
|
|
end if;
|
|
|
|
-- Print header line
|
|
|
|
Print_Str (Prefix_Str);
|
|
Print_Node_Header (N);
|
|
|
|
if Is_Rewrite_Substitution (N) then
|
|
Print_Str (Prefix_Str);
|
|
Print_Str (" Rewritten: original node = ");
|
|
Print_Node_Ref (Original_Node (N));
|
|
Print_Eol;
|
|
end if;
|
|
|
|
if Print_Low_Level_Info then
|
|
Print_Atree_Info (N);
|
|
end if;
|
|
|
|
if N = Empty then
|
|
return;
|
|
end if;
|
|
|
|
if not Is_List_Member (N) then
|
|
Print_Str (Prefix_Str);
|
|
Print_Str (" Parent = ");
|
|
Print_Node_Ref (Parent (N));
|
|
Print_Eol;
|
|
end if;
|
|
|
|
-- Print Sloc field if it is set
|
|
|
|
if Sloc (N) /= No_Location then
|
|
Print_Str (Prefix);
|
|
Print_Str ("Sloc = ");
|
|
|
|
if Sloc (N) = Standard_Location then
|
|
Print_Str ("Standard_Location");
|
|
|
|
elsif Sloc (N) = Standard_ASCII_Location then
|
|
Print_Str ("Standard_ASCII_Location");
|
|
|
|
else
|
|
Sfile := Get_Source_File_Index (Sloc (N));
|
|
Print_Int (Int (Sloc (N)) - Int (Source_Text (Sfile)'First));
|
|
Write_Str (" ");
|
|
Write_Location (Sloc (N));
|
|
end if;
|
|
|
|
Print_Eol;
|
|
end if;
|
|
|
|
-- Print Chars field if present
|
|
|
|
if Nkind (N) in N_Has_Chars then
|
|
if Field_Is_Initial_Zero (N, F_Chars) then
|
|
Print_Str (Prefix);
|
|
Print_Str ("Chars = initial zero");
|
|
Print_Eol;
|
|
|
|
elsif Chars (N) /= No_Name then
|
|
Print_Str (Prefix);
|
|
Print_Str ("Chars = ");
|
|
Print_Name (Chars (N));
|
|
Write_Str (" (Name_Id=");
|
|
Write_Int (Int (Chars (N)));
|
|
Write_Char (')');
|
|
Print_Eol;
|
|
end if;
|
|
end if;
|
|
|
|
-- Special field print operations for non-entity nodes
|
|
|
|
if Nkind (N) not in N_Entity then
|
|
|
|
-- Deal with Left_Opnd and Right_Opnd fields
|
|
|
|
if Nkind (N) in N_Op
|
|
or else Nkind (N) in N_Short_Circuit
|
|
or else Nkind (N) in N_Membership_Test
|
|
then
|
|
-- Print Left_Opnd if present
|
|
|
|
if Nkind (N) not in N_Unary_Op then
|
|
Print_Str (Prefix);
|
|
Print_Str ("Left_Opnd = ");
|
|
Print_Node_Ref (Left_Opnd (N));
|
|
Print_Eol;
|
|
end if;
|
|
|
|
-- Print Right_Opnd
|
|
|
|
Print_Str (Prefix);
|
|
Print_Str ("Right_Opnd = ");
|
|
Print_Node_Ref (Right_Opnd (N));
|
|
Print_Eol;
|
|
end if;
|
|
|
|
-- Deal with Entity_Or_Associated_Node. If N has both, then just
|
|
-- print Entity; they are the same thing.
|
|
|
|
if N in N_Inclusive_Has_Entity and then Present (Entity (N)) then
|
|
Print_Str (Prefix);
|
|
Print_Str ("Entity = ");
|
|
Print_Node_Ref (Entity (N));
|
|
Print_Eol;
|
|
|
|
elsif N in N_Has_Associated_Node
|
|
and then Present (Associated_Node (N))
|
|
then
|
|
Print_Str (Prefix);
|
|
Print_Str ("Associated_Node = ");
|
|
Print_Node_Ref (Associated_Node (N));
|
|
Print_Eol;
|
|
end if;
|
|
|
|
-- Print special fields if we have a subexpression
|
|
|
|
if Nkind (N) in N_Subexpr then
|
|
|
|
if Assignment_OK (N) then
|
|
Print_Str (Prefix);
|
|
Print_Str ("Assignment_OK = True");
|
|
Print_Eol;
|
|
end if;
|
|
|
|
if Do_Range_Check (N) then
|
|
Print_Str (Prefix);
|
|
Print_Str ("Do_Range_Check = True");
|
|
Print_Eol;
|
|
end if;
|
|
|
|
if Has_Dynamic_Length_Check (N) then
|
|
Print_Str (Prefix);
|
|
Print_Str ("Has_Dynamic_Length_Check = True");
|
|
Print_Eol;
|
|
end if;
|
|
|
|
if Has_Aspects (N) then
|
|
Print_Str (Prefix);
|
|
Print_Str ("Has_Aspects = True");
|
|
Print_Eol;
|
|
end if;
|
|
|
|
if Is_Controlling_Actual (N) then
|
|
Print_Str (Prefix);
|
|
Print_Str ("Is_Controlling_Actual = True");
|
|
Print_Eol;
|
|
end if;
|
|
|
|
if Is_Overloaded (N) then
|
|
Print_Str (Prefix);
|
|
Print_Str ("Is_Overloaded = True");
|
|
Print_Eol;
|
|
end if;
|
|
|
|
if Is_Static_Expression (N) then
|
|
Print_Str (Prefix);
|
|
Print_Str ("Is_Static_Expression = True");
|
|
Print_Eol;
|
|
end if;
|
|
|
|
if Must_Not_Freeze (N) then
|
|
Print_Str (Prefix);
|
|
Print_Str ("Must_Not_Freeze = True");
|
|
Print_Eol;
|
|
end if;
|
|
|
|
if Paren_Count (N) /= 0 then
|
|
Print_Str (Prefix);
|
|
Print_Str ("Paren_Count = ");
|
|
Print_Int (Int (Paren_Count (N)));
|
|
Print_Eol;
|
|
end if;
|
|
|
|
if Raises_Constraint_Error (N) then
|
|
Print_Str (Prefix);
|
|
Print_Str ("Raises_Constraint_Error = True");
|
|
Print_Eol;
|
|
end if;
|
|
|
|
end if;
|
|
|
|
-- Print Do_Overflow_Check field if present
|
|
|
|
if Nkind (N) in N_Op and then Do_Overflow_Check (N) then
|
|
Print_Str (Prefix);
|
|
Print_Str ("Do_Overflow_Check = True");
|
|
Print_Eol;
|
|
end if;
|
|
|
|
-- Print Etype field if present (printing of this field for entities
|
|
-- is handled by the Print_Entity_Info procedure).
|
|
|
|
if Nkind (N) in N_Has_Etype and then Present (Etype (N)) then
|
|
Print_Str (Prefix);
|
|
Print_Str ("Etype = ");
|
|
Print_Node_Ref (Etype (N));
|
|
Print_Eol;
|
|
end if;
|
|
end if;
|
|
|
|
declare
|
|
Fields : Node_Field_Array renames Node_Field_Table (Nkind (N)).all;
|
|
Should_Print : constant Node_Field_Set :=
|
|
-- Set of fields that should be printed. False for fields that were
|
|
-- already printed above, and for In_List, which we don't bother
|
|
-- printing.
|
|
(F_Nkind
|
|
| F_Chars
|
|
| F_Comes_From_Source
|
|
| F_Analyzed
|
|
| F_Error_Posted
|
|
| F_Is_Ignored_Ghost_Node
|
|
| F_Check_Actuals
|
|
| F_Link -- Parent was printed
|
|
| F_Sloc
|
|
| F_Left_Opnd
|
|
| F_Right_Opnd
|
|
| F_Entity_Or_Associated_Node -- one of them was printed
|
|
| F_Assignment_OK
|
|
| F_Do_Range_Check
|
|
| F_Has_Dynamic_Length_Check
|
|
| F_Has_Aspects
|
|
| F_Is_Controlling_Actual
|
|
| F_Is_Overloaded
|
|
| F_Is_Static_Expression
|
|
| F_Must_Not_Freeze
|
|
| F_Small_Paren_Count -- Paren_Count was printed
|
|
| F_Raises_Constraint_Error
|
|
| F_Do_Overflow_Check
|
|
| F_Etype
|
|
| F_In_List
|
|
=> False,
|
|
|
|
others => True);
|
|
|
|
Fmt : constant UI_Format :=
|
|
(if Nkind (N) = N_Integer_Literal and then Print_In_Hex (N)
|
|
then Hex
|
|
else Auto);
|
|
|
|
begin
|
|
-- Outer loop makes flags come out last
|
|
|
|
for Print_Flags in Boolean loop
|
|
for Field_Index in Fields'Range loop
|
|
declare
|
|
FD : Field_Descriptor renames
|
|
Field_Descriptors (Fields (Field_Index));
|
|
begin
|
|
if Should_Print (Fields (Field_Index))
|
|
and then (FD.Kind = Flag_Field) = Print_Flags
|
|
then
|
|
-- Special case for End_Span, which also prints the
|
|
-- End_Location.
|
|
|
|
if Fields (Field_Index) = F_End_Span then
|
|
Print_End_Span (N);
|
|
|
|
else
|
|
Print_Node_Field
|
|
(Prefix, Fields (Field_Index), N, FD, Fmt);
|
|
end if;
|
|
end if;
|
|
end;
|
|
end loop;
|
|
end loop;
|
|
end;
|
|
|
|
-- Print aspects if present
|
|
|
|
if Has_Aspects (N) then
|
|
Print_Str (Prefix);
|
|
Print_Str ("Aspect_Specifications = ");
|
|
Print_Field (Union_Id (Aspect_Specifications (N)));
|
|
Print_Eol;
|
|
end if;
|
|
|
|
-- Print entity information for entities
|
|
|
|
if Nkind (N) in N_Entity then
|
|
Print_Entity_Info (N, Prefix);
|
|
end if;
|
|
|
|
-- Print the SCIL node (if available)
|
|
|
|
if Present (Get_SCIL_Node (N)) then
|
|
Print_Str (Prefix);
|
|
Print_Str ("SCIL_Node = ");
|
|
Print_Node_Ref (Get_SCIL_Node (N));
|
|
Print_Eol;
|
|
end if;
|
|
end Print_Node;
|
|
|
|
------------------------
|
|
-- Print_Node_Briefly --
|
|
------------------------
|
|
|
|
procedure Print_Node_Briefly (N : Node_Id) is
|
|
begin
|
|
Printing_Descendants := False;
|
|
Phase := Printing;
|
|
Print_Node_Header (N);
|
|
end Print_Node_Briefly;
|
|
|
|
-----------------------
|
|
-- Print_Node_Header --
|
|
-----------------------
|
|
|
|
procedure Print_Node_Header (N : Node_Id) is
|
|
Enumerate : Boolean := False;
|
|
-- Flag set when enumerating multiple header flags
|
|
|
|
procedure Print_Header_Flag (Flag : String);
|
|
-- Output one of the flags that appears in a node header. The routine
|
|
-- automatically handles enumeration of multiple flags.
|
|
|
|
-----------------------
|
|
-- Print_Header_Flag --
|
|
-----------------------
|
|
|
|
procedure Print_Header_Flag (Flag : String) is
|
|
begin
|
|
if Enumerate then
|
|
Print_Char (',');
|
|
else
|
|
Enumerate := True;
|
|
Print_Char ('(');
|
|
end if;
|
|
|
|
Print_Str (Flag);
|
|
end Print_Header_Flag;
|
|
|
|
-- Start of processing for Print_Node_Header
|
|
|
|
begin
|
|
Print_Node_Ref (N);
|
|
|
|
if not Is_Valid_Node (Union_Id (N)) then
|
|
Print_Str (" (no such node)");
|
|
Print_Eol;
|
|
return;
|
|
end if;
|
|
|
|
Print_Char (' ');
|
|
|
|
if Comes_From_Source (N) then
|
|
Print_Header_Flag ("source");
|
|
end if;
|
|
|
|
if Analyzed (N) then
|
|
Print_Header_Flag ("analyzed");
|
|
end if;
|
|
|
|
if Error_Posted (N) then
|
|
Print_Header_Flag ("posted");
|
|
end if;
|
|
|
|
if Is_Ignored_Ghost_Node (N) then
|
|
Print_Header_Flag ("ignored ghost");
|
|
end if;
|
|
|
|
if Check_Actuals (N) then
|
|
Print_Header_Flag ("check actuals");
|
|
end if;
|
|
|
|
if Enumerate then
|
|
Print_Char (')');
|
|
end if;
|
|
|
|
Print_Eol;
|
|
end Print_Node_Header;
|
|
|
|
---------------------
|
|
-- Print_Node_Kind --
|
|
---------------------
|
|
|
|
procedure Print_Node_Kind (N : Node_Id) is
|
|
begin
|
|
if Phase = Printing then
|
|
Print_Str_Mixed_Case (Node_Kind'Image (Nkind (N)));
|
|
end if;
|
|
end Print_Node_Kind;
|
|
|
|
--------------------
|
|
-- Print_Node_Ref --
|
|
--------------------
|
|
|
|
procedure Print_Node_Ref (N : Node_Id) is
|
|
S : Nat;
|
|
|
|
begin
|
|
if Phase /= Printing then
|
|
return;
|
|
end if;
|
|
|
|
if N = Empty then
|
|
Write_Str ("<empty>");
|
|
|
|
elsif N = Error then
|
|
Write_Str ("<error>");
|
|
|
|
else
|
|
if Printing_Descendants then
|
|
S := Serial_Number (Int (N));
|
|
|
|
if S /= 0 then
|
|
Write_Str ("Node");
|
|
Write_Str (" #");
|
|
Write_Int (S);
|
|
Write_Char (' ');
|
|
end if;
|
|
end if;
|
|
|
|
Print_Node_Kind (N);
|
|
|
|
if Nkind (N) in N_Has_Chars then
|
|
Write_Char (' ');
|
|
|
|
if Field_Is_Initial_Zero (N, F_Chars) then
|
|
Print_Str ("Chars = initial zero");
|
|
Print_Eol;
|
|
|
|
else
|
|
Print_Name (Chars (N));
|
|
end if;
|
|
end if;
|
|
|
|
-- If this is a discrete expression whose value is known, print that
|
|
-- value.
|
|
|
|
if Nkind (N) in N_Subexpr
|
|
and then Compile_Time_Known_Value (N)
|
|
and then Present (Etype (N))
|
|
and then Is_Discrete_Type (Etype (N))
|
|
then
|
|
if Is_Entity_Name (N) -- e.g. enumeration literal
|
|
or else Nkind (N) in N_Integer_Literal
|
|
| N_Character_Literal
|
|
| N_Unchecked_Type_Conversion
|
|
then
|
|
Print_Str (" val = ");
|
|
UI_Write (Expr_Value (N));
|
|
end if;
|
|
end if;
|
|
|
|
if Nkind (N) in N_Entity then
|
|
Write_Str (" (Entity_Id=");
|
|
else
|
|
Write_Str (" (Node_Id=");
|
|
end if;
|
|
|
|
Write_Int (Int (N));
|
|
|
|
if Sloc (N) <= Standard_Location then
|
|
Write_Char ('s');
|
|
end if;
|
|
|
|
Write_Char (')');
|
|
|
|
end if;
|
|
end Print_Node_Ref;
|
|
|
|
------------------------
|
|
-- Print_Node_Subtree --
|
|
------------------------
|
|
|
|
procedure Print_Node_Subtree (N : Node_Id) is
|
|
begin
|
|
Print_Init;
|
|
|
|
Next_Serial_Number := 1;
|
|
Phase := Marking;
|
|
Visit_Node (N, "", ' ');
|
|
|
|
Next_Serial_Number := 1;
|
|
Phase := Printing;
|
|
Visit_Node (N, "", ' ');
|
|
|
|
Print_Term;
|
|
end Print_Node_Subtree;
|
|
|
|
---------------
|
|
-- Print_Str --
|
|
---------------
|
|
|
|
procedure Print_Str (S : String) is
|
|
begin
|
|
if Phase = Printing then
|
|
Write_Str (S);
|
|
end if;
|
|
end Print_Str;
|
|
|
|
--------------------------
|
|
-- Print_Str_Mixed_Case --
|
|
--------------------------
|
|
|
|
procedure Print_Str_Mixed_Case (S : String) is
|
|
begin
|
|
Print_Str (To_Mixed (S));
|
|
end Print_Str_Mixed_Case;
|
|
|
|
----------------
|
|
-- Print_Term --
|
|
----------------
|
|
|
|
procedure Print_Term is
|
|
begin
|
|
Serial_Numbers.Destroy (Hash_Table);
|
|
end Print_Term;
|
|
|
|
---------------------
|
|
-- Print_Tree_Elist --
|
|
---------------------
|
|
|
|
procedure Print_Tree_Elist (E : Elist_Id) is
|
|
M : Elmt_Id;
|
|
|
|
begin
|
|
Printing_Descendants := False;
|
|
Phase := Printing;
|
|
|
|
Print_Elist_Ref (E);
|
|
Print_Eol;
|
|
|
|
if Present (E) and then not Is_Empty_Elmt_List (E) then
|
|
M := First_Elmt (E);
|
|
|
|
loop
|
|
Print_Char ('|');
|
|
Print_Eol;
|
|
exit when No (Next_Elmt (M));
|
|
Print_Node (Node (M), "", '|');
|
|
Next_Elmt (M);
|
|
end loop;
|
|
|
|
Print_Node (Node (M), "", ' ');
|
|
Print_Eol;
|
|
end if;
|
|
end Print_Tree_Elist;
|
|
|
|
---------------------
|
|
-- Print_Tree_List --
|
|
---------------------
|
|
|
|
procedure Print_Tree_List (L : List_Id) is
|
|
N : Node_Id;
|
|
|
|
begin
|
|
Printing_Descendants := False;
|
|
Phase := Printing;
|
|
|
|
Print_List_Ref (L);
|
|
Print_Str (" List_Id=");
|
|
Print_Int (Int (L));
|
|
Print_Eol;
|
|
|
|
N := First (L);
|
|
|
|
if N = Empty then
|
|
Print_Str ("<empty node list>");
|
|
Print_Eol;
|
|
|
|
else
|
|
loop
|
|
Print_Char ('|');
|
|
Print_Eol;
|
|
exit when Next (N) = Empty;
|
|
Print_Node (N, "", '|');
|
|
Next (N);
|
|
end loop;
|
|
|
|
Print_Node (N, "", ' ');
|
|
Print_Eol;
|
|
end if;
|
|
end Print_Tree_List;
|
|
|
|
---------------------
|
|
-- Print_Tree_Node --
|
|
---------------------
|
|
|
|
procedure Print_Tree_Node (N : Node_Id; Label : String := "") is
|
|
begin
|
|
Printing_Descendants := False;
|
|
Phase := Printing;
|
|
Print_Node (N, Label, ' ');
|
|
end Print_Tree_Node;
|
|
|
|
--------
|
|
-- pt --
|
|
--------
|
|
|
|
procedure pt (N : Union_Id) is
|
|
begin
|
|
case N is
|
|
when List_Low_Bound .. List_High_Bound - 1 =>
|
|
Print_List_Subtree (List_Id (N));
|
|
|
|
when Node_Range =>
|
|
Print_Node_Subtree (Node_Id (N));
|
|
|
|
when Elist_Range =>
|
|
Print_Elist_Subtree (Elist_Id (N));
|
|
|
|
when others =>
|
|
pp (N);
|
|
end case;
|
|
end pt;
|
|
|
|
-------------------
|
|
-- Serial_Number --
|
|
-------------------
|
|
|
|
Hash_Id : Int;
|
|
-- Set by an unsuccessful call to Serial_Number (one which returns zero)
|
|
-- to save the Id that should be used if Set_Serial_Number is called.
|
|
|
|
function Serial_Number (Id : Int) return Nat is
|
|
begin
|
|
Hash_Id := Id;
|
|
return Serial_Numbers.Get (Hash_Table, Id);
|
|
end Serial_Number;
|
|
|
|
-----------------------
|
|
-- Set_Serial_Number --
|
|
-----------------------
|
|
|
|
procedure Set_Serial_Number is
|
|
begin
|
|
Serial_Numbers.Put (Hash_Table, Hash_Id, Next_Serial_Number);
|
|
Next_Serial_Number := Next_Serial_Number + 1;
|
|
end Set_Serial_Number;
|
|
|
|
--------------
|
|
-- To_Mixed --
|
|
--------------
|
|
|
|
function To_Mixed (S : String) return String is
|
|
begin
|
|
return Result : String (S'Range) := S do
|
|
To_Mixed (Result);
|
|
end return;
|
|
end To_Mixed;
|
|
|
|
---------------
|
|
-- Tree_Dump --
|
|
---------------
|
|
|
|
procedure Tree_Dump is
|
|
procedure Underline;
|
|
-- Put underline under string we just printed
|
|
|
|
procedure Underline is
|
|
Col : constant Int := Column;
|
|
|
|
begin
|
|
Write_Eol;
|
|
|
|
while Col > Column loop
|
|
Write_Char ('-');
|
|
end loop;
|
|
|
|
Write_Eol;
|
|
end Underline;
|
|
|
|
-- Start of processing for Tree_Dump. Note that we turn off the tree dump
|
|
-- flags immediately, before starting the dump. This avoids generating two
|
|
-- copies of the dump if an abort occurs after printing the dump, and more
|
|
-- importantly, avoids an infinite loop if an abort occurs during the dump.
|
|
|
|
-- Note: unlike in the source print case (in Sprint), we do not output
|
|
-- separate trees for each unit. Instead the -df debug switch causes the
|
|
-- tree that is output from the main unit to trace references into other
|
|
-- units (normally such references are not traced). Since all other units
|
|
-- are linked to the main unit by at least one reference, this causes all
|
|
-- tree nodes to be included in the output tree.
|
|
|
|
begin
|
|
if Debug_Flag_Y then
|
|
Debug_Flag_Y := False;
|
|
Write_Eol;
|
|
Write_Str ("Tree created for Standard (spec) ");
|
|
Underline;
|
|
Print_Node_Subtree (Standard_Package_Node);
|
|
Write_Eol;
|
|
end if;
|
|
|
|
if Debug_Flag_T then
|
|
Debug_Flag_T := False;
|
|
|
|
Write_Eol;
|
|
Write_Str ("Tree created for ");
|
|
Write_Unit_Name (Unit_Name (Main_Unit));
|
|
Underline;
|
|
Print_Node_Subtree (Cunit (Main_Unit));
|
|
Write_Eol;
|
|
end if;
|
|
end Tree_Dump;
|
|
|
|
-----------------
|
|
-- Visit_Elist --
|
|
-----------------
|
|
|
|
procedure Visit_Elist (E : Elist_Id; Prefix_Str : String) is
|
|
M : Elmt_Id;
|
|
N : Node_Id;
|
|
S : constant Nat := Serial_Number (Int (E));
|
|
|
|
begin
|
|
-- In marking phase, return if already marked, otherwise set next
|
|
-- serial number in hash table for later reference.
|
|
|
|
if Phase = Marking then
|
|
if S /= 0 then
|
|
return; -- already visited
|
|
else
|
|
Set_Serial_Number;
|
|
end if;
|
|
|
|
-- In printing phase, if already printed, then return, otherwise we
|
|
-- are printing the next item, so increment the serial number.
|
|
|
|
else
|
|
if S < Next_Serial_Number then
|
|
return; -- already printed
|
|
else
|
|
Next_Serial_Number := Next_Serial_Number + 1;
|
|
end if;
|
|
end if;
|
|
|
|
-- Now process the list (Print calls have no effect in marking phase)
|
|
|
|
Print_Str (Prefix_Str);
|
|
Print_Elist_Ref (E);
|
|
Print_Eol;
|
|
|
|
if Is_Empty_Elmt_List (E) then
|
|
Print_Str (Prefix_Str);
|
|
Print_Str ("(Empty element list)");
|
|
Print_Eol;
|
|
Print_Eol;
|
|
|
|
else
|
|
if Phase = Printing then
|
|
M := First_Elmt (E);
|
|
while Present (M) loop
|
|
N := Node (M);
|
|
Print_Str (Prefix_Str);
|
|
Print_Str (" ");
|
|
Print_Node_Ref (N);
|
|
Print_Eol;
|
|
Next_Elmt (M);
|
|
end loop;
|
|
|
|
Print_Str (Prefix_Str);
|
|
Print_Eol;
|
|
end if;
|
|
|
|
M := First_Elmt (E);
|
|
while Present (M) loop
|
|
Visit_Node (Node (M), Prefix_Str, ' ');
|
|
Next_Elmt (M);
|
|
end loop;
|
|
end if;
|
|
end Visit_Elist;
|
|
|
|
----------------
|
|
-- Visit_List --
|
|
----------------
|
|
|
|
procedure Visit_List (L : List_Id; Prefix_Str : String) is
|
|
N : Node_Id;
|
|
S : constant Nat := Serial_Number (Int (L));
|
|
|
|
begin
|
|
-- In marking phase, return if already marked, otherwise set next
|
|
-- serial number in hash table for later reference.
|
|
|
|
if Phase = Marking then
|
|
if S /= 0 then
|
|
return;
|
|
else
|
|
Set_Serial_Number;
|
|
end if;
|
|
|
|
-- In printing phase, if already printed, then return, otherwise we
|
|
-- are printing the next item, so increment the serial number.
|
|
|
|
else
|
|
if S < Next_Serial_Number then
|
|
return; -- already printed
|
|
else
|
|
Next_Serial_Number := Next_Serial_Number + 1;
|
|
end if;
|
|
end if;
|
|
|
|
-- Now process the list (Print calls have no effect in marking phase)
|
|
|
|
Print_Str (Prefix_Str);
|
|
Print_List_Ref (L);
|
|
Print_Eol;
|
|
|
|
Print_Str (Prefix_Str);
|
|
Print_Str ("|Parent = ");
|
|
Print_Node_Ref (Parent (L));
|
|
Print_Eol;
|
|
|
|
N := First (L);
|
|
|
|
if N = Empty then
|
|
Print_Str (Prefix_Str);
|
|
Print_Str ("(Empty list)");
|
|
Print_Eol;
|
|
Print_Eol;
|
|
|
|
else
|
|
Print_Str (Prefix_Str);
|
|
Print_Char ('|');
|
|
Print_Eol;
|
|
|
|
while Next (N) /= Empty loop
|
|
Visit_Node (N, Prefix_Str, '|');
|
|
Next (N);
|
|
end loop;
|
|
end if;
|
|
|
|
Visit_Node (N, Prefix_Str, ' ');
|
|
end Visit_List;
|
|
|
|
----------------
|
|
-- Visit_Node --
|
|
----------------
|
|
|
|
procedure Visit_Node
|
|
(N : Node_Id;
|
|
Prefix_Str : String;
|
|
Prefix_Char : Character)
|
|
is
|
|
New_Prefix : String (Prefix_Str'First .. Prefix_Str'Last + 2);
|
|
-- Prefix string for printing referenced fields
|
|
|
|
procedure Visit_Descendant (D : Union_Id);
|
|
-- This procedure tests the given value of one of the Fields referenced
|
|
-- by the current node to determine whether to visit it recursively.
|
|
-- The visited node will be indented using New_Prefix.
|
|
|
|
----------------------
|
|
-- Visit_Descendant --
|
|
----------------------
|
|
|
|
procedure Visit_Descendant (D : Union_Id) is
|
|
begin
|
|
-- Case of descendant is a node
|
|
|
|
if D in Node_Range then
|
|
|
|
-- Don't bother about Empty or Error descendants
|
|
|
|
if D <= Union_Id (Empty_Or_Error) then
|
|
return;
|
|
end if;
|
|
|
|
declare
|
|
Nod : constant Node_Or_Entity_Id := Node_Or_Entity_Id (D);
|
|
|
|
begin
|
|
-- Descendants in one of the standardly compiled internal
|
|
-- packages are normally ignored, unless the parent is also
|
|
-- in such a package (happens when Standard itself is output)
|
|
-- or if the -df switch is set which causes all links to be
|
|
-- followed, even into package standard.
|
|
|
|
if Sloc (Nod) <= Standard_Location then
|
|
if Sloc (N) > Standard_Location
|
|
and then not Debug_Flag_F
|
|
then
|
|
return;
|
|
end if;
|
|
|
|
-- Don't bother about a descendant in a different unit than
|
|
-- the node we came from unless the -df switch is set. Note
|
|
-- that we know at this point that Sloc (D) > Standard_Location
|
|
|
|
-- Note: the tests for No_Location here just make sure that we
|
|
-- don't blow up on a node which is missing an Sloc value. This
|
|
-- should not normally happen.
|
|
|
|
else
|
|
if (Sloc (N) <= Standard_Location
|
|
or else Sloc (N) = No_Location
|
|
or else Sloc (Nod) = No_Location
|
|
or else not In_Same_Source_Unit (Nod, N))
|
|
and then not Debug_Flag_F
|
|
then
|
|
return;
|
|
end if;
|
|
end if;
|
|
|
|
-- Don't bother visiting a source node that has a parent which
|
|
-- is not the node we came from. We prefer to trace such nodes
|
|
-- from their real parents. This causes the tree to be printed
|
|
-- in a more coherent order, e.g. a defining identifier listed
|
|
-- next to its corresponding declaration, instead of next to
|
|
-- some semantic reference.
|
|
|
|
-- This test is skipped for nodes in standard packages unless
|
|
-- the -dy option is set (which outputs the tree for standard)
|
|
|
|
-- Also, always follow pointers to Is_Itype entities,
|
|
-- since we want to list these when they are first referenced.
|
|
|
|
if Parent (Nod) /= Empty
|
|
and then Comes_From_Source (Nod)
|
|
and then Parent (Nod) /= N
|
|
and then (Sloc (N) > Standard_Location or else Debug_Flag_Y)
|
|
then
|
|
return;
|
|
end if;
|
|
|
|
-- If we successfully fall through all the above tests (which
|
|
-- execute a return if the node is not to be visited), we can
|
|
-- go ahead and visit the node.
|
|
|
|
Visit_Node (Nod, New_Prefix, ' ');
|
|
end;
|
|
|
|
-- Case of descendant is a list
|
|
|
|
elsif D in List_Range then
|
|
|
|
-- Don't bother with a missing list, empty list or error list
|
|
|
|
pragma Assert (D /= Union_Id (No_List));
|
|
-- Because No_List = Empty, which is in Node_Range above
|
|
|
|
if D = Union_Id (Error_List)
|
|
or else Is_Empty_List (List_Id (D))
|
|
then
|
|
return;
|
|
|
|
-- Otherwise we can visit the list. Note that we don't bother to
|
|
-- do the parent test that we did for the node case, because it
|
|
-- just does not happen that lists are referenced more than one
|
|
-- place in the tree. We aren't counting on this being the case
|
|
-- to generate valid output, it is just that we don't need in
|
|
-- practice to worry about listing the list at a place that is
|
|
-- inconvenient.
|
|
|
|
else
|
|
Visit_List (List_Id (D), New_Prefix);
|
|
end if;
|
|
|
|
-- Case of descendant is an element list
|
|
|
|
elsif D in Elist_Range then
|
|
|
|
-- Don't bother with a missing list, or an empty list
|
|
|
|
if D = Union_Id (No_Elist)
|
|
or else Is_Empty_Elmt_List (Elist_Id (D))
|
|
then
|
|
return;
|
|
|
|
-- Otherwise, visit the referenced element list
|
|
|
|
else
|
|
Visit_Elist (Elist_Id (D), New_Prefix);
|
|
end if;
|
|
|
|
else
|
|
raise Program_Error;
|
|
end if;
|
|
end Visit_Descendant;
|
|
|
|
-- Start of processing for Visit_Node
|
|
|
|
begin
|
|
if N = Empty then
|
|
return;
|
|
end if;
|
|
|
|
-- Set fatal error node in case we get a blow up during the trace
|
|
|
|
Current_Error_Node := N;
|
|
|
|
New_Prefix (Prefix_Str'Range) := Prefix_Str;
|
|
New_Prefix (Prefix_Str'Last + 1) := Prefix_Char;
|
|
New_Prefix (Prefix_Str'Last + 2) := ' ';
|
|
|
|
-- In the marking phase, all we do is to set the serial number
|
|
|
|
if Phase = Marking then
|
|
if Serial_Number (Int (N)) /= 0 then
|
|
return; -- already visited
|
|
else
|
|
Set_Serial_Number;
|
|
end if;
|
|
|
|
-- In the printing phase, we print the node
|
|
|
|
else
|
|
if Serial_Number (Int (N)) < Next_Serial_Number then
|
|
|
|
-- Here we have already visited the node, but if it is in a list,
|
|
-- we still want to print the reference, so that it is clear that
|
|
-- it belongs to the list.
|
|
|
|
if Is_List_Member (N) then
|
|
Print_Str (Prefix_Str);
|
|
Print_Node_Ref (N);
|
|
Print_Eol;
|
|
Print_Str (Prefix_Str);
|
|
Print_Char (Prefix_Char);
|
|
Print_Str ("(already output)");
|
|
Print_Eol;
|
|
Print_Str (Prefix_Str);
|
|
Print_Char (Prefix_Char);
|
|
Print_Eol;
|
|
end if;
|
|
|
|
return;
|
|
|
|
else
|
|
Print_Node (N, Prefix_Str, Prefix_Char);
|
|
Print_Str (Prefix_Str);
|
|
Print_Char (Prefix_Char);
|
|
Print_Eol;
|
|
Next_Serial_Number := Next_Serial_Number + 1;
|
|
end if;
|
|
end if;
|
|
|
|
-- Visit all descendants of this node
|
|
|
|
declare
|
|
A : Node_Field_Array renames Node_Field_Table (Nkind (N)).all;
|
|
begin
|
|
for Field_Index in A'Range loop
|
|
declare
|
|
F : constant Node_Field := A (Field_Index);
|
|
FD : Field_Descriptor renames Field_Descriptors (F);
|
|
begin
|
|
if FD.Kind in Node_Id_Field | List_Id_Field | Elist_Id_Field
|
|
-- For all other kinds of descendants (strings, names, uints
|
|
-- etc), there is nothing to visit (the contents of the
|
|
-- field will be printed when we print the containing node,
|
|
-- but what concerns us now is looking for descendants in
|
|
-- the tree.
|
|
|
|
and then F /= F_Next_Entity -- See below for why we skip this
|
|
then
|
|
Visit_Descendant (Get_Union_Id (N, FD.Offset));
|
|
end if;
|
|
end;
|
|
end loop;
|
|
end;
|
|
|
|
if Has_Aspects (N) then
|
|
Visit_Descendant (Union_Id (Aspect_Specifications (N)));
|
|
end if;
|
|
|
|
if Nkind (N) in N_Entity then
|
|
declare
|
|
A : Entity_Field_Array renames Entity_Field_Table (Ekind (N)).all;
|
|
begin
|
|
for Field_Index in A'Range loop
|
|
declare
|
|
F : constant Entity_Field := A (Field_Index);
|
|
FD : Field_Descriptor renames Field_Descriptors (F);
|
|
begin
|
|
if FD.Kind in Node_Id_Field | List_Id_Field | Elist_Id_Field
|
|
then
|
|
Visit_Descendant (Get_Union_Id (N, FD.Offset));
|
|
end if;
|
|
end;
|
|
end loop;
|
|
end;
|
|
|
|
-- Now an interesting special case. Normally parents are always
|
|
-- printed since we traverse the tree in a downwards direction.
|
|
-- However, there is an exception to this rule, which is the
|
|
-- case where a parent is constructed by the compiler and is not
|
|
-- referenced elsewhere in the tree. The following catches this case.
|
|
|
|
if not Comes_From_Source (N) then
|
|
Visit_Descendant (Union_Id (Parent (N)));
|
|
end if;
|
|
|
|
-- You may be wondering why we omitted Next_Entity above. The answer
|
|
-- is that we want to treat it rather specially. Why? Because a
|
|
-- Next_Entity link does not correspond to a level deeper in the
|
|
-- tree, and we do not want the tree to march off to the right of the
|
|
-- page due to bogus indentations coming from this effect.
|
|
|
|
-- To prevent this, what we do is to control references via
|
|
-- Next_Entity only from the first entity on a given scope chain,
|
|
-- and we keep them all at the same level. Of course if an entity
|
|
-- has already been referenced it is not printed.
|
|
|
|
if Present (Next_Entity (N))
|
|
and then Present (Scope (N))
|
|
and then First_Entity (Scope (N)) = N
|
|
then
|
|
declare
|
|
Nod : Node_Id;
|
|
|
|
begin
|
|
Nod := N;
|
|
while Present (Nod) loop
|
|
Next_Entity (Nod);
|
|
Visit_Descendant (Union_Id (Nod));
|
|
end loop;
|
|
end;
|
|
end if;
|
|
end if;
|
|
end Visit_Node;
|
|
|
|
end Treepr;
|