aboutsummaryrefslogtreecommitdiff
path: root/gcc/ada/libgnat/s-valuer.adb
diff options
context:
space:
mode:
Diffstat (limited to 'gcc/ada/libgnat/s-valuer.adb')
-rw-r--r--gcc/ada/libgnat/s-valuer.adb249
1 files changed, 109 insertions, 140 deletions
diff --git a/gcc/ada/libgnat/s-valuer.adb b/gcc/ada/libgnat/s-valuer.adb
index 6f557e9..961dda4 100644
--- a/gcc/ada/libgnat/s-valuer.adb
+++ b/gcc/ada/libgnat/s-valuer.adb
@@ -42,14 +42,6 @@ package body System.Value_R is
function As_Digit (C : Character) return Char_As_Digit;
-- Given a character return the digit it represents
- procedure Round_Extra
- (Digit : Char_As_Digit;
- Base : Unsigned;
- Value : in out Uns;
- Scale : in out Integer;
- Extra : in out Char_As_Digit);
- -- Round the triplet (Value, Scale, Extra) according to Digit in Base
-
procedure Scan_Decimal_Digits
(Str : String;
Index : in out Integer;
@@ -59,7 +51,7 @@ package body System.Value_R is
Value : in out Value_Array;
Scale : in out Scale_Array;
N : in out Positive;
- Extra : in out Char_As_Digit;
+ Extra2 : in out Unsigned;
Base_Violation : in out Boolean);
-- Scan the decimal part of a real (i.e. after decimal separator)
--
@@ -68,7 +60,8 @@ package body System.Value_R is
--
-- For each digit parsed, Value = Value * Base + Digit and Scale is
-- decremented by 1. If precision limit is reached, remaining digits are
- -- still parsed but ignored, except for the first which is stored in Extra.
+ -- still parsed but ignored, except for the first two of them which are
+ -- stored in Extra2.
--
-- Base_Violation is set to True if a digit found is not part of the Base
--
@@ -83,7 +76,8 @@ package body System.Value_R is
Value : out Value_Array;
Scale : out Scale_Array;
N : out Positive;
- Extra : out Char_As_Digit;
+ Extra2 : out Unsigned;
+ Extra2_Filled : out Boolean;
Base_Violation : in out Boolean);
-- Scan the integral part of a real (i.e. before decimal separator)
--
@@ -93,7 +87,7 @@ package body System.Value_R is
-- For each digit parsed, either Value := Value * Base + Digit or Scale
-- is incremented by 1 if precision limit is reached, in which case the
-- remaining digits are still parsed but ignored, except for the first
- -- which is stored in Extra.
+ -- two of them which are stored in Extra2 if Extra2_Filled is True.
--
-- Base_Violation is set to True if a digit found is not part of the Base
--
@@ -119,47 +113,6 @@ package body System.Value_R is
end case;
end As_Digit;
- -----------------
- -- Round_Extra --
- -----------------
-
- procedure Round_Extra
- (Digit : Char_As_Digit;
- Base : Unsigned;
- Value : in out Uns;
- Scale : in out Integer;
- Extra : in out Char_As_Digit)
- is
- pragma Assert (Base in 2 .. 16);
-
- B : constant Uns := Uns (Base);
-
- begin
- if Digit >= Base / 2 then
-
- -- If Extra is maximum, round Value
-
- if Extra = Base - 1 then
-
- -- If Value is maximum, scale it up
-
- if Value = Precision_Limit then
- Extra := Char_As_Digit (Value mod B);
- Value := Value / B;
- Scale := Scale + 1;
- Round_Extra (Digit, Base, Value, Scale, Extra);
-
- else
- Extra := 0;
- Value := Value + 1;
- end if;
-
- else
- Extra := Extra + 1;
- end if;
- end if;
- end Round_Extra;
-
-------------------------
-- Scan_Decimal_Digits --
-------------------------
@@ -173,7 +126,7 @@ package body System.Value_R is
Value : in out Value_Array;
Scale : in out Scale_Array;
N : in out Positive;
- Extra : in out Char_As_Digit;
+ Extra2 : in out Unsigned;
Base_Violation : in out Boolean)
is
@@ -192,8 +145,7 @@ package body System.Value_R is
-- to Precision_Limit.
Precision_Limit_Just_Reached : Boolean;
- -- Set to True if Precision_Limit_Reached was just set to True, but only
- -- used when Round is True.
+ -- Set to True if Precision_Limit_Reached was just set to True
Digit : Char_As_Digit;
-- The current digit
@@ -205,17 +157,16 @@ package body System.Value_R is
-- Number of trailing zeros at a given point
begin
- -- If initial Scale is not 0 then it means that Precision_Limit was
+ -- If initial Scale is not 0, then this means that Precision_Limit was
-- reached during scanning of the integral part.
if Scale (Data_Index'Last) > 0 then
Precision_Limit_Reached := True;
+ Precision_Limit_Just_Reached := True;
+
else
- Extra := 0;
+ Extra2 := 0;
Precision_Limit_Reached := False;
- end if;
-
- if Round then
Precision_Limit_Just_Reached := False;
end if;
@@ -229,28 +180,27 @@ package body System.Value_R is
Digit := As_Digit (Str (Index));
loop
- -- Check if base is correct. If the base is not specified, the digit
- -- E or e cannot be considered as a base violation as it can be used
- -- for exponentiation.
+ -- If the base is not explicitly specified, 'e' or 'E' marks the
+ -- beginning of the exponent part.
+
+ if not Base_Specified and then Digit = E_Digit then
+ return;
+ end if;
+
+ -- Check that Digit is a valid digit with respect to Base
if Digit >= Base then
- if Base_Specified then
- Base_Violation := True;
- elsif Digit = E_Digit then
- return;
- else
- Base_Violation := True;
- end if;
+ Base_Violation := True;
end if;
-- If precision limit has been reached, just ignore any remaining
-- digits for the computation of Value and Scale, but store the
- -- first in Extra and use the second to round Extra. The scanning
- -- should continue only to assess the validity of the string.
+ -- first two digits in Extra2. The scanning should continue only
+ -- to assess the validity of the string.
if Precision_Limit_Reached then
- if Round and then Precision_Limit_Just_Reached then
- Round_Extra (Digit, Base, Value (N), Scale (N), Extra);
+ if Precision_Limit_Just_Reached then
+ Extra2 := Extra2 + Digit;
Precision_Limit_Just_Reached := False;
end if;
@@ -273,11 +223,8 @@ package body System.Value_R is
Scale (N) := Scale (N - 1) - 1;
else
- Extra := 0;
+ Extra2 := (if J = Trailing_Zeros then Digit else 0);
Precision_Limit_Reached := True;
- if Round and then J = Trailing_Zeros then
- Round_Extra (Digit, Base, Value (N), Scale (N), Extra);
- end if;
exit;
end if;
@@ -316,11 +263,9 @@ package body System.Value_R is
Scale (N) := Scale (N - 1) - 1;
else
- Extra := Digit;
+ Extra2 := Digit * Base;
Precision_Limit_Reached := True;
- if Round then
- Precision_Limit_Just_Reached := True;
- end if;
+ Precision_Limit_Just_Reached := True;
end if;
end if;
end if;
@@ -339,10 +284,12 @@ package body System.Value_R is
-- Underscore is only allowed if followed by a digit
- if Digit = Underscore and Index + 1 <= Max then
+ if Digit = Underscore and then Index + 1 <= Max then
Digit := As_Digit (Str (Index + 1));
- if Digit in Valid_Digit then
+ if Digit in Valid_Digit and then
+ (Digit /= E_Digit or else Base > E_Digit)
+ then
Index := Index + 1;
else
return;
@@ -370,7 +317,8 @@ package body System.Value_R is
Value : out Value_Array;
Scale : out Scale_Array;
N : out Positive;
- Extra : out Char_As_Digit;
+ Extra2 : out Unsigned;
+ Extra2_Filled : out Boolean;
Base_Violation : in out Boolean)
is
pragma Assert (Base in 2 .. 16);
@@ -386,8 +334,7 @@ package body System.Value_R is
-- to Precision_Limit.
Precision_Limit_Just_Reached : Boolean;
- -- Set to True if Precision_Limit_Reached was just set to True, but only
- -- used when Round is True.
+ -- Set to True if Precision_Limit_Reached was just set to True
Digit : Char_As_Digit;
-- The current digit
@@ -396,18 +343,16 @@ package body System.Value_R is
-- Temporary
begin
- -- Initialize N, Value, Scale and Extra
+ -- Initialize N, Value, Scale, Extra2 and Extra2_Filled
N := 1;
Value := (others => 0);
Scale := (others => 0);
- Extra := 0;
+ Extra2 := 0;
+ Extra2_Filled := False;
Precision_Limit_Reached := False;
-
- if Round then
- Precision_Limit_Just_Reached := False;
- end if;
+ Precision_Limit_Just_Reached := False;
pragma Assert (Max <= Str'Last);
@@ -417,30 +362,30 @@ package body System.Value_R is
Digit := As_Digit (Str (Index));
loop
- -- Check if base is correct. If the base is not specified, the digit
- -- E or e cannot be considered as a base violation as it can be used
- -- for exponentiation.
+ -- If the base is not explicitly specified, 'e' or 'E' marks the
+ -- beginning of the exponent part.
+
+ if not Base_Specified and then Digit = E_Digit then
+ return;
+ end if;
+
+ -- Check that Digit is a valid digit with respect to Base
if Digit >= Base then
- if Base_Specified then
- Base_Violation := True;
- elsif Digit = E_Digit then
- return;
- else
- Base_Violation := True;
- end if;
+ Base_Violation := True;
end if;
-- If precision limit has been reached, just ignore any remaining
-- digits for the computation of Value and Scale, but store the
- -- first in Extra and use the second to round Extra. The scanning
- -- should continue only to assess the validity of the string.
+ -- first two digits in Extra2. The scanning should continue only
+ -- to assess the validity of the string.
if Precision_Limit_Reached then
Scale (N) := Scale (N) + 1;
- if Round and then Precision_Limit_Just_Reached then
- Round_Extra (Digit, Base, Value (N), Scale (N), Extra);
+ if Precision_Limit_Just_Reached then
+ Extra2 := Extra2 + Digit;
+ Extra2_Filled := True;
Precision_Limit_Just_Reached := False;
end if;
@@ -465,11 +410,9 @@ package body System.Value_R is
Value (N) := Uns (Digit);
else
- Extra := Digit;
+ Extra2 := Digit * Base;
Precision_Limit_Reached := True;
- if Round then
- Precision_Limit_Just_Reached := True;
- end if;
+ Precision_Limit_Just_Reached := True;
Scale (N) := Scale (N) + 1;
end if;
end if;
@@ -494,9 +437,11 @@ package body System.Value_R is
-- Next character is not a digit. In that case stop scanning
-- unless the next chracter is an underscore followed by a digit.
- if Digit = Underscore and Index + 1 <= Max then
+ if Digit = Underscore and then Index + 1 <= Max then
Digit := As_Digit (Str (Index + 1));
- if Digit in Valid_Digit then
+ if Digit in Valid_Digit and then
+ (Digit /= E_Digit or else Base > E_Digit)
+ then
Index := Index + 1;
else
return;
@@ -513,13 +458,13 @@ package body System.Value_R is
-------------------
function Scan_Raw_Real
- (Str : String;
- Ptr : not null access Integer;
- Max : Integer;
- Base : out Unsigned;
- Scale : out Scale_Array;
- Extra : out Unsigned;
- Minus : out Boolean) return Value_Array
+ (Str : String;
+ Ptr : not null access Integer;
+ Max : Integer;
+ Base : out Unsigned;
+ Scale : out Scale_Array;
+ Extra2 : out Unsigned;
+ Minus : out Boolean) return Value_Array
is
pragma Assert (Max <= Str'Last);
@@ -534,6 +479,9 @@ package body System.Value_R is
-- If True some digits where not in the base. The real is still scanned
-- till the end even if an error will be raised.
+ Extra2_Filled : Boolean;
+ -- True if Extra2 has been filled
+
N : Positive;
-- Index number of the current part
@@ -578,12 +526,12 @@ package body System.Value_R is
if Str (Index) in '0' .. '9' then
After_Point := False;
- -- If this is a digit it can indicates either the float decimal
- -- part or the base to use.
+ -- If this is a digit it can indicate either the integral part or the
+ -- base to use.
Scan_Integral_Digits
(Str, Index, Max, Base, False, Value, Scale, N,
- Char_As_Digit (Extra), Base_Violation);
+ Extra2, Extra2_Filled, Base_Violation);
-- A dot is allowed only if followed by a digit (RM 3.5(39.8))
@@ -596,13 +544,15 @@ package body System.Value_R is
N := 1;
Value := (others => 0);
Scale := (others => 0);
- Extra := 0;
+ Extra2 := 0;
+ Extra2_Filled := False;
else
Bad_Value (Str);
end if;
- -- Check if the first number encountered is a base
+ -- Check if the first number encountered is a base. ':' is allowed in
+ -- place of '#' in virtue of RM J.2 (3).
pragma Assert (Index >= Str'First);
@@ -611,7 +561,13 @@ package body System.Value_R is
then
Base_Char := Str (Index);
- if N = 1 and then Value (1) in 2 .. 16 then
+ -- Functionally, "(Parts = 1 or else N = 1)" in the condition of the
+ -- following if statement could replaced by the simpler "N = 1". The
+ -- reason we use a more complicated expression is to accommodate
+ -- machine-code-based coverage tools: the simple version makes it
+ -- impossible to fully cover generic instances of System.Value_R with
+ -- Parts = 1.
+ if (Parts = 1 or else N = 1) and then Value (1) in 2 .. 16 then
Base := Unsigned (Value (1));
else
Base_Violation := True;
@@ -630,16 +586,16 @@ package body System.Value_R is
end if;
end if;
- -- Scan the integral part if still necessary
+ -- Scan the integral part if there was a base and no point right after
if Base_Char /= ASCII.NUL and then not After_Point then
- if Index > Max or else As_Digit (Str (Index)) not in Valid_Digit then
+ if As_Digit (Str (Index)) not in Valid_Digit then
Bad_Value (Str);
end if;
Scan_Integral_Digits
(Str, Index, Max, Base, Base_Char /= ASCII.NUL, Value, Scale,
- N, Char_As_Digit (Extra), Base_Violation);
+ N, Extra2, Extra2_Filled, Base_Violation);
end if;
-- Do we have a dot?
@@ -664,9 +620,22 @@ package body System.Value_R is
if After_Point then
pragma Assert (Index <= Max);
- Scan_Decimal_Digits
- (Str, Index, Max, Base, Base_Char /= ASCII.NUL, Value, Scale,
- N, Char_As_Digit (Extra), Base_Violation);
+ -- If Extra2 has been filled, we are done with it
+
+ if Extra2_Filled then
+ declare
+ Dummy : Unsigned := 0;
+ begin
+ Scan_Decimal_Digits
+ (Str, Index, Max, Base, Base_Char /= ASCII.NUL, Value, Scale,
+ N, Dummy, Base_Violation);
+ end;
+
+ else
+ Scan_Decimal_Digits
+ (Str, Index, Max, Base, Base_Char /= ASCII.NUL, Value, Scale,
+ N, Extra2, Base_Violation);
+ end if;
end if;
-- If an explicit base was specified ensure that the delimiter is found
@@ -714,11 +683,11 @@ package body System.Value_R is
--------------------
function Value_Raw_Real
- (Str : String;
- Base : out Unsigned;
- Scale : out Scale_Array;
- Extra : out Unsigned;
- Minus : out Boolean) return Value_Array
+ (Str : String;
+ Base : out Unsigned;
+ Scale : out Scale_Array;
+ Extra2 : out Unsigned;
+ Minus : out Boolean) return Value_Array
is
P : aliased Integer;
V : Value_Array;
@@ -732,14 +701,14 @@ package body System.Value_R is
declare
subtype NT is String (1 .. Str'Length);
begin
- return Value_Raw_Real (NT (Str), Base, Scale, Extra, Minus);
+ return Value_Raw_Real (NT (Str), Base, Scale, Extra2, Minus);
end;
end if;
-- Normal case
P := Str'First;
- V := Scan_Raw_Real (Str, P'Access, Str'Last, Base, Scale, Extra, Minus);
+ V := Scan_Raw_Real (Str, P'Access, Str'Last, Base, Scale, Extra2, Minus);
Scan_Trailing_Blanks (Str, P);
return V;