OSDN Git Service

2007-09-26 Thomas Quinot <quinot@adacore.com>
[pf3gnuchains/gcc-fork.git] / gcc / ada / sinput.adb
1 ------------------------------------------------------------------------------
2 --                                                                          --
3 --                         GNAT COMPILER COMPONENTS                         --
4 --                                                                          --
5 --                               S I N P U T                                --
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 2,  or (at your option) any later ver- --
14 -- sion.  GNAT is distributed in the hope that it will be useful, but WITH- --
15 -- OUT ANY WARRANTY;  without even the  implied warranty of MERCHANTABILITY --
16 -- or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License --
17 -- for  more details.  You should have  received  a copy of the GNU General --
18 -- Public License  distributed with GNAT;  see file COPYING.  If not, write --
19 -- to  the  Free Software Foundation,  51  Franklin  Street,  Fifth  Floor, --
20 -- Boston, MA 02110-1301, USA.                                              --
21 --                                                                          --
22 -- As a special exception,  if other files  instantiate  generics from this --
23 -- unit, or you link  this unit with other files  to produce an executable, --
24 -- this  unit  does not  by itself cause  the resulting  executable  to  be --
25 -- covered  by the  GNU  General  Public  License.  This exception does not --
26 -- however invalidate  any other reasons why  the executable file  might be --
27 -- covered by the  GNU Public License.                                      --
28 --                                                                          --
29 -- GNAT was originally developed  by the GNAT team at  New York University. --
30 -- Extensive contributions were provided by Ada Core Technologies Inc.      --
31 --                                                                          --
32 ------------------------------------------------------------------------------
33
34 pragma Style_Checks (All_Checks);
35 --  Subprograms not all in alpha order
36
37 with Debug;    use Debug;
38 with Opt;      use Opt;
39 with Output;   use Output;
40 with Tree_IO;  use Tree_IO;
41 with System;   use System;
42 with Widechar; use Widechar;
43
44 with System.Memory;
45
46 with Unchecked_Conversion;
47 with Unchecked_Deallocation;
48
49 package body Sinput is
50
51    use ASCII;
52    --  Make control characters visible
53
54    First_Time_Around : Boolean := True;
55
56    --  Routines to support conversion between types Lines_Table_Ptr,
57    --  Logical_Lines_Table_Ptr and System.Address.
58
59    pragma Warnings (Off);
60    --  These unchecked conversions are aliasing safe, since they are never
61    --  used to construct improperly aliased pointer values.
62
63    function To_Address is
64      new Unchecked_Conversion (Lines_Table_Ptr, Address);
65
66    function To_Address is
67      new Unchecked_Conversion (Logical_Lines_Table_Ptr, Address);
68
69    function To_Pointer is
70      new Unchecked_Conversion (Address, Lines_Table_Ptr);
71
72    function To_Pointer is
73      new Unchecked_Conversion (Address, Logical_Lines_Table_Ptr);
74
75    pragma Warnings (On);
76
77    ---------------------------
78    -- Add_Line_Tables_Entry --
79    ---------------------------
80
81    procedure Add_Line_Tables_Entry
82      (S : in out Source_File_Record;
83       P : Source_Ptr)
84    is
85       LL : Physical_Line_Number;
86
87    begin
88       --  Reallocate the lines tables if necessary
89
90       --  Note: the reason we do not use the normal Table package
91       --  mechanism is that we have several of these tables. We could
92       --  use the new GNAT.Dynamic_Tables package and that would probably
93       --  be a good idea ???
94
95       if S.Last_Source_Line = S.Lines_Table_Max then
96          Alloc_Line_Tables
97            (S,
98             Int (S.Last_Source_Line) *
99               ((100 + Alloc.Lines_Increment) / 100));
100
101          if Debug_Flag_D then
102             Write_Str ("--> Reallocating lines table, size = ");
103             Write_Int (Int (S.Lines_Table_Max));
104             Write_Eol;
105          end if;
106       end if;
107
108       S.Last_Source_Line := S.Last_Source_Line + 1;
109       LL := S.Last_Source_Line;
110
111       S.Lines_Table (LL) := P;
112
113       --  Deal with setting new entry in logical lines table if one is
114       --  present. Note that there is always space (because the call to
115       --  Alloc_Line_Tables makes sure both tables are the same length),
116
117       if S.Logical_Lines_Table /= null then
118
119          --  We can always set the entry from the previous one, because
120          --  the processing for a Source_Reference pragma ensures that
121          --  at least one entry following the pragma is set up correctly.
122
123          S.Logical_Lines_Table (LL) := S.Logical_Lines_Table (LL - 1) + 1;
124       end if;
125    end Add_Line_Tables_Entry;
126
127    -----------------------
128    -- Alloc_Line_Tables --
129    -----------------------
130
131    procedure Alloc_Line_Tables
132      (S       : in out Source_File_Record;
133       New_Max : Nat)
134    is
135       subtype size_t is Memory.size_t;
136
137       New_Table : Lines_Table_Ptr;
138
139       New_Logical_Table : Logical_Lines_Table_Ptr;
140
141       New_Size : constant size_t :=
142                    size_t (New_Max * Lines_Table_Type'Component_Size /
143                                                              Storage_Unit);
144
145    begin
146       if S.Lines_Table = null then
147          New_Table := To_Pointer (Memory.Alloc (New_Size));
148
149       else
150          New_Table :=
151            To_Pointer (Memory.Realloc (To_Address (S.Lines_Table), New_Size));
152       end if;
153
154       if New_Table = null then
155          raise Storage_Error;
156       else
157          S.Lines_Table     := New_Table;
158          S.Lines_Table_Max := Physical_Line_Number (New_Max);
159       end if;
160
161       if S.Num_SRef_Pragmas /= 0 then
162          if S.Logical_Lines_Table = null then
163             New_Logical_Table := To_Pointer (Memory.Alloc (New_Size));
164          else
165             New_Logical_Table := To_Pointer
166               (Memory.Realloc (To_Address (S.Logical_Lines_Table), New_Size));
167          end if;
168
169          if New_Logical_Table = null then
170             raise Storage_Error;
171          else
172             S.Logical_Lines_Table := New_Logical_Table;
173          end if;
174       end if;
175    end Alloc_Line_Tables;
176
177    -----------------
178    -- Backup_Line --
179    -----------------
180
181    procedure Backup_Line (P : in out Source_Ptr) is
182       Sindex : constant Source_File_Index := Get_Source_File_Index (P);
183       Src    : constant Source_Buffer_Ptr :=
184                  Source_File.Table (Sindex).Source_Text;
185       Sfirst : constant Source_Ptr :=
186                  Source_File.Table (Sindex).Source_First;
187
188    begin
189       P := P - 1;
190
191       if P = Sfirst then
192          return;
193       end if;
194
195       if Src (P) = CR then
196          if Src (P - 1) = LF then
197             P := P - 1;
198          end if;
199
200       else -- Src (P) = LF
201          if Src (P - 1) = CR then
202             P := P - 1;
203          end if;
204       end if;
205
206       --  Now find first character of the previous line
207
208       while P > Sfirst
209         and then Src (P - 1) /= LF
210         and then Src (P - 1) /= CR
211       loop
212          P := P - 1;
213       end loop;
214    end Backup_Line;
215
216    ---------------------------
217    -- Build_Location_String --
218    ---------------------------
219
220    procedure Build_Location_String (Loc : Source_Ptr) is
221       Ptr : Source_Ptr;
222
223    begin
224       Name_Len := 0;
225
226       --  Loop through instantiations
227
228       Ptr := Loc;
229       loop
230          Get_Name_String_And_Append
231            (Reference_Name (Get_Source_File_Index (Ptr)));
232          Add_Char_To_Name_Buffer (':');
233          Add_Nat_To_Name_Buffer
234            (Nat (Get_Logical_Line_Number (Ptr)));
235
236          Ptr := Instantiation_Location (Ptr);
237          exit when Ptr = No_Location;
238          Add_Str_To_Name_Buffer (" instantiated at ");
239       end loop;
240
241       Name_Buffer (Name_Len + 1) := NUL;
242       return;
243    end Build_Location_String;
244
245    -----------------------
246    -- Get_Column_Number --
247    -----------------------
248
249    function Get_Column_Number (P : Source_Ptr) return Column_Number is
250       S      : Source_Ptr;
251       C      : Column_Number;
252       Sindex : Source_File_Index;
253       Src    : Source_Buffer_Ptr;
254
255    begin
256       --  If the input source pointer is not a meaningful value then return
257       --  at once with column number 1. This can happen for a file not found
258       --  condition for a file loaded indirectly by RTE, and also perhaps on
259       --  some unknown internal error conditions. In either case we certainly
260       --  don't want to blow up.
261
262       if P < 1 then
263          return 1;
264
265       else
266          Sindex := Get_Source_File_Index (P);
267          Src := Source_File.Table (Sindex).Source_Text;
268          S := Line_Start (P);
269          C := 1;
270
271          while S < P loop
272             if Src (S) = HT then
273                C := (C - 1) / 8 * 8 + (8 + 1);
274             else
275                C := C + 1;
276             end if;
277
278             S := S + 1;
279          end loop;
280
281          return C;
282       end if;
283    end Get_Column_Number;
284
285    -----------------------------
286    -- Get_Logical_Line_Number --
287    -----------------------------
288
289    function Get_Logical_Line_Number
290      (P    : Source_Ptr)
291       return Logical_Line_Number
292    is
293       SFR : Source_File_Record
294               renames Source_File.Table (Get_Source_File_Index (P));
295
296       L : constant Physical_Line_Number := Get_Physical_Line_Number (P);
297
298    begin
299       if SFR.Num_SRef_Pragmas = 0 then
300          return Logical_Line_Number (L);
301       else
302          return SFR.Logical_Lines_Table (L);
303       end if;
304    end Get_Logical_Line_Number;
305
306    ------------------------------
307    -- Get_Physical_Line_Number --
308    ------------------------------
309
310    function Get_Physical_Line_Number
311      (P    : Source_Ptr)
312       return Physical_Line_Number
313    is
314       Sfile : Source_File_Index;
315       Table : Lines_Table_Ptr;
316       Lo    : Physical_Line_Number;
317       Hi    : Physical_Line_Number;
318       Mid   : Physical_Line_Number;
319       Loc   : Source_Ptr;
320
321    begin
322       --  If the input source pointer is not a meaningful value then return
323       --  at once with line number 1. This can happen for a file not found
324       --  condition for a file loaded indirectly by RTE, and also perhaps on
325       --  some unknown internal error conditions. In either case we certainly
326       --  don't want to blow up.
327
328       if P < 1 then
329          return 1;
330
331       --  Otherwise we can do the binary search
332
333       else
334          Sfile := Get_Source_File_Index (P);
335          Loc   := P + Source_File.Table (Sfile).Sloc_Adjust;
336          Table := Source_File.Table (Sfile).Lines_Table;
337          Lo    := 1;
338          Hi    := Source_File.Table (Sfile).Last_Source_Line;
339
340          loop
341             Mid := (Lo + Hi) / 2;
342
343             if Loc < Table (Mid) then
344                Hi := Mid - 1;
345
346             else -- Loc >= Table (Mid)
347
348                if Mid = Hi or else
349                   Loc < Table (Mid + 1)
350                then
351                   return Mid;
352                else
353                   Lo := Mid + 1;
354                end if;
355
356             end if;
357
358          end loop;
359       end if;
360    end Get_Physical_Line_Number;
361
362    ---------------------------
363    -- Get_Source_File_Index --
364    ---------------------------
365
366    Source_Cache_First : Source_Ptr := 1;
367    Source_Cache_Last  : Source_Ptr := 0;
368    --  Records the First and Last subscript values for the most recently
369    --  referenced entry in the source table, to optimize the common case
370    --  of repeated references to the same entry. The initial values force
371    --  an initial search to set the cache value.
372
373    Source_Cache_Index : Source_File_Index := No_Source_File;
374    --  Contains the index of the entry corresponding to Source_Cache
375
376    function Get_Source_File_Index
377      (S    : Source_Ptr)
378       return Source_File_Index
379    is
380    begin
381       if S in Source_Cache_First .. Source_Cache_Last then
382          return Source_Cache_Index;
383
384       else
385          for J in Source_File_Index_Table (Int (S) / Chunk_Size)
386                                                     .. Source_File.Last
387          loop
388             if S in Source_File.Table (J).Source_First ..
389                     Source_File.Table (J).Source_Last
390             then
391                Source_Cache_Index := J;
392                Source_Cache_First :=
393                  Source_File.Table (Source_Cache_Index).Source_First;
394                Source_Cache_Last :=
395                  Source_File.Table (Source_Cache_Index).Source_Last;
396                return Source_Cache_Index;
397             end if;
398          end loop;
399       end if;
400
401       --  We must find a matching entry in the above loop!
402
403       raise Program_Error;
404    end Get_Source_File_Index;
405
406    ----------------
407    -- Initialize --
408    ----------------
409
410    procedure Initialize is
411    begin
412       Source_Cache_First := 1;
413       Source_Cache_Last  := 0;
414       Source_Cache_Index := No_Source_File;
415       Source_gnat_adc    := No_Source_File;
416       First_Time_Around  := True;
417
418       Source_File.Init;
419    end Initialize;
420
421    -------------------------
422    -- Instantiation_Depth --
423    -------------------------
424
425    function Instantiation_Depth (S : Source_Ptr) return Nat is
426       Sind  : Source_File_Index;
427       Sval  : Source_Ptr;
428       Depth : Nat;
429
430    begin
431       Sval := S;
432       Depth := 0;
433
434       loop
435          Sind := Get_Source_File_Index (Sval);
436          Sval := Instantiation (Sind);
437          exit when Sval = No_Location;
438          Depth := Depth + 1;
439       end loop;
440
441       return Depth;
442    end Instantiation_Depth;
443
444    ----------------------------
445    -- Instantiation_Location --
446    ----------------------------
447
448    function Instantiation_Location (S : Source_Ptr) return Source_Ptr is
449    begin
450       return Instantiation (Get_Source_File_Index (S));
451    end Instantiation_Location;
452
453    ----------------------
454    -- Last_Source_File --
455    ----------------------
456
457    function Last_Source_File return Source_File_Index is
458    begin
459       return Source_File.Last;
460    end Last_Source_File;
461
462    ----------------
463    -- Line_Start --
464    ----------------
465
466    function Line_Start (P : Source_Ptr) return Source_Ptr is
467       Sindex : constant Source_File_Index := Get_Source_File_Index (P);
468       Src    : constant Source_Buffer_Ptr :=
469                  Source_File.Table (Sindex).Source_Text;
470       Sfirst : constant Source_Ptr :=
471                  Source_File.Table (Sindex).Source_First;
472       S      : Source_Ptr;
473
474    begin
475       S := P;
476
477       while S > Sfirst
478         and then Src (S - 1) /= CR
479         and then Src (S - 1) /= LF
480       loop
481          S := S - 1;
482       end loop;
483
484       return S;
485    end Line_Start;
486
487    function Line_Start
488      (L    : Physical_Line_Number;
489       S    : Source_File_Index)
490       return Source_Ptr
491    is
492    begin
493       return Source_File.Table (S).Lines_Table (L);
494    end Line_Start;
495
496    ----------
497    -- Lock --
498    ----------
499
500    procedure Lock is
501    begin
502       Source_File.Locked := True;
503       Source_File.Release;
504    end Lock;
505
506    ----------------------
507    -- Num_Source_Files --
508    ----------------------
509
510    function Num_Source_Files return Nat is
511    begin
512       return Int (Source_File.Last) - Int (Source_File.First) + 1;
513    end Num_Source_Files;
514
515    ----------------------
516    -- Num_Source_Lines --
517    ----------------------
518
519    function Num_Source_Lines (S : Source_File_Index) return Nat is
520    begin
521       return Nat (Source_File.Table (S).Last_Source_Line);
522    end Num_Source_Lines;
523
524    -----------------------
525    -- Original_Location --
526    -----------------------
527
528    function Original_Location (S : Source_Ptr) return Source_Ptr is
529       Sindex : Source_File_Index;
530       Tindex : Source_File_Index;
531
532    begin
533       if S <= No_Location then
534          return S;
535
536       else
537          Sindex := Get_Source_File_Index (S);
538
539          if Instantiation (Sindex) = No_Location then
540             return S;
541
542          else
543             Tindex := Template (Sindex);
544             while Instantiation (Tindex) /= No_Location loop
545                Tindex := Template (Tindex);
546             end loop;
547
548             return S - Source_First (Sindex) + Source_First (Tindex);
549          end if;
550       end if;
551    end Original_Location;
552
553    -------------------------
554    -- Physical_To_Logical --
555    -------------------------
556
557    function Physical_To_Logical
558      (Line : Physical_Line_Number;
559       S    : Source_File_Index)
560       return Logical_Line_Number
561    is
562       SFR : Source_File_Record renames Source_File.Table (S);
563
564    begin
565       if SFR.Num_SRef_Pragmas = 0 then
566          return Logical_Line_Number (Line);
567       else
568          return SFR.Logical_Lines_Table (Line);
569       end if;
570    end Physical_To_Logical;
571
572    --------------------------------
573    -- Register_Source_Ref_Pragma --
574    --------------------------------
575
576    procedure Register_Source_Ref_Pragma
577      (File_Name          : File_Name_Type;
578       Stripped_File_Name : File_Name_Type;
579       Mapped_Line        : Nat;
580       Line_After_Pragma  : Physical_Line_Number)
581    is
582       subtype size_t is Memory.size_t;
583
584       SFR : Source_File_Record renames Source_File.Table (Current_Source_File);
585
586       ML : Logical_Line_Number;
587
588    begin
589       if File_Name /= No_File then
590          SFR.Reference_Name := Stripped_File_Name;
591          SFR.Full_Ref_Name  := File_Name;
592
593          if not Debug_Generated_Code then
594             SFR.Debug_Source_Name := Stripped_File_Name;
595             SFR.Full_Debug_Name   := File_Name;
596          end if;
597
598          SFR.Num_SRef_Pragmas := SFR.Num_SRef_Pragmas + 1;
599       end if;
600
601       if SFR.Num_SRef_Pragmas = 1 then
602          SFR.First_Mapped_Line := Logical_Line_Number (Mapped_Line);
603       end if;
604
605       if SFR.Logical_Lines_Table = null then
606          SFR.Logical_Lines_Table := To_Pointer
607            (Memory.Alloc
608              (size_t (SFR.Lines_Table_Max *
609                         Logical_Lines_Table_Type'Component_Size /
610                                                         Storage_Unit)));
611       end if;
612
613       SFR.Logical_Lines_Table (Line_After_Pragma - 1) := No_Line_Number;
614
615       ML := Logical_Line_Number (Mapped_Line);
616       for J in Line_After_Pragma .. SFR.Last_Source_Line loop
617          SFR.Logical_Lines_Table (J) := ML;
618          ML := ML + 1;
619       end loop;
620    end Register_Source_Ref_Pragma;
621
622    ---------------------------------
623    -- Set_Source_File_Index_Table --
624    ---------------------------------
625
626    procedure Set_Source_File_Index_Table (Xnew : Source_File_Index) is
627       Ind : Int;
628       SP  : Source_Ptr;
629       SL  : constant Source_Ptr := Source_File.Table (Xnew).Source_Last;
630
631    begin
632       SP  := (Source_File.Table (Xnew).Source_First + Chunk_Size - 1)
633                                                     / Chunk_Size * Chunk_Size;
634       Ind := Int (SP) / Chunk_Size;
635
636       while SP <= SL loop
637          Source_File_Index_Table (Ind) := Xnew;
638          SP := SP + Chunk_Size;
639          Ind := Ind + 1;
640       end loop;
641    end Set_Source_File_Index_Table;
642
643    ---------------------------
644    -- Skip_Line_Terminators --
645    ---------------------------
646
647    procedure Skip_Line_Terminators
648      (P        : in out Source_Ptr;
649       Physical : out Boolean)
650    is
651       Chr : constant Character := Source (P);
652
653    begin
654       if  Chr = CR then
655          if Source (P + 1) = LF then
656             P := P + 2;
657          else
658             P := P + 1;
659          end if;
660
661       elsif Chr = LF then
662          if Source (P) = CR then
663             P := P + 2;
664          else
665             P := P + 1;
666          end if;
667
668       elsif Chr = FF or else Chr = VT then
669          P := P + 1;
670          Physical := False;
671          return;
672
673          --  Otherwise we have a wide character
674
675       else
676          Skip_Wide (Source, P);
677       end if;
678
679       --  Fall through in the physical line terminator case. First deal with
680       --  making a possible entry into the lines table if one is needed.
681
682       --  Note: we are dealing with a real source file here, this cannot be
683       --  the instantiation case, so we need not worry about Sloc adjustment.
684
685       declare
686          S : Source_File_Record
687                renames Source_File.Table (Current_Source_File);
688
689       begin
690          Physical := True;
691
692          --  Make entry in lines table if not already made (in some scan backup
693          --  cases, we will be rescanning previously scanned source, so the
694          --  entry may have already been made on the previous forward scan).
695
696          if Source (P) /= EOF
697            and then P > S.Lines_Table (S.Last_Source_Line)
698          then
699             Add_Line_Tables_Entry (S, P);
700          end if;
701       end;
702    end Skip_Line_Terminators;
703
704    -------------------
705    -- Source_Offset --
706    -------------------
707
708    function Source_Offset (S : Source_Ptr) return Nat is
709       Sindex : constant Source_File_Index := Get_Source_File_Index (S);
710       Sfirst : constant Source_Ptr :=
711                  Source_File.Table (Sindex).Source_First;
712
713    begin
714       return Nat (S - Sfirst);
715    end Source_Offset;
716
717    ------------------------
718    -- Top_Level_Location --
719    ------------------------
720
721    function Top_Level_Location (S : Source_Ptr) return Source_Ptr is
722       Oldloc : Source_Ptr;
723       Newloc : Source_Ptr;
724
725    begin
726       Newloc := S;
727       loop
728          Oldloc := Newloc;
729          Newloc := Instantiation_Location (Oldloc);
730          exit when Newloc = No_Location;
731       end loop;
732
733       return Oldloc;
734    end Top_Level_Location;
735
736    ---------------
737    -- Tree_Read --
738    ---------------
739
740    procedure Tree_Read is
741    begin
742       --  First we must free any old source buffer pointers
743
744       if not First_Time_Around then
745          for J in Source_File.First .. Source_File.Last loop
746             declare
747                S : Source_File_Record renames Source_File.Table (J);
748
749                procedure Free_Ptr is new Unchecked_Deallocation
750                  (Big_Source_Buffer, Source_Buffer_Ptr);
751
752                pragma Warnings (Off);
753                --  This unchecked conversion is aliasing safe, since it is not
754                --  used to create improperly aliased pointer values.
755
756                function To_Source_Buffer_Ptr is new
757                  Unchecked_Conversion (Address, Source_Buffer_Ptr);
758
759                pragma Warnings (On);
760
761                Tmp1 : Source_Buffer_Ptr;
762
763             begin
764                if S.Instantiation /= No_Location then
765                   null;
766
767                else
768                   --  We have to recreate a proper pointer to the actual array
769                   --  from the zero origin pointer stored in the source table.
770
771                   Tmp1 :=
772                     To_Source_Buffer_Ptr
773                       (S.Source_Text (S.Source_First)'Address);
774                   Free_Ptr (Tmp1);
775
776                   --  Note: we are using free here, because we used malloc
777                   --  or realloc directly to allocate the tables. That is
778                   --  because we were playing the big array trick.
779
780                   if S.Lines_Table /= null then
781                      Memory.Free (To_Address (S.Lines_Table));
782                      S.Lines_Table := null;
783                   end if;
784
785                   if S.Logical_Lines_Table /= null then
786                      Memory.Free (To_Address (S.Logical_Lines_Table));
787                      S.Logical_Lines_Table := null;
788                   end if;
789                end if;
790             end;
791          end loop;
792       end if;
793
794       --  Reset source cache pointers to force new read
795
796       Source_Cache_First := 1;
797       Source_Cache_Last  := 0;
798
799       --  Read in source file table
800
801       Source_File.Tree_Read;
802
803       --  The pointers we read in there for the source buffer and lines
804       --  table pointers are junk. We now read in the actual data that
805       --  is referenced by these two fields.
806
807       for J in Source_File.First .. Source_File.Last loop
808          declare
809             S : Source_File_Record renames Source_File.Table (J);
810
811          begin
812             --  For the instantiation case, we do not read in any data. Instead
813             --  we share the data for the generic template entry. Since the
814             --  template always occurs first, we can safetly refer to its data.
815
816             if S.Instantiation /= No_Location then
817                declare
818                   ST : Source_File_Record renames
819                          Source_File.Table (S.Template);
820
821                begin
822                   --  The lines tables are copied from the template entry
823
824                   S.Lines_Table :=
825                     Source_File.Table (S.Template).Lines_Table;
826                   S.Logical_Lines_Table :=
827                     Source_File.Table (S.Template).Logical_Lines_Table;
828
829                   --  In the case of the source table pointer, we share the
830                   --  same data as the generic template, but the virtual origin
831                   --  is adjusted. For example, if the first subscript of the
832                   --  template is 100, and that of the instantiation is 200,
833                   --  then the instantiation pointer is obtained by subtracting
834                   --  100 from the template pointer.
835
836                   declare
837                      pragma Suppress (All_Checks);
838
839                      pragma Warnings (Off);
840                      --  This unchecked conversion is aliasing safe since it
841                      --  not used to create improperly aliased pointer values.
842
843                      function To_Source_Buffer_Ptr is new
844                        Unchecked_Conversion (Address, Source_Buffer_Ptr);
845
846                      pragma Warnings (On);
847
848                   begin
849                      S.Source_Text :=
850                        To_Source_Buffer_Ptr
851                           (ST.Source_Text
852                             (ST.Source_First - S.Source_First)'Address);
853                   end;
854                end;
855
856             --  Normal case (non-instantiation)
857
858             else
859                First_Time_Around := False;
860                S.Lines_Table := null;
861                S.Logical_Lines_Table := null;
862                Alloc_Line_Tables (S, Int (S.Last_Source_Line));
863
864                for J in 1 .. S.Last_Source_Line loop
865                   Tree_Read_Int (Int (S.Lines_Table (J)));
866                end loop;
867
868                if S.Num_SRef_Pragmas /= 0 then
869                   for J in 1 .. S.Last_Source_Line loop
870                      Tree_Read_Int (Int (S.Logical_Lines_Table (J)));
871                   end loop;
872                end if;
873
874                --  Allocate source buffer and read in the data and then set the
875                --  virtual origin to point to the logical zero'th element. This
876                --  address must be computed with subscript checks turned off.
877
878                declare
879                   subtype B is Text_Buffer (S.Source_First .. S.Source_Last);
880                   type Text_Buffer_Ptr is access B;
881                   T : Text_Buffer_Ptr;
882
883                   pragma Suppress (All_Checks);
884
885                   pragma Warnings (Off);
886                   --  This unchecked conversion is aliasing safe, since it is
887                   --  never used to create improperly aliased pointer values.
888
889                   function To_Source_Buffer_Ptr is new
890                     Unchecked_Conversion (Address, Source_Buffer_Ptr);
891
892                   pragma Warnings (On);
893
894                begin
895                   T := new B;
896
897                   Tree_Read_Data (T (S.Source_First)'Address,
898                      Int (S.Source_Last) - Int (S.Source_First) + 1);
899
900                   S.Source_Text := To_Source_Buffer_Ptr (T (0)'Address);
901                end;
902             end if;
903          end;
904
905          Set_Source_File_Index_Table (J);
906       end loop;
907    end Tree_Read;
908
909    ----------------
910    -- Tree_Write --
911    ----------------
912
913    procedure Tree_Write is
914    begin
915       Source_File.Tree_Write;
916
917       --  The pointers we wrote out there for the source buffer and lines
918       --  table pointers are junk, we now write out the actual data that
919       --  is referenced by these two fields.
920
921       for J in Source_File.First .. Source_File.Last loop
922          declare
923             S : Source_File_Record renames Source_File.Table (J);
924
925          begin
926             --  For instantiations, there is nothing to do, since the data is
927             --  shared with the generic template. When the tree is read, the
928             --  pointers must be set, but no extra data needs to be written.
929
930             if S.Instantiation /= No_Location then
931                null;
932
933             --  For the normal case, write out the data of the tables
934
935             else
936                --  Lines table
937
938                for J in 1 .. S.Last_Source_Line loop
939                   Tree_Write_Int (Int (S.Lines_Table (J)));
940                end loop;
941
942                --  Logical lines table if present
943
944                if S.Num_SRef_Pragmas /= 0 then
945                   for J in 1 .. S.Last_Source_Line loop
946                      Tree_Write_Int (Int (S.Logical_Lines_Table (J)));
947                   end loop;
948                end if;
949
950                --  Source buffer
951
952                Tree_Write_Data
953                  (S.Source_Text (S.Source_First)'Address,
954                    Int (S.Source_Last) - Int (S.Source_First) + 1);
955             end if;
956          end;
957       end loop;
958    end Tree_Write;
959
960    --------------------
961    -- Write_Location --
962    --------------------
963
964    procedure Write_Location (P : Source_Ptr) is
965    begin
966       if P = No_Location then
967          Write_Str ("<no location>");
968
969       elsif P <= Standard_Location then
970          Write_Str ("<standard location>");
971
972       else
973          declare
974             SI : constant Source_File_Index := Get_Source_File_Index (P);
975
976          begin
977             Write_Name (Debug_Source_Name (SI));
978             Write_Char (':');
979             Write_Int (Int (Get_Logical_Line_Number (P)));
980             Write_Char (':');
981             Write_Int (Int (Get_Column_Number (P)));
982
983             if Instantiation (SI) /= No_Location then
984                Write_Str (" [");
985                Write_Location (Instantiation (SI));
986                Write_Char (']');
987             end if;
988          end;
989       end if;
990    end Write_Location;
991
992    ----------------------
993    -- Write_Time_Stamp --
994    ----------------------
995
996    procedure Write_Time_Stamp (S : Source_File_Index) is
997       T : constant Time_Stamp_Type := Time_Stamp (S);
998       P : Natural;
999
1000    begin
1001       if T (1) = '9' then
1002          Write_Str ("19");
1003          P := 0;
1004       else
1005          Write_Char (T (1));
1006          Write_Char (T (2));
1007          P := 2;
1008       end if;
1009
1010       Write_Char (T (P + 1));
1011       Write_Char (T (P + 2));
1012       Write_Char ('-');
1013
1014       Write_Char (T (P + 3));
1015       Write_Char (T (P + 4));
1016       Write_Char ('-');
1017
1018       Write_Char (T (P + 5));
1019       Write_Char (T (P + 6));
1020       Write_Char (' ');
1021
1022       Write_Char (T (P + 7));
1023       Write_Char (T (P + 8));
1024       Write_Char (':');
1025
1026       Write_Char (T (P + 9));
1027       Write_Char (T (P + 10));
1028       Write_Char (':');
1029
1030       Write_Char (T (P + 11));
1031       Write_Char (T (P + 12));
1032    end Write_Time_Stamp;
1033
1034    ----------------------------------------------
1035    -- Access Subprograms for Source File Table --
1036    ----------------------------------------------
1037
1038    function Debug_Source_Name (S : SFI) return File_Name_Type is
1039    begin
1040       return Source_File.Table (S).Debug_Source_Name;
1041    end Debug_Source_Name;
1042
1043    function File_Name (S : SFI) return File_Name_Type is
1044    begin
1045       return Source_File.Table (S).File_Name;
1046    end File_Name;
1047
1048    function File_Type (S : SFI) return Type_Of_File is
1049    begin
1050       return Source_File.Table (S).File_Type;
1051    end File_Type;
1052
1053    function First_Mapped_Line (S : SFI) return Logical_Line_Number is
1054    begin
1055       return Source_File.Table (S).First_Mapped_Line;
1056    end First_Mapped_Line;
1057
1058    function Full_Debug_Name (S : SFI) return File_Name_Type is
1059    begin
1060       return Source_File.Table (S).Full_Debug_Name;
1061    end Full_Debug_Name;
1062
1063    function Full_File_Name (S : SFI) return File_Name_Type is
1064    begin
1065       return Source_File.Table (S).Full_File_Name;
1066    end Full_File_Name;
1067
1068    function Full_Ref_Name (S : SFI) return File_Name_Type is
1069    begin
1070       return Source_File.Table (S).Full_Ref_Name;
1071    end Full_Ref_Name;
1072
1073    function Identifier_Casing (S : SFI) return Casing_Type is
1074    begin
1075       return Source_File.Table (S).Identifier_Casing;
1076    end Identifier_Casing;
1077
1078    function Inlined_Body (S : SFI) return Boolean is
1079    begin
1080       return Source_File.Table (S).Inlined_Body;
1081    end Inlined_Body;
1082
1083    function Instantiation (S : SFI) return Source_Ptr is
1084    begin
1085       return Source_File.Table (S).Instantiation;
1086    end Instantiation;
1087
1088    function Keyword_Casing (S : SFI) return Casing_Type is
1089    begin
1090       return Source_File.Table (S).Keyword_Casing;
1091    end Keyword_Casing;
1092
1093    function Last_Source_Line (S : SFI) return Physical_Line_Number is
1094    begin
1095       return Source_File.Table (S).Last_Source_Line;
1096    end Last_Source_Line;
1097
1098    function License (S : SFI) return License_Type is
1099    begin
1100       return Source_File.Table (S).License;
1101    end License;
1102
1103    function Num_SRef_Pragmas (S : SFI) return Nat is
1104    begin
1105       return Source_File.Table (S).Num_SRef_Pragmas;
1106    end Num_SRef_Pragmas;
1107
1108    function Reference_Name (S : SFI) return File_Name_Type is
1109    begin
1110       return Source_File.Table (S).Reference_Name;
1111    end Reference_Name;
1112
1113    function Source_Checksum (S : SFI) return Word is
1114    begin
1115       return Source_File.Table (S).Source_Checksum;
1116    end Source_Checksum;
1117
1118    function Source_First (S : SFI) return Source_Ptr is
1119    begin
1120       if S = Internal_Source_File then
1121          return Internal_Source'First;
1122       else
1123          return Source_File.Table (S).Source_First;
1124       end if;
1125    end Source_First;
1126
1127    function Source_Last (S : SFI) return Source_Ptr is
1128    begin
1129       if S = Internal_Source_File then
1130          return Internal_Source'Last;
1131       else
1132          return Source_File.Table (S).Source_Last;
1133       end if;
1134
1135    end Source_Last;
1136
1137    function Source_Text (S : SFI) return Source_Buffer_Ptr is
1138    begin
1139       if S = Internal_Source_File then
1140          return Internal_Source_Ptr;
1141       else
1142          return Source_File.Table (S).Source_Text;
1143       end if;
1144
1145    end Source_Text;
1146
1147    function Template (S : SFI) return SFI is
1148    begin
1149       return Source_File.Table (S).Template;
1150    end Template;
1151
1152    function Time_Stamp (S : SFI) return Time_Stamp_Type is
1153    begin
1154       return Source_File.Table (S).Time_Stamp;
1155    end Time_Stamp;
1156
1157    function Unit (S : SFI) return Unit_Number_Type is
1158    begin
1159       return Source_File.Table (S).Unit;
1160    end Unit;
1161
1162    ------------------------------------------
1163    -- Set Procedures for Source File Table --
1164    ------------------------------------------
1165
1166    procedure Set_Identifier_Casing (S : SFI; C : Casing_Type) is
1167    begin
1168       Source_File.Table (S).Identifier_Casing := C;
1169    end Set_Identifier_Casing;
1170
1171    procedure Set_Keyword_Casing (S : SFI; C : Casing_Type) is
1172    begin
1173       Source_File.Table (S).Keyword_Casing := C;
1174    end Set_Keyword_Casing;
1175
1176    procedure Set_License (S : SFI; L : License_Type) is
1177    begin
1178       Source_File.Table (S).License := L;
1179    end Set_License;
1180
1181    procedure Set_Unit (S : SFI; U : Unit_Number_Type) is
1182    begin
1183       Source_File.Table (S).Unit := U;
1184    end Set_Unit;
1185
1186    ----------------------
1187    -- Trim_Lines_Table --
1188    ----------------------
1189
1190    procedure Trim_Lines_Table (S : Source_File_Index) is
1191       Max : constant Nat := Nat (Source_File.Table (S).Last_Source_Line);
1192
1193    begin
1194       --  Release allocated storage that is no longer needed
1195
1196       Source_File.Table (S).Lines_Table := To_Pointer
1197         (Memory.Realloc
1198           (To_Address (Source_File.Table (S).Lines_Table),
1199            Memory.size_t
1200             (Max * (Lines_Table_Type'Component_Size / System.Storage_Unit))));
1201       Source_File.Table (S).Lines_Table_Max := Physical_Line_Number (Max);
1202    end Trim_Lines_Table;
1203
1204    ------------
1205    -- Unlock --
1206    ------------
1207
1208    procedure Unlock is
1209    begin
1210       Source_File.Locked := False;
1211       Source_File.Release;
1212    end Unlock;
1213
1214    --------
1215    -- wl --
1216    --------
1217
1218    procedure wl (P : Source_Ptr) is
1219    begin
1220       Write_Location (P);
1221       Write_Eol;
1222    end wl;
1223
1224 end Sinput;