1 ------------------------------------------------------------------------------
3 -- GNAT COMPILER COMPONENTS --
9 -- Copyright (C) 2009, Free Software Foundation, Inc. --
11 -- GNAT is free software; you can redistribute it and/or modify it under --
12 -- terms of the GNU General Public License as published by the Free Soft- --
13 -- ware Foundation; either version 3, or (at your option) any later ver- --
14 -- sion. GNAT is distributed in the hope that it will be useful, but WITH- --
15 -- OUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY --
16 -- or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License --
17 -- for more details. You should have received a copy of the GNU General --
18 -- Public License distributed with GNAT; see file COPYING3. If not, go to --
19 -- http://www.gnu.org/licenses for a complete copy of the license. --
21 -- GNAT was originally developed by the GNAT team at New York University. --
22 -- Extensive contributions were provided by Ada Core Technologies Inc. --
24 ------------------------------------------------------------------------------
26 with Atree
; use Atree
;
27 with Debug
; use Debug
;
29 with Lib
.Util
; use Lib
.Util
;
30 with Nlists
; use Nlists
;
32 with Output
; use Output
;
33 with Sinfo
; use Sinfo
;
34 with Sinput
; use Sinput
;
37 with GNAT
.HTable
; use GNAT
.HTable
;
38 with GNAT
.Heap_Sort_G
;
40 package body Par_SCO
is
46 -- Internal table used to store recorded SCO values. Table is populated by
47 -- calls to SCO_Record, and entries may be modified by Set_SCO_Condition.
49 type SCO_Table_Entry
is record
57 package SCO_Table
is new Table
.Table
(
58 Table_Component_Type
=> SCO_Table_Entry
,
59 Table_Index_Type
=> Nat
,
62 Table_Increment
=> 300,
63 Table_Name
=> "SCO_Table_Entry");
65 -- The SCO_Table_Entry values appear as follows:
70 -- From = starting sloc
77 -- From = starting sloc
82 -- C1 = 'I', 'E', 'W', 'X' (if/exit/while/expression)
83 -- C2 = 'c', 't', or 'f'
84 -- From = starting sloc
89 -- C1 = 'I', 'E', 'W', 'X' (if/exit/while/expression)
96 -- C1 = '!', '^', '&', '|'
104 -- C2 = 'c', 't', or 'f' (condition/true/false)
105 -- From = starting sloc
107 -- Last = False for all but the last entry, True for last entry
109 -- Note: the sequence starting with a decision, and continuing with
110 -- operators and elements up to and including the first one labeled with
111 -- Last=True, indicate the sequence to be output for a complex decision
112 -- on a single CD decision line.
118 -- This table keeps track of the units and the corresponding starting and
119 -- ending indexes (From, To) in the SCO table. Note that entry zero is
120 -- unused, it is for convenience in calling the sort routine.
122 type SCO_Unit_Table_Entry
is record
123 Unit
: Unit_Number_Type
;
128 package SCO_Unit_Table
is new Table
.Table
(
129 Table_Component_Type
=> SCO_Unit_Table_Entry
,
130 Table_Index_Type
=> Int
,
131 Table_Low_Bound
=> 0,
133 Table_Increment
=> 200,
134 Table_Name
=> "SCO_Unit_Table_Entry");
136 --------------------------
137 -- Condition Hash Table --
138 --------------------------
140 -- We need to be able to get to conditions quickly for handling the calls
141 -- to Set_SCO_Condition efficiently. For this purpose we identify the
142 -- conditions in the table by their starting sloc, and use the following
143 -- hash table to map from these starting sloc values to SCO_Table indexes.
145 type Header_Num
is new Integer range 0 .. 996;
146 -- Type for hash table headers
148 function Hash
(F
: Source_Ptr
) return Header_Num
;
149 -- Function to Hash source pointer value
151 function Equal
(F1
, F2
: Source_Ptr
) return Boolean;
152 -- Function to test two keys for equality
154 package Condition_Hash_Table
is new Simple_HTable
155 (Header_Num
, Int
, 0, Source_Ptr
, Hash
, Equal
);
156 -- The actual hash table
158 --------------------------
159 -- Internal Subprograms --
160 --------------------------
162 function Has_Decision
(N
: Node_Id
) return Boolean;
163 -- N is the node for a subexpression. Returns True if the subexpression
164 -- contains a nested decision (i.e. either is a logical operator, or
165 -- contains a logical operator in its subtree).
167 function Is_Logical_Operator
(N
: Node_Id
) return Boolean;
168 -- N is the node for a subexpression. This procedure just tests N to see
169 -- if it is a logical operator (including short circuit conditions) and
170 -- returns True if so, False otherwise, it does no other processing.
172 procedure Process_Decisions
(N
: Node_Id
; T
: Character);
173 -- If N is Empty, has no effect. Otherwise scans the tree for the node N,
174 -- to output any decisions it contains. T is one of IEWX (for context of
175 -- expresion: if/while/when-exit/expression). If T is other than X, then
176 -- the node is always a decision a decision is always present (at the very
177 -- least a simple decision is present at the top level).
179 procedure Process_Decisions
(L
: List_Id
; T
: Character);
180 -- Calls above procedure for each element of the list L
182 procedure Set_Table_Entry
188 -- Append an entry to SCO_Table with fields set as per arguments
190 procedure Traverse_Declarations_Or_Statements
(L
: List_Id
);
191 procedure Traverse_Generic_Package_Declaration
(N
: Node_Id
);
192 procedure Traverse_Handled_Statement_Sequence
(N
: Node_Id
);
193 procedure Traverse_Package_Body
(N
: Node_Id
);
194 procedure Traverse_Package_Declaration
(N
: Node_Id
);
195 procedure Traverse_Subprogram_Body
(N
: Node_Id
);
196 -- Traverse the corresponding construct, generating SCO table entries
199 -- Debug routine to dump SCO table
207 Write_Line
("SCO Unit Table");
208 Write_Line
("--------------");
210 for Index
in SCO_Unit_Table
.First
.. SCO_Unit_Table
.Last
loop
213 Write_Str
(". Unit = ");
214 Write_Int
(Int
(SCO_Unit_Table
.Table
(Index
).Unit
));
215 Write_Str
(" From = ");
216 Write_Int
(Int
(SCO_Unit_Table
.Table
(Index
).From
));
217 Write_Str
(" To = ");
218 Write_Int
(Int
(SCO_Unit_Table
.Table
(Index
).To
));
223 Write_Line
("SCO Table");
224 Write_Line
("---------");
226 for Index
in SCO_Table
.First
.. SCO_Table
.Last
loop
228 T
: SCO_Table_Entry
renames SCO_Table
.Table
(Index
);
233 Write_Str
(". C1 = '");
235 Write_Str
("' C2 = '");
237 Write_Str
("' From = ");
238 Write_Location
(T
.From
);
239 Write_Str
(" To = ");
240 Write_Location
(T
.To
);
241 Write_Str
(" Last = ");
246 Write_Str
(" False");
258 function Equal
(F1
, F2
: Source_Ptr
) return Boolean is
267 function Has_Decision
(N
: Node_Id
) return Boolean is
269 function Check_Node
(N
: Node_Id
) return Traverse_Result
;
275 function Check_Node
(N
: Node_Id
) return Traverse_Result
is
277 if Is_Logical_Operator
(N
) then
284 function Traverse
is new Traverse_Func
(Check_Node
);
286 -- Start of processing for Has_Decision
289 return Traverse
(N
) = Abandon
;
296 function Hash
(F
: Source_Ptr
) return Header_Num
is
298 return Header_Num
(Nat
(F
) mod 997);
305 procedure Initialize
is
308 SCO_Unit_Table
.Increment_Last
;
312 -------------------------
313 -- Is_Logical_Operator --
314 -------------------------
316 function Is_Logical_Operator
(N
: Node_Id
) return Boolean is
318 return Nkind_In
(N
, N_Op_And
,
324 end Is_Logical_Operator
;
326 -----------------------
327 -- Process_Decisions --
328 -----------------------
330 -- Version taking a list
332 procedure Process_Decisions
(L
: List_Id
; T
: Character) is
337 while Present
(N
) loop
338 Process_Decisions
(N
, T
);
342 end Process_Decisions
;
344 -- Version taking a node
346 procedure Process_Decisions
(N
: Node_Id
; T
: Character) is
348 function Process_Node
(N
: Node_Id
) return Traverse_Result
;
349 -- Processes one node in the traversal, looking for logical operators,
350 -- and if one is found, outputs the appropriate table entries.
352 procedure Output_Decision_Operand
(N
: Node_Id
);
353 -- The node N is the top level logical operator of a decision, or it is
354 -- one of the operands of a logical operator belonging to a single
355 -- complex decision. This routine outputs the sequence of table entries
356 -- corresponding to the node. Note that we do not process the sub-
357 -- operands to look for further decisions, that processing is done in
358 -- Process_Decision_Operand, because we can't get decisions mixed up in
359 -- the global table. Call has no effect if N is Empty.
361 procedure Output_Element
(N
: Node_Id
; T
: Character);
362 -- Node N is an operand of a logical operator that is not itself a
363 -- logical operator, or it is a simple decision. This routine outputs
364 -- the table entry for the element, with C1 set to T (' ' for one of
365 -- the elements of a complex decision, or 'I'/'W'/'E' for a simple
366 -- decision (from an IF, WHILE, or EXIT WHEN). Last is set to False,
367 -- and an entry is made in the condition hash table.
369 procedure Process_Decision_Operand
(N
: Node_Id
);
370 -- This is called on node N, the top level node of a decision, or on one
371 -- of its operands or suboperands after generating the full output for
372 -- the complex decision. It process the suboperands of the decision
373 -- looking for nested decisions.
375 -----------------------------
376 -- Output_Decision_Operand --
377 -----------------------------
379 procedure Output_Decision_Operand
(N
: Node_Id
) is
392 elsif Is_Logical_Operator
(N
) then
393 if Nkind
(N
) = N_Op_Not
then
400 if Nkind
(N
) = N_Op_Xor
then
402 elsif Nkind_In
(N
, N_Op_Or
, N_Or_Else
) then
409 Sloc_Range
(N
, FSloc
, LSloc
);
410 Set_Table_Entry
(C
, ' ', FSloc
, LSloc
, False);
412 Output_Decision_Operand
(L
);
413 Output_Decision_Operand
(Right_Opnd
(N
));
415 -- Not a logical operator
418 Output_Element
(N
, ' ');
420 end Output_Decision_Operand
;
426 procedure Output_Element
(N
: Node_Id
; T
: Character) is
430 Sloc_Range
(N
, FSloc
, LSloc
);
431 Set_Table_Entry
(T
, 'c', FSloc
, LSloc
, False);
432 Condition_Hash_Table
.Set
(FSloc
, SCO_Table
.Last
);
435 ------------------------------
436 -- Process_Decision_Operand --
437 ------------------------------
439 procedure Process_Decision_Operand
(N
: Node_Id
) is
441 if Is_Logical_Operator
(N
) then
442 if Nkind
(N
) /= N_Op_Not
then
443 Process_Decision_Operand
(Left_Opnd
(N
));
446 Process_Decision_Operand
(Right_Opnd
(N
));
449 Process_Decisions
(N
, 'X');
451 end Process_Decision_Operand
;
457 function Process_Node
(N
: Node_Id
) return Traverse_Result
is
461 -- Logical operators and short circuit forms, output table
462 -- entries and then process operands recursively to deal with
463 -- nested conditions.
476 -- If outer level, then type comes from call, otherwise it
477 -- is more deeply nested and counts as X for expression.
479 if N
= Process_Decisions
.N
then
480 T
:= Process_Decisions
.T
;
485 -- Output header for sequence
487 Set_Table_Entry
(T
, ' ', No_Location
, No_Location
, False);
489 -- Output the decision
491 Output_Decision_Operand
(N
);
493 -- Change Last in last table entry to True to mark end
495 SCO_Table
.Table
(SCO_Table
.Last
).Last
:= True;
497 -- Process any embedded decisions
499 Process_Decision_Operand
(N
);
503 -- Conditional expression, processed like an if statement
505 when N_Conditional_Expression
=>
507 Cond
: constant Node_Id
:= First
(Expressions
(N
));
508 Thnx
: constant Node_Id
:= Next
(Cond
);
509 Elsx
: constant Node_Id
:= Next
(Thnx
);
511 Process_Decisions
(Cond
, 'I');
512 Process_Decisions
(Thnx
, 'X');
513 Process_Decisions
(Elsx
, 'X');
517 -- All other cases, continue scan
525 procedure Traverse
is new Traverse_Proc
(Process_Node
);
527 -- Start of processing for Process_Decisions
534 -- See if we have simple decision at outer level and if so then
535 -- generate the decision entry for this simple decision. A simple
536 -- decision is a boolean expression (which is not a logical operator
537 -- or short circuit form) appearing as the operand of an IF, WHILE
538 -- or EXIT WHEN construct.
540 if T
/= 'X' and then not Is_Logical_Operator
(N
) then
541 Output_Element
(N
, T
);
543 -- Change Last in last table entry to True to mark end of
544 -- sequence, which is this case is only one element long.
546 SCO_Table
.Table
(SCO_Table
.Last
).Last
:= True;
550 end Process_Decisions
;
556 procedure SCO_Output
is
559 U
: Unit_Number_Type
;
561 procedure Output_Range
(From
: Source_Ptr
; To
: Source_Ptr
);
562 -- Outputs Sloc range in line:col-line:col format (for now we do not
563 -- worry about generic instantiations???)
569 procedure Output_Range
(From
: Source_Ptr
; To
: Source_Ptr
) is
571 Write_Info_Nat
(Int
(Get_Logical_Line_Number
(From
)));
572 Write_Info_Char
(':');
573 Write_Info_Nat
(Int
(Get_Column_Number
(From
)));
574 Write_Info_Char
('-');
575 Write_Info_Nat
(Int
(Get_Logical_Line_Number
(To
)));
576 Write_Info_Char
(':');
577 Write_Info_Nat
(Int
(Get_Column_Number
(To
)));
580 -- Start of processing for SCO_Output
583 if Debug_Flag_Dot_OO
then
587 -- Sort the unit table
589 Unit_Table_Sort
: declare
591 function Lt
(Op1
, Op2
: Natural) return Boolean;
592 -- Comparison routine for sort call
594 procedure Move
(From
: Natural; To
: Natural);
595 -- Move routine for sort call
601 function Lt
(Op1
, Op2
: Natural) return Boolean is
603 return Dependency_Num
(SCO_Unit_Table
.Table
(Nat
(Op1
)).Unit
) <
604 Dependency_Num
(SCO_Unit_Table
.Table
(Nat
(Op2
)).Unit
);
611 procedure Move
(From
: Natural; To
: Natural) is
613 SCO_Unit_Table
.Table
(Nat
(To
)) :=
614 SCO_Unit_Table
.Table
(Nat
(From
));
617 package Sorting
is new GNAT
.Heap_Sort_G
(Move
, Lt
);
619 -- Start of processing for Unit_Table_Sort
622 Sorting
.Sort
(Integer (SCO_Unit_Table
.Last
));
625 -- Loop through entries in the unit table
627 for J
in 1 .. SCO_Unit_Table
.Last
loop
628 U
:= SCO_Unit_Table
.Table
(J
).Unit
;
630 -- Output header line preceded by blank line
632 Write_Info_Terminate
;
633 Write_Info_Initiate
('C');
634 Write_Info_Char
(' ');
635 Write_Info_Nat
(Dependency_Num
(U
));
636 Write_Info_Char
(' ');
637 Write_Info_Name
(Reference_Name
(Source_Index
(U
)));
638 Write_Info_Terminate
;
640 Start
:= SCO_Unit_Table
.Table
(J
).From
;
641 Stop
:= SCO_Unit_Table
.Table
(J
).To
;
643 -- Loop through relevant entries in SCO table, outputting C lines
645 while Start
<= Stop
loop
647 T
: SCO_Table_Entry
renames SCO_Table
.Table
(Start
);
650 Write_Info_Initiate
('C');
651 Write_Info_Char
(T
.C1
);
658 Write_Info_Char
(' ');
659 Output_Range
(T
.From
, T
.To
);
663 when 'I' |
'E' |
'W' |
'X' =>
668 -- Loop through table entries for this decision
672 T
: SCO_Table_Entry
renames SCO_Table
.Table
(Start
);
675 Write_Info_Char
(' ');
677 if T
.C1
= '!' or else
682 Write_Info_Char
(T
.C1
);
685 Write_Info_Char
(T
.C2
);
686 Output_Range
(T
.From
, T
.To
);
698 Write_Info_Terminate
;
701 exit when Start
= Stop
;
704 pragma Assert
(Start
<= Stop
);
713 procedure SCO_Record
(U
: Unit_Number_Type
) is
718 -- Ignore call if not generating code and generating SCO's
720 if not (Generate_SCO
and then Operating_Mode
= Generate_Code
) then
724 -- Ignore call if this unit already recorded
726 for J
in 1 .. SCO_Unit_Table
.Last
loop
727 if SCO_Unit_Table
.Table
(J
).Unit
= U
then
732 -- Otherwise record starting entry
734 From
:= SCO_Table
.Last
+ 1;
736 -- Get Unit (checking case of subunit)
738 Lu
:= Unit
(Cunit
(U
));
740 if Nkind
(Lu
) = N_Subunit
then
741 Lu
:= Proper_Body
(Lu
);
746 if Nkind
(Lu
) = N_Subprogram_Body
then
747 Traverse_Subprogram_Body
(Lu
);
749 elsif Nkind
(Lu
) = N_Package_Declaration
then
750 Traverse_Package_Declaration
(Lu
);
752 elsif Nkind
(Lu
) = N_Package_Body
then
753 Traverse_Package_Body
(Lu
);
755 elsif Nkind
(Lu
) = N_Generic_Package_Declaration
then
756 Traverse_Generic_Package_Declaration
(Lu
);
758 -- For anything else, the only issue is default expressions for
759 -- parameters, where we have to worry about possible embedded decisions
763 Process_Decisions
(Lu
, 'X');
766 -- Make entry for new unit in unit table
768 SCO_Unit_Table
.Append
((Unit
=> U
, From
=> From
, To
=> SCO_Table
.Last
));
771 -----------------------
772 -- Set_SCO_Condition --
773 -----------------------
775 procedure Set_SCO_Condition
(First_Loc
: Source_Ptr
; Typ
: Character) is
776 Index
: constant Nat
:= Condition_Hash_Table
.Get
(First_Loc
);
779 SCO_Table
.Table
(Index
).C2
:= Typ
;
781 end Set_SCO_Condition
;
783 ---------------------
784 -- Set_Table_Entry --
785 ---------------------
787 procedure Set_Table_Entry
795 SCO_Table
.Append
((C1
=> C1
,
802 -----------------------------------------
803 -- Traverse_Declarations_Or_Statements --
804 -----------------------------------------
806 procedure Traverse_Declarations_Or_Statements
(L
: List_Id
) is
815 -- Set False if current entity terminates statement list
817 procedure Set_Statement_Entry
;
818 -- If Start is No_Location, does nothing, otherwise outputs a SCO_Table
819 -- statement entry for the range Start-Stop and then sets both Start
820 -- and Stop to No_Location. Unconditionally sets Term to True. This is
821 -- called when we find a statement or declaration that generates its
822 -- own table entry, so that we must end the current statement sequence.
824 -------------------------
825 -- Set_Statement_Entry --
826 -------------------------
828 procedure Set_Statement_Entry
is
832 if Start
/= No_Location
then
833 Set_Table_Entry
('S', ' ', Start
, Stop
, False);
834 Start
:= No_Location
;
837 end Set_Statement_Entry
;
839 -- Start of processing for Traverse_Declarations_Or_Statements
842 if Is_Non_Empty_List
(L
) then
844 Start
:= No_Location
;
846 -- Loop through statements or declarations
848 while Present
(N
) loop
853 -- Package declaration
855 when N_Package_Declaration
=>
857 Traverse_Package_Declaration
(N
);
859 -- Generic package declaration
861 when N_Generic_Package_Declaration
=>
863 Traverse_Generic_Package_Declaration
(N
);
867 when N_Package_Body
=>
869 Traverse_Package_Body
(N
);
871 -- Subprogram declaration
873 when N_Subprogram_Declaration
=>
876 (Parameter_Specifications
(Specification
(N
)), 'X');
878 -- Generic subprogram declaration
880 when N_Generic_Subprogram_Declaration
=>
882 Process_Decisions
(Generic_Formal_Declarations
(N
), 'X');
884 (Parameter_Specifications
(Specification
(N
)), 'X');
888 when N_Subprogram_Body
=>
890 Traverse_Subprogram_Body
(N
);
894 when N_Exit_Statement
=>
896 Process_Decisions
(Condition
(N
), 'E');
898 -- This is an exit point
900 Sloc_Range
(N
, From
, To
);
901 Set_Table_Entry
('T', ' ', From
, To
, False);
903 -- Label (breaks statement sequence)
910 when N_Block_Statement
=>
912 Traverse_Declarations_Or_Statements
(Declarations
(N
));
913 Traverse_Handled_Statement_Sequence
914 (Handled_Statement_Sequence
(N
));
918 when N_If_Statement
=>
920 Process_Decisions
(Condition
(N
), 'I');
921 Traverse_Declarations_Or_Statements
(Then_Statements
(N
));
923 if Present
(Elsif_Parts
(N
)) then
925 Elif
: Node_Id
:= First
(Elsif_Parts
(N
));
927 while Present
(Elif
) loop
928 Process_Decisions
(Condition
(Elif
), 'I');
929 Traverse_Declarations_Or_Statements
930 (Then_Statements
(Elif
));
936 Traverse_Declarations_Or_Statements
(Else_Statements
(N
));
938 -- Unconditional exit points
940 when N_Requeue_Statement |
944 Sloc_Range
(N
, From
, To
);
945 Set_Table_Entry
('T', ' ', From
, To
, False);
947 -- Simple return statement
949 when N_Simple_Return_Statement
=>
952 -- Process possible return expression
954 Process_Decisions
(Expression
(N
), 'X');
956 -- Return is an exit point
958 Sloc_Range
(N
, From
, To
);
959 Set_Table_Entry
('T', ' ', From
, To
, False);
961 -- Extended return statement
963 when N_Extended_Return_Statement
=>
965 Traverse_Declarations_Or_Statements
966 (Return_Object_Declarations
(N
));
967 Traverse_Handled_Statement_Sequence
968 (Handled_Statement_Sequence
(N
));
970 -- Return is an exit point
972 Sloc_Range
(N
, From
, To
);
973 Set_Table_Entry
('T', ' ', From
, To
, False);
977 when N_Loop_Statement
=>
979 -- Even if not a while loop, we want a new statement seq
983 if Present
(Iteration_Scheme
(N
)) then
985 (Condition
(Iteration_Scheme
(N
)), 'W');
988 Traverse_Declarations_Or_Statements
(Statements
(N
));
993 if Has_Decision
(N
) then
995 Process_Decisions
(N
, 'X');
999 -- If that element did not terminate the current sequence of
1000 -- statements, then establish or extend this sequence.
1003 if Start
= No_Location
then
1004 Sloc_Range
(N
, Start
, Stop
);
1006 Sloc_Range
(N
, Dummy
, Stop
);
1013 Set_Statement_Entry
;
1015 end Traverse_Declarations_Or_Statements
;
1017 ------------------------------------------
1018 -- Traverse_Generic_Package_Declaration --
1019 ------------------------------------------
1021 procedure Traverse_Generic_Package_Declaration
(N
: Node_Id
) is
1023 Process_Decisions
(Generic_Formal_Declarations
(N
), 'X');
1024 Traverse_Package_Declaration
(N
);
1025 end Traverse_Generic_Package_Declaration
;
1027 -----------------------------------------
1028 -- Traverse_Handled_Statement_Sequence --
1029 -----------------------------------------
1031 procedure Traverse_Handled_Statement_Sequence
(N
: Node_Id
) is
1036 Traverse_Declarations_Or_Statements
(Statements
(N
));
1038 if Present
(Exception_Handlers
(N
)) then
1039 Handler
:= First
(Exception_Handlers
(N
));
1040 while Present
(Handler
) loop
1041 Traverse_Declarations_Or_Statements
(Statements
(Handler
));
1046 end Traverse_Handled_Statement_Sequence
;
1048 ---------------------------
1049 -- Traverse_Package_Body --
1050 ---------------------------
1052 procedure Traverse_Package_Body
(N
: Node_Id
) is
1054 Traverse_Declarations_Or_Statements
(Declarations
(N
));
1055 Traverse_Handled_Statement_Sequence
(Handled_Statement_Sequence
(N
));
1056 end Traverse_Package_Body
;
1058 ----------------------------------
1059 -- Traverse_Package_Declaration --
1060 ----------------------------------
1062 procedure Traverse_Package_Declaration
(N
: Node_Id
) is
1063 Spec
: constant Node_Id
:= Specification
(N
);
1065 Traverse_Declarations_Or_Statements
(Visible_Declarations
(Spec
));
1066 Traverse_Declarations_Or_Statements
(Private_Declarations
(Spec
));
1067 end Traverse_Package_Declaration
;
1069 ------------------------------
1070 -- Traverse_Subprogram_Body --
1071 ------------------------------
1073 procedure Traverse_Subprogram_Body
(N
: Node_Id
) is
1075 Traverse_Declarations_Or_Statements
(Declarations
(N
));
1076 Traverse_Handled_Statement_Sequence
(Handled_Statement_Sequence
(N
));
1077 end Traverse_Subprogram_Body
;