1 ------------------------------------------------------------------------------
3 -- GNAT COMPILER COMPONENTS --
9 -- Copyright (C) 1992-2023, Free Software Foundation, Inc. --
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. --
21 -- GNAT was originally developed by the GNAT team at New York University. --
22 -- Extensive contributions were provided by Ada Core Technologies Inc. --
24 ------------------------------------------------------------------------------
27 with Atree
; use Atree
;
28 with Debug
; use Debug
;
29 with Einfo
; use Einfo
;
30 with Einfo
.Entities
; use Einfo
.Entities
;
31 with Einfo
.Utils
; use Einfo
.Utils
;
32 with Errout
; use Errout
;
33 with Fname
; use Fname
;
36 with Osint
; use Osint
;
37 with Output
; use Output
;
39 with Prepcomp
; use Prepcomp
;
40 with Scans
; use Scans
;
42 with Sem_Aux
; use Sem_Aux
;
43 with Sem_Util
; use Sem_Util
;
44 with Sinfo
; use Sinfo
;
45 with Sinfo
.Nodes
; use Sinfo
.Nodes
;
46 with Snames
; use Snames
;
47 with System
; use System
;
49 with System
.OS_Lib
; use System
.OS_Lib
;
51 package body Sinput
.L
is
53 Prep_Buffer
: Text_Buffer_Ptr
:= null;
54 -- A buffer to temporarily stored the result of preprocessing a source.
55 -- It is only allocated if there is at least one source to preprocess.
57 Prep_Buffer_Last
: Text_Ptr
:= 0;
58 -- Index of the last significant character in Prep_Buffer
60 Initial_Size_Of_Prep_Buffer
: constant := 10_000
;
61 -- Size of Prep_Buffer when it is first allocated
63 -- When a file is to be preprocessed and the options to list symbols
64 -- has been selected (switch -s), Prep.List_Symbols is called with a
65 -- "foreword", a single line indicating what source the symbols apply to.
66 -- The following two constant String are the start and the end of this
69 Foreword_Start
: constant String :=
70 "Preprocessing Symbols for source """;
72 Foreword_End
: constant String := """";
78 procedure Put_Char_In_Prep_Buffer
(C
: Character);
79 -- Add one character in Prep_Buffer, extending Prep_Buffer if need be.
80 -- Used to initialize the preprocessor.
82 procedure New_EOL_In_Prep_Buffer
;
83 -- Add an LF to Prep_Buffer (used to initialize the preprocessor)
87 T
: Osint
.File_Type
) return Source_File_Index
;
88 -- Load a source file, a configuration pragmas file or a definition file
89 -- Coding also allows preprocessing file, but not a library file ???
91 -------------------------------
92 -- Adjust_Instantiation_Sloc --
93 -------------------------------
95 procedure Adjust_Instantiation_Sloc
97 Factor
: Sloc_Adjustment
)
99 Loc
: constant Source_Ptr
:= Sloc
(N
);
102 -- We only do the adjustment if the value is between the appropriate low
103 -- and high values. It is not clear that this should ever not be the
104 -- case, but in practice there seem to be some nodes that get copied
105 -- twice, and this is a defence against that happening.
107 if Loc
in Factor
.Lo
.. Factor
.Hi
then
108 Set_Sloc
(N
, Loc
+ Factor
.Adjust
);
110 end Adjust_Instantiation_Sloc
;
112 --------------------------------
113 -- Complete_Source_File_Entry --
114 --------------------------------
116 procedure Complete_Source_File_Entry
is
117 CSF
: constant Source_File_Index
:= Current_Source_File
;
119 Trim_Lines_Table
(CSF
);
120 Source_File
.Table
(CSF
).Source_Checksum
:= Checksum
;
121 end Complete_Source_File_Entry
;
123 ---------------------------------
124 -- Create_Instantiation_Source --
125 ---------------------------------
127 procedure Create_Instantiation_Source
128 (Inst_Node
: Entity_Id
;
129 Template_Id
: Entity_Id
;
130 Factor
: out Sloc_Adjustment
;
131 Inlined_Body
: Boolean := False;
132 Inherited_Pragma
: Boolean := False)
134 Dnod
: constant Node_Id
:= Declaration_Node
(Template_Id
);
135 Xold
: Source_File_Index
;
136 Xnew
: Source_File_Index
;
139 Xold
:= Get_Source_File_Index
(Sloc
(Template_Id
));
140 Factor
.Lo
:= Source_File
.Table
(Xold
).Source_First
;
141 Factor
.Hi
:= Source_File
.Table
(Xold
).Source_Last
;
143 Source_File
.Append
(Source_File
.Table
(Xold
));
144 Xnew
:= Source_File
.Last
;
148 Write_Str
("*** Create_Instantiation_Source: created source ");
149 Write_Int
(Int
(Xnew
));
154 Sold
: Source_File_Record
renames Source_File
.Table
(Xold
);
155 Snew
: Source_File_Record
renames Source_File
.Table
(Xnew
);
161 Snew
.Inlined_Body
:= Inlined_Body
;
162 Snew
.Inherited_Pragma
:= Inherited_Pragma
;
163 Snew
.Template
:= Xold
;
165 -- For a genuine generic instantiation, assign new instance id. For
166 -- inlined bodies or inherited pragmas, we retain that of the
167 -- template, but we save the call location.
169 if Inlined_Body
or Inherited_Pragma
then
170 Snew
.Inlined_Call
:= Sloc
(Inst_Node
);
173 -- If the spec has been instantiated already, and we are now
174 -- creating the instance source for the corresponding body now,
175 -- retrieve the instance id that was assigned to the spec, which
176 -- corresponds to the same instantiation sloc.
178 Inst_Spec
:= Instance_Spec
(Inst_Node
);
179 if Present
(Inst_Spec
) then
181 Inst_Spec_Ent
: Entity_Id
;
182 -- Instance spec entity
184 Inst_Spec_Sloc
: Source_Ptr
;
185 -- Virtual sloc of the spec instance source
187 Inst_Spec_Inst_Id
: Instance_Id
;
188 -- Instance id assigned to the instance spec
191 Inst_Spec_Ent
:= Defining_Entity
(Inst_Spec
);
193 -- For a subprogram instantiation, we want the subprogram
194 -- instance, not the wrapper package.
196 if Present
(Related_Instance
(Inst_Spec_Ent
)) then
197 Inst_Spec_Ent
:= Related_Instance
(Inst_Spec_Ent
);
200 -- The specification of the instance entity has a virtual
201 -- sloc within the instance sloc range.
203 -- ??? But the Unit_Declaration_Node has the sloc of the
204 -- instantiation, which is somewhat of an oddity.
208 (Specification
(Unit_Declaration_Node
(Inst_Spec_Ent
)));
211 (Get_Source_File_Index
(Inst_Spec_Sloc
)).Instance
;
214 (Sloc
(Inst_Node
) = Instances
.Table
(Inst_Spec_Inst_Id
));
215 Snew
.Instance
:= Inst_Spec_Inst_Id
;
219 Instances
.Append
(Sloc
(Inst_Node
));
220 Snew
.Instance
:= Instances
.Last
;
224 -- Now compute the new values of Source_First and Source_Last and
225 -- adjust the source file pointer to have the correct bounds for the
226 -- new range of values.
228 -- Source_First must be greater than the last Source_Last value and
229 -- also must be a multiple of Source_Align.
232 ((Source_File
.Table
(Xnew
- 1).Source_Last
+ Source_Align
) /
233 Source_Align
) * Source_Align
;
234 Factor
.Adjust
:= Snew
.Source_First
- Factor
.Lo
;
235 Snew
.Source_Last
:= Factor
.Hi
+ Factor
.Adjust
;
237 Set_Source_File_Index_Table
(Xnew
);
239 Snew
.Sloc_Adjust
:= Sold
.Sloc_Adjust
- Factor
.Adjust
;
241 -- Modify the Dope of the instance Source_Text to use the
242 -- above-computed bounds.
245 Dope
: constant Dope_Ptr
:=
246 new Dope_Rec
'(Snew.Source_First, Snew.Source_Last);
248 Snew.Source_Text := Sold.Source_Text;
249 Set_Dope (Snew.Source_Text'Address, Dope);
250 pragma Assert (Snew.Source_Text'First = Snew.Source_First);
251 pragma Assert (Snew.Source_Text'Last = Snew.Source_Last);
257 if Nkind (Dnod) in N_Proper_Body
258 and then Was_Originally_Stub (Dnod)
260 Write_Str ("subunit ");
262 elsif Ekind (Template_Id) = E_Generic_Package then
263 if Nkind (Dnod) = N_Package_Body then
264 Write_Str ("body of package ");
266 Write_Str ("spec of package ");
269 elsif Ekind (Template_Id) = E_Function then
270 Write_Str ("body of function ");
272 elsif Ekind (Template_Id) = E_Procedure then
273 Write_Str ("body of procedure ");
275 elsif Ekind (Template_Id) = E_Generic_Function then
276 Write_Str ("spec of function ");
278 elsif Ekind (Template_Id) = E_Generic_Procedure then
279 Write_Str ("spec of procedure ");
281 elsif Ekind (Template_Id) = E_Package_Body then
282 Write_Str ("body of package ");
284 else pragma Assert (Ekind (Template_Id) = E_Subprogram_Body);
285 if Nkind (Dnod) = N_Procedure_Specification then
286 Write_Str ("body of procedure ");
288 Write_Str ("body of function ");
292 Write_Name (Chars (Template_Id));
295 Write_Str (" copying from file name = ");
296 Write_Name (File_Name (Xold));
299 Write_Str (" old source index = ");
300 Write_Int (Int (Xold));
303 Write_Str (" old lo = ");
304 Write_Int (Int (Factor.Lo));
307 Write_Str (" old hi = ");
308 Write_Int (Int (Factor.Hi));
311 Write_Str (" new lo = ");
312 Write_Int (Int (Snew.Source_First));
315 Write_Str (" new hi = ");
316 Write_Int (Int (Snew.Source_Last));
319 Write_Str (" adjustment factor = ");
320 Write_Int (Int (Factor.Adjust));
323 Write_Str (" instantiation location: ");
324 Write_Location (Sloc (Inst_Node));
328 end Create_Instantiation_Source;
330 ----------------------
331 -- Load_Config_File --
332 ----------------------
334 function Load_Config_File
335 (N : File_Name_Type) return Source_File_Index
338 return Load_File (N, Osint.Config);
339 end Load_Config_File;
341 --------------------------
342 -- Load_Definition_File --
343 --------------------------
345 function Load_Definition_File
346 (N : File_Name_Type) return Source_File_Index
349 return Load_File (N, Osint.Definition);
350 end Load_Definition_File;
358 T : Osint.File_Type) return Source_File_Index
360 FD : File_Descriptor;
363 Src : Source_Buffer_Ptr;
364 X : Source_File_Index;
366 Preprocessing_Needed : Boolean := False;
369 -- If already there, don't need to reload file. An exception occurs
370 -- in multiple unit per file mode. It would be nice in this case to
371 -- share the same source file for each unit, but this leads to many
372 -- difficulties with assumptions (e.g. in the body of lib), that a
373 -- unit can be found by locating its source file index. Since we do
374 -- not expect much use of this mode, it's no big deal to waste a bit
375 -- of space and time by reading and storing the source multiple times.
377 if Multiple_Unit_Index = 0 then
378 for J in 1 .. Source_File.Last loop
379 if Source_File.Table (J).File_Name = N then
385 -- Here we must build a new entry in the file table
387 -- But first, we must check if a source needs to be preprocessed,
388 -- because we may have to load and parse a definition file, and we want
389 -- to do that before we load the source, so that the buffer of the
390 -- source will be the last created, and we will be able to replace it
391 -- and modify Hi without stepping on another buffer.
393 if T = Osint.Source and then not Is_Internal_File_Name (N) then
394 Prepare_To_Preprocess
395 (Source => N, Preprocessing_Needed => Preprocessing_Needed);
398 Source_File.Increment_Last;
399 X := Source_File.Last;
403 Write_Str ("Sinput.L.Load_File: created source ");
406 Write_Str (Get_Name_String (N));
409 -- Compute starting index, respecting alignment requirement
411 if X = Source_File.First then
412 Lo := First_Source_Ptr;
414 Lo := ((Source_File.Table (X - 1).Source_Last + Source_Align) /
415 Source_Align) * Source_Align;
418 Osint.Read_Source_File (N, Lo, Hi, Src, FD, T);
420 if Null_Source_Buffer_Ptr (Src) then
421 Source_File.Decrement_Last;
423 if FD = Osint.Null_FD then
424 return No_Source_File;
426 return No_Access_To_Source_File;
431 Write_Str ("*** Build source file table entry, Index = ");
433 Write_Str (", file name = ");
436 Write_Str (" lo = ");
437 Write_Int (Int (Lo));
439 Write_Str (" hi = ");
440 Write_Int (Int (Hi));
443 Write_Str (" first 10 chars -->");
446 procedure Wchar (C : Character);
447 -- Writes character or ? for control character
453 procedure Wchar (C : Character) is
456 or else C in ASCII.DEL .. Character'Val (16#9F#)
465 for J in Lo .. Lo + 9 loop
472 Write_Str (" last 10 chars -->");
474 for J in Hi - 10 .. Hi - 1 loop
481 if Src (Hi) /= EOF then
482 Write_Str (" error: no EOF at end");
489 S : Source_File_Record renames Source_File.Table (X);
490 File_Type : Type_Of_File;
495 File_Type := Sinput.Src;
497 when Osint.Library =>
501 File_Type := Sinput.Config;
503 when Osint.Definition =>
506 when Osint.Preprocessing_Data =>
507 File_Type := Preproc;
510 S := (Debug_Source_Name => N,
512 File_Type => File_Type,
513 First_Mapped_Line => No_Line_Number,
514 Full_Debug_Name => Osint.Full_Source_Name,
515 Full_File_Name => Osint.Full_Source_Name,
516 Full_Ref_Name => Osint.Full_Source_Name,
517 Instance => No_Instance_Id,
518 Identifier_Casing => Unknown,
519 Inlined_Call => No_Location,
520 Inlined_Body => False,
521 Inherited_Pragma => False,
522 Keyword_Casing => Unknown,
523 Last_Source_Line => 1,
526 Lines_Table_Max => 1,
527 Logical_Lines_Table => null,
528 Num_SRef_Pragmas => 0,
531 Source_Checksum => 0,
535 Template => No_Source_File,
537 Time_Stamp => Osint.Current_Source_File_Stamp,
540 Alloc_Line_Tables (S, Opt.Table_Factor * Alloc.Lines_Initial);
541 S.Lines_Table (1) := Lo;
544 -- Preprocess the source if it needs to be preprocessed
546 if Preprocessing_Needed then
548 -- Temporarily set the Source_File_Index_Table entries for the
549 -- source, to avoid crash when reporting an error.
551 Set_Source_File_Index_Table (X);
553 if Opt.List_Preprocessing_Symbols then
555 Foreword : constant String :=
556 Foreword_Start & Get_Name_String (N) & Foreword_End;
558 Prep.List_Symbols (Foreword);
563 T : constant Nat := Total_Errors_Detected;
564 -- Used to check if there were errors during preprocessing
566 Save_Style_Check : Boolean;
567 -- Saved state of the Style_Check flag (which needs to be
568 -- temporarily set to False during preprocessing, see below).
573 -- If this is the first time we preprocess a source, allocate
574 -- the preprocessing buffer.
576 if Prep_Buffer = null then
578 new Text_Buffer (1 .. Initial_Size_Of_Prep_Buffer);
581 -- Make sure the preprocessing buffer is empty
583 Prep_Buffer_Last := 0;
585 -- Initialize the preprocessor hooks
588 (Error_Msg => Errout.Error_Msg'Access,
589 Scan => Scn.Scanner.Scan'Access,
590 Set_Ignore_Errors => Errout.Set_Ignore_Errors'Access,
591 Put_Char => Put_Char_In_Prep_Buffer'Access,
592 New_EOL => New_EOL_In_Prep_Buffer'Access);
594 -- Initialize scanner and set its behavior for preprocessing,
595 -- then preprocess. Also disable style checks, since some of
596 -- them are done in the scanner (specifically, those dealing
597 -- with line length and line termination), and cannot be done
598 -- during preprocessing (because the source file index table
599 -- has not been set yet).
601 Scn.Scanner.Initialize_Scanner (X);
603 Scn.Scanner.Set_Special_Character ('#
');
604 Scn.Scanner.Set_Special_Character ('$
');
605 Scn.Scanner.Set_End_Of_Line_As_Token (True);
606 Save_Style_Check := Opt.Style_Check;
607 Opt.Style_Check := False;
609 -- The actual preprocessing step
611 Preprocess (Modified);
613 -- Reset the scanner to its standard behavior, and restore the
614 -- Style_Checks flag.
616 Scn.Scanner.Reset_Special_Characters;
617 Scn.Scanner.Set_End_Of_Line_As_Token (False);
618 Opt.Style_Check := Save_Style_Check;
620 -- If there were errors during preprocessing, record an error
621 -- at the start of the file, and do not change the source
624 if T /= Total_Errors_Detected then
626 ("file could not be successfully preprocessed", Lo);
627 return No_Source_File;
630 -- Output the result of the preprocessing, if requested and
631 -- the source has been modified by the preprocessing. Only
632 -- do that for the main unit (spec, body and subunits).
634 if Generate_Processed_File
637 ((Compiler_State = Parsing
638 and then Parsing_Main_Extended_Source)
640 (Compiler_State = Analyzing
641 and then Analysing_Subunit_Of_Main))
644 FD : File_Descriptor;
648 Prep_Filename : constant String :=
649 Get_Name_String (N) & Prep_Suffix;
652 Delete_File (Prep_Filename, Status);
654 FD := Create_New_File (Prep_Filename, Text);
656 Status := FD /= Invalid_FD;
662 Prep_Buffer (1)'Address,
663 Integer (Prep_Buffer_Last));
664 Status := NB = Integer (Prep_Buffer_Last);
673 ("??could not write processed file """ &
674 Name_Buffer (1 .. Name_Len) & '"',
680 -- Set the new value of Hi
682 Hi := Lo + Source_Ptr (Prep_Buffer_Last);
684 -- Create the new source buffer
687 Var_Ptr : constant Source_Buffer_Ptr_Var :=
688 new Source_Buffer (Lo .. Hi);
689 -- Allocate source buffer, allowing extra character at
693 Var_Ptr (Lo .. Hi - 1) :=
694 Prep_Buffer (1 .. Prep_Buffer_Last);
696 Src := Var_Ptr.all'Access;
699 -- Record in the table the new source buffer and the
702 Source_File.Table (X).Source_Text := Src;
703 Source_File.Table (X).Source_Last := Hi;
705 -- Reset Last_Line to 1, because the lines do not
706 -- have necessarily the same starts and lengths.
708 Source_File.Table (X).Last_Source_Line := 1;
713 Set_Source_File_Index_Table (X);
718 ----------------------------------
719 -- Load_Preprocessing_Data_File --
720 ----------------------------------
722 function Load_Preprocessing_Data_File
723 (N : File_Name_Type) return Source_File_Index
726 return Load_File (N, Osint.Preprocessing_Data);
727 end Load_Preprocessing_Data_File;
729 ----------------------
730 -- Load_Source_File --
731 ----------------------
733 function Load_Source_File
734 (N : File_Name_Type) return Source_File_Index
737 return Load_File (N, Osint.Source);
738 end Load_Source_File;
740 ----------------------------
741 -- New_EOL_In_Prep_Buffer --
742 ----------------------------
744 procedure New_EOL_In_Prep_Buffer is
746 Put_Char_In_Prep_Buffer (ASCII.LF);
747 end New_EOL_In_Prep_Buffer;
749 -----------------------------
750 -- Put_Char_In_Prep_Buffer --
751 -----------------------------
753 procedure Put_Char_In_Prep_Buffer (C : Character) is
755 -- If preprocessing buffer is not large enough, double it
757 if Prep_Buffer_Last = Prep_Buffer'Last then
759 New_Prep_Buffer : constant Text_Buffer_Ptr :=
760 new Text_Buffer (1 .. 2 * Prep_Buffer_Last);
763 New_Prep_Buffer (Prep_Buffer'Range) := Prep_Buffer.all;
765 Prep_Buffer := New_Prep_Buffer;
769 Prep_Buffer_Last := Prep_Buffer_Last + 1;
770 Prep_Buffer (Prep_Buffer_Last) := C;
771 end Put_Char_In_Prep_Buffer;
773 -------------------------
774 -- Source_File_Is_Body --
775 -------------------------
777 function Source_File_Is_Body (X : Source_File_Index) return Boolean is
781 Initialize_Scanner (No_Unit, X);
783 -- Loop to look for subprogram or package body
788 -- PRAGMA, WITH, USE (which can appear before a body)
794 -- We just want to skip any of these, do it by skipping to a
795 -- semicolon, but check for EOF, in case we have bad syntax.
798 if Token = Tok_Semicolon then
801 elsif Token = Tok_EOF then
811 Scan; -- Past PACKAGE
813 -- We have a body if and only if BODY follows
815 return Token = Tok_Body;
817 -- FUNCTION or PROCEDURE
824 -- Loop through tokens following PROCEDURE or FUNCTION
831 -- For parens, count paren level (note that paren level
832 -- can get greater than 1 if we have default parameters).
834 when Tok_Left_Paren =>
835 Pcount := Pcount + 1;
837 when Tok_Right_Paren =>
838 Pcount := Pcount - 1;
840 -- EOF means something weird, probably no body
845 -- BEGIN or IS or END definitely means body is present
853 -- Semicolon means no body present if at outside any
854 -- parens. If within parens, ignore, since it could be
855 -- a parameter separator.
857 when Tok_Semicolon =>
862 -- Skip anything else
869 -- Anything else in main scan means we don't have a body
875 end Source_File_Is_Body;
877 ----------------------------
878 -- Source_File_Is_No_Body --
879 ----------------------------
881 function Source_File_Is_No_Body (X : Source_File_Index) return Boolean is
883 Initialize_Scanner (No_Unit, X);
885 if Token /= Tok_Pragma then
891 if Token /= Tok_Identifier
892 or else Chars (Token_Node) /= Name_No_Body
897 Scan; -- past No_Body
899 if Token /= Tok_Semicolon then
903 Scan; -- past semicolon
905 return Token = Tok_EOF;
906 end Source_File_Is_No_Body;