FSF GCC merge 02/23/03
[official-gcc.git] / gcc / ada / scn-nlit.adb
blob4e766033b34703e6b21fc5b014854531cb9d69e8
1 ------------------------------------------------------------------------------
2 -- --
3 -- GNAT COMPILER COMPONENTS --
4 -- --
5 -- S C N . N L I T --
6 -- --
7 -- B o d y --
8 -- --
9 -- --
10 -- Copyright (C) 1992-2001 Free Software Foundation, Inc. --
11 -- --
12 -- GNAT is free software; you can redistribute it and/or modify it under --
13 -- terms of the GNU General Public License as published by the Free Soft- --
14 -- ware Foundation; either version 2, or (at your option) any later ver- --
15 -- sion. GNAT is distributed in the hope that it will be useful, but WITH- --
16 -- OUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY --
17 -- or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License --
18 -- for more details. You should have received a copy of the GNU General --
19 -- Public License distributed with GNAT; see file COPYING. If not, write --
20 -- to the Free Software Foundation, 59 Temple Place - Suite 330, Boston, --
21 -- MA 02111-1307, USA. --
22 -- --
23 -- GNAT was originally developed by the GNAT team at New York University. --
24 -- Extensive contributions were provided by Ada Core Technologies Inc. --
25 -- --
26 ------------------------------------------------------------------------------
28 with Uintp; use Uintp;
29 with Urealp; use Urealp;
31 separate (Scn)
32 procedure Nlit is
34 C : Character;
35 -- Current source program character
37 Base_Char : Character;
38 -- Either # or : (character at start of based number)
40 Base : Int;
41 -- Value of base
43 UI_Base : Uint;
44 -- Value of base in Uint format
46 UI_Int_Value : Uint;
47 -- Value of integer scanned by Scan_Integer in Uint format
49 UI_Num_Value : Uint;
50 -- Value of integer in numeric value being scanned
52 Scale : Int;
53 -- Scale value for real literal
55 UI_Scale : Uint;
56 -- Scale in Uint format
58 Exponent_Is_Negative : Boolean;
59 -- Set true for negative exponent
61 Extended_Digit_Value : Int;
62 -- Extended digit value
64 Point_Scanned : Boolean;
65 -- Flag for decimal point scanned in numeric literal
67 -----------------------
68 -- Local Subprograms --
69 -----------------------
71 procedure Error_Digit_Expected;
72 -- Signal error of bad digit, Scan_Ptr points to the location at which
73 -- the digit was expected on input, and is unchanged on return.
75 procedure Scan_Integer;
76 -- Procedure to scan integer literal. On entry, Scan_Ptr points to a
77 -- digit, on exit Scan_Ptr points past the last character of the integer.
78 -- For each digit encountered, UI_Int_Value is multiplied by 10, and the
79 -- value of the digit added to the result. In addition, the value in
80 -- Scale is decremented by one for each actual digit scanned.
82 --------------------------
83 -- Error_Digit_Expected --
84 --------------------------
86 procedure Error_Digit_Expected is
87 begin
88 Error_Msg_S ("digit expected");
89 end Error_Digit_Expected;
91 -------------------
92 -- Scan_Integer --
93 -------------------
95 procedure Scan_Integer is
96 C : Character;
97 -- Next character scanned
99 begin
100 C := Source (Scan_Ptr);
102 -- Loop through digits (allowing underlines)
104 loop
105 Accumulate_Checksum (C);
106 UI_Int_Value :=
107 UI_Int_Value * 10 + (Character'Pos (C) - Character'Pos ('0'));
108 Scan_Ptr := Scan_Ptr + 1;
109 Scale := Scale - 1;
110 C := Source (Scan_Ptr);
112 if C = '_' then
113 Accumulate_Checksum ('_');
115 loop
116 Scan_Ptr := Scan_Ptr + 1;
117 C := Source (Scan_Ptr);
118 exit when C /= '_';
119 Error_No_Double_Underline;
120 end loop;
122 if C not in '0' .. '9' then
123 Error_Digit_Expected;
124 exit;
125 end if;
127 else
128 exit when C not in '0' .. '9';
129 end if;
130 end loop;
132 end Scan_Integer;
134 ----------------------------------
135 -- Start of Processing for Nlit --
136 ----------------------------------
138 begin
139 Base := 10;
140 UI_Base := Uint_10;
141 UI_Int_Value := Uint_0;
142 Scale := 0;
143 Scan_Integer;
144 Scale := 0;
145 Point_Scanned := False;
146 UI_Num_Value := UI_Int_Value;
148 -- Various possibilities now for continuing the literal are
149 -- period, E/e (for exponent), or :/# (for based literal).
151 Scale := 0;
152 C := Source (Scan_Ptr);
154 if C = '.' then
156 -- Scan out point, but do not scan past .. which is a range sequence,
157 -- and must not be eaten up scanning a numeric literal.
159 while C = '.' and then Source (Scan_Ptr + 1) /= '.' loop
160 Accumulate_Checksum ('.');
162 if Point_Scanned then
163 Error_Msg_S ("duplicate point ignored");
164 end if;
166 Point_Scanned := True;
167 Scan_Ptr := Scan_Ptr + 1;
168 C := Source (Scan_Ptr);
170 if C not in '0' .. '9' then
171 Error_Msg ("real literal cannot end with point", Scan_Ptr - 1);
172 else
173 Scan_Integer;
174 UI_Num_Value := UI_Int_Value;
175 end if;
176 end loop;
178 -- Based literal case. The base is the value we already scanned.
179 -- In the case of colon, we insist that the following character
180 -- is indeed an extended digit or a period. This catches a number
181 -- of common errors, as well as catching the well known tricky
182 -- bug otherwise arising from "x : integer range 1 .. 10:= 6;"
184 elsif C = '#'
185 or else (C = ':' and then
186 (Source (Scan_Ptr + 1) = '.'
187 or else
188 Source (Scan_Ptr + 1) in '0' .. '9'
189 or else
190 Source (Scan_Ptr + 1) in 'A' .. 'Z'
191 or else
192 Source (Scan_Ptr + 1) in 'a' .. 'z'))
193 then
194 Accumulate_Checksum (C);
195 Base_Char := C;
196 UI_Base := UI_Int_Value;
198 if UI_Base < 2 or else UI_Base > 16 then
199 Error_Msg_SC ("base not 2-16");
200 UI_Base := Uint_16;
201 end if;
203 Base := UI_To_Int (UI_Base);
204 Scan_Ptr := Scan_Ptr + 1;
206 -- Scan out extended integer [. integer]
208 C := Source (Scan_Ptr);
209 UI_Int_Value := Uint_0;
210 Scale := 0;
212 loop
213 if C in '0' .. '9' then
214 Accumulate_Checksum (C);
215 Extended_Digit_Value :=
216 Int'(Character'Pos (C)) - Int'(Character'Pos ('0'));
218 elsif C in 'A' .. 'F' then
219 Accumulate_Checksum (Character'Val (Character'Pos (C) + 32));
220 Extended_Digit_Value :=
221 Int'(Character'Pos (C)) - Int'(Character'Pos ('A')) + 10;
223 elsif C in 'a' .. 'f' then
224 Accumulate_Checksum (C);
225 Extended_Digit_Value :=
226 Int'(Character'Pos (C)) - Int'(Character'Pos ('a')) + 10;
228 else
229 Error_Msg_S ("extended digit expected");
230 exit;
231 end if;
233 if Extended_Digit_Value >= Base then
234 Error_Msg_S ("digit >= base");
235 end if;
237 UI_Int_Value := UI_Int_Value * UI_Base + Extended_Digit_Value;
238 Scale := Scale - 1;
239 Scan_Ptr := Scan_Ptr + 1;
240 C := Source (Scan_Ptr);
242 if C = '_' then
243 loop
244 Accumulate_Checksum ('_');
245 Scan_Ptr := Scan_Ptr + 1;
246 C := Source (Scan_Ptr);
247 exit when C /= '_';
248 Error_No_Double_Underline;
249 end loop;
251 elsif C = '.' then
252 Accumulate_Checksum ('.');
254 if Point_Scanned then
255 Error_Msg_S ("duplicate point ignored");
256 end if;
258 Scan_Ptr := Scan_Ptr + 1;
259 C := Source (Scan_Ptr);
260 Point_Scanned := True;
261 Scale := 0;
263 elsif C = Base_Char then
264 Accumulate_Checksum (C);
265 Scan_Ptr := Scan_Ptr + 1;
266 exit;
268 elsif C = '#' or else C = ':' then
269 Error_Msg_S ("based number delimiters must match");
270 Scan_Ptr := Scan_Ptr + 1;
271 exit;
273 elsif not Identifier_Char (C) then
274 if Base_Char = '#' then
275 Error_Msg_S ("missing '#");
276 else
277 Error_Msg_S ("missing ':");
278 end if;
280 exit;
281 end if;
283 end loop;
285 UI_Num_Value := UI_Int_Value;
286 end if;
288 -- Scan out exponent
290 if not Point_Scanned then
291 Scale := 0;
292 UI_Scale := Uint_0;
293 else
294 UI_Scale := UI_From_Int (Scale);
295 end if;
297 if Source (Scan_Ptr) = 'e' or else Source (Scan_Ptr) = 'E' then
298 Accumulate_Checksum ('e');
299 Scan_Ptr := Scan_Ptr + 1;
300 Exponent_Is_Negative := False;
302 if Source (Scan_Ptr) = '+' then
303 Accumulate_Checksum ('+');
304 Scan_Ptr := Scan_Ptr + 1;
306 elsif Source (Scan_Ptr) = '-' then
307 Accumulate_Checksum ('-');
309 if not Point_Scanned then
310 Error_Msg_S ("negative exponent not allowed for integer literal");
311 else
312 Exponent_Is_Negative := True;
313 end if;
315 Scan_Ptr := Scan_Ptr + 1;
316 end if;
318 UI_Int_Value := Uint_0;
320 if Source (Scan_Ptr) in '0' .. '9' then
321 Scan_Integer;
322 else
323 Error_Digit_Expected;
324 end if;
326 if Exponent_Is_Negative then
327 UI_Scale := UI_Scale - UI_Int_Value;
328 else
329 UI_Scale := UI_Scale + UI_Int_Value;
330 end if;
331 end if;
333 -- Case of real literal to be returned
335 if Point_Scanned then
336 Token := Tok_Real_Literal;
337 Token_Node := New_Node (N_Real_Literal, Token_Ptr);
338 Set_Realval (Token_Node,
339 UR_From_Components (
340 Num => UI_Num_Value,
341 Den => -UI_Scale,
342 Rbase => Base));
344 -- Case of integer literal to be returned
346 else
347 Token := Tok_Integer_Literal;
348 Token_Node := New_Node (N_Integer_Literal, Token_Ptr);
350 if UI_Scale = 0 then
351 Set_Intval (Token_Node, UI_Num_Value);
353 -- Avoid doing possibly expensive calculations in cases like
354 -- parsing 163E800_000# when semantics will not be done anyway.
355 -- This is especially useful when parsing garbled input.
357 elsif Operating_Mode /= Check_Syntax
358 and then (Serious_Errors_Detected = 0 or else Try_Semantics)
359 then
360 Set_Intval (Token_Node, UI_Num_Value * UI_Base ** UI_Scale);
362 else
363 Set_Intval (Token_Node, No_Uint);
364 end if;
366 end if;
368 return;
370 end Nlit;