1 ------------------------------------------------------------------------------
3 -- GNAT COMPILER COMPONENTS --
11 -- Copyright (C) 1992-2001 Free Software Foundation, Inc. --
13 -- GNAT is free software; you can redistribute it and/or modify it under --
14 -- terms of the GNU General Public License as published by the Free Soft- --
15 -- ware Foundation; either version 2, or (at your option) any later ver- --
16 -- sion. GNAT is distributed in the hope that it will be useful, but WITH- --
17 -- OUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY --
18 -- or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License --
19 -- for more details. You should have received a copy of the GNU General --
20 -- Public License distributed with GNAT; see file COPYING. If not, write --
21 -- to the Free Software Foundation, 59 Temple Place - Suite 330, Boston, --
22 -- MA 02111-1307, USA. --
24 -- GNAT was originally developed by the GNAT team at New York University. --
25 -- It is now maintained by Ada Core Technologies Inc (http://www.gnat.com). --
27 ------------------------------------------------------------------------------
29 with Butil; use Butil;
30 with Debug; use Debug;
31 with Fname; use Fname;
32 with Namet; use Namet;
33 with Osint; use Osint;
34 with Output; use Output;
39 -- Make control characters visible
45 procedure Initialize_ALI is
47 -- When (re)initializing ALI data structures the ALI user expects to
48 -- get a fresh set of data structures. Thus we first need to erase the
49 -- marks put in the name table by the previous set of ALI routine calls.
50 -- This loop is empty and harmless the first time in.
52 for J in ALIs.First .. ALIs.Last loop
53 Set_Name_Table_Info (ALIs.Table (J).Afile, 0);
66 -- Add dummy zero'th item in Linker_Options for the sort function
68 Linker_Options.Increment_Last;
70 -- Initialize global variables recording cumulative options in all
71 -- ALI files that are read for a given processing run in gnatbind.
73 Dynamic_Elaboration_Checks_Specified := False;
74 Float_Format_Specified := ' ';
75 Locking_Policy_Specified := ' ';
76 No_Normalize_Scalars_Specified := False;
77 No_Object_Specified := False;
78 Normalize_Scalars_Specified := False;
79 No_Run_Time_Specified := False;
80 Queuing_Policy_Specified := ' ';
81 Static_Elaboration_Model_Used := False;
82 Task_Dispatching_Policy_Specified := ' ';
83 Unreserve_All_Interrupts_Specified := False;
84 Zero_Cost_Exceptions_Specified := False;
97 Read_Xref : Boolean := False)
100 P : Text_Ptr := T'First;
101 Line : Logical_Line_Number := 1;
107 function At_Eol return Boolean;
108 -- Test if at end of line
110 function At_End_Of_Field return Boolean;
111 -- Test if at end of line, or if at blank or horizontal tab
113 procedure Check_At_End_Of_Field;
114 -- Check if we are at end of field, fatal error if not
116 procedure Checkc (C : Character);
117 -- Check next character is C. If so bump past it, if not fatal error
119 Bad_ALI_Format : exception;
121 procedure Fatal_Error;
122 -- Generate fatal error message for badly formatted ALI file if
123 -- Err is false, or raise Bad_ALI_Format if Err is True.
125 function Getc return Character;
126 -- Get next character, bumping P past the character obtained
128 function Get_Name (Lower : Boolean := False) return Name_Id;
129 -- Skip blanks, then scan out a name (name is left in Name_Buffer with
130 -- length in Name_Len, as well as being returned in Name_Id form). The
131 -- name is adjusted appropriately if it refers to a file that is to be
132 -- substituted by another name as a result of a configuration pragma.
133 -- If Lower is set to true then the Name_Buffer will be converted to
134 -- all lower case. This only happends for systems where file names are
135 -- not case sensitive, and ensures that gnatbind works correctly on
136 -- such systems, regardless of the case of the file name. Note that
137 -- a name can be terminated by a right typeref bracket.
139 function Get_Nat return Nat;
140 -- Skip blanks, then scan out an unsigned integer value in Nat range
142 function Get_Stamp return Time_Stamp_Type;
143 -- Skip blanks, then scan out a time stamp
145 function Nextc return Character;
146 -- Return current character without modifying pointer P
149 -- Skip past end of line (fatal error if not at end of line)
151 procedure Skip_Space;
152 -- Skip past white space (blanks or horizontal tab)
154 ---------------------
155 -- At_End_Of_Field --
156 ---------------------
158 function At_End_Of_Field return Boolean is
167 function At_Eol return Boolean is
169 return Nextc = EOF or else Nextc = CR or else Nextc = LF;
172 ---------------------------
173 -- Check_At_End_Of_Field --
174 ---------------------------
176 procedure Check_At_End_Of_Field is
178 if not At_End_Of_Field then
181 end Check_At_End_Of_Field;
187 procedure Checkc (C : Character) is
200 procedure Fatal_Error is
205 procedure Wchar (C : Character);
206 -- Write a single character, replacing horizontal tab by spaces
208 procedure Wchar (C : Character) is
213 exit when Col mod 8 = 0;
222 -- Start of processing for Fatal_Error
226 raise Bad_ALI_Format;
230 Write_Str ("fatal error: file ");
232 Write_Str (" is incorrectly formatted");
235 ("make sure you are using consistent versions of gcc/gnatbind");
238 -- Find start of line
243 and then T (Ptr1 - 1) /= CR
244 and then T (Ptr1 - 1) /= LF
249 Write_Int (Int (Line));
264 and then T (Ptr2) /= CR
265 and then T (Ptr2) /= LF
277 if T (Ptr1) = HT then
289 Exit_Program (E_Fatal);
296 function Get_Name (Lower : Boolean := False) return Name_Id is
306 Name_Len := Name_Len + 1;
307 Name_Buffer (Name_Len) := Getc;
308 exit when At_End_Of_Field;
309 exit when Nextc = ')' or else Nextc = '}' or else Nextc = '>';
312 -- Convert file name to all lower case if file names are not case
313 -- sensitive. This ensures that we handle names in the canonical
314 -- lower case format, regardless of the actual case.
316 if Lower and not File_Names_Case_Sensitive then
317 Canonical_Case_File_Name (Name_Buffer (1 .. Name_Len));
327 function Get_Nat return Nat is
336 V := V * 10 + (Character'Pos (Getc) - Character'Pos ('0'));
337 exit when At_End_Of_Field;
338 exit when Nextc < '0' or Nextc > '9';
348 function Get_Stamp return Time_Stamp_Type is
359 -- Following reads old style time stamp missing first two digits
361 if Nextc in '7' .. '9' then
366 -- Normal case of full year in time stamp
372 for J in Start .. T'Last loop
383 function Getc return Character is
397 function Nextc return Character is
406 procedure Skip_Eol is
409 if not At_Eol then Fatal_Error; end if;
411 -- Loop to skip past blank lines (first time through skips this EOL)
413 while Nextc < ' ' and then Nextc /= EOF loop
426 procedure Skip_Space is
428 while Nextc = ' ' or else Nextc = HT loop
433 --------------------------------------
434 -- Start of processing for Scan_ALI --
435 --------------------------------------
440 Set_Name_Table_Info (F, Int (Id));
444 Compile_Errors => False,
445 First_Sdep => No_Sdep_Id,
446 First_Unit => No_Unit_Id,
448 Last_Sdep => No_Sdep_Id,
449 Last_Unit => No_Unit_Id,
450 Locking_Policy => ' ',
452 Main_Program => None,
454 No_Run_Time => False,
455 Normalize_Scalars => False,
456 Ofile_Full_Name => Full_Object_File_Name,
457 Queuing_Policy => ' ',
458 Restrictions => (others => ' '),
460 Task_Dispatching_Policy => ' ',
461 Time_Slice_Value => -1,
463 Unit_Exception_Table => False,
464 Ver => (others => ' '),
466 Zero_Cost_Exceptions => False);
468 -- Acquire library version
475 for J in 1 .. Ver_Len_Max loop
478 ALIs.Table (Id).Ver (J) := C;
479 ALIs.Table (Id).Ver_Len := J;
484 -- Acquire main program line if present
495 ALIs.Table (Id).Main_Program := Func;
497 ALIs.Table (Id).Main_Program := Proc;
507 ALIs.Table (Id).Main_Priority := Get_Nat;
515 ALIs.Table (Id).Time_Slice_Value := Get_Nat;
522 ALIs.Table (Id).WC_Encoding := Getc;
530 -- Acquire argument lines
532 First_Arg := Args.Last + 1;
534 Arg_Loop : while C = 'A' loop
538 while not At_Eol loop
539 Name_Len := Name_Len + 1;
540 Name_Buffer (Name_Len) := Getc;
544 Args.Table (Args.Last) := new String'(Name_Buffer (1 .. Name_Len));
550 -- Acquire P line, first set defaults
558 while not At_Eol loop
565 ALIs.Table (Id).Compile_Errors := True;
568 Float_Format_Specified := Getc;
569 ALIs.Table (Id).Float_Format := Float_Format_Specified;
572 Locking_Policy_Specified := Getc;
573 ALIs.Table (Id).Locking_Policy := Locking_Policy_Specified;
579 ALIs.Table (Id).No_Object := True;
580 No_Object_Specified := True;
583 No_Run_Time_Specified := True;
584 ALIs.Table (Id).No_Run_Time := True;
587 ALIs.Table (Id).Normalize_Scalars := True;
588 Normalize_Scalars_Specified := True;
596 Queuing_Policy_Specified := Getc;
597 ALIs.Table (Id).Queuing_Policy := Queuing_Policy_Specified;
600 Task_Dispatching_Policy_Specified := Getc;
601 ALIs.Table (Id).Task_Dispatching_Policy :=
602 Task_Dispatching_Policy_Specified;
606 Unreserve_All_Interrupts_Specified := True;
611 ALIs.Table (Id).Unit_Exception_Table := True;
616 ALIs.Table (Id).Zero_Cost_Exceptions := True;
617 Zero_Cost_Exceptions_Specified := True;
625 No_Normalize_Scalars_Specified := True;
630 -- Acquire restrictions line
639 for J in Partition_Restrictions loop
642 if C = 'v' or else C = 'r' or else C = 'n' then
643 ALIs.Table (Id).Restrictions (J) := C;
657 -- Loop to acquire unit entries
659 Unit_Loop : while C = 'U' loop
662 Units.Increment_Last;
664 if ALIs.Table (Id).First_Unit = No_Unit_Id then
665 ALIs.Table (Id).First_Unit := Units.Last;
668 Units.Table (Units.Last).Uname := Get_Name;
669 Units.Table (Units.Last).Predefined := Is_Predefined_Unit;
670 Units.Table (Units.Last).Internal := Is_Internal_Unit;
671 Units.Table (Units.Last).My_ALI := Id;
672 Units.Table (Units.Last).Sfile := Get_Name (Lower => True);
673 Units.Table (Units.Last).Pure := False;
674 Units.Table (Units.Last).Preelab := False;
675 Units.Table (Units.Last).No_Elab := False;
676 Units.Table (Units.Last).Shared_Passive := False;
677 Units.Table (Units.Last).RCI := False;
678 Units.Table (Units.Last).Remote_Types := False;
679 Units.Table (Units.Last).Has_RACW := False;
680 Units.Table (Units.Last).Init_Scalars := False;
681 Units.Table (Units.Last).Is_Generic := False;
682 Units.Table (Units.Last).Icasing := Mixed_Case;
683 Units.Table (Units.Last).Kcasing := All_Lower_Case;
684 Units.Table (Units.Last).Dynamic_Elab := False;
685 Units.Table (Units.Last).Elaborate_Body := False;
686 Units.Table (Units.Last).Set_Elab_Entity := False;
687 Units.Table (Units.Last).Version := "00000000";
688 Units.Table (Units.Last).First_With := Withs.Last + 1;
689 Units.Table (Units.Last).First_Arg := First_Arg;
690 Units.Table (Units.Last).Elab_Position := 0;
693 Write_Str (" ----> reading unit ");
694 Write_Unit_Name (Units.Table (Units.Last).Uname);
695 Write_Str (" from file ");
696 Write_Name (Units.Table (Units.Last).Sfile);
700 -- Check for duplicated unit in different files
703 Info : constant Int := Get_Name_Table_Info
704 (Units.Table (Units.Last).Uname);
707 and then Units.Table (Units.Last).Sfile /=
708 Units.Table (Unit_Id (Info)).Sfile
710 -- If Err is set then treat duplicate unit name as an instance
711 -- of a bad ALI format. This is the case of being called from
712 -- gnatmake, and the point is that if anything is wrong with
713 -- the ALI file, then gnatmake should just recompile.
716 raise Bad_ALI_Format;
718 -- If Err is not set, then this is a fatal error
722 Write_Str ("error: duplicate unit name: ");
725 Write_Str ("error: unit """);
726 Write_Unit_Name (Units.Table (Units.Last).Uname);
727 Write_Str (""" found in file """);
728 Write_Name_Decoded (Units.Table (Units.Last).Sfile);
732 Write_Str ("error: unit """);
733 Write_Unit_Name (Units.Table (Unit_Id (Info)).Uname);
734 Write_Str (""" found in file """);
735 Write_Name_Decoded (Units.Table (Unit_Id (Info)).Sfile);
739 Exit_Program (E_Fatal);
745 (Units.Table (Units.Last).Uname, Int (Units.Last));
747 -- Scan out possible version and other parameters
756 if C in '0' .. '9' or else C in 'a' .. 'f' then
757 Units.Table (Units.Last).Version (1) := C;
761 Units.Table (Units.Last).Version (J) := C;
764 -- DE parameter (Dynamic elaboration checks
768 Check_At_End_Of_Field;
769 Units.Table (Units.Last).Dynamic_Elab := True;
770 Dynamic_Elaboration_Checks_Specified := True;
778 Units.Table (Units.Last).Elaborate_Body := True;
781 Units.Table (Units.Last).Set_Elab_Entity := True;
787 Check_At_End_Of_Field;
789 -- GE parameter (generic)
793 Check_At_End_Of_Field;
794 Units.Table (Units.Last).Is_Generic := True;
796 -- IL/IS/IU parameters
802 Units.Table (Units.Last).Icasing := All_Lower_Case;
805 Units.Table (Units.Last).Init_Scalars := True;
806 Initialize_Scalars_Used := True;
809 Units.Table (Units.Last).Icasing := All_Upper_Case;
815 Check_At_End_Of_Field;
823 Units.Table (Units.Last).Kcasing := Mixed_Case;
826 Units.Table (Units.Last).Kcasing := All_Upper_Case;
832 Check_At_End_Of_Field;
838 Units.Table (Units.Last).No_Elab := True;
839 Check_At_End_Of_Field;
841 -- PR/PU/PK parameters
846 -- PR parameter (preelaborate)
849 Units.Table (Units.Last).Preelab := True;
851 -- PU parameter (pure)
854 Units.Table (Units.Last).Pure := True;
856 -- PK indicates unit is package
859 Units.Table (Units.Last).Unit_Kind := 'p';
865 Check_At_End_Of_Field;
872 -- RC parameter (remote call interface)
875 Units.Table (Units.Last).RCI := True;
877 -- RT parameter (remote types)
880 Units.Table (Units.Last).Remote_Types := True;
882 -- RA parameter (remote access to class wide type)
885 Units.Table (Units.Last).Has_RACW := True;
891 Check_At_End_Of_Field;
896 -- SP parameter (shared passive)
899 Units.Table (Units.Last).Shared_Passive := True;
901 -- SU parameter indicates unit is subprogram
904 Units.Table (Units.Last).Unit_Kind := 's';
910 Check_At_End_Of_Field;
920 -- Check if static elaboration model used
922 if not Units.Table (Units.Last).Dynamic_Elab
923 and then not Units.Table (Units.Last).Internal
925 Static_Elaboration_Model_Used := True;
928 -- Scan out With lines for this unit
932 With_Loop : while C = 'W' loop
935 Withs.Increment_Last;
936 Withs.Table (Withs.Last).Uname := Get_Name;
937 Withs.Table (Withs.Last).Elaborate := False;
938 Withs.Table (Withs.Last).Elaborate_All := False;
939 Withs.Table (Withs.Last).Elab_All_Desirable := False;
941 -- Generic case with no object file available
944 Withs.Table (Withs.Last).Sfile := No_File;
945 Withs.Table (Withs.Last).Afile := No_File;
950 Withs.Table (Withs.Last).Sfile := Get_Name (Lower => True);
951 Withs.Table (Withs.Last).Afile := Get_Name;
953 -- Scan out possible E, EA, and NE parameters
955 while not At_Eol loop
961 if At_End_Of_Field then
962 Withs.Table (Withs.Last).Elaborate := True;
964 elsif Nextc = 'A' then
966 Check_At_End_Of_Field;
967 Withs.Table (Withs.Last).Elaborate_All := True;
971 Check_At_End_Of_Field;
973 -- Store ED indication unless ignore required
975 if not Ignore_ED then
976 Withs.Table (Withs.Last).Elab_All_Desirable := True;
988 Units.Table (Units.Last).Last_With := Withs.Last;
989 Units.Table (Units.Last).Last_Arg := Args.Last;
993 -- End loop through units for one ALI file
995 ALIs.Table (Id).Last_Unit := Units.Last;
996 ALIs.Table (Id).Sfile := Units.Table (ALIs.Table (Id).First_Unit).Sfile;
998 -- Set types of the units (there can be at most 2 of them)
1000 if ALIs.Table (Id).First_Unit /= ALIs.Table (Id).Last_Unit then
1001 Units.Table (ALIs.Table (Id).First_Unit).Utype := Is_Body;
1002 Units.Table (ALIs.Table (Id).Last_Unit).Utype := Is_Spec;
1005 -- Deal with body only and spec only cases, note that the reason we
1006 -- do our own checking of the name (rather than using Is_Body_Name)
1007 -- is that Uname drags in far too much compiler junk!
1009 Get_Name_String (Units.Table (Units.Last).Uname);
1011 if Name_Buffer (Name_Len) = 'b' then
1012 Units.Table (Units.Last).Utype := Is_Body_Only;
1014 Units.Table (Units.Last).Utype := Is_Spec_Only;
1018 -- If there are linker options lines present, scan them
1029 if C < Character'Val (16#20#)
1030 or else C > Character'Val (16#7E#)
1035 C := Character'Val (0);
1042 for J in 1 .. 2 loop
1045 if C in '0' .. '9' then
1047 Character'Pos (C) - Character'Pos ('0');
1049 elsif C in 'A' .. 'F' then
1051 Character'Pos (C) - Character'Pos ('A') + 10;
1060 Add_Char_To_Name_Buffer (Character'Val (V));
1065 exit when Nextc /= '"';
1069 Add_Char_To_Name_Buffer (C);
1073 Add_Char_To_Name_Buffer (nul);
1078 Linker_Options.Increment_Last;
1080 Linker_Options.Table (Linker_Options.Last).Name
1083 Linker_Options.Table (Linker_Options.Last).Unit
1084 := ALIs.Table (Id).First_Unit;
1086 Linker_Options.Table (Linker_Options.Last).Internal_File
1087 := Is_Internal_File_Name (F);
1089 Linker_Options.Table (Linker_Options.Last).Original_Pos
1090 := Linker_Options.Last;
1094 -- Scan out external version references and put in hash table
1109 exit when At_End_Of_Field;
1110 Add_Char_To_Name_Buffer (C);
1113 Version_Ref.Set (new String'(Name_Buffer (1 .. Name_Len)), True);
1118 -- Scan out source dependency lines for this ALI file
1120 ALIs.Table (Id).First_Sdep := Sdep.Last + 1;
1125 Sdep.Increment_Last;
1126 Sdep.Table (Sdep.Last).Sfile := Get_Name (Lower => True);
1127 Sdep.Table (Sdep.Last).Stamp := Get_Stamp;
1129 -- Check for version number present, and if so store it
1142 exit when At_Eol or else Ctr = 8;
1144 if Nextc in '0' .. '9' then
1146 Character'Pos (Nextc) - Character'Pos ('0');
1148 elsif Nextc in 'a' .. 'f' then
1150 Character'Pos (Nextc) - Character'Pos ('a') + 10;
1160 if Ctr = 8 and then At_End_Of_Field then
1161 Sdep.Table (Sdep.Last).Checksum := Chk;
1167 -- Acquire subunit and reference file name entries
1169 Sdep.Table (Sdep.Last).Subunit_Name := No_Name;
1170 Sdep.Table (Sdep.Last).Rfile := Sdep.Table (Sdep.Last).Sfile;
1171 Sdep.Table (Sdep.Last).Start_Line := 1;
1176 -- Here for subunit name
1178 if Nextc not in '0' .. '9' then
1181 while not At_End_Of_Field loop
1182 Name_Len := Name_Len + 1;
1183 Name_Buffer (Name_Len) := Getc;
1186 Sdep.Table (Sdep.Last).Subunit_Name := Name_Enter;
1190 -- Here for reference file name entry
1192 if Nextc in '0' .. '9' then
1193 Sdep.Table (Sdep.Last).Start_Line := Get_Nat;
1198 while not At_End_Of_Field loop
1199 Name_Len := Name_Len + 1;
1200 Name_Buffer (Name_Len) := Getc;
1203 Sdep.Table (Sdep.Last).Rfile := Name_Enter;
1211 ALIs.Table (Id).Last_Sdep := Sdep.Last;
1213 -- Loop through Xref sections (skip loop if not reading xref stuff)
1215 while Read_Xref and then C = 'X' loop
1217 -- Make new entry in section table
1219 Xref_Section.Increment_Last;
1222 XS : Xref_Section_Record renames
1223 Xref_Section.Table (Xref_Section.Last);
1225 Current_File_Num : Sdep_Id;
1226 -- Keeps track of the current file number (changed by nn|)
1229 XS.File_Num := Sdep_Id (Get_Nat + Nat (First_Sdep_Entry) - 1);
1230 XS.File_Name := Get_Name;
1231 XS.First_Entity := Xref_Entity.Last + 1;
1233 Current_File_Num := XS.File_Num;
1238 -- Loop through Xref entities
1240 while C /= 'X' and then C /= EOF loop
1241 Xref_Entity.Increment_Last;
1244 XE : Xref_Entity_Record renames
1245 Xref_Entity.Table (Xref_Entity.Last);
1253 XE.Lib := (Getc = '*');
1254 XE.Entity := Get_Name;
1259 when '<' => XE.Tref := Tref_Derived;
1260 when '(' => XE.Tref := Tref_Access;
1261 when '{' => XE.Tref := Tref_Type;
1262 when others => XE.Tref := Tref_None;
1265 -- Case of typeref field present
1267 if XE.Tref /= Tref_None then
1268 P := P + 1; -- skip opening bracket
1270 if Nextc in 'a' .. 'z' then
1271 XE.Tref_File_Num := No_Sdep_Id;
1273 XE.Tref_Type := ' ';
1275 XE.Tref_Standard_Entity := Get_Name;
1282 Sdep_Id (N + Nat (First_Sdep_Entry) - 1);
1283 Current_File_Num := XE.Tref_File_Num;
1288 XE.Tref_File_Num := Current_File_Num;
1292 XE.Tref_Type := Getc;
1293 XE.Tref_Col := Get_Nat;
1294 XE.Tref_Standard_Entity := No_Name;
1297 P := P + 1; -- skip closing bracket
1299 -- No typeref entry present
1302 XE.Tref_File_Num := No_Sdep_Id;
1304 XE.Tref_Type := ' ';
1306 XE.Tref_Standard_Entity := No_Name;
1309 XE.First_Xref := Xref.Last + 1;
1311 -- Loop through cross-references for this entity
1313 Current_File_Num := XS.File_Num;
1320 exit when Nextc /= '.';
1324 Xref.Increment_Last;
1327 XR : Xref_Record renames Xref.Table (Xref.Last);
1334 Sdep_Id (N + Nat (First_Sdep_Entry) - 1);
1335 Current_File_Num := XR.File_Num;
1340 XR.File_Num := Current_File_Num;
1349 -- Record last cross-reference
1351 XE.Last_Xref := Xref.Last;
1356 -- Record last entity
1358 XS.Last_Entity := Xref_Entity.Last;
1364 -- Here after dealing with xref sections
1366 if C /= EOF and then C /= 'X' then
1373 when Bad_ALI_Format =>
1382 function SEq (F1, F2 : String_Ptr) return Boolean is
1384 return F1.all = F2.all;
1391 function SHash (S : String_Ptr) return Vindex is
1396 for J in S.all'Range loop
1397 H := H * 2 + Character'Pos (S (J));
1400 return Vindex (Vindex'First + Vindex (H mod Vindex'Range_Length));