[gcc/testsuite]
[official-gcc.git] / gcc / ada / sinput-l.adb
blob360e7117e45f2db3d66ea63a0c500a5d9262f5e6
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-2017, 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 package body Sinput.L is
50 Prep_Buffer : Text_Buffer_Ptr := null;
51 -- A buffer to temporarily stored the result of preprocessing a source.
52 -- It is only allocated if there is at least one source to preprocess.
54 Prep_Buffer_Last : Text_Ptr := 0;
55 -- Index of the last significant character in Prep_Buffer
57 Initial_Size_Of_Prep_Buffer : constant := 10_000;
58 -- Size of Prep_Buffer when it is first allocated
60 -- When a file is to be preprocessed and the options to list symbols
61 -- has been selected (switch -s), Prep.List_Symbols is called with a
62 -- "foreword", a single line indicating what source the symbols apply to.
63 -- The following two constant String are the start and the end of this
64 -- foreword.
66 Foreword_Start : constant String :=
67 "Preprocessing Symbols for source """;
69 Foreword_End : constant String := """";
71 -----------------
72 -- Subprograms --
73 -----------------
75 procedure Put_Char_In_Prep_Buffer (C : Character);
76 -- Add one character in Prep_Buffer, extending Prep_Buffer if need be.
77 -- Used to initialize the preprocessor.
79 procedure New_EOL_In_Prep_Buffer;
80 -- Add an LF to Prep_Buffer (used to initialize the preprocessor)
82 function Load_File
83 (N : File_Name_Type;
84 T : Osint.File_Type) return Source_File_Index;
85 -- Load a source file, a configuration pragmas file or a definition file
86 -- Coding also allows preprocessing file, but not a library file ???
88 -------------------------------
89 -- Adjust_Instantiation_Sloc --
90 -------------------------------
92 procedure Adjust_Instantiation_Sloc
93 (N : Node_Id;
94 Factor : Sloc_Adjustment)
96 Loc : constant Source_Ptr := Sloc (N);
98 begin
99 -- We only do the adjustment if the value is between the appropriate low
100 -- and high values. It is not clear that this should ever not be the
101 -- case, but in practice there seem to be some nodes that get copied
102 -- twice, and this is a defence against that happening.
104 if Loc in Factor.Lo .. Factor.Hi then
105 Set_Sloc (N, Loc + Factor.Adjust);
106 end if;
107 end Adjust_Instantiation_Sloc;
109 --------------------------------
110 -- Complete_Source_File_Entry --
111 --------------------------------
113 procedure Complete_Source_File_Entry is
114 CSF : constant Source_File_Index := Current_Source_File;
115 begin
116 Trim_Lines_Table (CSF);
117 Source_File.Table (CSF).Source_Checksum := Checksum;
118 end Complete_Source_File_Entry;
120 ---------------------------------
121 -- Create_Instantiation_Source --
122 ---------------------------------
124 procedure Create_Instantiation_Source
125 (Inst_Node : Entity_Id;
126 Template_Id : Entity_Id;
127 Factor : out Sloc_Adjustment;
128 Inlined_Body : Boolean := False;
129 Inherited_Pragma : Boolean := False)
131 Dnod : constant Node_Id := Declaration_Node (Template_Id);
132 Xold : Source_File_Index;
133 Xnew : Source_File_Index;
135 begin
136 Xold := Get_Source_File_Index (Sloc (Template_Id));
137 Factor.Lo := Source_File.Table (Xold).Source_First;
138 Factor.Hi := Source_File.Table (Xold).Source_Last;
140 Source_File.Append (Source_File.Table (Xold));
141 Xnew := Source_File.Last;
143 if Debug_Flag_L then
144 Write_Eol;
145 Write_Str ("*** Create_Instantiation_Source: created source ");
146 Write_Int (Int (Xnew));
147 Write_Line ("");
148 end if;
150 declare
151 Sold : Source_File_Record renames Source_File.Table (Xold);
152 Snew : Source_File_Record renames Source_File.Table (Xnew);
154 Inst_Spec : Node_Id;
156 begin
157 Snew.Index := Xnew;
158 Snew.Inlined_Body := Inlined_Body;
159 Snew.Inherited_Pragma := Inherited_Pragma;
160 Snew.Template := Xold;
162 -- For a genuine generic instantiation, assign new instance id. For
163 -- inlined bodies or inherited pragmas, we retain that of the
164 -- template, but we save the call location.
166 if Inlined_Body or Inherited_Pragma then
167 Snew.Inlined_Call := Sloc (Inst_Node);
169 else
170 -- If the spec has been instantiated already, and we are now
171 -- creating the instance source for the corresponding body now,
172 -- retrieve the instance id that was assigned to the spec, which
173 -- corresponds to the same instantiation sloc.
175 Inst_Spec := Instance_Spec (Inst_Node);
176 if Present (Inst_Spec) then
177 declare
178 Inst_Spec_Ent : Entity_Id;
179 -- Instance spec entity
181 Inst_Spec_Sloc : Source_Ptr;
182 -- Virtual sloc of the spec instance source
184 Inst_Spec_Inst_Id : Instance_Id;
185 -- Instance id assigned to the instance spec
187 begin
188 Inst_Spec_Ent := Defining_Entity (Inst_Spec);
190 -- For a subprogram instantiation, we want the subprogram
191 -- instance, not the wrapper package.
193 if Present (Related_Instance (Inst_Spec_Ent)) then
194 Inst_Spec_Ent := Related_Instance (Inst_Spec_Ent);
195 end if;
197 -- The specification of the instance entity has a virtual
198 -- sloc within the instance sloc range.
200 -- ??? But the Unit_Declaration_Node has the sloc of the
201 -- instantiation, which is somewhat of an oddity.
203 Inst_Spec_Sloc :=
204 Sloc
205 (Specification (Unit_Declaration_Node (Inst_Spec_Ent)));
206 Inst_Spec_Inst_Id :=
207 Source_File.Table
208 (Get_Source_File_Index (Inst_Spec_Sloc)).Instance;
210 pragma Assert
211 (Sloc (Inst_Node) = Instances.Table (Inst_Spec_Inst_Id));
212 Snew.Instance := Inst_Spec_Inst_Id;
213 end;
215 else
216 Instances.Append (Sloc (Inst_Node));
217 Snew.Instance := Instances.Last;
218 end if;
219 end if;
221 -- Now compute the new values of Source_First and Source_Last and
222 -- adjust the source file pointer to have the correct bounds for the
223 -- new range of values.
225 -- Source_First must be greater than the last Source_Last value and
226 -- also must be a multiple of Source_Align.
228 Snew.Source_First :=
229 ((Source_File.Table (Xnew - 1).Source_Last + Source_Align) /
230 Source_Align) * Source_Align;
231 Factor.Adjust := Snew.Source_First - Factor.Lo;
232 Snew.Source_Last := Factor.Hi + Factor.Adjust;
234 Set_Source_File_Index_Table (Xnew);
236 Snew.Sloc_Adjust := Sold.Sloc_Adjust - Factor.Adjust;
238 -- Modify the Dope of the instance Source_Text to use the
239 -- above-computed bounds.
241 declare
242 Dope : constant Dope_Ptr :=
243 new Dope_Rec'(Snew.Source_First, Snew.Source_Last);
244 begin
245 Snew.Source_Text := Sold.Source_Text;
246 Set_Dope (Snew.Source_Text'Address, Dope);
247 pragma Assert (Snew.Source_Text'First = Snew.Source_First);
248 pragma Assert (Snew.Source_Text'Last = Snew.Source_Last);
249 end;
251 if Debug_Flag_L then
252 Write_Str (" for ");
254 if Nkind (Dnod) in N_Proper_Body
255 and then Was_Originally_Stub (Dnod)
256 then
257 Write_Str ("subunit ");
259 elsif Ekind (Template_Id) = E_Generic_Package then
260 if Nkind (Dnod) = N_Package_Body then
261 Write_Str ("body of package ");
262 else
263 Write_Str ("spec of package ");
264 end if;
266 elsif Ekind (Template_Id) = E_Function then
267 Write_Str ("body of function ");
269 elsif Ekind (Template_Id) = E_Procedure then
270 Write_Str ("body of procedure ");
272 elsif Ekind (Template_Id) = E_Generic_Function then
273 Write_Str ("spec of function ");
275 elsif Ekind (Template_Id) = E_Generic_Procedure then
276 Write_Str ("spec of procedure ");
278 elsif Ekind (Template_Id) = E_Package_Body then
279 Write_Str ("body of package ");
281 else pragma Assert (Ekind (Template_Id) = E_Subprogram_Body);
282 if Nkind (Dnod) = N_Procedure_Specification then
283 Write_Str ("body of procedure ");
284 else
285 Write_Str ("body of function ");
286 end if;
287 end if;
289 Write_Name (Chars (Template_Id));
290 Write_Eol;
292 Write_Str (" copying from file name = ");
293 Write_Name (File_Name (Xold));
294 Write_Eol;
296 Write_Str (" old source index = ");
297 Write_Int (Int (Xold));
298 Write_Eol;
300 Write_Str (" old lo = ");
301 Write_Int (Int (Factor.Lo));
302 Write_Eol;
304 Write_Str (" old hi = ");
305 Write_Int (Int (Factor.Hi));
306 Write_Eol;
308 Write_Str (" new lo = ");
309 Write_Int (Int (Snew.Source_First));
310 Write_Eol;
312 Write_Str (" new hi = ");
313 Write_Int (Int (Snew.Source_Last));
314 Write_Eol;
316 Write_Str (" adjustment factor = ");
317 Write_Int (Int (Factor.Adjust));
318 Write_Eol;
320 Write_Str (" instantiation location: ");
321 Write_Location (Sloc (Inst_Node));
322 Write_Eol;
323 end if;
324 end;
325 end Create_Instantiation_Source;
327 ----------------------
328 -- Load_Config_File --
329 ----------------------
331 function Load_Config_File
332 (N : File_Name_Type) return Source_File_Index
334 begin
335 return Load_File (N, Osint.Config);
336 end Load_Config_File;
338 --------------------------
339 -- Load_Definition_File --
340 --------------------------
342 function Load_Definition_File
343 (N : File_Name_Type) return Source_File_Index
345 begin
346 return Load_File (N, Osint.Definition);
347 end Load_Definition_File;
349 ---------------
350 -- Load_File --
351 ---------------
353 function Load_File
354 (N : File_Name_Type;
355 T : Osint.File_Type) return Source_File_Index
357 Src : Source_Buffer_Ptr;
358 X : Source_File_Index;
359 Lo : Source_Ptr;
360 Hi : Source_Ptr;
362 Preprocessing_Needed : Boolean := False;
364 begin
365 -- If already there, don't need to reload file. An exception occurs
366 -- in multiple unit per file mode. It would be nice in this case to
367 -- share the same source file for each unit, but this leads to many
368 -- difficulties with assumptions (e.g. in the body of lib), that a
369 -- unit can be found by locating its source file index. Since we do
370 -- not expect much use of this mode, it's no big deal to waste a bit
371 -- of space and time by reading and storing the source multiple times.
373 if Multiple_Unit_Index = 0 then
374 for J in 1 .. Source_File.Last loop
375 if Source_File.Table (J).File_Name = N then
376 return J;
377 end if;
378 end loop;
379 end if;
381 -- Here we must build a new entry in the file table
383 -- But first, we must check if a source needs to be preprocessed,
384 -- because we may have to load and parse a definition file, and we want
385 -- to do that before we load the source, so that the buffer of the
386 -- source will be the last created, and we will be able to replace it
387 -- and modify Hi without stepping on another buffer.
389 if T = Osint.Source and then not Is_Internal_File_Name (N) then
390 Prepare_To_Preprocess
391 (Source => N, Preprocessing_Needed => Preprocessing_Needed);
392 end if;
394 Source_File.Increment_Last;
395 X := Source_File.Last;
397 if Debug_Flag_L then
398 Write_Eol;
399 Write_Str ("Sinput.L.Load_File: created source ");
400 Write_Int (Int (X));
401 Write_Str (" for ");
402 Write_Str (Get_Name_String (N));
403 end if;
405 -- Compute starting index, respecting alignment requirement
407 if X = Source_File.First then
408 Lo := First_Source_Ptr;
409 else
410 Lo := ((Source_File.Table (X - 1).Source_Last + Source_Align) /
411 Source_Align) * Source_Align;
412 end if;
414 Osint.Read_Source_File (N, Lo, Hi, Src, T);
416 if Null_Source_Buffer_Ptr (Src) then
417 Source_File.Decrement_Last;
418 return No_Source_File;
420 else
421 if Debug_Flag_L then
422 Write_Eol;
423 Write_Str ("*** Build source file table entry, Index = ");
424 Write_Int (Int (X));
425 Write_Str (", file name = ");
426 Write_Name (N);
427 Write_Eol;
428 Write_Str (" lo = ");
429 Write_Int (Int (Lo));
430 Write_Eol;
431 Write_Str (" hi = ");
432 Write_Int (Int (Hi));
433 Write_Eol;
435 Write_Str (" first 10 chars -->");
437 declare
438 procedure Wchar (C : Character);
439 -- Writes character or ? for control character
441 -----------
442 -- Wchar --
443 -----------
445 procedure Wchar (C : Character) is
446 begin
447 if C < ' '
448 or else C in ASCII.DEL .. Character'Val (16#9F#)
449 then
450 Write_Char ('?');
451 else
452 Write_Char (C);
453 end if;
454 end Wchar;
456 begin
457 for J in Lo .. Lo + 9 loop
458 Wchar (Src (J));
459 end loop;
461 Write_Str ("<--");
462 Write_Eol;
464 Write_Str (" last 10 chars -->");
466 for J in Hi - 10 .. Hi - 1 loop
467 Wchar (Src (J));
468 end loop;
470 Write_Str ("<--");
471 Write_Eol;
473 if Src (Hi) /= EOF then
474 Write_Str (" error: no EOF at end");
475 Write_Eol;
476 end if;
477 end;
478 end if;
480 declare
481 S : Source_File_Record renames Source_File.Table (X);
482 File_Type : Type_Of_File;
484 begin
485 case T is
486 when Osint.Source =>
487 File_Type := Sinput.Src;
489 when Osint.Library =>
490 raise Program_Error;
492 when Osint.Config =>
493 File_Type := Sinput.Config;
495 when Osint.Definition =>
496 File_Type := Def;
498 when Osint.Preprocessing_Data =>
499 File_Type := Preproc;
500 end case;
502 S := (Debug_Source_Name => N,
503 File_Name => N,
504 File_Type => File_Type,
505 First_Mapped_Line => No_Line_Number,
506 Full_Debug_Name => Osint.Full_Source_Name,
507 Full_File_Name => Osint.Full_Source_Name,
508 Full_Ref_Name => Osint.Full_Source_Name,
509 Instance => No_Instance_Id,
510 Identifier_Casing => Unknown,
511 Inlined_Call => No_Location,
512 Inlined_Body => False,
513 Inherited_Pragma => False,
514 Keyword_Casing => Unknown,
515 Last_Source_Line => 1,
516 License => Unknown,
517 Lines_Table => null,
518 Lines_Table_Max => 1,
519 Logical_Lines_Table => null,
520 Num_SRef_Pragmas => 0,
521 Reference_Name => N,
522 Sloc_Adjust => 0,
523 Source_Checksum => 0,
524 Source_First => Lo,
525 Source_Last => Hi,
526 Source_Text => Src,
527 Template => No_Source_File,
528 Unit => No_Unit,
529 Time_Stamp => Osint.Current_Source_File_Stamp,
530 Index => X);
532 Alloc_Line_Tables (S, Opt.Table_Factor * Alloc.Lines_Initial);
533 S.Lines_Table (1) := Lo;
534 end;
536 -- Preprocess the source if it needs to be preprocessed
538 if Preprocessing_Needed then
540 -- Temporarily set the Source_File_Index_Table entries for the
541 -- source, to avoid crash when reporting an error.
543 Set_Source_File_Index_Table (X);
545 if Opt.List_Preprocessing_Symbols then
546 Get_Name_String (N);
548 declare
549 Foreword : String (1 .. Foreword_Start'Length +
550 Name_Len + Foreword_End'Length);
552 begin
553 Foreword (1 .. Foreword_Start'Length) := Foreword_Start;
554 Foreword (Foreword_Start'Length + 1 ..
555 Foreword_Start'Length + Name_Len) :=
556 Name_Buffer (1 .. Name_Len);
557 Foreword (Foreword'Last - Foreword_End'Length + 1 ..
558 Foreword'Last) := Foreword_End;
559 Prep.List_Symbols (Foreword);
560 end;
561 end if;
563 declare
564 T : constant Nat := Total_Errors_Detected;
565 -- Used to check if there were errors during preprocessing
567 Save_Style_Check : Boolean;
568 -- Saved state of the Style_Check flag (which needs to be
569 -- temporarily set to False during preprocessing, see below).
571 Modified : Boolean;
573 begin
574 -- If this is the first time we preprocess a source, allocate
575 -- the preprocessing buffer.
577 if Prep_Buffer = null then
578 Prep_Buffer :=
579 new Text_Buffer (1 .. Initial_Size_Of_Prep_Buffer);
580 end if;
582 -- Make sure the preprocessing buffer is empty
584 Prep_Buffer_Last := 0;
586 -- Initialize the preprocessor hooks
588 Prep.Setup_Hooks
589 (Error_Msg => Errout.Error_Msg'Access,
590 Scan => Scn.Scanner.Scan'Access,
591 Set_Ignore_Errors => Errout.Set_Ignore_Errors'Access,
592 Put_Char => Put_Char_In_Prep_Buffer'Access,
593 New_EOL => New_EOL_In_Prep_Buffer'Access);
595 -- Initialize scanner and set its behavior for preprocessing,
596 -- then preprocess. Also disable style checks, since some of
597 -- them are done in the scanner (specifically, those dealing
598 -- with line length and line termination), and cannot be done
599 -- during preprocessing (because the source file index table
600 -- has not been set yet).
602 Scn.Scanner.Initialize_Scanner (X);
604 Scn.Scanner.Set_Special_Character ('#');
605 Scn.Scanner.Set_Special_Character ('$');
606 Scn.Scanner.Set_End_Of_Line_As_Token (True);
607 Save_Style_Check := Opt.Style_Check;
608 Opt.Style_Check := False;
610 -- The actual preprocessing step
612 Preprocess (Modified);
614 -- Reset the scanner to its standard behavior, and restore the
615 -- Style_Checks flag.
617 Scn.Scanner.Reset_Special_Characters;
618 Scn.Scanner.Set_End_Of_Line_As_Token (False);
619 Opt.Style_Check := Save_Style_Check;
621 -- If there were errors during preprocessing, record an error
622 -- at the start of the file, and do not change the source
623 -- buffer.
625 if T /= Total_Errors_Detected then
626 Errout.Error_Msg
627 ("file could not be successfully preprocessed", Lo);
628 return No_Source_File;
630 else
631 -- Output the result of the preprocessing, if requested and
632 -- the source has been modified by the preprocessing. Only
633 -- do that for the main unit (spec, body and subunits).
635 if Generate_Processed_File
636 and then Modified
637 and then
638 ((Compiler_State = Parsing
639 and then Parsing_Main_Extended_Source)
640 or else
641 (Compiler_State = Analyzing
642 and then Analysing_Subunit_Of_Main))
643 then
644 declare
645 FD : File_Descriptor;
646 NB : Integer;
647 Status : Boolean;
649 begin
650 Get_Name_String (N);
651 Add_Str_To_Name_Buffer (Prep_Suffix);
653 Delete_File (Name_Buffer (1 .. Name_Len), Status);
655 FD :=
656 Create_New_File (Name_Buffer (1 .. Name_Len), Text);
658 Status := FD /= Invalid_FD;
660 if Status then
661 NB :=
662 Write
663 (FD,
664 Prep_Buffer (1)'Address,
665 Integer (Prep_Buffer_Last));
666 Status := NB = Integer (Prep_Buffer_Last);
667 end if;
669 if Status then
670 Close (FD, Status);
671 end if;
673 if not Status then
674 Errout.Error_Msg
675 ("??could not write processed file """ &
676 Name_Buffer (1 .. Name_Len) & '"',
677 Lo);
678 end if;
679 end;
680 end if;
682 -- Set the new value of Hi
684 Hi := Lo + Source_Ptr (Prep_Buffer_Last);
686 -- Create the new source buffer
688 declare
689 Var_Ptr : constant Source_Buffer_Ptr_Var :=
690 new Source_Buffer (Lo .. Hi);
691 -- Allocate source buffer, allowing extra character at
692 -- end for EOF.
694 begin
695 Var_Ptr (Lo .. Hi - 1) :=
696 Prep_Buffer (1 .. Prep_Buffer_Last);
697 Var_Ptr (Hi) := EOF;
698 Src := Var_Ptr.all'Access;
699 end;
701 -- Record in the table the new source buffer and the
702 -- new value of Hi.
704 Source_File.Table (X).Source_Text := Src;
705 Source_File.Table (X).Source_Last := Hi;
707 -- Reset Last_Line to 1, because the lines do not
708 -- have necessarily the same starts and lengths.
710 Source_File.Table (X).Last_Source_Line := 1;
711 end if;
712 end;
713 end if;
715 Set_Source_File_Index_Table (X);
716 return X;
717 end if;
718 end Load_File;
720 ----------------------------------
721 -- Load_Preprocessing_Data_File --
722 ----------------------------------
724 function Load_Preprocessing_Data_File
725 (N : File_Name_Type) return Source_File_Index
727 begin
728 return Load_File (N, Osint.Preprocessing_Data);
729 end Load_Preprocessing_Data_File;
731 ----------------------
732 -- Load_Source_File --
733 ----------------------
735 function Load_Source_File
736 (N : File_Name_Type) return Source_File_Index
738 begin
739 return Load_File (N, Osint.Source);
740 end Load_Source_File;
742 ----------------------------
743 -- New_EOL_In_Prep_Buffer --
744 ----------------------------
746 procedure New_EOL_In_Prep_Buffer is
747 begin
748 Put_Char_In_Prep_Buffer (ASCII.LF);
749 end New_EOL_In_Prep_Buffer;
751 -----------------------------
752 -- Put_Char_In_Prep_Buffer --
753 -----------------------------
755 procedure Put_Char_In_Prep_Buffer (C : Character) is
756 begin
757 -- If preprocessing buffer is not large enough, double it
759 if Prep_Buffer_Last = Prep_Buffer'Last then
760 declare
761 New_Prep_Buffer : constant Text_Buffer_Ptr :=
762 new Text_Buffer (1 .. 2 * Prep_Buffer_Last);
764 begin
765 New_Prep_Buffer (Prep_Buffer'Range) := Prep_Buffer.all;
766 Free (Prep_Buffer);
767 Prep_Buffer := New_Prep_Buffer;
768 end;
769 end if;
771 Prep_Buffer_Last := Prep_Buffer_Last + 1;
772 Prep_Buffer (Prep_Buffer_Last) := C;
773 end Put_Char_In_Prep_Buffer;
775 -------------------------
776 -- Source_File_Is_Body --
777 -------------------------
779 function Source_File_Is_Body (X : Source_File_Index) return Boolean is
780 Pcount : Natural;
782 begin
783 Initialize_Scanner (No_Unit, X);
785 -- Loop to look for subprogram or package body
787 loop
788 case Token is
790 -- PRAGMA, WITH, USE (which can appear before a body)
792 when Tok_Pragma
793 | Tok_Use
794 | Tok_With
796 -- We just want to skip any of these, do it by skipping to a
797 -- semicolon, but check for EOF, in case we have bad syntax.
799 loop
800 if Token = Tok_Semicolon then
801 Scan;
802 exit;
803 elsif Token = Tok_EOF then
804 return False;
805 else
806 Scan;
807 end if;
808 end loop;
810 -- PACKAGE
812 when Tok_Package =>
813 Scan; -- Past PACKAGE
815 -- We have a body if and only if BODY follows
817 return Token = Tok_Body;
819 -- FUNCTION or PROCEDURE
821 when Tok_Function
822 | Tok_Procedure
824 Pcount := 0;
826 -- Loop through tokens following PROCEDURE or FUNCTION
828 loop
829 Scan;
831 case Token is
833 -- For parens, count paren level (note that paren level
834 -- can get greater than 1 if we have default parameters).
836 when Tok_Left_Paren =>
837 Pcount := Pcount + 1;
839 when Tok_Right_Paren =>
840 Pcount := Pcount - 1;
842 -- EOF means something weird, probably no body
844 when Tok_EOF =>
845 return False;
847 -- BEGIN or IS or END definitely means body is present
849 when Tok_Begin
850 | Tok_End
851 | Tok_Is
853 return True;
855 -- Semicolon means no body present if at outside any
856 -- parens. If within parens, ignore, since it could be
857 -- a parameter separator.
859 when Tok_Semicolon =>
860 if Pcount = 0 then
861 return False;
862 end if;
864 -- Skip anything else
866 when others =>
867 null;
868 end case;
869 end loop;
871 -- Anything else in main scan means we don't have a body
873 when others =>
874 return False;
875 end case;
876 end loop;
877 end Source_File_Is_Body;
879 ----------------------------
880 -- Source_File_Is_No_Body --
881 ----------------------------
883 function Source_File_Is_No_Body (X : Source_File_Index) return Boolean is
884 begin
885 Initialize_Scanner (No_Unit, X);
887 if Token /= Tok_Pragma then
888 return False;
889 end if;
891 Scan; -- past pragma
893 if Token /= Tok_Identifier
894 or else Chars (Token_Node) /= Name_No_Body
895 then
896 return False;
897 end if;
899 Scan; -- past No_Body
901 if Token /= Tok_Semicolon then
902 return False;
903 end if;
905 Scan; -- past semicolon
907 return Token = Tok_EOF;
908 end Source_File_Is_No_Body;
910 end Sinput.L;