2008-05-30 Vladimir Makarov <vmakarov@redhat.com>
[official-gcc.git] / gcc / ada / prep.adb
blobeb739a752745f70d7d555f68b3da2ae619f6276d
1 ------------------------------------------------------------------------------
2 -- --
3 -- GNAT COMPILER COMPONENTS --
4 -- --
5 -- P R E P --
6 -- --
7 -- B o d y --
8 -- --
9 -- Copyright (C) 2002-2007, 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 Name_Defined : Name_Id;
123 -- defined, as a name_id
125 ---------------
126 -- Behaviour --
127 ---------------
129 -- Accesses to procedure specified by procedure Initialize
131 Error_Msg : Error_Msg_Proc;
132 -- Report an error
134 Scan : Scan_Proc;
135 -- Scan one token
137 Set_Ignore_Errors : Set_Ignore_Errors_Proc;
138 -- Indicate if error should be taken into account
140 Put_Char : Put_Char_Proc;
141 -- Output one character
143 New_EOL : New_EOL_Proc;
144 -- Output an end of line indication
146 -------------------------------
147 -- State of the Preprocessor --
148 -------------------------------
150 type Pp_State is record
151 If_Ptr : Source_Ptr;
152 -- The location of the #if statement.
153 -- Used to flag #if with no corresponding #end if, at the end.
155 Else_Ptr : Source_Ptr;
156 -- The location of the #else statement.
157 -- Used to detect multiple #else.
159 Deleting : Boolean;
160 -- Set to True when the code should be deleted or commented out
162 Match_Seen : Boolean;
163 -- Set to True when a condition in an #if or an #elsif is True.
164 -- Also set to True if Deleting at the previous level is True.
165 -- Used to decide if Deleting should be set to True in a following
166 -- #elsif or #else.
168 end record;
170 type Pp_Depth is new Nat;
172 Ground : constant Pp_Depth := 0;
174 package Pp_States is new Table.Table
175 (Table_Component_Type => Pp_State,
176 Table_Index_Type => Pp_Depth,
177 Table_Low_Bound => 1,
178 Table_Initial => 10,
179 Table_Increment => 100,
180 Table_Name => "Prep.Pp_States");
181 -- A stack of the states of the preprocessor, for nested #if
183 type Operator is (None, Op_Or, Op_And);
185 -----------------
186 -- Subprograms --
187 -----------------
189 function Deleting return Boolean;
190 -- Return True if code should be deleted or commented out
192 function Expression
193 (Evaluate_It : Boolean;
194 Complemented : Boolean := False) 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
201 -- of the buffer.
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);
215 begin
216 if New_Name /= No_Name then
217 case Token is
218 when Tok_If | Tok_Else | Tok_Elsif | Tok_End |
219 Tok_And | Tok_Or | Tok_Then =>
220 if All_Keywords then
221 Token := Tok_Identifier;
222 Token_Name := New_Name;
223 end if;
225 when others =>
226 Token := Tok_Identifier;
227 Token_Name := New_Name;
228 end case;
229 end if;
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;
243 begin
244 -- Look for the character '='
246 for J in Definition'Range loop
247 if Definition (J) = '=' then
248 Index := J;
249 exit;
250 end if;
251 end loop;
253 -- If no character '=', then the value is True
255 if Index = 0 then
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, """");
265 else
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) /= '"'
276 then
277 for J in Index + 1 .. Definition'Last loop
278 case Definition (J) is
279 when '_' | '.' | '0' .. '9' | 'a' .. 'z' | 'A' .. 'Z' =>
280 null;
282 when others =>
283 Fail ("illegal value """,
284 Definition (Index + 1 .. Definition'Last),
285 """");
286 end case;
287 end loop;
288 end if;
290 -- And put the value in the result
292 Result.Is_A_String := False;
293 Start_String;
294 Store_String_Chars (Definition (Index + 1 .. Definition'Last));
295 Result.Value := End_String;
296 end if;
298 -- Now, check the syntax of the symbol (we don't allow accented and
299 -- wide characters)
301 if Name_Buffer (1) not in 'a' .. 'z'
302 and then Name_Buffer (1) not in 'A' .. 'Z'
303 then
304 Fail ("symbol """,
305 Name_Buffer (1 .. Name_Len),
306 """ does not start with a letter");
307 end if;
309 for J in 2 .. Name_Len loop
310 case Name_Buffer (J) is
311 when 'a' .. 'z' | 'A' .. 'Z' | '0' .. '9' =>
312 null;
314 when '_' =>
315 if J = Name_Len then
316 Fail ("symbol """,
317 Name_Buffer (1 .. Name_Len),
318 """ end with a '_'");
320 elsif Name_Buffer (J + 1) = '_' then
321 Fail ("symbol """,
322 Name_Buffer (1 .. Name_Len),
323 """ contains consecutive '_'");
324 end if;
326 when others =>
327 Fail ("symbol """,
328 Name_Buffer (1 .. Name_Len),
329 """ contains illegal character(s)");
330 end case;
331 end loop;
333 Result.On_The_Command_Line := True;
335 -- Put the symbol name in the result
337 declare
338 Sym : constant String := Name_Buffer (1 .. Name_Len);
340 begin
341 for Index in 1 .. Name_Len loop
342 Name_Buffer (Index) := Fold_Lower (Name_Buffer (Index));
343 end loop;
345 Result.Symbol := Name_Find;
346 Name_Len := Sym'Length;
347 Name_Buffer (1 .. Name_Len) := Sym;
348 Result.Original := Name_Find;
349 end;
351 Data := Result;
352 end Check_Command_Line_Symbol_Definition;
354 --------------
355 -- Deleting --
356 --------------
358 function Deleting return Boolean is
359 begin
360 -- Always return False when not inside an #if statement
362 if Pp_States.Last = Ground then
363 return False;
364 else
365 return Pp_States.Table (Pp_States.Last).Deleting;
366 end if;
367 end Deleting;
369 ----------------
370 -- Expression --
371 ----------------
373 function Expression
374 (Evaluate_It : Boolean;
375 Complemented : Boolean := False) return Boolean
377 Evaluation : Boolean := Evaluate_It;
378 -- Is set to False after an "or else" when left term is True and
379 -- after an "and then" when left term is False.
381 Final_Result : Boolean := False;
383 Current_Result : Boolean := False;
384 -- Value of a term
386 Current_Operator : Operator := None;
387 Symbol1 : Symbol_Id;
388 Symbol2 : Symbol_Id;
389 Symbol_Name1 : Name_Id;
390 Symbol_Name2 : Name_Id;
391 Symbol_Pos1 : Source_Ptr;
392 Symbol_Pos2 : Source_Ptr;
393 Symbol_Value1 : String_Id;
394 Symbol_Value2 : String_Id;
396 begin
397 -- Loop for each term
399 loop
400 Change_Reserved_Keyword_To_Symbol;
402 Current_Result := False;
404 case Token is
406 when Tok_Left_Paren =>
408 -- ( expression )
410 Scan.all;
411 Current_Result := Expression (Evaluation);
413 if Token = Tok_Right_Paren then
414 Scan.all;
416 else
417 Error_Msg ("`)` expected", Token_Ptr);
418 end if;
420 when Tok_Not =>
422 -- not expression
424 Scan.all;
425 Current_Result :=
426 not Expression (Evaluation, Complemented => True);
428 when Tok_Identifier =>
429 Symbol_Name1 := Token_Name;
430 Symbol_Pos1 := Token_Ptr;
431 Scan.all;
433 if Token = Tok_Apostrophe then
435 -- symbol'Defined
437 Scan.all;
439 if Token = Tok_Identifier
440 and then Token_Name = Name_Defined
441 then
442 Scan.all;
444 else
445 Error_Msg ("identifier `Defined` expected", Token_Ptr);
446 end if;
448 if Evaluation then
449 Current_Result := Index_Of (Symbol_Name1) /= No_Symbol;
450 end if;
452 elsif Token = Tok_Equal then
453 Scan.all;
455 Change_Reserved_Keyword_To_Symbol;
457 if Token = Tok_Identifier then
459 -- symbol = symbol
461 Symbol_Name2 := Token_Name;
462 Symbol_Pos2 := Token_Ptr;
463 Scan.all;
465 if Evaluation then
466 Symbol1 := Index_Of (Symbol_Name1);
468 if Symbol1 = No_Symbol then
469 if Undefined_Symbols_Are_False then
470 Symbol_Value1 := String_False;
472 else
473 Error_Msg_Name_1 := Symbol_Name1;
474 Error_Msg ("unknown symbol %", Symbol_Pos1);
475 Symbol_Value1 := No_String;
476 end if;
478 else
479 Symbol_Value1 :=
480 Mapping.Table (Symbol1).Value;
481 end if;
483 Symbol2 := Index_Of (Symbol_Name2);
485 if Symbol2 = No_Symbol then
486 if Undefined_Symbols_Are_False then
487 Symbol_Value2 := String_False;
489 else
490 Error_Msg_Name_1 := Symbol_Name2;
491 Error_Msg ("unknown symbol %", Symbol_Pos2);
492 Symbol_Value2 := No_String;
493 end if;
495 else
496 Symbol_Value2 := Mapping.Table (Symbol2).Value;
497 end if;
499 if Symbol_Value1 /= No_String
500 and then Symbol_Value2 /= No_String
501 then
502 Current_Result := Matching_Strings
503 (Symbol_Value1, Symbol_Value2);
504 end if;
505 end if;
507 elsif Token = Tok_String_Literal then
509 -- symbol = "value"
511 if Evaluation then
512 Symbol1 := Index_Of (Symbol_Name1);
514 if Symbol1 = No_Symbol then
515 if Undefined_Symbols_Are_False then
516 Symbol_Value1 := String_False;
518 else
519 Error_Msg_Name_1 := Symbol_Name1;
520 Error_Msg ("unknown symbol %", Symbol_Pos1);
521 Symbol_Value1 := No_String;
522 end if;
524 else
525 Symbol_Value1 := Mapping.Table (Symbol1).Value;
526 end if;
528 if Symbol_Value1 /= No_String then
529 Current_Result :=
530 Matching_Strings
531 (Symbol_Value1,
532 String_Literal_Id);
533 end if;
534 end if;
536 Scan.all;
538 else
539 Error_Msg
540 ("symbol or literal string expected", Token_Ptr);
541 end if;
543 else
544 -- symbol (True or False)
546 if Evaluation then
547 Symbol1 := Index_Of (Symbol_Name1);
549 if Symbol1 = No_Symbol then
550 if Undefined_Symbols_Are_False then
551 Symbol_Value1 := String_False;
553 else
554 Error_Msg_Name_1 := Symbol_Name1;
555 Error_Msg ("unknown symbol %", Symbol_Pos1);
556 Symbol_Value1 := No_String;
557 end if;
559 else
560 Symbol_Value1 := Mapping.Table (Symbol1).Value;
561 end if;
563 if Symbol_Value1 /= No_String then
564 String_To_Name_Buffer (Symbol_Value1);
566 for Index in 1 .. Name_Len loop
567 Name_Buffer (Index) :=
568 Fold_Lower (Name_Buffer (Index));
569 end loop;
571 if Name_Buffer (1 .. Name_Len) = "true" then
572 Current_Result := True;
574 elsif Name_Buffer (1 .. Name_Len) = "false" then
575 Current_Result := False;
577 else
578 Error_Msg_Name_1 := Symbol_Name1;
579 Error_Msg
580 ("value of symbol % is not True or False",
581 Symbol_Pos1);
582 end if;
583 end if;
584 end if;
585 end if;
587 when others =>
588 Error_Msg ("`(`, NOT or symbol expected", Token_Ptr);
589 end case;
591 -- Update the cumulative final result
593 case Current_Operator is
594 when None =>
595 Final_Result := Current_Result;
597 when Op_Or =>
598 Final_Result := Final_Result or Current_Result;
600 when Op_And =>
601 Final_Result := Final_Result and Current_Result;
602 end case;
604 -- Check the next operator
606 if Token = Tok_And then
607 if Complemented then
608 Error_Msg
609 ("mixing NOT and AND is not allowed, parentheses are required",
610 Token_Ptr);
612 elsif Current_Operator = Op_Or then
613 Error_Msg ("mixing OR and AND is not allowed", Token_Ptr);
614 end if;
616 Current_Operator := Op_And;
617 Scan.all;
619 if Token = Tok_Then then
620 Scan.all;
622 if Final_Result = False then
623 Evaluation := False;
624 end if;
625 end if;
627 elsif Token = Tok_Or then
628 if Complemented then
629 Error_Msg
630 ("mixing NOT and OR is not allowed, parentheses are required",
631 Token_Ptr);
633 elsif Current_Operator = Op_And then
634 Error_Msg ("mixing AND and OR is not allowed", Token_Ptr);
635 end if;
637 Current_Operator := Op_Or;
638 Scan.all;
640 if Token = Tok_Else then
641 Scan.all;
643 if Final_Result then
644 Evaluation := False;
645 end if;
646 end if;
648 else
649 -- No operator: exit the term loop
651 exit;
652 end if;
653 end loop;
655 return Final_Result;
656 end Expression;
658 -----------------------
659 -- Go_To_End_Of_Line --
660 -----------------------
662 procedure Go_To_End_Of_Line is
663 begin
664 -- Scan until we get an end of line or we reach the end of the buffer
666 while Token /= Tok_End_Of_Line
667 and then Token /= Tok_EOF
668 loop
669 Scan.all;
670 end loop;
671 end Go_To_End_Of_Line;
673 --------------
674 -- Index_Of --
675 --------------
677 function Index_Of (Symbol : Name_Id) return Symbol_Id is
678 begin
679 if Mapping.Table /= null then
680 for J in Symbol_Id range 1 .. Symbol_Table.Last (Mapping) loop
681 if Mapping.Table (J).Symbol = Symbol then
682 return J;
683 end if;
684 end loop;
685 end if;
687 return No_Symbol;
688 end Index_Of;
690 ----------------
691 -- Initialize --
692 ----------------
694 procedure Initialize
695 (Error_Msg : Error_Msg_Proc;
696 Scan : Scan_Proc;
697 Set_Ignore_Errors : Set_Ignore_Errors_Proc;
698 Put_Char : Put_Char_Proc;
699 New_EOL : New_EOL_Proc)
701 begin
702 if not Already_Initialized then
703 Start_String;
704 Store_String_Chars ("True");
705 True_Value.Value := End_String;
707 Start_String;
708 Empty_String := End_String;
710 Name_Len := 7;
711 Name_Buffer (1 .. Name_Len) := "defined";
712 Name_Defined := Name_Find;
714 Start_String;
715 Store_String_Chars ("False");
716 String_False := End_String;
718 Already_Initialized := True;
719 end if;
721 Prep.Error_Msg := Error_Msg;
722 Prep.Scan := Scan;
723 Prep.Set_Ignore_Errors := Set_Ignore_Errors;
724 Prep.Put_Char := Put_Char;
725 Prep.New_EOL := New_EOL;
726 end Initialize;
728 ------------------
729 -- List_Symbols --
730 ------------------
732 procedure List_Symbols (Foreword : String) is
733 Order : array (0 .. Integer (Symbol_Table.Last (Mapping)))
734 of Symbol_Id;
735 -- After alphabetical sorting, this array stores the indices of
736 -- the symbols in the order they are displayed.
738 function Lt (Op1, Op2 : Natural) return Boolean;
739 -- Comparison routine for sort call
741 procedure Move (From : Natural; To : Natural);
742 -- Move routine for sort call
744 --------
745 -- Lt --
746 --------
748 function Lt (Op1, Op2 : Natural) return Boolean is
749 S1 : constant String :=
750 Get_Name_String (Mapping.Table (Order (Op1)).Symbol);
751 S2 : constant String :=
752 Get_Name_String (Mapping.Table (Order (Op2)).Symbol);
754 begin
755 return S1 < S2;
756 end Lt;
758 ----------
759 -- Move --
760 ----------
762 procedure Move (From : Natural; To : Natural) is
763 begin
764 Order (To) := Order (From);
765 end Move;
767 package Sort_Syms is new GNAT.Heap_Sort_G (Move, Lt);
769 Max_L : Natural;
770 -- Maximum length of any symbol
772 -- Start of processing for List_Symbols_Case
774 begin
775 if Symbol_Table.Last (Mapping) = 0 then
776 return;
777 end if;
779 if Foreword'Length > 0 then
780 Write_Eol;
781 Write_Line (Foreword);
783 for J in Foreword'Range loop
784 Write_Char ('=');
785 end loop;
786 end if;
788 -- Initialize the order
790 for J in Order'Range loop
791 Order (J) := Symbol_Id (J);
792 end loop;
794 -- Sort alphabetically
796 Sort_Syms.Sort (Order'Last);
798 Max_L := 7;
800 for J in 1 .. Symbol_Table.Last (Mapping) loop
801 Get_Name_String (Mapping.Table (J).Original);
802 Max_L := Integer'Max (Max_L, Name_Len);
803 end loop;
805 Write_Eol;
806 Write_Str ("Symbol");
808 for J in 1 .. Max_L - 5 loop
809 Write_Char (' ');
810 end loop;
812 Write_Line ("Value");
814 Write_Str ("------");
816 for J in 1 .. Max_L - 5 loop
817 Write_Char (' ');
818 end loop;
820 Write_Line ("------");
822 for J in 1 .. Order'Last loop
823 declare
824 Data : constant Symbol_Data := Mapping.Table (Order (J));
826 begin
827 Get_Name_String (Data.Original);
828 Write_Str (Name_Buffer (1 .. Name_Len));
830 for K in Name_Len .. Max_L loop
831 Write_Char (' ');
832 end loop;
834 String_To_Name_Buffer (Data.Value);
836 if Data.Is_A_String then
837 Write_Char ('"');
839 for J in 1 .. Name_Len loop
840 Write_Char (Name_Buffer (J));
842 if Name_Buffer (J) = '"' then
843 Write_Char ('"');
844 end if;
845 end loop;
847 Write_Char ('"');
849 else
850 Write_Str (Name_Buffer (1 .. Name_Len));
851 end if;
852 end;
854 Write_Eol;
855 end loop;
857 Write_Eol;
858 end List_Symbols;
860 ----------------------
861 -- Matching_Strings --
862 ----------------------
864 function Matching_Strings (S1, S2 : String_Id) return Boolean is
865 begin
866 String_To_Name_Buffer (S1);
868 for Index in 1 .. Name_Len loop
869 Name_Buffer (Index) := Fold_Lower (Name_Buffer (Index));
870 end loop;
872 declare
873 String1 : constant String := Name_Buffer (1 .. Name_Len);
875 begin
876 String_To_Name_Buffer (S2);
878 for Index in 1 .. Name_Len loop
879 Name_Buffer (Index) := Fold_Lower (Name_Buffer (Index));
880 end loop;
882 return String1 = Name_Buffer (1 .. Name_Len);
883 end;
884 end Matching_Strings;
886 --------------------
887 -- Parse_Def_File --
888 --------------------
890 procedure Parse_Def_File is
891 Symbol : Symbol_Id;
892 Symbol_Name : Name_Id;
893 Original_Name : Name_Id;
894 Data : Symbol_Data;
895 Value_Start : Source_Ptr;
896 Value_End : Source_Ptr;
897 Ch : Character;
899 use ASCII;
901 begin
902 Def_Line_Loop :
903 loop
904 Scan.all;
906 exit Def_Line_Loop when Token = Tok_EOF;
908 if Token /= Tok_End_Of_Line then
909 Change_Reserved_Keyword_To_Symbol;
911 if Token /= Tok_Identifier then
912 Error_Msg ("identifier expected", Token_Ptr);
913 goto Cleanup;
914 end if;
916 Symbol_Name := Token_Name;
917 Name_Len := 0;
919 for Ptr in Token_Ptr .. Scan_Ptr - 1 loop
920 Name_Len := Name_Len + 1;
921 Name_Buffer (Name_Len) := Sinput.Source (Ptr);
922 end loop;
924 Original_Name := Name_Find;
925 Scan.all;
927 if Token /= Tok_Colon_Equal then
928 Error_Msg ("`:=` expected", Token_Ptr);
929 goto Cleanup;
930 end if;
932 Scan.all;
934 if Token = Tok_String_Literal then
935 Data := (Symbol => Symbol_Name,
936 Original => Original_Name,
937 On_The_Command_Line => False,
938 Is_A_String => True,
939 Value => String_Literal_Id);
941 Scan.all;
943 if Token /= Tok_End_Of_Line and then Token /= Tok_EOF then
944 Error_Msg ("extraneous text in definition", Token_Ptr);
945 goto Cleanup;
946 end if;
948 elsif Token = Tok_End_Of_Line or Token = Tok_EOF then
949 Data := (Symbol => Symbol_Name,
950 Original => Original_Name,
951 On_The_Command_Line => False,
952 Is_A_String => False,
953 Value => Empty_String);
955 else
956 Value_Start := Token_Ptr;
957 Value_End := Token_Ptr - 1;
958 Scan_Ptr := Token_Ptr;
960 Value_Chars_Loop :
961 loop
962 Ch := Sinput.Source (Scan_Ptr);
964 case Ch is
965 when '_' | '.' | '0' .. '9' | 'a' .. 'z' | 'A' .. 'Z' =>
966 Value_End := Scan_Ptr;
967 Scan_Ptr := Scan_Ptr + 1;
969 when ' ' | HT | VT | CR | LF | FF =>
970 exit Value_Chars_Loop;
972 when others =>
973 Error_Msg ("illegal character", Scan_Ptr);
974 goto Cleanup;
975 end case;
976 end loop Value_Chars_Loop;
978 Scan.all;
980 if Token /= Tok_End_Of_Line and then Token /= Tok_EOF then
981 Error_Msg ("extraneous text in definition", Token_Ptr);
982 goto Cleanup;
983 end if;
985 Start_String;
987 while Value_Start <= Value_End loop
988 Store_String_Char (Sinput.Source (Value_Start));
989 Value_Start := Value_Start + 1;
990 end loop;
992 Data := (Symbol => Symbol_Name,
993 Original => Original_Name,
994 On_The_Command_Line => False,
995 Is_A_String => False,
996 Value => End_String);
997 end if;
999 -- Now that we have the value, get the symbol index
1001 Symbol := Index_Of (Symbol_Name);
1003 if Symbol /= No_Symbol then
1004 -- If we already have an entry for this symbol, replace it
1005 -- with the new value, except if the symbol was declared
1006 -- on the command line.
1008 if Mapping.Table (Symbol).On_The_Command_Line then
1009 goto Continue;
1010 end if;
1012 else
1013 -- As it is the first time we see this symbol, create a new
1014 -- entry in the table.
1016 if Mapping.Table = null then
1017 Symbol_Table.Init (Mapping);
1018 end if;
1020 Symbol_Table.Increment_Last (Mapping);
1021 Symbol := Symbol_Table.Last (Mapping);
1022 end if;
1024 Mapping.Table (Symbol) := Data;
1025 goto Continue;
1027 <<Cleanup>>
1028 Set_Ignore_Errors (To => True);
1030 while Token /= Tok_End_Of_Line and Token /= Tok_EOF loop
1031 Scan.all;
1032 end loop;
1034 Set_Ignore_Errors (To => False);
1036 <<Continue>>
1037 null;
1038 end if;
1039 end loop Def_Line_Loop;
1040 end Parse_Def_File;
1042 ----------------
1043 -- Preprocess --
1044 ----------------
1046 procedure Preprocess is
1047 Start_Of_Processing : Source_Ptr;
1048 Cond : Boolean;
1049 Preprocessor_Line : Boolean := False;
1051 procedure Output (From, To : Source_Ptr);
1052 -- Output the characters with indices From .. To in the buffer
1053 -- to the output file.
1055 procedure Output_Line (From, To : Source_Ptr);
1056 -- Output a line or the end of a line from the buffer to the output
1057 -- file, followed by an end of line terminator. Depending on the value
1058 -- of Deleting and the switches, the line may be commented out, blank or
1059 -- not output at all.
1061 ------------
1062 -- Output --
1063 ------------
1065 procedure Output (From, To : Source_Ptr) is
1066 begin
1067 for J in From .. To loop
1068 Put_Char (Sinput.Source (J));
1069 end loop;
1070 end Output;
1072 -----------------
1073 -- Output_Line --
1074 -----------------
1076 procedure Output_Line (From, To : Source_Ptr) is
1077 begin
1078 if Deleting or Preprocessor_Line then
1079 if Blank_Deleted_Lines then
1080 New_EOL.all;
1082 elsif Comment_Deleted_Lines then
1083 Put_Char ('-');
1084 Put_Char ('-');
1085 Put_Char ('!');
1087 if From < To then
1088 Put_Char (' ');
1089 Output (From, To);
1090 end if;
1092 New_EOL.all;
1093 end if;
1095 else
1096 Output (From, To);
1097 New_EOL.all;
1098 end if;
1099 end Output_Line;
1101 -- Start of processing for Preprocess
1103 begin
1104 Start_Of_Processing := Scan_Ptr;
1106 -- We need to call Scan for the first time, because Initialize_Scanner
1107 -- is no longer doing it.
1109 Scan.all;
1111 Input_Line_Loop : loop
1112 exit Input_Line_Loop when Token = Tok_EOF;
1114 Preprocessor_Line := False;
1116 if Token /= Tok_End_Of_Line then
1118 -- Preprocessor line
1120 if Token = Tok_Special and then Special_Character = '#' then
1121 Preprocessor_Line := True;
1122 Scan.all;
1124 case Token is
1126 -- #if
1128 when Tok_If =>
1129 declare
1130 If_Ptr : constant Source_Ptr := Token_Ptr;
1132 begin
1133 Scan.all;
1134 Cond := Expression (not Deleting);
1136 -- Check for an eventual "then"
1138 if Token = Tok_Then then
1139 Scan.all;
1140 end if;
1142 -- It is an error to have trailing characters after
1143 -- the condition or "then".
1145 if Token /= Tok_End_Of_Line
1146 and then Token /= Tok_EOF
1147 then
1148 Error_Msg
1149 ("extraneous text on preprocessor line",
1150 Token_Ptr);
1151 Go_To_End_Of_Line;
1152 end if;
1154 declare
1155 -- Set the initial state of this new "#if".
1156 -- This must be done before incrementing the
1157 -- Last of the table, otherwise function
1158 -- Deleting does not report the correct value.
1160 New_State : constant Pp_State :=
1161 (If_Ptr => If_Ptr,
1162 Else_Ptr => 0,
1163 Deleting => Deleting or (not Cond),
1164 Match_Seen => Deleting or Cond);
1166 begin
1167 Pp_States.Increment_Last;
1168 Pp_States.Table (Pp_States.Last) := New_State;
1169 end;
1170 end;
1172 -- #elsif
1174 when Tok_Elsif =>
1175 Cond := False;
1177 if Pp_States.Last = 0
1178 or else Pp_States.Table (Pp_States.Last).Else_Ptr
1179 /= 0
1180 then
1181 Error_Msg ("no IF for this ELSIF", Token_Ptr);
1183 else
1184 Cond :=
1185 not Pp_States.Table (Pp_States.Last).Match_Seen;
1186 end if;
1188 Scan.all;
1189 Cond := Expression (Cond);
1191 -- Check for an eventual "then"
1193 if Token = Tok_Then then
1194 Scan.all;
1195 end if;
1197 -- It is an error to have trailing characters after
1198 -- the condition or "then".
1200 if Token /= Tok_End_Of_Line
1201 and then Token /= Tok_EOF
1202 then
1203 Error_Msg
1204 ("extraneous text on preprocessor line",
1205 Token_Ptr);
1207 Go_To_End_Of_Line;
1208 end if;
1210 -- Depending on the value of the condition, set the
1211 -- new values of Deleting and Match_Seen.
1212 if Pp_States.Last > 0 then
1213 if Pp_States.Table (Pp_States.Last).Match_Seen then
1214 Pp_States.Table (Pp_States.Last).Deleting :=
1215 True;
1216 else
1217 if Cond then
1218 Pp_States.Table (Pp_States.Last).Match_Seen :=
1219 True;
1220 Pp_States.Table (Pp_States.Last).Deleting :=
1221 False;
1222 end if;
1223 end if;
1224 end if;
1226 -- #else
1228 when Tok_Else =>
1229 if Pp_States.Last = 0 then
1230 Error_Msg ("no IF for this ELSE", Token_Ptr);
1232 elsif
1233 Pp_States.Table (Pp_States.Last).Else_Ptr /= 0
1234 then
1235 Error_Msg ("duplicate ELSE line", Token_Ptr);
1236 end if;
1238 -- Set the possibly new values of Deleting and
1239 -- Match_Seen.
1241 if Pp_States.Last > 0 then
1242 if Pp_States.Table (Pp_States.Last).Match_Seen then
1243 Pp_States.Table (Pp_States.Last).Deleting :=
1244 True;
1246 else
1247 Pp_States.Table (Pp_States.Last).Match_Seen :=
1248 True;
1249 Pp_States.Table (Pp_States.Last).Deleting :=
1250 False;
1251 end if;
1253 -- Set the Else_Ptr to check for illegal #elsif
1254 -- later.
1256 Pp_States.Table (Pp_States.Last).Else_Ptr :=
1257 Token_Ptr;
1258 end if;
1260 Scan.all;
1262 -- It is an error to have characters after "#else"
1263 if Token /= Tok_End_Of_Line
1264 and then Token /= Tok_EOF
1265 then
1266 Error_Msg
1267 ("extraneous text on preprocessor line",
1268 Token_Ptr);
1269 Go_To_End_Of_Line;
1270 end if;
1272 -- #end if;
1274 when Tok_End =>
1275 if Pp_States.Last = 0 then
1276 Error_Msg ("no IF for this END", Token_Ptr);
1277 end if;
1279 Scan.all;
1281 if Token /= Tok_If then
1282 Error_Msg ("IF expected", Token_Ptr);
1284 else
1285 Scan.all;
1287 if Token /= Tok_Semicolon then
1288 Error_Msg ("`;` Expected", Token_Ptr);
1290 else
1291 Scan.all;
1293 -- It is an error to have character after
1294 -- "#end if;".
1295 if Token /= Tok_End_Of_Line
1296 and then Token /= Tok_EOF
1297 then
1298 Error_Msg
1299 ("extraneous text on preprocessor line",
1300 Token_Ptr);
1301 end if;
1302 end if;
1303 end if;
1305 -- In case of one of the errors above, skip the tokens
1306 -- until the end of line is reached.
1308 Go_To_End_Of_Line;
1310 -- Decrement the depth of the #if stack
1312 if Pp_States.Last > 0 then
1313 Pp_States.Decrement_Last;
1314 end if;
1316 -- Illegal preprocessor line
1318 when others =>
1319 if Pp_States.Last = 0 then
1320 Error_Msg ("IF expected", Token_Ptr);
1322 elsif
1323 Pp_States.Table (Pp_States.Last).Else_Ptr = 0
1324 then
1325 Error_Msg ("IF, ELSIF, ELSE, or `END IF` expected",
1326 Token_Ptr);
1328 else
1329 Error_Msg ("IF or `END IF` expected", Token_Ptr);
1330 end if;
1332 -- Skip to the end of this illegal line
1334 Go_To_End_Of_Line;
1335 end case;
1337 -- Not a preprocessor line
1339 else
1340 -- Do not report errors for those lines, even if there are
1341 -- Ada parsing errors.
1343 Set_Ignore_Errors (To => True);
1345 if Deleting then
1346 Go_To_End_Of_Line;
1348 else
1349 while Token /= Tok_End_Of_Line
1350 and then Token /= Tok_EOF
1351 loop
1352 if Token = Tok_Special
1353 and then Special_Character = '$'
1354 then
1355 declare
1356 Dollar_Ptr : constant Source_Ptr := Token_Ptr;
1357 Symbol : Symbol_Id;
1359 begin
1360 Scan.all;
1361 Change_Reserved_Keyword_To_Symbol;
1363 if Token = Tok_Identifier
1364 and then Token_Ptr = Dollar_Ptr + 1
1365 then
1366 -- $symbol
1368 Symbol := Index_Of (Token_Name);
1370 -- If symbol exists, replace by its value
1372 if Symbol /= No_Symbol then
1373 Output (Start_Of_Processing, Dollar_Ptr - 1);
1374 Start_Of_Processing := Scan_Ptr;
1375 String_To_Name_Buffer
1376 (Mapping.Table (Symbol).Value);
1378 if Mapping.Table (Symbol).Is_A_String then
1380 -- Value is an Ada string
1382 Put_Char ('"');
1384 for J in 1 .. Name_Len loop
1385 Put_Char (Name_Buffer (J));
1387 if Name_Buffer (J) = '"' then
1388 Put_Char ('"');
1389 end if;
1390 end loop;
1392 Put_Char ('"');
1394 else
1395 -- Value is a sequence of characters, not
1396 -- an Ada string.
1398 for J in 1 .. Name_Len loop
1399 Put_Char (Name_Buffer (J));
1400 end loop;
1401 end if;
1402 end if;
1403 end if;
1404 end;
1405 end if;
1407 Scan.all;
1408 end loop;
1409 end if;
1411 Set_Ignore_Errors (To => False);
1412 end if;
1413 end if;
1415 pragma Assert (Token = Tok_End_Of_Line or Token = Tok_EOF);
1417 -- At this point, the token is either end of line or EOF.
1418 -- The line to possibly output stops just before the token.
1420 Output_Line (Start_Of_Processing, Token_Ptr - 1);
1422 -- If we are at the end of a line, the scan pointer is at the first
1423 -- non blank character, not necessarily the first character of the
1424 -- line; so, we have to deduct Start_Of_Processing from the token
1425 -- pointer.
1427 if Token = Tok_End_Of_Line then
1428 if (Sinput.Source (Token_Ptr) = ASCII.CR
1429 and then Sinput.Source (Token_Ptr + 1) = ASCII.LF)
1430 or else
1431 (Sinput.Source (Token_Ptr) = ASCII.CR
1432 and then Sinput.Source (Token_Ptr + 1) = ASCII.LF)
1433 then
1434 Start_Of_Processing := Token_Ptr + 2;
1435 else
1436 Start_Of_Processing := Token_Ptr + 1;
1437 end if;
1438 end if;
1440 -- Now, scan the first token of the next line. If the token is EOF,
1441 -- the scan pointer will not move, and the token will still be EOF.
1443 Set_Ignore_Errors (To => True);
1444 Scan.all;
1445 Set_Ignore_Errors (To => False);
1446 end loop Input_Line_Loop;
1448 -- Report an error for any missing some "#end if;"
1450 for Level in reverse 1 .. Pp_States.Last loop
1451 Error_Msg ("no `END IF` for this IF", Pp_States.Table (Level).If_Ptr);
1452 end loop;
1453 end Preprocess;
1455 end Prep;