OSDN Git Service

2007-09-26 Thomas Quinot <quinot@adacore.com>
[pf3gnuchains/gcc-fork.git] / gcc / ada / ali.adb
1 ------------------------------------------------------------------------------
2 --                                                                          --
3 --                         GNAT COMPILER COMPONENTS                         --
4 --                                                                          --
5 --                                  A L I                                   --
6 --                                                                          --
7 --                                 B o d y                                  --
8 --                                                                          --
9 --          Copyright (C) 1992-2007, Free Software Foundation, Inc.         --
10 --                                                                          --
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.          --
20 --                                                                          --
21 -- GNAT was originally developed  by the GNAT team at  New York University. --
22 -- Extensive contributions were provided by Ada Core Technologies Inc.      --
23 --                                                                          --
24 ------------------------------------------------------------------------------
25
26 with Butil;  use Butil;
27 with Debug;  use Debug;
28 with Fname;  use Fname;
29 with Opt;    use Opt;
30 with Osint;  use Osint;
31 with Output; use Output;
32
33 package body ALI is
34
35    use ASCII;
36    --  Make control characters visible
37
38    --  The following variable records which characters currently are
39    --  used as line type markers in the ALI file. This is used in
40    --  Scan_ALI to detect (or skip) invalid lines.
41
42    Known_ALI_Lines : constant array (Character range 'A' .. 'Z') of Boolean :=
43      ('V'    => True,   -- version
44       'M'    => True,   -- main program
45       'A'    => True,   -- argument
46       'P'    => True,   -- program
47       'R'    => True,   -- restriction
48       'I'    => True,   -- interrupt
49       'U'    => True,   -- unit
50       'W'    => True,   -- with
51       'L'    => True,   -- linker option
52       'E'    => True,   -- external
53       'D'    => True,   -- dependency
54       'X'    => True,   -- xref
55       'S'    => True,   -- specific dispatching
56       others => False);
57
58    --------------------
59    -- Initialize_ALI --
60    --------------------
61
62    procedure Initialize_ALI is
63    begin
64       --  When (re)initializing ALI data structures the ALI user expects to
65       --  get a fresh set of data structures. Thus we first need to erase the
66       --  marks put in the name table by the previous set of ALI routine calls.
67       --  These two loops are empty and harmless the first time in.
68
69       for J in ALIs.First .. ALIs.Last loop
70          Set_Name_Table_Info (ALIs.Table (J).Afile, 0);
71       end loop;
72
73       for J in Units.First .. Units.Last loop
74          Set_Name_Table_Info (Units.Table (J).Uname, 0);
75       end loop;
76
77       --  Free argument table strings
78
79       for J in Args.First .. Args.Last loop
80          Free (Args.Table (J));
81       end loop;
82
83       --  Initialize all tables
84
85       ALIs.Init;
86       No_Deps.Init;
87       Units.Init;
88       Withs.Init;
89       Sdep.Init;
90       Linker_Options.Init;
91       Xref_Section.Init;
92       Xref_Entity.Init;
93       Xref.Init;
94       Version_Ref.Reset;
95
96       --  Add dummy zero'th item in Linker_Options for the sort function
97
98       Linker_Options.Increment_Last;
99
100       --  Initialize global variables recording cumulative options in all
101       --  ALI files that are read for a given processing run in gnatbind.
102
103       Dynamic_Elaboration_Checks_Specified := False;
104       Float_Format_Specified               := ' ';
105       Locking_Policy_Specified             := ' ';
106       No_Normalize_Scalars_Specified       := False;
107       No_Object_Specified                  := False;
108       Normalize_Scalars_Specified          := False;
109       Queuing_Policy_Specified             := ' ';
110       Static_Elaboration_Model_Used        := False;
111       Task_Dispatching_Policy_Specified    := ' ';
112       Unreserve_All_Interrupts_Specified   := False;
113       Zero_Cost_Exceptions_Specified       := False;
114    end Initialize_ALI;
115
116    --------------
117    -- Scan_ALI --
118    --------------
119
120    function Scan_ALI
121      (F             : File_Name_Type;
122       T             : Text_Buffer_Ptr;
123       Ignore_ED     : Boolean;
124       Err           : Boolean;
125       Read_Xref     : Boolean := False;
126       Read_Lines    : String  := "";
127       Ignore_Lines  : String  := "X";
128       Ignore_Errors : Boolean := False) return ALI_Id
129    is
130       P         : Text_Ptr := T'First;
131       Line      : Logical_Line_Number := 1;
132       Id        : ALI_Id;
133       C         : Character;
134       NS_Found  : Boolean;
135       First_Arg : Arg_Id;
136
137       Ignore : array (Character range 'A' .. 'Z') of Boolean;
138       --  Ignore (X) is set to True if lines starting with X are to
139       --  be ignored by Scan_ALI and skipped, and False if the lines
140       --  are to be read and processed.
141
142       Bad_ALI_Format : exception;
143       --  Exception raised by Fatal_Error if Err is True
144
145       function At_Eol return Boolean;
146       --  Test if at end of line
147
148       function At_End_Of_Field return Boolean;
149       --  Test if at end of line, or if at blank or horizontal tab
150
151       procedure Check_At_End_Of_Field;
152       --  Check if we are at end of field, fatal error if not
153
154       procedure Checkc (C : Character);
155       --  Check next character is C. If so bump past it, if not fatal error
156
157       procedure Check_Unknown_Line;
158       --  If Ignore_Errors mode, then checks C to make sure that it is not
159       --  an unknown ALI line type characters, and if so, skips lines
160       --  until the first character of the line is one of these characters,
161       --  at which point it does a Getc to put that character in C. The
162       --  call has no effect if C is already an appropriate character.
163       --  If not in Ignore_Errors mode, a fatal error is signalled if the
164       --  line is unknown. Note that if C is an EOL on entry, the line is
165       --  skipped (it is assumed that blank lines are never significant).
166       --  If C is EOF on entry, the call has no effect (it is assumed that
167       --  the caller will properly handle this case).
168
169       procedure Fatal_Error;
170       --  Generate fatal error message for badly formatted ALI file if
171       --  Err is false, or raise Bad_ALI_Format if Err is True.
172
173       procedure Fatal_Error_Ignore;
174       pragma Inline (Fatal_Error_Ignore);
175       --  In Ignore_Errors mode, has no effect, otherwise same as Fatal_Error
176
177       function Getc return Character;
178       --  Get next character, bumping P past the character obtained
179
180       function Get_File_Name (Lower : Boolean := False) return File_Name_Type;
181       --  Skip blanks, then scan out a file name (name is left in Name_Buffer
182       --  with length in Name_Len, as well as returning a File_Name_Type value.
183       --  If lower is false, the case is unchanged, if Lower is True then the
184       --  result is forced to all lower case for systems where file names are
185       --  not case sensitive. This ensures that gnatbind works correctly
186       --  regardless of the case of the file name on all systems. The scan
187       --  is terminated by a end of line, space or horizontal tab. Any other
188       --  special characters are included in the returned name.
189
190       function Get_Name
191         (Ignore_Spaces  : Boolean := False;
192          Ignore_Special : Boolean := False)return Name_Id;
193       --  Skip blanks, then scan out a name (name is left in Name_Buffer with
194       --  length in Name_Len, as well as being returned in Name_Id form).
195       --  If Lower is set to True then the Name_Buffer will be converted to
196       --  all lower case, for systems where file names are not case sensitive.
197       --  This ensures that gnatbind works correctly regardless of the case
198       --  of the file name on all systems. The termination condition depends
199       --  on the settings of Ignore_Spaces and Ignore_Special:
200       --
201       --    If Ignore_Spaces is False (normal case), then scan is terminated
202       --    by the normal end of field condition (EOL, space, horizontal tab)
203       --
204       --    If Ignore_Special is False (normal case), the scan is terminated by
205       --    a typeref bracket or an equal sign except for the special case of
206       --    an operator name starting with a double quite which is terminated
207       --    by another double quote.
208       --
209       --  It is an error to set both Ignore_Spaces and Ignore_Special to True.
210       --  This function handles wide characters properly.
211
212       function Get_Nat return Nat;
213       --  Skip blanks, then scan out an unsigned integer value in Nat range
214       --  raises ALI_Reading_Error if the encoutered type is not natural.
215
216       function Get_Stamp return Time_Stamp_Type;
217       --  Skip blanks, then scan out a time stamp
218
219       function Get_Unit_Name return Unit_Name_Type;
220       --  Skip blanks, then scan out a file name (name is left in Name_Buffer
221       --  with length in Name_Len, as well as returning a Unit_Name_Type value.
222       --  The case is unchanged and terminated by a normal end of field.
223
224       function Nextc return Character;
225       --  Return current character without modifying pointer P
226
227       procedure Get_Typeref
228         (Current_File_Num : Sdep_Id;
229          Ref             : out Tref_Kind;
230          File_Num        : out Sdep_Id;
231          Line            : out Nat;
232          Ref_Type        : out Character;
233          Col             : out Nat;
234          Standard_Entity : out Name_Id);
235       --  Parse the definition of a typeref (<...>, {...} or (...))
236
237       procedure Skip_Eol;
238       --  Skip past spaces, then skip past end of line (fatal error if not
239       --  at end of line). Also skips past any following blank lines.
240
241       procedure Skip_Line;
242       --  Skip rest of current line and any following blank lines
243
244       procedure Skip_Space;
245       --  Skip past white space (blanks or horizontal tab)
246
247       procedure Skipc;
248       --  Skip past next character, does not affect value in C. This call
249       --  is like calling Getc and ignoring the returned result.
250
251       ---------------------
252       -- At_End_Of_Field --
253       ---------------------
254
255       function At_End_Of_Field return Boolean is
256       begin
257          return Nextc <= ' ';
258       end At_End_Of_Field;
259
260       ------------
261       -- At_Eol --
262       ------------
263
264       function At_Eol return Boolean is
265       begin
266          return Nextc = EOF or else Nextc = CR or else Nextc = LF;
267       end At_Eol;
268
269       ---------------------------
270       -- Check_At_End_Of_Field --
271       ---------------------------
272
273       procedure Check_At_End_Of_Field is
274       begin
275          if not At_End_Of_Field then
276             if Ignore_Errors then
277                while Nextc > ' ' loop
278                   P := P + 1;
279                end loop;
280             else
281                Fatal_Error;
282             end if;
283          end if;
284       end Check_At_End_Of_Field;
285
286       ------------------------
287       -- Check_Unknown_Line --
288       ------------------------
289
290       procedure Check_Unknown_Line is
291       begin
292          while C not in 'A' .. 'Z'
293            or else not Known_ALI_Lines (C)
294          loop
295             if C = CR or else C = LF then
296                Skip_Line;
297                C := Nextc;
298
299             elsif C = EOF then
300                return;
301
302             elsif Ignore_Errors then
303                Skip_Line;
304                C := Getc;
305
306             else
307                Fatal_Error;
308             end if;
309          end loop;
310       end Check_Unknown_Line;
311
312       ------------
313       -- Checkc --
314       ------------
315
316       procedure Checkc (C : Character) is
317       begin
318          if Nextc = C then
319             P := P + 1;
320          elsif Ignore_Errors then
321             P := P + 1;
322          else
323             Fatal_Error;
324          end if;
325       end Checkc;
326
327       -----------------
328       -- Fatal_Error --
329       -----------------
330
331       procedure Fatal_Error is
332          Ptr1 : Text_Ptr;
333          Ptr2 : Text_Ptr;
334          Col  : Int;
335
336          procedure Wchar (C : Character);
337          --  Write a single character, replacing horizontal tab by spaces
338
339          procedure Wchar (C : Character) is
340          begin
341             if C = HT then
342                loop
343                   Wchar (' ');
344                   exit when Col mod 8 = 0;
345                end loop;
346
347             else
348                Write_Char (C);
349                Col := Col + 1;
350             end if;
351          end Wchar;
352
353       --  Start of processing for Fatal_Error
354
355       begin
356          if Err then
357             raise Bad_ALI_Format;
358          end if;
359
360          Set_Standard_Error;
361          Write_Str ("fatal error: file ");
362          Write_Name (F);
363          Write_Str (" is incorrectly formatted");
364          Write_Eol;
365
366          Write_Str ("make sure you are using consistent versions " &
367
368          --  Split the following line so that it can easily be transformed for
369          --  e.g. JVM/.NET back-ends where the compiler has a different name.
370
371                     "of gcc/gnatbind");
372
373          Write_Eol;
374
375          --  Find start of line
376
377          Ptr1 := P;
378          while Ptr1 > T'First
379            and then T (Ptr1 - 1) /= CR
380            and then T (Ptr1 - 1) /= LF
381          loop
382             Ptr1 := Ptr1 - 1;
383          end loop;
384
385          Write_Int (Int (Line));
386          Write_Str (". ");
387
388          if Line < 100 then
389             Write_Char (' ');
390          end if;
391
392          if Line < 10 then
393             Write_Char (' ');
394          end if;
395
396          Col := 0;
397          Ptr2 := Ptr1;
398
399          while Ptr2 < T'Last
400            and then T (Ptr2) /= CR
401            and then T (Ptr2) /= LF
402          loop
403             Wchar (T (Ptr2));
404             Ptr2 := Ptr2 + 1;
405          end loop;
406
407          Write_Eol;
408
409          Write_Str ("     ");
410          Col := 0;
411
412          while Ptr1 < P loop
413             if T (Ptr1) = HT then
414                Wchar (HT);
415             else
416                Wchar (' ');
417             end if;
418
419             Ptr1 := Ptr1 + 1;
420          end loop;
421
422          Wchar ('|');
423          Write_Eol;
424
425          Exit_Program (E_Fatal);
426       end Fatal_Error;
427
428       ------------------------
429       -- Fatal_Error_Ignore --
430       ------------------------
431
432       procedure Fatal_Error_Ignore is
433       begin
434          if not Ignore_Errors then
435             Fatal_Error;
436          end if;
437       end Fatal_Error_Ignore;
438
439       -------------------
440       -- Get_File_Name --
441       -------------------
442
443       function Get_File_Name
444         (Lower : Boolean := False) return File_Name_Type
445       is
446          F : Name_Id;
447
448       begin
449          F := Get_Name (Ignore_Special => True);
450
451          --  Convert file name to all lower case if file names are not case
452          --  sensitive. This ensures that we handle names in the canonical
453          --  lower case format, regardless of the actual case.
454
455          if Lower and not File_Names_Case_Sensitive then
456             Canonical_Case_File_Name (Name_Buffer (1 .. Name_Len));
457             return Name_Find;
458          else
459             return File_Name_Type (F);
460          end if;
461       end Get_File_Name;
462
463       --------------
464       -- Get_Name --
465       --------------
466
467       function Get_Name
468         (Ignore_Spaces  : Boolean := False;
469          Ignore_Special : Boolean := False) return Name_Id
470       is
471       begin
472          Name_Len := 0;
473          Skip_Space;
474
475          if At_Eol then
476             if Ignore_Errors then
477                return Error_Name;
478             else
479                Fatal_Error;
480             end if;
481          end if;
482
483          loop
484             Name_Len := Name_Len + 1;
485             Name_Buffer (Name_Len) := Getc;
486
487             exit when At_End_Of_Field and not Ignore_Spaces;
488
489             if not Ignore_Special then
490                if Name_Buffer (1) = '"' then
491                   exit when Name_Len > 1 and then Name_Buffer (Name_Len) = '"';
492
493                else
494                   --  Terminate on parens or angle brackets or equal sign
495
496                   exit when Nextc = '(' or else Nextc = ')'
497                     or else Nextc = '{' or else Nextc = '}'
498                     or else Nextc = '<' or else Nextc = '>'
499                     or else Nextc = '=';
500
501                   --  Terminate if left bracket not part of wide char sequence
502                   --  Note that we only recognize brackets notation so far ???
503
504                   exit when Nextc = '[' and then T (P + 1) /= '"';
505
506                   --  Terminate if right bracket not part of wide char sequence
507
508                   exit when Nextc = ']' and then T (P - 1) /= '"';
509                end if;
510             end if;
511          end loop;
512
513          return Name_Find;
514       end Get_Name;
515
516       -------------------
517       -- Get_Unit_Name --
518       -------------------
519
520       function Get_Unit_Name return Unit_Name_Type is
521       begin
522          return Unit_Name_Type (Get_Name);
523       end Get_Unit_Name;
524
525       -------------
526       -- Get_Nat --
527       -------------
528
529       function Get_Nat return Nat is
530          V : Nat;
531
532       begin
533          Skip_Space;
534
535          --  Check if we are on a number. In the case of bas ALI files, this
536          --  may not be true.
537
538          if not (Nextc in '0' .. '9') then
539             Fatal_Error;
540          end if;
541
542          V := 0;
543          loop
544             V := V * 10 + (Character'Pos (Getc) - Character'Pos ('0'));
545
546             exit when At_End_Of_Field;
547             exit when Nextc < '0' or Nextc > '9';
548          end loop;
549
550          return V;
551       end Get_Nat;
552
553       ---------------
554       -- Get_Stamp --
555       ---------------
556
557       function Get_Stamp return Time_Stamp_Type is
558          T     : Time_Stamp_Type;
559          Start : Integer;
560
561       begin
562          Skip_Space;
563
564          if At_Eol then
565             if Ignore_Errors then
566                return Dummy_Time_Stamp;
567             else
568                Fatal_Error;
569             end if;
570          end if;
571
572          --  Following reads old style time stamp missing first two digits
573
574          if Nextc in '7' .. '9' then
575             T (1) := '1';
576             T (2) := '9';
577             Start := 3;
578
579          --  Normal case of full year in time stamp
580
581          else
582             Start := 1;
583          end if;
584
585          for J in Start .. T'Last loop
586             T (J) := Getc;
587          end loop;
588
589          return T;
590       end Get_Stamp;
591
592       -----------------
593       -- Get_Typeref --
594       -----------------
595
596       procedure Get_Typeref
597         (Current_File_Num : Sdep_Id;
598          Ref              : out Tref_Kind;
599          File_Num         : out Sdep_Id;
600          Line             : out Nat;
601          Ref_Type         : out Character;
602          Col              : out Nat;
603          Standard_Entity  : out Name_Id)
604       is
605          N : Nat;
606       begin
607          case Nextc is
608             when '<'    => Ref := Tref_Derived;
609             when '('    => Ref := Tref_Access;
610             when '{'    => Ref := Tref_Type;
611             when others => Ref := Tref_None;
612          end case;
613
614          --  Case of typeref field present
615
616          if Ref /= Tref_None then
617             P := P + 1; -- skip opening bracket
618
619             if Nextc in 'a' .. 'z' then
620                File_Num        := No_Sdep_Id;
621                Line            := 0;
622                Ref_Type        := ' ';
623                Col             := 0;
624                Standard_Entity := Get_Name (Ignore_Spaces => True);
625             else
626                N := Get_Nat;
627
628                if Nextc = '|' then
629                   File_Num := Sdep_Id (N + Nat (First_Sdep_Entry) - 1);
630                   P := P + 1;
631                   N := Get_Nat;
632                else
633                   File_Num := Current_File_Num;
634                end if;
635
636                Line            := N;
637                Ref_Type        := Getc;
638                Col             := Get_Nat;
639                Standard_Entity := No_Name;
640             end if;
641
642             --  ??? Temporary workaround for nested generics case:
643             --     4i4 Directories{1|4I9[4|6[3|3]]}
644             --  See C918-002
645
646             declare
647                Nested_Brackets : Natural := 0;
648
649             begin
650                loop
651                   case Nextc is
652                      when '['   =>
653                         Nested_Brackets := Nested_Brackets + 1;
654                      when ']' =>
655                         Nested_Brackets := Nested_Brackets - 1;
656                      when others =>
657                         if Nested_Brackets = 0 then
658                            exit;
659                         end if;
660                   end case;
661
662                   Skipc;
663                end loop;
664             end;
665
666             P := P + 1; -- skip closing bracket
667             Skip_Space;
668
669          --  No typeref entry present
670
671          else
672             File_Num        := No_Sdep_Id;
673             Line            := 0;
674             Ref_Type        := ' ';
675             Col             := 0;
676             Standard_Entity := No_Name;
677          end if;
678       end Get_Typeref;
679
680       ----------
681       -- Getc --
682       ----------
683
684       function Getc return Character is
685       begin
686          if P = T'Last then
687             return EOF;
688          else
689             P := P + 1;
690             return T (P - 1);
691          end if;
692       end Getc;
693
694       -----------
695       -- Nextc --
696       -----------
697
698       function Nextc return Character is
699       begin
700          return T (P);
701       end Nextc;
702
703       --------------
704       -- Skip_Eol --
705       --------------
706
707       procedure Skip_Eol is
708       begin
709          Skip_Space;
710
711          if not At_Eol then
712             if Ignore_Errors then
713                while not At_Eol loop
714                   P := P + 1;
715                end loop;
716             else
717                Fatal_Error;
718             end if;
719          end if;
720
721          --  Loop to skip past blank lines (first time through skips this EOL)
722
723          while Nextc < ' ' and then Nextc /= EOF loop
724             if Nextc = LF then
725                Line := Line + 1;
726             end if;
727
728             P := P + 1;
729          end loop;
730       end Skip_Eol;
731
732       ---------------
733       -- Skip_Line --
734       ---------------
735
736       procedure Skip_Line is
737       begin
738          while not At_Eol loop
739             P := P + 1;
740          end loop;
741
742          Skip_Eol;
743       end Skip_Line;
744
745       ----------------
746       -- Skip_Space --
747       ----------------
748
749       procedure Skip_Space is
750       begin
751          while Nextc = ' ' or else Nextc = HT loop
752             P := P + 1;
753          end loop;
754       end Skip_Space;
755
756       -----------
757       -- Skipc --
758       -----------
759
760       procedure Skipc is
761       begin
762          if P /= T'Last then
763             P := P + 1;
764          end if;
765       end Skipc;
766
767    --  Start of processing for Scan_ALI
768
769    begin
770       First_Sdep_Entry := Sdep.Last + 1;
771
772       --  Acquire lines to be ignored
773
774       if Read_Xref then
775          Ignore := ('U' | 'W' | 'D' | 'X' => False, others => True);
776
777       --  Read_Lines parameter given
778
779       elsif Read_Lines /= "" then
780          Ignore := ('U' => False, others => True);
781
782          for J in Read_Lines'Range loop
783             Ignore (Read_Lines (J)) := False;
784          end loop;
785
786       --  Process Ignore_Lines parameter
787
788       else
789          Ignore := (others => False);
790
791          for J in Ignore_Lines'Range loop
792             pragma Assert (Ignore_Lines (J) /= 'U');
793             Ignore (Ignore_Lines (J)) := True;
794          end loop;
795       end if;
796
797       --  Setup ALI Table entry with appropriate defaults
798
799       ALIs.Increment_Last;
800       Id := ALIs.Last;
801       Set_Name_Table_Info (F, Int (Id));
802
803       ALIs.Table (Id) := (
804         Afile                      => F,
805         Compile_Errors             => False,
806         First_Interrupt_State      => Interrupt_States.Last + 1,
807         First_Sdep                 => No_Sdep_Id,
808         First_Specific_Dispatching => Specific_Dispatching.Last + 1,
809         First_Unit                 => No_Unit_Id,
810         Float_Format               => 'I',
811         Last_Interrupt_State       => Interrupt_States.Last,
812         Last_Sdep                  => No_Sdep_Id,
813         Last_Specific_Dispatching  => Specific_Dispatching.Last,
814         Last_Unit                  => No_Unit_Id,
815         Locking_Policy             => ' ',
816         Main_Priority              => -1,
817         Main_Program               => None,
818         No_Object                  => False,
819         Normalize_Scalars          => False,
820         Ofile_Full_Name            => Full_Object_File_Name,
821         Queuing_Policy             => ' ',
822         Restrictions               => No_Restrictions,
823         SAL_Interface              => False,
824         Sfile                      => No_File,
825         Task_Dispatching_Policy    => ' ',
826         Time_Slice_Value           => -1,
827         WC_Encoding                => '8',
828         Unit_Exception_Table       => False,
829         Ver                        => (others => ' '),
830         Ver_Len                    => 0,
831         Zero_Cost_Exceptions       => False);
832
833       --  Now we acquire the input lines from the ALI file. Note that the
834       --  convention in the following code is that as we enter each section,
835       --  C is set to contain the first character of the following line.
836
837       C := Getc;
838       Check_Unknown_Line;
839
840       --  Acquire library version
841
842       if C /= 'V' then
843
844          --  The V line missing really indicates trouble, most likely it
845          --  means we don't have an ALI file at all, so here we give a
846          --  fatal error even if we are in Ignore_Errors mode.
847
848          Fatal_Error;
849
850       elsif Ignore ('V') then
851          Skip_Line;
852
853       else
854          Checkc (' ');
855          Skip_Space;
856          Checkc ('"');
857
858          for J in 1 .. Ver_Len_Max loop
859             C := Getc;
860             exit when C = '"';
861             ALIs.Table (Id).Ver (J) := C;
862             ALIs.Table (Id).Ver_Len := J;
863          end loop;
864
865          Skip_Eol;
866       end if;
867
868       C := Getc;
869       Check_Unknown_Line;
870
871       --  Acquire main program line if present
872
873       if C = 'M' then
874          if Ignore ('M') then
875             Skip_Line;
876
877          else
878             Checkc (' ');
879             Skip_Space;
880
881             C := Getc;
882
883             if C = 'F' then
884                ALIs.Table (Id).Main_Program := Func;
885             elsif C = 'P' then
886                ALIs.Table (Id).Main_Program := Proc;
887             else
888                P := P - 1;
889                Fatal_Error;
890             end if;
891
892             Skip_Space;
893
894             if not At_Eol then
895                if Nextc < 'A' then
896                   ALIs.Table (Id).Main_Priority := Get_Nat;
897                end if;
898
899                Skip_Space;
900
901                if Nextc = 'T' then
902                   P := P + 1;
903                   Checkc ('=');
904                   ALIs.Table (Id).Time_Slice_Value := Get_Nat;
905                end if;
906
907                Skip_Space;
908
909                Checkc ('W');
910                Checkc ('=');
911                ALIs.Table (Id).WC_Encoding := Getc;
912             end if;
913
914             Skip_Eol;
915          end if;
916
917          C := Getc;
918       end if;
919
920       --  Acquire argument lines
921
922       First_Arg := Args.Last + 1;
923
924       A_Loop : loop
925          Check_Unknown_Line;
926          exit A_Loop when C /= 'A';
927
928          if Ignore ('A') then
929             Skip_Line;
930
931          else
932             Checkc (' ');
933             Name_Len := 0;
934
935             while not At_Eol loop
936                Name_Len := Name_Len + 1;
937                Name_Buffer (Name_Len) := Getc;
938             end loop;
939
940             Args.Increment_Last;
941             Args.Table (Args.Last) := new String'(Name_Buffer (1 .. Name_Len));
942
943             Skip_Eol;
944          end if;
945
946          C := Getc;
947       end loop A_Loop;
948
949       --  Acquire P line
950
951       Check_Unknown_Line;
952
953       while C /= 'P' loop
954          if Ignore_Errors then
955             if C = EOF then
956                Fatal_Error;
957             else
958                Skip_Line;
959                C := Nextc;
960             end if;
961          else
962             Fatal_Error;
963          end if;
964       end loop;
965
966       if Ignore ('P') then
967          Skip_Line;
968
969       --  Process P line
970
971       else
972          NS_Found := False;
973
974          while not At_Eol loop
975             Checkc (' ');
976             Skip_Space;
977             C := Getc;
978
979             --  Processing for CE
980
981             if C = 'C' then
982                Checkc ('E');
983                ALIs.Table (Id).Compile_Errors := True;
984
985             --  Processing for DB
986
987             elsif C = 'D' then
988                Checkc ('B');
989                Detect_Blocking := True;
990
991             --  Processing for FD/FG/FI
992
993             elsif C = 'F' then
994                Float_Format_Specified := Getc;
995                ALIs.Table (Id).Float_Format := Float_Format_Specified;
996
997             --  Processing for Lx
998
999             elsif C = 'L' then
1000                Locking_Policy_Specified := Getc;
1001                ALIs.Table (Id).Locking_Policy := Locking_Policy_Specified;
1002
1003             --  Processing for flags starting with N
1004
1005             elsif C = 'N' then
1006                C := Getc;
1007
1008                --  Processing for NO
1009
1010                if C = 'O' then
1011                   ALIs.Table (Id).No_Object := True;
1012                   No_Object_Specified := True;
1013
1014                --  Processing for NR
1015
1016                elsif C = 'R' then
1017                   No_Run_Time_Mode           := True;
1018                   Configurable_Run_Time_Mode := True;
1019
1020                --  Processing for NS
1021
1022                elsif C = 'S' then
1023                   ALIs.Table (Id).Normalize_Scalars := True;
1024                   Normalize_Scalars_Specified := True;
1025                   NS_Found := True;
1026
1027                --  Invalid switch starting with N
1028
1029                else
1030                   Fatal_Error_Ignore;
1031                end if;
1032
1033             --  Processing for Qx
1034
1035             elsif C = 'Q' then
1036                Queuing_Policy_Specified := Getc;
1037                ALIs.Table (Id).Queuing_Policy := Queuing_Policy_Specified;
1038
1039             --  Processing for flags starting with S
1040
1041             elsif C = 'S' then
1042                C := Getc;
1043
1044                --  Processing for SL
1045
1046                if C = 'L' then
1047                   ALIs.Table (Id).SAL_Interface := True;
1048
1049                --  Processing for SS
1050
1051                elsif C = 'S' then
1052                   Opt.Sec_Stack_Used := True;
1053
1054                --  Invalid switch starting with S
1055
1056                else
1057                   Fatal_Error_Ignore;
1058                end if;
1059
1060             --  Processing for Tx
1061
1062             elsif C = 'T' then
1063                Task_Dispatching_Policy_Specified := Getc;
1064                ALIs.Table (Id).Task_Dispatching_Policy :=
1065                  Task_Dispatching_Policy_Specified;
1066
1067             --  Processing for switch starting with U
1068
1069             elsif C = 'U' then
1070                C := Getc;
1071
1072                --  Processing for UA
1073
1074                if C  = 'A' then
1075                   Unreserve_All_Interrupts_Specified := True;
1076
1077                --  Processing for UX
1078
1079                elsif C = 'X' then
1080                   ALIs.Table (Id).Unit_Exception_Table := True;
1081
1082                --  Invalid switches starting with U
1083
1084                else
1085                   Fatal_Error_Ignore;
1086                end if;
1087
1088             --  Processing for ZX
1089
1090             elsif C = 'Z' then
1091                C := Getc;
1092
1093                if C = 'X' then
1094                   ALIs.Table (Id).Zero_Cost_Exceptions := True;
1095                   Zero_Cost_Exceptions_Specified := True;
1096                else
1097                   Fatal_Error_Ignore;
1098                end if;
1099
1100             --  Invalid parameter
1101
1102             else
1103                C := Getc;
1104                Fatal_Error_Ignore;
1105             end if;
1106          end loop;
1107
1108          if not NS_Found then
1109             No_Normalize_Scalars_Specified := True;
1110          end if;
1111
1112          Skip_Eol;
1113       end if;
1114
1115       C := Getc;
1116       Check_Unknown_Line;
1117
1118       --  Acquire first restrictions line
1119
1120       while C /= 'R' loop
1121          if Ignore_Errors then
1122             if C = EOF then
1123                Fatal_Error;
1124             else
1125                Skip_Line;
1126                C := Nextc;
1127             end if;
1128          else
1129             Fatal_Error;
1130          end if;
1131       end loop;
1132
1133       if Ignore ('R') then
1134          Skip_Line;
1135
1136       --  Process restrictions line
1137
1138       else
1139          Scan_Restrictions : declare
1140             Save_R : constant Restrictions_Info := Cumulative_Restrictions;
1141             --  Save cumulative restrictions in case we have a fatal error
1142
1143             Bad_R_Line : exception;
1144             --  Signal bad restrictions line (raised on unexpected character)
1145
1146          begin
1147             Checkc (' ');
1148             Skip_Space;
1149
1150             --  Acquire information for boolean restrictions
1151
1152             for R in All_Boolean_Restrictions loop
1153                C := Getc;
1154
1155                case C is
1156                   when 'v' =>
1157                      ALIs.Table (Id).Restrictions.Violated (R) := True;
1158                      Cumulative_Restrictions.Violated (R) := True;
1159
1160                   when 'r' =>
1161                      ALIs.Table (Id).Restrictions.Set (R) := True;
1162                      Cumulative_Restrictions.Set (R) := True;
1163
1164                   when 'n' =>
1165                      null;
1166
1167                   when others =>
1168                      raise Bad_R_Line;
1169                end case;
1170             end loop;
1171
1172             --  Acquire information for parameter restrictions
1173
1174             for RP in All_Parameter_Restrictions loop
1175
1176                --  Acquire restrictions pragma information
1177
1178                case Getc is
1179                   when 'n' =>
1180                      null;
1181
1182                   when 'r' =>
1183                      ALIs.Table (Id).Restrictions.Set (RP) := True;
1184
1185                      declare
1186                         N : constant Integer := Integer (Get_Nat);
1187                      begin
1188                         ALIs.Table (Id).Restrictions.Value (RP) := N;
1189
1190                         if Cumulative_Restrictions.Set (RP) then
1191                            Cumulative_Restrictions.Value (RP) :=
1192                              Integer'Min
1193                                (Cumulative_Restrictions.Value (RP), N);
1194                         else
1195                            Cumulative_Restrictions.Set (RP) := True;
1196                            Cumulative_Restrictions.Value (RP) := N;
1197                         end if;
1198                      end;
1199
1200                   when others =>
1201                      raise Bad_R_Line;
1202                end case;
1203
1204                --  Acquire restrictions violations information
1205
1206                case Getc is
1207                   when 'n' =>
1208                      null;
1209
1210                   when 'v' =>
1211                      ALIs.Table (Id).Restrictions.Violated (RP) := True;
1212                      Cumulative_Restrictions.Violated (RP) := True;
1213
1214                      declare
1215                         N : constant Integer := Integer (Get_Nat);
1216                         pragma Unsuppress (Overflow_Check);
1217
1218                      begin
1219                         ALIs.Table (Id).Restrictions.Count (RP) := N;
1220
1221                         if RP in Checked_Max_Parameter_Restrictions then
1222                            Cumulative_Restrictions.Count (RP) :=
1223                              Integer'Max
1224                                (Cumulative_Restrictions.Count (RP), N);
1225                         else
1226                            Cumulative_Restrictions.Count (RP) :=
1227                              Cumulative_Restrictions.Count (RP) + N;
1228                         end if;
1229
1230                      exception
1231                         when Constraint_Error =>
1232
1233                            --  A constraint error comes from the addition in
1234                            --  the else branch. We reset to the maximum and
1235                            --  indicate that the real value is now unknown.
1236
1237                            Cumulative_Restrictions.Value (RP) := Integer'Last;
1238                            Cumulative_Restrictions.Unknown (RP) := True;
1239                      end;
1240
1241                      if Nextc = '+' then
1242                         Skipc;
1243                         ALIs.Table (Id).Restrictions.Unknown (RP) := True;
1244                         Cumulative_Restrictions.Unknown (RP) := True;
1245                      end if;
1246
1247                   when others =>
1248                      raise Bad_R_Line;
1249                end case;
1250             end loop;
1251
1252             Skip_Eol;
1253
1254          --  Here if error during scanning of restrictions line
1255
1256          exception
1257             when Bad_R_Line =>
1258
1259                --  In Ignore_Errors mode, undo any changes to restrictions
1260                --  from this unit, and continue on.
1261
1262                if Ignore_Errors then
1263                   Cumulative_Restrictions := Save_R;
1264                   ALIs.Table (Id).Restrictions := No_Restrictions;
1265                   Skip_Eol;
1266
1267                --  In normal mode, this is a fatal error
1268
1269                else
1270                   Fatal_Error;
1271                end if;
1272
1273          end Scan_Restrictions;
1274       end if;
1275
1276       --  Acquire additional restrictions (No_Dependence) lines if present
1277
1278       C := Getc;
1279       while C = 'R' loop
1280          if Ignore ('R') then
1281             Skip_Line;
1282          else
1283             Skip_Space;
1284             No_Deps.Append ((Id, Get_Name));
1285          end if;
1286
1287          Skip_Eol;
1288          C := Getc;
1289       end loop;
1290
1291       --  Acquire 'I' lines if present
1292
1293       Check_Unknown_Line;
1294
1295       while C = 'I' loop
1296          if Ignore ('I') then
1297             Skip_Line;
1298
1299          else
1300             declare
1301                Int_Num : Nat;
1302                I_State : Character;
1303                Line_No : Nat;
1304
1305             begin
1306                Int_Num := Get_Nat;
1307                Skip_Space;
1308                I_State := Getc;
1309                Line_No := Get_Nat;
1310
1311                Interrupt_States.Append (
1312                  (Interrupt_Id    => Int_Num,
1313                   Interrupt_State => I_State,
1314                   IS_Pragma_Line  => Line_No));
1315
1316                ALIs.Table (Id).Last_Interrupt_State := Interrupt_States.Last;
1317                Skip_Eol;
1318             end;
1319          end if;
1320
1321          C := Getc;
1322       end loop;
1323
1324       --  Acquire 'S' lines if present
1325
1326       Check_Unknown_Line;
1327
1328       while C = 'S' loop
1329          if Ignore ('S') then
1330             Skip_Line;
1331
1332          else
1333             declare
1334                Policy     : Character;
1335                First_Prio : Nat;
1336                Last_Prio  : Nat;
1337                Line_No    : Nat;
1338
1339             begin
1340                Checkc (' ');
1341                Skip_Space;
1342
1343                Policy := Getc;
1344                Skip_Space;
1345                First_Prio := Get_Nat;
1346                Last_Prio := Get_Nat;
1347                Line_No := Get_Nat;
1348
1349                Specific_Dispatching.Append (
1350                  (Dispatching_Policy => Policy,
1351                   First_Priority     => First_Prio,
1352                   Last_Priority      => Last_Prio,
1353                   PSD_Pragma_Line    => Line_No));
1354
1355                ALIs.Table (Id).Last_Specific_Dispatching :=
1356                  Specific_Dispatching.Last;
1357
1358                Skip_Eol;
1359             end;
1360          end if;
1361
1362          C := Getc;
1363       end loop;
1364
1365       --  Loop to acquire unit entries
1366
1367       U_Loop : loop
1368          Check_Unknown_Line;
1369          exit U_Loop when C /= 'U';
1370
1371          --  Note: as per spec, we never ignore U lines
1372
1373          Checkc (' ');
1374          Skip_Space;
1375          Units.Increment_Last;
1376
1377          if ALIs.Table (Id).First_Unit = No_Unit_Id then
1378             ALIs.Table (Id).First_Unit := Units.Last;
1379          end if;
1380
1381          declare
1382             UL : Unit_Record renames Units.Table (Units.Last);
1383
1384          begin
1385             UL.Uname                    := Get_Unit_Name;
1386             UL.Predefined               := Is_Predefined_Unit;
1387             UL.Internal                 := Is_Internal_Unit;
1388             UL.My_ALI                   := Id;
1389             UL.Sfile                    := Get_File_Name (Lower => True);
1390             UL.Pure                     := False;
1391             UL.Preelab                  := False;
1392             UL.No_Elab                  := False;
1393             UL.Shared_Passive           := False;
1394             UL.RCI                      := False;
1395             UL.Remote_Types             := False;
1396             UL.Has_RACW                 := False;
1397             UL.Init_Scalars             := False;
1398             UL.Is_Generic               := False;
1399             UL.Icasing                  := Mixed_Case;
1400             UL.Kcasing                  := All_Lower_Case;
1401             UL.Dynamic_Elab             := False;
1402             UL.Elaborate_Body           := False;
1403             UL.Set_Elab_Entity          := False;
1404             UL.Version                  := "00000000";
1405             UL.First_With               := Withs.Last + 1;
1406             UL.First_Arg                := First_Arg;
1407             UL.Elab_Position            := 0;
1408             UL.SAL_Interface            := ALIs.Table (Id).SAL_Interface;
1409             UL.Body_Needed_For_SAL      := False;
1410             UL.Elaborate_Body_Desirable := False;
1411
1412             if Debug_Flag_U then
1413                Write_Str (" ----> reading unit ");
1414                Write_Int (Int (Units.Last));
1415                Write_Str ("  ");
1416                Write_Unit_Name (UL.Uname);
1417                Write_Str (" from file ");
1418                Write_Name (UL.Sfile);
1419                Write_Eol;
1420             end if;
1421          end;
1422
1423          --  Check for duplicated unit in different files
1424
1425          declare
1426             Info : constant Int := Get_Name_Table_Info
1427                                      (Units.Table (Units.Last).Uname);
1428          begin
1429             if Info /= 0
1430               and then Units.Table (Units.Last).Sfile /=
1431                        Units.Table (Unit_Id (Info)).Sfile
1432             then
1433                --  If Err is set then ignore duplicate unit name. This is the
1434                --  case of a call from gnatmake, where the situation can arise
1435                --  from substitution of source files. In such situations, the
1436                --  processing in gnatmake will always result in any required
1437                --  recompilations in any case, and if we consider this to be
1438                --  an error we get strange cases (for example when a generic
1439                --  instantiation is replaced by a normal package) where we
1440                --  read the old ali file, decide to recompile, and then decide
1441                --  that the old and new ali files are incompatible.
1442
1443                if Err then
1444                   null;
1445
1446                --  If Err is not set, then this is a fatal error. This is
1447                --  the case of being called from the binder, where we must
1448                --  definitely diagnose this as an error.
1449
1450                else
1451                   Set_Standard_Error;
1452                   Write_Str ("error: duplicate unit name: ");
1453                   Write_Eol;
1454
1455                   Write_Str ("error: unit """);
1456                   Write_Unit_Name (Units.Table (Units.Last).Uname);
1457                   Write_Str (""" found in file """);
1458                   Write_Name_Decoded (Units.Table (Units.Last).Sfile);
1459                   Write_Char ('"');
1460                   Write_Eol;
1461
1462                   Write_Str ("error: unit """);
1463                   Write_Unit_Name (Units.Table (Unit_Id (Info)).Uname);
1464                   Write_Str (""" found in file """);
1465                   Write_Name_Decoded (Units.Table (Unit_Id (Info)).Sfile);
1466                   Write_Char ('"');
1467                   Write_Eol;
1468
1469                   Exit_Program (E_Fatal);
1470                end if;
1471             end if;
1472          end;
1473
1474          Set_Name_Table_Info
1475            (Units.Table (Units.Last).Uname, Int (Units.Last));
1476
1477          --  Scan out possible version and other parameters
1478
1479          loop
1480             Skip_Space;
1481             exit when At_Eol;
1482             C := Getc;
1483
1484             --  Version field
1485
1486             if C in '0' .. '9' or else C in 'a' .. 'f' then
1487                Units.Table (Units.Last).Version (1) := C;
1488
1489                for J in 2 .. 8 loop
1490                   C := Getc;
1491                   Units.Table (Units.Last).Version (J) := C;
1492                end loop;
1493
1494             --  BD/BN parameters
1495
1496             elsif C = 'B' then
1497                C := Getc;
1498
1499                if C = 'D' then
1500                   Check_At_End_Of_Field;
1501                   Units.Table (Units.Last).Elaborate_Body_Desirable := True;
1502
1503                elsif C = 'N' then
1504                   Check_At_End_Of_Field;
1505                   Units.Table (Units.Last).Body_Needed_For_SAL := True;
1506
1507                else
1508                   Fatal_Error_Ignore;
1509                end if;
1510
1511             --  DE parameter (Dynamic elaboration checks)
1512
1513             elsif C = 'D' then
1514                C := Getc;
1515
1516                if C = 'E' then
1517                   Check_At_End_Of_Field;
1518                   Units.Table (Units.Last).Dynamic_Elab := True;
1519                   Dynamic_Elaboration_Checks_Specified := True;
1520                else
1521                   Fatal_Error_Ignore;
1522                end if;
1523
1524             --  EB/EE parameters
1525
1526             elsif C = 'E' then
1527                C := Getc;
1528
1529                if C = 'B' then
1530                   Units.Table (Units.Last).Elaborate_Body := True;
1531                elsif C = 'E' then
1532                   Units.Table (Units.Last).Set_Elab_Entity := True;
1533                else
1534                   Fatal_Error_Ignore;
1535                end if;
1536
1537                Check_At_End_Of_Field;
1538
1539             --  GE parameter (generic)
1540
1541             elsif C = 'G' then
1542                C := Getc;
1543
1544                if C = 'E' then
1545                   Check_At_End_Of_Field;
1546                   Units.Table (Units.Last).Is_Generic := True;
1547                else
1548                   Fatal_Error_Ignore;
1549                end if;
1550
1551             --  IL/IS/IU parameters
1552
1553             elsif C = 'I' then
1554                C := Getc;
1555
1556                if C = 'L' then
1557                   Units.Table (Units.Last).Icasing := All_Lower_Case;
1558                elsif C = 'S' then
1559                   Units.Table (Units.Last).Init_Scalars := True;
1560                   Initialize_Scalars_Used := True;
1561                elsif C = 'U' then
1562                   Units.Table (Units.Last).Icasing := All_Upper_Case;
1563                else
1564                   Fatal_Error_Ignore;
1565                end if;
1566
1567                Check_At_End_Of_Field;
1568
1569             --  KM/KU parameters
1570
1571             elsif C = 'K' then
1572                C := Getc;
1573
1574                if C = 'M' then
1575                   Units.Table (Units.Last).Kcasing := Mixed_Case;
1576                elsif C = 'U' then
1577                   Units.Table (Units.Last).Kcasing := All_Upper_Case;
1578                else
1579                   Fatal_Error_Ignore;
1580                end if;
1581
1582                Check_At_End_Of_Field;
1583
1584             --  NE parameter
1585
1586             elsif C = 'N' then
1587                C := Getc;
1588
1589                if C = 'E' then
1590                   Units.Table (Units.Last).No_Elab := True;
1591                   Check_At_End_Of_Field;
1592                else
1593                   Fatal_Error_Ignore;
1594                end if;
1595
1596             --  PR/PU/PK parameters
1597
1598             elsif C = 'P' then
1599                C := Getc;
1600
1601                if C = 'R' then
1602                   Units.Table (Units.Last).Preelab := True;
1603                elsif C = 'U' then
1604                   Units.Table (Units.Last).Pure := True;
1605                elsif C = 'K' then
1606                   Units.Table (Units.Last).Unit_Kind := 'p';
1607                else
1608                   Fatal_Error_Ignore;
1609                end if;
1610
1611                Check_At_End_Of_Field;
1612
1613             --  RC/RT parameters
1614
1615             elsif C = 'R' then
1616                C := Getc;
1617
1618                if C = 'C' then
1619                   Units.Table (Units.Last).RCI := True;
1620                elsif C = 'T' then
1621                   Units.Table (Units.Last).Remote_Types := True;
1622                elsif C = 'A' then
1623                   Units.Table (Units.Last).Has_RACW := True;
1624                else
1625                   Fatal_Error_Ignore;
1626                end if;
1627
1628                Check_At_End_Of_Field;
1629
1630             elsif C = 'S' then
1631                C := Getc;
1632
1633                if C = 'P' then
1634                   Units.Table (Units.Last).Shared_Passive := True;
1635                elsif C = 'U' then
1636                   Units.Table (Units.Last).Unit_Kind := 's';
1637                else
1638                   Fatal_Error_Ignore;
1639                end if;
1640
1641                Check_At_End_Of_Field;
1642
1643             else
1644                C := Getc;
1645                Fatal_Error_Ignore;
1646             end if;
1647          end loop;
1648
1649          Skip_Eol;
1650
1651          --  Check if static elaboration model used
1652
1653          if not Units.Table (Units.Last).Dynamic_Elab
1654            and then not Units.Table (Units.Last).Internal
1655          then
1656             Static_Elaboration_Model_Used := True;
1657          end if;
1658
1659          C := Getc;
1660
1661          --  Scan out With lines for this unit
1662
1663          With_Loop : loop
1664             Check_Unknown_Line;
1665             exit With_Loop when C /= 'W';
1666
1667             if Ignore ('W') then
1668                Skip_Line;
1669
1670             else
1671                Checkc (' ');
1672                Skip_Space;
1673                Withs.Increment_Last;
1674                Withs.Table (Withs.Last).Uname              := Get_Unit_Name;
1675                Withs.Table (Withs.Last).Elaborate          := False;
1676                Withs.Table (Withs.Last).Elaborate_All      := False;
1677                Withs.Table (Withs.Last).Elab_Desirable     := False;
1678                Withs.Table (Withs.Last).Elab_All_Desirable := False;
1679                Withs.Table (Withs.Last).SAL_Interface      := False;
1680
1681                --  Generic case with no object file available
1682
1683                if At_Eol then
1684                   Withs.Table (Withs.Last).Sfile := No_File;
1685                   Withs.Table (Withs.Last).Afile := No_File;
1686
1687                --  Normal case
1688
1689                else
1690                   Withs.Table (Withs.Last).Sfile := Get_File_Name
1691                                                       (Lower => True);
1692                   Withs.Table (Withs.Last).Afile := Get_File_Name
1693                                                       (Lower => True);
1694
1695                   --  Scan out possible E, EA, ED, and AD parameters
1696
1697                   while not At_Eol loop
1698                      Skip_Space;
1699
1700                      if Nextc = 'A' then
1701                         P := P + 1;
1702                         Checkc ('D');
1703                         Check_At_End_Of_Field;
1704
1705                         --  Store AD indication unless ignore required
1706
1707                         if not Ignore_ED then
1708                            Withs.Table (Withs.Last).Elab_All_Desirable :=
1709                              True;
1710                         end if;
1711
1712                      elsif Nextc = 'E' then
1713                         P := P + 1;
1714
1715                         if At_End_Of_Field then
1716                            Withs.Table (Withs.Last).Elaborate := True;
1717
1718                         elsif Nextc = 'A' then
1719                            P := P + 1;
1720                            Check_At_End_Of_Field;
1721                            Withs.Table (Withs.Last).Elaborate_All := True;
1722
1723                         else
1724                            Checkc ('D');
1725                            Check_At_End_Of_Field;
1726
1727                            --  Store ED indication unless ignore required
1728
1729                            if not Ignore_ED then
1730                               Withs.Table (Withs.Last).Elab_Desirable :=
1731                                 True;
1732                            end if;
1733                         end if;
1734
1735                      else
1736                         Fatal_Error;
1737                      end if;
1738                   end loop;
1739                end if;
1740
1741                Skip_Eol;
1742             end if;
1743
1744             C := Getc;
1745          end loop With_Loop;
1746
1747          Units.Table (Units.Last).Last_With := Withs.Last;
1748          Units.Table (Units.Last).Last_Arg  := Args.Last;
1749
1750          --  If there are linker options lines present, scan them
1751
1752          Name_Len := 0;
1753
1754          Linker_Options_Loop : loop
1755             Check_Unknown_Line;
1756             exit Linker_Options_Loop when C /= 'L';
1757
1758             if Ignore ('L') then
1759                Skip_Line;
1760
1761             else
1762                Checkc (' ');
1763                Skip_Space;
1764                Checkc ('"');
1765
1766                loop
1767                   C := Getc;
1768
1769                   if C < Character'Val (16#20#)
1770                     or else C > Character'Val (16#7E#)
1771                   then
1772                      Fatal_Error_Ignore;
1773
1774                   elsif C = '{' then
1775                      C := Character'Val (0);
1776
1777                      declare
1778                         V : Natural;
1779
1780                      begin
1781                         V := 0;
1782                         for J in 1 .. 2 loop
1783                            C := Getc;
1784
1785                            if C in '0' .. '9' then
1786                               V := V * 16 +
1787                                      Character'Pos (C) -
1788                                        Character'Pos ('0');
1789
1790                            elsif C in 'A' .. 'F' then
1791                               V := V * 16 +
1792                                      Character'Pos (C) -
1793                                        Character'Pos ('A') +
1794                                          10;
1795
1796                            else
1797                               Fatal_Error_Ignore;
1798                            end if;
1799                         end loop;
1800
1801                         Checkc ('}');
1802                         Add_Char_To_Name_Buffer (Character'Val (V));
1803                      end;
1804
1805                   else
1806                      if C = '"' then
1807                         exit when Nextc /= '"';
1808                         C := Getc;
1809                      end if;
1810
1811                      Add_Char_To_Name_Buffer (C);
1812                   end if;
1813                end loop;
1814
1815                Add_Char_To_Name_Buffer (nul);
1816                Skip_Eol;
1817             end if;
1818
1819             C := Getc;
1820          end loop Linker_Options_Loop;
1821
1822          --  Store the linker options entry if one was found
1823
1824          if Name_Len /= 0 then
1825             Linker_Options.Increment_Last;
1826
1827             Linker_Options.Table (Linker_Options.Last).Name :=
1828               Name_Enter;
1829
1830             Linker_Options.Table (Linker_Options.Last).Unit :=
1831               Units.Last;
1832
1833             Linker_Options.Table (Linker_Options.Last).Internal_File :=
1834               Is_Internal_File_Name (F);
1835
1836             Linker_Options.Table (Linker_Options.Last).Original_Pos :=
1837               Linker_Options.Last;
1838          end if;
1839       end loop U_Loop;
1840
1841       --  End loop through units for one ALI file
1842
1843       ALIs.Table (Id).Last_Unit := Units.Last;
1844       ALIs.Table (Id).Sfile := Units.Table (ALIs.Table (Id).First_Unit).Sfile;
1845
1846       --  Set types of the units (there can be at most 2 of them)
1847
1848       if ALIs.Table (Id).First_Unit /= ALIs.Table (Id).Last_Unit then
1849          Units.Table (ALIs.Table (Id).First_Unit).Utype := Is_Body;
1850          Units.Table (ALIs.Table (Id).Last_Unit).Utype  := Is_Spec;
1851
1852       else
1853          --  Deal with body only and spec only cases, note that the reason we
1854          --  do our own checking of the name (rather than using Is_Body_Name)
1855          --  is that Uname drags in far too much compiler junk!
1856
1857          Get_Name_String (Units.Table (Units.Last).Uname);
1858
1859          if Name_Buffer (Name_Len) = 'b' then
1860             Units.Table (Units.Last).Utype := Is_Body_Only;
1861          else
1862             Units.Table (Units.Last).Utype := Is_Spec_Only;
1863          end if;
1864       end if;
1865
1866       --  Scan out external version references and put in hash table
1867
1868       E_Loop : loop
1869          Check_Unknown_Line;
1870          exit E_Loop when C /= 'E';
1871
1872          if Ignore ('E') then
1873             Skip_Line;
1874
1875          else
1876             Checkc (' ');
1877             Skip_Space;
1878
1879             Name_Len := 0;
1880             Name_Len := 0;
1881             loop
1882                C := Getc;
1883
1884                if C < ' ' then
1885                   Fatal_Error;
1886                end if;
1887
1888                exit when At_End_Of_Field;
1889                Add_Char_To_Name_Buffer (C);
1890             end loop;
1891
1892             Version_Ref.Set (new String'(Name_Buffer (1 .. Name_Len)), True);
1893             Skip_Eol;
1894          end if;
1895
1896          C := Getc;
1897       end loop E_Loop;
1898
1899       --  Scan out source dependency lines for this ALI file
1900
1901       ALIs.Table (Id).First_Sdep := Sdep.Last + 1;
1902
1903       D_Loop : loop
1904          Check_Unknown_Line;
1905          exit D_Loop when C /= 'D';
1906
1907          if Ignore ('D') then
1908             Skip_Line;
1909
1910          else
1911             Checkc (' ');
1912             Skip_Space;
1913             Sdep.Increment_Last;
1914
1915             --  In the following call, Lower is not set to True, this is either
1916             --  a bug, or it deserves a special comment as to why this is so???
1917
1918             Sdep.Table (Sdep.Last).Sfile := Get_File_Name;
1919
1920             Sdep.Table (Sdep.Last).Stamp := Get_Stamp;
1921             Sdep.Table (Sdep.Last).Dummy_Entry :=
1922               (Sdep.Table (Sdep.Last).Stamp = Dummy_Time_Stamp);
1923
1924             --  Acquire checksum value
1925
1926             Skip_Space;
1927
1928             declare
1929                Ctr : Natural;
1930                Chk : Word;
1931
1932             begin
1933                Ctr := 0;
1934                Chk := 0;
1935
1936                loop
1937                   exit when At_Eol or else Ctr = 8;
1938
1939                   if Nextc in '0' .. '9' then
1940                      Chk := Chk * 16 +
1941                               Character'Pos (Nextc) - Character'Pos ('0');
1942
1943                   elsif Nextc in 'a' .. 'f' then
1944                      Chk := Chk * 16 +
1945                               Character'Pos (Nextc) - Character'Pos ('a') + 10;
1946
1947                   else
1948                      exit;
1949                   end if;
1950
1951                   Ctr := Ctr + 1;
1952                   P := P + 1;
1953                end loop;
1954
1955                if Ctr = 8 and then At_End_Of_Field then
1956                   Sdep.Table (Sdep.Last).Checksum := Chk;
1957                else
1958                   Fatal_Error;
1959                end if;
1960             end;
1961
1962             --  Acquire subunit and reference file name entries
1963
1964             Sdep.Table (Sdep.Last).Subunit_Name := No_Name;
1965             Sdep.Table (Sdep.Last).Rfile        :=
1966               Sdep.Table (Sdep.Last).Sfile;
1967             Sdep.Table (Sdep.Last).Start_Line   := 1;
1968
1969             if not At_Eol then
1970                Skip_Space;
1971
1972                --  Here for subunit name
1973
1974                if Nextc not in '0' .. '9' then
1975                   Name_Len := 0;
1976
1977                   while not At_End_Of_Field loop
1978                      Name_Len := Name_Len + 1;
1979                      Name_Buffer (Name_Len) := Getc;
1980                   end loop;
1981
1982                   Sdep.Table (Sdep.Last).Subunit_Name := Name_Enter;
1983                   Skip_Space;
1984                end if;
1985
1986                --  Here for reference file name entry
1987
1988                if Nextc in '0' .. '9' then
1989                   Sdep.Table (Sdep.Last).Start_Line := Get_Nat;
1990                   Checkc (':');
1991
1992                   Name_Len := 0;
1993
1994                   while not At_End_Of_Field loop
1995                      Name_Len := Name_Len + 1;
1996                      Name_Buffer (Name_Len) := Getc;
1997                   end loop;
1998
1999                   Sdep.Table (Sdep.Last).Rfile := Name_Enter;
2000                end if;
2001             end if;
2002
2003             Skip_Eol;
2004          end if;
2005
2006          C := Getc;
2007       end loop D_Loop;
2008
2009       ALIs.Table (Id).Last_Sdep := Sdep.Last;
2010
2011       --  We must at this stage be at an Xref line or the end of file
2012
2013       if C = EOF then
2014          return Id;
2015       end if;
2016
2017       Check_Unknown_Line;
2018
2019       if C /= 'X' then
2020          Fatal_Error;
2021       end if;
2022
2023       --  If we are ignoring Xref sections we are done (we ignore all
2024       --  remaining lines since only xref related lines follow X).
2025
2026       if Ignore ('X') and then not Debug_Flag_X then
2027          return Id;
2028       end if;
2029
2030       --  Loop through Xref sections
2031
2032       X_Loop : loop
2033          Check_Unknown_Line;
2034          exit X_Loop when C /= 'X';
2035
2036          --  Make new entry in section table
2037
2038          Xref_Section.Increment_Last;
2039
2040          Read_Refs_For_One_File : declare
2041             XS : Xref_Section_Record renames
2042                    Xref_Section.Table (Xref_Section.Last);
2043
2044             Current_File_Num : Sdep_Id;
2045             --  Keeps track of the current file number (changed by nn|)
2046
2047          begin
2048             XS.File_Num     := Sdep_Id (Get_Nat + Nat (First_Sdep_Entry) - 1);
2049             XS.File_Name    := Get_File_Name;
2050             XS.First_Entity := Xref_Entity.Last + 1;
2051
2052             Current_File_Num := XS.File_Num;
2053
2054             Skip_Space;
2055
2056             Skip_Eol;
2057             C := Nextc;
2058
2059             --  Loop through Xref entities
2060
2061             while C /= 'X' and then C /= EOF loop
2062                Xref_Entity.Increment_Last;
2063
2064                Read_Refs_For_One_Entity : declare
2065                   XE : Xref_Entity_Record renames
2066                          Xref_Entity.Table (Xref_Entity.Last);
2067                   N  : Nat;
2068
2069                   procedure Read_Instantiation_Reference;
2070                   --  Acquire instantiation reference. Caller has checked
2071                   --  that current character is '[' and on return the cursor
2072                   --  is skipped past the corresponding closing ']'.
2073
2074                   ----------------------------------
2075                   -- Read_Instantiation_Reference --
2076                   ----------------------------------
2077
2078                   procedure Read_Instantiation_Reference is
2079                      Local_File_Num : Sdep_Id := Current_File_Num;
2080
2081                   begin
2082                      Xref.Increment_Last;
2083
2084                      declare
2085                         XR : Xref_Record renames Xref.Table (Xref.Last);
2086
2087                      begin
2088                         P := P + 1; -- skip [
2089                         N := Get_Nat;
2090
2091                         if Nextc = '|' then
2092                            XR.File_Num :=
2093                              Sdep_Id (N + Nat (First_Sdep_Entry) - 1);
2094                            Local_File_Num := XR.File_Num;
2095                            P := P + 1;
2096                            N := Get_Nat;
2097
2098                         else
2099                            XR.File_Num := Local_File_Num;
2100                         end if;
2101
2102                         XR.Line  := N;
2103                         XR.Rtype := ' ';
2104                         XR.Col   := 0;
2105
2106                         --  Recursive call for next reference
2107
2108                         if Nextc = '[' then
2109                            pragma Warnings (Off); -- kill recursion warning
2110                            Read_Instantiation_Reference;
2111                            pragma Warnings (On);
2112                         end if;
2113
2114                         --  Skip closing bracket after recursive call
2115
2116                         P := P + 1;
2117                      end;
2118                   end Read_Instantiation_Reference;
2119
2120                --  Start of processing for Read_Refs_For_One_Entity
2121
2122                begin
2123                   XE.Line   := Get_Nat;
2124                   XE.Etype  := Getc;
2125                   XE.Col    := Get_Nat;
2126                   XE.Lib    := (Getc = '*');
2127                   XE.Entity := Get_Name;
2128
2129                   --  Handle the information about generic instantiations
2130
2131                   if Nextc = '[' then
2132                      Skipc; --  Opening '['
2133                      N := Get_Nat;
2134
2135                      if Nextc /= '|' then
2136                         XE.Iref_File_Num := Current_File_Num;
2137                         XE.Iref_Line     := N;
2138                      else
2139                         XE.Iref_File_Num :=
2140                           Sdep_Id (N + Nat (First_Sdep_Entry) - 1);
2141                         Skipc;
2142                         XE.Iref_Line := Get_Nat;
2143                      end if;
2144
2145                      if Getc /= ']' then
2146                         Fatal_Error;
2147                      end if;
2148
2149                   else
2150                      XE.Iref_File_Num := No_Sdep_Id;
2151                      XE.Iref_Line     := 0;
2152                   end if;
2153
2154                   Current_File_Num := XS.File_Num;
2155
2156                   --  Renaming reference is present
2157
2158                   if Nextc = '=' then
2159                      P := P + 1;
2160                      XE.Rref_Line := Get_Nat;
2161
2162                      if Getc /= ':' then
2163                         Fatal_Error;
2164                      end if;
2165
2166                      XE.Rref_Col := Get_Nat;
2167
2168                   --  No renaming reference present
2169
2170                   else
2171                      XE.Rref_Line := 0;
2172                      XE.Rref_Col  := 0;
2173                   end if;
2174
2175                   Skip_Space;
2176
2177                   --  See if type reference present
2178
2179                   Get_Typeref
2180                     (Current_File_Num, XE.Tref, XE.Tref_File_Num, XE.Tref_Line,
2181                      XE.Tref_Type, XE.Tref_Col, XE.Tref_Standard_Entity);
2182
2183                   --  Do we have an overriding procedure, instead ?
2184                   if XE.Tref_Type = 'p' then
2185                      XE.Oref_File_Num := XE.Tref_File_Num;
2186                      XE.Oref_Line     := XE.Tref_Line;
2187                      XE.Oref_Col      := XE.Tref_Col;
2188                      XE.Tref_File_Num := No_Sdep_Id;
2189                      XE.Tref          := Tref_None;
2190                   else
2191                      --  We might have additional information about the
2192                      --  overloaded subprograms
2193                      declare
2194                         Ref : Tref_Kind;
2195                         Typ : Character;
2196                         Standard_Entity : Name_Id;
2197                      begin
2198                         Get_Typeref
2199                           (Current_File_Num,
2200                            Ref, XE.Oref_File_Num,
2201                            XE.Oref_Line, Typ, XE.Oref_Col, Standard_Entity);
2202                      end;
2203                   end if;
2204
2205                   XE.First_Xref := Xref.Last + 1;
2206
2207                   --  Loop through cross-references for this entity
2208
2209                   loop
2210                      Skip_Space;
2211
2212                      if At_Eol then
2213                         Skip_Eol;
2214                         exit when Nextc /= '.';
2215                         P := P + 1;
2216                      end if;
2217
2218                      Xref.Increment_Last;
2219
2220                      declare
2221                         XR : Xref_Record renames Xref.Table (Xref.Last);
2222
2223                      begin
2224                         N := Get_Nat;
2225
2226                         if Nextc = '|' then
2227                            XR.File_Num :=
2228                              Sdep_Id (N + Nat (First_Sdep_Entry) - 1);
2229                            Current_File_Num := XR.File_Num;
2230                            P := P + 1;
2231                            N := Get_Nat;
2232                         else
2233                            XR.File_Num := Current_File_Num;
2234                         end if;
2235
2236                         XR.Line  := N;
2237                         XR.Rtype := Getc;
2238
2239                         --  Imported entities reference as in:
2240                         --    494b<c,__gnat_copy_attribs>25
2241                         --  ??? Simply skipped for now
2242
2243                         if Nextc = '<' then
2244                            while Getc /= '>' loop
2245                               null;
2246                            end loop;
2247                         end if;
2248
2249                         XR.Col   := Get_Nat;
2250
2251                         if Nextc = '[' then
2252                            Read_Instantiation_Reference;
2253                         end if;
2254                      end;
2255                   end loop;
2256
2257                   --  Record last cross-reference
2258
2259                   XE.Last_Xref := Xref.Last;
2260                   C := Nextc;
2261
2262                exception
2263                   when Bad_ALI_Format =>
2264
2265                      --  If ignoring errors, then we skip a line with an
2266                      --  unexpected error, and try to continue subsequent
2267                      --  xref lines.
2268
2269                      if Ignore_Errors then
2270                         Xref_Entity.Decrement_Last;
2271                         Skip_Line;
2272                         C := Nextc;
2273
2274                      --  Otherwise, we reraise the fatal exception
2275
2276                      else
2277                         raise;
2278                      end if;
2279                end Read_Refs_For_One_Entity;
2280             end loop;
2281
2282             --  Record last entity
2283
2284             XS.Last_Entity := Xref_Entity.Last;
2285
2286          end Read_Refs_For_One_File;
2287
2288          C := Getc;
2289       end loop X_Loop;
2290
2291       --  Here after dealing with xref sections
2292
2293       if C /= EOF and then C /= 'X' then
2294          Fatal_Error;
2295       end if;
2296
2297       return Id;
2298
2299    exception
2300       when Bad_ALI_Format =>
2301          return No_ALI_Id;
2302    end Scan_ALI;
2303
2304    ---------
2305    -- SEq --
2306    ---------
2307
2308    function SEq (F1, F2 : String_Ptr) return Boolean is
2309    begin
2310       return F1.all = F2.all;
2311    end SEq;
2312
2313    -----------
2314    -- SHash --
2315    -----------
2316
2317    function SHash (S : String_Ptr) return Vindex is
2318       H : Word;
2319
2320    begin
2321       H := 0;
2322       for J in S.all'Range loop
2323          H := H * 2 + Character'Pos (S (J));
2324       end loop;
2325
2326       return Vindex (Vindex'First + Vindex (H mod Vindex'Range_Length));
2327    end SHash;
2328
2329 end ALI;