cfgloopmanip.c (copy_loop_info): New function.
[official-gcc.git] / gcc / ada / prep.adb
blob3ec2087926a0a7fd068752794e72a29b89998b50
1 ------------------------------------------------------------------------------
2 -- --
3 -- GNAT COMPILER COMPONENTS --
4 -- --
5 -- P R E P --
6 -- --
7 -- B o d y --
8 -- --
9 -- Copyright (C) 2002-2012, 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 Csets; use Csets;
27 with Err_Vars; use Err_Vars;
28 with Opt; use Opt;
29 with Osint; use Osint;
30 with Output; use Output;
31 with Scans; use Scans;
32 with Snames; use Snames;
33 with Sinput;
34 with Stringt; use Stringt;
35 with Table;
37 with GNAT.Heap_Sort_G;
39 package body Prep is
41 use Symbol_Table;
43 type Token_Name_Array is array (Token_Type) of Name_Id;
44 Token_Names : constant Token_Name_Array :=
45 (Tok_Abort => Name_Abort,
46 Tok_Abs => Name_Abs,
47 Tok_Abstract => Name_Abstract,
48 Tok_Accept => Name_Accept,
49 Tok_Aliased => Name_Aliased,
50 Tok_All => Name_All,
51 Tok_Array => Name_Array,
52 Tok_And => Name_And,
53 Tok_At => Name_At,
54 Tok_Begin => Name_Begin,
55 Tok_Body => Name_Body,
56 Tok_Case => Name_Case,
57 Tok_Constant => Name_Constant,
58 Tok_Declare => Name_Declare,
59 Tok_Delay => Name_Delay,
60 Tok_Delta => Name_Delta,
61 Tok_Digits => Name_Digits,
62 Tok_Else => Name_Else,
63 Tok_Elsif => Name_Elsif,
64 Tok_End => Name_End,
65 Tok_Entry => Name_Entry,
66 Tok_Exception => Name_Exception,
67 Tok_Exit => Name_Exit,
68 Tok_For => Name_For,
69 Tok_Function => Name_Function,
70 Tok_Generic => Name_Generic,
71 Tok_Goto => Name_Goto,
72 Tok_If => Name_If,
73 Tok_Is => Name_Is,
74 Tok_Limited => Name_Limited,
75 Tok_Loop => Name_Loop,
76 Tok_Mod => Name_Mod,
77 Tok_New => Name_New,
78 Tok_Null => Name_Null,
79 Tok_Of => Name_Of,
80 Tok_Or => Name_Or,
81 Tok_Others => Name_Others,
82 Tok_Out => Name_Out,
83 Tok_Package => Name_Package,
84 Tok_Pragma => Name_Pragma,
85 Tok_Private => Name_Private,
86 Tok_Procedure => Name_Procedure,
87 Tok_Protected => Name_Protected,
88 Tok_Raise => Name_Raise,
89 Tok_Range => Name_Range,
90 Tok_Record => Name_Record,
91 Tok_Rem => Name_Rem,
92 Tok_Renames => Name_Renames,
93 Tok_Requeue => Name_Requeue,
94 Tok_Return => Name_Return,
95 Tok_Reverse => Name_Reverse,
96 Tok_Select => Name_Select,
97 Tok_Separate => Name_Separate,
98 Tok_Subtype => Name_Subtype,
99 Tok_Tagged => Name_Tagged,
100 Tok_Task => Name_Task,
101 Tok_Terminate => Name_Terminate,
102 Tok_Then => Name_Then,
103 Tok_Type => Name_Type,
104 Tok_Until => Name_Until,
105 Tok_Use => Name_Use,
106 Tok_When => Name_When,
107 Tok_While => Name_While,
108 Tok_With => Name_With,
109 Tok_Xor => Name_Xor,
110 others => No_Name);
112 Already_Initialized : Boolean := False;
113 -- Used to avoid repetition of the part of the initialisation that needs
114 -- to be done only once.
116 Empty_String : String_Id;
117 -- "", as a string_id
119 String_False : String_Id;
120 -- "false", as a string_id
122 ---------------
123 -- Behaviour --
124 ---------------
126 -- Accesses to procedure specified by procedure Initialize
128 Error_Msg : Error_Msg_Proc;
129 -- Report an error
131 Scan : Scan_Proc;
132 -- Scan one token
134 Set_Ignore_Errors : Set_Ignore_Errors_Proc;
135 -- Indicate if error should be taken into account
137 Put_Char : Put_Char_Proc;
138 -- Output one character
140 New_EOL : New_EOL_Proc;
141 -- Output an end of line indication
143 -------------------------------
144 -- State of the Preprocessor --
145 -------------------------------
147 type Pp_State is record
148 If_Ptr : Source_Ptr;
149 -- The location of the #if statement.
150 -- Used to flag #if with no corresponding #end if, at the end.
152 Else_Ptr : Source_Ptr;
153 -- The location of the #else statement.
154 -- Used to detect multiple #else.
156 Deleting : Boolean;
157 -- Set to True when the code should be deleted or commented out
159 Match_Seen : Boolean;
160 -- Set to True when a condition in an #if or an #elsif is True.
161 -- Also set to True if Deleting at the previous level is True.
162 -- Used to decide if Deleting should be set to True in a following
163 -- #elsif or #else.
165 end record;
167 type Pp_Depth is new Nat;
169 Ground : constant Pp_Depth := 0;
171 package Pp_States is new Table.Table
172 (Table_Component_Type => Pp_State,
173 Table_Index_Type => Pp_Depth,
174 Table_Low_Bound => 1,
175 Table_Initial => 10,
176 Table_Increment => 100,
177 Table_Name => "Prep.Pp_States");
178 -- A stack of the states of the preprocessor, for nested #if
180 type Operator is (None, Op_Or, Op_And);
182 -----------------
183 -- Subprograms --
184 -----------------
186 function Deleting return Boolean;
187 -- Return True if code should be deleted or commented out
189 function Expression
190 (Evaluate_It : Boolean;
191 Complemented : Boolean := False) return Boolean;
192 -- Evaluate a condition in an #if or an #elsif statement.
193 -- If Evaluate_It is False, the condition is effectively evaluated,
194 -- otherwise, only the syntax is checked.
196 procedure Go_To_End_Of_Line;
197 -- Advance the scan pointer until we reach an end of line or the end
198 -- of the buffer.
200 function Matching_Strings (S1, S2 : String_Id) return Boolean;
201 -- Returns True if the two string parameters are equal (case insensitive)
203 ---------------------------------------
204 -- Change_Reserved_Keyword_To_Symbol --
205 ---------------------------------------
207 procedure Change_Reserved_Keyword_To_Symbol
208 (All_Keywords : Boolean := False)
210 New_Name : constant Name_Id := Token_Names (Token);
212 begin
213 if New_Name /= No_Name then
214 case Token is
215 when Tok_If | Tok_Else | Tok_Elsif | Tok_End |
216 Tok_And | Tok_Or | Tok_Then =>
217 if All_Keywords then
218 Token := Tok_Identifier;
219 Token_Name := New_Name;
220 end if;
222 when others =>
223 Token := Tok_Identifier;
224 Token_Name := New_Name;
225 end case;
226 end if;
227 end Change_Reserved_Keyword_To_Symbol;
229 ------------------------------------------
230 -- Check_Command_Line_Symbol_Definition --
231 ------------------------------------------
233 procedure Check_Command_Line_Symbol_Definition
234 (Definition : String;
235 Data : out Symbol_Data)
237 Index : Natural := 0;
238 Result : Symbol_Data;
240 begin
241 -- Look for the character '='
243 for J in Definition'Range loop
244 if Definition (J) = '=' then
245 Index := J;
246 exit;
247 end if;
248 end loop;
250 -- If no character '=', then the value is True
252 if Index = 0 then
253 -- Put the symbol in the name buffer
255 Name_Len := Definition'Length;
256 Name_Buffer (1 .. Name_Len) := Definition;
257 Result := True_Value;
259 elsif Index = Definition'First then
260 Fail ("invalid symbol definition """ & Definition & """");
262 else
263 -- Put the symbol in the name buffer
265 Name_Len := Index - Definition'First;
266 Name_Buffer (1 .. Name_Len) :=
267 String'(Definition (Definition'First .. Index - 1));
269 -- Check the syntax of the value
271 if Definition (Index + 1) /= '"'
272 or else Definition (Definition'Last) /= '"'
273 then
274 for J in Index + 1 .. Definition'Last loop
275 case Definition (J) is
276 when '_' | '.' | '0' .. '9' | 'a' .. 'z' | 'A' .. 'Z' =>
277 null;
279 when others =>
280 Fail ("illegal value """
281 & Definition (Index + 1 .. Definition'Last)
282 & """");
283 end case;
284 end loop;
285 end if;
287 -- And put the value in the result
289 Result.Is_A_String := False;
290 Start_String;
291 Store_String_Chars (Definition (Index + 1 .. Definition'Last));
292 Result.Value := End_String;
293 end if;
295 -- Now, check the syntax of the symbol (we don't allow accented or
296 -- wide characters).
298 if Name_Buffer (1) not in 'a' .. 'z'
299 and then Name_Buffer (1) not in 'A' .. 'Z'
300 then
301 Fail ("symbol """
302 & Name_Buffer (1 .. Name_Len)
303 & """ does not start with a letter");
304 end if;
306 for J in 2 .. Name_Len loop
307 case Name_Buffer (J) is
308 when 'a' .. 'z' | 'A' .. 'Z' | '0' .. '9' =>
309 null;
311 when '_' =>
312 if J = Name_Len then
313 Fail ("symbol """
314 & Name_Buffer (1 .. Name_Len)
315 & """ end with a '_'");
317 elsif Name_Buffer (J + 1) = '_' then
318 Fail ("symbol """
319 & Name_Buffer (1 .. Name_Len)
320 & """ contains consecutive '_'");
321 end if;
323 when others =>
324 Fail ("symbol """
325 & Name_Buffer (1 .. Name_Len)
326 & """ contains illegal character(s)");
327 end case;
328 end loop;
330 Result.On_The_Command_Line := True;
332 -- Put the symbol name in the result
334 declare
335 Sym : constant String := Name_Buffer (1 .. Name_Len);
337 begin
338 for Index in 1 .. Name_Len loop
339 Name_Buffer (Index) := Fold_Lower (Name_Buffer (Index));
340 end loop;
342 Result.Symbol := Name_Find;
343 Name_Len := Sym'Length;
344 Name_Buffer (1 .. Name_Len) := Sym;
345 Result.Original := Name_Find;
346 end;
348 Data := Result;
349 end Check_Command_Line_Symbol_Definition;
351 --------------
352 -- Deleting --
353 --------------
355 function Deleting return Boolean is
356 begin
357 -- Always return False when not inside an #if statement
359 if Opt.No_Deletion or else Pp_States.Last = Ground then
360 return False;
361 else
362 return Pp_States.Table (Pp_States.Last).Deleting;
363 end if;
364 end Deleting;
366 ----------------
367 -- Expression --
368 ----------------
370 function Expression
371 (Evaluate_It : Boolean;
372 Complemented : Boolean := False) return Boolean
374 Evaluation : Boolean := Evaluate_It;
375 -- Is set to False after an "or else" when left term is True and
376 -- after an "and then" when left term is False.
378 Final_Result : Boolean := False;
380 Current_Result : Boolean := False;
381 -- Value of a term
383 Current_Operator : Operator := None;
384 Symbol1 : Symbol_Id;
385 Symbol2 : Symbol_Id;
386 Symbol_Name1 : Name_Id;
387 Symbol_Name2 : Name_Id;
388 Symbol_Pos1 : Source_Ptr;
389 Symbol_Pos2 : Source_Ptr;
390 Symbol_Value1 : String_Id;
391 Symbol_Value2 : String_Id;
393 begin
394 -- Loop for each term
396 loop
397 Change_Reserved_Keyword_To_Symbol;
399 Current_Result := False;
401 case Token is
403 when Tok_Left_Paren =>
405 -- ( expression )
407 Scan.all;
408 Current_Result := Expression (Evaluation);
410 if Token = Tok_Right_Paren then
411 Scan.all;
413 else
414 Error_Msg -- CODEFIX
415 ("`)` expected", Token_Ptr);
416 end if;
418 when Tok_Not =>
420 -- not expression
422 Scan.all;
423 Current_Result :=
424 not Expression (Evaluation, Complemented => True);
426 when Tok_Identifier =>
427 Symbol_Name1 := Token_Name;
428 Symbol_Pos1 := Token_Ptr;
429 Scan.all;
431 if Token = Tok_Apostrophe then
433 -- symbol'Defined
435 Scan.all;
437 if Token = Tok_Identifier
438 and then Token_Name = Name_Defined
439 then
440 Scan.all;
442 else
443 Error_Msg ("identifier `Defined` expected", Token_Ptr);
444 end if;
446 if Evaluation then
447 Current_Result := Index_Of (Symbol_Name1) /= No_Symbol;
448 end if;
450 elsif Token = Tok_Equal then
451 Scan.all;
453 Change_Reserved_Keyword_To_Symbol;
455 if Token = Tok_Identifier then
457 -- symbol = symbol
459 Symbol_Name2 := Token_Name;
460 Symbol_Pos2 := Token_Ptr;
461 Scan.all;
463 if Evaluation then
464 Symbol1 := Index_Of (Symbol_Name1);
466 if Symbol1 = No_Symbol then
467 if Undefined_Symbols_Are_False then
468 Symbol_Value1 := String_False;
470 else
471 Error_Msg_Name_1 := Symbol_Name1;
472 Error_Msg ("unknown symbol %", Symbol_Pos1);
473 Symbol_Value1 := No_String;
474 end if;
476 else
477 Symbol_Value1 :=
478 Mapping.Table (Symbol1).Value;
479 end if;
481 Symbol2 := Index_Of (Symbol_Name2);
483 if Symbol2 = No_Symbol then
484 if Undefined_Symbols_Are_False then
485 Symbol_Value2 := String_False;
487 else
488 Error_Msg_Name_1 := Symbol_Name2;
489 Error_Msg ("unknown symbol %", Symbol_Pos2);
490 Symbol_Value2 := No_String;
491 end if;
493 else
494 Symbol_Value2 := Mapping.Table (Symbol2).Value;
495 end if;
497 if Symbol_Value1 /= No_String
498 and then Symbol_Value2 /= No_String
499 then
500 Current_Result := Matching_Strings
501 (Symbol_Value1, Symbol_Value2);
502 end if;
503 end if;
505 elsif Token = Tok_String_Literal then
507 -- symbol = "value"
509 if Evaluation then
510 Symbol1 := Index_Of (Symbol_Name1);
512 if Symbol1 = No_Symbol then
513 if Undefined_Symbols_Are_False then
514 Symbol_Value1 := String_False;
516 else
517 Error_Msg_Name_1 := Symbol_Name1;
518 Error_Msg ("unknown symbol %", Symbol_Pos1);
519 Symbol_Value1 := No_String;
520 end if;
522 else
523 Symbol_Value1 := Mapping.Table (Symbol1).Value;
524 end if;
526 if Symbol_Value1 /= No_String then
527 Current_Result :=
528 Matching_Strings
529 (Symbol_Value1,
530 String_Literal_Id);
531 end if;
532 end if;
534 Scan.all;
536 else
537 Error_Msg
538 ("symbol or literal string expected", Token_Ptr);
539 end if;
541 else
542 -- symbol (True or False)
544 if Evaluation then
545 Symbol1 := Index_Of (Symbol_Name1);
547 if Symbol1 = No_Symbol then
548 if Undefined_Symbols_Are_False then
549 Symbol_Value1 := String_False;
551 else
552 Error_Msg_Name_1 := Symbol_Name1;
553 Error_Msg ("unknown symbol %", Symbol_Pos1);
554 Symbol_Value1 := No_String;
555 end if;
557 else
558 Symbol_Value1 := Mapping.Table (Symbol1).Value;
559 end if;
561 if Symbol_Value1 /= No_String then
562 String_To_Name_Buffer (Symbol_Value1);
564 for Index in 1 .. Name_Len loop
565 Name_Buffer (Index) :=
566 Fold_Lower (Name_Buffer (Index));
567 end loop;
569 if Name_Buffer (1 .. Name_Len) = "true" then
570 Current_Result := True;
572 elsif Name_Buffer (1 .. Name_Len) = "false" then
573 Current_Result := False;
575 else
576 Error_Msg_Name_1 := Symbol_Name1;
577 Error_Msg
578 ("value of symbol % is not True or False",
579 Symbol_Pos1);
580 end if;
581 end if;
582 end if;
583 end if;
585 when others =>
586 Error_Msg ("`(`, NOT or symbol expected", Token_Ptr);
587 end case;
589 -- Update the cumulative final result
591 case Current_Operator is
592 when None =>
593 Final_Result := Current_Result;
595 when Op_Or =>
596 Final_Result := Final_Result or Current_Result;
598 when Op_And =>
599 Final_Result := Final_Result and Current_Result;
600 end case;
602 -- Check the next operator
604 if Token = Tok_And then
605 if Complemented then
606 Error_Msg
607 ("mixing NOT and AND is not allowed, parentheses are required",
608 Token_Ptr);
610 elsif Current_Operator = Op_Or then
611 Error_Msg ("mixing OR and AND is not allowed", Token_Ptr);
612 end if;
614 Current_Operator := Op_And;
615 Scan.all;
617 if Token = Tok_Then then
618 Scan.all;
620 if Final_Result = False then
621 Evaluation := False;
622 end if;
623 end if;
625 elsif Token = Tok_Or then
626 if Complemented then
627 Error_Msg
628 ("mixing NOT and OR is not allowed, parentheses are required",
629 Token_Ptr);
631 elsif Current_Operator = Op_And then
632 Error_Msg ("mixing AND and OR is not allowed", Token_Ptr);
633 end if;
635 Current_Operator := Op_Or;
636 Scan.all;
638 if Token = Tok_Else then
639 Scan.all;
641 if Final_Result then
642 Evaluation := False;
643 end if;
644 end if;
646 else
647 -- No operator: exit the term loop
649 exit;
650 end if;
651 end loop;
653 return Final_Result;
654 end Expression;
656 -----------------------
657 -- Go_To_End_Of_Line --
658 -----------------------
660 procedure Go_To_End_Of_Line is
661 begin
662 -- Scan until we get an end of line or we reach the end of the buffer
664 while Token /= Tok_End_Of_Line
665 and then Token /= Tok_EOF
666 loop
667 Scan.all;
668 end loop;
669 end Go_To_End_Of_Line;
671 --------------
672 -- Index_Of --
673 --------------
675 function Index_Of (Symbol : Name_Id) return Symbol_Id is
676 begin
677 if Mapping.Table /= null then
678 for J in Symbol_Id range 1 .. Symbol_Table.Last (Mapping) loop
679 if Mapping.Table (J).Symbol = Symbol then
680 return J;
681 end if;
682 end loop;
683 end if;
685 return No_Symbol;
686 end Index_Of;
688 ----------------
689 -- Initialize --
690 ----------------
692 procedure Initialize is
693 begin
694 if not Already_Initialized then
695 Start_String;
696 Store_String_Chars ("True");
697 True_Value.Value := End_String;
699 Start_String;
700 Empty_String := End_String;
702 Start_String;
703 Store_String_Chars ("False");
704 String_False := End_String;
706 Already_Initialized := True;
707 end if;
708 end Initialize;
710 ------------------
711 -- List_Symbols --
712 ------------------
714 procedure List_Symbols (Foreword : String) is
715 Order : array (0 .. Integer (Symbol_Table.Last (Mapping)))
716 of Symbol_Id;
717 -- After alphabetical sorting, this array stores the indexes of the
718 -- symbols in the order they are displayed.
720 function Lt (Op1, Op2 : Natural) return Boolean;
721 -- Comparison routine for sort call
723 procedure Move (From : Natural; To : Natural);
724 -- Move routine for sort call
726 --------
727 -- Lt --
728 --------
730 function Lt (Op1, Op2 : Natural) return Boolean is
731 S1 : constant String :=
732 Get_Name_String (Mapping.Table (Order (Op1)).Symbol);
733 S2 : constant String :=
734 Get_Name_String (Mapping.Table (Order (Op2)).Symbol);
736 begin
737 return S1 < S2;
738 end Lt;
740 ----------
741 -- Move --
742 ----------
744 procedure Move (From : Natural; To : Natural) is
745 begin
746 Order (To) := Order (From);
747 end Move;
749 package Sort_Syms is new GNAT.Heap_Sort_G (Move, Lt);
751 Max_L : Natural;
752 -- Maximum length of any symbol
754 -- Start of processing for List_Symbols_Case
756 begin
757 if Symbol_Table.Last (Mapping) = 0 then
758 return;
759 end if;
761 if Foreword'Length > 0 then
762 Write_Eol;
763 Write_Line (Foreword);
765 for J in Foreword'Range loop
766 Write_Char ('=');
767 end loop;
768 end if;
770 -- Initialize the order
772 for J in Order'Range loop
773 Order (J) := Symbol_Id (J);
774 end loop;
776 -- Sort alphabetically
778 Sort_Syms.Sort (Order'Last);
780 Max_L := 7;
782 for J in 1 .. Symbol_Table.Last (Mapping) loop
783 Get_Name_String (Mapping.Table (J).Original);
784 Max_L := Integer'Max (Max_L, Name_Len);
785 end loop;
787 Write_Eol;
788 Write_Str ("Symbol");
790 for J in 1 .. Max_L - 5 loop
791 Write_Char (' ');
792 end loop;
794 Write_Line ("Value");
796 Write_Str ("------");
798 for J in 1 .. Max_L - 5 loop
799 Write_Char (' ');
800 end loop;
802 Write_Line ("------");
804 for J in 1 .. Order'Last loop
805 declare
806 Data : constant Symbol_Data := Mapping.Table (Order (J));
808 begin
809 Get_Name_String (Data.Original);
810 Write_Str (Name_Buffer (1 .. Name_Len));
812 for K in Name_Len .. Max_L loop
813 Write_Char (' ');
814 end loop;
816 String_To_Name_Buffer (Data.Value);
818 if Data.Is_A_String then
819 Write_Char ('"');
821 for J in 1 .. Name_Len loop
822 Write_Char (Name_Buffer (J));
824 if Name_Buffer (J) = '"' then
825 Write_Char ('"');
826 end if;
827 end loop;
829 Write_Char ('"');
831 else
832 Write_Str (Name_Buffer (1 .. Name_Len));
833 end if;
834 end;
836 Write_Eol;
837 end loop;
839 Write_Eol;
840 end List_Symbols;
842 ----------------------
843 -- Matching_Strings --
844 ----------------------
846 function Matching_Strings (S1, S2 : String_Id) return Boolean is
847 begin
848 String_To_Name_Buffer (S1);
850 for Index in 1 .. Name_Len loop
851 Name_Buffer (Index) := Fold_Lower (Name_Buffer (Index));
852 end loop;
854 declare
855 String1 : constant String := Name_Buffer (1 .. Name_Len);
857 begin
858 String_To_Name_Buffer (S2);
860 for Index in 1 .. Name_Len loop
861 Name_Buffer (Index) := Fold_Lower (Name_Buffer (Index));
862 end loop;
864 return String1 = Name_Buffer (1 .. Name_Len);
865 end;
866 end Matching_Strings;
868 --------------------
869 -- Parse_Def_File --
870 --------------------
872 procedure Parse_Def_File is
873 Symbol : Symbol_Id;
874 Symbol_Name : Name_Id;
875 Original_Name : Name_Id;
876 Data : Symbol_Data;
877 Value_Start : Source_Ptr;
878 Value_End : Source_Ptr;
879 Ch : Character;
881 use ASCII;
883 begin
884 Def_Line_Loop :
885 loop
886 Scan.all;
888 exit Def_Line_Loop when Token = Tok_EOF;
890 if Token /= Tok_End_Of_Line then
891 Change_Reserved_Keyword_To_Symbol;
893 if Token /= Tok_Identifier then
894 Error_Msg ("identifier expected", Token_Ptr);
895 goto Cleanup;
896 end if;
898 Symbol_Name := Token_Name;
899 Name_Len := 0;
901 for Ptr in Token_Ptr .. Scan_Ptr - 1 loop
902 Name_Len := Name_Len + 1;
903 Name_Buffer (Name_Len) := Sinput.Source (Ptr);
904 end loop;
906 Original_Name := Name_Find;
907 Scan.all;
909 if Token /= Tok_Colon_Equal then
910 Error_Msg -- CODEFIX
911 ("`:=` expected", Token_Ptr);
912 goto Cleanup;
913 end if;
915 Scan.all;
917 if Token = Tok_String_Literal then
918 Data := (Symbol => Symbol_Name,
919 Original => Original_Name,
920 On_The_Command_Line => False,
921 Is_A_String => True,
922 Value => String_Literal_Id);
924 Scan.all;
926 if Token /= Tok_End_Of_Line and then Token /= Tok_EOF then
927 Error_Msg ("extraneous text in definition", Token_Ptr);
928 goto Cleanup;
929 end if;
931 elsif Token = Tok_End_Of_Line or else Token = Tok_EOF then
932 Data := (Symbol => Symbol_Name,
933 Original => Original_Name,
934 On_The_Command_Line => False,
935 Is_A_String => False,
936 Value => Empty_String);
938 else
939 Value_Start := Token_Ptr;
940 Value_End := Token_Ptr - 1;
941 Scan_Ptr := Token_Ptr;
943 Value_Chars_Loop :
944 loop
945 Ch := Sinput.Source (Scan_Ptr);
947 case Ch is
948 when '_' | '.' | '0' .. '9' | 'a' .. 'z' | 'A' .. 'Z' =>
949 Value_End := Scan_Ptr;
950 Scan_Ptr := Scan_Ptr + 1;
952 when ' ' | HT | VT | CR | LF | FF =>
953 exit Value_Chars_Loop;
955 when others =>
956 Error_Msg ("illegal character", Scan_Ptr);
957 goto Cleanup;
958 end case;
959 end loop Value_Chars_Loop;
961 Scan.all;
963 if Token /= Tok_End_Of_Line and then Token /= Tok_EOF then
964 Error_Msg ("extraneous text in definition", Token_Ptr);
965 goto Cleanup;
966 end if;
968 Start_String;
970 while Value_Start <= Value_End loop
971 Store_String_Char (Sinput.Source (Value_Start));
972 Value_Start := Value_Start + 1;
973 end loop;
975 Data := (Symbol => Symbol_Name,
976 Original => Original_Name,
977 On_The_Command_Line => False,
978 Is_A_String => False,
979 Value => End_String);
980 end if;
982 -- Now that we have the value, get the symbol index
984 Symbol := Index_Of (Symbol_Name);
986 if Symbol /= No_Symbol then
987 -- If we already have an entry for this symbol, replace it
988 -- with the new value, except if the symbol was declared
989 -- on the command line.
991 if Mapping.Table (Symbol).On_The_Command_Line then
992 goto Continue;
993 end if;
995 else
996 -- As it is the first time we see this symbol, create a new
997 -- entry in the table.
999 if Mapping.Table = null then
1000 Symbol_Table.Init (Mapping);
1001 end if;
1003 Symbol_Table.Increment_Last (Mapping);
1004 Symbol := Symbol_Table.Last (Mapping);
1005 end if;
1007 Mapping.Table (Symbol) := Data;
1008 goto Continue;
1010 <<Cleanup>>
1011 Set_Ignore_Errors (To => True);
1013 while Token /= Tok_End_Of_Line and then Token /= Tok_EOF loop
1014 Scan.all;
1015 end loop;
1017 Set_Ignore_Errors (To => False);
1019 <<Continue>>
1020 null;
1021 end if;
1022 end loop Def_Line_Loop;
1023 end Parse_Def_File;
1025 ----------------
1026 -- Preprocess --
1027 ----------------
1029 procedure Preprocess (Source_Modified : out Boolean) is
1030 Start_Of_Processing : Source_Ptr;
1031 Cond : Boolean;
1032 Preprocessor_Line : Boolean := False;
1033 No_Error_Found : Boolean := True;
1034 Modified : Boolean := False;
1036 procedure Output (From, To : Source_Ptr);
1037 -- Output the characters with indexes From .. To in the buffer to the
1038 -- output file.
1040 procedure Output_Line (From, To : Source_Ptr);
1041 -- Output a line or the end of a line from the buffer to the output
1042 -- file, followed by an end of line terminator. Depending on the value
1043 -- of Deleting and the switches, the line may be commented out, blank or
1044 -- not output at all.
1046 ------------
1047 -- Output --
1048 ------------
1050 procedure Output (From, To : Source_Ptr) is
1051 begin
1052 for J in From .. To loop
1053 Put_Char (Sinput.Source (J));
1054 end loop;
1055 end Output;
1057 -----------------
1058 -- Output_Line --
1059 -----------------
1061 procedure Output_Line (From, To : Source_Ptr) is
1062 begin
1063 if Deleting or else Preprocessor_Line then
1064 if Blank_Deleted_Lines then
1065 New_EOL.all;
1067 elsif Comment_Deleted_Lines then
1068 Put_Char ('-');
1069 Put_Char ('-');
1070 Put_Char ('!');
1072 if From < To then
1073 Put_Char (' ');
1074 Output (From, To);
1075 end if;
1077 New_EOL.all;
1078 end if;
1080 else
1081 Output (From, To);
1082 New_EOL.all;
1083 end if;
1084 end Output_Line;
1086 -- Start of processing for Preprocess
1088 begin
1089 Start_Of_Processing := Scan_Ptr;
1091 -- We need to call Scan for the first time, because Initialize_Scanner
1092 -- is no longer doing it.
1094 Scan.all;
1096 Input_Line_Loop : loop
1097 exit Input_Line_Loop when Token = Tok_EOF;
1099 Preprocessor_Line := False;
1101 if Token /= Tok_End_Of_Line then
1103 -- Preprocessor line
1105 if Token = Tok_Special and then Special_Character = '#' then
1106 Modified := True;
1107 Preprocessor_Line := True;
1108 Scan.all;
1110 case Token is
1112 -- #if
1114 when Tok_If =>
1115 declare
1116 If_Ptr : constant Source_Ptr := Token_Ptr;
1118 begin
1119 Scan.all;
1120 Cond := Expression (not Deleting);
1122 -- Check for an eventual "then"
1124 if Token = Tok_Then then
1125 Scan.all;
1126 end if;
1128 -- It is an error to have trailing characters after
1129 -- the condition or "then".
1131 if Token /= Tok_End_Of_Line
1132 and then Token /= Tok_EOF
1133 then
1134 Error_Msg
1135 ("extraneous text on preprocessor line",
1136 Token_Ptr);
1137 No_Error_Found := False;
1138 Go_To_End_Of_Line;
1139 end if;
1141 declare
1142 -- Set the initial state of this new "#if". This
1143 -- must be done before incrementing the Last of
1144 -- the table, otherwise function Deleting does
1145 -- not report the correct value.
1147 New_State : constant Pp_State :=
1148 (If_Ptr => If_Ptr,
1149 Else_Ptr => 0,
1150 Deleting => Deleting
1151 or else not Cond,
1152 Match_Seen => Deleting or else Cond);
1154 begin
1155 Pp_States.Increment_Last;
1156 Pp_States.Table (Pp_States.Last) := New_State;
1157 end;
1158 end;
1160 -- #elsif
1162 when Tok_Elsif =>
1163 Cond := False;
1165 if Pp_States.Last = 0
1166 or else Pp_States.Table (Pp_States.Last).Else_Ptr /= 0
1167 then
1168 Error_Msg ("no IF for this ELSIF", Token_Ptr);
1169 No_Error_Found := False;
1171 else
1172 Cond :=
1173 not Pp_States.Table (Pp_States.Last).Match_Seen;
1174 end if;
1176 Scan.all;
1177 Cond := Expression (Cond);
1179 -- Check for an eventual "then"
1181 if Token = Tok_Then then
1182 Scan.all;
1183 end if;
1185 -- It is an error to have trailing characters after
1186 -- the condition or "then".
1188 if Token /= Tok_End_Of_Line
1189 and then Token /= Tok_EOF
1190 then
1191 Error_Msg
1192 ("extraneous text on preprocessor line",
1193 Token_Ptr);
1194 No_Error_Found := False;
1196 Go_To_End_Of_Line;
1197 end if;
1199 -- Depending on the value of the condition, set the
1200 -- new values of Deleting and Match_Seen.
1201 if Pp_States.Last > 0 then
1202 if Pp_States.Table (Pp_States.Last).Match_Seen then
1203 Pp_States.Table (Pp_States.Last).Deleting := True;
1204 else
1205 if Cond then
1206 Pp_States.Table (Pp_States.Last).Match_Seen :=
1207 True;
1208 Pp_States.Table (Pp_States.Last).Deleting :=
1209 False;
1210 end if;
1211 end if;
1212 end if;
1214 -- #else
1216 when Tok_Else =>
1217 if Pp_States.Last = 0 then
1218 Error_Msg ("no IF for this ELSE", Token_Ptr);
1219 No_Error_Found := False;
1221 elsif
1222 Pp_States.Table (Pp_States.Last).Else_Ptr /= 0
1223 then
1224 Error_Msg -- CODEFIX
1225 ("duplicate ELSE line", Token_Ptr);
1226 No_Error_Found := False;
1227 end if;
1229 -- Set the possibly new values of Deleting and
1230 -- Match_Seen.
1232 if Pp_States.Last > 0 then
1233 if Pp_States.Table (Pp_States.Last).Match_Seen then
1234 Pp_States.Table (Pp_States.Last).Deleting :=
1235 True;
1237 else
1238 Pp_States.Table (Pp_States.Last).Match_Seen :=
1239 True;
1240 Pp_States.Table (Pp_States.Last).Deleting :=
1241 False;
1242 end if;
1244 -- Set the Else_Ptr to check for illegal #elsif
1245 -- later.
1247 Pp_States.Table (Pp_States.Last).Else_Ptr :=
1248 Token_Ptr;
1249 end if;
1251 Scan.all;
1253 -- It is an error to have characters after "#else"
1254 if Token /= Tok_End_Of_Line
1255 and then Token /= Tok_EOF
1256 then
1257 Error_Msg
1258 ("extraneous text on preprocessor line",
1259 Token_Ptr);
1260 No_Error_Found := False;
1261 Go_To_End_Of_Line;
1262 end if;
1264 -- #end if;
1266 when Tok_End =>
1267 if Pp_States.Last = 0 then
1268 Error_Msg ("no IF for this END", Token_Ptr);
1269 No_Error_Found := False;
1270 end if;
1272 Scan.all;
1274 if Token /= Tok_If then
1275 Error_Msg -- CODEFIX
1276 ("IF expected", Token_Ptr);
1277 No_Error_Found := False;
1279 else
1280 Scan.all;
1282 if Token /= Tok_Semicolon then
1283 Error_Msg -- CODEFIX
1284 ("`;` Expected", Token_Ptr);
1285 No_Error_Found := False;
1287 else
1288 Scan.all;
1290 -- It is an error to have character after
1291 -- "#end if;".
1292 if Token /= Tok_End_Of_Line
1293 and then Token /= Tok_EOF
1294 then
1295 Error_Msg
1296 ("extraneous text on preprocessor line",
1297 Token_Ptr);
1298 No_Error_Found := False;
1299 end if;
1300 end if;
1301 end if;
1303 -- In case of one of the errors above, skip the tokens
1304 -- until the end of line is reached.
1306 Go_To_End_Of_Line;
1308 -- Decrement the depth of the #if stack
1310 if Pp_States.Last > 0 then
1311 Pp_States.Decrement_Last;
1312 end if;
1314 -- Illegal preprocessor line
1316 when others =>
1317 No_Error_Found := False;
1319 if Pp_States.Last = 0 then
1320 Error_Msg -- CODEFIX
1321 ("IF expected", Token_Ptr);
1323 elsif
1324 Pp_States.Table (Pp_States.Last).Else_Ptr = 0
1325 then
1326 Error_Msg
1327 ("IF, ELSIF, ELSE, or `END IF` expected",
1328 Token_Ptr);
1330 else
1331 Error_Msg ("IF or `END IF` expected", Token_Ptr);
1332 end if;
1334 -- Skip to the end of this illegal line
1336 Go_To_End_Of_Line;
1337 end case;
1339 -- Not a preprocessor line
1341 else
1342 -- Do not report errors for those lines, even if there are
1343 -- Ada parsing errors.
1345 Set_Ignore_Errors (To => True);
1347 if Deleting then
1348 Go_To_End_Of_Line;
1350 else
1351 while Token /= Tok_End_Of_Line
1352 and then Token /= Tok_EOF
1353 loop
1354 if Token = Tok_Special
1355 and then Special_Character = '$'
1356 then
1357 Modified := True;
1359 declare
1360 Dollar_Ptr : constant Source_Ptr := Token_Ptr;
1361 Symbol : Symbol_Id;
1363 begin
1364 Scan.all;
1365 Change_Reserved_Keyword_To_Symbol;
1367 if Token = Tok_Identifier
1368 and then Token_Ptr = Dollar_Ptr + 1
1369 then
1370 -- $symbol
1372 Symbol := Index_Of (Token_Name);
1374 -- If symbol exists, replace by its value
1376 if Symbol /= No_Symbol then
1377 Output (Start_Of_Processing, Dollar_Ptr - 1);
1378 Start_Of_Processing := Scan_Ptr;
1379 String_To_Name_Buffer
1380 (Mapping.Table (Symbol).Value);
1382 if Mapping.Table (Symbol).Is_A_String then
1384 -- Value is an Ada string
1386 Put_Char ('"');
1388 for J in 1 .. Name_Len loop
1389 Put_Char (Name_Buffer (J));
1391 if Name_Buffer (J) = '"' then
1392 Put_Char ('"');
1393 end if;
1394 end loop;
1396 Put_Char ('"');
1398 else
1399 -- Value is a sequence of characters, not
1400 -- an Ada string.
1402 for J in 1 .. Name_Len loop
1403 Put_Char (Name_Buffer (J));
1404 end loop;
1405 end if;
1406 end if;
1407 end if;
1408 end;
1409 end if;
1411 Scan.all;
1412 end loop;
1413 end if;
1415 Set_Ignore_Errors (To => False);
1416 end if;
1417 end if;
1419 pragma Assert (Token = Tok_End_Of_Line or else Token = Tok_EOF);
1421 -- At this point, the token is either end of line or EOF.
1422 -- The line to possibly output stops just before the token.
1424 Output_Line (Start_Of_Processing, Token_Ptr - 1);
1426 -- If we are at the end of a line, the scan pointer is at the first
1427 -- non blank character, not necessarily the first character of the
1428 -- line; so, we have to deduct Start_Of_Processing from the token
1429 -- pointer.
1431 if Token = Tok_End_Of_Line then
1432 if (Sinput.Source (Token_Ptr) = ASCII.CR
1433 and then Sinput.Source (Token_Ptr + 1) = ASCII.LF)
1434 or else
1435 (Sinput.Source (Token_Ptr) = ASCII.CR
1436 and then Sinput.Source (Token_Ptr + 1) = ASCII.LF)
1437 then
1438 Start_Of_Processing := Token_Ptr + 2;
1439 else
1440 Start_Of_Processing := Token_Ptr + 1;
1441 end if;
1442 end if;
1444 -- Now, scan the first token of the next line. If the token is EOF,
1445 -- the scan pointer will not move, and the token will still be EOF.
1447 Set_Ignore_Errors (To => True);
1448 Scan.all;
1449 Set_Ignore_Errors (To => False);
1450 end loop Input_Line_Loop;
1452 -- Report an error for any missing some "#end if;"
1454 for Level in reverse 1 .. Pp_States.Last loop
1455 Error_Msg ("no `END IF` for this IF", Pp_States.Table (Level).If_Ptr);
1456 No_Error_Found := False;
1457 end loop;
1459 Source_Modified := No_Error_Found and Modified;
1460 end Preprocess;
1462 -----------------
1463 -- Setup_Hooks --
1464 -----------------
1466 procedure Setup_Hooks
1467 (Error_Msg : Error_Msg_Proc;
1468 Scan : Scan_Proc;
1469 Set_Ignore_Errors : Set_Ignore_Errors_Proc;
1470 Put_Char : Put_Char_Proc;
1471 New_EOL : New_EOL_Proc)
1473 begin
1474 pragma Assert (Already_Initialized);
1476 Prep.Error_Msg := Error_Msg;
1477 Prep.Scan := Scan;
1478 Prep.Set_Ignore_Errors := Set_Ignore_Errors;
1479 Prep.Put_Char := Put_Char;
1480 Prep.New_EOL := New_EOL;
1481 end Setup_Hooks;
1483 end Prep;