OSDN Git Service

New Language: Ada
[pf3gnuchains/gcc-fork.git] / gcc / ada / s-valllu.adb
1 ------------------------------------------------------------------------------
2 --                                                                          --
3 --                         GNAT COMPILER COMPONENTS                         --
4 --                                                                          --
5 --                       S Y S T E M . V A L _ L L U                        --
6 --                                                                          --
7 --                                 S p e c                                  --
8 --                                                                          --
9 --                            $Revision: 1.12 $                             --
10 --                                                                          --
11 --          Copyright (C) 1992-1997 Free Software Foundation, Inc.          --
12 --                                                                          --
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.                                                      --
23 --                                                                          --
24 -- As a special exception,  if other files  instantiate  generics from this --
25 -- unit, or you link  this unit with other files  to produce an executable, --
26 -- this  unit  does not  by itself cause  the resulting  executable  to  be --
27 -- covered  by the  GNU  General  Public  License.  This exception does not --
28 -- however invalidate  any other reasons why  the executable file  might be --
29 -- covered by the  GNU Public License.                                      --
30 --                                                                          --
31 -- GNAT was originally developed  by the GNAT team at  New York University. --
32 -- It is now maintained by Ada Core Technologies Inc (http://www.gnat.com). --
33 --                                                                          --
34 ------------------------------------------------------------------------------
35
36 with System.Unsigned_Types; use System.Unsigned_Types;
37 with System.Val_Util;       use System.Val_Util;
38
39 package body System.Val_LLU is
40
41    -----------------------------
42    -- Scan_Long_Long_Unsigned --
43    -----------------------------
44
45    function Scan_Long_Long_Unsigned
46      (Str  : String;
47       Ptr  : access Integer;
48       Max  : Integer)
49       return Long_Long_Unsigned
50    is
51       P : Integer;
52       --  Local copy of the pointer
53
54       Uval : Long_Long_Unsigned;
55       --  Accumulated unsigned integer result
56
57       Expon : Integer;
58       --  Exponent value
59
60       Minus : Boolean := False;
61       --  Set to True if minus sign is present, otherwise to False. Note that
62       --  a minus sign is permissible for the singular case of -0, and in any
63       --  case the pointer is left pointing past a negative integer literal.
64
65       Overflow : Boolean := False;
66       --  Set True if overflow is detected at any point
67
68       Start : Positive;
69       --  Save location of first non-blank character
70
71       Base_Char : Character;
72       --  Base character (# or :) in based case
73
74       Base : Long_Long_Unsigned := 10;
75       --  Base value (reset in based case)
76
77       Digit : Long_Long_Unsigned;
78       --  Digit value
79
80    begin
81       Scan_Sign (Str, Ptr, Max, Minus, Start);
82
83       if Str (Ptr.all) not in '0' .. '9' then
84          Ptr.all := Start;
85          raise Constraint_Error;
86       end if;
87
88       P := Ptr.all;
89       Uval := Character'Pos (Str (P)) - Character'Pos ('0');
90       P := P + 1;
91
92       --  Scan out digits of what is either the number or the base.
93       --  In either case, we are definitely scanning out in base 10.
94
95       declare
96          Umax : constant := (Long_Long_Unsigned'Last - 9) / 10;
97          --  Max value which cannot overflow on accumulating next digit
98
99          Umax10 : constant := Long_Long_Unsigned'Last / 10;
100          --  Numbers bigger than Umax10 overflow if multiplied by 10
101
102       begin
103          --  Loop through decimal digits
104          loop
105             exit when P > Max;
106
107             Digit := Character'Pos (Str (P)) - Character'Pos ('0');
108
109             --  Non-digit encountered
110
111             if Digit > 9 then
112                if Str (P) = '_' then
113                   Scan_Underscore (Str, P, Ptr, Max, False);
114                else
115                   exit;
116                end if;
117
118             --  Accumulate result, checking for overflow
119
120             else
121                if Uval <= Umax then
122                   Uval := 10 * Uval + Digit;
123
124                elsif Uval > Umax10 then
125                   Overflow := True;
126
127                else
128                   Uval := 10 * Uval + Digit;
129
130                   if Uval < Umax10 then
131                      Overflow := True;
132                   end if;
133                end if;
134
135                P := P + 1;
136             end if;
137          end loop;
138       end;
139
140       Ptr.all := P;
141
142       --  Deal with based case
143
144       if P < Max and then (Str (P) = ':' or else Str (P) = '#') then
145          Base_Char := Str (P);
146          P := P + 1;
147          Base := Uval;
148          Uval := 0;
149
150          --  Check base value. Overflow is set True if we find a bad base, or
151          --  a digit that is out of range of the base. That way, we scan out
152          --  the numeral that is still syntactically correct, though illegal.
153          --  We use a safe base of 16 for this scan, to avoid zero divide.
154
155          if Base not in 2 .. 16 then
156             Overflow := True;
157             Base :=  16;
158          end if;
159
160          --  Scan out based integer
161
162          declare
163             Umax : constant Long_Long_Unsigned :=
164                      (Long_Long_Unsigned'Last - Base + 1) / Base;
165             --  Max value which cannot overflow on accumulating next digit
166
167             UmaxB : constant Long_Long_Unsigned :=
168                       Long_Long_Unsigned'Last / Base;
169             --  Numbers bigger than UmaxB overflow if multiplied by base
170
171          begin
172             --  Loop to scan out based integer value
173
174             loop
175                --  We require a digit at this stage
176
177                if Str (P) in '0' .. '9' then
178                   Digit := Character'Pos (Str (P)) - Character'Pos ('0');
179
180                elsif Str (P) in 'A' .. 'F' then
181                   Digit :=
182                     Character'Pos (Str (P)) - (Character'Pos ('A') - 10);
183
184                elsif Str (P) in 'a' .. 'f' then
185                   Digit :=
186                     Character'Pos (Str (P)) - (Character'Pos ('a') - 10);
187
188                --  If we don't have a digit, then this is not a based number
189                --  after all, so we use the value we scanned out as the base
190                --  (now in Base), and the pointer to the base character was
191                --  already stored in Ptr.all.
192
193                else
194                   Uval := Base;
195                   exit;
196                end if;
197
198                --  If digit is too large, just signal overflow and continue.
199                --  The idea here is to keep scanning as long as the input is
200                --  syntactically valid, even if we have detected overflow
201
202                if Digit >= Base then
203                   Overflow := True;
204
205                --  Here we accumulate the value, checking overflow
206
207                elsif Uval <= Umax then
208                   Uval := Base * Uval + Digit;
209
210                elsif Uval > UmaxB then
211                   Overflow := True;
212
213                else
214                   Uval := Base * Uval + Digit;
215
216                   if Uval < UmaxB then
217                      Overflow := True;
218                   end if;
219                end if;
220
221                --  If at end of string with no base char, not a based number
222                --  but we signal Constraint_Error and set the pointer past
223                --  the end of the field, since this is what the ACVC tests
224                --  seem to require, see CE3704N, line 204.
225
226                P := P + 1;
227
228                if P > Max then
229                   Ptr.all := P;
230                   raise Constraint_Error;
231                end if;
232
233                --  If terminating base character, we are done with loop
234
235                if Str (P) = Base_Char then
236                   Ptr.all := P + 1;
237                   exit;
238
239                --  Deal with underscore
240
241                elsif Str (P) = '_' then
242                   Scan_Underscore (Str, P, Ptr, Max, True);
243                end if;
244
245             end loop;
246          end;
247       end if;
248
249       --  Come here with scanned unsigned value in Uval. The only remaining
250       --  required step is to deal with exponent if one is present.
251
252       Expon := Scan_Exponent (Str, Ptr, Max);
253
254       if Expon /= 0 and then Uval /= 0 then
255
256          --  For non-zero value, scale by exponent value. No need to do this
257          --  efficiently, since use of exponent in integer literals is rare,
258          --  and in any case the exponent cannot be very large.
259
260          declare
261             UmaxB : constant Long_Long_Unsigned :=
262                       Long_Long_Unsigned'Last / Base;
263             --  Numbers bigger than UmaxB overflow if multiplied by base
264
265          begin
266             for J in 1 .. Expon loop
267                if Uval > UmaxB then
268                   Overflow := True;
269                   exit;
270                end if;
271
272                Uval := Uval * Base;
273             end loop;
274          end;
275       end if;
276
277       --  Return result, dealing with sign and overflow
278
279       if Overflow or else (Minus and then Uval /= 0) then
280          raise Constraint_Error;
281       else
282          return Uval;
283       end if;
284    end Scan_Long_Long_Unsigned;
285
286    ------------------------------
287    -- Value_Long_Long_Unsigned --
288    ------------------------------
289
290    function Value_Long_Long_Unsigned
291      (Str : String)
292      return Long_Long_Unsigned
293    is
294       V : Long_Long_Unsigned;
295       P : aliased Integer := Str'First;
296
297    begin
298       V := Scan_Long_Long_Unsigned (Str, P'Access, Str'Last);
299       Scan_Trailing_Blanks (Str, P);
300       return V;
301
302    end Value_Long_Long_Unsigned;
303
304 end System.Val_LLU;