1 ------------------------------------------------------------------------------
3 -- GNAT COMPILER COMPONENTS --
9 -- Copyright (C) 2003-2012, 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 ------------------------------------------------------------------------------
26 with Atree
; use Atree
;
27 with Errout
; use Errout
;
28 with Lib
.Writ
; use Lib
.Writ
;
30 with Osint
; use Osint
;
32 with Scans
; use Scans
;
34 with Sinput
.L
; use Sinput
.L
;
35 with Stringt
; use Stringt
;
37 with Types
; use Types
;
39 package body Prepcomp
is
41 No_Preprocessing
: Boolean := True;
42 -- Set to False if there is at least one source that needs to be
45 Source_Index_Of_Preproc_Data_File
: Source_File_Index
:= No_Source_File
;
47 -- The following variable should be a constant, but this is not possible
48 -- because its type GNAT.Dynamic_Tables.Instance has a component P of
49 -- uninitialized private type GNAT.Dynamic_Tables.Table_Private and there
50 -- are no exported values for this private type. Warnings are Off because
51 -- it is never assigned a value.
53 pragma Warnings
(Off
);
54 No_Mapping
: Prep
.Symbol_Table
.Instance
;
57 type Preproc_Data
is record
58 Mapping
: Symbol_Table
.Instance
;
59 File_Name
: File_Name_Type
:= No_File
;
60 Deffile
: String_Id
:= No_String
;
61 Undef_False
: Boolean := False;
62 Always_Blank
: Boolean := False;
63 Comments
: Boolean := False;
64 No_Deletion
: Boolean := False;
65 List_Symbols
: Boolean := False;
66 Processed
: Boolean := False;
68 -- Structure to keep the preprocessing data for a file name or for the
69 -- default (when Name_Id = No_Name).
71 No_Preproc_Data
: constant Preproc_Data
:=
72 (Mapping
=> No_Mapping
,
76 Always_Blank
=> False,
79 List_Symbols
=> False,
82 Default_Data
: Preproc_Data
:= No_Preproc_Data
;
83 -- The preprocessing data to be used when no specific preprocessing data
84 -- is specified for a source.
86 Default_Data_Defined
: Boolean := False;
87 -- True if source for which no specific preprocessing is specified need to
88 -- be preprocess with the Default_Data.
90 Current_Data
: Preproc_Data
:= No_Preproc_Data
;
92 package Preproc_Data_Table
is new Table
.Table
93 (Table_Component_Type
=> Preproc_Data
,
94 Table_Index_Type
=> Int
,
97 Table_Increment
=> 100,
98 Table_Name
=> "Prepcomp.Preproc_Data_Table");
99 -- Table to store the specific preprocessing data
101 Command_Line_Symbols
: Symbol_Table
.Instance
;
102 -- A table to store symbol definitions specified on the command line with
105 package Dependencies
is new Table
.Table
106 (Table_Component_Type
=> Source_File_Index
,
107 Table_Index_Type
=> Int
,
108 Table_Low_Bound
=> 1,
110 Table_Increment
=> 100,
111 Table_Name
=> "Prepcomp.Dependencies");
112 -- Table to store the dependencies on preprocessing files
114 procedure Add_Command_Line_Symbols
;
115 -- Add the command line symbol definitions, if any, to Prep.Mapping table
117 procedure Skip_To_End_Of_Line
;
118 -- Ignore errors and scan up to the next end of line or the end of file
120 ------------------------------
121 -- Add_Command_Line_Symbols --
122 ------------------------------
124 procedure Add_Command_Line_Symbols
is
125 Symbol_Id
: Prep
.Symbol_Id
;
128 for J
in 1 .. Symbol_Table
.Last
(Command_Line_Symbols
) loop
129 Symbol_Id
:= Prep
.Index_Of
(Command_Line_Symbols
.Table
(J
).Symbol
);
131 if Symbol_Id
= No_Symbol
then
132 Symbol_Table
.Increment_Last
(Prep
.Mapping
);
133 Symbol_Id
:= Symbol_Table
.Last
(Prep
.Mapping
);
136 Prep
.Mapping
.Table
(Symbol_Id
) := Command_Line_Symbols
.Table
(J
);
138 end Add_Command_Line_Symbols
;
140 ----------------------
141 -- Add_Dependencies --
142 ----------------------
144 procedure Add_Dependencies
is
146 for Index
in 1 .. Dependencies
.Last
loop
147 Add_Preprocessing_Dependency
(Dependencies
.Table
(Index
));
149 end Add_Dependencies
;
155 procedure Check_Symbols
is
157 -- If there is at least one switch -gnateD specified
159 if Symbol_Table
.Last
(Command_Line_Symbols
) >= 1 then
160 Current_Data
:= No_Preproc_Data
;
161 No_Preprocessing
:= False;
162 Current_Data
.Processed
:= True;
164 -- Start with an empty, initialized mapping table; use Prep.Mapping,
165 -- because Prep.Index_Of uses Prep.Mapping.
167 Prep
.Mapping
:= No_Mapping
;
168 Symbol_Table
.Init
(Prep
.Mapping
);
170 -- Add the command line symbols
172 Add_Command_Line_Symbols
;
174 -- Put the resulting Prep.Mapping in Current_Data, and immediately
175 -- set Prep.Mapping to nil.
177 Current_Data
.Mapping
:= Prep
.Mapping
;
178 Prep
.Mapping
:= No_Mapping
;
180 -- Set the default data
182 Default_Data
:= Current_Data
;
183 Default_Data_Defined
:= True;
187 ------------------------------
188 -- Parse_Preprocessing_Data --
189 ------------------------------
191 procedure Parse_Preprocessing_Data_File
(N
: File_Name_Type
) is
192 OK
: Boolean := False;
193 Dash_Location
: Source_Ptr
;
194 Symbol_Data
: Prep
.Symbol_Data
;
195 Symbol_Id
: Prep
.Symbol_Id
;
196 T
: constant Nat
:= Total_Errors_Detected
;
199 -- Load the preprocessing data file
201 Source_Index_Of_Preproc_Data_File
:= Load_Preprocessing_Data_File
(N
);
203 -- Fail if preprocessing data file cannot be found
205 if Source_Index_Of_Preproc_Data_File
= No_Source_File
then
207 Fail
("preprocessing data file """
208 & Name_Buffer
(1 .. Name_Len
)
212 -- Initialize scanner and set its behavior for processing a data file
214 Scn
.Scanner
.Initialize_Scanner
(Source_Index_Of_Preproc_Data_File
);
215 Scn
.Scanner
.Set_End_Of_Line_As_Token
(True);
216 Scn
.Scanner
.Reset_Special_Characters
;
222 exit For_Each_Line
when Token
= Tok_EOF
;
224 if Token
= Tok_End_Of_Line
then
231 No_Preprocessing
:= False;
232 Current_Data
:= No_Preproc_Data
;
239 if Default_Data_Defined
then
241 ("multiple default preprocessing data", Token_Ptr
);
245 Default_Data_Defined
:= True;
248 when Tok_String_Literal
=>
252 String_To_Name_Buffer
(String_Literal_Id
);
253 Canonical_Case_File_Name
(Name_Buffer
(1 .. Name_Len
));
254 Current_Data
.File_Name
:= Name_Find
;
257 for Index
in 1 .. Preproc_Data_Table
.Last
loop
258 if Current_Data
.File_Name
=
259 Preproc_Data_Table
.Table
(Index
).File_Name
261 Error_Msg_File_1
:= Current_Data
.File_Name
;
263 ("multiple preprocessing data for{", Token_Ptr
);
270 Error_Msg
("`'*` or literal string expected", Token_Ptr
);
273 -- If there is a problem, skip the line
280 -- Scan past the * or the literal string
284 -- A literal string in second position is a definition file
286 if Token
= Tok_String_Literal
then
287 Current_Data
.Deffile
:= String_Literal_Id
;
288 Current_Data
.Processed
:= False;
292 -- If there is no definition file, set Processed to True now
294 Current_Data
.Processed
:= True;
297 -- Start with an empty, initialized mapping table; use Prep.Mapping,
298 -- because Prep.Index_Of uses Prep.Mapping.
300 Prep
.Mapping
:= No_Mapping
;
301 Symbol_Table
.Init
(Prep
.Mapping
);
303 -- Check the switches that may follow
305 while Token
/= Tok_End_Of_Line
and then Token
/= Tok_EOF
loop
306 if Token
/= Tok_Minus
then
308 ("`'-` expected", Token_Ptr
);
313 -- Keep the location of the '-' for possible error reporting
315 Dash_Location
:= Token_Ptr
;
321 Change_Reserved_Keyword_To_Symbol
;
323 -- An identifier (or a reserved word converted to an
324 -- identifier) is expected and there must be no blank space
325 -- between the '-' and the identifier.
327 if Token
= Tok_Identifier
328 and then Token_Ptr
= Dash_Location
+ 1
330 Get_Name_String
(Token_Name
);
332 -- Check the character in the source, because the case is
335 case Sinput
.Source
(Token_Ptr
) is
338 -- All source text preserved (also implies -u)
341 Current_Data
.No_Deletion
:= True;
342 Current_Data
.Undef_False
:= True;
348 -- Undefined symbol are False
351 Current_Data
.Undef_False
:= True;
360 Current_Data
.Always_Blank
:= True;
366 -- Comment removed lines
369 Current_Data
.Comments
:= True;
378 Current_Data
.List_Symbols
:= True;
390 -- A symbol must be an Ada identifier; it cannot start
391 -- with an underline or a digit.
393 if Name_Buffer
(2) = '_'
394 or else Name_Buffer
(2) in '0' .. '9'
396 Error_Msg
("symbol expected", Token_Ptr
+ 1);
401 -- Get the name id of the symbol
403 Symbol_Data
.On_The_Command_Line
:= True;
404 Name_Buffer
(1 .. Name_Len
- 1) :=
405 Name_Buffer
(2 .. Name_Len
);
406 Name_Len
:= Name_Len
- 1;
407 Symbol_Data
.Symbol
:= Name_Find
;
409 if Name_Buffer
(1 .. Name_Len
) = "if"
410 or else Name_Buffer
(1 .. Name_Len
) = "else"
411 or else Name_Buffer
(1 .. Name_Len
) = "elsif"
412 or else Name_Buffer
(1 .. Name_Len
) = "end"
413 or else Name_Buffer
(1 .. Name_Len
) = "not"
414 or else Name_Buffer
(1 .. Name_Len
) = "and"
415 or else Name_Buffer
(1 .. Name_Len
) = "then"
417 Error_Msg
("symbol expected", Token_Ptr
+ 1);
422 -- Get the name id of the original symbol, with
423 -- possibly capital letters.
425 Name_Len
:= Integer (Scan_Ptr
- Token_Ptr
- 1);
427 for J
in 1 .. Name_Len
loop
429 Sinput
.Source
(Token_Ptr
+ Text_Ptr
(J
));
432 Symbol_Data
.Original
:= Name_Find
;
434 -- Scan past D<symbol>
438 if Token
/= Tok_Equal
then
440 ("`=` expected", Token_Ptr
);
449 -- Here any reserved word is OK
451 Change_Reserved_Keyword_To_Symbol
452 (All_Keywords
=> True);
454 -- Value can be an identifier (or a reserved word)
455 -- or a literal string.
458 when Tok_String_Literal
=>
459 Symbol_Data
.Is_A_String
:= True;
460 Symbol_Data
.Value
:= String_Literal_Id
;
462 when Tok_Identifier
=>
463 Symbol_Data
.Is_A_String
:= False;
466 for J
in Token_Ptr
.. Scan_Ptr
- 1 loop
467 Store_String_Char
(Sinput
.Source
(J
));
470 Symbol_Data
.Value
:= End_String
;
474 ("literal string or identifier expected",
480 -- If symbol already exists, replace old definition
483 Symbol_Id
:= Prep
.Index_Of
(Symbol_Data
.Symbol
);
485 -- Otherwise, add a new entry in the table
487 if Symbol_Id
= No_Symbol
then
488 Symbol_Table
.Increment_Last
(Prep
.Mapping
);
489 Symbol_Id
:= Symbol_Table
.Last
(Mapping
);
492 Prep
.Mapping
.Table
(Symbol_Id
) := Symbol_Data
;
503 Error_Msg
("invalid switch", Dash_Location
);
509 -- Add the command line symbols, if any, possibly replacing symbols
512 Add_Command_Line_Symbols
;
514 -- Put the resulting Prep.Mapping in Current_Data, and immediately
515 -- set Prep.Mapping to nil.
517 Current_Data
.Mapping
:= Prep
.Mapping
;
518 Prep
.Mapping
:= No_Mapping
;
520 -- Record Current_Data
522 if Current_Data
.File_Name
= No_File
then
523 Default_Data
:= Current_Data
;
526 Preproc_Data_Table
.Increment_Last
;
527 Preproc_Data_Table
.Table
(Preproc_Data_Table
.Last
) := Current_Data
;
530 Current_Data
:= No_Preproc_Data
;
531 end loop For_Each_Line
;
533 Scn
.Scanner
.Set_End_Of_Line_As_Token
(False);
535 -- Fail if there were errors in the preprocessing data file
537 if Total_Errors_Detected
> T
then
538 Errout
.Finalize
(Last_Call
=> True);
539 Errout
.Output_Messages
;
540 Fail
("errors found in preprocessing data file """
541 & Get_Name_String
(N
) & """");
544 -- Record the dependency on the preprocessor data file
546 Dependencies
.Increment_Last
;
547 Dependencies
.Table
(Dependencies
.Last
) :=
548 Source_Index_Of_Preproc_Data_File
;
549 end Parse_Preprocessing_Data_File
;
551 ---------------------------
552 -- Prepare_To_Preprocess --
553 ---------------------------
555 procedure Prepare_To_Preprocess
556 (Source
: File_Name_Type
;
557 Preprocessing_Needed
: out Boolean)
559 Default
: Boolean := False;
563 -- By default, preprocessing is not needed
565 Preprocessing_Needed
:= False;
567 if No_Preprocessing
then
571 -- First, look for preprocessing data specific to the current source
573 for J
in 1 .. Preproc_Data_Table
.Last
loop
574 if Preproc_Data_Table
.Table
(J
).File_Name
= Source
then
576 Current_Data
:= Preproc_Data_Table
.Table
(J
);
581 -- If no specific preprocessing data, then take the default
584 if Default_Data_Defined
then
585 Current_Data
:= Default_Data
;
589 -- If no default, then nothing to do
595 -- Set the preprocessing flags according to the preprocessing data
597 if Current_Data
.Comments
and not Current_Data
.Always_Blank
then
598 Comment_Deleted_Lines
:= True;
599 Blank_Deleted_Lines
:= False;
601 Comment_Deleted_Lines
:= False;
602 Blank_Deleted_Lines
:= True;
605 No_Deletion
:= Current_Data
.No_Deletion
;
606 Undefined_Symbols_Are_False
:= Current_Data
.Undef_False
;
607 List_Preprocessing_Symbols
:= Current_Data
.List_Symbols
;
609 -- If not already done it, process the definition file
611 if Current_Data
.Processed
then
615 Prep
.Mapping
:= Current_Data
.Mapping
;
618 -- First put the mapping in Prep.Mapping, because Prep.Parse_Def_File
619 -- works on Prep.Mapping.
621 Prep
.Mapping
:= Current_Data
.Mapping
;
623 String_To_Name_Buffer
(Current_Data
.Deffile
);
626 N
: constant File_Name_Type
:= Name_Find
;
627 Deffile
: constant Source_File_Index
:=
628 Load_Definition_File
(N
);
629 Add_Deffile
: Boolean := True;
630 T
: constant Nat
:= Total_Errors_Detected
;
633 if Deffile
= No_Source_File
then
634 Fail
("definition file """
635 & Get_Name_String
(N
)
639 -- Initialize the preprocessor and set the characteristics of the
640 -- scanner for a definition file.
643 (Error_Msg
=> Errout
.Error_Msg
'Access,
644 Scan
=> Scn
.Scanner
.Scan
'Access,
645 Set_Ignore_Errors
=> Errout
.Set_Ignore_Errors
'Access,
649 Scn
.Scanner
.Set_End_Of_Line_As_Token
(True);
650 Scn
.Scanner
.Reset_Special_Characters
;
652 -- Initialize the scanner and process the definition file
654 Scn
.Scanner
.Initialize_Scanner
(Deffile
);
657 -- Reset the behaviour of the scanner to the default
659 Scn
.Scanner
.Set_End_Of_Line_As_Token
(False);
661 -- Fail if errors were found while processing the definition file
663 if T
/= Total_Errors_Detected
then
664 Errout
.Finalize
(Last_Call
=> True);
665 Errout
.Output_Messages
;
666 Fail
("errors found in definition file """
667 & Get_Name_String
(N
)
671 for Index
in 1 .. Dependencies
.Last
loop
672 if Dependencies
.Table
(Index
) = Deffile
then
673 Add_Deffile
:= False;
679 Dependencies
.Increment_Last
;
680 Dependencies
.Table
(Dependencies
.Last
) := Deffile
;
684 -- Get back the mapping, indicate that the definition file is
685 -- processed and store back the preprocessing data.
687 Current_Data
.Mapping
:= Prep
.Mapping
;
688 Current_Data
.Processed
:= True;
691 Default_Data
:= Current_Data
;
694 Preproc_Data_Table
.Table
(Index
) := Current_Data
;
698 Preprocessing_Needed
:= True;
699 end Prepare_To_Preprocess
;
701 ---------------------------------------------
702 -- Process_Command_Line_Symbol_Definitions --
703 ---------------------------------------------
705 procedure Process_Command_Line_Symbol_Definitions
is
706 Symbol_Data
: Prep
.Symbol_Data
;
707 Found
: Boolean := False;
710 Symbol_Table
.Init
(Command_Line_Symbols
);
712 -- The command line definitions have been stored temporarily in
713 -- array Symbol_Definitions.
715 for Index
in 1 .. Preprocessing_Symbol_Last
loop
716 -- Check each symbol definition, fail immediately if syntax is not
719 Check_Command_Line_Symbol_Definition
720 (Definition
=> Preprocessing_Symbol_Defs
(Index
).all,
721 Data
=> Symbol_Data
);
724 -- If there is already a definition for this symbol, replace the old
725 -- definition by this one.
727 for J
in 1 .. Symbol_Table
.Last
(Command_Line_Symbols
) loop
728 if Command_Line_Symbols
.Table
(J
).Symbol
= Symbol_Data
.Symbol
then
729 Command_Line_Symbols
.Table
(J
) := Symbol_Data
;
735 -- Otherwise, create a new entry in the table
738 Symbol_Table
.Increment_Last
(Command_Line_Symbols
);
739 Command_Line_Symbols
.Table
740 (Symbol_Table
.Last
(Command_Line_Symbols
)) := Symbol_Data
;
743 end Process_Command_Line_Symbol_Definitions
;
745 -------------------------
746 -- Skip_To_End_Of_Line --
747 -------------------------
749 procedure Skip_To_End_Of_Line
is
751 Set_Ignore_Errors
(To
=> True);
753 while Token
/= Tok_End_Of_Line
and then Token
/= Tok_EOF
loop
757 Set_Ignore_Errors
(To
=> False);
758 end Skip_To_End_Of_Line
;