1 ------------------------------------------------------------------------------
3 -- GNAT COMPILER COMPONENTS --
9 -- Copyright (C) 2002-2007, 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;
30 with Osint; use Osint;
31 with Output; use Output;
32 with Scans; use Scans;
33 with Snames; use Snames;
35 with Stringt; use Stringt;
38 with GNAT.Heap_Sort_G;
44 type Token_Name_Array is array (Token_Type) of Name_Id;
45 Token_Names : constant Token_Name_Array :=
46 (Tok_Abort => Name_Abort,
48 Tok_Abstract => Name_Abstract,
49 Tok_Accept => Name_Accept,
50 Tok_Aliased => Name_Aliased,
52 Tok_Array => Name_Array,
55 Tok_Begin => Name_Begin,
56 Tok_Body => Name_Body,
57 Tok_Case => Name_Case,
58 Tok_Constant => Name_Constant,
59 Tok_Declare => Name_Declare,
60 Tok_Delay => Name_Delay,
61 Tok_Delta => Name_Delta,
62 Tok_Digits => Name_Digits,
63 Tok_Else => Name_Else,
64 Tok_Elsif => Name_Elsif,
66 Tok_Entry => Name_Entry,
67 Tok_Exception => Name_Exception,
68 Tok_Exit => Name_Exit,
70 Tok_Function => Name_Function,
71 Tok_Generic => Name_Generic,
72 Tok_Goto => Name_Goto,
75 Tok_Limited => Name_Limited,
76 Tok_Loop => Name_Loop,
79 Tok_Null => Name_Null,
82 Tok_Others => Name_Others,
84 Tok_Package => Name_Package,
85 Tok_Pragma => Name_Pragma,
86 Tok_Private => Name_Private,
87 Tok_Procedure => Name_Procedure,
88 Tok_Protected => Name_Protected,
89 Tok_Raise => Name_Raise,
90 Tok_Range => Name_Range,
91 Tok_Record => Name_Record,
93 Tok_Renames => Name_Renames,
94 Tok_Requeue => Name_Requeue,
95 Tok_Return => Name_Return,
96 Tok_Reverse => Name_Reverse,
97 Tok_Select => Name_Select,
98 Tok_Separate => Name_Separate,
99 Tok_Subtype => Name_Subtype,
100 Tok_Tagged => Name_Tagged,
101 Tok_Task => Name_Task,
102 Tok_Terminate => Name_Terminate,
103 Tok_Then => Name_Then,
104 Tok_Type => Name_Type,
105 Tok_Until => Name_Until,
107 Tok_When => Name_When,
108 Tok_While => Name_While,
109 Tok_With => Name_With,
113 Already_Initialized : Boolean := False;
114 -- Used to avoid repetition of the part of the initialisation that needs
115 -- to be done only once.
117 Empty_String : String_Id;
118 -- "", as a string_id
120 String_False : String_Id;
121 -- "false", as a string_id
123 Name_Defined : Name_Id;
124 -- defined, as a name_id
130 -- Accesses to procedure specified by procedure Initialize
132 Error_Msg : Error_Msg_Proc;
138 Set_Ignore_Errors : Set_Ignore_Errors_Proc;
139 -- Indicate if error should be taken into account
141 Put_Char : Put_Char_Proc;
142 -- Output one character
144 New_EOL : New_EOL_Proc;
145 -- Output an end of line indication
147 -------------------------------
148 -- State of the Preprocessor --
149 -------------------------------
151 type Pp_State is record
153 -- The location of the #if statement.
154 -- Used to flag #if with no corresponding #end if, at the end.
156 Else_Ptr : Source_Ptr;
157 -- The location of the #else statement.
158 -- Used to detect multiple #else.
161 -- Set to True when the code should be deleted or commented out
163 Match_Seen : Boolean;
164 -- Set to True when a condition in an #if or an #elsif is True.
165 -- Also set to True if Deleting at the previous level is True.
166 -- Used to decide if Deleting should be set to True in a following
171 type Pp_Depth is new Nat;
173 Ground : constant Pp_Depth := 0;
175 package Pp_States is new Table.Table
176 (Table_Component_Type => Pp_State,
177 Table_Index_Type => Pp_Depth,
178 Table_Low_Bound => 1,
180 Table_Increment => 100,
181 Table_Name => "Prep.Pp_States");
182 -- A stack of the states of the preprocessor, for nested #if
184 type Operator is (None, Op_Or, Op_And);
190 function Deleting return Boolean;
191 -- Return True if code should be deleted or commented out
194 (Evaluate_It : Boolean;
195 Complemented : Boolean := False) return Boolean;
196 -- Evaluate a condition in an #if or an #elsif statement.
197 -- If Evaluate_It is False, the condition is effectively evaluated,
198 -- otherwise, only the syntax is checked.
200 procedure Go_To_End_Of_Line;
201 -- Advance the scan pointer until we reach an end of line or the end
204 function Matching_Strings (S1, S2 : String_Id) return Boolean;
205 -- Returns True if the two string parameters are equal (case insensitive)
207 ---------------------------------------
208 -- Change_Reserved_Keyword_To_Symbol --
209 ---------------------------------------
211 procedure Change_Reserved_Keyword_To_Symbol
212 (All_Keywords : Boolean := False)
214 New_Name : constant Name_Id := Token_Names (Token);
217 if New_Name /= No_Name then
219 when Tok_If | Tok_Else | Tok_Elsif | Tok_End |
220 Tok_And | Tok_Or | Tok_Then =>
222 Token := Tok_Identifier;
223 Token_Name := New_Name;
227 Token := Tok_Identifier;
228 Token_Name := New_Name;
231 end Change_Reserved_Keyword_To_Symbol;
233 ------------------------------------------
234 -- Check_Command_Line_Symbol_Definition --
235 ------------------------------------------
237 procedure Check_Command_Line_Symbol_Definition
238 (Definition : String;
239 Data : out Symbol_Data)
241 Index : Natural := 0;
242 Result : Symbol_Data;
245 -- Look for the character '='
247 for J in Definition'Range loop
248 if Definition (J) = '=' then
254 -- If no character '=', then the value is True
257 -- Put the symbol in the name buffer
259 Name_Len := Definition'Length;
260 Name_Buffer (1 .. Name_Len) := Definition;
261 Result := True_Value;
263 elsif Index = Definition'First then
264 Fail ("invalid symbol definition """, Definition, """");
267 -- Put the symbol in the name buffer
269 Name_Len := Index - Definition'First;
270 Name_Buffer (1 .. Name_Len) :=
271 String'(Definition (Definition'First .. Index - 1));
273 -- Check the syntax of the value
275 if Definition (Index + 1) /= '"'
276 or else Definition (Definition'Last) /= '"'
278 for J in Index + 1 .. Definition'Last loop
279 case Definition (J) is
280 when '_' | '.' | '0' .. '9' | 'a' .. 'z' | 'A' .. 'Z' =>
284 Fail ("illegal value """,
285 Definition (Index + 1 .. Definition'Last),
291 -- And put the value in the result
293 Result.Is_A_String := False;
295 Store_String_Chars (Definition (Index + 1 .. Definition'Last));
296 Result.Value := End_String;
299 -- Now, check the syntax of the symbol (we don't allow accented and
302 if Name_Buffer (1) not in 'a' .. 'z'
303 and then Name_Buffer (1) not in 'A' .. 'Z'
306 Name_Buffer (1 .. Name_Len),
307 """ does not start with a letter");
310 for J in 2 .. Name_Len loop
311 case Name_Buffer (J) is
312 when 'a' .. 'z' | 'A' .. 'Z' | '0' .. '9' =>
318 Name_Buffer (1 .. Name_Len),
319 """ end with a '_'");
321 elsif Name_Buffer (J + 1) = '_' then
323 Name_Buffer (1 .. Name_Len),
324 """ contains consecutive '_'");
329 Name_Buffer (1 .. Name_Len),
330 """ contains illegal character(s)");
334 Result.On_The_Command_Line := True;
336 -- Put the symbol name in the result
339 Sym : constant String := Name_Buffer (1 .. Name_Len);
342 for Index in 1 .. Name_Len loop
343 Name_Buffer (Index) := Fold_Lower (Name_Buffer (Index));
346 Result.Symbol := Name_Find;
347 Name_Len := Sym'Length;
348 Name_Buffer (1 .. Name_Len) := Sym;
349 Result.Original := Name_Find;
353 end Check_Command_Line_Symbol_Definition;
359 function Deleting return Boolean is
361 -- Always return False when not inside an #if statement
363 if Pp_States.Last = Ground then
366 return Pp_States.Table (Pp_States.Last).Deleting;
375 (Evaluate_It : Boolean;
376 Complemented : Boolean := False) return Boolean
378 Evaluation : Boolean := Evaluate_It;
379 -- Is set to False after an "or else" when left term is True and
380 -- after an "and then" when left term is False.
382 Final_Result : Boolean := False;
384 Current_Result : Boolean := False;
387 Current_Operator : Operator := None;
390 Symbol_Name1 : Name_Id;
391 Symbol_Name2 : Name_Id;
392 Symbol_Pos1 : Source_Ptr;
393 Symbol_Pos2 : Source_Ptr;
394 Symbol_Value1 : String_Id;
395 Symbol_Value2 : String_Id;
398 -- Loop for each term
401 Change_Reserved_Keyword_To_Symbol;
403 Current_Result := False;
407 when Tok_Left_Paren =>
412 Current_Result := Expression (Evaluation);
414 if Token = Tok_Right_Paren then
418 Error_Msg ("`)` expected", Token_Ptr);
427 not Expression (Evaluation, Complemented => True);
429 when Tok_Identifier =>
430 Symbol_Name1 := Token_Name;
431 Symbol_Pos1 := Token_Ptr;
434 if Token = Tok_Apostrophe then
440 if Token = Tok_Identifier
441 and then Token_Name = Name_Defined
446 Error_Msg ("identifier `Defined` expected", Token_Ptr);
450 Current_Result := Index_Of (Symbol_Name1) /= No_Symbol;
453 elsif Token = Tok_Equal then
456 Change_Reserved_Keyword_To_Symbol;
458 if Token = Tok_Identifier then
462 Symbol_Name2 := Token_Name;
463 Symbol_Pos2 := Token_Ptr;
467 Symbol1 := Index_Of (Symbol_Name1);
469 if Symbol1 = No_Symbol then
470 if Undefined_Symbols_Are_False then
471 Symbol_Value1 := String_False;
474 Error_Msg_Name_1 := Symbol_Name1;
475 Error_Msg ("unknown symbol %", Symbol_Pos1);
476 Symbol_Value1 := No_String;
481 Mapping.Table (Symbol1).Value;
484 Symbol2 := Index_Of (Symbol_Name2);
486 if Symbol2 = No_Symbol then
487 if Undefined_Symbols_Are_False then
488 Symbol_Value2 := String_False;
491 Error_Msg_Name_1 := Symbol_Name2;
492 Error_Msg ("unknown symbol %", Symbol_Pos2);
493 Symbol_Value2 := No_String;
497 Symbol_Value2 := Mapping.Table (Symbol2).Value;
500 if Symbol_Value1 /= No_String
501 and then Symbol_Value2 /= No_String
503 Current_Result := Matching_Strings
504 (Symbol_Value1, Symbol_Value2);
508 elsif Token = Tok_String_Literal then
513 Symbol1 := Index_Of (Symbol_Name1);
515 if Symbol1 = No_Symbol then
516 if Undefined_Symbols_Are_False then
517 Symbol_Value1 := String_False;
520 Error_Msg_Name_1 := Symbol_Name1;
521 Error_Msg ("unknown symbol %", Symbol_Pos1);
522 Symbol_Value1 := No_String;
526 Symbol_Value1 := Mapping.Table (Symbol1).Value;
529 if Symbol_Value1 /= No_String then
541 ("symbol or literal string expected", Token_Ptr);
545 -- symbol (True or False)
548 Symbol1 := Index_Of (Symbol_Name1);
550 if Symbol1 = No_Symbol then
551 if Undefined_Symbols_Are_False then
552 Symbol_Value1 := String_False;
555 Error_Msg_Name_1 := Symbol_Name1;
556 Error_Msg ("unknown symbol %", Symbol_Pos1);
557 Symbol_Value1 := No_String;
561 Symbol_Value1 := Mapping.Table (Symbol1).Value;
564 if Symbol_Value1 /= No_String then
565 String_To_Name_Buffer (Symbol_Value1);
567 for Index in 1 .. Name_Len loop
568 Name_Buffer (Index) :=
569 Fold_Lower (Name_Buffer (Index));
572 if Name_Buffer (1 .. Name_Len) = "true" then
573 Current_Result := True;
575 elsif Name_Buffer (1 .. Name_Len) = "false" then
576 Current_Result := False;
579 Error_Msg_Name_1 := Symbol_Name1;
581 ("value of symbol % is not True or False",
589 Error_Msg ("`(`, NOT or symbol expected", Token_Ptr);
592 -- Update the cumulative final result
594 case Current_Operator is
596 Final_Result := Current_Result;
599 Final_Result := Final_Result or Current_Result;
602 Final_Result := Final_Result and Current_Result;
605 -- Check the next operator
607 if Token = Tok_And then
610 ("mixing NOT and AND is not allowed, parentheses are required",
613 elsif Current_Operator = Op_Or then
614 Error_Msg ("mixing OR and AND is not allowed", Token_Ptr);
617 Current_Operator := Op_And;
620 if Token = Tok_Then then
623 if Final_Result = False then
628 elsif Token = Tok_Or then
631 ("mixing NOT and OR is not allowed, parentheses are required",
634 elsif Current_Operator = Op_And then
635 Error_Msg ("mixing AND and OR is not allowed", Token_Ptr);
638 Current_Operator := Op_Or;
641 if Token = Tok_Else then
650 -- No operator: exit the term loop
659 -----------------------
660 -- Go_To_End_Of_Line --
661 -----------------------
663 procedure Go_To_End_Of_Line is
665 -- Scan until we get an end of line or we reach the end of the buffer
667 while Token /= Tok_End_Of_Line
668 and then Token /= Tok_EOF
672 end Go_To_End_Of_Line;
678 function Index_Of (Symbol : Name_Id) return Symbol_Id is
680 if Mapping.Table /= null then
681 for J in Symbol_Id range 1 .. Symbol_Table.Last (Mapping) loop
682 if Mapping.Table (J).Symbol = Symbol then
696 (Error_Msg : Error_Msg_Proc;
698 Set_Ignore_Errors : Set_Ignore_Errors_Proc;
699 Put_Char : Put_Char_Proc;
700 New_EOL : New_EOL_Proc)
703 if not Already_Initialized then
705 Store_String_Chars ("True");
706 True_Value.Value := End_String;
709 Empty_String := End_String;
712 Name_Buffer (1 .. Name_Len) := "defined";
713 Name_Defined := Name_Find;
716 Store_String_Chars ("False");
717 String_False := End_String;
719 Already_Initialized := True;
722 Prep.Error_Msg := Error_Msg;
724 Prep.Set_Ignore_Errors := Set_Ignore_Errors;
725 Prep.Put_Char := Put_Char;
726 Prep.New_EOL := New_EOL;
733 procedure List_Symbols (Foreword : String) is
734 Order : array (0 .. Integer (Symbol_Table.Last (Mapping)))
736 -- After alphabetical sorting, this array stores thehe indices of
737 -- the symbols in the order they are displayed.
739 function Lt (Op1, Op2 : Natural) return Boolean;
740 -- Comparison routine for sort call
742 procedure Move (From : Natural; To : Natural);
743 -- Move routine for sort call
749 function Lt (Op1, Op2 : Natural) return Boolean is
750 S1 : constant String :=
751 Get_Name_String (Mapping.Table (Order (Op1)).Symbol);
752 S2 : constant String :=
753 Get_Name_String (Mapping.Table (Order (Op2)).Symbol);
763 procedure Move (From : Natural; To : Natural) is
765 Order (To) := Order (From);
768 package Sort_Syms is new GNAT.Heap_Sort_G (Move, Lt);
771 -- Maximum length of any symbol
773 -- Start of processing for List_Symbols_Case
776 if Symbol_Table.Last (Mapping) = 0 then
780 if Foreword'Length > 0 then
782 Write_Line (Foreword);
784 for J in Foreword'Range loop
789 -- Initialize the order
791 for J in Order'Range loop
792 Order (J) := Symbol_Id (J);
795 -- Sort alphabetically
797 Sort_Syms.Sort (Order'Last);
801 for J in 1 .. Symbol_Table.Last (Mapping) loop
802 Get_Name_String (Mapping.Table (J).Original);
803 Max_L := Integer'Max (Max_L, Name_Len);
807 Write_Str ("Symbol");
809 for J in 1 .. Max_L - 5 loop
813 Write_Line ("Value");
815 Write_Str ("------");
817 for J in 1 .. Max_L - 5 loop
821 Write_Line ("------");
823 for J in 1 .. Order'Last loop
825 Data : constant Symbol_Data := Mapping.Table (Order (J));
828 Get_Name_String (Data.Original);
829 Write_Str (Name_Buffer (1 .. Name_Len));
831 for K in Name_Len .. Max_L loop
835 String_To_Name_Buffer (Data.Value);
837 if Data.Is_A_String then
840 for J in 1 .. Name_Len loop
841 Write_Char (Name_Buffer (J));
843 if Name_Buffer (J) = '"' then
851 Write_Str (Name_Buffer (1 .. Name_Len));
861 ----------------------
862 -- Matching_Strings --
863 ----------------------
865 function Matching_Strings (S1, S2 : String_Id) return Boolean is
867 String_To_Name_Buffer (S1);
869 for Index in 1 .. Name_Len loop
870 Name_Buffer (Index) := Fold_Lower (Name_Buffer (Index));
874 String1 : constant String := Name_Buffer (1 .. Name_Len);
877 String_To_Name_Buffer (S2);
879 for Index in 1 .. Name_Len loop
880 Name_Buffer (Index) := Fold_Lower (Name_Buffer (Index));
883 return String1 = Name_Buffer (1 .. Name_Len);
885 end Matching_Strings;
891 procedure Parse_Def_File is
893 Symbol_Name : Name_Id;
894 Original_Name : Name_Id;
896 Value_Start : Source_Ptr;
897 Value_End : Source_Ptr;
907 exit Def_Line_Loop when Token = Tok_EOF;
909 if Token /= Tok_End_Of_Line then
910 Change_Reserved_Keyword_To_Symbol;
912 if Token /= Tok_Identifier then
913 Error_Msg ("identifier expected", Token_Ptr);
917 Symbol_Name := Token_Name;
920 for Ptr in Token_Ptr .. Scan_Ptr - 1 loop
921 Name_Len := Name_Len + 1;
922 Name_Buffer (Name_Len) := Sinput.Source (Ptr);
925 Original_Name := Name_Find;
928 if Token /= Tok_Colon_Equal then
929 Error_Msg ("`:=` expected", Token_Ptr);
935 if Token = Tok_String_Literal then
936 Data := (Symbol => Symbol_Name,
937 Original => Original_Name,
938 On_The_Command_Line => False,
940 Value => String_Literal_Id);
944 if Token /= Tok_End_Of_Line and then Token /= Tok_EOF then
945 Error_Msg ("extraneous text in definition", Token_Ptr);
949 elsif Token = Tok_End_Of_Line or Token = Tok_EOF then
950 Data := (Symbol => Symbol_Name,
951 Original => Original_Name,
952 On_The_Command_Line => False,
953 Is_A_String => False,
954 Value => Empty_String);
957 Value_Start := Token_Ptr;
958 Value_End := Token_Ptr - 1;
959 Scan_Ptr := Token_Ptr;
963 Ch := Sinput.Source (Scan_Ptr);
966 when '_' | '.' | '0' .. '9' | 'a' .. 'z' | 'A' .. 'Z' =>
967 Value_End := Scan_Ptr;
968 Scan_Ptr := Scan_Ptr + 1;
970 when ' ' | HT | VT | CR | LF | FF =>
971 exit Value_Chars_Loop;
974 Error_Msg ("illegal character", Scan_Ptr);
977 end loop Value_Chars_Loop;
981 if Token /= Tok_End_Of_Line and then Token /= Tok_EOF then
982 Error_Msg ("extraneous text in definition", Token_Ptr);
988 while Value_Start <= Value_End loop
989 Store_String_Char (Sinput.Source (Value_Start));
990 Value_Start := Value_Start + 1;
993 Data := (Symbol => Symbol_Name,
994 Original => Original_Name,
995 On_The_Command_Line => False,
996 Is_A_String => False,
997 Value => End_String);
1000 -- Now that we have the value, get the symbol index
1002 Symbol := Index_Of (Symbol_Name);
1004 if Symbol /= No_Symbol then
1005 -- If we already have an entry for this symbol, replace it
1006 -- with the new value, except if the symbol was declared
1007 -- on the command line.
1009 if Mapping.Table (Symbol).On_The_Command_Line then
1014 -- As it is the first time we see this symbol, create a new
1015 -- entry in the table.
1017 if Mapping.Table = null then
1018 Symbol_Table.Init (Mapping);
1021 Symbol_Table.Increment_Last (Mapping);
1022 Symbol := Symbol_Table.Last (Mapping);
1025 Mapping.Table (Symbol) := Data;
1029 Set_Ignore_Errors (To => True);
1031 while Token /= Tok_End_Of_Line and Token /= Tok_EOF loop
1035 Set_Ignore_Errors (To => False);
1040 end loop Def_Line_Loop;
1047 procedure Preprocess is
1048 Start_Of_Processing : Source_Ptr;
1050 Preprocessor_Line : Boolean := False;
1052 procedure Output (From, To : Source_Ptr);
1053 -- Output the characters with indices From .. To in the buffer
1054 -- to the output file.
1056 procedure Output_Line (From, To : Source_Ptr);
1057 -- Output a line or the end of a line from the buffer to the output
1058 -- file, followed by an end of line terminator. Depending on the value
1059 -- of Deleting and the switches, the line may be commented out, blank or
1060 -- not output at all.
1066 procedure Output (From, To : Source_Ptr) is
1068 for J in From .. To loop
1069 Put_Char (Sinput.Source (J));
1077 procedure Output_Line (From, To : Source_Ptr) is
1079 if Deleting or Preprocessor_Line then
1080 if Blank_Deleted_Lines then
1083 elsif Comment_Deleted_Lines then
1102 -- Start of processing for Preprocess
1105 Start_Of_Processing := Scan_Ptr;
1107 -- We need to call Scan for the first time, because Initialize_Scanner
1108 -- is no longer doing it.
1112 Input_Line_Loop : loop
1113 exit Input_Line_Loop when Token = Tok_EOF;
1115 Preprocessor_Line := False;
1117 if Token /= Tok_End_Of_Line then
1119 -- Preprocessor line
1121 if Token = Tok_Special and then Special_Character = '#' then
1122 Preprocessor_Line := True;
1131 If_Ptr : constant Source_Ptr := Token_Ptr;
1135 Cond := Expression (not Deleting);
1137 -- Check for an eventual "then"
1139 if Token = Tok_Then then
1143 -- It is an error to have trailing characters after
1144 -- the condition or "then".
1146 if Token /= Tok_End_Of_Line
1147 and then Token /= Tok_EOF
1150 ("extraneous text on preprocessor line",
1156 -- Set the initial state of this new "#if".
1157 -- This must be done before incrementing the
1158 -- Last of the table, otherwise function
1159 -- Deleting does not report the correct value.
1161 New_State : constant Pp_State :=
1164 Deleting => Deleting or (not Cond),
1165 Match_Seen => Deleting or Cond);
1168 Pp_States.Increment_Last;
1169 Pp_States.Table (Pp_States.Last) := New_State;
1178 if Pp_States.Last = 0
1179 or else Pp_States.Table (Pp_States.Last).Else_Ptr
1182 Error_Msg ("no IF for this ELSIF", Token_Ptr);
1186 not Pp_States.Table (Pp_States.Last).Match_Seen;
1190 Cond := Expression (Cond);
1192 -- Check for an eventual "then"
1194 if Token = Tok_Then then
1198 -- It is an error to have trailing characters after
1199 -- the condition or "then".
1201 if Token /= Tok_End_Of_Line
1202 and then Token /= Tok_EOF
1205 ("extraneous text on preprocessor line",
1211 -- Depending on the value of the condition, set the
1212 -- new values of Deleting and Match_Seen.
1213 if Pp_States.Last > 0 then
1214 if Pp_States.Table (Pp_States.Last).Match_Seen then
1215 Pp_States.Table (Pp_States.Last).Deleting :=
1219 Pp_States.Table (Pp_States.Last).Match_Seen :=
1221 Pp_States.Table (Pp_States.Last).Deleting :=
1230 if Pp_States.Last = 0 then
1231 Error_Msg ("no IF for this ELSE", Token_Ptr);
1234 Pp_States.Table (Pp_States.Last).Else_Ptr /= 0
1236 Error_Msg ("duplicate ELSE line", Token_Ptr);
1239 -- Set the possibly new values of Deleting and
1242 if Pp_States.Last > 0 then
1243 if Pp_States.Table (Pp_States.Last).Match_Seen then
1244 Pp_States.Table (Pp_States.Last).Deleting :=
1248 Pp_States.Table (Pp_States.Last).Match_Seen :=
1250 Pp_States.Table (Pp_States.Last).Deleting :=
1254 -- Set the Else_Ptr to check for illegal #elsif
1257 Pp_States.Table (Pp_States.Last).Else_Ptr :=
1263 -- It is an error to have characters after "#else"
1264 if Token /= Tok_End_Of_Line
1265 and then Token /= Tok_EOF
1268 ("extraneous text on preprocessor line",
1276 if Pp_States.Last = 0 then
1277 Error_Msg ("no IF for this END", Token_Ptr);
1282 if Token /= Tok_If then
1283 Error_Msg ("IF expected", Token_Ptr);
1288 if Token /= Tok_Semicolon then
1289 Error_Msg ("`;` Expected", Token_Ptr);
1294 -- It is an error to have character after
1296 if Token /= Tok_End_Of_Line
1297 and then Token /= Tok_EOF
1300 ("extraneous text on preprocessor line",
1306 -- In case of one of the errors above, skip the tokens
1307 -- until the end of line is reached.
1311 -- Decrement the depth of the #if stack
1313 if Pp_States.Last > 0 then
1314 Pp_States.Decrement_Last;
1317 -- Illegal preprocessor line
1320 if Pp_States.Last = 0 then
1321 Error_Msg ("IF expected", Token_Ptr);
1324 Pp_States.Table (Pp_States.Last).Else_Ptr = 0
1326 Error_Msg ("IF, ELSIF, ELSE, or `END IF` expected",
1330 Error_Msg ("IF or `END IF` expected", Token_Ptr);
1333 -- Skip to the end of this illegal line
1338 -- Not a preprocessor line
1341 -- Do not report errors for those lines, even if there are
1342 -- Ada parsing errors.
1344 Set_Ignore_Errors (To => True);
1350 while Token /= Tok_End_Of_Line
1351 and then Token /= Tok_EOF
1353 if Token = Tok_Special
1354 and then Special_Character = '$'
1357 Dollar_Ptr : constant Source_Ptr := Token_Ptr;
1362 Change_Reserved_Keyword_To_Symbol;
1364 if Token = Tok_Identifier
1365 and then Token_Ptr = Dollar_Ptr + 1
1369 Symbol := Index_Of (Token_Name);
1371 -- If symbol exists, replace by its value
1373 if Symbol /= No_Symbol then
1374 Output (Start_Of_Processing, Dollar_Ptr - 1);
1375 Start_Of_Processing := Scan_Ptr;
1376 String_To_Name_Buffer
1377 (Mapping.Table (Symbol).Value);
1379 if Mapping.Table (Symbol).Is_A_String then
1381 -- Value is an Ada string
1385 for J in 1 .. Name_Len loop
1386 Put_Char (Name_Buffer (J));
1388 if Name_Buffer (J) = '"' then
1396 -- Value is a sequence of characters, not
1399 for J in 1 .. Name_Len loop
1400 Put_Char (Name_Buffer (J));
1412 Set_Ignore_Errors (To => False);
1416 pragma Assert (Token = Tok_End_Of_Line or Token = Tok_EOF);
1418 -- At this point, the token is either end of line or EOF.
1419 -- The line to possibly output stops just before the token.
1421 Output_Line (Start_Of_Processing, Token_Ptr - 1);
1423 -- If we are at the end of a line, the scan pointer is at the first
1424 -- non blank character, not necessarily the first character of the
1425 -- line; so, we have to deduct Start_Of_Processing from the token
1428 if Token = Tok_End_Of_Line then
1429 if (Sinput.Source (Token_Ptr) = ASCII.CR
1430 and then Sinput.Source (Token_Ptr + 1) = ASCII.LF)
1432 (Sinput.Source (Token_Ptr) = ASCII.CR
1433 and then Sinput.Source (Token_Ptr + 1) = ASCII.LF)
1435 Start_Of_Processing := Token_Ptr + 2;
1437 Start_Of_Processing := Token_Ptr + 1;
1441 -- Now, scan the first token of the next line. If the token is EOF,
1442 -- the scan ponter will not move, and the token will still be EOF.
1444 Set_Ignore_Errors (To => True);
1446 Set_Ignore_Errors (To => False);
1447 end loop Input_Line_Loop;
1449 -- Report an error for any missing some "#end if;"
1451 for Level in reverse 1 .. Pp_States.Last loop
1452 Error_Msg ("no `END IF` for this IF", Pp_States.Table (Level).If_Ptr);