2016-10-26 François Dumont <fdumont@gcc.gnu.org>
[official-gcc.git] / gcc / ada / sinput-l.adb
blobaa9acb897d23fd3acbc5c851bbc91f20bb48ef2b
1 ------------------------------------------------------------------------------
2 -- --
3 -- GNAT COMPILER COMPONENTS --
4 -- --
5 -- S I N P U T . L --
6 -- --
7 -- B o d y --
8 -- --
9 -- Copyright (C) 1992-2016, 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 ------------------------------------------------------------------------------
26 with Alloc;
27 with Atree; use Atree;
28 with Debug; use Debug;
29 with Einfo; use Einfo;
30 with Errout; use Errout;
31 with Fname; use Fname;
32 with Lib; use Lib;
33 with Opt; use Opt;
34 with Osint; use Osint;
35 with Output; use Output;
36 with Prep; use Prep;
37 with Prepcomp; use Prepcomp;
38 with Scans; use Scans;
39 with Scn; use Scn;
40 with Sem_Aux; use Sem_Aux;
41 with Sem_Util; use Sem_Util;
42 with Sinfo; use Sinfo;
43 with Snames; use Snames;
44 with System; use System;
46 with System.OS_Lib; use System.OS_Lib;
48 with Unchecked_Conversion;
50 package body Sinput.L is
52 Prep_Buffer : Text_Buffer_Ptr := null;
53 -- A buffer to temporarily stored the result of preprocessing a source.
54 -- It is only allocated if there is at least one source to preprocess.
56 Prep_Buffer_Last : Text_Ptr := 0;
57 -- Index of the last significant character in Prep_Buffer
59 Initial_Size_Of_Prep_Buffer : constant := 10_000;
60 -- Size of Prep_Buffer when it is first allocated
62 -- When a file is to be preprocessed and the options to list symbols
63 -- has been selected (switch -s), Prep.List_Symbols is called with a
64 -- "foreword", a single line indicating what source the symbols apply to.
65 -- The following two constant String are the start and the end of this
66 -- foreword.
68 Foreword_Start : constant String :=
69 "Preprocessing Symbols for source """;
71 Foreword_End : constant String := """";
73 -----------------
74 -- Subprograms --
75 -----------------
77 procedure Put_Char_In_Prep_Buffer (C : Character);
78 -- Add one character in Prep_Buffer, extending Prep_Buffer if need be.
79 -- Used to initialize the preprocessor.
81 procedure New_EOL_In_Prep_Buffer;
82 -- Add an LF to Prep_Buffer (used to initialize the preprocessor)
84 function Load_File
85 (N : File_Name_Type;
86 T : Osint.File_Type) return Source_File_Index;
87 -- Load a source file, a configuration pragmas file or a definition file
88 -- Coding also allows preprocessing file, but not a library file ???
90 -------------------------------
91 -- Adjust_Instantiation_Sloc --
92 -------------------------------
94 procedure Adjust_Instantiation_Sloc
95 (N : Node_Id;
96 Factor : Sloc_Adjustment)
98 Loc : constant Source_Ptr := Sloc (N);
100 begin
101 -- We only do the adjustment if the value is between the appropriate low
102 -- and high values. It is not clear that this should ever not be the
103 -- case, but in practice there seem to be some nodes that get copied
104 -- twice, and this is a defence against that happening.
106 if Factor.Lo <= Loc and then Loc <= Factor.Hi then
107 Set_Sloc (N, Loc + Factor.Adjust);
108 end if;
109 end Adjust_Instantiation_Sloc;
111 --------------------------------
112 -- Complete_Source_File_Entry --
113 --------------------------------
115 procedure Complete_Source_File_Entry is
116 CSF : constant Source_File_Index := Current_Source_File;
117 begin
118 Trim_Lines_Table (CSF);
119 Source_File.Table (CSF).Source_Checksum := Checksum;
120 end Complete_Source_File_Entry;
122 ---------------------------------
123 -- Create_Instantiation_Source --
124 ---------------------------------
126 procedure Create_Instantiation_Source
127 (Inst_Node : Entity_Id;
128 Template_Id : Entity_Id;
129 Factor : out Sloc_Adjustment;
130 Inlined_Body : Boolean := False;
131 Inherited_Pragma : Boolean := False)
133 Dnod : constant Node_Id := Declaration_Node (Template_Id);
134 Xold : Source_File_Index;
135 Xnew : Source_File_Index;
137 begin
138 Xold := Get_Source_File_Index (Sloc (Template_Id));
139 Factor.Lo := Source_File.Table (Xold).Source_First;
140 Factor.Hi := Source_File.Table (Xold).Source_Last;
142 Source_File.Append (Source_File.Table (Xold));
143 Xnew := Source_File.Last;
145 declare
146 Sold : Source_File_Record renames Source_File.Table (Xold);
147 Snew : Source_File_Record renames Source_File.Table (Xnew);
149 Inst_Spec : Node_Id;
151 begin
152 Snew.Inlined_Body := Inlined_Body;
153 Snew.Inherited_Pragma := Inherited_Pragma;
154 Snew.Template := Xold;
156 -- For a genuine generic instantiation, assign new instance id. For
157 -- inlined bodies or inherited pragmas, we retain that of the
158 -- template, but we save the call location.
160 if Inlined_Body or Inherited_Pragma then
161 Snew.Inlined_Call := Sloc (Inst_Node);
163 else
164 -- If the spec has been instantiated already, and we are now
165 -- creating the instance source for the corresponding body now,
166 -- retrieve the instance id that was assigned to the spec, which
167 -- corresponds to the same instantiation sloc.
169 Inst_Spec := Instance_Spec (Inst_Node);
170 if Present (Inst_Spec) then
171 declare
172 Inst_Spec_Ent : Entity_Id;
173 -- Instance spec entity
175 Inst_Spec_Sloc : Source_Ptr;
176 -- Virtual sloc of the spec instance source
178 Inst_Spec_Inst_Id : Instance_Id;
179 -- Instance id assigned to the instance spec
181 begin
182 Inst_Spec_Ent := Defining_Entity (Inst_Spec);
184 -- For a subprogram instantiation, we want the subprogram
185 -- instance, not the wrapper package.
187 if Present (Related_Instance (Inst_Spec_Ent)) then
188 Inst_Spec_Ent := Related_Instance (Inst_Spec_Ent);
189 end if;
191 -- The specification of the instance entity has a virtual
192 -- sloc within the instance sloc range.
194 -- ??? But the Unit_Declaration_Node has the sloc of the
195 -- instantiation, which is somewhat of an oddity.
197 Inst_Spec_Sloc :=
198 Sloc
199 (Specification (Unit_Declaration_Node (Inst_Spec_Ent)));
200 Inst_Spec_Inst_Id :=
201 Source_File.Table
202 (Get_Source_File_Index (Inst_Spec_Sloc)).Instance;
204 pragma Assert
205 (Sloc (Inst_Node) = Instances.Table (Inst_Spec_Inst_Id));
206 Snew.Instance := Inst_Spec_Inst_Id;
207 end;
209 else
210 Instances.Append (Sloc (Inst_Node));
211 Snew.Instance := Instances.Last;
212 end if;
213 end if;
215 -- Now compute the new values of Source_First and Source_Last and
216 -- adjust the source file pointer to have the correct virtual origin
217 -- for the new range of values.
219 -- Source_First must be greater than the last Source_Last value and
220 -- also must be a multiple of Source_Align.
222 Snew.Source_First :=
223 ((Source_File.Table (Xnew - 1).Source_Last + Source_Align) /
224 Source_Align) * Source_Align;
225 Factor.Adjust := Snew.Source_First - Factor.Lo;
226 Snew.Source_Last := Factor.Hi + Factor.Adjust;
228 Set_Source_File_Index_Table (Xnew);
230 Snew.Sloc_Adjust := Sold.Sloc_Adjust - Factor.Adjust;
232 if Debug_Flag_L then
233 Write_Eol;
234 Write_Str ("*** Create instantiation source for ");
236 if Nkind (Dnod) in N_Proper_Body
237 and then Was_Originally_Stub (Dnod)
238 then
239 Write_Str ("subunit ");
241 elsif Ekind (Template_Id) = E_Generic_Package then
242 if Nkind (Dnod) = N_Package_Body then
243 Write_Str ("body of package ");
244 else
245 Write_Str ("spec of package ");
246 end if;
248 elsif Ekind (Template_Id) = E_Function then
249 Write_Str ("body of function ");
251 elsif Ekind (Template_Id) = E_Procedure then
252 Write_Str ("body of procedure ");
254 elsif Ekind (Template_Id) = E_Generic_Function then
255 Write_Str ("spec of function ");
257 elsif Ekind (Template_Id) = E_Generic_Procedure then
258 Write_Str ("spec of procedure ");
260 elsif Ekind (Template_Id) = E_Package_Body then
261 Write_Str ("body of package ");
263 else pragma Assert (Ekind (Template_Id) = E_Subprogram_Body);
264 if Nkind (Dnod) = N_Procedure_Specification then
265 Write_Str ("body of procedure ");
266 else
267 Write_Str ("body of function ");
268 end if;
269 end if;
271 Write_Name (Chars (Template_Id));
272 Write_Eol;
274 Write_Str (" new source index = ");
275 Write_Int (Int (Xnew));
276 Write_Eol;
278 Write_Str (" copying from file name = ");
279 Write_Name (File_Name (Xold));
280 Write_Eol;
282 Write_Str (" old source index = ");
283 Write_Int (Int (Xold));
284 Write_Eol;
286 Write_Str (" old lo = ");
287 Write_Int (Int (Factor.Lo));
288 Write_Eol;
290 Write_Str (" old hi = ");
291 Write_Int (Int (Factor.Hi));
292 Write_Eol;
294 Write_Str (" new lo = ");
295 Write_Int (Int (Snew.Source_First));
296 Write_Eol;
298 Write_Str (" new hi = ");
299 Write_Int (Int (Snew.Source_Last));
300 Write_Eol;
302 Write_Str (" adjustment factor = ");
303 Write_Int (Int (Factor.Adjust));
304 Write_Eol;
306 Write_Str (" instantiation location: ");
307 Write_Location (Sloc (Inst_Node));
308 Write_Eol;
309 end if;
311 -- For a given character in the source, a higher subscript will be
312 -- used to access the instantiation, which means that the virtual
313 -- origin must have a corresponding lower value. We compute this new
314 -- origin by taking the address of the appropriate adjusted element
315 -- in the old array. Since this adjusted element will be at a
316 -- negative subscript, we must suppress checks.
318 declare
319 pragma Suppress (All_Checks);
321 pragma Warnings (Off);
322 -- This unchecked conversion is aliasing safe, since it is never
323 -- used to create improperly aliased pointer values.
325 function To_Source_Buffer_Ptr is new
326 Unchecked_Conversion (Address, Source_Buffer_Ptr);
328 pragma Warnings (On);
330 begin
331 Snew.Source_Text :=
332 To_Source_Buffer_Ptr
333 (Sold.Source_Text (-Factor.Adjust)'Address);
334 end;
335 end;
336 end Create_Instantiation_Source;
338 ----------------------
339 -- Load_Config_File --
340 ----------------------
342 function Load_Config_File
343 (N : File_Name_Type) return Source_File_Index
345 begin
346 return Load_File (N, Osint.Config);
347 end Load_Config_File;
349 --------------------------
350 -- Load_Definition_File --
351 --------------------------
353 function Load_Definition_File
354 (N : File_Name_Type) return Source_File_Index
356 begin
357 return Load_File (N, Osint.Definition);
358 end Load_Definition_File;
360 ---------------
361 -- Load_File --
362 ---------------
364 function Load_File
365 (N : File_Name_Type;
366 T : Osint.File_Type) return Source_File_Index
368 Src : Source_Buffer_Ptr;
369 X : Source_File_Index;
370 Lo : Source_Ptr;
371 Hi : Source_Ptr;
373 Preprocessing_Needed : Boolean := False;
375 begin
376 -- If already there, don't need to reload file. An exception occurs
377 -- in multiple unit per file mode. It would be nice in this case to
378 -- share the same source file for each unit, but this leads to many
379 -- difficulties with assumptions (e.g. in the body of lib), that a
380 -- unit can be found by locating its source file index. Since we do
381 -- not expect much use of this mode, it's no big deal to waste a bit
382 -- of space and time by reading and storing the source multiple times.
384 if Multiple_Unit_Index = 0 then
385 for J in 1 .. Source_File.Last loop
386 if Source_File.Table (J).File_Name = N then
387 return J;
388 end if;
389 end loop;
390 end if;
392 -- Here we must build a new entry in the file table
394 -- But first, we must check if a source needs to be preprocessed,
395 -- because we may have to load and parse a definition file, and we want
396 -- to do that before we load the source, so that the buffer of the
397 -- source will be the last created, and we will be able to replace it
398 -- and modify Hi without stepping on another buffer.
400 if T = Osint.Source and then not Is_Internal_File_Name (N) then
401 Prepare_To_Preprocess
402 (Source => N, Preprocessing_Needed => Preprocessing_Needed);
403 end if;
405 Source_File.Increment_Last;
406 X := Source_File.Last;
408 -- Compute starting index, respecting alignment requirement
410 if X = Source_File.First then
411 Lo := First_Source_Ptr;
412 else
413 Lo := ((Source_File.Table (X - 1).Source_Last + Source_Align) /
414 Source_Align) * Source_Align;
415 end if;
417 Osint.Read_Source_File (N, Lo, Hi, Src, T);
419 if Src = null then
420 Source_File.Decrement_Last;
421 return No_Source_File;
423 else
424 if Debug_Flag_L then
425 Write_Eol;
426 Write_Str ("*** Build source file table entry, Index = ");
427 Write_Int (Int (X));
428 Write_Str (", file name = ");
429 Write_Name (N);
430 Write_Eol;
431 Write_Str (" lo = ");
432 Write_Int (Int (Lo));
433 Write_Eol;
434 Write_Str (" hi = ");
435 Write_Int (Int (Hi));
436 Write_Eol;
438 Write_Str (" first 10 chars -->");
440 declare
441 procedure Wchar (C : Character);
442 -- Writes character or ? for control character
444 -----------
445 -- Wchar --
446 -----------
448 procedure Wchar (C : Character) is
449 begin
450 if C < ' '
451 or else C in ASCII.DEL .. Character'Val (16#9F#)
452 then
453 Write_Char ('?');
454 else
455 Write_Char (C);
456 end if;
457 end Wchar;
459 begin
460 for J in Lo .. Lo + 9 loop
461 Wchar (Src (J));
462 end loop;
464 Write_Str ("<--");
465 Write_Eol;
467 Write_Str (" last 10 chars -->");
469 for J in Hi - 10 .. Hi - 1 loop
470 Wchar (Src (J));
471 end loop;
473 Write_Str ("<--");
474 Write_Eol;
476 if Src (Hi) /= EOF then
477 Write_Str (" error: no EOF at end");
478 Write_Eol;
479 end if;
480 end;
481 end if;
483 declare
484 S : Source_File_Record renames Source_File.Table (X);
485 File_Type : Type_Of_File;
487 begin
488 case T is
489 when Osint.Source =>
490 File_Type := Sinput.Src;
492 when Osint.Library =>
493 raise Program_Error;
495 when Osint.Config =>
496 File_Type := Sinput.Config;
498 when Osint.Definition =>
499 File_Type := Def;
501 when Osint.Preprocessing_Data =>
502 File_Type := Preproc;
503 end case;
505 S := (Debug_Source_Name => N,
506 File_Name => N,
507 File_Type => File_Type,
508 First_Mapped_Line => No_Line_Number,
509 Full_Debug_Name => Osint.Full_Source_Name,
510 Full_File_Name => Osint.Full_Source_Name,
511 Full_Ref_Name => Osint.Full_Source_Name,
512 Instance => No_Instance_Id,
513 Identifier_Casing => Unknown,
514 Inlined_Call => No_Location,
515 Inlined_Body => False,
516 Inherited_Pragma => False,
517 Keyword_Casing => Unknown,
518 Last_Source_Line => 1,
519 License => Unknown,
520 Lines_Table => null,
521 Lines_Table_Max => 1,
522 Logical_Lines_Table => null,
523 Num_SRef_Pragmas => 0,
524 Reference_Name => N,
525 Sloc_Adjust => 0,
526 Source_Checksum => 0,
527 Source_First => Lo,
528 Source_Last => Hi,
529 Source_Text => Src,
530 Template => No_Source_File,
531 Unit => No_Unit,
532 Time_Stamp => Osint.Current_Source_File_Stamp);
534 Alloc_Line_Tables (S, Opt.Table_Factor * Alloc.Lines_Initial);
535 S.Lines_Table (1) := Lo;
536 end;
538 -- Preprocess the source if it needs to be preprocessed
540 if Preprocessing_Needed then
542 -- Temporarily set the Source_File_Index_Table entries for the
543 -- source, to avoid crash when reporting an error.
545 Set_Source_File_Index_Table (X);
547 if Opt.List_Preprocessing_Symbols then
548 Get_Name_String (N);
550 declare
551 Foreword : String (1 .. Foreword_Start'Length +
552 Name_Len + Foreword_End'Length);
554 begin
555 Foreword (1 .. Foreword_Start'Length) := Foreword_Start;
556 Foreword (Foreword_Start'Length + 1 ..
557 Foreword_Start'Length + Name_Len) :=
558 Name_Buffer (1 .. Name_Len);
559 Foreword (Foreword'Last - Foreword_End'Length + 1 ..
560 Foreword'Last) := Foreword_End;
561 Prep.List_Symbols (Foreword);
562 end;
563 end if;
565 declare
566 T : constant Nat := Total_Errors_Detected;
567 -- Used to check if there were errors during preprocessing
569 Save_Style_Check : Boolean;
570 -- Saved state of the Style_Check flag (which needs to be
571 -- temporarily set to False during preprocessing, see below).
573 Modified : Boolean;
575 begin
576 -- If this is the first time we preprocess a source, allocate
577 -- the preprocessing buffer.
579 if Prep_Buffer = null then
580 Prep_Buffer :=
581 new Text_Buffer (1 .. Initial_Size_Of_Prep_Buffer);
582 end if;
584 -- Make sure the preprocessing buffer is empty
586 Prep_Buffer_Last := 0;
588 -- Initialize the preprocessor hooks
590 Prep.Setup_Hooks
591 (Error_Msg => Errout.Error_Msg'Access,
592 Scan => Scn.Scanner.Scan'Access,
593 Set_Ignore_Errors => Errout.Set_Ignore_Errors'Access,
594 Put_Char => Put_Char_In_Prep_Buffer'Access,
595 New_EOL => New_EOL_In_Prep_Buffer'Access);
597 -- Initialize scanner and set its behavior for preprocessing,
598 -- then preprocess. Also disable style checks, since some of
599 -- them are done in the scanner (specifically, those dealing
600 -- with line length and line termination), and cannot be done
601 -- during preprocessing (because the source file index table
602 -- has not been set yet).
604 Scn.Scanner.Initialize_Scanner (X);
606 Scn.Scanner.Set_Special_Character ('#');
607 Scn.Scanner.Set_Special_Character ('$');
608 Scn.Scanner.Set_End_Of_Line_As_Token (True);
609 Save_Style_Check := Opt.Style_Check;
610 Opt.Style_Check := False;
612 -- The actual preprocessing step
614 Preprocess (Modified);
616 -- Reset the scanner to its standard behavior, and restore the
617 -- Style_Checks flag.
619 Scn.Scanner.Reset_Special_Characters;
620 Scn.Scanner.Set_End_Of_Line_As_Token (False);
621 Opt.Style_Check := Save_Style_Check;
623 -- If there were errors during preprocessing, record an error
624 -- at the start of the file, and do not change the source
625 -- buffer.
627 if T /= Total_Errors_Detected then
628 Errout.Error_Msg
629 ("file could not be successfully preprocessed", Lo);
630 return No_Source_File;
632 else
633 -- Output the result of the preprocessing, if requested and
634 -- the source has been modified by the preprocessing. Only
635 -- do that for the main unit (spec, body and subunits).
637 if Generate_Processed_File
638 and then Modified
639 and then
640 ((Compiler_State = Parsing
641 and then Parsing_Main_Extended_Source)
642 or else
643 (Compiler_State = Analyzing
644 and then Analysing_Subunit_Of_Main))
645 then
646 declare
647 FD : File_Descriptor;
648 NB : Integer;
649 Status : Boolean;
651 begin
652 Get_Name_String (N);
653 Add_Str_To_Name_Buffer (Prep_Suffix);
655 Delete_File (Name_Buffer (1 .. Name_Len), Status);
657 FD :=
658 Create_New_File (Name_Buffer (1 .. Name_Len), Text);
660 Status := FD /= Invalid_FD;
662 if Status then
663 NB :=
664 Write
665 (FD,
666 Prep_Buffer (1)'Address,
667 Integer (Prep_Buffer_Last));
668 Status := NB = Integer (Prep_Buffer_Last);
669 end if;
671 if Status then
672 Close (FD, Status);
673 end if;
675 if not Status then
676 Errout.Error_Msg
677 ("??could not write processed file """ &
678 Name_Buffer (1 .. Name_Len) & '"',
679 Lo);
680 end if;
681 end;
682 end if;
684 -- Set the new value of Hi
686 Hi := Lo + Source_Ptr (Prep_Buffer_Last);
688 -- Create the new source buffer
690 declare
691 subtype Actual_Source_Buffer is Source_Buffer (Lo .. Hi);
692 -- Physical buffer allocated
694 type Actual_Source_Ptr is access Actual_Source_Buffer;
695 -- Pointer type for the physical buffer allocated
697 Actual_Ptr : constant Actual_Source_Ptr :=
698 new Actual_Source_Buffer;
699 -- Actual physical buffer
701 begin
702 Actual_Ptr (Lo .. Hi - 1) :=
703 Prep_Buffer (1 .. Prep_Buffer_Last);
704 Actual_Ptr (Hi) := EOF;
706 -- Now we need to work out the proper virtual origin
707 -- pointer to return. This is Actual_Ptr (0)'Address, but
708 -- we have to be careful to suppress checks to compute
709 -- this address.
711 declare
712 pragma Suppress (All_Checks);
714 pragma Warnings (Off);
715 -- This unchecked conversion is aliasing safe, since
716 -- it is never used to create improperly aliased
717 -- pointer values.
719 function To_Source_Buffer_Ptr is new
720 Unchecked_Conversion (Address, Source_Buffer_Ptr);
722 pragma Warnings (On);
724 begin
725 Src := To_Source_Buffer_Ptr (Actual_Ptr (0)'Address);
727 -- Record in the table the new source buffer and the
728 -- new value of Hi.
730 Source_File.Table (X).Source_Text := Src;
731 Source_File.Table (X).Source_Last := Hi;
733 -- Reset Last_Line to 1, because the lines do not
734 -- have necessarily the same starts and lengths.
736 Source_File.Table (X).Last_Source_Line := 1;
737 end;
738 end;
739 end if;
740 end;
741 end if;
743 Set_Source_File_Index_Table (X);
744 return X;
745 end if;
746 end Load_File;
748 ----------------------------------
749 -- Load_Preprocessing_Data_File --
750 ----------------------------------
752 function Load_Preprocessing_Data_File
753 (N : File_Name_Type) return Source_File_Index
755 begin
756 return Load_File (N, Osint.Preprocessing_Data);
757 end Load_Preprocessing_Data_File;
759 ----------------------
760 -- Load_Source_File --
761 ----------------------
763 function Load_Source_File
764 (N : File_Name_Type) return Source_File_Index
766 begin
767 return Load_File (N, Osint.Source);
768 end Load_Source_File;
770 ----------------------------
771 -- New_EOL_In_Prep_Buffer --
772 ----------------------------
774 procedure New_EOL_In_Prep_Buffer is
775 begin
776 Put_Char_In_Prep_Buffer (ASCII.LF);
777 end New_EOL_In_Prep_Buffer;
779 -----------------------------
780 -- Put_Char_In_Prep_Buffer --
781 -----------------------------
783 procedure Put_Char_In_Prep_Buffer (C : Character) is
784 begin
785 -- If preprocessing buffer is not large enough, double it
787 if Prep_Buffer_Last = Prep_Buffer'Last then
788 declare
789 New_Prep_Buffer : constant Text_Buffer_Ptr :=
790 new Text_Buffer (1 .. 2 * Prep_Buffer_Last);
792 begin
793 New_Prep_Buffer (Prep_Buffer'Range) := Prep_Buffer.all;
794 Free (Prep_Buffer);
795 Prep_Buffer := New_Prep_Buffer;
796 end;
797 end if;
799 Prep_Buffer_Last := Prep_Buffer_Last + 1;
800 Prep_Buffer (Prep_Buffer_Last) := C;
801 end Put_Char_In_Prep_Buffer;
803 -------------------------
804 -- Source_File_Is_Body --
805 -------------------------
807 function Source_File_Is_Body (X : Source_File_Index) return Boolean is
808 Pcount : Natural;
810 begin
811 Initialize_Scanner (No_Unit, X);
813 -- Loop to look for subprogram or package body
815 loop
816 case Token is
818 -- PRAGMA, WITH, USE (which can appear before a body)
820 when Tok_Pragma | Tok_With | Tok_Use =>
822 -- We just want to skip any of these, do it by skipping to a
823 -- semicolon, but check for EOF, in case we have bad syntax.
825 loop
826 if Token = Tok_Semicolon then
827 Scan;
828 exit;
829 elsif Token = Tok_EOF then
830 return False;
831 else
832 Scan;
833 end if;
834 end loop;
836 -- PACKAGE
838 when Tok_Package =>
839 Scan; -- Past PACKAGE
841 -- We have a body if and only if BODY follows
843 return Token = Tok_Body;
845 -- FUNCTION or PROCEDURE
847 when Tok_Procedure | Tok_Function =>
848 Pcount := 0;
850 -- Loop through tokens following PROCEDURE or FUNCTION
852 loop
853 Scan;
855 case Token is
857 -- For parens, count paren level (note that paren level
858 -- can get greater than 1 if we have default parameters).
860 when Tok_Left_Paren =>
861 Pcount := Pcount + 1;
863 when Tok_Right_Paren =>
864 Pcount := Pcount - 1;
866 -- EOF means something weird, probably no body
868 when Tok_EOF =>
869 return False;
871 -- BEGIN or IS or END definitely means body is present
873 when Tok_Begin | Tok_Is | Tok_End =>
874 return True;
876 -- Semicolon means no body present if at outside any
877 -- parens. If within parens, ignore, since it could be
878 -- a parameter separator.
880 when Tok_Semicolon =>
881 if Pcount = 0 then
882 return False;
883 end if;
885 -- Skip anything else
887 when others =>
888 null;
889 end case;
890 end loop;
892 -- Anything else in main scan means we don't have a body
894 when others =>
895 return False;
896 end case;
897 end loop;
898 end Source_File_Is_Body;
900 ----------------------------
901 -- Source_File_Is_No_Body --
902 ----------------------------
904 function Source_File_Is_No_Body (X : Source_File_Index) return Boolean is
905 begin
906 Initialize_Scanner (No_Unit, X);
908 if Token /= Tok_Pragma then
909 return False;
910 end if;
912 Scan; -- past pragma
914 if Token /= Tok_Identifier
915 or else Chars (Token_Node) /= Name_No_Body
916 then
917 return False;
918 end if;
920 Scan; -- past No_Body
922 if Token /= Tok_Semicolon then
923 return False;
924 end if;
926 Scan; -- past semicolon
928 return Token = Tok_EOF;
929 end Source_File_Is_No_Body;
931 end Sinput.L;