Mark ChangeLog
[official-gcc.git] / gcc / ada / prep.adb
blob6b9000c7a0ce47989e4baaf87a06e8a11fb5b57f
1 ------------------------------------------------------------------------------
2 -- --
3 -- GNAT COMPILER COMPONENTS --
4 -- --
5 -- P R E P --
6 -- --
7 -- B o d y --
8 -- --
9 -- Copyright (C) 2002-2003, 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 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, 59 Temple Place - Suite 330, Boston, --
20 -- MA 02111-1307, USA. --
21 -- --
22 -- GNAT was originally developed by the GNAT team at New York University. --
23 -- Extensive contributions were provided by Ada Core Technologies Inc. --
24 -- --
25 ------------------------------------------------------------------------------
27 with Csets; use Csets;
28 with Err_Vars; use Err_Vars;
29 with Namet; use Namet;
30 with Opt; use Opt;
31 with Osint; use Osint;
32 with Output; use Output;
33 with Scans; use Scans;
34 with Snames; use Snames;
35 with Sinput;
36 with Stringt; use Stringt;
37 with Table;
38 with Types; use Types;
40 with GNAT.Heap_Sort_G;
42 package body Prep is
44 use Symbol_Table;
46 type Token_Name_Array is array (Token_Type) of Name_Id;
47 Token_Names : constant Token_Name_Array :=
48 (Tok_Abort => Name_Abort,
49 Tok_Abs => Name_Abs,
50 Tok_Abstract => Name_Abstract,
51 Tok_Accept => Name_Accept,
52 Tok_Aliased => Name_Aliased,
53 Tok_All => Name_All,
54 Tok_Array => Name_Array,
55 Tok_And => Name_And,
56 Tok_At => Name_At,
57 Tok_Begin => Name_Begin,
58 Tok_Body => Name_Body,
59 Tok_Case => Name_Case,
60 Tok_Constant => Name_Constant,
61 Tok_Declare => Name_Declare,
62 Tok_Delay => Name_Delay,
63 Tok_Delta => Name_Delta,
64 Tok_Digits => Name_Digits,
65 Tok_Else => Name_Else,
66 Tok_Elsif => Name_Elsif,
67 Tok_End => Name_End,
68 Tok_Entry => Name_Entry,
69 Tok_Exception => Name_Exception,
70 Tok_Exit => Name_Exit,
71 Tok_For => Name_For,
72 Tok_Function => Name_Function,
73 Tok_Generic => Name_Generic,
74 Tok_Goto => Name_Goto,
75 Tok_If => Name_If,
76 Tok_Is => Name_Is,
77 Tok_Limited => Name_Limited,
78 Tok_Loop => Name_Loop,
79 Tok_Mod => Name_Mod,
80 Tok_New => Name_New,
81 Tok_Null => Name_Null,
82 Tok_Of => Name_Of,
83 Tok_Or => Name_Or,
84 Tok_Others => Name_Others,
85 Tok_Out => Name_Out,
86 Tok_Package => Name_Package,
87 Tok_Pragma => Name_Pragma,
88 Tok_Private => Name_Private,
89 Tok_Procedure => Name_Procedure,
90 Tok_Protected => Name_Protected,
91 Tok_Raise => Name_Raise,
92 Tok_Range => Name_Range,
93 Tok_Record => Name_Record,
94 Tok_Rem => Name_Rem,
95 Tok_Renames => Name_Renames,
96 Tok_Requeue => Name_Requeue,
97 Tok_Return => Name_Return,
98 Tok_Reverse => Name_Reverse,
99 Tok_Select => Name_Select,
100 Tok_Separate => Name_Separate,
101 Tok_Subtype => Name_Subtype,
102 Tok_Tagged => Name_Tagged,
103 Tok_Task => Name_Task,
104 Tok_Terminate => Name_Terminate,
105 Tok_Then => Name_Then,
106 Tok_Type => Name_Type,
107 Tok_Until => Name_Until,
108 Tok_Use => Name_Use,
109 Tok_When => Name_When,
110 Tok_While => Name_While,
111 Tok_With => Name_With,
112 Tok_Xor => Name_Xor,
113 others => No_Name);
115 Already_Initialized : Boolean := False;
116 -- Used to avoid repetition of the part of the initialisation that needs
117 -- to be done only once.
119 Empty_String : String_Id;
120 -- "", as a string_id
122 String_False : String_Id;
123 -- "false", as a string_id
125 Name_Defined : Name_Id;
126 -- defined, as a name_id
128 ---------------
129 -- Behaviour --
130 ---------------
132 -- Accesses to procedure specified by procedure Initialize.
134 Error_Msg : Error_Msg_Proc;
135 -- Report an error
137 Scan : Scan_Proc;
138 -- Scan one token
140 Set_Ignore_Errors : Set_Ignore_Errors_Proc;
141 -- Indicate if error should be taken into account
143 Put_Char : Put_Char_Proc;
144 -- Output one character
146 New_EOL : New_EOL_Proc;
147 -- Output an end of line indication
149 -------------------------------
150 -- State of the Preprocessor --
151 -------------------------------
153 type Pp_State is record
154 If_Ptr : Source_Ptr;
155 -- The location of the #if statement.
156 -- Used to flag #if with no corresponding #end if, at the end.
158 Else_Ptr : Source_Ptr;
159 -- The location of the #else statement.
160 -- Used to detect multiple #else.
162 Deleting : Boolean;
163 -- Set to True when the code should be deleted or commented out.
165 Match_Seen : Boolean;
166 -- Set to True when a condition in an #if or an #elsif is True.
167 -- Also set to True if Deleting at the previous level is True.
168 -- Used to decide if Deleting should be set to True in a following
169 -- #elsif or #else.
171 end record;
173 type Pp_Depth is new Nat;
175 Ground : constant Pp_Depth := 0;
177 package Pp_States is new Table.Table
178 (Table_Component_Type => Pp_State,
179 Table_Index_Type => Pp_Depth,
180 Table_Low_Bound => 1,
181 Table_Initial => 10,
182 Table_Increment => 10,
183 Table_Name => "Prep.Pp_States");
184 -- A stack of the states of the preprocessor, for nested #if
186 type Operator is (None, Op_Or, Op_And);
188 -----------------
189 -- Subprograms --
190 -----------------
192 function Deleting return Boolean;
193 -- Return True if code should be deleted or commented out
195 function Expression (Evaluate_It : Boolean) 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
202 -- of the buffer.
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);
216 begin
217 if New_Name /= No_Name then
218 case Token is
219 when Tok_If | Tok_Else | Tok_Elsif | Tok_End |
220 Tok_And | Tok_Or | Tok_Then =>
221 if All_Keywords then
222 Token := Tok_Identifier;
223 Token_Name := New_Name;
224 end if;
226 when others =>
227 Token := Tok_Identifier;
228 Token_Name := New_Name;
229 end case;
230 end if;
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;
244 begin
245 -- Look for the character '='
247 for J in Definition'Range loop
248 if Definition (J) = '=' then
249 Index := J;
250 exit;
251 end if;
252 end loop;
254 -- If no character '=', then the value is True
256 if Index = 0 then
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, """");
266 else
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) /= '"'
277 then
278 for J in Index + 1 .. Definition'Last loop
279 case Definition (J) is
280 when '_' | '.' | '0' .. '9' |
281 'a' .. 'z' | 'A' .. 'Z' =>
282 null;
284 when others =>
285 Fail ("illegal value """,
286 Definition (Index + 1 .. Definition'Last),
287 """");
288 end case;
289 end loop;
290 end if;
292 -- And put the value in the result
294 Result.Is_A_String := False;
295 Start_String;
296 Store_String_Chars (Definition (Index + 1 .. Definition'Last));
297 Result.Value := End_String;
298 end if;
300 -- Now, check the syntax of the symbol (we don't allow accented and
301 -- wide characters)
303 if Name_Buffer (1) not in 'a' .. 'z'
304 and then Name_Buffer (1) not in 'A' .. 'Z'
305 then
306 Fail ("symbol """,
307 Name_Buffer (1 .. Name_Len),
308 """ does not start with a letter");
309 end if;
311 for J in 2 .. Name_Len loop
312 case Name_Buffer (J) is
313 when 'a' .. 'z' | 'A' .. 'Z' | '0' .. '9' =>
314 null;
316 when '_' =>
317 if J = Name_Len then
318 Fail ("symbol """,
319 Name_Buffer (1 .. Name_Len),
320 """ end with a '_'");
322 elsif Name_Buffer (J + 1) = '_' then
323 Fail ("symbol """,
324 Name_Buffer (1 .. Name_Len),
325 """ contains consecutive '_'");
326 end if;
328 when others =>
329 Fail ("symbol """,
330 Name_Buffer (1 .. Name_Len),
331 """ contains illegal character(s)");
332 end case;
333 end loop;
335 Result.On_The_Command_Line := True;
337 -- Put the symbol name in the result
339 declare
340 Sym : constant String :=
341 Name_Buffer (1 .. Name_Len);
343 begin
344 for Index in 1 .. Name_Len loop
345 Name_Buffer (Index) := Fold_Lower (Name_Buffer (Index));
346 end loop;
348 Result.Symbol := Name_Find;
349 Name_Len := Sym'Length;
350 Name_Buffer (1 .. Name_Len) := Sym;
351 Result.Original := Name_Find;
352 end;
354 Data := Result;
355 end Check_Command_Line_Symbol_Definition;
357 --------------
358 -- Deleting --
359 --------------
361 function Deleting return Boolean is
362 begin
363 -- Always return False when not inside an #if statement
365 if Pp_States.Last = Ground then
366 return False;
368 else
369 return Pp_States.Table (Pp_States.Last).Deleting;
370 end if;
371 end Deleting;
373 ----------------
374 -- Expression --
375 ----------------
377 function Expression (Evaluate_It : Boolean) return Boolean is
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;
385 -- Value of a term
387 Current_Operator : Operator := None;
388 Symbol1 : Symbol_Id;
389 Symbol2 : Symbol_Id;
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;
397 begin
398 -- Loop for each term
400 loop
401 Change_Reserved_Keyword_To_Symbol;
403 Current_Result := False;
405 case Token is
407 when Tok_Left_Paren =>
409 -- ( expression )
411 Scan.all;
412 Current_Result := Expression (Evaluation);
414 if Token = Tok_Right_Paren then
415 Scan.all;
417 else
418 Error_Msg ("`)` expected", Token_Ptr);
419 end if;
421 when Tok_Not =>
423 -- not expression
425 Scan.all;
426 Current_Result := not Expression (Evaluation);
428 when Tok_Identifier =>
429 Symbol_Name1 := Token_Name;
430 Symbol_Pos1 := Token_Ptr;
431 Scan.all;
433 if Token = Tok_Apostrophe then
434 -- symbol'Defined
436 Scan.all;
438 if Token = Tok_Identifier
439 and then Token_Name = Name_Defined
440 then
441 Scan.all;
443 else
444 Error_Msg ("identifier `Defined` expected", Token_Ptr);
445 end if;
447 if Evaluation then
448 Current_Result := Index_Of (Symbol_Name1) /= No_Symbol;
449 end if;
451 elsif Token = Tok_Equal then
452 Scan.all;
454 Change_Reserved_Keyword_To_Symbol;
456 if Token = Tok_Identifier then
458 -- symbol = symbol
460 Symbol_Name2 := Token_Name;
461 Symbol_Pos2 := Token_Ptr;
462 Scan.all;
464 if Evaluation then
465 Symbol1 := Index_Of (Symbol_Name1);
467 if Symbol1 = No_Symbol then
468 if Undefined_Symbols_Are_False then
469 Symbol_Value1 := String_False;
471 else
472 Error_Msg_Name_1 := Symbol_Name1;
473 Error_Msg ("unknown symbol %", Symbol_Pos1);
474 Symbol_Value1 := No_String;
475 end if;
477 else
478 Symbol_Value1 :=
479 Mapping.Table (Symbol1).Value;
480 end if;
482 Symbol2 := Index_Of (Symbol_Name2);
484 if Symbol2 = No_Symbol then
485 if Undefined_Symbols_Are_False then
486 Symbol_Value2 := String_False;
488 else
489 Error_Msg_Name_1 := Symbol_Name2;
490 Error_Msg ("unknown symbol %", Symbol_Pos2);
491 Symbol_Value2 := No_String;
492 end if;
494 else
495 Symbol_Value2 := Mapping.Table (Symbol2).Value;
496 end if;
498 if Symbol_Value1 /= No_String
499 and then Symbol_Value2 /= No_String
500 then
501 Current_Result := Matching_Strings
502 (Symbol_Value1, Symbol_Value2);
503 end if;
504 end if;
506 elsif Token = Tok_String_Literal then
508 -- symbol = "value"
510 if Evaluation then
511 Symbol1 := Index_Of (Symbol_Name1);
513 if Symbol1 = No_Symbol then
514 if Undefined_Symbols_Are_False then
515 Symbol_Value1 := String_False;
517 else
518 Error_Msg_Name_1 := Symbol_Name1;
519 Error_Msg ("unknown symbol %", Symbol_Pos1);
520 Symbol_Value1 := No_String;
521 end if;
523 else
524 Symbol_Value1 := Mapping.Table (Symbol1).Value;
525 end if;
527 if Symbol_Value1 /= No_String then
528 Current_Result :=
529 Matching_Strings
530 (Symbol_Value1,
531 String_Literal_Id);
532 end if;
533 end if;
535 Scan.all;
537 else
538 Error_Msg
539 ("symbol or literal string expected", Token_Ptr);
540 end if;
542 else
543 -- symbol (True or False)
545 if Evaluation then
546 Symbol1 := Index_Of (Symbol_Name1);
548 if Symbol1 = No_Symbol then
549 if Undefined_Symbols_Are_False then
550 Symbol_Value1 := String_False;
552 else
553 Error_Msg_Name_1 := Symbol_Name1;
554 Error_Msg ("unknown symbol %", Symbol_Pos1);
555 Symbol_Value1 := No_String;
556 end if;
558 else
559 Symbol_Value1 := Mapping.Table (Symbol1).Value;
560 end if;
562 if Symbol_Value1 /= No_String then
563 String_To_Name_Buffer (Symbol_Value1);
565 for Index in 1 .. Name_Len loop
566 Name_Buffer (Index) :=
567 Fold_Lower (Name_Buffer (Index));
568 end loop;
570 if Name_Buffer (1 .. Name_Len) = "true" then
571 Current_Result := True;
573 elsif Name_Buffer (1 .. Name_Len) = "false" then
574 Current_Result := False;
576 else
577 Error_Msg_Name_1 := Symbol_Name1;
578 Error_Msg
579 ("value of symbol % is not True or False",
580 Symbol_Pos1);
581 end if;
582 end if;
583 end if;
584 end if;
586 when others =>
587 Error_Msg ("`(`, NOT or symbol expected", Token_Ptr);
588 end case;
590 -- Update the cumulative final result
592 case Current_Operator is
593 when None =>
594 Final_Result := Current_Result;
596 when Op_Or =>
597 Final_Result := Final_Result or Current_Result;
599 when Op_And =>
600 Final_Result := Final_Result and Current_Result;
601 end case;
603 -- Check the next operator
605 if Token = Tok_And then
606 if Current_Operator = Op_Or then
607 Error_Msg ("mixing OR and AND is not allowed", Token_Ptr);
608 end if;
610 Current_Operator := Op_And;
611 Scan.all;
613 if Token = Tok_Then then
614 Scan.all;
616 if Final_Result = False then
617 Evaluation := False;
618 end if;
619 end if;
621 elsif Token = Tok_Or then
622 if Current_Operator = Op_And then
623 Error_Msg ("mixing AND and OR is not allowed", Token_Ptr);
624 end if;
626 Current_Operator := Op_Or;
627 Scan.all;
629 if Token = Tok_Else then
630 Scan.all;
632 if Final_Result then
633 Evaluation := False;
634 end if;
635 end if;
637 else
638 -- No operator: exit the term loop
640 exit;
641 end if;
642 end loop;
644 return Final_Result;
645 end Expression;
647 -----------------------
648 -- Go_To_End_Of_Line --
649 -----------------------
651 procedure Go_To_End_Of_Line is
652 begin
653 -- Scan until we get an end of line or we reach the end of the buffer
655 while Token /= Tok_End_Of_Line
656 and then Token /= Tok_EOF
657 loop
658 Scan.all;
659 end loop;
660 end Go_To_End_Of_Line;
662 --------------
663 -- Index_Of --
664 --------------
666 function Index_Of (Symbol : Name_Id) return Symbol_Id is
667 begin
668 if Mapping.Table /= null then
669 for J in Symbol_Id range 1 .. Symbol_Table.Last (Mapping) loop
670 if Mapping.Table (J).Symbol = Symbol then
671 return J;
672 end if;
673 end loop;
674 end if;
676 return No_Symbol;
677 end Index_Of;
679 ----------------
680 -- Preprocess --
681 ----------------
683 procedure Preprocess is
684 Start_Of_Processing : Source_Ptr;
685 Cond : Boolean;
686 Preprocessor_Line : Boolean := False;
688 procedure Output (From, To : Source_Ptr);
689 -- Output the characters with indices From .. To in the buffer
690 -- to the output file.
692 procedure Output_Line (From, To : Source_Ptr);
693 -- Output a line or the end of a line from the buffer to the output
694 -- file, followed by an end of line terminator.
695 -- Depending on the value of Deleting and the switches, the line
696 -- may be commented out, blank or not output at all.
698 ------------
699 -- Output --
700 ------------
702 procedure Output (From, To : Source_Ptr) is
703 begin
704 for J in From .. To loop
705 Put_Char (Sinput.Source (J));
706 end loop;
707 end Output;
709 -----------------
710 -- Output_Line --
711 -----------------
713 procedure Output_Line (From, To : Source_Ptr) is
714 begin
715 if Deleting or Preprocessor_Line then
716 if Blank_Deleted_Lines then
717 New_EOL.all;
719 elsif Comment_Deleted_Lines then
720 Put_Char ('-');
721 Put_Char ('-');
722 Put_Char ('!');
724 if From < To then
725 Put_Char (' ');
726 Output (From, To);
727 end if;
729 New_EOL.all;
730 end if;
732 else
733 Output (From, To);
734 New_EOL.all;
735 end if;
736 end Output_Line;
738 -- Start of processing for Preprocess
740 begin
741 Start_Of_Processing := Scan_Ptr;
743 -- We need to call Scan for the first time, because Initialyze_Scanner
744 -- is no longer doing it.
746 Scan.all;
748 Input_Line_Loop :
749 loop
750 exit Input_Line_Loop when Token = Tok_EOF;
752 Preprocessor_Line := False;
754 if Token /= Tok_End_Of_Line then
756 -- Preprocessor line
758 if Token = Tok_Special and then Special_Character = '#' then
759 Preprocessor_Line := True;
760 Scan.all;
762 case Token is
764 when Tok_If =>
765 -- #if
767 declare
768 If_Ptr : constant Source_Ptr := Token_Ptr;
770 begin
771 Scan.all;
772 Cond := Expression (not Deleting);
774 -- Check for an eventual "then"
776 if Token = Tok_Then then
777 Scan.all;
778 end if;
780 -- It is an error to have trailing characters after
781 -- the condition or "then".
783 if Token /= Tok_End_Of_Line
784 and then Token /= Tok_EOF
785 then
786 Error_Msg
787 ("extraneous text on preprocessor line",
788 Token_Ptr);
789 Go_To_End_Of_Line;
790 end if;
792 declare
793 -- Set the initial state of this new "#if".
794 -- This must be done before incrementing the
795 -- Last of the table, otherwise function
796 -- Deleting does not report the correct value.
798 New_State : constant Pp_State :=
799 (If_Ptr => If_Ptr,
800 Else_Ptr => 0,
801 Deleting => Deleting or (not Cond),
802 Match_Seen => Deleting or Cond);
804 begin
805 Pp_States.Increment_Last;
806 Pp_States.Table (Pp_States.Last) := New_State;
807 end;
808 end;
810 when Tok_Elsif =>
811 -- #elsif
813 Cond := False;
815 if Pp_States.Last = 0
816 or else Pp_States.Table (Pp_States.Last).Else_Ptr
817 /= 0
818 then
819 Error_Msg ("no IF for this ELSIF", Token_Ptr);
821 else
822 Cond :=
823 not Pp_States.Table (Pp_States.Last).Match_Seen;
824 end if;
826 Scan.all;
827 Cond := Expression (Cond);
829 -- Check for an eventual "then"
831 if Token = Tok_Then then
832 Scan.all;
833 end if;
835 -- It is an error to have trailing characters after
836 -- the condition or "then".
838 if Token /= Tok_End_Of_Line
839 and then Token /= Tok_EOF
840 then
841 Error_Msg
842 ("extraneous text on preprocessor line",
843 Token_Ptr);
845 Go_To_End_Of_Line;
846 end if;
848 -- Depending on the value of the condition, set the
849 -- new values of Deleting and Match_Seen.
850 if Pp_States.Last > 0 then
851 if Pp_States.Table (Pp_States.Last).Match_Seen then
852 Pp_States.Table (Pp_States.Last).Deleting :=
853 True;
854 else
855 if Cond then
856 Pp_States.Table (Pp_States.Last).Match_Seen :=
857 True;
858 Pp_States.Table (Pp_States.Last).Deleting :=
859 False;
860 end if;
861 end if;
862 end if;
864 when Tok_Else =>
865 -- #else
867 if Pp_States.Last = 0 then
868 Error_Msg ("no IF for this ELSE", Token_Ptr);
870 elsif
871 Pp_States.Table (Pp_States.Last).Else_Ptr /= 0
872 then
873 Error_Msg ("duplicate ELSE line", Token_Ptr);
874 end if;
876 -- Set the possibly new values of Deleting and
877 -- Match_Seen.
879 if Pp_States.Last > 0 then
880 if Pp_States.Table (Pp_States.Last).Match_Seen then
881 Pp_States.Table (Pp_States.Last).Deleting :=
882 True;
884 else
885 Pp_States.Table (Pp_States.Last).Match_Seen :=
886 True;
887 Pp_States.Table (Pp_States.Last).Deleting :=
888 False;
889 end if;
891 -- Set the Else_Ptr to check for illegal #elsif
892 -- later.
894 Pp_States.Table (Pp_States.Last).Else_Ptr :=
895 Token_Ptr;
896 end if;
898 Scan.all;
900 -- It is an error to have characters after "#else"
901 if Token /= Tok_End_Of_Line
902 and then Token /= Tok_EOF
903 then
904 Error_Msg
905 ("extraneous text on preprocessor line",
906 Token_Ptr);
907 Go_To_End_Of_Line;
908 end if;
910 when Tok_End =>
911 -- #end if;
913 if Pp_States.Last = 0 then
914 Error_Msg ("no IF for this END", Token_Ptr);
915 end if;
917 Scan.all;
919 if Token /= Tok_If then
920 Error_Msg ("IF expected", Token_Ptr);
922 else
923 Scan.all;
925 if Token /= Tok_Semicolon then
926 Error_Msg ("`;` Expected", Token_Ptr);
928 else
929 Scan.all;
931 -- It is an error to have character after
932 -- "#end if;".
933 if Token /= Tok_End_Of_Line
934 and then Token /= Tok_EOF
935 then
936 Error_Msg
937 ("extraneous text on preprocessor line",
938 Token_Ptr);
939 end if;
940 end if;
941 end if;
943 -- In case of one of the errors above, skip the tokens
944 -- until the end of line is reached.
946 Go_To_End_Of_Line;
948 -- Decrement the depth of the #if stack.
950 if Pp_States.Last > 0 then
951 Pp_States.Decrement_Last;
952 end if;
954 when others =>
955 -- Illegal preprocessor line
957 if Pp_States.Last = 0 then
958 Error_Msg ("IF expected", Token_Ptr);
960 elsif
961 Pp_States.Table (Pp_States.Last).Else_Ptr = 0
962 then
963 Error_Msg ("IF, ELSIF, ELSE, or `END IF` expected",
964 Token_Ptr);
966 else
967 Error_Msg ("IF or `END IF` expected", Token_Ptr);
968 end if;
970 -- Skip to the end of this illegal line
972 Go_To_End_Of_Line;
973 end case;
975 -- Not a preprocessor line
977 else
978 -- Do not report errors for those lines, even if there are
979 -- Ada parsing errors.
981 Set_Ignore_Errors (To => True);
983 if Deleting then
984 Go_To_End_Of_Line;
986 else
987 while Token /= Tok_End_Of_Line
988 and then Token /= Tok_EOF
989 loop
990 if Token = Tok_Special
991 and then Special_Character = '$'
992 then
993 declare
994 Dollar_Ptr : constant Source_Ptr := Token_Ptr;
995 Symbol : Symbol_Id;
997 begin
998 Scan.all;
999 Change_Reserved_Keyword_To_Symbol;
1001 if Token = Tok_Identifier
1002 and then Token_Ptr = Dollar_Ptr + 1
1003 then
1004 -- $symbol
1006 Symbol := Index_Of (Token_Name);
1008 -- If there is such a symbol, replace it by its
1009 -- value.
1011 if Symbol /= No_Symbol then
1012 Output (Start_Of_Processing, Dollar_Ptr - 1);
1013 Start_Of_Processing := Scan_Ptr;
1014 String_To_Name_Buffer
1015 (Mapping.Table (Symbol).Value);
1017 if Mapping.Table (Symbol).Is_A_String then
1019 -- Value is an Ada string
1021 Put_Char ('"');
1023 for J in 1 .. Name_Len loop
1024 Put_Char (Name_Buffer (J));
1026 if Name_Buffer (J) = '"' then
1027 Put_Char ('"');
1028 end if;
1029 end loop;
1031 Put_Char ('"');
1033 else
1034 -- Value is a sequence of characters, not
1035 -- an Ada string.
1037 for J in 1 .. Name_Len loop
1038 Put_Char (Name_Buffer (J));
1039 end loop;
1040 end if;
1041 end if;
1042 end if;
1043 end;
1044 end if;
1046 Scan.all;
1047 end loop;
1048 end if;
1050 Set_Ignore_Errors (To => False);
1051 end if;
1052 end if;
1054 pragma Assert (Token = Tok_End_Of_Line or Token = Tok_EOF);
1056 -- At this point, the token is either end of line or EOF.
1057 -- The line to possibly output stops just before the token.
1059 Output_Line (Start_Of_Processing, Token_Ptr - 1);
1061 -- If we are at the end of a line, the scan pointer is at the first
1062 -- non blank character, not necessarily the first character of the
1063 -- line; so, we have to deduct Start_Of_Processing from the token
1064 -- pointer.
1066 if Token = Tok_End_Of_Line then
1067 if (Sinput.Source (Token_Ptr) = ASCII.CR
1068 and then Sinput.Source (Token_Ptr + 1) = ASCII.LF)
1069 or else
1070 (Sinput.Source (Token_Ptr) = ASCII.CR
1071 and then Sinput.Source (Token_Ptr + 1) = ASCII.LF)
1072 then
1073 Start_Of_Processing := Token_Ptr + 2;
1075 else
1076 Start_Of_Processing := Token_Ptr + 1;
1077 end if;
1078 end if;
1080 -- Now, we scan the first token of the next line.
1081 -- If the token is EOF, the scan ponter will not move, and the token
1082 -- will still be EOF.
1084 Scan.all;
1085 end loop Input_Line_Loop;
1087 -- Report an error for any missing some "#end if;"
1089 for Level in reverse 1 .. Pp_States.Last loop
1090 Error_Msg ("no `END IF` for this IF", Pp_States.Table (Level).If_Ptr);
1091 end loop;
1092 end Preprocess;
1094 ----------------
1095 -- Initialize --
1096 ----------------
1098 procedure Initialize
1099 (Error_Msg : Error_Msg_Proc;
1100 Scan : Scan_Proc;
1101 Set_Ignore_Errors : Set_Ignore_Errors_Proc;
1102 Put_Char : Put_Char_Proc;
1103 New_EOL : New_EOL_Proc)
1105 begin
1106 if not Already_Initialized then
1107 Start_String;
1108 Store_String_Chars ("True");
1109 True_Value.Value := End_String;
1111 Start_String;
1112 Empty_String := End_String;
1114 Name_Len := 7;
1115 Name_Buffer (1 .. Name_Len) := "defined";
1116 Name_Defined := Name_Find;
1118 Start_String;
1119 Store_String_Chars ("False");
1120 String_False := End_String;
1122 Already_Initialized := True;
1123 end if;
1125 Prep.Error_Msg := Error_Msg;
1126 Prep.Scan := Scan;
1127 Prep.Set_Ignore_Errors := Set_Ignore_Errors;
1128 Prep.Put_Char := Put_Char;
1129 Prep.New_EOL := New_EOL;
1130 end Initialize;
1132 ------------------
1133 -- List_Symbols --
1134 ------------------
1136 procedure List_Symbols (Foreword : String) is
1137 Order : array (0 .. Integer (Symbol_Table.Last (Mapping)))
1138 of Symbol_Id;
1139 -- After alphabetical sorting, this array stores thehe indices of
1140 -- the symbols in the order they are displayed.
1142 function Lt (Op1, Op2 : Natural) return Boolean;
1143 -- Comparison routine for sort call
1145 procedure Move (From : Natural; To : Natural);
1146 -- Move routine for sort call
1148 --------
1149 -- Lt --
1150 --------
1152 function Lt (Op1, Op2 : Natural) return Boolean is
1153 S1 : constant String :=
1154 Get_Name_String (Mapping.Table (Order (Op1)).Symbol);
1155 S2 : constant String :=
1156 Get_Name_String (Mapping.Table (Order (Op2)).Symbol);
1158 begin
1159 return S1 < S2;
1160 end Lt;
1162 ----------
1163 -- Move --
1164 ----------
1166 procedure Move (From : Natural; To : Natural) is
1167 begin
1168 Order (To) := Order (From);
1169 end Move;
1171 package Sort_Syms is new GNAT.Heap_Sort_G (Move, Lt);
1173 Max_L : Natural;
1174 -- Maximum length of any symbol
1176 -- Start of processing for List_Symbols_Case
1178 begin
1179 if Symbol_Table.Last (Mapping) = 0 then
1180 return;
1181 end if;
1183 if Foreword'Length > 0 then
1184 Write_Eol;
1185 Write_Line (Foreword);
1187 for J in Foreword'Range loop
1188 Write_Char ('=');
1189 end loop;
1190 end if;
1192 -- Initialize the order
1194 for J in Order'Range loop
1195 Order (J) := Symbol_Id (J);
1196 end loop;
1198 -- Sort alphabetically
1200 Sort_Syms.Sort (Order'Last);
1202 Max_L := 7;
1204 for J in 1 .. Symbol_Table.Last (Mapping) loop
1205 Get_Name_String (Mapping.Table (J).Original);
1206 Max_L := Integer'Max (Max_L, Name_Len);
1207 end loop;
1209 Write_Eol;
1210 Write_Str ("Symbol");
1212 for J in 1 .. Max_L - 5 loop
1213 Write_Char (' ');
1214 end loop;
1216 Write_Line ("Value");
1218 Write_Str ("------");
1220 for J in 1 .. Max_L - 5 loop
1221 Write_Char (' ');
1222 end loop;
1224 Write_Line ("------");
1226 for J in 1 .. Order'Last loop
1227 declare
1228 Data : constant Symbol_Data := Mapping.Table (Order (J));
1230 begin
1231 Get_Name_String (Data.Original);
1232 Write_Str (Name_Buffer (1 .. Name_Len));
1234 for K in Name_Len .. Max_L loop
1235 Write_Char (' ');
1236 end loop;
1238 String_To_Name_Buffer (Data.Value);
1240 if Data.Is_A_String then
1241 Write_Char ('"');
1243 for J in 1 .. Name_Len loop
1244 Write_Char (Name_Buffer (J));
1246 if Name_Buffer (J) = '"' then
1247 Write_Char ('"');
1248 end if;
1249 end loop;
1251 Write_Char ('"');
1253 else
1254 Write_Str (Name_Buffer (1 .. Name_Len));
1255 end if;
1256 end;
1258 Write_Eol;
1259 end loop;
1261 Write_Eol;
1262 end List_Symbols;
1264 ----------------------
1265 -- Matching_Strings --
1266 ----------------------
1268 function Matching_Strings (S1, S2 : String_Id) return Boolean is
1269 begin
1270 String_To_Name_Buffer (S1);
1272 for Index in 1 .. Name_Len loop
1273 Name_Buffer (Index) := Fold_Lower (Name_Buffer (Index));
1274 end loop;
1276 declare
1277 String1 : constant String := Name_Buffer (1 .. Name_Len);
1279 begin
1280 String_To_Name_Buffer (S2);
1282 for Index in 1 .. Name_Len loop
1283 Name_Buffer (Index) := Fold_Lower (Name_Buffer (Index));
1284 end loop;
1286 return String1 = Name_Buffer (1 .. Name_Len);
1287 end;
1288 end Matching_Strings;
1290 --------------------
1291 -- Parse_Def_File --
1292 --------------------
1294 procedure Parse_Def_File is
1295 Symbol : Symbol_Id;
1296 Symbol_Name : Name_Id;
1297 Original_Name : Name_Id;
1298 Data : Symbol_Data;
1299 Value_Start : Source_Ptr;
1300 Value_End : Source_Ptr;
1301 Ch : Character;
1303 use ASCII;
1305 begin
1306 Def_Line_Loop :
1307 loop
1308 Scan.all;
1310 exit Def_Line_Loop when Token = Tok_EOF;
1312 if Token /= Tok_End_Of_Line then
1313 Change_Reserved_Keyword_To_Symbol;
1315 if Token /= Tok_Identifier then
1316 Error_Msg ("identifier expected", Token_Ptr);
1317 goto Cleanup;
1318 end if;
1320 Symbol_Name := Token_Name;
1321 Name_Len := 0;
1323 for Ptr in Token_Ptr .. Scan_Ptr - 1 loop
1324 Name_Len := Name_Len + 1;
1325 Name_Buffer (Name_Len) := Sinput.Source (Ptr);
1326 end loop;
1328 Original_Name := Name_Find;
1329 Scan.all;
1331 if Token /= Tok_Colon_Equal then
1332 Error_Msg ("`:=` expected", Token_Ptr);
1333 goto Cleanup;
1334 end if;
1336 Scan.all;
1338 if Token = Tok_String_Literal then
1339 Data := (Symbol => Symbol_Name,
1340 Original => Original_Name,
1341 On_The_Command_Line => False,
1342 Is_A_String => True,
1343 Value => String_Literal_Id);
1345 Scan.all;
1347 if Token /= Tok_End_Of_Line and then Token /= Tok_EOF then
1348 Error_Msg ("extraneous text in definition", Token_Ptr);
1349 goto Cleanup;
1350 end if;
1352 elsif Token = Tok_End_Of_Line or Token = Tok_EOF then
1353 Data := (Symbol => Symbol_Name,
1354 Original => Original_Name,
1355 On_The_Command_Line => False,
1356 Is_A_String => False,
1357 Value => Empty_String);
1359 else
1360 Value_Start := Token_Ptr;
1361 Value_End := Token_Ptr - 1;
1362 Scan_Ptr := Token_Ptr;
1364 Value_Chars_Loop :
1365 loop
1366 Ch := Sinput.Source (Scan_Ptr);
1368 case Ch is
1369 when '_' | '.' | '0' .. '9' | 'a' .. 'z' | 'A' .. 'Z' =>
1370 Value_End := Scan_Ptr;
1371 Scan_Ptr := Scan_Ptr + 1;
1373 when ' ' | HT | VT | CR | LF | FF =>
1374 exit Value_Chars_Loop;
1376 when others =>
1377 Error_Msg ("illegal character", Scan_Ptr);
1378 goto Cleanup;
1379 end case;
1380 end loop Value_Chars_Loop;
1382 Scan.all;
1384 if Token /= Tok_End_Of_Line and then Token /= Tok_EOF then
1385 Error_Msg ("extraneous text in definition", Token_Ptr);
1386 goto Cleanup;
1387 end if;
1389 Start_String;
1391 while Value_Start <= Value_End loop
1392 Store_String_Char (Sinput.Source (Value_Start));
1393 Value_Start := Value_Start + 1;
1394 end loop;
1396 Data := (Symbol => Symbol_Name,
1397 Original => Original_Name,
1398 On_The_Command_Line => False,
1399 Is_A_String => False,
1400 Value => End_String);
1401 end if;
1403 -- Now that we have the value, get the symbol index
1405 Symbol := Index_Of (Symbol_Name);
1407 if Symbol /= No_Symbol then
1408 -- If we already have an entry for this symbol, replace it
1409 -- with the new value, except if the symbol was declared
1410 -- on the command line.
1412 if Mapping.Table (Symbol).On_The_Command_Line then
1413 goto Continue;
1414 end if;
1416 else
1417 -- As it is the first time we see this symbol, create a new
1418 -- entry in the table.
1420 if Mapping.Table = null then
1421 Symbol_Table.Init (Mapping);
1422 end if;
1424 Symbol_Table.Increment_Last (Mapping);
1425 Symbol := Symbol_Table.Last (Mapping);
1426 end if;
1428 Mapping.Table (Symbol) := Data;
1429 goto Continue;
1431 <<Cleanup>>
1432 Set_Ignore_Errors (To => True);
1434 while Token /= Tok_End_Of_Line and Token /= Tok_EOF loop
1435 Scan.all;
1436 end loop;
1438 Set_Ignore_Errors (To => False);
1440 <<Continue>>
1441 null;
1442 end if;
1443 end loop Def_Line_Loop;
1444 end Parse_Def_File;
1446 end Prep;