1 ------------------------------------------------------------------------------
3 -- GNAT COMPILER COMPONENTS --
9 -- Copyright (C) 1992-2007, 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 2, 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 COPYING. If not, write --
19 -- to the Free Software Foundation, 51 Franklin Street, Fifth Floor, --
20 -- Boston, MA 02110-1301, USA. --
22 -- As a special exception, if other files instantiate generics from this --
23 -- unit, or you link this unit with other files to produce an executable, --
24 -- this unit does not by itself cause the resulting executable to be --
25 -- covered by the GNU General Public License. This exception does not --
26 -- however invalidate any other reasons why the executable file might be --
27 -- covered by the GNU Public License. --
29 -- GNAT was originally developed by the GNAT team at New York University. --
30 -- Extensive contributions were provided by Ada Core Technologies Inc. --
32 ------------------------------------------------------------------------------
34 -- WARNING: There is a C version of this package. Any changes to this source
35 -- file must be properly reflected in the corresponding C header a-nlists.h
38 with Atree; use Atree;
39 with Debug; use Debug;
40 with Output; use Output;
41 with Sinfo; use Sinfo;
44 package body Nlists is
46 use Atree_Private_Part;
47 -- Get access to Nodes table
49 ----------------------------------
50 -- Implementation of Node Lists --
51 ----------------------------------
53 -- A node list is represented by a list header which contains
56 type List_Header is record
58 -- Pointer to first node in list. Empty if list is empty
61 -- Pointer to last node in list. Empty if list is empty
64 -- Pointer to parent of list. Empty if list has no parent
67 -- The node lists are stored in a table indexed by List_Id values
69 package Lists is new Table.Table (
70 Table_Component_Type => List_Header,
71 Table_Index_Type => List_Id'Base,
72 Table_Low_Bound => First_List_Id,
73 Table_Initial => Alloc.Lists_Initial,
74 Table_Increment => Alloc.Lists_Increment,
75 Table_Name => "Lists");
77 -- The nodes in the list all have the In_List flag set, and their Link
78 -- fields (which otherwise point to the parent) contain the List_Id of
79 -- the list header giving immediate access to the list containing the
80 -- node, and its parent and first and last elements.
82 -- Two auxiliary tables, indexed by Node_Id values and built in parallel
83 -- with the main nodes table and always having the same size contain the
84 -- list link values that allow locating the previous and next node in a
85 -- list. The entries in these tables are valid only if the In_List flag
86 -- is set in the corresponding node. Next_Node is Empty at the end of a
87 -- list and Prev_Node is Empty at the start of a list.
89 package Next_Node is new Table.Table (
90 Table_Component_Type => Node_Id,
91 Table_Index_Type => Node_Id'Base,
92 Table_Low_Bound => First_Node_Id,
93 Table_Initial => Alloc.Orig_Nodes_Initial,
94 Table_Increment => Alloc.Orig_Nodes_Increment,
95 Table_Name => "Next_Node");
97 package Prev_Node is new Table.Table (
98 Table_Component_Type => Node_Id,
99 Table_Index_Type => Node_Id'Base,
100 Table_Low_Bound => First_Node_Id,
101 Table_Initial => Alloc.Orig_Nodes_Initial,
102 Table_Increment => Alloc.Orig_Nodes_Increment,
103 Table_Name => "Prev_Node");
105 -----------------------
106 -- Local Subprograms --
107 -----------------------
109 procedure Set_First (List : List_Id; To : Node_Id);
110 pragma Inline (Set_First);
111 -- Sets First field of list header List to reference To
113 procedure Set_Last (List : List_Id; To : Node_Id);
114 pragma Inline (Set_Last);
115 -- Sets Last field of list header List to reference To
117 procedure Set_List_Link (Node : Node_Id; To : List_Id);
118 pragma Inline (Set_List_Link);
119 -- Sets list link of Node to list header To
121 procedure Set_Next (Node : Node_Id; To : Node_Id);
122 pragma Inline (Set_Next);
123 -- Sets the Next_Node pointer for Node to reference To
125 procedure Set_Prev (Node : Node_Id; To : Node_Id);
126 pragma Inline (Set_Prev);
127 -- Sets the Prev_Node pointer for Node to reference To
129 --------------------------
130 -- Allocate_List_Tables --
131 --------------------------
133 procedure Allocate_List_Tables (N : Node_Id) is
134 Old_Last : constant Node_Id'Base := Next_Node.Last;
137 pragma Assert (N >= Old_Last);
138 Next_Node.Set_Last (N);
139 Prev_Node.Set_Last (N);
141 -- Make sure we have no uninitialized junk in any new entires added.
142 -- This ensures that Tree_Gen will not write out any unitialized junk.
144 for J in Old_Last + 1 .. N loop
145 Next_Node.Table (J) := Empty;
146 Prev_Node.Table (J) := Empty;
148 end Allocate_List_Tables;
154 procedure Append (Node : Node_Id; To : List_Id) is
155 L : constant Node_Id := Last (To);
157 procedure Append_Debug;
158 pragma Inline (Append_Debug);
159 -- Output debug information if Debug_Flag_N set
165 procedure Append_Debug is
168 Write_Str ("Append node ");
169 Write_Int (Int (Node));
170 Write_Str (" to list ");
171 Write_Int (Int (To));
176 -- Start of processing for Append
179 pragma Assert (not Is_List_Member (Node));
185 pragma Debug (Append_Debug);
188 Set_First (To, Node);
195 Nodes.Table (Node).In_List := True;
197 Set_Next (Node, Empty);
199 Set_List_Link (Node, To);
206 procedure Append_List (List : List_Id; To : List_Id) is
208 procedure Append_List_Debug;
209 pragma Inline (Append_List_Debug);
210 -- Output debug information if Debug_Flag_N set
212 -----------------------
213 -- Append_List_Debug --
214 -----------------------
216 procedure Append_List_Debug is
219 Write_Str ("Append list ");
220 Write_Int (Int (List));
221 Write_Str (" to list ");
222 Write_Int (Int (To));
225 end Append_List_Debug;
227 -- Start of processing for Append_List
230 if Is_Empty_List (List) then
235 L : constant Node_Id := Last (To);
236 F : constant Node_Id := First (List);
240 pragma Debug (Append_List_Debug);
244 Set_List_Link (N, To);
256 Set_Last (To, Last (List));
258 Set_First (List, Empty);
259 Set_Last (List, Empty);
268 procedure Append_List_To (To : List_Id; List : List_Id) is
270 Append_List (List, To);
277 procedure Append_To (To : List_Id; Node : Node_Id) is
286 procedure Delete_List (L : List_Id) is
290 while Is_Non_Empty_List (L) loop
291 N := Remove_Head (L);
295 -- Should recycle list header???
302 function First (List : List_Id) return Node_Id is
304 if List = No_List then
307 pragma Assert (List in First_List_Id .. Lists.Last);
308 return Lists.Table (List).First;
312 ----------------------
313 -- First_Non_Pragma --
314 ----------------------
316 function First_Non_Pragma (List : List_Id) return Node_Id is
317 N : constant Node_Id := First (List);
320 if Nkind (N) /= N_Pragma
322 Nkind (N) /= N_Null_Statement
326 return Next_Non_Pragma (N);
328 end First_Non_Pragma;
334 procedure Initialize is
335 E : constant List_Id := Error_List;
342 -- Allocate Error_List list header
344 Lists.Increment_Last;
345 Set_Parent (E, Empty);
346 Set_First (E, Empty);
354 procedure Insert_After (After : Node_Id; Node : Node_Id) is
356 procedure Insert_After_Debug;
357 pragma Inline (Insert_After_Debug);
358 -- Output debug information if Debug_Flag_N set
360 ------------------------
361 -- Insert_After_Debug --
362 ------------------------
364 procedure Insert_After_Debug is
367 Write_Str ("Insert node");
368 Write_Int (Int (Node));
369 Write_Str (" after node ");
370 Write_Int (Int (After));
373 end Insert_After_Debug;
375 -- Start of processing for Insert_After
379 (Is_List_Member (After) and then not Is_List_Member (Node));
385 pragma Debug (Insert_After_Debug);
388 Before : constant Node_Id := Next (After);
389 LC : constant List_Id := List_Containing (After);
392 if Present (Before) then
393 Set_Prev (Before, Node);
398 Set_Next (After, Node);
400 Nodes.Table (Node).In_List := True;
402 Set_Prev (Node, After);
403 Set_Next (Node, Before);
404 Set_List_Link (Node, LC);
412 procedure Insert_Before (Before : Node_Id; Node : Node_Id) is
414 procedure Insert_Before_Debug;
415 pragma Inline (Insert_Before_Debug);
416 -- Output debug information if Debug_Flag_N set
418 -------------------------
419 -- Insert_Before_Debug --
420 -------------------------
422 procedure Insert_Before_Debug is
425 Write_Str ("Insert node");
426 Write_Int (Int (Node));
427 Write_Str (" before node ");
428 Write_Int (Int (Before));
431 end Insert_Before_Debug;
433 -- Start of processing for Insert_Before
437 (Is_List_Member (Before) and then not Is_List_Member (Node));
443 pragma Debug (Insert_Before_Debug);
446 After : constant Node_Id := Prev (Before);
447 LC : constant List_Id := List_Containing (Before);
450 if Present (After) then
451 Set_Next (After, Node);
453 Set_First (LC, Node);
456 Set_Prev (Before, Node);
458 Nodes.Table (Node).In_List := True;
460 Set_Prev (Node, After);
461 Set_Next (Node, Before);
462 Set_List_Link (Node, LC);
466 -----------------------
467 -- Insert_List_After --
468 -----------------------
470 procedure Insert_List_After (After : Node_Id; List : List_Id) is
472 procedure Insert_List_After_Debug;
473 pragma Inline (Insert_List_After_Debug);
474 -- Output debug information if Debug_Flag_N set
476 -----------------------------
477 -- Insert_List_After_Debug --
478 -----------------------------
480 procedure Insert_List_After_Debug is
483 Write_Str ("Insert list ");
484 Write_Int (Int (List));
485 Write_Str (" after node ");
486 Write_Int (Int (After));
489 end Insert_List_After_Debug;
491 -- Start of processing for Insert_List_After
494 pragma Assert (Is_List_Member (After));
496 if Is_Empty_List (List) then
501 Before : constant Node_Id := Next (After);
502 LC : constant List_Id := List_Containing (After);
503 F : constant Node_Id := First (List);
504 L : constant Node_Id := Last (List);
508 pragma Debug (Insert_List_After_Debug);
512 Set_List_Link (N, LC);
517 if Present (Before) then
518 Set_Prev (Before, L);
525 Set_Next (L, Before);
527 Set_First (List, Empty);
528 Set_Last (List, Empty);
531 end Insert_List_After;
533 ------------------------
534 -- Insert_List_Before --
535 ------------------------
537 procedure Insert_List_Before (Before : Node_Id; List : List_Id) is
539 procedure Insert_List_Before_Debug;
540 pragma Inline (Insert_List_Before_Debug);
541 -- Output debug information if Debug_Flag_N set
543 ------------------------------
544 -- Insert_List_Before_Debug --
545 ------------------------------
547 procedure Insert_List_Before_Debug is
550 Write_Str ("Insert list ");
551 Write_Int (Int (List));
552 Write_Str (" before node ");
553 Write_Int (Int (Before));
556 end Insert_List_Before_Debug;
558 -- Start of prodcessing for Insert_List_Before
561 pragma Assert (Is_List_Member (Before));
563 if Is_Empty_List (List) then
568 After : constant Node_Id := Prev (Before);
569 LC : constant List_Id := List_Containing (Before);
570 F : constant Node_Id := First (List);
571 L : constant Node_Id := Last (List);
575 pragma Debug (Insert_List_Before_Debug);
579 Set_List_Link (N, LC);
584 if Present (After) then
590 Set_Prev (Before, L);
592 Set_Next (L, Before);
594 Set_First (List, Empty);
595 Set_Last (List, Empty);
598 end Insert_List_Before;
604 function Is_Empty_List (List : List_Id) return Boolean is
606 return First (List) = Empty;
613 function Is_List_Member (Node : Node_Id) return Boolean is
615 return Nodes.Table (Node).In_List;
618 -----------------------
619 -- Is_Non_Empty_List --
620 -----------------------
622 function Is_Non_Empty_List (List : List_Id) return Boolean is
624 return List /= No_List and then First (List) /= Empty;
625 end Is_Non_Empty_List;
631 function Last (List : List_Id) return Node_Id is
633 pragma Assert (List in First_List_Id .. Lists.Last);
634 return Lists.Table (List).Last;
641 function Last_List_Id return List_Id is
646 ---------------------
647 -- Last_Non_Pragma --
648 ---------------------
650 function Last_Non_Pragma (List : List_Id) return Node_Id is
651 N : constant Node_Id := Last (List);
654 if Nkind (N) /= N_Pragma then
657 return Prev_Non_Pragma (N);
661 ---------------------
662 -- List_Containing --
663 ---------------------
665 function List_Containing (Node : Node_Id) return List_Id is
667 pragma Assert (Is_List_Member (Node));
668 return List_Id (Nodes.Table (Node).Link);
675 function List_Length (List : List_Id) return Nat is
681 Node := First (List);
682 while Present (Node) loop
683 Result := Result + 1;
694 function Lists_Address return System.Address is
696 return Lists.Table (First_List_Id)'Address;
705 Lists.Locked := True;
708 Prev_Node.Locked := True;
709 Next_Node.Locked := True;
719 function New_Copy_List (List : List_Id) return List_Id is
724 if List = No_List then
731 while Present (E) loop
732 Append (New_Copy (E), NL);
740 ----------------------------
741 -- New_Copy_List_Original --
742 ----------------------------
744 function New_Copy_List_Original (List : List_Id) return List_Id is
749 if List = No_List then
756 while Present (E) loop
757 if Comes_From_Source (E) then
758 Append (New_Copy (E), NL);
766 end New_Copy_List_Original;
768 ------------------------
769 -- New_Copy_List_Tree --
770 ------------------------
772 function New_Copy_List_Tree (List : List_Id) return List_Id is
777 if List = No_List then
784 while Present (E) loop
785 Append (New_Copy_Tree (E), NL);
791 end New_Copy_List_Tree;
797 function New_List return List_Id is
799 procedure New_List_Debug;
800 pragma Inline (New_List_Debug);
801 -- Output debugging information if Debug_Flag_N is set
807 procedure New_List_Debug is
810 Write_Str ("Allocate new list, returned ID = ");
811 Write_Int (Int (Lists.Last));
816 -- Start of processing for New_List
819 Lists.Increment_Last;
822 List : constant List_Id := Lists.Last;
825 Set_Parent (List, Empty);
826 Set_First (List, Empty);
827 Set_Last (List, Empty);
829 pragma Debug (New_List_Debug);
834 -- Since the one argument case is common, we optimize to build the right
835 -- list directly, rather than first building an empty list and then doing
836 -- the insertion, which results in some unnecessary work.
838 function New_List (Node : Node_Id) return List_Id is
840 procedure New_List_Debug;
841 pragma Inline (New_List_Debug);
842 -- Output debugging information if Debug_Flag_N is set
848 procedure New_List_Debug is
851 Write_Str ("Allocate new list, returned ID = ");
852 Write_Int (Int (Lists.Last));
857 -- Start of processing for New_List
864 pragma Assert (not Is_List_Member (Node));
866 Lists.Increment_Last;
869 List : constant List_Id := Lists.Last;
872 Set_Parent (List, Empty);
873 Set_First (List, Node);
874 Set_Last (List, Node);
876 Nodes.Table (Node).In_List := True;
877 Set_List_Link (Node, List);
878 Set_Prev (Node, Empty);
879 Set_Next (Node, Empty);
880 pragma Debug (New_List_Debug);
886 function New_List (Node1, Node2 : Node_Id) return List_Id is
887 L : constant List_Id := New_List (Node1);
893 function New_List (Node1, Node2, Node3 : Node_Id) return List_Id is
894 L : constant List_Id := New_List (Node1);
901 function New_List (Node1, Node2, Node3, Node4 : Node_Id) return List_Id is
902 L : constant List_Id := New_List (Node1);
915 Node5 : Node_Id) return List_Id
917 L : constant List_Id := New_List (Node1);
932 Node6 : Node_Id) return List_Id
934 L : constant List_Id := New_List (Node1);
948 function Next (Node : Node_Id) return Node_Id is
950 pragma Assert (Is_List_Member (Node));
951 return Next_Node.Table (Node);
954 procedure Next (Node : in out Node_Id) is
959 -----------------------
960 -- Next_Node_Address --
961 -----------------------
963 function Next_Node_Address return System.Address is
965 return Next_Node.Table (First_Node_Id)'Address;
966 end Next_Node_Address;
968 ---------------------
969 -- Next_Non_Pragma --
970 ---------------------
972 function Next_Non_Pragma (Node : Node_Id) return Node_Id is
979 exit when Nkind (N) /= N_Pragma
981 Nkind (N) /= N_Null_Statement;
987 procedure Next_Non_Pragma (Node : in out Node_Id) is
989 Node := Next_Non_Pragma (Node);
996 function No (List : List_Id) return Boolean is
998 return List = No_List;
1005 function Num_Lists return Nat is
1007 return Int (Lists.Last) - Int (Lists.First) + 1;
1014 function p (U : Union_Id) return Node_Id is
1016 if U in Node_Range then
1017 return Parent (Node_Id (U));
1018 elsif U in List_Range then
1019 return Parent (List_Id (U));
1029 function Parent (List : List_Id) return Node_Id is
1031 pragma Assert (List in First_List_Id .. Lists.Last);
1032 return Lists.Table (List).Parent;
1039 function Pick (List : List_Id; Index : Pos) return Node_Id is
1043 Elmt := First (List);
1044 for J in 1 .. Index - 1 loop
1045 Elmt := Next (Elmt);
1055 procedure Prepend (Node : Node_Id; To : List_Id) is
1056 F : constant Node_Id := First (To);
1058 procedure Prepend_Debug;
1059 pragma Inline (Prepend_Debug);
1060 -- Output debug information if Debug_Flag_N set
1066 procedure Prepend_Debug is
1068 if Debug_Flag_N then
1069 Write_Str ("Prepend node ");
1070 Write_Int (Int (Node));
1071 Write_Str (" to list ");
1072 Write_Int (Int (To));
1077 -- Start of processing for Prepend_Debug
1080 pragma Assert (not Is_List_Member (Node));
1082 if Node = Error then
1086 pragma Debug (Prepend_Debug);
1089 Set_Last (To, Node);
1094 Set_First (To, Node);
1096 Nodes.Table (Node).In_List := True;
1099 Set_Prev (Node, Empty);
1100 Set_List_Link (Node, To);
1107 procedure Prepend_To (To : List_Id; Node : Node_Id) is
1116 function Present (List : List_Id) return Boolean is
1118 return List /= No_List;
1125 function Prev (Node : Node_Id) return Node_Id is
1127 pragma Assert (Is_List_Member (Node));
1128 return Prev_Node.Table (Node);
1131 procedure Prev (Node : in out Node_Id) is
1133 Node := Prev (Node);
1136 -----------------------
1137 -- Prev_Node_Address --
1138 -----------------------
1140 function Prev_Node_Address return System.Address is
1142 return Prev_Node.Table (First_Node_Id)'Address;
1143 end Prev_Node_Address;
1145 ---------------------
1146 -- Prev_Non_Pragma --
1147 ---------------------
1149 function Prev_Non_Pragma (Node : Node_Id) return Node_Id is
1156 exit when Nkind (N) /= N_Pragma;
1160 end Prev_Non_Pragma;
1162 procedure Prev_Non_Pragma (Node : in out Node_Id) is
1164 Node := Prev_Non_Pragma (Node);
1165 end Prev_Non_Pragma;
1171 procedure Remove (Node : Node_Id) is
1172 Lst : constant List_Id := List_Containing (Node);
1173 Prv : constant Node_Id := Prev (Node);
1174 Nxt : constant Node_Id := Next (Node);
1176 procedure Remove_Debug;
1177 pragma Inline (Remove_Debug);
1178 -- Output debug information if Debug_Flag_N set
1184 procedure Remove_Debug is
1186 if Debug_Flag_N then
1187 Write_Str ("Remove node ");
1188 Write_Int (Int (Node));
1193 -- Start of processing for Remove
1196 pragma Debug (Remove_Debug);
1199 Set_First (Lst, Nxt);
1201 Set_Next (Prv, Nxt);
1205 Set_Last (Lst, Prv);
1207 Set_Prev (Nxt, Prv);
1210 Nodes.Table (Node).In_List := False;
1211 Set_Parent (Node, Empty);
1218 function Remove_Head (List : List_Id) return Node_Id is
1219 Frst : constant Node_Id := First (List);
1221 procedure Remove_Head_Debug;
1222 pragma Inline (Remove_Head_Debug);
1223 -- Output debug information if Debug_Flag_N set
1225 -----------------------
1226 -- Remove_Head_Debug --
1227 -----------------------
1229 procedure Remove_Head_Debug is
1231 if Debug_Flag_N then
1232 Write_Str ("Remove head of list ");
1233 Write_Int (Int (List));
1236 end Remove_Head_Debug;
1238 -- Start of processing for Remove_Head
1241 pragma Debug (Remove_Head_Debug);
1243 if Frst = Empty then
1248 Nxt : constant Node_Id := Next (Frst);
1251 Set_First (List, Nxt);
1254 Set_Last (List, Empty);
1256 Set_Prev (Nxt, Empty);
1259 Nodes.Table (Frst).In_List := False;
1260 Set_Parent (Frst, Empty);
1270 function Remove_Next (Node : Node_Id) return Node_Id is
1271 Nxt : constant Node_Id := Next (Node);
1273 procedure Remove_Next_Debug;
1274 pragma Inline (Remove_Next_Debug);
1275 -- Output debug information if Debug_Flag_N set
1277 -----------------------
1278 -- Remove_Next_Debug --
1279 -----------------------
1281 procedure Remove_Next_Debug is
1283 if Debug_Flag_N then
1284 Write_Str ("Remove next node after ");
1285 Write_Int (Int (Node));
1288 end Remove_Next_Debug;
1290 -- Start of processing for Remove_Next
1293 if Present (Nxt) then
1295 Nxt2 : constant Node_Id := Next (Nxt);
1296 LC : constant List_Id := List_Containing (Node);
1299 pragma Debug (Remove_Next_Debug);
1300 Set_Next (Node, Nxt2);
1303 Set_Last (LC, Node);
1305 Set_Prev (Nxt2, Node);
1308 Nodes.Table (Nxt).In_List := False;
1309 Set_Parent (Nxt, Empty);
1320 procedure Set_First (List : List_Id; To : Node_Id) is
1322 Lists.Table (List).First := To;
1329 procedure Set_Last (List : List_Id; To : Node_Id) is
1331 Lists.Table (List).Last := To;
1338 procedure Set_List_Link (Node : Node_Id; To : List_Id) is
1340 Nodes.Table (Node).Link := Union_Id (To);
1347 procedure Set_Next (Node : Node_Id; To : Node_Id) is
1349 Next_Node.Table (Node) := To;
1356 procedure Set_Parent (List : List_Id; Node : Node_Id) is
1358 pragma Assert (List in First_List_Id .. Lists.Last);
1359 Lists.Table (List).Parent := Node;
1366 procedure Set_Prev (Node : Node_Id; To : Node_Id) is
1368 Prev_Node.Table (Node) := To;
1375 procedure Tree_Read is
1378 Next_Node.Tree_Read;
1379 Prev_Node.Tree_Read;
1386 procedure Tree_Write is
1389 Next_Node.Tree_Write;
1390 Prev_Node.Tree_Write;
1399 Lists.Locked := False;
1400 Prev_Node.Locked := False;
1401 Next_Node.Locked := False;