| ------------------------------------------------------------------------------ |
| -- -- |
| -- GNAT COMPILER COMPONENTS -- |
| -- -- |
| -- N A M E T -- |
| -- -- |
| -- 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. -- |
| -- -- |
| ------------------------------------------------------------------------------ |
| |
| -- WARNING: There is a C version of this package. Any changes to this |
| -- source file must be properly reflected in the C header file namet.h |
| -- which is created manually from namet.ads and namet.adb. |
| |
| with Debug; use Debug; |
| with Opt; use Opt; |
| with Output; use Output; |
| with Widechar; |
| |
| with Interfaces; use Interfaces; |
| |
| package body Namet is |
| |
| Name_Chars_Reserve : constant := 5000; |
| Name_Entries_Reserve : constant := 100; |
| -- The names table is locked during gigi processing, since gigi assumes |
| -- that the table does not move. After returning from gigi, the names |
| -- table is unlocked again, since writing library file information needs |
| -- to generate some extra names. To avoid the inefficiency of always |
| -- reallocating during this second unlocked phase, we reserve a bit of |
| -- extra space before doing the release call. |
| |
| Hash_Num : constant Int := 2**16; |
| -- Number of headers in the hash table. Current hash algorithm is closely |
| -- tailored to this choice, so it can only be changed if a corresponding |
| -- change is made to the hash algorithm. |
| |
| Hash_Max : constant Int := Hash_Num - 1; |
| -- Indexes in the hash header table run from 0 to Hash_Num - 1 |
| |
| subtype Hash_Index_Type is Int range 0 .. Hash_Max; |
| -- Range of hash index values |
| |
| Hash_Table : array (Hash_Index_Type) of Name_Id; |
| -- The hash table is used to locate existing entries in the names table. |
| -- The entries point to the first names table entry whose hash value |
| -- matches the hash code. Then subsequent names table entries with the |
| -- same hash code value are linked through the Hash_Link fields. |
| |
| ----------------------- |
| -- Local Subprograms -- |
| ----------------------- |
| |
| function Hash (Buf : Bounded_String) return Hash_Index_Type; |
| pragma Inline (Hash); |
| -- Compute hash code for name stored in Buf |
| |
| procedure Strip_Qualification_And_Suffixes (Buf : in out Bounded_String); |
| -- Given an encoded entity name in Buf, remove package body |
| -- suffix as described for Strip_Package_Body_Suffix, and also remove |
| -- all qualification, i.e. names followed by two underscores. |
| |
| ----------------------------- |
| -- Add_Char_To_Name_Buffer -- |
| ----------------------------- |
| |
| procedure Add_Char_To_Name_Buffer (C : Character) is |
| begin |
| Append (Global_Name_Buffer, C); |
| end Add_Char_To_Name_Buffer; |
| |
| ---------------------------- |
| -- Add_Nat_To_Name_Buffer -- |
| ---------------------------- |
| |
| procedure Add_Nat_To_Name_Buffer (V : Nat) is |
| begin |
| Append (Global_Name_Buffer, V); |
| end Add_Nat_To_Name_Buffer; |
| |
| ---------------------------- |
| -- Add_Str_To_Name_Buffer -- |
| ---------------------------- |
| |
| procedure Add_Str_To_Name_Buffer (S : String) is |
| begin |
| Append (Global_Name_Buffer, S); |
| end Add_Str_To_Name_Buffer; |
| |
| ------------ |
| -- Append -- |
| ------------ |
| |
| procedure Append (Buf : in out Bounded_String; C : Character) is |
| begin |
| Buf.Length := Buf.Length + 1; |
| |
| if Buf.Length > Buf.Chars'Last then |
| Write_Str ("Name buffer overflow; Max_Length = "); |
| Write_Int (Int (Buf.Max_Length)); |
| Write_Line (""); |
| raise Program_Error; |
| end if; |
| |
| Buf.Chars (Buf.Length) := C; |
| end Append; |
| |
| procedure Append (Buf : in out Bounded_String; V : Nat) is |
| begin |
| if V >= 10 then |
| Append (Buf, V / 10); |
| end if; |
| |
| Append (Buf, Character'Val (Character'Pos ('0') + V rem 10)); |
| end Append; |
| |
| procedure Append (Buf : in out Bounded_String; S : String) is |
| First : constant Natural := Buf.Length + 1; |
| begin |
| Buf.Length := Buf.Length + S'Length; |
| |
| if Buf.Length > Buf.Chars'Last then |
| Write_Str ("Name buffer overflow; Max_Length = "); |
| Write_Int (Int (Buf.Max_Length)); |
| Write_Line (""); |
| raise Program_Error; |
| end if; |
| |
| Buf.Chars (First .. Buf.Length) := S; |
| -- A loop calling Append(Character) would be cleaner, but this slice |
| -- assignment is substantially faster. |
| end Append; |
| |
| procedure Append (Buf : in out Bounded_String; Buf2 : Bounded_String) is |
| begin |
| Append (Buf, Buf2.Chars (1 .. Buf2.Length)); |
| end Append; |
| |
| procedure Append (Buf : in out Bounded_String; Id : Valid_Name_Id) is |
| pragma Assert (Is_Valid_Name (Id)); |
| |
| Index : constant Int := Name_Entries.Table (Id).Name_Chars_Index; |
| Len : constant Short := Name_Entries.Table (Id).Name_Len; |
| Chars : Name_Chars.Table_Type renames |
| Name_Chars.Table (Index + 1 .. Index + Int (Len)); |
| begin |
| Append (Buf, String (Chars)); |
| end Append; |
| |
| -------------------- |
| -- Append_Decoded -- |
| -------------------- |
| |
| procedure Append_Decoded |
| (Buf : in out Bounded_String; |
| Id : Valid_Name_Id) |
| is |
| Temp : Bounded_String; |
| |
| function Has_Encodings (Temp : Bounded_String) return Boolean; |
| -- True if Temp contains encoded characters. If not, we can set |
| -- Name_Has_No_Encodings to True below, and never call this again |
| -- on the same Name_Id. |
| |
| function Has_Encodings (Temp : Bounded_String) return Boolean is |
| begin |
| for J in 1 .. Temp.Length loop |
| if Temp.Chars (J) in 'U' | 'W' | 'Q' | 'O' then |
| return True; |
| end if; |
| end loop; |
| |
| return False; |
| end Has_Encodings; |
| |
| begin |
| Append (Temp, Id); |
| |
| -- Skip scan if we already know there are no encodings (i.e. the first |
| -- time this was called on Id, the Has_Encodings call below returned |
| -- False). |
| |
| if Name_Entries.Table (Id).Name_Has_No_Encodings then |
| goto Done; |
| end if; |
| |
| if not Has_Encodings (Temp) then |
| Name_Entries.Table (Id).Name_Has_No_Encodings := True; |
| goto Done; |
| end if; |
| |
| -- Here we have at least some encoding that we must decode |
| |
| Decode : declare |
| New_Len : Natural; |
| Old : Positive; |
| New_Buf : String (1 .. Temp.Chars'Last); |
| |
| procedure Copy_One_Character; |
| -- Copy a character from Temp.Chars to New_Buf. Includes case |
| -- of copying a Uhh,Whhhh,WWhhhhhhhh sequence and decoding it. |
| |
| function Hex (N : Natural) return Word; |
| -- Scans past N digits using Old pointer and returns hex value |
| |
| procedure Insert_Character (C : Character); |
| -- Insert a new character into output decoded name |
| |
| ------------------------ |
| -- Copy_One_Character -- |
| ------------------------ |
| |
| procedure Copy_One_Character is |
| C : Character; |
| |
| begin |
| C := Temp.Chars (Old); |
| |
| -- U (upper half insertion case) |
| |
| if C = 'U' |
| and then Old < Temp.Length |
| and then Temp.Chars (Old + 1) not in 'A' .. 'Z' | '_' |
| then |
| Old := Old + 1; |
| |
| -- If we have upper half encoding, then we have to set an |
| -- appropriate wide character sequence for this character. |
| |
| if Upper_Half_Encoding then |
| Widechar.Set_Wide (Char_Code (Hex (2)), New_Buf, New_Len); |
| |
| -- For other encoding methods, upper half characters can |
| -- simply use their normal representation. |
| |
| else |
| declare |
| W2 : constant Word := Hex (2); |
| begin |
| pragma Assert (W2 <= 255); |
| -- Add assumption to facilitate static analysis. Note |
| -- that we cannot use pragma Assume for bootstrap |
| -- reasons. |
| Insert_Character (Character'Val (W2)); |
| end; |
| end if; |
| |
| -- WW (wide wide character insertion) |
| |
| elsif C = 'W' |
| and then Old < Temp.Length |
| and then Temp.Chars (Old + 1) = 'W' |
| then |
| Old := Old + 2; |
| Widechar.Set_Wide (Char_Code (Hex (8)), New_Buf, New_Len); |
| |
| -- W (wide character insertion) |
| |
| elsif C = 'W' |
| and then Old < Temp.Length |
| and then Temp.Chars (Old + 1) not in 'A' .. 'Z' | '_' |
| then |
| Old := Old + 1; |
| Widechar.Set_Wide (Char_Code (Hex (4)), New_Buf, New_Len); |
| |
| -- Any other character is copied unchanged |
| |
| else |
| Insert_Character (C); |
| Old := Old + 1; |
| end if; |
| end Copy_One_Character; |
| |
| --------- |
| -- Hex -- |
| --------- |
| |
| function Hex (N : Natural) return Word is |
| T : Word := 0; |
| C : Character; |
| |
| begin |
| for J in 1 .. N loop |
| C := Temp.Chars (Old); |
| Old := Old + 1; |
| |
| pragma Assert (C in '0' .. '9' | 'a' .. 'f'); |
| |
| if C <= '9' then |
| T := 16 * T + Character'Pos (C) - Character'Pos ('0'); |
| else -- C in 'a' .. 'f' |
| T := 16 * T + Character'Pos (C) - (Character'Pos ('a') - 10); |
| end if; |
| end loop; |
| |
| return T; |
| end Hex; |
| |
| ---------------------- |
| -- Insert_Character -- |
| ---------------------- |
| |
| procedure Insert_Character (C : Character) is |
| begin |
| New_Len := New_Len + 1; |
| New_Buf (New_Len) := C; |
| end Insert_Character; |
| |
| -- Start of processing for Decode |
| |
| begin |
| New_Len := 0; |
| Old := 1; |
| |
| -- Loop through characters of name |
| |
| while Old <= Temp.Length loop |
| |
| -- Case of character literal, put apostrophes around character |
| |
| if Temp.Chars (Old) = 'Q' |
| and then Old < Temp.Length |
| then |
| Old := Old + 1; |
| Insert_Character ('''); |
| Copy_One_Character; |
| Insert_Character ('''); |
| |
| -- Case of operator name |
| |
| elsif Temp.Chars (Old) = 'O' |
| and then Old < Temp.Length |
| and then Temp.Chars (Old + 1) not in 'A' .. 'Z' | '_' |
| then |
| Old := Old + 1; |
| |
| declare |
| -- This table maps the 2nd and 3rd characters of the name |
| -- into the required output. Two blanks means leave the |
| -- name alone |
| |
| Map : constant String := |
| "ab " & -- Oabs => "abs" |
| "ad+ " & -- Oadd => "+" |
| "an " & -- Oand => "and" |
| "co& " & -- Oconcat => "&" |
| "di/ " & -- Odivide => "/" |
| "eq= " & -- Oeq => "=" |
| "ex**" & -- Oexpon => "**" |
| "gt> " & -- Ogt => ">" |
| "ge>=" & -- Oge => ">=" |
| "le<=" & -- Ole => "<=" |
| "lt< " & -- Olt => "<" |
| "mo " & -- Omod => "mod" |
| "mu* " & -- Omutliply => "*" |
| "ne/=" & -- One => "/=" |
| "no " & -- Onot => "not" |
| "or " & -- Oor => "or" |
| "re " & -- Orem => "rem" |
| "su- " & -- Osubtract => "-" |
| "xo "; -- Oxor => "xor" |
| |
| J : Integer; |
| |
| begin |
| Insert_Character ('"'); |
| |
| -- Search the map. Note that this loop must terminate, if |
| -- not we have some kind of internal error, and a constraint |
| -- error may be raised. |
| |
| J := Map'First; |
| loop |
| exit when Temp.Chars (Old) = Map (J) |
| and then Temp.Chars (Old + 1) = Map (J + 1); |
| J := J + 4; |
| end loop; |
| |
| -- Special operator name |
| |
| if Map (J + 2) /= ' ' then |
| Insert_Character (Map (J + 2)); |
| |
| if Map (J + 3) /= ' ' then |
| Insert_Character (Map (J + 3)); |
| end if; |
| |
| Insert_Character ('"'); |
| |
| -- Skip past original operator name in input |
| |
| while Old <= Temp.Length |
| and then Temp.Chars (Old) in 'a' .. 'z' |
| loop |
| Old := Old + 1; |
| end loop; |
| |
| -- For other operator names, leave them in lower case, |
| -- surrounded by apostrophes |
| |
| else |
| -- Copy original operator name from input to output |
| |
| while Old <= Temp.Length |
| and then Temp.Chars (Old) in 'a' .. 'z' |
| loop |
| Copy_One_Character; |
| end loop; |
| |
| Insert_Character ('"'); |
| end if; |
| end; |
| |
| -- Else copy one character and keep going |
| |
| else |
| Copy_One_Character; |
| end if; |
| end loop; |
| |
| -- Copy new buffer as result |
| |
| Temp.Length := New_Len; |
| Temp.Chars (1 .. New_Len) := New_Buf (1 .. New_Len); |
| end Decode; |
| |
| <<Done>> |
| Append (Buf, Temp); |
| end Append_Decoded; |
| |
| ---------------------------------- |
| -- Append_Decoded_With_Brackets -- |
| ---------------------------------- |
| |
| procedure Append_Decoded_With_Brackets |
| (Buf : in out Bounded_String; |
| Id : Valid_Name_Id) |
| is |
| P : Natural; |
| |
| begin |
| -- Case of operator name, normal decoding is fine |
| |
| if Buf.Chars (1) = 'O' then |
| Append_Decoded (Buf, Id); |
| |
| -- For character literals, normal decoding is fine |
| |
| elsif Buf.Chars (1) = 'Q' then |
| Append_Decoded (Buf, Id); |
| |
| -- Only remaining issue is U/W/WW sequences |
| |
| else |
| declare |
| Temp : Bounded_String; |
| begin |
| Append (Temp, Id); |
| |
| P := 1; |
| while P < Temp.Length loop |
| if Temp.Chars (P + 1) in 'A' .. 'Z' then |
| P := P + 1; |
| |
| -- Uhh encoding |
| |
| elsif Temp.Chars (P) = 'U' then |
| for J in reverse P + 3 .. P + Temp.Length loop |
| Temp.Chars (J + 3) := Temp.Chars (J); |
| end loop; |
| |
| Temp.Length := Temp.Length + 3; |
| Temp.Chars (P + 3) := Temp.Chars (P + 2); |
| Temp.Chars (P + 2) := Temp.Chars (P + 1); |
| Temp.Chars (P) := '['; |
| Temp.Chars (P + 1) := '"'; |
| Temp.Chars (P + 4) := '"'; |
| Temp.Chars (P + 5) := ']'; |
| P := P + 6; |
| |
| -- WWhhhhhhhh encoding |
| |
| elsif Temp.Chars (P) = 'W' |
| and then P + 9 <= Temp.Length |
| and then Temp.Chars (P + 1) = 'W' |
| and then Temp.Chars (P + 2) not in 'A' .. 'Z' | '_' |
| then |
| Temp.Chars (P + 12 .. Temp.Length + 2) := |
| Temp.Chars (P + 10 .. Temp.Length); |
| Temp.Chars (P) := '['; |
| Temp.Chars (P + 1) := '"'; |
| Temp.Chars (P + 10) := '"'; |
| Temp.Chars (P + 11) := ']'; |
| Temp.Length := Temp.Length + 2; |
| P := P + 12; |
| |
| -- Whhhh encoding |
| |
| elsif Temp.Chars (P) = 'W' |
| and then P < Temp.Length |
| and then Temp.Chars (P + 1) not in 'A' .. 'Z' | '_' |
| then |
| Temp.Chars (P + 8 .. P + Temp.Length + 3) := |
| Temp.Chars (P + 5 .. Temp.Length); |
| Temp.Chars (P + 2 .. P + 5) := Temp.Chars (P + 1 .. P + 4); |
| Temp.Chars (P) := '['; |
| Temp.Chars (P + 1) := '"'; |
| Temp.Chars (P + 6) := '"'; |
| Temp.Chars (P + 7) := ']'; |
| Temp.Length := Temp.Length + 3; |
| P := P + 8; |
| |
| else |
| P := P + 1; |
| end if; |
| end loop; |
| |
| Append (Buf, Temp); |
| end; |
| end if; |
| end Append_Decoded_With_Brackets; |
| |
| -------------------- |
| -- Append_Encoded -- |
| -------------------- |
| |
| procedure Append_Encoded (Buf : in out Bounded_String; C : Char_Code) is |
| procedure Set_Hex_Chars (C : Char_Code); |
| -- Stores given value, which is in the range 0 .. 255, as two hex |
| -- digits (using lower case a-f) in Buf.Chars, incrementing Buf.Length. |
| |
| ------------------- |
| -- Set_Hex_Chars -- |
| ------------------- |
| |
| procedure Set_Hex_Chars (C : Char_Code) is |
| Hexd : constant String := "0123456789abcdef"; |
| N : constant Natural := Natural (C); |
| begin |
| Buf.Chars (Buf.Length + 1) := Hexd (N / 16 + 1); |
| Buf.Chars (Buf.Length + 2) := Hexd (N mod 16 + 1); |
| Buf.Length := Buf.Length + 2; |
| end Set_Hex_Chars; |
| |
| -- Start of processing for Append_Encoded |
| |
| begin |
| Buf.Length := Buf.Length + 1; |
| |
| if In_Character_Range (C) then |
| declare |
| CC : constant Character := Get_Character (C); |
| begin |
| if CC in 'a' .. 'z' | '0' .. '9' then |
| Buf.Chars (Buf.Length) := CC; |
| else |
| Buf.Chars (Buf.Length) := 'U'; |
| Set_Hex_Chars (C); |
| end if; |
| end; |
| |
| elsif In_Wide_Character_Range (C) then |
| Buf.Chars (Buf.Length) := 'W'; |
| Set_Hex_Chars (C / 256); |
| Set_Hex_Chars (C mod 256); |
| |
| else |
| Buf.Chars (Buf.Length) := 'W'; |
| Buf.Length := Buf.Length + 1; |
| Buf.Chars (Buf.Length) := 'W'; |
| Set_Hex_Chars (C / 2 ** 24); |
| Set_Hex_Chars ((C / 2 ** 16) mod 256); |
| Set_Hex_Chars ((C / 256) mod 256); |
| Set_Hex_Chars (C mod 256); |
| end if; |
| end Append_Encoded; |
| |
| ------------------------ |
| -- Append_Unqualified -- |
| ------------------------ |
| |
| procedure Append_Unqualified |
| (Buf : in out Bounded_String; |
| Id : Valid_Name_Id) |
| is |
| Temp : Bounded_String; |
| begin |
| Append (Temp, Id); |
| Strip_Qualification_And_Suffixes (Temp); |
| Append (Buf, Temp); |
| end Append_Unqualified; |
| |
| -------------------------------- |
| -- Append_Unqualified_Decoded -- |
| -------------------------------- |
| |
| procedure Append_Unqualified_Decoded |
| (Buf : in out Bounded_String; |
| Id : Valid_Name_Id) |
| is |
| Temp : Bounded_String; |
| begin |
| Append_Decoded (Temp, Id); |
| Strip_Qualification_And_Suffixes (Temp); |
| Append (Buf, Temp); |
| end Append_Unqualified_Decoded; |
| |
| -------------------------------- |
| -- Destroy_Global_Name_Buffer -- |
| -------------------------------- |
| |
| procedure Destroy_Global_Name_Buffer is |
| procedure Do_It; |
| -- Do the work. Needed only for "pragma Debug" below, so we don't do |
| -- anything in production mode. |
| |
| procedure Do_It is |
| begin |
| Global_Name_Buffer.Length := Global_Name_Buffer.Max_Length; |
| Global_Name_Buffer.Chars := (others => '!'); |
| end Do_It; |
| pragma Debug (Do_It); |
| begin |
| null; |
| end Destroy_Global_Name_Buffer; |
| |
| -------------- |
| -- Finalize -- |
| -------------- |
| |
| procedure Finalize is |
| F : array (Int range 0 .. 50) of Int; |
| -- N'th entry is the number of chains of length N, except last entry, |
| -- which is the number of chains of length F'Last or more. |
| |
| Max_Chain_Length : Nat := 0; |
| -- Maximum length of all chains |
| |
| Probes : Nat := 0; |
| -- Used to compute average number of probes |
| |
| Nsyms : Nat := 0; |
| -- Number of symbols in table |
| |
| Verbosity : constant Int range 1 .. 3 := 1; |
| pragma Warnings (Off, Verbosity); |
| -- This constant indicates the level of verbosity in the output from |
| -- this procedure. Currently this can only be changed by editing the |
| -- declaration above and recompiling. That's good enough in practice, |
| -- since we very rarely need to use this debug option. Settings are: |
| -- |
| -- 1 => print basic summary information |
| -- 2 => in addition print number of entries per hash chain |
| -- 3 => in addition print content of entries |
| |
| Zero : constant Int := Character'Pos ('0'); |
| |
| begin |
| if not Debug_Flag_H then |
| return; |
| end if; |
| |
| for J in F'Range loop |
| F (J) := 0; |
| end loop; |
| |
| for J in Hash_Index_Type loop |
| if Hash_Table (J) = No_Name then |
| F (0) := F (0) + 1; |
| |
| else |
| declare |
| C : Nat; |
| N : Name_Id; |
| S : Int; |
| |
| begin |
| C := 0; |
| N := Hash_Table (J); |
| |
| while N /= No_Name loop |
| N := Name_Entries.Table (N).Hash_Link; |
| C := C + 1; |
| end loop; |
| |
| Nsyms := Nsyms + 1; |
| Probes := Probes + (1 + C) * 100; |
| |
| if C > Max_Chain_Length then |
| Max_Chain_Length := C; |
| end if; |
| |
| if Verbosity >= 2 then |
| Write_Str ("Hash_Table ("); |
| Write_Int (J); |
| Write_Str (") has "); |
| Write_Int (C); |
| Write_Str (" entries"); |
| Write_Eol; |
| end if; |
| |
| if C < F'Last then |
| F (C) := F (C) + 1; |
| else |
| F (F'Last) := F (F'Last) + 1; |
| end if; |
| |
| if Verbosity >= 3 then |
| N := Hash_Table (J); |
| while N /= No_Name loop |
| S := Name_Entries.Table (N).Name_Chars_Index; |
| |
| Write_Str (" "); |
| |
| for J in 1 .. Name_Entries.Table (N).Name_Len loop |
| Write_Char (Name_Chars.Table (S + Int (J))); |
| end loop; |
| |
| Write_Eol; |
| |
| N := Name_Entries.Table (N).Hash_Link; |
| end loop; |
| end if; |
| end; |
| end if; |
| end loop; |
| |
| Write_Eol; |
| |
| for J in F'Range loop |
| if F (J) /= 0 then |
| Write_Str ("Number of hash chains of length "); |
| |
| if J < 10 then |
| Write_Char (' '); |
| end if; |
| |
| Write_Int (J); |
| |
| if J = F'Last then |
| Write_Str (" or greater"); |
| end if; |
| |
| Write_Str (" = "); |
| Write_Int (F (J)); |
| Write_Eol; |
| end if; |
| end loop; |
| |
| -- Print out average number of probes, in the case where Name_Find is |
| -- called for a string that is already in the table. |
| |
| Write_Eol; |
| Write_Str ("Average number of probes for lookup = "); |
| pragma Assert (Nsyms /= 0); |
| -- Add assumption to facilitate static analysis. Here Nsyms cannot be |
| -- zero because many symbols are added to the table by default. |
| Probes := Probes / Nsyms; |
| Write_Int (Probes / 200); |
| Write_Char ('.'); |
| Probes := (Probes mod 200) / 2; |
| Write_Char (Character'Val (Zero + Probes / 10)); |
| Write_Char (Character'Val (Zero + Probes mod 10)); |
| Write_Eol; |
| |
| Write_Str ("Max_Chain_Length = "); |
| Write_Int (Max_Chain_Length); |
| Write_Eol; |
| Write_Str ("Name_Chars'Length = "); |
| Write_Int (Name_Chars.Last - Name_Chars.First + 1); |
| Write_Eol; |
| Write_Str ("Name_Entries'Length = "); |
| Write_Int (Int (Name_Entries.Last - Name_Entries.First + 1)); |
| Write_Eol; |
| Write_Str ("Nsyms = "); |
| Write_Int (Nsyms); |
| Write_Eol; |
| end Finalize; |
| |
| ----------------------------- |
| -- Get_Decoded_Name_String -- |
| ----------------------------- |
| |
| procedure Get_Decoded_Name_String (Id : Valid_Name_Id) is |
| begin |
| Global_Name_Buffer.Length := 0; |
| Append_Decoded (Global_Name_Buffer, Id); |
| end Get_Decoded_Name_String; |
| |
| ------------------------------------------- |
| -- Get_Decoded_Name_String_With_Brackets -- |
| ------------------------------------------- |
| |
| procedure Get_Decoded_Name_String_With_Brackets (Id : Valid_Name_Id) is |
| begin |
| Global_Name_Buffer.Length := 0; |
| Append_Decoded_With_Brackets (Global_Name_Buffer, Id); |
| end Get_Decoded_Name_String_With_Brackets; |
| |
| ------------------------ |
| -- Get_Last_Two_Chars -- |
| ------------------------ |
| |
| procedure Get_Last_Two_Chars |
| (N : Valid_Name_Id; |
| C1 : out Character; |
| C2 : out Character) |
| is |
| NE : Name_Entry renames Name_Entries.Table (N); |
| NEL : constant Int := Int (NE.Name_Len); |
| |
| begin |
| if NEL >= 2 then |
| C1 := Name_Chars.Table (NE.Name_Chars_Index + NEL - 1); |
| C2 := Name_Chars.Table (NE.Name_Chars_Index + NEL - 0); |
| else |
| C1 := ASCII.NUL; |
| C2 := ASCII.NUL; |
| end if; |
| end Get_Last_Two_Chars; |
| |
| --------------------- |
| -- Get_Name_String -- |
| --------------------- |
| |
| procedure Get_Name_String (Id : Valid_Name_Id) is |
| begin |
| Global_Name_Buffer.Length := 0; |
| Append (Global_Name_Buffer, Id); |
| end Get_Name_String; |
| |
| function Get_Name_String (Id : Valid_Name_Id) return String is |
| Buf : Bounded_String (Max_Length => Natural (Length_Of_Name (Id))); |
| begin |
| Append (Buf, Id); |
| return +Buf; |
| end Get_Name_String; |
| |
| -------------------------------- |
| -- Get_Name_String_And_Append -- |
| -------------------------------- |
| |
| procedure Get_Name_String_And_Append (Id : Valid_Name_Id) is |
| begin |
| Append (Global_Name_Buffer, Id); |
| end Get_Name_String_And_Append; |
| |
| ----------------------------- |
| -- Get_Name_Table_Boolean1 -- |
| ----------------------------- |
| |
| function Get_Name_Table_Boolean1 (Id : Valid_Name_Id) return Boolean is |
| begin |
| pragma Assert (Is_Valid_Name (Id)); |
| return Name_Entries.Table (Id).Boolean1_Info; |
| end Get_Name_Table_Boolean1; |
| |
| ----------------------------- |
| -- Get_Name_Table_Boolean2 -- |
| ----------------------------- |
| |
| function Get_Name_Table_Boolean2 (Id : Valid_Name_Id) return Boolean is |
| begin |
| pragma Assert (Is_Valid_Name (Id)); |
| return Name_Entries.Table (Id).Boolean2_Info; |
| end Get_Name_Table_Boolean2; |
| |
| ----------------------------- |
| -- Get_Name_Table_Boolean3 -- |
| ----------------------------- |
| |
| function Get_Name_Table_Boolean3 (Id : Valid_Name_Id) return Boolean is |
| begin |
| pragma Assert (Is_Valid_Name (Id)); |
| return Name_Entries.Table (Id).Boolean3_Info; |
| end Get_Name_Table_Boolean3; |
| |
| ------------------------- |
| -- Get_Name_Table_Byte -- |
| ------------------------- |
| |
| function Get_Name_Table_Byte (Id : Valid_Name_Id) return Byte is |
| begin |
| pragma Assert (Is_Valid_Name (Id)); |
| return Name_Entries.Table (Id).Byte_Info; |
| end Get_Name_Table_Byte; |
| |
| ------------------------- |
| -- Get_Name_Table_Int -- |
| ------------------------- |
| |
| function Get_Name_Table_Int (Id : Valid_Name_Id) return Int is |
| begin |
| pragma Assert (Is_Valid_Name (Id)); |
| return Name_Entries.Table (Id).Int_Info; |
| end Get_Name_Table_Int; |
| |
| ----------------------------------------- |
| -- Get_Unqualified_Decoded_Name_String -- |
| ----------------------------------------- |
| |
| procedure Get_Unqualified_Decoded_Name_String (Id : Valid_Name_Id) is |
| begin |
| Global_Name_Buffer.Length := 0; |
| Append_Unqualified_Decoded (Global_Name_Buffer, Id); |
| end Get_Unqualified_Decoded_Name_String; |
| |
| --------------------------------- |
| -- Get_Unqualified_Name_String -- |
| --------------------------------- |
| |
| procedure Get_Unqualified_Name_String (Id : Valid_Name_Id) is |
| begin |
| Global_Name_Buffer.Length := 0; |
| Append_Unqualified (Global_Name_Buffer, Id); |
| end Get_Unqualified_Name_String; |
| |
| ---------- |
| -- Hash -- |
| ---------- |
| |
| function Hash (Buf : Bounded_String) return Hash_Index_Type is |
| |
| -- This hash function looks at every character, in order to make it |
| -- likely that similar strings get different hash values. The rotate by |
| -- 7 bits has been determined empirically to be good, and it doesn't |
| -- lose bits like a shift would. The final conversion can't overflow, |
| -- because the table is 2**16 in size. This function probably needs to |
| -- be changed if the hash table size is changed. |
| |
| -- Note that we could get some speed improvement by aligning the string |
| -- to 32 or 64 bits, and doing word-wise xor's. We could also implement |
| -- a growable table. It doesn't seem worth the trouble to do those |
| -- things, for now. |
| |
| Result : Unsigned_16 := 0; |
| |
| begin |
| for J in 1 .. Buf.Length loop |
| Result := Rotate_Left (Result, 7) xor Character'Pos (Buf.Chars (J)); |
| end loop; |
| |
| return Hash_Index_Type (Result); |
| end Hash; |
| |
| ---------------- |
| -- Initialize -- |
| ---------------- |
| |
| procedure Initialize is |
| begin |
| null; |
| end Initialize; |
| |
| ---------------- |
| -- Insert_Str -- |
| ---------------- |
| |
| procedure Insert_Str |
| (Buf : in out Bounded_String; |
| S : String; |
| Index : Positive) |
| is |
| SL : constant Natural := S'Length; |
| |
| begin |
| Buf.Chars (Index + SL .. Buf.Length + SL) := |
| Buf.Chars (Index .. Buf.Length); |
| Buf.Chars (Index .. Index + SL - 1) := S; |
| Buf.Length := Buf.Length + SL; |
| end Insert_Str; |
| |
| ------------------------------- |
| -- Insert_Str_In_Name_Buffer -- |
| ------------------------------- |
| |
| procedure Insert_Str_In_Name_Buffer (S : String; Index : Positive) is |
| begin |
| Insert_Str (Global_Name_Buffer, S, Index); |
| end Insert_Str_In_Name_Buffer; |
| |
| ---------------------- |
| -- Is_Internal_Name -- |
| ---------------------- |
| |
| function Is_Internal_Name (Buf : Bounded_String) return Boolean is |
| J : Natural; |
| |
| begin |
| -- Any name starting or ending with underscore is internal |
| |
| if Buf.Chars (1) = '_' or else Buf.Chars (Buf.Length) = '_' then |
| return True; |
| |
| -- Allow quoted character |
| |
| elsif Buf.Chars (1) = ''' then |
| return False; |
| |
| -- All other cases, scan name |
| |
| else |
| -- Test backwards, because we only want to test the last entity |
| -- name if the name we have is qualified with other entities. |
| |
| J := Buf.Length; |
| while J /= 0 loop |
| |
| -- Skip stuff between brackets (A-F OK there) |
| |
| if Buf.Chars (J) = ']' then |
| loop |
| J := J - 1; |
| exit when J = 1 or else Buf.Chars (J) = '['; |
| end loop; |
| |
| -- Test for internal letter |
| |
| elsif Is_OK_Internal_Letter (Buf.Chars (J)) then |
| return True; |
| |
| -- Quit if we come to terminating double underscore (note that |
| -- if the current character is an underscore, we know that |
| -- there is a previous character present, since we already |
| -- filtered out the case of Buf.Chars (1) = '_' above. |
| |
| elsif Buf.Chars (J) = '_' |
| and then Buf.Chars (J - 1) = '_' |
| and then Buf.Chars (J - 2) /= '_' |
| then |
| return False; |
| end if; |
| |
| J := J - 1; |
| end loop; |
| end if; |
| |
| return False; |
| end Is_Internal_Name; |
| |
| function Is_Internal_Name (Id : Valid_Name_Id) return Boolean is |
| Buf : Bounded_String (Max_Length => Natural (Length_Of_Name (Id))); |
| begin |
| Append (Buf, Id); |
| return Is_Internal_Name (Buf); |
| end Is_Internal_Name; |
| |
| function Is_Internal_Name return Boolean is |
| begin |
| return Is_Internal_Name (Global_Name_Buffer); |
| end Is_Internal_Name; |
| |
| --------------------------- |
| -- Is_OK_Internal_Letter -- |
| --------------------------- |
| |
| function Is_OK_Internal_Letter (C : Character) return Boolean is |
| begin |
| return C in 'A' .. 'Z' and then C not in 'O' | 'Q' | 'U' | 'W' | 'X'; |
| end Is_OK_Internal_Letter; |
| |
| ---------------------- |
| -- Is_Operator_Name -- |
| ---------------------- |
| |
| function Is_Operator_Name (Id : Valid_Name_Id) return Boolean is |
| S : Int; |
| begin |
| pragma Assert (Is_Valid_Name (Id)); |
| S := Name_Entries.Table (Id).Name_Chars_Index; |
| return Name_Chars.Table (S + 1) = 'O'; |
| end Is_Operator_Name; |
| |
| ------------------- |
| -- Is_Valid_Name -- |
| ------------------- |
| |
| function Is_Valid_Name (Id : Name_Id) return Boolean is |
| begin |
| return Id in Name_Entries.First .. Name_Entries.Last; |
| end Is_Valid_Name; |
| |
| ------------------ |
| -- Last_Name_Id -- |
| ------------------ |
| |
| function Last_Name_Id return Name_Id is |
| begin |
| return Name_Id (Int (First_Name_Id) + Name_Entries_Count - 1); |
| end Last_Name_Id; |
| |
| -------------------- |
| -- Length_Of_Name -- |
| -------------------- |
| |
| function Length_Of_Name (Id : Valid_Name_Id) return Nat is |
| begin |
| return Int (Name_Entries.Table (Id).Name_Len); |
| end Length_Of_Name; |
| |
| ---------- |
| -- Lock -- |
| ---------- |
| |
| procedure Lock is |
| begin |
| Name_Chars.Set_Last (Name_Chars.Last + Name_Chars_Reserve); |
| Name_Entries.Set_Last (Name_Entries.Last + Name_Entries_Reserve); |
| Name_Chars.Release; |
| Name_Chars.Locked := True; |
| Name_Entries.Release; |
| Name_Entries.Locked := True; |
| end Lock; |
| |
| ---------------- |
| -- Name_Enter -- |
| ---------------- |
| |
| function Name_Enter |
| (Buf : Bounded_String := Global_Name_Buffer) return Valid_Name_Id |
| is |
| begin |
| Name_Entries.Append |
| ((Name_Chars_Index => Name_Chars.Last, |
| Name_Len => Short (Buf.Length), |
| Byte_Info => 0, |
| Int_Info => 0, |
| Hash_Link => No_Name, |
| Name_Has_No_Encodings => False, |
| Boolean1_Info => False, |
| Boolean2_Info => False, |
| Boolean3_Info => False, |
| Spare => False)); |
| |
| -- Set corresponding string entry in the Name_Chars table |
| |
| for J in 1 .. Buf.Length loop |
| Name_Chars.Append (Buf.Chars (J)); |
| end loop; |
| |
| Name_Chars.Append (ASCII.NUL); |
| |
| return Name_Entries.Last; |
| end Name_Enter; |
| |
| function Name_Enter (S : String) return Valid_Name_Id is |
| Buf : Bounded_String (Max_Length => S'Length); |
| begin |
| Append (Buf, S); |
| return Name_Enter (Buf); |
| end Name_Enter; |
| |
| ------------------------ |
| -- Name_Entries_Count -- |
| ------------------------ |
| |
| function Name_Entries_Count return Nat is |
| begin |
| return Int (Name_Entries.Last - Name_Entries.First + 1); |
| end Name_Entries_Count; |
| |
| --------------- |
| -- Name_Find -- |
| --------------- |
| |
| function Name_Find |
| (Buf : Bounded_String := Global_Name_Buffer) return Valid_Name_Id |
| is |
| New_Id : Name_Id; |
| -- Id of entry in hash search, and value to be returned |
| |
| S : Int; |
| -- Pointer into string table |
| |
| Hash_Index : Hash_Index_Type; |
| -- Computed hash index |
| |
| Result : Valid_Name_Id; |
| |
| begin |
| -- Quick handling for one character names |
| |
| if Buf.Length = 1 then |
| Result := First_Name_Id + Character'Pos (Buf.Chars (1)); |
| |
| -- Otherwise search hash table for existing matching entry |
| |
| else |
| Hash_Index := Namet.Hash (Buf); |
| New_Id := Hash_Table (Hash_Index); |
| |
| if New_Id = No_Name then |
| Hash_Table (Hash_Index) := Name_Entries.Last + 1; |
| |
| else |
| Search : loop |
| if Buf.Length /= |
| Integer (Name_Entries.Table (New_Id).Name_Len) |
| then |
| goto No_Match; |
| end if; |
| |
| S := Name_Entries.Table (New_Id).Name_Chars_Index; |
| |
| for J in 1 .. Buf.Length loop |
| if Name_Chars.Table (S + Int (J)) /= Buf.Chars (J) then |
| goto No_Match; |
| end if; |
| end loop; |
| |
| Result := New_Id; |
| goto Done; |
| |
| -- Current entry in hash chain does not match |
| |
| <<No_Match>> |
| if Name_Entries.Table (New_Id).Hash_Link /= No_Name then |
| New_Id := Name_Entries.Table (New_Id).Hash_Link; |
| else |
| Name_Entries.Table (New_Id).Hash_Link := |
| Name_Entries.Last + 1; |
| exit Search; |
| end if; |
| end loop Search; |
| end if; |
| |
| -- We fall through here only if a matching entry was not found in the |
| -- hash table. We now create a new entry in the names table. The hash |
| -- link pointing to the new entry (Name_Entries.Last+1) has been set. |
| |
| Name_Entries.Append |
| ((Name_Chars_Index => Name_Chars.Last, |
| Name_Len => Short (Buf.Length), |
| Hash_Link => No_Name, |
| Int_Info => 0, |
| Byte_Info => 0, |
| Name_Has_No_Encodings => False, |
| Boolean1_Info => False, |
| Boolean2_Info => False, |
| Boolean3_Info => False, |
| Spare => False)); |
| |
| -- Set corresponding string entry in the Name_Chars table |
| |
| for J in 1 .. Buf.Length loop |
| Name_Chars.Append (Buf.Chars (J)); |
| end loop; |
| |
| Name_Chars.Append (ASCII.NUL); |
| |
| Result := Name_Entries.Last; |
| end if; |
| |
| <<Done>> |
| return Result; |
| end Name_Find; |
| |
| function Name_Find (S : String) return Valid_Name_Id is |
| Buf : Bounded_String (Max_Length => S'Length); |
| begin |
| Append (Buf, S); |
| return Name_Find (Buf); |
| end Name_Find; |
| |
| ----------------- |
| -- Name_Equals -- |
| ----------------- |
| |
| function Name_Equals |
| (N1 : Valid_Name_Id; |
| N2 : Valid_Name_Id) return Boolean |
| is |
| begin |
| return N1 = N2 or else Get_Name_String (N1) = Get_Name_String (N2); |
| end Name_Equals; |
| |
| ------------- |
| -- Present -- |
| ------------- |
| |
| function Present (Nam : File_Name_Type) return Boolean is |
| begin |
| return Nam /= No_File; |
| end Present; |
| |
| ------------- |
| -- Present -- |
| ------------- |
| |
| function Present (Nam : Name_Id) return Boolean is |
| begin |
| return Nam /= No_Name; |
| end Present; |
| |
| ------------- |
| -- Present -- |
| ------------- |
| |
| function Present (Nam : Unit_Name_Type) return Boolean is |
| begin |
| return Nam /= No_Unit_Name; |
| end Present; |
| |
| ------------------ |
| -- Reinitialize -- |
| ------------------ |
| |
| procedure Reinitialize is |
| begin |
| Name_Chars.Init; |
| Name_Entries.Init; |
| |
| -- Initialize entries for one character names |
| |
| for C in Character loop |
| Name_Entries.Append |
| ((Name_Chars_Index => Name_Chars.Last, |
| Name_Len => 1, |
| Byte_Info => 0, |
| Int_Info => 0, |
| Hash_Link => No_Name, |
| Name_Has_No_Encodings => True, |
| Boolean1_Info => False, |
| Boolean2_Info => False, |
| Boolean3_Info => False, |
| Spare => False)); |
| |
| Name_Chars.Append (C); |
| Name_Chars.Append (ASCII.NUL); |
| end loop; |
| |
| -- Clear hash table |
| |
| for J in Hash_Index_Type loop |
| Hash_Table (J) := No_Name; |
| end loop; |
| end Reinitialize; |
| |
| ---------------------- |
| -- Reset_Name_Table -- |
| ---------------------- |
| |
| procedure Reset_Name_Table is |
| begin |
| for J in First_Name_Id .. Name_Entries.Last loop |
| Name_Entries.Table (J).Int_Info := 0; |
| Name_Entries.Table (J).Byte_Info := 0; |
| end loop; |
| end Reset_Name_Table; |
| |
| -------------------------------- |
| -- Set_Character_Literal_Name -- |
| -------------------------------- |
| |
| procedure Set_Character_Literal_Name |
| (Buf : in out Bounded_String; |
| C : Char_Code) |
| is |
| begin |
| Buf.Length := 0; |
| Append (Buf, 'Q'); |
| Append_Encoded (Buf, C); |
| end Set_Character_Literal_Name; |
| |
| procedure Set_Character_Literal_Name (C : Char_Code) is |
| begin |
| Set_Character_Literal_Name (Global_Name_Buffer, C); |
| end Set_Character_Literal_Name; |
| |
| ----------------------------- |
| -- Set_Name_Table_Boolean1 -- |
| ----------------------------- |
| |
| procedure Set_Name_Table_Boolean1 (Id : Valid_Name_Id; Val : Boolean) is |
| begin |
| pragma Assert (Is_Valid_Name (Id)); |
| Name_Entries.Table (Id).Boolean1_Info := Val; |
| end Set_Name_Table_Boolean1; |
| |
| ----------------------------- |
| -- Set_Name_Table_Boolean2 -- |
| ----------------------------- |
| |
| procedure Set_Name_Table_Boolean2 (Id : Valid_Name_Id; Val : Boolean) is |
| begin |
| pragma Assert (Is_Valid_Name (Id)); |
| Name_Entries.Table (Id).Boolean2_Info := Val; |
| end Set_Name_Table_Boolean2; |
| |
| ----------------------------- |
| -- Set_Name_Table_Boolean3 -- |
| ----------------------------- |
| |
| procedure Set_Name_Table_Boolean3 (Id : Valid_Name_Id; Val : Boolean) is |
| begin |
| pragma Assert (Is_Valid_Name (Id)); |
| Name_Entries.Table (Id).Boolean3_Info := Val; |
| end Set_Name_Table_Boolean3; |
| |
| ------------------------- |
| -- Set_Name_Table_Byte -- |
| ------------------------- |
| |
| procedure Set_Name_Table_Byte (Id : Valid_Name_Id; Val : Byte) is |
| begin |
| pragma Assert (Is_Valid_Name (Id)); |
| Name_Entries.Table (Id).Byte_Info := Val; |
| end Set_Name_Table_Byte; |
| |
| ------------------------- |
| -- Set_Name_Table_Int -- |
| ------------------------- |
| |
| procedure Set_Name_Table_Int (Id : Valid_Name_Id; Val : Int) is |
| begin |
| pragma Assert (Is_Valid_Name (Id)); |
| Name_Entries.Table (Id).Int_Info := Val; |
| end Set_Name_Table_Int; |
| |
| ----------------------------- |
| -- Store_Encoded_Character -- |
| ----------------------------- |
| |
| procedure Store_Encoded_Character (C : Char_Code) is |
| begin |
| Append_Encoded (Global_Name_Buffer, C); |
| end Store_Encoded_Character; |
| |
| -------------------------------------- |
| -- Strip_Qualification_And_Suffixes -- |
| -------------------------------------- |
| |
| procedure Strip_Qualification_And_Suffixes (Buf : in out Bounded_String) is |
| J : Integer; |
| |
| begin |
| -- Strip package body qualification string off end |
| |
| for J in reverse 2 .. Buf.Length loop |
| if Buf.Chars (J) = 'X' then |
| Buf.Length := J - 1; |
| exit; |
| end if; |
| |
| exit when Buf.Chars (J) not in 'b' | 'n' | 'p'; |
| end loop; |
| |
| -- Find rightmost __ or $ separator if one exists. First we position |
| -- to start the search. If we have a character constant, position |
| -- just before it, otherwise position to last character but one |
| |
| if Buf.Chars (Buf.Length) = ''' then |
| J := Buf.Length - 2; |
| while J > 0 and then Buf.Chars (J) /= ''' loop |
| J := J - 1; |
| end loop; |
| |
| else |
| J := Buf.Length - 1; |
| end if; |
| |
| -- Loop to search for rightmost __ or $ (homonym) separator |
| |
| while J > 1 loop |
| |
| -- If $ separator, homonym separator, so strip it and keep looking |
| |
| if Buf.Chars (J) = '$' then |
| Buf.Length := J - 1; |
| J := Buf.Length - 1; |
| |
| -- Else check for __ found |
| |
| elsif Buf.Chars (J) = '_' and then Buf.Chars (J + 1) = '_' then |
| |
| -- Found __ so see if digit follows, and if so, this is a |
| -- homonym separator, so strip it and keep looking. |
| |
| if Buf.Chars (J + 2) in '0' .. '9' then |
| Buf.Length := J - 1; |
| J := Buf.Length - 1; |
| |
| -- If not a homonym separator, then we simply strip the |
| -- separator and everything that precedes it, and we are done |
| |
| else |
| Buf.Chars (1 .. Buf.Length - J - 1) := |
| Buf.Chars (J + 2 .. Buf.Length); |
| Buf.Length := Buf.Length - J - 1; |
| exit; |
| end if; |
| |
| else |
| J := J - 1; |
| end if; |
| end loop; |
| end Strip_Qualification_And_Suffixes; |
| |
| --------------- |
| -- To_String -- |
| --------------- |
| |
| function To_String (Buf : Bounded_String) return String is |
| begin |
| return Buf.Chars (1 .. Buf.Length); |
| end To_String; |
| |
| ------------ |
| -- Unlock -- |
| ------------ |
| |
| procedure Unlock is |
| begin |
| Name_Chars.Locked := False; |
| Name_Chars.Set_Last (Name_Chars.Last - Name_Chars_Reserve); |
| Name_Chars.Release; |
| Name_Entries.Locked := False; |
| Name_Entries.Set_Last (Name_Entries.Last - Name_Entries_Reserve); |
| Name_Entries.Release; |
| end Unlock; |
| |
| -------- |
| -- wn -- |
| -------- |
| |
| procedure wn (Id : Name_Id) is |
| begin |
| Write_Name_For_Debug (Id); |
| Write_Eol; |
| end wn; |
| |
| ---------------- |
| -- Write_Name -- |
| ---------------- |
| |
| procedure Write_Name (Id : Valid_Name_Id) is |
| Buf : Bounded_String (Max_Length => Natural (Length_Of_Name (Id))); |
| begin |
| Append (Buf, Id); |
| Write_Str (Buf.Chars (1 .. Buf.Length)); |
| end Write_Name; |
| |
| ------------------------ |
| -- Write_Name_Decoded -- |
| ------------------------ |
| |
| procedure Write_Name_Decoded (Id : Valid_Name_Id) is |
| Buf : Bounded_String; |
| begin |
| Append_Decoded (Buf, Id); |
| Write_Str (Buf.Chars (1 .. Buf.Length)); |
| end Write_Name_Decoded; |
| |
| -------------------------- |
| -- Write_Name_For_Debug -- |
| -------------------------- |
| |
| procedure Write_Name_For_Debug (Id : Name_Id; Quote : String := "") is |
| begin |
| if Is_Valid_Name (Id) then |
| Write_Str (Quote); |
| |
| declare |
| Buf : Bounded_String (Max_Length => Natural (Length_Of_Name (Id))); |
| begin |
| Append (Buf, Id); |
| Write_Str (Buf.Chars (1 .. Buf.Length)); |
| end; |
| |
| Write_Str (Quote); |
| |
| elsif Id = No_Name then |
| Write_Str ("<No_Name>"); |
| |
| elsif Id = Error_Name then |
| Write_Str ("<Error_Name>"); |
| |
| else |
| Write_Str ("<invalid name "); |
| Write_Int (Int (Id)); |
| Write_Str (">"); |
| end if; |
| end Write_Name_For_Debug; |
| |
| -- Package initialization, initialize tables |
| |
| begin |
| Reinitialize; |
| end Namet; |