1 ------------------------------------------------------------------------------
3 -- GNAT COMPILER COMPONENTS --
11 -- Copyright (C) 1996-2001, Free Software Foundation, Inc. --
13 -- GNAT is free software; you can redistribute it and/or modify it under --
14 -- terms of the GNU General Public License as published by the Free Soft- --
15 -- ware Foundation; either version 2, or (at your option) any later ver- --
16 -- sion. GNAT is distributed in the hope that it will be useful, but WITH- --
17 -- OUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY --
18 -- or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License --
19 -- for more details. You should have received a copy of the GNU General --
20 -- Public License distributed with GNAT; see file COPYING. If not, write --
21 -- to the Free Software Foundation, 59 Temple Place - Suite 330, Boston, --
22 -- MA 02111-1307, USA. --
24 -- GNAT was originally developed by the GNAT team at New York University. --
25 -- It is now maintained by Ada Core Technologies Inc (http://www.gnat.com). --
27 ------------------------------------------------------------------------------
29 with Ada
.Characters
.Handling
; use Ada
.Characters
.Handling
;
30 with Ada
.Strings
.Fixed
;
31 with Ada
.Command_Line
; use Ada
.Command_Line
;
32 with Ada
.Text_IO
; use Ada
.Text_IO
;
34 with GNAT
.Heap_Sort_G
;
35 with GNAT
.Command_Line
;
40 pragma Ident
(Gnatvsn
.Gnat_Version_String
);
42 Version_String
: constant String := "$Revision: 1.27 $";
44 type Strptr
is access String;
46 Usage_Error
: exception;
47 -- Raised if a usage error is detected, causes termination of processing
48 -- with an appropriate error message and error exit status set.
50 Fatal_Error
: exception;
51 -- Exception raised if fatal error detected
53 Expression_Error
: exception;
54 -- Exception raised when an invalid boolean expression is found
55 -- on a preprocessor line
57 ------------------------
58 -- Argument Line Data --
59 ------------------------
62 Outfile_Name
: Strptr
;
63 Deffile_Name
: Strptr
;
70 Opt_Comment_Deleted_Lines
: Boolean := False; -- Set if -c switch set
71 Blank_Deleted_Lines
: Boolean := False; -- Set if -b switch set
72 List_Symbols
: Boolean := False; -- Set if -s switch set
73 Source_Ref_Pragma
: Boolean := False; -- Set if -r switch set
74 Undefined_Is_False
: Boolean := False; -- Set if -u switch set
75 -- Record command line options
77 ---------------------------
78 -- Definitions File Data --
79 ---------------------------
81 Num_Syms
: Natural := 0;
82 -- Number of symbols defined in definitions file
84 Symbols
: array (0 .. 10_000
) of Strptr
;
85 Values
: array (0 .. 10_000
) of Strptr
;
86 -- Symbol names and values. Note that the zero'th element is used only
87 -- during the call to Sort (to hold a temporary value, as required by
88 -- the GNAT.Heap_Sort_G interface).
94 Current_File_Name
: Strptr
;
95 -- Holds name of file being read (definitions file or input file)
97 Line_Buffer
: String (1 .. 20_000
);
100 Line_Length
: Natural;
101 -- Length of line in Line_Buffer
104 -- Current input file line number
107 -- Input scan pointer for line in Line_Buffer
109 type Keyword
is (K_Not
, K_Then
, K_If
, K_Else
, K_End
, K_Elsif
,
110 K_And
, K_Or
, K_Open_Paren
, K_Close_Paren
,
111 K_Defined
, K_Andthen
, K_Orelse
, K_Equal
, K_None
);
112 -- Keywords that are recognized on preprocessor lines. K_None indicates
113 -- that no keyword was present.
118 Start_Sym
, End_Sym
: Natural;
119 -- First and last positions of scanned symbol
121 Num_Errors
: Natural := 0;
122 -- Number of errors detected
124 -----------------------
125 -- Preprocessor Data --
126 -----------------------
128 -- The following record represents the state of an #if structure:
130 type PP_Rec
is record
132 -- Line number for #if line
135 -- Line number for #else line, zero = no else seen yet
138 -- True if lines currently being deleted
140 Match_Seen
: Boolean;
141 -- True if either the #if condition or one of the previously seen
142 -- #elsif lines was true, meaning that any future #elsif sections
143 -- or the #else section, is to be deleted.
147 -- Preprocessor #if nesting level. A value of zero means that we are
148 -- outside any #if structure.
150 PP
: array (0 .. 100) of PP_Rec
;
151 -- Stack of records showing state of #if structures. PP (1) is the
152 -- outer level entry, and PP (PP_Depth) is the active entry. PP (0)
153 -- contains a dummy entry whose Deleting flag is always set to False.
159 function At_End_Of_Line
return Boolean;
160 -- First advances Ptr using Skip_Spaces. Then returns True if Ptr is
161 -- either at the end of the line, or at a -- comment sequence.
163 procedure Error
(Msg
: String);
164 -- Post error message with given text. The line number is taken from
165 -- Line_Num, and the column number from Ptr.
167 function Eval_Condition
168 (Parenthesis
: Natural := 0;
169 Do_Eval
: Boolean := True)
171 -- Eval the condition found in the current Line. The condition can
172 -- include any of the 'and', 'or', 'not', and parenthesis subexpressions.
173 -- If Line is an invalid expression, then Expression_Error is raised,
174 -- after an error message has been printed. Line can include 'then'
175 -- followed by a comment, which is automatically ignored. If Do_Eval
176 -- is False, then the expression is not evaluated at all, and symbols
179 function Eval_Symbol
(Do_Eval
: Boolean) return Boolean;
180 -- Read and evaluate the next symbol or expression (A, A'Defined, A=...)
181 -- If it is followed by 'Defined or an equality test, read as many symbols
182 -- as needed. Do_Eval has the same meaning as in Eval_Condition
185 -- Print a help page to summarize the usage of gnatprep
187 function Is_Preprocessor_Line
return Boolean;
188 -- Tests if current line is a preprocessor line, i.e. that its first
189 -- non-blank character is a # character. If so, then a result of True
190 -- is returned, and Ptr is set to point to the character following the
191 -- # character. If not, False is returned and Ptr is undefined.
194 -- Make sure no junk is present on a preprocessor line. Ptr points past
195 -- the scanned preprocessor syntax.
197 function OK_Identifier
(S
: String) return Boolean;
198 -- Tests if given referenced string is valid Ada identifier
200 function Matching_Strings
(S1
, S2
: String) return Boolean;
201 -- Check if S1 and S2 are the same string (this is a case independent
202 -- comparison, lower and upper case letters are considered to match).
203 -- Duplicate quotes in S2 are considered as a single quote ("" => ")
205 procedure Parse_Def_File
;
206 -- Parse the deffile given by the user
208 function Scan_Keyword
return Keyword
;
209 -- Advances Ptr to end of line or next non-blank using Skip_Spaces. Then
210 -- attempts to scan out a recognized keyword. if a recognized keyword is
211 -- found, sets Ptr past it, and returns the code for the keyword, if not,
212 -- then Ptr is left unchanged pointing to a non-blank character or to the
215 function Symbol_Scanned
return Boolean;
216 -- On entry, Start_Sym is set to the first character of an identifier
217 -- symbol to be scanned out. On return, End_Sym is set to the last
218 -- character of the identifier, and the result indicates if the scanned
219 -- symbol is a valid identifier (True = valid). Ptr is not changed.
221 procedure Skip_Spaces
;
222 -- Skips Ptr past tabs and spaces to next non-blank, or one character
223 -- past the end of line.
225 function Variable_Index
(Name
: String) return Natural;
226 -- Returns the index of the variable in the table. If the variable is not
227 -- found, returns Natural'Last
233 function At_End_Of_Line
return Boolean is
237 return Ptr
> Line_Length
239 (Ptr
< Line_Length
and then Line_Buffer
(Ptr
.. Ptr
+ 1) = "--");
246 procedure Error
(Msg
: String) is
247 L
: constant String := Natural'Image (Line_Num
);
248 C
: constant String := Natural'Image (Ptr
);
251 Put
(Standard_Error
, Current_File_Name
.all);
252 Put
(Standard_Error
, ':');
253 Put
(Standard_Error
, L
(2 .. L
'Length));
254 Put
(Standard_Error
, ':');
255 Put
(Standard_Error
, C
(2 .. C
'Length));
256 Put
(Standard_Error
, ": ");
258 Put_Line
(Standard_Error
, Msg
);
259 Num_Errors
:= Num_Errors
+ 1;
266 function Eval_Condition
267 (Parenthesis
: Natural := 0;
268 Do_Eval
: Boolean := True)
271 Symbol_Is_True
: Boolean := False; -- init to avoid warning
275 -- Find the next subexpression
281 Symbol_Is_True
:= Eval_Symbol
(Do_Eval
);
285 -- Not applies to the next subexpression (either a simple
286 -- evaluation like A or A'Defined, or a parenthesis expression)
290 if K
= K_Open_Paren
then
291 Symbol_Is_True
:= not Eval_Condition
(Parenthesis
+ 1, Do_Eval
);
293 elsif K
= K_None
then
294 Symbol_Is_True
:= not Eval_Symbol
(Do_Eval
);
297 Ptr
:= Start_Sym
; -- Puts the keyword back
301 Symbol_Is_True
:= Eval_Condition
(Parenthesis
+ 1, Do_Eval
);
305 Error
("invalid syntax in preprocessor line");
306 raise Expression_Error
;
309 -- Do we have a compound expression with AND, OR, ...
314 if not At_End_Of_Line
then
315 Error
("Invalid Syntax at end of line");
316 raise Expression_Error
;
319 if Parenthesis
/= 0 then
320 Error
("Unmatched opening parenthesis");
321 raise Expression_Error
;
324 return Symbol_Is_True
;
327 if Parenthesis
/= 0 then
328 Error
("Unmatched opening parenthesis");
329 raise Expression_Error
;
332 return Symbol_Is_True
;
334 when K_Close_Paren
=>
335 if Parenthesis
= 0 then
336 Error
("Unmatched closing parenthesis");
337 raise Expression_Error
;
340 return Symbol_Is_True
;
343 return Symbol_Is_True
and Eval_Condition
(Parenthesis
, Do_Eval
);
346 if not Symbol_Is_True
then
348 -- Just skip the symbols for the remaining part
350 Symbol_Is_True
:= Eval_Condition
(Parenthesis
, False);
354 return Eval_Condition
(Parenthesis
, Do_Eval
);
358 return Symbol_Is_True
or Eval_Condition
(Parenthesis
, Do_Eval
);
361 if Symbol_Is_True
then
363 -- Just skip the symbols for the remaining part
365 Symbol_Is_True
:= Eval_Condition
(Parenthesis
, False);
369 return Eval_Condition
(Parenthesis
, Do_Eval
);
373 Error
("invalid syntax in preprocessor line");
374 raise Expression_Error
;
383 function Eval_Symbol
(Do_Eval
: Boolean) return Boolean is
384 Sym
: constant String := Line_Buffer
(Start_Sym
.. End_Sym
);
387 Symbol_Defined
: Boolean := False;
388 Symbol_Is_True
: Boolean := False;
396 if not Symbol_Scanned
then
397 Error
("invalid symbol name");
398 raise Expression_Error
;
403 -- Test if we have a simple test (A) or a more complicated one
408 if K
/= K_Defined
and then K
/= K_Equal
then
409 Ptr
:= Start_Sym
; -- Puts the keyword back
412 Index
:= Variable_Index
(Sym
);
416 Symbol_Defined
:= Index
/= Natural'Last;
417 Symbol_Is_True
:= Symbol_Defined
;
421 -- Read the second part of the statement
425 if not Symbol_Scanned
426 and then End_Sym
< Start_Sym
428 Error
("No right part for the equality test");
429 raise Expression_Error
;
434 -- If the variable was not found
437 if Index
= Natural'Last then
438 if not Undefined_Is_False
then
439 Error
("symbol name """ & Sym
&
440 """ is not defined in definitions file");
445 Right
: constant String
446 := Line_Buffer
(Start_Sym
.. End_Sym
);
449 if Right
(Right
'First) = '"' then
453 Right
(Right
'First + 1 .. Right
'Last - 1));
455 Index_R
:= Variable_Index
(Right
);
456 if Index_R
= Natural'Last then
457 Error
("Variable " & Right
& " in test is "
459 raise Expression_Error
;
462 Matching_Strings
(Values
(Index
).all,
463 Values
(Index_R
).all);
472 if Index
= Natural'Last then
474 Symbol_Defined
:= False;
475 if Do_Eval
and then not Symbol_Defined
then
476 if Undefined_Is_False
then
477 Symbol_Defined
:= True;
478 Symbol_Is_True
:= False;
482 ("symbol name """ & Sym
&
483 """ is not defined in definitions file");
487 elsif not Do_Eval
then
488 Symbol_Is_True
:= True;
490 elsif Matching_Strings
(Values
(Index
).all, "True") then
491 Symbol_Is_True
:= True;
493 elsif Matching_Strings
(Values
(Index
).all, "False") then
494 Symbol_Is_True
:= False;
497 Error
("symbol value is not True or False");
498 Symbol_Is_True
:= False;
503 return Symbol_Is_True
;
510 procedure Help_Page
is
512 Put_Line
(Standard_Error
,
513 "GNAT Preprocessor Version " &
514 Version_String
(12 .. 15) &
515 " Copyright 1996-2001 Free Software Foundation, Inc.");
516 Put_Line
(Standard_Error
,
517 "Usage: gnatprep [-bcrsu] [-Dsymbol=value] infile " &
518 "outfile [deffile]");
519 New_Line
(Standard_Error
);
520 Put_Line
(Standard_Error
, " infile Name of the input file");
521 Put_Line
(Standard_Error
, " outfile Name of the output file");
522 Put_Line
(Standard_Error
, " deffile Name of the definition file");
523 New_Line
(Standard_Error
);
524 Put_Line
(Standard_Error
, "gnatprep switches:");
525 Put_Line
(Standard_Error
, " -b Replace preprocessor lines by " &
527 Put_Line
(Standard_Error
, " -c Keep preprocessor lines as comments");
528 Put_Line
(Standard_Error
, " -D Associate symbol with value");
529 Put_Line
(Standard_Error
, " -r Generate Source_Reference pragma");
530 Put_Line
(Standard_Error
, " -s Print a sorted list of symbol names " &
532 Put_Line
(Standard_Error
, " -u Treat undefined symbols as FALSE");
533 New_Line
(Standard_Error
);
536 --------------------------
537 -- Is_Preprocessor_Line --
538 --------------------------
540 function Is_Preprocessor_Line
return Boolean is
544 while Ptr
<= Line_Length
loop
545 if Line_Buffer
(Ptr
) = '#' then
549 elsif Line_Buffer
(Ptr
) > ' ' then
558 end Is_Preprocessor_Line
;
560 ----------------------
561 -- Matching_Strings --
562 ----------------------
564 function Matching_Strings
(S1
, S2
: String) return Boolean is
565 S2_Index
: Integer := S2
'First;
568 for S1_Index
in S1
'Range loop
570 if To_Upper
(S1
(S1_Index
)) /= To_Upper
(S2
(S2_Index
)) then
574 if S2
(S2_Index
) = '"'
575 and then S2_Index
< S2
'Last
576 and then S2
(S2_Index
+ 1) = '"'
578 S2_Index
:= S2_Index
+ 2;
580 S2_Index
:= S2_Index
+ 1;
583 -- If S2 was too short then
585 if S2_Index
> S2
'Last and then S1_Index
< S1
'Last then
591 return S2_Index
= S2
'Last + 1;
592 end Matching_Strings
;
603 or else (Ptr
< Line_Length
604 and then Line_Buffer
(Ptr
.. Ptr
+ 1) /= "--")
606 Error
("extraneous text on preprocessor line ignored");
614 function OK_Identifier
(S
: String) return Boolean is
615 P
: Natural := S
'First;
618 if S
'Length /= 0 and then S
(P
) = Character'Val (39) then -- '''
623 or else not Is_Letter
(S
(P
))
628 while P
<= S
'Last loop
629 if Is_Letter
(S
(P
)) or Is_Digit
(S
(P
)) then
634 and then S
(P
+ 1) /= '_'
653 procedure Parse_Def_File
is
655 Open
(Deffile
, In_File
, Deffile_Name
.all);
658 Current_File_Name
:= Deffile_Name
;
660 -- Loop through lines in symbol definitions file
662 while not End_Of_File
(Deffile
) loop
663 Get_Line
(Deffile
, Line_Buffer
, Line_Length
);
664 Line_Num
:= Line_Num
+ 1;
670 or else (Ptr
< Line_Length
672 Line_Buffer
(Ptr
.. Ptr
+ 1) = "--")
679 if not Symbol_Scanned
then
680 Error
("invalid symbol identifier """ &
681 Line_Buffer
(Start_Sym
.. End_Sym
) &
689 if Ptr
>= Line_Length
690 or else Line_Buffer
(Ptr
.. Ptr
+ 1) /= ":="
692 Error
("missing "":="" in symbol definition line");
699 Num_Syms
:= Num_Syms
+ 1;
700 Symbols
(Num_Syms
) := new String'(Line_Buffer (Start_Sym .. End_Sym));
705 if At_End_Of_Line then
708 elsif Line_Buffer (Start_Sym) = '"' then
709 End_Sym := End_Sym + 1;
711 End_Sym := End_Sym + 1;
713 if End_Sym > Line_Length then
714 Error ("no closing quote
for string constant");
717 elsif End_Sym < Line_Length
718 and then Line_Buffer (End_Sym .. End_Sym + 1) = """"""
720 End_Sym := End_Sym + 1;
722 elsif Line_Buffer (End_Sym) = '"' then
730 while End_Sym < Line_Length
731 and then (Is_Alphanumeric (Line_Buffer (End_Sym + 1))
733 Line_Buffer (End_Sym + 1) = '_
'
735 Line_Buffer (End_Sym + 1) = '.')
737 End_Sym := End_Sym + 1;
742 if not At_End_Of_Line then
743 Error ("incorrect symbol value syntax");
748 Values (Num_Syms) := new String'(Line_Buffer
(Start_Sym
.. End_Sym
));
755 -- Could not open the file
758 Put_Line
(Standard_Error
, "cannot open " & Deffile_Name
.all);
766 function Scan_Keyword
return Keyword
is
767 Kptr
: constant Natural := Ptr
;
773 if Symbol_Scanned
then
775 -- If the symbol was the last thing on the line, End_Sym will
776 -- point too far in Line_Buffer
778 if End_Sym
> Line_Length
then
779 End_Sym
:= Line_Length
;
785 Sym
: constant String := Line_Buffer
(Start_Sym
.. End_Sym
);
788 if Matching_Strings
(Sym
, "not") then
791 elsif Matching_Strings
(Sym
, "then") then
794 elsif Matching_Strings
(Sym
, "if") then
797 elsif Matching_Strings
(Sym
, "else") then
800 elsif Matching_Strings
(Sym
, "end") then
803 elsif Matching_Strings
(Sym
, "elsif") then
806 elsif Matching_Strings
(Sym
, "and") then
807 if Scan_Keyword
= K_Then
then
811 Ptr
:= Start_Sym
; -- Put back the last keyword read
816 elsif Matching_Strings
(Sym
, "or") then
817 if Scan_Keyword
= K_Else
then
821 Ptr
:= Start_Sym
; -- Put back the last keyword read
826 elsif Matching_Strings
(Sym
, "'defined") then
833 return K_Close_Paren
;
849 procedure Skip_Spaces
is
851 while Ptr
<= Line_Length
loop
852 if Line_Buffer
(Ptr
) /= ' '
853 and then Line_Buffer
(Ptr
) /= ASCII
.HT
866 function Symbol_Scanned
return Boolean is
868 End_Sym
:= Start_Sym
- 1;
870 case Line_Buffer
(End_Sym
+ 1) is
872 when '(' |
')' |
'=' =>
873 End_Sym
:= End_Sym
+ 1;
877 End_Sym
:= End_Sym
+ 1;
878 while End_Sym
< Line_Length
loop
880 if Line_Buffer
(End_Sym
+ 1) = '"' then
882 if End_Sym
+ 2 < Line_Length
883 and then Line_Buffer
(End_Sym
+ 2) = '"'
885 End_Sym
:= End_Sym
+ 2;
890 End_Sym
:= End_Sym
+ 1;
894 if End_Sym
>= Line_Length
then
895 Error
("Invalid string ");
896 raise Expression_Error
;
899 End_Sym
:= End_Sym
+ 1;
903 End_Sym
:= End_Sym
+ 1;
909 while End_Sym
< Line_Length
910 and then (Is_Alphanumeric
(Line_Buffer
(End_Sym
+ 1))
911 or else Line_Buffer
(End_Sym
+ 1) = '_')
913 End_Sym
:= End_Sym
+ 1;
916 return OK_Identifier
(Line_Buffer
(Start_Sym
.. End_Sym
));
923 function Variable_Index
(Name
: String) return Natural is
925 for J
in 1 .. Num_Syms
loop
926 if Matching_Strings
(Symbols
(J
).all, Name
) then
934 -- Start of processing for GNATprep
938 -- Parse the switches
941 case GNAT
.Command_Line
.Getopt
("D: b c r s u") is
947 S
: String := GNAT
.Command_Line
.Parameter
;
951 Index
:= Ada
.Strings
.Fixed
.Index
(S
, "=");
954 Num_Syms
:= Num_Syms
+ 1;
955 Symbols
(Num_Syms
) := new String'(S);
956 Values (Num_Syms) := new String'("True");
959 Num_Syms
:= Num_Syms
+ 1;
960 Symbols
(Num_Syms
) := new String'(S (S'First .. Index - 1));
961 Values (Num_Syms) := new String'(S
(Index
+ 1 .. S
'Last));
966 Blank_Deleted_Lines
:= True;
969 Opt_Comment_Deleted_Lines
:= True;
972 Source_Ref_Pragma
:= True;
975 List_Symbols
:= True;
978 Undefined_Is_False
:= True;
985 -- Get the file names
989 S
: constant String := GNAT
.Command_Line
.Get_Argument
;
992 exit when S
'Length = 0;
994 if Infile_Name
= null then
995 Infile_Name
:= new String'(S);
996 elsif Outfile_Name = null then
997 Outfile_Name := new String'(S
);
998 elsif Deffile_Name
= null then
999 Deffile_Name
:= new String'(S);
1006 -- Test we had all the arguments needed
1008 if Infile_Name = null
1009 or else Outfile_Name = null
1014 if Source_Ref_Pragma and (not Opt_Comment_Deleted_Lines) then
1015 Blank_Deleted_Lines := True;
1018 -- Get symbol definitions
1020 if Deffile_Name /= null then
1024 if Num_Errors > 0 then
1027 elsif List_Symbols and then Num_Syms > 0 then
1028 List_Symbols_Case : declare
1030 function Lt (Op1, Op2 : Natural) return Boolean;
1031 -- Comparison routine for sort call
1033 procedure Move (From : Natural; To : Natural);
1034 -- Move routine for sort call
1036 function Lt (Op1, Op2 : Natural) return Boolean is
1037 L1 : constant Natural := Symbols (Op1)'Length;
1038 L2 : constant Natural := Symbols (Op2)'Length;
1039 MinL : constant Natural := Natural'Min (L1, L2);
1044 for J in 0 .. MinL - 1 loop
1045 C1 := To_Upper (Symbols (Op1).all (Symbols (Op1)'First + J));
1046 C2 := To_Upper (Symbols (Op2).all (Symbols (Op2)'First + J));
1059 procedure Move (From : Natural; To : Natural) is
1061 Symbols (To) := Symbols (From);
1062 Values (To) := Values (From);
1065 package Sort_Syms is new GNAT.Heap_Sort_G (Move, Lt);
1068 -- Maximum length of any symbol
1070 -- Start of processing for List_Symbols_Case
1073 Sort_Syms.Sort (Num_Syms);
1076 for J in 1 .. Num_Syms loop
1077 Max_L := Natural'Max (Max_L, Symbols (J)'Length);
1083 for J in 1 .. Max_L - 5 loop
1091 for J in 1 .. Max_L - 5 loop
1095 Put_Line ("------");
1097 for J in 1 .. Num_Syms loop
1098 Put (Symbols (J).all);
1100 for K in 1 .. Max_L - Symbols (J)'Length + 1 loop
1104 Put_Line (Values (J).all);
1108 end List_Symbols_Case;
1111 -- Open files and initialize preprocessing
1114 Open (Infile, In_File, Infile_Name.all);
1118 Put_Line (Standard_Error, "cannot open " & Infile_Name.all);
1123 Create (Outfile, Out_File, Outfile_Name.all);
1127 Put_Line (Standard_Error, "cannot create " & Outfile_Name.all);
1131 if Source_Ref_Pragma then
1133 (Outfile, "pragma Source_Reference (1, """ & Infile_Name.all & """);");
1137 Current_File_Name := Infile_Name;
1140 PP (0).Deleting := False;
1142 -- Loop through lines in input file
1144 while not End_Of_File (Infile) loop
1145 Get_Line (Infile, Line_Buffer, Line_Length);
1146 Line_Num := Line_Num + 1;
1148 -- Handle preprocessor line
1150 if Is_Preprocessor_Line then
1155 -- If/Elsif processing
1157 when K_If | K_Elsif =>
1159 -- If differs from elsif only in that an initial stack entry
1160 -- must be made for the new if range. We set the match seen
1161 -- entry to a copy of the deleting status in the range above
1162 -- us. If we are deleting in the range above us, then we want
1163 -- all the branches of the nested #if to delete.
1166 PP_Depth := PP_Depth + 1;
1168 (If_Line => Line_Num,
1171 Match_Seen => PP (PP_Depth - 1).Deleting);
1173 elsif PP_Depth = 0 then
1174 Error ("no matching #if for this #elsif");
1179 PP (PP_Depth).Deleting := True;
1181 if not PP (PP_Depth).Match_Seen
1182 and then Eval_Condition = True
1185 -- Case of match and no match yet in this #if
1187 PP (PP_Depth).Deleting := False;
1188 PP (PP_Depth).Match_Seen := True;
1192 -- Processing for #else
1196 if PP_Depth = 0 then
1197 Error ("no matching #if for this #else");
1199 elsif PP (PP_Depth).Else_Line /= 0 then
1200 Error ("duplicate #else line (previous was on line" &
1201 Natural'Image (PP (PP_Depth).Else_Line) &
1205 PP (PP_Depth).Else_Line := Line_Num;
1206 PP (PP_Depth).Deleting := PP (PP_Depth).Match_Seen;
1215 if PP_Depth = 0 then
1216 Error ("no matching #if for this #end");
1221 if Scan_Keyword /= K_If then
1222 Error ("expected if after #end");
1223 Ptr := Line_Length + 1;
1228 if Ptr > Line_Length
1229 or else Line_Buffer (Ptr) /= ';'
1231 Error ("missing semicolon after #end if");
1238 PP_Depth := PP_Depth - 1;
1242 Error ("invalid preprocessor keyword syntax");
1246 -- Handle symbol substitution
1248 -- Substitution is not allowed in string (which we simply skip),
1249 -- but is allowed inside character constants. The last case is
1250 -- because there is no way to know whether the user want to
1251 -- substitute the name of an attribute ('Min
or 'Max for instance)
1252 -- or actually meant to substitue a character ('$name
' is probably
1253 -- a character constant, but my_type'$name
'Min is probably an
1254 -- attribute, with $name=Base)
1259 while Ptr
< Line_Length
loop
1260 exit when At_End_Of_Line
;
1262 case Line_Buffer
(Ptr
) is
1266 -- Two special cases here:
1267 -- '"' => we don't want the " sign to appear as belonging
1269 -- '$' => this is obviously not a substitution, just skip it
1271 if Ptr
< Line_Length
- 1
1272 and then Line_Buffer
(Ptr
+ 1) = '"'
1275 elsif Ptr
< Line_Length
- 2
1276 and then Line_Buffer
(Ptr
+ 1 .. Ptr
+ 2) = "$'"
1283 -- The special case of "" inside the string is easy to
1284 -- handle: just ignore them. The second one will be seen
1285 -- as the beginning of a second string
1288 while Ptr
< Line_Length
1289 and then Line_Buffer
(Ptr
) /= '"'
1296 -- $ found, so scan out possible following symbol
1298 Start_Sym
:= Ptr
+ 1;
1300 if Symbol_Scanned
then
1302 -- Look up symbol in table and if found do replacement
1304 for J
in 1 .. Num_Syms
loop
1306 (Symbols
(J
).all, Line_Buffer
(Start_Sym
.. End_Sym
))
1309 OldL
: constant Positive :=
1310 End_Sym
- Start_Sym
+ 2;
1311 NewL
: constant Positive := Values
(J
)'Length;
1312 AdjL
: constant Integer := NewL
- OldL
;
1313 NewP
: constant Positive := Ptr
+ NewL
- 1;
1316 Line_Buffer
(NewP
+ 1 .. Line_Length
+ AdjL
) :=
1317 Line_Buffer
(End_Sym
+ 1 .. Line_Length
);
1318 Line_Buffer
(Ptr
.. NewP
) := Values
(J
).all;
1321 Line_Length
:= Line_Length
+ AdjL
;
1337 -- Here after dealing with preprocessor line, output current line
1341 if Is_Preprocessor_Line
or else PP
(PP_Depth
).Deleting
then
1342 if Blank_Deleted_Lines
then
1345 elsif Opt_Comment_Deleted_Lines
then
1346 if Line_Length
= 0 then
1347 Put_Line
(Outfile
, "--!");
1349 Put
(Outfile
, "--! ");
1350 Put_Line
(Outfile
, Line_Buffer
(1 .. Line_Length
));
1355 Put_Line
(Outfile
, Line_Buffer
(1 .. Line_Length
));
1359 for J
in 1 .. PP_Depth
loop
1360 Error
("no matching #end for #if at line" &
1361 Natural'Image (PP
(J
).If_Line
));
1364 if Num_Errors
= 0 then
1366 Set_Exit_Status
(0);
1369 Set_Exit_Status
(1);
1375 Set_Exit_Status
(1);
1377 when GNAT
.Command_Line
.Invalid_Parameter
=>
1378 Put_Line
(Standard_Error
, "No parameter given for -"
1379 & GNAT
.Command_Line
.Full_Switch
);
1381 Set_Exit_Status
(1);
1383 when GNAT
.Command_Line
.Invalid_Switch
=>
1384 Put_Line
(Standard_Error
, "Invalid Switch: -"
1385 & GNAT
.Command_Line
.Full_Switch
);
1387 Set_Exit_Status
(1);
1390 Set_Exit_Status
(1);
1392 when Expression_Error
=>
1393 Set_Exit_Status
(1);