1 ------------------------------------------------------------------------------
3 -- GNAT COMPILER COMPONENTS --
9 -- Copyright (C) 2002-2006, 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 2, 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 COPYING. If not, write --
19 -- to the Free Software Foundation, 51 Franklin Street, Fifth Floor, --
20 -- Boston, MA 02110-1301, USA. --
22 -- GNAT was originally developed by the GNAT team at New York University. --
23 -- Extensive contributions were provided by Ada Core Technologies Inc. --
25 ------------------------------------------------------------------------------
27 with Csets
; use Csets
;
28 with Err_Vars
; use Err_Vars
;
29 with Namet
; use Namet
;
31 with Osint
; use Osint
;
32 with Output
; use Output
;
33 with Scans
; use Scans
;
34 with Snames
; use Snames
;
36 with Stringt
; use Stringt
;
39 with GNAT
.Heap_Sort_G
;
45 type Token_Name_Array
is array (Token_Type
) of Name_Id
;
46 Token_Names
: constant Token_Name_Array
:=
47 (Tok_Abort
=> Name_Abort
,
49 Tok_Abstract
=> Name_Abstract
,
50 Tok_Accept
=> Name_Accept
,
51 Tok_Aliased
=> Name_Aliased
,
53 Tok_Array
=> Name_Array
,
56 Tok_Begin
=> Name_Begin
,
57 Tok_Body
=> Name_Body
,
58 Tok_Case
=> Name_Case
,
59 Tok_Constant
=> Name_Constant
,
60 Tok_Declare
=> Name_Declare
,
61 Tok_Delay
=> Name_Delay
,
62 Tok_Delta
=> Name_Delta
,
63 Tok_Digits
=> Name_Digits
,
64 Tok_Else
=> Name_Else
,
65 Tok_Elsif
=> Name_Elsif
,
67 Tok_Entry
=> Name_Entry
,
68 Tok_Exception
=> Name_Exception
,
69 Tok_Exit
=> Name_Exit
,
71 Tok_Function
=> Name_Function
,
72 Tok_Generic
=> Name_Generic
,
73 Tok_Goto
=> Name_Goto
,
76 Tok_Limited
=> Name_Limited
,
77 Tok_Loop
=> Name_Loop
,
80 Tok_Null
=> Name_Null
,
83 Tok_Others
=> Name_Others
,
85 Tok_Package
=> Name_Package
,
86 Tok_Pragma
=> Name_Pragma
,
87 Tok_Private
=> Name_Private
,
88 Tok_Procedure
=> Name_Procedure
,
89 Tok_Protected
=> Name_Protected
,
90 Tok_Raise
=> Name_Raise
,
91 Tok_Range
=> Name_Range
,
92 Tok_Record
=> Name_Record
,
94 Tok_Renames
=> Name_Renames
,
95 Tok_Requeue
=> Name_Requeue
,
96 Tok_Return
=> Name_Return
,
97 Tok_Reverse
=> Name_Reverse
,
98 Tok_Select
=> Name_Select
,
99 Tok_Separate
=> Name_Separate
,
100 Tok_Subtype
=> Name_Subtype
,
101 Tok_Tagged
=> Name_Tagged
,
102 Tok_Task
=> Name_Task
,
103 Tok_Terminate
=> Name_Terminate
,
104 Tok_Then
=> Name_Then
,
105 Tok_Type
=> Name_Type
,
106 Tok_Until
=> Name_Until
,
108 Tok_When
=> Name_When
,
109 Tok_While
=> Name_While
,
110 Tok_With
=> Name_With
,
114 Already_Initialized
: Boolean := False;
115 -- Used to avoid repetition of the part of the initialisation that needs
116 -- to be done only once.
118 Empty_String
: String_Id
;
119 -- "", as a string_id
121 String_False
: String_Id
;
122 -- "false", as a string_id
124 Name_Defined
: Name_Id
;
125 -- defined, as a name_id
131 -- Accesses to procedure specified by procedure Initialize
133 Error_Msg
: Error_Msg_Proc
;
139 Set_Ignore_Errors
: Set_Ignore_Errors_Proc
;
140 -- Indicate if error should be taken into account
142 Put_Char
: Put_Char_Proc
;
143 -- Output one character
145 New_EOL
: New_EOL_Proc
;
146 -- Output an end of line indication
148 -------------------------------
149 -- State of the Preprocessor --
150 -------------------------------
152 type Pp_State
is record
154 -- The location of the #if statement.
155 -- Used to flag #if with no corresponding #end if, at the end.
157 Else_Ptr
: Source_Ptr
;
158 -- The location of the #else statement.
159 -- Used to detect multiple #else.
162 -- Set to True when the code should be deleted or commented out
164 Match_Seen
: Boolean;
165 -- Set to True when a condition in an #if or an #elsif is True.
166 -- Also set to True if Deleting at the previous level is True.
167 -- Used to decide if Deleting should be set to True in a following
172 type Pp_Depth
is new Nat
;
174 Ground
: constant Pp_Depth
:= 0;
176 package Pp_States
is new Table
.Table
177 (Table_Component_Type
=> Pp_State
,
178 Table_Index_Type
=> Pp_Depth
,
179 Table_Low_Bound
=> 1,
181 Table_Increment
=> 100,
182 Table_Name
=> "Prep.Pp_States");
183 -- A stack of the states of the preprocessor, for nested #if
185 type Operator
is (None
, Op_Or
, Op_And
);
191 function Deleting
return Boolean;
192 -- Return True if code should be deleted or commented out
194 function Expression
(Evaluate_It
: Boolean) return Boolean;
195 -- Evaluate a condition in an #if or an #elsif statement.
196 -- If Evaluate_It is False, the condition is effectively evaluated,
197 -- otherwise, only the syntax is checked.
199 procedure Go_To_End_Of_Line
;
200 -- Advance the scan pointer until we reach an end of line or the end
203 function Matching_Strings
(S1
, S2
: String_Id
) return Boolean;
204 -- Returns True if the two string parameters are equal (case insensitive)
206 ---------------------------------------
207 -- Change_Reserved_Keyword_To_Symbol --
208 ---------------------------------------
210 procedure Change_Reserved_Keyword_To_Symbol
211 (All_Keywords
: Boolean := False)
213 New_Name
: constant Name_Id
:= Token_Names
(Token
);
216 if New_Name
/= No_Name
then
218 when Tok_If | Tok_Else | Tok_Elsif | Tok_End |
219 Tok_And | Tok_Or | Tok_Then
=>
221 Token
:= Tok_Identifier
;
222 Token_Name
:= New_Name
;
226 Token
:= Tok_Identifier
;
227 Token_Name
:= New_Name
;
230 end Change_Reserved_Keyword_To_Symbol
;
232 ------------------------------------------
233 -- Check_Command_Line_Symbol_Definition --
234 ------------------------------------------
236 procedure Check_Command_Line_Symbol_Definition
237 (Definition
: String;
238 Data
: out Symbol_Data
)
240 Index
: Natural := 0;
241 Result
: Symbol_Data
;
244 -- Look for the character '='
246 for J
in Definition
'Range loop
247 if Definition
(J
) = '=' then
253 -- If no character '=', then the value is True
256 -- Put the symbol in the name buffer
258 Name_Len
:= Definition
'Length;
259 Name_Buffer
(1 .. Name_Len
) := Definition
;
260 Result
:= True_Value
;
262 elsif Index
= Definition
'First then
263 Fail
("invalid symbol definition """, Definition
, """");
266 -- Put the symbol in the name buffer
268 Name_Len
:= Index
- Definition
'First;
269 Name_Buffer
(1 .. Name_Len
) :=
270 String'(Definition (Definition'First .. Index - 1));
272 -- Check the syntax of the value
274 if Definition (Index + 1) /= '"'
275 or else Definition (Definition'Last) /= '"'
277 for J in Index + 1 .. Definition'Last loop
278 case Definition (J) is
279 when '_
' | '.' | '0' .. '9' | 'a
' .. 'z
' | 'A
' .. 'Z
' =>
283 Fail ("illegal value """,
284 Definition (Index + 1 .. Definition'Last),
290 -- And put the value in the result
292 Result.Is_A_String := False;
294 Store_String_Chars (Definition (Index + 1 .. Definition'Last));
295 Result.Value := End_String;
298 -- Now, check the syntax of the symbol (we don't allow accented and
301 if Name_Buffer (1) not in 'a
' .. 'z
'
302 and then Name_Buffer (1) not in 'A
' .. 'Z
'
305 Name_Buffer (1 .. Name_Len),
306 """ does not start with a letter");
309 for J in 2 .. Name_Len loop
310 case Name_Buffer (J) is
311 when 'a
' .. 'z
' | 'A
' .. 'Z
' | '0' .. '9' =>
317 Name_Buffer (1 .. Name_Len),
318 """ end with a '_
'");
320 elsif Name_Buffer (J + 1) = '_
' then
322 Name_Buffer (1 .. Name_Len),
323 """ contains consecutive '_
'");
328 Name_Buffer (1 .. Name_Len),
329 """ contains illegal character(s)");
333 Result.On_The_Command_Line := True;
335 -- Put the symbol name in the result
338 Sym : constant String := Name_Buffer (1 .. Name_Len);
341 for Index in 1 .. Name_Len loop
342 Name_Buffer (Index) := Fold_Lower (Name_Buffer (Index));
345 Result.Symbol := Name_Find;
346 Name_Len := Sym'Length;
347 Name_Buffer (1 .. Name_Len) := Sym;
348 Result.Original := Name_Find;
352 end Check_Command_Line_Symbol_Definition;
358 function Deleting return Boolean is
360 -- Always return False when not inside an #if statement
362 if Pp_States.Last = Ground then
366 return Pp_States.Table (Pp_States.Last).Deleting;
374 function Expression (Evaluate_It : Boolean) return Boolean is
375 Evaluation : Boolean := Evaluate_It;
376 -- Is set to False after an "or else" when left term is True and
377 -- after an "and then" when left term is False.
379 Final_Result : Boolean := False;
381 Current_Result : Boolean := False;
384 Current_Operator : Operator := None;
387 Symbol_Name1 : Name_Id;
388 Symbol_Name2 : Name_Id;
389 Symbol_Pos1 : Source_Ptr;
390 Symbol_Pos2 : Source_Ptr;
391 Symbol_Value1 : String_Id;
392 Symbol_Value2 : String_Id;
395 -- Loop for each term
398 Change_Reserved_Keyword_To_Symbol;
400 Current_Result := False;
404 when Tok_Left_Paren =>
409 Current_Result := Expression (Evaluation);
411 if Token = Tok_Right_Paren then
415 Error_Msg ("`)` expected", Token_Ptr);
423 Current_Result := not Expression (Evaluation);
425 when Tok_Identifier =>
426 Symbol_Name1 := Token_Name;
427 Symbol_Pos1 := Token_Ptr;
430 if Token = Tok_Apostrophe then
436 if Token = Tok_Identifier
437 and then Token_Name = Name_Defined
442 Error_Msg ("identifier `Defined` expected", Token_Ptr);
446 Current_Result := Index_Of (Symbol_Name1) /= No_Symbol;
449 elsif Token = Tok_Equal then
452 Change_Reserved_Keyword_To_Symbol;
454 if Token = Tok_Identifier then
458 Symbol_Name2 := Token_Name;
459 Symbol_Pos2 := Token_Ptr;
463 Symbol1 := Index_Of (Symbol_Name1);
465 if Symbol1 = No_Symbol then
466 if Undefined_Symbols_Are_False then
467 Symbol_Value1 := String_False;
470 Error_Msg_Name_1 := Symbol_Name1;
471 Error_Msg ("unknown symbol %", Symbol_Pos1);
472 Symbol_Value1 := No_String;
477 Mapping.Table (Symbol1).Value;
480 Symbol2 := Index_Of (Symbol_Name2);
482 if Symbol2 = No_Symbol then
483 if Undefined_Symbols_Are_False then
484 Symbol_Value2 := String_False;
487 Error_Msg_Name_1 := Symbol_Name2;
488 Error_Msg ("unknown symbol %", Symbol_Pos2);
489 Symbol_Value2 := No_String;
493 Symbol_Value2 := Mapping.Table (Symbol2).Value;
496 if Symbol_Value1 /= No_String
497 and then Symbol_Value2 /= No_String
499 Current_Result := Matching_Strings
500 (Symbol_Value1, Symbol_Value2);
504 elsif Token = Tok_String_Literal then
509 Symbol1 := Index_Of (Symbol_Name1);
511 if Symbol1 = No_Symbol then
512 if Undefined_Symbols_Are_False then
513 Symbol_Value1 := String_False;
516 Error_Msg_Name_1 := Symbol_Name1;
517 Error_Msg ("unknown symbol %", Symbol_Pos1);
518 Symbol_Value1 := No_String;
522 Symbol_Value1 := Mapping.Table (Symbol1).Value;
525 if Symbol_Value1 /= No_String then
537 ("symbol or literal string expected", Token_Ptr);
541 -- symbol (True or False)
544 Symbol1 := Index_Of (Symbol_Name1);
546 if Symbol1 = No_Symbol then
547 if Undefined_Symbols_Are_False then
548 Symbol_Value1 := String_False;
551 Error_Msg_Name_1 := Symbol_Name1;
552 Error_Msg ("unknown symbol %", Symbol_Pos1);
553 Symbol_Value1 := No_String;
557 Symbol_Value1 := Mapping.Table (Symbol1).Value;
560 if Symbol_Value1 /= No_String then
561 String_To_Name_Buffer (Symbol_Value1);
563 for Index in 1 .. Name_Len loop
564 Name_Buffer (Index) :=
565 Fold_Lower (Name_Buffer (Index));
568 if Name_Buffer (1 .. Name_Len) = "true" then
569 Current_Result := True;
571 elsif Name_Buffer (1 .. Name_Len) = "false" then
572 Current_Result := False;
575 Error_Msg_Name_1 := Symbol_Name1;
577 ("value of symbol % is not True or False",
585 Error_Msg ("`(`, NOT or symbol expected", Token_Ptr);
588 -- Update the cumulative final result
590 case Current_Operator is
592 Final_Result := Current_Result;
595 Final_Result := Final_Result or Current_Result;
598 Final_Result := Final_Result and Current_Result;
601 -- Check the next operator
603 if Token = Tok_And then
604 if Current_Operator = Op_Or then
605 Error_Msg ("mixing OR and AND is not allowed", Token_Ptr);
608 Current_Operator := Op_And;
611 if Token = Tok_Then then
614 if Final_Result = False then
619 elsif Token = Tok_Or then
620 if Current_Operator = Op_And then
621 Error_Msg ("mixing AND and OR is not allowed", Token_Ptr);
624 Current_Operator := Op_Or;
627 if Token = Tok_Else then
636 -- No operator: exit the term loop
645 -----------------------
646 -- Go_To_End_Of_Line --
647 -----------------------
649 procedure Go_To_End_Of_Line is
651 -- Scan until we get an end of line or we reach the end of the buffer
653 while Token /= Tok_End_Of_Line
654 and then Token /= Tok_EOF
658 end Go_To_End_Of_Line;
664 function Index_Of (Symbol : Name_Id) return Symbol_Id is
666 if Mapping.Table /= null then
667 for J in Symbol_Id range 1 .. Symbol_Table.Last (Mapping) loop
668 if Mapping.Table (J).Symbol = Symbol then
682 (Error_Msg : Error_Msg_Proc;
684 Set_Ignore_Errors : Set_Ignore_Errors_Proc;
685 Put_Char : Put_Char_Proc;
686 New_EOL : New_EOL_Proc)
689 if not Already_Initialized then
691 Store_String_Chars ("True");
692 True_Value.Value := End_String;
695 Empty_String := End_String;
698 Name_Buffer (1 .. Name_Len) := "defined";
699 Name_Defined := Name_Find;
702 Store_String_Chars ("False");
703 String_False := End_String;
705 Already_Initialized := True;
708 Prep.Error_Msg := Error_Msg;
710 Prep.Set_Ignore_Errors := Set_Ignore_Errors;
711 Prep.Put_Char := Put_Char;
712 Prep.New_EOL := New_EOL;
719 procedure List_Symbols (Foreword : String) is
720 Order : array (0 .. Integer (Symbol_Table.Last (Mapping)))
722 -- After alphabetical sorting, this array stores thehe indices of
723 -- the symbols in the order they are displayed.
725 function Lt (Op1, Op2 : Natural) return Boolean;
726 -- Comparison routine for sort call
728 procedure Move (From : Natural; To : Natural);
729 -- Move routine for sort call
735 function Lt (Op1, Op2 : Natural) return Boolean is
736 S1 : constant String :=
737 Get_Name_String (Mapping.Table (Order (Op1)).Symbol);
738 S2 : constant String :=
739 Get_Name_String (Mapping.Table (Order (Op2)).Symbol);
749 procedure Move (From : Natural; To : Natural) is
751 Order (To) := Order (From);
754 package Sort_Syms is new GNAT.Heap_Sort_G (Move, Lt);
757 -- Maximum length of any symbol
759 -- Start of processing for List_Symbols_Case
762 if Symbol_Table.Last (Mapping) = 0 then
766 if Foreword'Length > 0 then
768 Write_Line (Foreword);
770 for J in Foreword'Range loop
775 -- Initialize the order
777 for J in Order'Range loop
778 Order (J) := Symbol_Id (J);
781 -- Sort alphabetically
783 Sort_Syms.Sort (Order'Last);
787 for J in 1 .. Symbol_Table.Last (Mapping) loop
788 Get_Name_String (Mapping.Table (J).Original);
789 Max_L := Integer'Max (Max_L, Name_Len);
793 Write_Str ("Symbol");
795 for J in 1 .. Max_L - 5 loop
799 Write_Line ("Value");
801 Write_Str ("------");
803 for J in 1 .. Max_L - 5 loop
807 Write_Line ("------");
809 for J in 1 .. Order'Last loop
811 Data : constant Symbol_Data := Mapping.Table (Order (J));
814 Get_Name_String (Data.Original);
815 Write_Str (Name_Buffer (1 .. Name_Len));
817 for K in Name_Len .. Max_L loop
821 String_To_Name_Buffer (Data.Value);
823 if Data.Is_A_String then
826 for J in 1 .. Name_Len loop
827 Write_Char (Name_Buffer (J));
829 if Name_Buffer (J) = '"' then
837 Write_Str (Name_Buffer (1 .. Name_Len));
847 ----------------------
848 -- Matching_Strings --
849 ----------------------
851 function Matching_Strings (S1, S2 : String_Id) return Boolean is
853 String_To_Name_Buffer (S1);
855 for Index in 1 .. Name_Len loop
856 Name_Buffer (Index) := Fold_Lower (Name_Buffer (Index));
860 String1 : constant String := Name_Buffer (1 .. Name_Len);
863 String_To_Name_Buffer (S2);
865 for Index in 1 .. Name_Len loop
866 Name_Buffer (Index) := Fold_Lower (Name_Buffer (Index));
869 return String1 = Name_Buffer (1 .. Name_Len);
871 end Matching_Strings;
877 procedure Parse_Def_File is
879 Symbol_Name : Name_Id;
880 Original_Name : Name_Id;
882 Value_Start : Source_Ptr;
883 Value_End : Source_Ptr;
893 exit Def_Line_Loop when Token = Tok_EOF;
895 if Token /= Tok_End_Of_Line then
896 Change_Reserved_Keyword_To_Symbol;
898 if Token /= Tok_Identifier then
899 Error_Msg ("identifier expected", Token_Ptr);
903 Symbol_Name := Token_Name;
906 for Ptr in Token_Ptr .. Scan_Ptr - 1 loop
907 Name_Len := Name_Len + 1;
908 Name_Buffer (Name_Len) := Sinput.Source (Ptr);
911 Original_Name := Name_Find;
914 if Token /= Tok_Colon_Equal then
915 Error_Msg ("`:=` expected", Token_Ptr);
921 if Token = Tok_String_Literal then
922 Data := (Symbol => Symbol_Name,
923 Original => Original_Name,
924 On_The_Command_Line => False,
926 Value => String_Literal_Id);
930 if Token /= Tok_End_Of_Line and then Token /= Tok_EOF then
931 Error_Msg ("extraneous text in definition", Token_Ptr);
935 elsif Token = Tok_End_Of_Line or Token = Tok_EOF then
936 Data := (Symbol => Symbol_Name,
937 Original => Original_Name,
938 On_The_Command_Line => False,
939 Is_A_String => False,
940 Value => Empty_String);
943 Value_Start := Token_Ptr;
944 Value_End := Token_Ptr - 1;
945 Scan_Ptr := Token_Ptr;
949 Ch := Sinput.Source (Scan_Ptr);
952 when '_
' | '.' | '0' .. '9' | 'a
' .. 'z
' | 'A
' .. 'Z
' =>
953 Value_End := Scan_Ptr;
954 Scan_Ptr := Scan_Ptr + 1;
956 when ' ' | HT | VT | CR | LF | FF =>
957 exit Value_Chars_Loop;
960 Error_Msg ("illegal character", Scan_Ptr);
963 end loop Value_Chars_Loop;
967 if Token /= Tok_End_Of_Line and then Token /= Tok_EOF then
968 Error_Msg ("extraneous text in definition", Token_Ptr);
974 while Value_Start <= Value_End loop
975 Store_String_Char (Sinput.Source (Value_Start));
976 Value_Start := Value_Start + 1;
979 Data := (Symbol => Symbol_Name,
980 Original => Original_Name,
981 On_The_Command_Line => False,
982 Is_A_String => False,
983 Value => End_String);
986 -- Now that we have the value, get the symbol index
988 Symbol := Index_Of (Symbol_Name);
990 if Symbol /= No_Symbol then
991 -- If we already have an entry for this symbol, replace it
992 -- with the new value, except if the symbol was declared
993 -- on the command line.
995 if Mapping.Table (Symbol).On_The_Command_Line then
1000 -- As it is the first time we see this symbol, create a new
1001 -- entry in the table.
1003 if Mapping.Table = null then
1004 Symbol_Table.Init (Mapping);
1007 Symbol_Table.Increment_Last (Mapping);
1008 Symbol := Symbol_Table.Last (Mapping);
1011 Mapping.Table (Symbol) := Data;
1015 Set_Ignore_Errors (To => True);
1017 while Token /= Tok_End_Of_Line and Token /= Tok_EOF loop
1021 Set_Ignore_Errors (To => False);
1026 end loop Def_Line_Loop;
1033 procedure Preprocess is
1034 Start_Of_Processing : Source_Ptr;
1036 Preprocessor_Line : Boolean := False;
1038 procedure Output (From, To : Source_Ptr);
1039 -- Output the characters with indices From .. To in the buffer
1040 -- to the output file.
1042 procedure Output_Line (From, To : Source_Ptr);
1043 -- Output a line or the end of a line from the buffer to the output
1044 -- file, followed by an end of line terminator. Depending on the value
1045 -- of Deleting and the switches, the line may be commented out, blank or
1046 -- not output at all.
1052 procedure Output (From, To : Source_Ptr) is
1054 for J in From .. To loop
1055 Put_Char (Sinput.Source (J));
1063 procedure Output_Line (From, To : Source_Ptr) is
1065 if Deleting or Preprocessor_Line then
1066 if Blank_Deleted_Lines then
1069 elsif Comment_Deleted_Lines then
1088 -- Start of processing for Preprocess
1091 Start_Of_Processing := Scan_Ptr;
1093 -- We need to call Scan for the first time, because Initialize_Scanner
1094 -- is no longer doing it.
1098 Input_Line_Loop : loop
1099 exit Input_Line_Loop when Token = Tok_EOF;
1101 Preprocessor_Line := False;
1103 if Token /= Tok_End_Of_Line then
1105 -- Preprocessor line
1107 if Token = Tok_Special and then Special_Character = '#
' then
1108 Preprocessor_Line := True;
1117 If_Ptr : constant Source_Ptr := Token_Ptr;
1121 Cond := Expression (not Deleting);
1123 -- Check for an eventual "then"
1125 if Token = Tok_Then then
1129 -- It is an error to have trailing characters after
1130 -- the condition or "then".
1132 if Token /= Tok_End_Of_Line
1133 and then Token /= Tok_EOF
1136 ("extraneous text on preprocessor line",
1142 -- Set the initial state of this new "#if".
1143 -- This must be done before incrementing the
1144 -- Last of the table, otherwise function
1145 -- Deleting does not report the correct value.
1147 New_State : constant Pp_State :=
1150 Deleting => Deleting or (not Cond),
1151 Match_Seen => Deleting or Cond);
1154 Pp_States.Increment_Last;
1155 Pp_States.Table (Pp_States.Last) := New_State;
1164 if Pp_States.Last = 0
1165 or else Pp_States.Table (Pp_States.Last).Else_Ptr
1168 Error_Msg ("no IF for this ELSIF", Token_Ptr);
1172 not Pp_States.Table (Pp_States.Last).Match_Seen;
1176 Cond := Expression (Cond);
1178 -- Check for an eventual "then"
1180 if Token = Tok_Then then
1184 -- It is an error to have trailing characters after
1185 -- the condition or "then".
1187 if Token /= Tok_End_Of_Line
1188 and then Token /= Tok_EOF
1191 ("extraneous text on preprocessor line",
1197 -- Depending on the value of the condition, set the
1198 -- new values of Deleting and Match_Seen.
1199 if Pp_States.Last > 0 then
1200 if Pp_States.Table (Pp_States.Last).Match_Seen then
1201 Pp_States.Table (Pp_States.Last).Deleting :=
1205 Pp_States.Table (Pp_States.Last).Match_Seen :=
1207 Pp_States.Table (Pp_States.Last).Deleting :=
1216 if Pp_States.Last = 0 then
1217 Error_Msg ("no IF for this ELSE", Token_Ptr);
1220 Pp_States.Table (Pp_States.Last).Else_Ptr /= 0
1222 Error_Msg ("duplicate ELSE line", Token_Ptr);
1225 -- Set the possibly new values of Deleting and
1228 if Pp_States.Last > 0 then
1229 if Pp_States.Table (Pp_States.Last).Match_Seen then
1230 Pp_States.Table (Pp_States.Last).Deleting :=
1234 Pp_States.Table (Pp_States.Last).Match_Seen :=
1236 Pp_States.Table (Pp_States.Last).Deleting :=
1240 -- Set the Else_Ptr to check for illegal #elsif
1243 Pp_States.Table (Pp_States.Last).Else_Ptr :=
1249 -- It is an error to have characters after "#else"
1250 if Token /= Tok_End_Of_Line
1251 and then Token /= Tok_EOF
1254 ("extraneous text on preprocessor line",
1262 if Pp_States.Last = 0 then
1263 Error_Msg ("no IF for this END", Token_Ptr);
1268 if Token /= Tok_If then
1269 Error_Msg ("IF expected", Token_Ptr);
1274 if Token /= Tok_Semicolon then
1275 Error_Msg ("`;` Expected", Token_Ptr);
1280 -- It is an error to have character after
1282 if Token /= Tok_End_Of_Line
1283 and then Token /= Tok_EOF
1286 ("extraneous text on preprocessor line",
1292 -- In case of one of the errors above, skip the tokens
1293 -- until the end of line is reached.
1297 -- Decrement the depth of the #if stack
1299 if Pp_States.Last > 0 then
1300 Pp_States.Decrement_Last;
1303 -- Illegal preprocessor line
1306 if Pp_States.Last = 0 then
1307 Error_Msg ("IF expected", Token_Ptr);
1310 Pp_States.Table (Pp_States.Last).Else_Ptr = 0
1312 Error_Msg ("IF, ELSIF, ELSE, or `END IF` expected",
1316 Error_Msg ("IF or `END IF` expected", Token_Ptr);
1319 -- Skip to the end of this illegal line
1324 -- Not a preprocessor line
1327 -- Do not report errors for those lines, even if there are
1328 -- Ada parsing errors.
1330 Set_Ignore_Errors (To => True);
1336 while Token /= Tok_End_Of_Line
1337 and then Token /= Tok_EOF
1339 if Token = Tok_Special
1340 and then Special_Character = '$
'
1343 Dollar_Ptr : constant Source_Ptr := Token_Ptr;
1348 Change_Reserved_Keyword_To_Symbol;
1350 if Token = Tok_Identifier
1351 and then Token_Ptr = Dollar_Ptr + 1
1355 Symbol := Index_Of (Token_Name);
1357 -- If symbol exists, replace by its value
1359 if Symbol /= No_Symbol then
1360 Output (Start_Of_Processing, Dollar_Ptr - 1);
1361 Start_Of_Processing := Scan_Ptr;
1362 String_To_Name_Buffer
1363 (Mapping.Table (Symbol).Value);
1365 if Mapping.Table (Symbol).Is_A_String then
1367 -- Value is an Ada string
1371 for J in 1 .. Name_Len loop
1372 Put_Char (Name_Buffer (J));
1374 if Name_Buffer (J) = '"' then
1382 -- Value is a sequence of characters, not
1385 for J in 1 .. Name_Len loop
1386 Put_Char (Name_Buffer (J));
1398 Set_Ignore_Errors (To => False);
1402 pragma Assert (Token = Tok_End_Of_Line or Token = Tok_EOF);
1404 -- At this point, the token is either end of line or EOF.
1405 -- The line to possibly output stops just before the token.
1407 Output_Line (Start_Of_Processing, Token_Ptr - 1);
1409 -- If we are at the end of a line, the scan pointer is at the first
1410 -- non blank character, not necessarily the first character of the
1411 -- line; so, we have to deduct Start_Of_Processing from the token
1414 if Token = Tok_End_Of_Line then
1415 if (Sinput.Source (Token_Ptr) = ASCII.CR
1416 and then Sinput.Source (Token_Ptr + 1) = ASCII.LF)
1418 (Sinput.Source (Token_Ptr) = ASCII.CR
1419 and then Sinput.Source (Token_Ptr + 1) = ASCII.LF)
1421 Start_Of_Processing := Token_Ptr + 2;
1423 Start_Of_Processing := Token_Ptr + 1;
1427 -- Now, scan the first token of the next line. If the token is EOF,
1428 -- the scan ponter will not move, and the token will still be EOF.
1430 Set_Ignore_Errors (To => True);
1432 Set_Ignore_Errors (To => False);
1433 end loop Input_Line_Loop;
1435 -- Report an error for any missing some "#end if;"
1437 for Level in reverse 1 .. Pp_States.Last loop
1438 Error_Msg ("no `END IF` for this IF", Pp_States.Table (Level).If_Ptr);