1 ------------------------------------------------------------------------------
3 -- GNAT COMPILER COMPONENTS --
9 -- Copyright (C) 1992-2001 Free Software Foundation, Inc. --
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. --
22 -- GNAT was originally developed by the GNAT team at New York University. --
23 -- Extensive contributions were provided by Ada Core Technologies Inc. --
25 ------------------------------------------------------------------------------
27 with Uintp; use Uintp;
28 with Urealp; use Urealp;
34 -- Current source program character
36 Base_Char : Character;
37 -- Either # or : (character at start of based number)
43 -- Value of base in Uint format
46 -- Value of integer scanned by Scan_Integer in Uint format
49 -- Value of integer in numeric value being scanned
52 -- Scale value for real literal
55 -- Scale in Uint format
57 Exponent_Is_Negative : Boolean;
58 -- Set true for negative exponent
60 Extended_Digit_Value : Int;
61 -- Extended digit value
63 Point_Scanned : Boolean;
64 -- Flag for decimal point scanned in numeric literal
66 -----------------------
67 -- Local Subprograms --
68 -----------------------
70 procedure Error_Digit_Expected;
71 -- Signal error of bad digit, Scan_Ptr points to the location at which
72 -- the digit was expected on input, and is unchanged on return.
74 procedure Scan_Integer;
75 -- Procedure to scan integer literal. On entry, Scan_Ptr points to a
76 -- digit, on exit Scan_Ptr points past the last character of the integer.
77 -- For each digit encountered, UI_Int_Value is multiplied by 10, and the
78 -- value of the digit added to the result. In addition, the value in
79 -- Scale is decremented by one for each actual digit scanned.
81 --------------------------
82 -- Error_Digit_Expected --
83 --------------------------
85 procedure Error_Digit_Expected is
87 Error_Msg_S ("digit expected");
88 end Error_Digit_Expected;
94 procedure Scan_Integer is
96 -- Next character scanned
99 C := Source (Scan_Ptr);
101 -- Loop through digits (allowing underlines)
104 Accumulate_Checksum (C);
106 UI_Int_Value * 10 + (Character'Pos (C) - Character'Pos ('0'));
107 Scan_Ptr := Scan_Ptr + 1;
109 C := Source (Scan_Ptr);
112 Accumulate_Checksum ('_');
115 Scan_Ptr := Scan_Ptr + 1;
116 C := Source (Scan_Ptr);
118 Error_No_Double_Underline;
121 if C not in '0' .. '9' then
122 Error_Digit_Expected;
127 exit when C not in '0' .. '9';
133 ----------------------------------
134 -- Start of Processing for Nlit --
135 ----------------------------------
140 UI_Int_Value := Uint_0;
144 Point_Scanned := False;
145 UI_Num_Value := UI_Int_Value;
147 -- Various possibilities now for continuing the literal are
148 -- period, E/e (for exponent), or :/# (for based literal).
151 C := Source (Scan_Ptr);
155 -- Scan out point, but do not scan past .. which is a range sequence,
156 -- and must not be eaten up scanning a numeric literal.
158 while C = '.' and then Source (Scan_Ptr + 1) /= '.' loop
159 Accumulate_Checksum ('.');
161 if Point_Scanned then
162 Error_Msg_S ("duplicate point ignored");
165 Point_Scanned := True;
166 Scan_Ptr := Scan_Ptr + 1;
167 C := Source (Scan_Ptr);
169 if C not in '0' .. '9' then
170 Error_Msg ("real literal cannot end with point", Scan_Ptr - 1);
173 UI_Num_Value := UI_Int_Value;
177 -- Based literal case. The base is the value we already scanned.
178 -- In the case of colon, we insist that the following character
179 -- is indeed an extended digit or a period. This catches a number
180 -- of common errors, as well as catching the well known tricky
181 -- bug otherwise arising from "x : integer range 1 .. 10:= 6;"
184 or else (C = ':' and then
185 (Source (Scan_Ptr + 1) = '.'
187 Source (Scan_Ptr + 1) in '0' .. '9'
189 Source (Scan_Ptr + 1) in 'A' .. 'Z'
191 Source (Scan_Ptr + 1) in 'a' .. 'z'))
193 Accumulate_Checksum (C);
195 UI_Base := UI_Int_Value;
197 if UI_Base < 2 or else UI_Base > 16 then
198 Error_Msg_SC ("base not 2-16");
202 Base := UI_To_Int (UI_Base);
203 Scan_Ptr := Scan_Ptr + 1;
205 -- Scan out extended integer [. integer]
207 C := Source (Scan_Ptr);
208 UI_Int_Value := Uint_0;
212 if C in '0' .. '9' then
213 Accumulate_Checksum (C);
214 Extended_Digit_Value :=
215 Int'(Character'Pos (C)) - Int'(Character'Pos ('0'));
217 elsif C in 'A' .. 'F' then
218 Accumulate_Checksum (Character'Val (Character'Pos (C) + 32));
219 Extended_Digit_Value :=
220 Int'(Character'Pos (C)) - Int'(Character'Pos ('A')) + 10;
222 elsif C in 'a' .. 'f' then
223 Accumulate_Checksum (C);
224 Extended_Digit_Value :=
225 Int'(Character'Pos (C)) - Int'(Character'Pos ('a')) + 10;
228 Error_Msg_S ("extended digit expected");
232 if Extended_Digit_Value >= Base then
233 Error_Msg_S ("digit >= base");
236 UI_Int_Value := UI_Int_Value * UI_Base + Extended_Digit_Value;
238 Scan_Ptr := Scan_Ptr + 1;
239 C := Source (Scan_Ptr);
243 Accumulate_Checksum ('_');
244 Scan_Ptr := Scan_Ptr + 1;
245 C := Source (Scan_Ptr);
247 Error_No_Double_Underline;
251 Accumulate_Checksum ('.');
253 if Point_Scanned then
254 Error_Msg_S ("duplicate point ignored");
257 Scan_Ptr := Scan_Ptr + 1;
258 C := Source (Scan_Ptr);
259 Point_Scanned := True;
262 elsif C = Base_Char then
263 Accumulate_Checksum (C);
264 Scan_Ptr := Scan_Ptr + 1;
267 elsif C = '#' or else C = ':' then
268 Error_Msg_S ("based number delimiters must match");
269 Scan_Ptr := Scan_Ptr + 1;
272 elsif not Identifier_Char (C) then
273 if Base_Char = '#' then
274 Error_Msg_S ("missing '#");
276 Error_Msg_S ("missing ':");
284 UI_Num_Value := UI_Int_Value;
289 if not Point_Scanned then
293 UI_Scale := UI_From_Int (Scale);
296 if Source (Scan_Ptr) = 'e' or else Source (Scan_Ptr) = 'E' then
297 Accumulate_Checksum ('e');
298 Scan_Ptr := Scan_Ptr + 1;
299 Exponent_Is_Negative := False;
301 if Source (Scan_Ptr) = '+' then
302 Accumulate_Checksum ('+');
303 Scan_Ptr := Scan_Ptr + 1;
305 elsif Source (Scan_Ptr) = '-' then
306 Accumulate_Checksum ('-');
308 if not Point_Scanned then
309 Error_Msg_S ("negative exponent not allowed for integer literal");
311 Exponent_Is_Negative := True;
314 Scan_Ptr := Scan_Ptr + 1;
317 UI_Int_Value := Uint_0;
319 if Source (Scan_Ptr) in '0' .. '9' then
322 Error_Digit_Expected;
325 if Exponent_Is_Negative then
326 UI_Scale := UI_Scale - UI_Int_Value;
328 UI_Scale := UI_Scale + UI_Int_Value;
332 -- Case of real literal to be returned
334 if Point_Scanned then
335 Token := Tok_Real_Literal;
336 Token_Node := New_Node (N_Real_Literal, Token_Ptr);
337 Set_Realval (Token_Node,
343 -- Case of integer literal to be returned
346 Token := Tok_Integer_Literal;
347 Token_Node := New_Node (N_Integer_Literal, Token_Ptr);
350 Set_Intval (Token_Node, UI_Num_Value);
352 -- Avoid doing possibly expensive calculations in cases like
353 -- parsing 163E800_000# when semantics will not be done anyway.
354 -- This is especially useful when parsing garbled input.
356 elsif Operating_Mode /= Check_Syntax
357 and then (Serious_Errors_Detected = 0 or else Try_Semantics)
359 Set_Intval (Token_Node, UI_Num_Value * UI_Base ** UI_Scale);
362 Set_Intval (Token_Node, No_Uint);