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-2021, 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
26pragma Style_Checks (All_Checks);
27--  Subprograms not all in alpha order
28
29with Atree;          use Atree;
30with Debug;          use Debug;
31with Opt;            use Opt;
32with Output;         use Output;
33with Scans;          use Scans;
34with Sinfo;          use Sinfo;
35with Sinfo.Nodes;    use Sinfo.Nodes;
36with Widechar;       use Widechar;
37
38with GNAT.Byte_Order_Mark; use GNAT.Byte_Order_Mark;
39
40with System.Storage_Elements;
41with System.Memory;
42with System.WCh_Con; use System.WCh_Con;
43
44with Unchecked_Conversion;
45with Unchecked_Deallocation;
46
47package body Sinput is
48
49   use ASCII, System;
50
51   --  Routines to support conversion between types Lines_Table_Ptr,
52   --  Logical_Lines_Table_Ptr and System.Address.
53
54   pragma Warnings (Off);
55   --  These unchecked conversions are aliasing safe, since they are never
56   --  used to construct improperly aliased pointer values.
57
58   function To_Address is
59     new Unchecked_Conversion (Lines_Table_Ptr, Address);
60
61   function To_Address is
62     new Unchecked_Conversion (Logical_Lines_Table_Ptr, Address);
63
64   function To_Pointer is
65     new Unchecked_Conversion (Address, Lines_Table_Ptr);
66
67   function To_Pointer is
68     new Unchecked_Conversion (Address, Logical_Lines_Table_Ptr);
69
70   pragma Warnings (On);
71
72   -----------------------------
73   -- Source_File_Index_Table --
74   -----------------------------
75
76   --  The Get_Source_File_Index function is called very frequently. Earlier
77   --  versions cached a single entry, but then reverted to a serial search,
78   --  and this proved to be a significant source of inefficiency. We then
79   --  switched to using a table with a start point followed by a serial
80   --  search. Now we make sure source buffers are on a reasonable boundary
81   --  (see Types.Source_Align), and we can just use a direct look up in the
82   --  following table.
83
84   --  Note that this array is pretty large, but in most operating systems
85   --  it will not be allocated in physical memory unless it is actually used.
86
87   Source_File_Index_Table :
88     array (Int range 0 .. 1 + (Int'Last / Source_Align)) of Source_File_Index;
89
90   ---------------------------
91   -- Add_Line_Tables_Entry --
92   ---------------------------
93
94   procedure Add_Line_Tables_Entry
95     (S : in out Source_File_Record;
96      P : Source_Ptr)
97   is
98      LL : Physical_Line_Number;
99
100   begin
101      --  Reallocate the lines tables if necessary
102
103      --  Note: the reason we do not use the normal Table package
104      --  mechanism is that we have several of these tables. We could
105      --  use the new GNAT.Dynamic_Tables package and that would probably
106      --  be a good idea ???
107
108      if S.Last_Source_Line = S.Lines_Table_Max then
109         Alloc_Line_Tables
110           (S,
111            Int (S.Last_Source_Line) *
112              ((100 + Alloc.Lines_Increment) / 100));
113
114         if Debug_Flag_D then
115            Write_Str ("--> Reallocating lines table, size = ");
116            Write_Int (Int (S.Lines_Table_Max));
117            Write_Eol;
118         end if;
119      end if;
120
121      S.Last_Source_Line := S.Last_Source_Line + 1;
122      LL := S.Last_Source_Line;
123
124      S.Lines_Table (LL) := P;
125
126      --  Deal with setting new entry in logical lines table if one is
127      --  present. Note that there is always space (because the call to
128      --  Alloc_Line_Tables makes sure both tables are the same length),
129
130      if S.Logical_Lines_Table /= null then
131
132         --  We can always set the entry from the previous one, because
133         --  the processing for a Source_Reference pragma ensures that
134         --  at least one entry following the pragma is set up correctly.
135
136         S.Logical_Lines_Table (LL) := S.Logical_Lines_Table (LL - 1) + 1;
137      end if;
138   end Add_Line_Tables_Entry;
139
140   -----------------------
141   -- Alloc_Line_Tables --
142   -----------------------
143
144   procedure Alloc_Line_Tables
145     (S       : in out Source_File_Record;
146      New_Max : Nat)
147   is
148      subtype size_t is Memory.size_t;
149
150      New_Table : Lines_Table_Ptr;
151
152      New_Logical_Table : Logical_Lines_Table_Ptr;
153
154      New_Size : constant size_t :=
155                   size_t (New_Max * Lines_Table_Type'Component_Size /
156                                                             Storage_Unit);
157
158   begin
159      if S.Lines_Table = null then
160         New_Table := To_Pointer (Memory.Alloc (New_Size));
161
162      else
163         New_Table :=
164           To_Pointer (Memory.Realloc (To_Address (S.Lines_Table), New_Size));
165      end if;
166
167      if New_Table = null then
168         raise Storage_Error;
169      else
170         S.Lines_Table     := New_Table;
171         S.Lines_Table_Max := Physical_Line_Number (New_Max);
172      end if;
173
174      if S.Num_SRef_Pragmas /= 0 then
175         if S.Logical_Lines_Table = null then
176            New_Logical_Table := To_Pointer (Memory.Alloc (New_Size));
177         else
178            New_Logical_Table := To_Pointer
179              (Memory.Realloc (To_Address (S.Logical_Lines_Table), New_Size));
180         end if;
181
182         if New_Logical_Table = null then
183            raise Storage_Error;
184         else
185            S.Logical_Lines_Table := New_Logical_Table;
186         end if;
187      end if;
188   end Alloc_Line_Tables;
189
190   -----------------
191   -- Backup_Line --
192   -----------------
193
194   procedure Backup_Line (P : in out Source_Ptr) is
195      Sindex : constant Source_File_Index := Get_Source_File_Index (P);
196      Src    : constant Source_Buffer_Ptr :=
197                 Source_File.Table (Sindex).Source_Text;
198      Sfirst : constant Source_Ptr :=
199                 Source_File.Table (Sindex).Source_First;
200
201   begin
202      P := P - 1;
203
204      if P = Sfirst then
205         return;
206      end if;
207
208      if Src (P) = CR then
209         if Src (P - 1) = LF then
210            P := P - 1;
211         end if;
212
213      else -- Src (P) = LF
214         if Src (P - 1) = CR then
215            P := P - 1;
216         end if;
217      end if;
218
219      --  Now find first character of the previous line
220
221      while P > Sfirst
222        and then Src (P - 1) /= LF
223        and then Src (P - 1) /= CR
224      loop
225         P := P - 1;
226      end loop;
227   end Backup_Line;
228
229   ---------------------------
230   -- Build_Location_String --
231   ---------------------------
232
233   procedure Build_Location_String
234     (Buf : in out Bounded_String;
235      Loc : Source_Ptr)
236   is
237      Ptr : Source_Ptr := Loc;
238
239   begin
240      --  Loop through instantiations
241
242      loop
243         Append (Buf, Reference_Name (Get_Source_File_Index (Ptr)));
244         Append (Buf, ':');
245         Append (Buf, Nat (Get_Logical_Line_Number (Ptr)));
246
247         Ptr := Instantiation_Location (Ptr);
248         exit when Ptr = No_Location;
249         Append (Buf, " instantiated at ");
250      end loop;
251   end Build_Location_String;
252
253   function Build_Location_String (Loc : Source_Ptr) return String is
254      Buf : Bounded_String;
255   begin
256      Build_Location_String (Buf, Loc);
257      return +Buf;
258   end Build_Location_String;
259
260   -------------------
261   -- Check_For_BOM --
262   -------------------
263
264   procedure Check_For_BOM is
265      BOM : BOM_Kind;
266      Len : Natural;
267      Tst : String (1 .. 5);
268      C   : Character;
269
270   begin
271      for J in 1 .. 5 loop
272         C := Source (Scan_Ptr + Source_Ptr (J) - 1);
273
274         --  Definitely no BOM if EOF character marks either end of file, or
275         --  an illegal non-BOM character if not at the end of file.
276
277         if C = EOF then
278            return;
279         end if;
280
281         Tst (J) := C;
282      end loop;
283
284      Read_BOM (Tst, Len, BOM, XML_Support => False);
285
286      case BOM is
287         when UTF8_All =>
288            Scan_Ptr := Scan_Ptr + Source_Ptr (Len);
289            First_Non_Blank_Location := Scan_Ptr;
290            Current_Line_Start := Scan_Ptr;
291            Wide_Character_Encoding_Method := WCEM_UTF8;
292            Upper_Half_Encoding := True;
293
294         when UTF16_BE
295            | UTF16_LE
296         =>
297            Set_Standard_Error;
298            Write_Line ("UTF-16 encoding format not recognized");
299            Set_Standard_Output;
300            raise Unrecoverable_Error;
301
302         when UTF32_BE
303            | UTF32_LE
304         =>
305            Set_Standard_Error;
306            Write_Line ("UTF-32 encoding format not recognized");
307            Set_Standard_Output;
308            raise Unrecoverable_Error;
309
310         when Unknown =>
311            null;
312
313         when others =>
314            raise Program_Error;
315      end case;
316   end Check_For_BOM;
317
318   -----------------------------
319   -- Clear_Source_File_Table --
320   -----------------------------
321
322   procedure Free is new Unchecked_Deallocation
323     (Lines_Table_Type, Lines_Table_Ptr);
324
325   procedure Free is new Unchecked_Deallocation
326     (Logical_Lines_Table_Type, Logical_Lines_Table_Ptr);
327
328   procedure Clear_Source_File_Table is
329   begin
330      for X in 1 .. Source_File.Last loop
331         declare
332            S  : Source_File_Record renames Source_File.Table (X);
333         begin
334            if S.Instance = No_Instance_Id then
335               Free_Source_Buffer (S.Source_Text);
336            else
337               Free_Dope (S.Source_Text'Address);
338               S.Source_Text := null;
339            end if;
340
341            Free (S.Lines_Table);
342            Free (S.Logical_Lines_Table);
343         end;
344      end loop;
345
346      Source_File.Free;
347      Sinput.Initialize;
348   end Clear_Source_File_Table;
349
350   ---------------------------------
351   -- Comes_From_Inherited_Pragma --
352   ---------------------------------
353
354   function Comes_From_Inherited_Pragma (S : Source_Ptr) return Boolean is
355      SIE : Source_File_Record renames
356              Source_File.Table (Get_Source_File_Index (S));
357   begin
358      return SIE.Inherited_Pragma;
359   end Comes_From_Inherited_Pragma;
360
361   -----------------------------
362   -- Comes_From_Inlined_Body --
363   -----------------------------
364
365   function Comes_From_Inlined_Body (S : Source_Ptr) return Boolean is
366      SIE : Source_File_Record renames
367              Source_File.Table (Get_Source_File_Index (S));
368   begin
369      return SIE.Inlined_Body;
370   end Comes_From_Inlined_Body;
371
372   ------------------------
373   -- Free_Source_Buffer --
374   ------------------------
375
376   procedure Free_Source_Buffer (Src : in out Source_Buffer_Ptr) is
377      --  Unchecked_Deallocation doesn't work for access-to-constant; we need
378      --  to first Unchecked_Convert to access-to-variable.
379
380      function To_Source_Buffer_Ptr_Var is new
381        Unchecked_Conversion (Source_Buffer_Ptr, Source_Buffer_Ptr_Var);
382
383      Temp : Source_Buffer_Ptr_Var := To_Source_Buffer_Ptr_Var (Src);
384
385      procedure Free_Ptr is new
386        Unchecked_Deallocation (Source_Buffer, Source_Buffer_Ptr_Var);
387   begin
388      Free_Ptr (Temp);
389      Src := null;
390   end Free_Source_Buffer;
391
392   -----------------------
393   -- Get_Column_Number --
394   -----------------------
395
396   function Get_Column_Number (P : Source_Ptr) return Column_Number is
397      S      : Source_Ptr;
398      C      : Column_Number;
399      Sindex : Source_File_Index;
400      Src    : Source_Buffer_Ptr;
401
402   begin
403      --  If the input source pointer is not a meaningful value then return
404      --  at once with column number 1. This can happen for a file not found
405      --  condition for a file loaded indirectly by RTE, and also perhaps on
406      --  some unknown internal error conditions. In either case we certainly
407      --  don't want to blow up.
408
409      if P < 1 then
410         return 1;
411
412      else
413         Sindex := Get_Source_File_Index (P);
414         Src := Source_File.Table (Sindex).Source_Text;
415         S := Line_Start (P);
416         C := 1;
417
418         while S < P loop
419            if Src (S) = HT then
420               C := (C - 1) / 8 * 8 + (8 + 1);
421               S := S + 1;
422
423            --  Deal with wide character case, but don't include brackets
424            --  notation in this circuit, since we know that this will
425            --  display unencoded (no one encodes brackets notation).
426
427            elsif Src (S) /= '[' and then Is_Start_Of_Wide_Char (Src, S) then
428               C := C + 1;
429               Skip_Wide (Src, S);
430
431            --  Normal (non-wide) character case or brackets sequence
432
433            else
434               C := C + 1;
435               S := S + 1;
436            end if;
437         end loop;
438
439         return C;
440      end if;
441   end Get_Column_Number;
442
443   -----------------------------
444   -- Get_Logical_Line_Number --
445   -----------------------------
446
447   function Get_Logical_Line_Number
448     (P : Source_Ptr) return Logical_Line_Number
449   is
450      SFR : Source_File_Record
451              renames Source_File.Table (Get_Source_File_Index (P));
452
453      L : constant Physical_Line_Number := Get_Physical_Line_Number (P);
454
455   begin
456      if SFR.Num_SRef_Pragmas = 0 then
457         return Logical_Line_Number (L);
458      else
459         return SFR.Logical_Lines_Table (L);
460      end if;
461   end Get_Logical_Line_Number;
462
463   ---------------------------------
464   -- Get_Logical_Line_Number_Img --
465   ---------------------------------
466
467   function Get_Logical_Line_Number_Img
468     (P : Source_Ptr) return String
469   is
470   begin
471      Name_Len := 0;
472      Add_Nat_To_Name_Buffer (Nat (Get_Logical_Line_Number (P)));
473      return Name_Buffer (1 .. Name_Len);
474   end Get_Logical_Line_Number_Img;
475
476   ------------------------------
477   -- Get_Physical_Line_Number --
478   ------------------------------
479
480   function Get_Physical_Line_Number
481     (P : Source_Ptr) return Physical_Line_Number
482   is
483      Sfile : Source_File_Index;
484      Table : Lines_Table_Ptr;
485      Lo    : Physical_Line_Number;
486      Hi    : Physical_Line_Number;
487      Mid   : Physical_Line_Number;
488      Loc   : Source_Ptr;
489
490   begin
491      --  If the input source pointer is not a meaningful value then return
492      --  at once with line number 1. This can happen for a file not found
493      --  condition for a file loaded indirectly by RTE, and also perhaps on
494      --  some unknown internal error conditions. In either case we certainly
495      --  don't want to blow up.
496
497      if P < 1 then
498         return 1;
499
500      --  Otherwise we can do the binary search
501
502      else
503         Sfile := Get_Source_File_Index (P);
504         Loc   := P + Source_File.Table (Sfile).Sloc_Adjust;
505         Table := Source_File.Table (Sfile).Lines_Table;
506         Lo    := 1;
507         Hi    := Source_File.Table (Sfile).Last_Source_Line;
508
509         loop
510            Mid := (Lo + Hi) / 2;
511
512            if Loc < Table (Mid) then
513               Hi := Mid - 1;
514
515            else -- Loc >= Table (Mid)
516
517               if Mid = Hi or else
518                  Loc < Table (Mid + 1)
519               then
520                  return Mid;
521               else
522                  Lo := Mid + 1;
523               end if;
524
525            end if;
526
527         end loop;
528      end if;
529   end Get_Physical_Line_Number;
530
531   ---------------------------
532   -- Get_Source_File_Index --
533   ---------------------------
534
535   function Get_Source_File_Index (S : Source_Ptr) return Source_File_Index is
536      Result : Source_File_Index;
537
538      procedure Assertions;
539      --  Assert various properties of the result
540
541      procedure Assertions is
542
543         --  ???The old version using zero-origin array indexing without array
544         --  bounds checks returned 1 (i.e. system.ads) for these special
545         --  locations, presumably by accident. We are mimicing that here.
546
547         Special : constant Boolean :=
548                     S = No_Location
549                       or else S = Standard_Location
550                       or else S = Standard_ASCII_Location
551                       or else S = System_Location;
552
553         pragma Assert ((S > No_Location) xor Special);
554         pragma Assert (Result in Source_File.First .. Source_File.Last);
555
556         SFR : Source_File_Record renames Source_File.Table (Result);
557
558      begin
559         --  SFR.Source_Text = null if and only if this is the SFR for a debug
560         --  output file (*.dg), and that file is under construction. S can be
561         --  slightly past Source_Last in that case because we haven't updated
562         --  Source_Last.
563
564         if Null_Source_Buffer_Ptr (SFR.Source_Text) then
565            pragma Assert (S >= SFR.Source_First); null;
566         else
567            pragma Assert (SFR.Source_Text'First = SFR.Source_First);
568            pragma Assert (SFR.Source_Text'Last = SFR.Source_Last);
569
570            if not Special then
571               pragma Assert (S in SFR.Source_First .. SFR.Source_Last);
572               null;
573            end if;
574         end if;
575      end Assertions;
576
577   --  Start of processing for Get_Source_File_Index
578
579   begin
580      if S > No_Location then
581         Result := Source_File_Index_Table (Int (S) / Source_Align);
582      else
583         Result := 1;
584      end if;
585
586      pragma Debug (Assertions);
587
588      return Result;
589   end Get_Source_File_Index;
590
591   ----------------
592   -- Initialize --
593   ----------------
594
595   procedure Initialize is
596   begin
597      Source_gnat_adc := No_Source_File;
598      Source_File.Init;
599      Instances.Init;
600      Instances.Append (No_Location);
601      pragma Assert (Instances.Last = No_Instance_Id);
602   end Initialize;
603
604   -------------------
605   -- Instantiation --
606   -------------------
607
608   function Instantiation (S : SFI) return Source_Ptr is
609      SIE : Source_File_Record renames Source_File.Table (S);
610   begin
611      if SIE.Inlined_Body or SIE.Inherited_Pragma then
612         return SIE.Inlined_Call;
613      else
614         return Instances.Table (SIE.Instance);
615      end if;
616   end Instantiation;
617
618   -------------------------
619   -- Instantiation_Depth --
620   -------------------------
621
622   function Instantiation_Depth (S : Source_Ptr) return Nat is
623      Sind  : Source_File_Index;
624      Sval  : Source_Ptr;
625      Depth : Nat;
626
627   begin
628      Sval := S;
629      Depth := 0;
630
631      loop
632         Sind := Get_Source_File_Index (Sval);
633         Sval := Instantiation (Sind);
634         exit when Sval = No_Location;
635         Depth := Depth + 1;
636      end loop;
637
638      return Depth;
639   end Instantiation_Depth;
640
641   ----------------------------
642   -- Instantiation_Location --
643   ----------------------------
644
645   function Instantiation_Location (S : Source_Ptr) return Source_Ptr is
646   begin
647      return Instantiation (Get_Source_File_Index (S));
648   end Instantiation_Location;
649
650   --------------------------
651   -- Iterate_On_Instances --
652   --------------------------
653
654   procedure Iterate_On_Instances is
655   begin
656      for J in 1 .. Instances.Last loop
657         Process (J, Instances.Table (J));
658      end loop;
659   end Iterate_On_Instances;
660
661   ----------------------
662   -- Last_Source_File --
663   ----------------------
664
665   function Last_Source_File return Source_File_Index is
666   begin
667      return Source_File.Last;
668   end Last_Source_File;
669
670   ----------------
671   -- Line_Start --
672   ----------------
673
674   function Line_Start (P : Source_Ptr) return Source_Ptr is
675      Sindex : constant Source_File_Index := Get_Source_File_Index (P);
676      Src    : constant Source_Buffer_Ptr :=
677                 Source_File.Table (Sindex).Source_Text;
678      Sfirst : constant Source_Ptr :=
679                 Source_File.Table (Sindex).Source_First;
680      S      : Source_Ptr;
681
682   begin
683      S := P;
684      while S > Sfirst
685        and then Src (S - 1) /= CR
686        and then Src (S - 1) /= LF
687      loop
688         S := S - 1;
689      end loop;
690
691      return S;
692   end Line_Start;
693
694   function Line_Start
695     (L : Physical_Line_Number;
696      S : Source_File_Index) return Source_Ptr
697   is
698   begin
699      return Source_File.Table (S).Lines_Table (L);
700   end Line_Start;
701
702   ----------
703   -- Lock --
704   ----------
705
706   procedure Lock is
707   begin
708      Source_File.Release;
709      Source_File.Locked := True;
710   end Lock;
711
712   ----------------------
713   -- Num_Source_Files --
714   ----------------------
715
716   function Num_Source_Files return Nat is
717   begin
718      return Int (Source_File.Last) - Int (Source_File.First) + 1;
719   end Num_Source_Files;
720
721   ----------------------
722   -- Num_Source_Lines --
723   ----------------------
724
725   function Num_Source_Lines (S : Source_File_Index) return Nat is
726   begin
727      return Nat (Source_File.Table (S).Last_Source_Line);
728   end Num_Source_Lines;
729
730   -----------------------
731   -- Original_Location --
732   -----------------------
733
734   function Original_Location (S : Source_Ptr) return Source_Ptr is
735      Sindex : Source_File_Index;
736      Tindex : Source_File_Index;
737
738   begin
739      if S <= No_Location then
740         return S;
741
742      else
743         Sindex := Get_Source_File_Index (S);
744
745         if Instantiation (Sindex) = No_Location then
746            return S;
747
748         else
749            Tindex := Template (Sindex);
750            while Instantiation (Tindex) /= No_Location loop
751               Tindex := Template (Tindex);
752            end loop;
753
754            return S - Source_First (Sindex) + Source_First (Tindex);
755         end if;
756      end if;
757   end Original_Location;
758
759   -------------------------
760   -- Physical_To_Logical --
761   -------------------------
762
763   function Physical_To_Logical
764     (Line : Physical_Line_Number;
765      S    : Source_File_Index) return Logical_Line_Number
766   is
767      SFR : Source_File_Record renames Source_File.Table (S);
768
769   begin
770      if SFR.Num_SRef_Pragmas = 0 then
771         return Logical_Line_Number (Line);
772      else
773         return SFR.Logical_Lines_Table (Line);
774      end if;
775   end Physical_To_Logical;
776
777   --------------------------------
778   -- Register_Source_Ref_Pragma --
779   --------------------------------
780
781   procedure Register_Source_Ref_Pragma
782     (File_Name          : File_Name_Type;
783      Stripped_File_Name : File_Name_Type;
784      Mapped_Line        : Nat;
785      Line_After_Pragma  : Physical_Line_Number)
786   is
787      subtype size_t is Memory.size_t;
788
789      SFR : Source_File_Record renames Source_File.Table (Current_Source_File);
790
791      ML : Logical_Line_Number;
792
793   begin
794      if File_Name /= No_File then
795         SFR.Reference_Name := Stripped_File_Name;
796         SFR.Full_Ref_Name  := File_Name;
797
798         if not Debug_Generated_Code then
799            SFR.Debug_Source_Name := Stripped_File_Name;
800            SFR.Full_Debug_Name   := File_Name;
801         end if;
802
803         SFR.Num_SRef_Pragmas := SFR.Num_SRef_Pragmas + 1;
804      end if;
805
806      if SFR.Num_SRef_Pragmas = 1 then
807         SFR.First_Mapped_Line := Logical_Line_Number (Mapped_Line);
808      end if;
809
810      if SFR.Logical_Lines_Table = null then
811         SFR.Logical_Lines_Table := To_Pointer
812           (Memory.Alloc
813             (size_t (SFR.Lines_Table_Max *
814                        Logical_Lines_Table_Type'Component_Size /
815                                                        Storage_Unit)));
816      end if;
817
818      SFR.Logical_Lines_Table (Line_After_Pragma - 1) := No_Line_Number;
819
820      ML := Logical_Line_Number (Mapped_Line);
821      for J in Line_After_Pragma .. SFR.Last_Source_Line loop
822         SFR.Logical_Lines_Table (J) := ML;
823         ML := ML + 1;
824      end loop;
825   end Register_Source_Ref_Pragma;
826
827   ---------------------------------
828   -- Set_Source_File_Index_Table --
829   ---------------------------------
830
831   procedure Set_Source_File_Index_Table (Xnew : Source_File_Index) is
832      Ind : Int;
833      SP  : Source_Ptr;
834      SL  : constant Source_Ptr := Source_File.Table (Xnew).Source_Last;
835   begin
836      SP  := Source_File.Table (Xnew).Source_First;
837      pragma Assert (SP mod Source_Align = 0);
838      Ind := Int (SP) / Source_Align;
839      while SP <= SL loop
840         Source_File_Index_Table (Ind) := Xnew;
841         SP := SP + Source_Align;
842         Ind := Ind + 1;
843      end loop;
844   end Set_Source_File_Index_Table;
845
846   ---------------------------
847   -- Skip_Line_Terminators --
848   ---------------------------
849
850   procedure Skip_Line_Terminators
851     (P        : in out Source_Ptr;
852      Physical : out Boolean)
853   is
854      Chr : constant Character := Source (P);
855
856   begin
857      if Chr = CR then
858         if Source (P + 1) = LF then
859            P := P + 2;
860         else
861            P := P + 1;
862         end if;
863
864      elsif Chr = LF then
865         P := P + 1;
866
867      elsif Chr = FF or else Chr = VT then
868         P := P + 1;
869         Physical := False;
870         return;
871
872         --  Otherwise we have a wide character
873
874      else
875         Skip_Wide (Source, P);
876      end if;
877
878      --  Fall through in the physical line terminator case. First deal with
879      --  making a possible entry into the lines table if one is needed.
880
881      --  Note: we are dealing with a real source file here, this cannot be
882      --  the instantiation case, so we need not worry about Sloc adjustment.
883
884      declare
885         S : Source_File_Record
886               renames Source_File.Table (Current_Source_File);
887
888      begin
889         Physical := True;
890
891         --  Make entry in lines table if not already made (in some scan backup
892         --  cases, we will be rescanning previously scanned source, so the
893         --  entry may have already been made on the previous forward scan).
894
895         if Source (P) /= EOF
896           and then P > S.Lines_Table (S.Last_Source_Line)
897         then
898            Add_Line_Tables_Entry (S, P);
899         end if;
900      end;
901   end Skip_Line_Terminators;
902
903   --------------
904   -- Set_Dope --
905   --------------
906
907   procedure Set_Dope
908     (Src : System.Address; New_Dope : Dope_Ptr)
909   is
910      --  A fat pointer is a pair consisting of data pointer and dope pointer,
911      --  in that order. So we want to overwrite the second word.
912      Dope : System.Address;
913      pragma Import (Ada, Dope);
914      use System.Storage_Elements;
915      for Dope'Address use Src + System.Address'Size / 8;
916   begin
917      Dope := New_Dope.all'Address;
918   end Set_Dope;
919
920   procedure Free_Dope (Src : System.Address) is
921      Dope : Dope_Ptr;
922      pragma Import (Ada, Dope);
923      use System.Storage_Elements;
924      for Dope'Address use Src + System.Address'Size / 8;
925      procedure Free is new Unchecked_Deallocation (Dope_Rec, Dope_Ptr);
926   begin
927      Free (Dope);
928   end Free_Dope;
929
930   ----------------
931   -- Sloc_Range --
932   ----------------
933
934   procedure Sloc_Range (N : Node_Id; Min, Max : out Source_Ptr) is
935
936      Indx : constant Source_File_Index := Get_Source_File_Index (Sloc (N));
937
938      function Process (N : Node_Id) return Traverse_Result;
939      --  Process function for traversing the node tree
940
941      procedure Traverse is new Traverse_Proc (Process);
942
943      -------------
944      -- Process --
945      -------------
946
947      function Process (N : Node_Id) return Traverse_Result is
948         Loc : constant Source_Ptr := Sloc (Original_Node (N));
949
950      begin
951         --  Skip nodes that may have been added during expansion and
952         --  that originate in other units, such as code for contracts
953         --  in subprogram bodies.
954
955         if Get_Source_File_Index (Loc) /= Indx then
956            return Skip;
957         end if;
958
959         if Loc > No_Location then
960            if Loc < Min then
961               Min := Loc;
962            elsif Loc > Max then
963               Max := Loc;
964            end if;
965         end if;
966
967         return OK_Orig;
968      end Process;
969
970   --  Start of processing for Sloc_Range
971
972   begin
973      Min := Sloc (N);
974      Max := Min;
975      Traverse (N);
976   end Sloc_Range;
977
978   -------------------
979   -- Source_Offset --
980   -------------------
981
982   function Source_Offset (S : Source_Ptr) return Nat is
983      Sindex : constant Source_File_Index := Get_Source_File_Index (S);
984      Sfirst : constant Source_Ptr :=
985                 Source_File.Table (Sindex).Source_First;
986   begin
987      return Nat (S - Sfirst);
988   end Source_Offset;
989
990   ------------------------
991   -- Top_Level_Location --
992   ------------------------
993
994   function Top_Level_Location (S : Source_Ptr) return Source_Ptr is
995      Oldloc : Source_Ptr;
996      Newloc : Source_Ptr;
997
998   begin
999      Newloc := S;
1000      loop
1001         Oldloc := Newloc;
1002         Newloc := Instantiation_Location (Oldloc);
1003         exit when Newloc = No_Location;
1004      end loop;
1005
1006      return Oldloc;
1007   end Top_Level_Location;
1008
1009   --------------------
1010   -- Write_Location --
1011   --------------------
1012
1013   procedure Write_Location (P : Source_Ptr) is
1014   begin
1015      if P = No_Location then
1016         Write_Str ("<no location>");
1017
1018      elsif P <= Standard_Location then
1019         Write_Str ("<standard location>");
1020
1021      else
1022         declare
1023            SI : constant Source_File_Index := Get_Source_File_Index (P);
1024
1025         begin
1026            Write_Name (Debug_Source_Name (SI));
1027            Write_Char (':');
1028            Write_Int (Int (Get_Logical_Line_Number (P)));
1029            Write_Char (':');
1030            Write_Int (Int (Get_Column_Number (P)));
1031
1032            if Instantiation (SI) /= No_Location then
1033               Write_Str (" [");
1034               Write_Location (Instantiation (SI));
1035               Write_Char (']');
1036            end if;
1037         end;
1038      end if;
1039   end Write_Location;
1040
1041   ----------------------
1042   -- Write_Time_Stamp --
1043   ----------------------
1044
1045   procedure Write_Time_Stamp (S : Source_File_Index) is
1046      T : constant Time_Stamp_Type := Time_Stamp (S);
1047      P : Natural;
1048
1049   begin
1050      if T (1) = '9' then
1051         Write_Str ("19");
1052         P := 0;
1053      else
1054         Write_Char (T (1));
1055         Write_Char (T (2));
1056         P := 2;
1057      end if;
1058
1059      Write_Char (T (P + 1));
1060      Write_Char (T (P + 2));
1061      Write_Char ('-');
1062
1063      Write_Char (T (P + 3));
1064      Write_Char (T (P + 4));
1065      Write_Char ('-');
1066
1067      Write_Char (T (P + 5));
1068      Write_Char (T (P + 6));
1069      Write_Char (' ');
1070
1071      Write_Char (T (P + 7));
1072      Write_Char (T (P + 8));
1073      Write_Char (':');
1074
1075      Write_Char (T (P + 9));
1076      Write_Char (T (P + 10));
1077      Write_Char (':');
1078
1079      Write_Char (T (P + 11));
1080      Write_Char (T (P + 12));
1081   end Write_Time_Stamp;
1082
1083   ----------------------------------------------
1084   -- Access Subprograms for Source File Table --
1085   ----------------------------------------------
1086
1087   function Debug_Source_Name (S : SFI) return File_Name_Type is
1088   begin
1089      return Source_File.Table (S).Debug_Source_Name;
1090   end Debug_Source_Name;
1091
1092   function Instance (S : SFI) return Instance_Id is
1093   begin
1094      return Source_File.Table (S).Instance;
1095   end Instance;
1096
1097   function File_Name (S : SFI) return File_Name_Type is
1098   begin
1099      return Source_File.Table (S).File_Name;
1100   end File_Name;
1101
1102   function File_Type (S : SFI) return Type_Of_File is
1103   begin
1104      return Source_File.Table (S).File_Type;
1105   end File_Type;
1106
1107   function First_Mapped_Line (S : SFI) return Logical_Line_Number is
1108   begin
1109      return Source_File.Table (S).First_Mapped_Line;
1110   end First_Mapped_Line;
1111
1112   function Full_Debug_Name (S : SFI) return File_Name_Type is
1113   begin
1114      return Source_File.Table (S).Full_Debug_Name;
1115   end Full_Debug_Name;
1116
1117   function Full_File_Name (S : SFI) return File_Name_Type is
1118   begin
1119      return Source_File.Table (S).Full_File_Name;
1120   end Full_File_Name;
1121
1122   function Full_Ref_Name (S : SFI) return File_Name_Type is
1123   begin
1124      return Source_File.Table (S).Full_Ref_Name;
1125   end Full_Ref_Name;
1126
1127   function Identifier_Casing (S : SFI) return Casing_Type is
1128   begin
1129      return Source_File.Table (S).Identifier_Casing;
1130   end Identifier_Casing;
1131
1132   function Inherited_Pragma (S : SFI) return Boolean is
1133   begin
1134      return Source_File.Table (S).Inherited_Pragma;
1135   end Inherited_Pragma;
1136
1137   function Inlined_Body (S : SFI) return Boolean is
1138   begin
1139      return Source_File.Table (S).Inlined_Body;
1140   end Inlined_Body;
1141
1142   function Inlined_Call (S : SFI) return Source_Ptr is
1143   begin
1144      return Source_File.Table (S).Inlined_Call;
1145   end Inlined_Call;
1146
1147   function Keyword_Casing (S : SFI) return Casing_Type is
1148   begin
1149      return Source_File.Table (S).Keyword_Casing;
1150   end Keyword_Casing;
1151
1152   function Last_Source_Line (S : SFI) return Physical_Line_Number is
1153   begin
1154      return Source_File.Table (S).Last_Source_Line;
1155   end Last_Source_Line;
1156
1157   function License (S : SFI) return License_Type is
1158   begin
1159      return Source_File.Table (S).License;
1160   end License;
1161
1162   function Num_SRef_Pragmas (S : SFI) return Nat is
1163   begin
1164      return Source_File.Table (S).Num_SRef_Pragmas;
1165   end Num_SRef_Pragmas;
1166
1167   function Reference_Name (S : SFI) return File_Name_Type is
1168   begin
1169      return Source_File.Table (S).Reference_Name;
1170   end Reference_Name;
1171
1172   function Source_Checksum (S : SFI) return Word is
1173   begin
1174      return Source_File.Table (S).Source_Checksum;
1175   end Source_Checksum;
1176
1177   function Source_First (S : SFI) return Source_Ptr is
1178   begin
1179      return Source_File.Table (S).Source_First;
1180   end Source_First;
1181
1182   function Source_Last (S : SFI) return Source_Ptr is
1183   begin
1184      return Source_File.Table (S).Source_Last;
1185   end Source_Last;
1186
1187   function Source_Text (S : SFI) return Source_Buffer_Ptr is
1188   begin
1189      return Source_File.Table (S).Source_Text;
1190   end Source_Text;
1191
1192   function Template (S : SFI) return SFI is
1193   begin
1194      return Source_File.Table (S).Template;
1195   end Template;
1196
1197   function Time_Stamp (S : SFI) return Time_Stamp_Type is
1198   begin
1199      return Source_File.Table (S).Time_Stamp;
1200   end Time_Stamp;
1201
1202   function Unit (S : SFI) return Unit_Number_Type is
1203   begin
1204      return Source_File.Table (S).Unit;
1205   end Unit;
1206
1207   ------------------------------------------
1208   -- Set Procedures for Source File Table --
1209   ------------------------------------------
1210
1211   procedure Set_Identifier_Casing (S : SFI; C : Casing_Type) is
1212   begin
1213      Source_File.Table (S).Identifier_Casing := C;
1214   end Set_Identifier_Casing;
1215
1216   procedure Set_Keyword_Casing (S : SFI; C : Casing_Type) is
1217   begin
1218      Source_File.Table (S).Keyword_Casing := C;
1219   end Set_Keyword_Casing;
1220
1221   procedure Set_License (S : SFI; L : License_Type) is
1222   begin
1223      Source_File.Table (S).License := L;
1224   end Set_License;
1225
1226   procedure Set_Unit (S : SFI; U : Unit_Number_Type) is
1227   begin
1228      Source_File.Table (S).Unit := U;
1229   end Set_Unit;
1230
1231   ----------------------
1232   -- Trim_Lines_Table --
1233   ----------------------
1234
1235   procedure Trim_Lines_Table (S : Source_File_Index) is
1236      Max : constant Nat := Nat (Source_File.Table (S).Last_Source_Line);
1237
1238   begin
1239      --  Release allocated storage that is no longer needed
1240
1241      Source_File.Table (S).Lines_Table := To_Pointer
1242        (Memory.Realloc
1243          (To_Address (Source_File.Table (S).Lines_Table),
1244           Memory.size_t
1245            (Max * (Lines_Table_Type'Component_Size / System.Storage_Unit))));
1246      Source_File.Table (S).Lines_Table_Max := Physical_Line_Number (Max);
1247   end Trim_Lines_Table;
1248
1249   ------------
1250   -- Unlock --
1251   ------------
1252
1253   procedure Unlock is
1254   begin
1255      Source_File.Locked := False;
1256      Source_File.Release;
1257   end Unlock;
1258
1259   --------
1260   -- wl --
1261   --------
1262
1263   procedure wl (P : Source_Ptr) is
1264   begin
1265      Write_Location (P);
1266      Write_Eol;
1267   end wl;
1268
1269end Sinput;
1270