1 ------------------------------------------------------------------------------
3 -- GNAT COMPILER COMPONENTS --
5 -- S Y S T E M . V A L _ R E A L --
9 -- Copyright (C) 1992-2019, 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 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. --
18 -- As a special exception under Section 7 of GPL version 3, you are granted --
19 -- additional permissions described in the GCC Runtime Library Exception, --
20 -- version 3.1, as published by the Free Software Foundation. --
22 -- You should have received a copy of the GNU General Public License and --
23 -- a copy of the GCC Runtime Library Exception along with this program; --
24 -- see the files COPYING3 and COPYING.RUNTIME respectively. If not, see --
25 -- <http://www.gnu.org/licenses/>. --
27 -- GNAT was originally developed by the GNAT team at New York University. --
28 -- Extensive contributions were provided by Ada Core Technologies Inc. --
30 ------------------------------------------------------------------------------
32 with System.Val_Util; use System.Val_Util;
33 with System.Float_Control;
35 package body System.Val_Real is
37 procedure Scan_Integral_Digits
39 Index : in out Integer;
41 Value : out Long_Long_Integer;
43 Base_Violation : in out Boolean;
44 Base : Long_Long_Integer := 10;
45 Base_Specified : Boolean := False);
46 -- Scan the integral part of a real (i.e: before decimal separator)
48 -- The string parsed is Str (Index .. Max), and after the call Index will
49 -- point to the first non parsed character.
51 -- For each digit parsed either value := value * base + digit, or scale
52 -- is incremented by 1.
54 -- Base_Violation will be set to True a digit found is not part of the Base
56 procedure Scan_Decimal_Digits
58 Index : in out Integer;
60 Value : in out Long_Long_Integer;
61 Scale : in out Integer;
62 Base_Violation : in out Boolean;
63 Base : Long_Long_Integer := 10;
64 Base_Specified : Boolean := False);
65 -- Scan the decimal part of a real (i.e: after decimal separator)
67 -- The string parsed is Str (Index .. Max), and after the call Index will
68 -- point to the first non parsed character.
70 -- For each digit parsed value = value * base + digit and scale is
71 -- decremented by 1. If precision limit is reached remaining digits are
72 -- still parsed but ignored.
74 -- Base_Violation will be set to True a digit found is not part of the Base
76 subtype Char_As_Digit is Long_Long_Integer range -2 .. 15;
77 subtype Valid_Digit is Char_As_Digit range 0 .. Char_As_Digit'Last;
78 Underscore : constant Char_As_Digit := -2;
79 E_Digit : constant Char_As_Digit := 14;
81 function As_Digit (C : Character) return Char_As_Digit;
82 -- Given a character return the digit it represent. If the character is
83 -- not a digit then a negative value is returned, -2 for underscore and
84 -- -1 for any other character.
86 Precision_Limit : constant Long_Long_Integer :=
87 2 ** (Long_Long_Float'Machine_Mantissa - 1) - 1;
88 -- This is an upper bound for the number of bits used to represent the
89 -- mantissa. Beyond that number, any digits parsed are useless.
95 function As_Digit (C : Character) return Char_As_Digit is
99 return Character'Pos (C) - Character'Pos ('0');
101 return Character'Pos (C) - (Character'Pos ('a') - 10);
103 return Character'Pos (C) - (Character'Pos ('A') - 10);
111 -------------------------
112 -- Scan_Decimal_Digits --
113 -------------------------
115 procedure Scan_Decimal_Digits
117 Index : in out Integer;
119 Value : in out Long_Long_Integer;
120 Scale : in out Integer;
121 Base_Violation : in out Boolean;
122 Base : Long_Long_Integer := 10;
123 Base_Specified : Boolean := False)
126 Precision_Limit_Reached : Boolean := False;
127 -- Set to True if addition of a digit will cause Value to be superior
128 -- to Precision_Limit.
130 Digit : Char_As_Digit;
131 -- The current digit.
133 Trailing_Zeros : Natural := 0;
134 -- Number of trailing zeros at a given point.
137 pragma Assert (Base in 2 .. 16);
139 -- If initial Scale is not 0 then it means that Precision_Limit was
140 -- reached during integral part scanning.
142 Precision_Limit_Reached := True;
145 -- The function precondition is that the first character is a valid
147 Digit := As_Digit (Str (Index));
150 -- Check if base is correct. If the base is not specified the digit
151 -- E or e cannot be considered as a base violation as it can be used
152 -- for exponentiation.
153 if Digit >= Base then
154 if Base_Specified then
155 Base_Violation := True;
156 elsif Digit = E_Digit then
159 Base_Violation := True;
163 -- If precision limit has been reached just ignore any remaining
164 -- digits for the computation of Value and Scale. The scanning
165 -- should continue only to assess the validity of the string
166 if not Precision_Limit_Reached then
168 -- Trailing '0' digits are ignored unless a non-zero digit is
170 Trailing_Zeros := Trailing_Zeros + 1;
173 -- Handle accumulated zeros.
174 for J in 1 .. Trailing_Zeros loop
175 if Value > Precision_Limit / Base then
176 Precision_Limit_Reached := True;
179 Value := Value * Base;
184 -- Reset trailing zero counter
187 -- Handle current non zero digit
188 if Value > (Precision_Limit - Digit) / Base then
189 Precision_Limit_Reached := True;
191 Value := Value * Base + Digit;
197 -- Check next character
204 Digit := As_Digit (Str (Index));
207 if Digit = Underscore and Index + 1 <= Max then
208 -- Underscore is only allowed if followed by a digit
209 Digit := As_Digit (Str (Index + 1));
210 if Digit in Valid_Digit then
216 -- Neither a valid underscore nor a digit.
221 end Scan_Decimal_Digits;
223 --------------------------
224 -- Scan_Integral_Digits --
225 --------------------------
227 procedure Scan_Integral_Digits
229 Index : in out Integer;
231 Value : out Long_Long_Integer;
233 Base_Violation : in out Boolean;
234 Base : Long_Long_Integer := 10;
235 Base_Specified : Boolean := False)
237 Precision_Limit_Reached : Boolean := False;
238 -- Set to True if addition of a digit will cause Value to be superior
239 -- to Precision_Limit.
241 Digit : Char_As_Digit;
245 -- Initialize Scale and Value
249 -- The function precondition is that the first character is a valid
251 Digit := As_Digit (Str (Index));
254 -- Check if base is correct. If the base is not specified the digit
255 -- E or e cannot be considered as a base violation as it can be used
256 -- for exponentiation.
257 if Digit >= Base then
258 if Base_Specified then
259 Base_Violation := True;
260 elsif Digit = E_Digit then
263 Base_Violation := True;
267 if Precision_Limit_Reached then
268 -- Precision limit has been reached so just update the exponent
271 pragma Assert (Base /= 0);
273 if Value > (Precision_Limit - Digit) / Base then
274 -- Updating Value will overflow so ignore this digit and any
275 -- following ones. Only update the scale
276 Precision_Limit_Reached := True;
279 Value := Value * Base + Digit;
283 -- Look for the next character
289 Digit := As_Digit (Str (Index));
291 if Digit not in Valid_Digit then
292 -- Next character is not a digit. In that case stop scanning
293 -- unless the next chracter is an underscore followed by a digit.
294 if Digit = Underscore and Index + 1 <= Max then
295 Digit := As_Digit (Str (Index + 1));
296 if Digit in Valid_Digit then
307 end Scan_Integral_Digits;
315 Ptr : not null access Integer;
317 return Long_Long_Float
321 -- Position of starting non-blank character
324 -- Set to True if minus sign is present, otherwise to False
327 -- Local copy of string pointer
329 Int_Value : Long_Long_Integer := -1;
330 -- Mantissa as an Integer
332 Int_Scale : Integer := 0;
335 Base_Violation : Boolean := False;
336 -- If True some digits where not in the base. The float is still scan
337 -- till the end even if an error will be raised.
339 Uval : Long_Long_Float := 0.0;
340 -- Contain the final value at the end of the function
342 After_Point : Boolean := False;
343 -- True if a decimal should be parsed
345 Base : Long_Long_Integer := 10;
346 -- Current base (default: 10)
348 Base_Char : Character := ASCII.NUL;
349 -- Character used to set the base. If Nul this means that default
353 -- We do not tolerate strings with Str'Last = Positive'Last
355 if Str'Last = Positive'Last then
356 raise Program_Error with
357 "string upper bound is Positive'Last, not supported";
360 -- We call the floating-point processor reset routine so that we can
361 -- be sure the floating-point processor is properly set for conversion
362 -- calls. This is notably need on Windows, where calls to the operating
363 -- system randomly reset the processor into 64-bit mode.
365 System.Float_Control.Reset;
367 -- Scan the optional sign
368 Scan_Sign (Str, Ptr, Max, Minus, Start);
372 -- First character can be either a decimal digit or a dot.
373 if Str (Index) in '0' .. '9' then
375 (CodePeer, Intentional,
376 "test always true", "defensive code below");
378 -- If this is a digit it can indicates either the float decimal
379 -- part or the base to use
386 Base_Violation => Base_Violation,
388 elsif Str (Index) = '.' and then
389 -- A dot is only allowed if followed by a digit.
391 Str (Index + 1) in '0' .. '9'
393 -- Initial point, allowed only if followed by digit (RM 3.5(47))
401 -- Check if the first number encountered is a base
402 if Index < Max and then
403 (Str (Index) = '#' or else Str (Index) = ':')
405 Base_Char := Str (Index);
408 -- Reset Int_Value to indicate that parsing of integral value should
411 if Base < 2 or else Base > 16 then
412 Base_Violation := True;
418 if Str (Index) = '.' and then
420 As_Digit (Str (Index + 1)) in Valid_Digit
428 -- Does scanning of integral part needed
429 if Int_Value < 0 then
430 if Index > Max or else As_Digit (Str (Index)) not in Valid_Digit then
440 Base_Violation => Base_Violation,
442 Base_Specified => Base_Char /= ASCII.NUL);
445 -- Do we have a dot ?
446 if not After_Point and then
447 Index <= Max and then
450 -- At this stage if After_Point was not set, this means that an
451 -- integral part has been found. Thus the dot is valid even if not
452 -- followed by a digit.
453 if Index < Max and then As_Digit (Str (Index + 1)) in Valid_Digit then
461 -- Parse decimal part
468 Base_Violation => Base_Violation,
470 Base_Specified => Base_Char /= ASCII.NUL);
473 -- If an explicit base was specified ensure that the delimiter is found
474 if Base_Char /= ASCII.NUL then
475 if Index > Max or else Str (Index) /= Base_Char then
482 -- Compute the final value
483 Uval := Long_Long_Float (Int_Value);
485 -- Update pointer and scan exponent.
488 Int_Scale := Int_Scale + Scan_Exponent (Str,
493 Uval := Uval * Long_Long_Float (Base) ** Int_Scale;
495 -- Here is where we check for a bad based number
496 if Base_Violation then
499 -- If OK, then deal with initial minus sign, note that this processing
500 -- is done even if Uval is zero, so that -0.0 is correctly interpreted.
515 function Value_Real (Str : String) return Long_Long_Float is
517 -- We have to special case Str'Last = Positive'Last because the normal
518 -- circuit ends up setting P to Str'Last + 1 which is out of bounds. We
519 -- deal with this by converting to a subtype which fixes the bounds.
521 if Str'Last = Positive'Last then
523 subtype NT is String (1 .. Str'Length);
525 return Value_Real (NT (Str));
528 -- Normal case where Str'Last < Positive'Last
533 P : aliased Integer := Str'First;
535 V := Scan_Real (Str, P'Access, Str'Last);
536 Scan_Trailing_Blanks (Str, P);