1------------------------------------------------------------------------------ 2-- -- 3-- GNAT COMPILER COMPONENTS -- 4-- -- 5-- S Y S T E M . V A L _ U T I L -- 6-- -- 7-- B o d y -- 8-- -- 9-- Copyright (C) 1992-2012, Free Software Foundation, Inc. -- 10-- -- 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. -- 17-- -- 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. -- 21-- -- 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/>. -- 26-- -- 27-- GNAT was originally developed by the GNAT team at New York University. -- 28-- Extensive contributions were provided by Ada Core Technologies Inc. -- 29-- -- 30------------------------------------------------------------------------------ 31 32with System.Case_Util; use System.Case_Util; 33 34package body System.Val_Util is 35 36 --------------- 37 -- Bad_Value -- 38 --------------- 39 40 procedure Bad_Value (S : String) is 41 begin 42 raise Constraint_Error with "bad input for 'Value: """ & S & '"'; 43 end Bad_Value; 44 45 ---------------------- 46 -- Normalize_String -- 47 ---------------------- 48 49 procedure Normalize_String 50 (S : in out String; 51 F, L : out Integer) 52 is 53 begin 54 F := S'First; 55 L := S'Last; 56 57 -- Scan for leading spaces 58 59 while F <= L and then S (F) = ' ' loop 60 F := F + 1; 61 end loop; 62 63 -- Check for case when the string contained no characters 64 65 if F > L then 66 Bad_Value (S); 67 end if; 68 69 -- Scan for trailing spaces 70 71 while S (L) = ' ' loop 72 L := L - 1; 73 end loop; 74 75 -- Except in the case of a character literal, convert to upper case 76 77 if S (F) /= ''' then 78 for J in F .. L loop 79 S (J) := To_Upper (S (J)); 80 end loop; 81 end if; 82 end Normalize_String; 83 84 ------------------- 85 -- Scan_Exponent -- 86 ------------------- 87 88 function Scan_Exponent 89 (Str : String; 90 Ptr : not null access Integer; 91 Max : Integer; 92 Real : Boolean := False) return Integer 93 is 94 P : Natural := Ptr.all; 95 M : Boolean; 96 X : Integer; 97 98 begin 99 if P >= Max 100 or else (Str (P) /= 'E' and then Str (P) /= 'e') 101 then 102 return 0; 103 end if; 104 105 -- We have an E/e, see if sign follows 106 107 P := P + 1; 108 109 if Str (P) = '+' then 110 P := P + 1; 111 112 if P > Max then 113 return 0; 114 else 115 M := False; 116 end if; 117 118 elsif Str (P) = '-' then 119 P := P + 1; 120 121 if P > Max or else not Real then 122 return 0; 123 else 124 M := True; 125 end if; 126 127 else 128 M := False; 129 end if; 130 131 if Str (P) not in '0' .. '9' then 132 return 0; 133 end if; 134 135 -- Scan out the exponent value as an unsigned integer. Values larger 136 -- than (Integer'Last / 10) are simply considered large enough here. 137 -- This assumption is correct for all machines we know of (e.g. in 138 -- the case of 16 bit integers it allows exponents up to 3276, which 139 -- is large enough for the largest floating types in base 2.) 140 141 X := 0; 142 143 loop 144 if X < (Integer'Last / 10) then 145 X := X * 10 + (Character'Pos (Str (P)) - Character'Pos ('0')); 146 end if; 147 148 P := P + 1; 149 150 exit when P > Max; 151 152 if Str (P) = '_' then 153 Scan_Underscore (Str, P, Ptr, Max, False); 154 else 155 exit when Str (P) not in '0' .. '9'; 156 end if; 157 end loop; 158 159 if M then 160 X := -X; 161 end if; 162 163 Ptr.all := P; 164 return X; 165 end Scan_Exponent; 166 167 -------------------- 168 -- Scan_Plus_Sign -- 169 -------------------- 170 171 procedure Scan_Plus_Sign 172 (Str : String; 173 Ptr : not null access Integer; 174 Max : Integer; 175 Start : out Positive) 176 is 177 P : Natural := Ptr.all; 178 179 begin 180 if P > Max then 181 Bad_Value (Str); 182 end if; 183 184 -- Scan past initial blanks 185 186 while Str (P) = ' ' loop 187 P := P + 1; 188 189 if P > Max then 190 Ptr.all := P; 191 Bad_Value (Str); 192 end if; 193 end loop; 194 195 Start := P; 196 197 -- Skip past an initial plus sign 198 199 if Str (P) = '+' then 200 P := P + 1; 201 202 if P > Max then 203 Ptr.all := Start; 204 Bad_Value (Str); 205 end if; 206 end if; 207 208 Ptr.all := P; 209 end Scan_Plus_Sign; 210 211 --------------- 212 -- Scan_Sign -- 213 --------------- 214 215 procedure Scan_Sign 216 (Str : String; 217 Ptr : not null access Integer; 218 Max : Integer; 219 Minus : out Boolean; 220 Start : out Positive) 221 is 222 P : Natural := Ptr.all; 223 224 begin 225 -- Deal with case of null string (all blanks!). As per spec, we 226 -- raise constraint error, with Ptr unchanged, and thus > Max. 227 228 if P > Max then 229 Bad_Value (Str); 230 end if; 231 232 -- Scan past initial blanks 233 234 while Str (P) = ' ' loop 235 P := P + 1; 236 237 if P > Max then 238 Ptr.all := P; 239 Bad_Value (Str); 240 end if; 241 end loop; 242 243 Start := P; 244 245 -- Remember an initial minus sign 246 247 if Str (P) = '-' then 248 Minus := True; 249 P := P + 1; 250 251 if P > Max then 252 Ptr.all := Start; 253 Bad_Value (Str); 254 end if; 255 256 -- Skip past an initial plus sign 257 258 elsif Str (P) = '+' then 259 Minus := False; 260 P := P + 1; 261 262 if P > Max then 263 Ptr.all := Start; 264 Bad_Value (Str); 265 end if; 266 267 else 268 Minus := False; 269 end if; 270 271 Ptr.all := P; 272 end Scan_Sign; 273 274 -------------------------- 275 -- Scan_Trailing_Blanks -- 276 -------------------------- 277 278 procedure Scan_Trailing_Blanks (Str : String; P : Positive) is 279 begin 280 for J in P .. Str'Last loop 281 if Str (J) /= ' ' then 282 Bad_Value (Str); 283 end if; 284 end loop; 285 end Scan_Trailing_Blanks; 286 287 --------------------- 288 -- Scan_Underscore -- 289 --------------------- 290 291 procedure Scan_Underscore 292 (Str : String; 293 P : in out Natural; 294 Ptr : not null access Integer; 295 Max : Integer; 296 Ext : Boolean) 297 is 298 C : Character; 299 300 begin 301 P := P + 1; 302 303 -- If underscore is at the end of string, then this is an error and 304 -- we raise Constraint_Error, leaving the pointer past the underscore. 305 -- This seems a bit strange. It means e.g. that if the field is: 306 307 -- 345_ 308 309 -- that Constraint_Error is raised. You might think that the RM in 310 -- this case would scan out the 345 as a valid integer, leaving the 311 -- pointer at the underscore, but the ACVC suite clearly requires 312 -- an error in this situation (see for example CE3704M). 313 314 if P > Max then 315 Ptr.all := P; 316 Bad_Value (Str); 317 end if; 318 319 -- Similarly, if no digit follows the underscore raise an error. This 320 -- also catches the case of double underscore which is also an error. 321 322 C := Str (P); 323 324 if C in '0' .. '9' 325 or else (Ext and then (C in 'A' .. 'F' or else C in 'a' .. 'f')) 326 then 327 return; 328 else 329 Ptr.all := P; 330 Bad_Value (Str); 331 end if; 332 end Scan_Underscore; 333 334end System.Val_Util; 335