|
|
1.1 root 1: /* atof_generic.c - turn a string of digits into a Flonum
2: Copyright (C) 1987 Free Software Foundation, Inc.
3:
4: This file is part of GAS, the GNU Assembler.
5:
6: GAS is free software; you can redistribute it and/or modify
7: it under the terms of the GNU General Public License as published by
8: the Free Software Foundation; either version 1, or (at your option)
9: any later version.
10:
11: GAS is distributed in the hope that it will be useful,
12: but WITHOUT ANY WARRANTY; without even the implied warranty of
13: MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14: GNU General Public License for more details.
15:
16: You should have received a copy of the GNU General Public License
17: along with GAS; see the file COPYING. If not, write to
18: the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
19:
20: #include <ctype.h>
21: #include <stdlib.h>
22: #include <string.h>
23: #include "flonum.h"
24:
25: #define FALSE (0)
26: #define TRUE (1)
27:
28: /***********************************************************************\
29: * *
30: * Given a string of decimal digits , with optional decimal *
31: * mark and optional decimal exponent (place value) of the *
32: * lowest_order decimal digit: produce a floating point *
33: * number. The number is 'generic' floating point: our *
34: * caller will encode it for a specific machine architecture. *
35: * *
36: * Assumptions *
37: * uses base (radix) 2 *
38: * this machine uses 2's complement binary integers *
39: * target flonums use " " " " *
40: * target flonums exponents fit in a long int *
41: * *
42: \***********************************************************************/
43:
44: /*
45:
46: Syntax:
47:
48: <flonum> ::= <optional-sign> <decimal-number> <optional-exponent>
49: <optional-sign> ::= '+' | '-' | {empty}
50: <decimal-number> ::= <integer>
51: | <integer> <radix-character>
52: | <integer> <radix-character> <integer>
53: | <radix-character> <integer>
54: <optional-exponent> ::= {empty} | <exponent-character> <optional-sign> <integer>
55: <integer> ::= <digit> | <digit> <integer>
56: <digit> ::= '0' | '1' | '2' | '3' | '4' | '5' | '6' | '7' | '8' | '9'
57: <exponent-character> ::= {one character from "string_of_decimal_exponent_marks"}
58: <radix-character> ::= {one character from "string_of_decimal_marks"}
59:
60: */
61:
62: /* 0 if OK */
63: int
64: atof_generic (
65: char **address_of_string_pointer, /* return pointer to just AFTER number read */
66: const char *string_of_decimal_marks, /* at most one per number */
67: const char *string_of_decimal_exponent_marks,
68: FLONUM_TYPE *address_of_generic_floating_point_number)
69: {
70:
71: int return_value; /* 0 means OK. */
72: char * first_digit;
73: /* char * last_digit; JF unused */
74: int number_of_digits_before_decimal;
75: int number_of_digits_after_decimal;
76: long int decimal_exponent;
77: int number_of_digits_available;
78: char digits_sign_char;
79:
80: {
81: /*
82: * Scan the input string, abstracting (1)digits (2)decimal mark (3) exponent.
83: * It would be simpler to modify the string, but we don't; just to be nice
84: * to caller.
85: * We need to know how many digits we have, so we can allocate space for
86: * the digits' value.
87: */
88:
89: char * p;
90: char c;
91: int seen_significant_digit;
92:
93: first_digit = * address_of_string_pointer;
94: c= *first_digit;
95: if (c=='-' || c=='+')
96: {
97: digits_sign_char = c;
98: first_digit ++;
99: }
100: else
101: digits_sign_char = '+';
102:
103: if( (first_digit[0]=='n' || first_digit[0]=='N')
104: && (first_digit[1]=='a' || first_digit[1]=='A')
105: && (first_digit[2]=='n' || first_digit[2]=='N')) {
106: address_of_generic_floating_point_number->sign=0;
107: address_of_generic_floating_point_number->exponent=0;
108: address_of_generic_floating_point_number->leader=address_of_generic_floating_point_number->low;
109: (*address_of_string_pointer)=first_digit+3;
110: return 0;
111: }
112: if( (first_digit[0]=='i' || first_digit[0]=='I')
113: && (first_digit[1]=='n' || first_digit[1]=='N')
114: && (first_digit[2]=='f' || first_digit[2]=='F')) {
115: address_of_generic_floating_point_number->sign= digits_sign_char=='+' ? 'P' : 'N';
116: address_of_generic_floating_point_number->exponent=0;
117: address_of_generic_floating_point_number->leader=address_of_generic_floating_point_number->low;
118: if( (first_digit[3]=='i' || first_digit[3]=='I')
119: && (first_digit[4]=='n' || first_digit[4]=='N')
120: && (first_digit[5]=='i' || first_digit[5]=='I')
121: && (first_digit[6]=='t' || first_digit[6]=='T')
122: && (first_digit[7]=='y' || first_digit[7]=='Y'))
123: (*address_of_string_pointer)=first_digit+8;
124: else
125: (*address_of_string_pointer)=first_digit+3;
126: return 0;
127: }
128:
129: number_of_digits_before_decimal = 0;
130: number_of_digits_after_decimal = 0;
131: decimal_exponent = 0;
132: seen_significant_digit = FALSE;
133: for (p = first_digit;
134: (c = * p)
135: && (!c || ! strchr(string_of_decimal_marks, c) )
136: && (!c || ! strchr(string_of_decimal_exponent_marks, c) );
137: p ++)
138: {
139: if (isdigit(c))
140: {
141: if (seen_significant_digit || c > '0')
142: {
143: number_of_digits_before_decimal ++;
144: seen_significant_digit = TRUE;
145: }
146: else
147: {
148: first_digit++;
149: }
150: }
151: else
152: {
153: break; /* p -> char after pre-decimal digits. */
154: }
155: } /* For each digit before decimal mark. */
156: if (c && strchr(string_of_decimal_marks, c))
157: {
158: for (p ++;
159: (c = * p)
160: && (!c || ! strchr(string_of_decimal_exponent_marks, c) );
161: p ++)
162: {
163: if (isdigit(c))
164: {
165: number_of_digits_after_decimal ++; /* This may be retracted below. */
166: if (/* seen_significant_digit || */ c > '0')
167: {
168: seen_significant_digit = TRUE;
169: }
170: }
171: else
172: {
173: if ( ! seen_significant_digit)
174: {
175: number_of_digits_after_decimal = 0;
176: }
177: break;
178: }
179: } /* For each digit after decimal mark. */
180: }
181: while(number_of_digits_after_decimal && first_digit[number_of_digits_before_decimal+number_of_digits_after_decimal]=='0')
182: --number_of_digits_after_decimal;
183: /* last_digit = p; JF unused */
184:
185: if (c && strchr(string_of_decimal_exponent_marks, c) )
186: {
187: char digits_exponent_sign_char;
188:
189: c = * ++ p;
190: if (c && strchr("+-",c))
191: {
192: digits_exponent_sign_char = c;
193: c = * ++ p;
194: }
195: else
196: {
197: digits_exponent_sign_char = '+';
198: }
199: for (;
200: (c);
201: c = * ++ p)
202: {
203: if (isdigit(c))
204: {
205: decimal_exponent = decimal_exponent * 10 + c - '0';
206: /*
207: * BUG! If we overflow here, we lose!
208: */
209: }
210: else
211: {
212: break;
213: }
214: }
215: if (digits_exponent_sign_char == '-')
216: {
217: decimal_exponent = - decimal_exponent;
218: }
219: }
220: * address_of_string_pointer = p;
221: }
222:
223: number_of_digits_available =
224: number_of_digits_before_decimal
225: + number_of_digits_after_decimal;
226: return_value = 0;
227: if (number_of_digits_available == 0)
228: {
229: address_of_generic_floating_point_number -> exponent = 0; /* Not strictly necessary */
230: address_of_generic_floating_point_number -> leader
231: = -1 + address_of_generic_floating_point_number -> low;
232: address_of_generic_floating_point_number -> sign = digits_sign_char;
233: /* We have just concocted (+/-)0.0E0 */
234: }
235: else
236: {
237: LITTLENUM_TYPE * digits_binary_low;
238: int precision;
239: int maximum_useful_digits;
240: int number_of_digits_to_use;
241: int more_than_enough_bits_for_digits;
242: int more_than_enough_littlenums_for_digits;
243: int size_of_digits_in_littlenums;
244: int size_of_digits_in_chars;
245: FLONUM_TYPE power_of_10_flonum;
246: FLONUM_TYPE digits_flonum;
247:
248:
249: precision = (address_of_generic_floating_point_number -> high
250: - address_of_generic_floating_point_number -> low
251: + 1
252: ); /* Number of destination littlenums. */
253: /* Includes guard bits (two littlenums worth) */
254: maximum_useful_digits = ( ((double) (precision - 2))
255: * ((double) (LITTLENUM_NUMBER_OF_BITS))
256: / (LOG_TO_BASE_2_OF_10)
257: )
258: + 2; /* 2 :: guard digits. */
259: if (number_of_digits_available > maximum_useful_digits)
260: {
261: number_of_digits_to_use = maximum_useful_digits;
262: }
263: else
264: {
265: number_of_digits_to_use = number_of_digits_available;
266: }
267: decimal_exponent += number_of_digits_before_decimal - number_of_digits_to_use;
268:
269: more_than_enough_bits_for_digits
270: = ((((double)number_of_digits_to_use) * LOG_TO_BASE_2_OF_10) + 1);
271: more_than_enough_littlenums_for_digits
272: = ( more_than_enough_bits_for_digits
273: / LITTLENUM_NUMBER_OF_BITS
274: )
275: + 2;
276:
277: /*
278: * Compute (digits) part. In "12.34E56" this is the "1234" part.
279: * Arithmetic is exact here. If no digits are supplied then
280: * this part is a 0 valued binary integer.
281: * Allocate room to build up the binary number as littlenums.
282: * We want this memory to disappear when we leave this function.
283: * Assume no alignment problems => (room for n objects) ==
284: * n * (room for 1 object).
285: */
286:
287: size_of_digits_in_littlenums = more_than_enough_littlenums_for_digits;
288: size_of_digits_in_chars = size_of_digits_in_littlenums
289: * sizeof( LITTLENUM_TYPE );
290: digits_binary_low = (LITTLENUM_TYPE *)
291: alloca (size_of_digits_in_chars);
292: memset((char *)digits_binary_low, '\0', size_of_digits_in_chars);
293:
294: /* Digits_binary_low[] is allocated and zeroed. */
295:
296: {
297: /*
298: * Parse the decimal digits as if * digits_low was in the units position.
299: * Emit a binary number into digits_binary_low[].
300: *
301: * Use a large-precision version of:
302: * (((1st-digit) * 10 + 2nd-digit) * 10 + 3rd-digit ...) * 10 + last-digit
303: */
304:
305: char * p;
306: char c;
307: int count; /* Number of useful digits left to scan. */
308:
309: for (p = first_digit, count = number_of_digits_to_use;
310: count;
311: p ++, -- count)
312: {
313: c = * p;
314: if (isdigit(c))
315: {
316: /*
317: * Multiply by 10. Assume can never overflow.
318: * Add this digit to digits_binary_low[].
319: */
320:
321: long int carry;
322: LITTLENUM_TYPE * littlenum_pointer;
323: LITTLENUM_TYPE * littlenum_limit;
324:
325: littlenum_limit
326: = digits_binary_low
327: + more_than_enough_littlenums_for_digits
328: - 1;
329: carry = c - '0'; /* char -> binary */
330: for (littlenum_pointer = digits_binary_low;
331: littlenum_pointer <= littlenum_limit;
332: littlenum_pointer ++)
333: {
334: long int work;
335:
336: work = carry + 10 * (long)(*littlenum_pointer);
337: * littlenum_pointer = work & LITTLENUM_MASK;
338: carry = work >> LITTLENUM_NUMBER_OF_BITS;
339: }
340: if (carry != 0)
341: {
342: /*
343: * We have a GROSS internal error.
344: * This should never happen.
345: */
346: abort(); /* RMS prefers abort() to any message. */
347: }
348: }
349: else
350: {
351: ++ count; /* '.' doesn't alter digits used count. */
352: } /* if valid digit */
353: } /* for each digit */
354: }
355:
356: /*
357: * Digits_binary_low[] properly encodes the value of the digits.
358: * Forget about any high-order littlenums that are 0.
359: */
360: while (digits_binary_low [size_of_digits_in_littlenums - 1] == 0
361: && size_of_digits_in_littlenums >= 2)
362: size_of_digits_in_littlenums --;
363:
364: digits_flonum . low = digits_binary_low;
365: digits_flonum . high = digits_binary_low + size_of_digits_in_littlenums - 1;
366: digits_flonum . leader = digits_flonum . high;
367: digits_flonum . exponent = 0;
368: /*
369: * The value of digits_flonum . sign should not be important.
370: * We have already decided the output's sign.
371: * We trust that the sign won't influence the other parts of the number!
372: * So we give it a value for these reasons:
373: * (1) courtesy to humans reading/debugging
374: * these numbers so they don't get excited about strange values
375: * (2) in future there may be more meaning attached to sign,
376: * and what was
377: * harmless noise may become disruptive, ill-conditioned (or worse)
378: * input.
379: */
380: digits_flonum . sign = '+';
381:
382: {
383: /*
384: * Compute the mantssa (& exponent) of the power of 10.
385: * If sucessful, then multiply the power of 10 by the digits
386: * giving return_binary_mantissa and return_binary_exponent.
387: */
388:
389: LITTLENUM_TYPE *power_binary_low;
390: int decimal_exponent_is_negative;
391: /* This refers to the "-56" in "12.34E-56". */
392: /* FALSE: decimal_exponent is positive (or 0) */
393: /* TRUE: decimal_exponent is negative */
394: FLONUM_TYPE temporary_flonum;
395: LITTLENUM_TYPE *temporary_binary_low;
396: int size_of_power_in_littlenums;
397: int size_of_power_in_chars;
398:
399: size_of_power_in_littlenums = precision;
400: /* Precision has a built-in fudge factor so we get a few guard bits. */
401:
402:
403: decimal_exponent_is_negative = decimal_exponent < 0;
404: if (decimal_exponent_is_negative)
405: {
406: decimal_exponent = - decimal_exponent;
407: }
408: /* From now on: the decimal exponent is > 0. Its sign is seperate. */
409:
410: size_of_power_in_chars
411: = size_of_power_in_littlenums
412: * sizeof( LITTLENUM_TYPE ) + 2;
413: power_binary_low = (LITTLENUM_TYPE *) alloca ( size_of_power_in_chars );
414: temporary_binary_low = (LITTLENUM_TYPE *) alloca ( size_of_power_in_chars );
415: memset((char *)power_binary_low, '\0', size_of_power_in_chars);
416: * power_binary_low = 1;
417: power_of_10_flonum . exponent = 0;
418: power_of_10_flonum . low = power_binary_low;
419: power_of_10_flonum . leader = power_binary_low;
420: power_of_10_flonum . high = power_binary_low + size_of_power_in_littlenums - 1;
421: power_of_10_flonum . sign = '+';
422: temporary_flonum . low = temporary_binary_low;
423: temporary_flonum . high = temporary_binary_low + size_of_power_in_littlenums - 1;
424: /*
425: * (power) == 1.
426: * Space for temporary_flonum allocated.
427: */
428:
429: /*
430: * ...
431: *
432: * WHILE more bits
433: * DO find next bit (with place value)
434: * multiply into power mantissa
435: * OD
436: */
437: {
438: int place_number_limit;
439: /* Any 10^(2^n) whose "n" exceeds this */
440: /* value will fall off the end of */
441: /* flonum_XXXX_powers_of_ten[]. */
442: int place_number;
443: const const_FLONUM_TYPE * multiplicand; /* -> 10^(2^n) */
444:
445: place_number_limit = table_size_of_flonum_powers_of_ten;
446: multiplicand
447: = ( decimal_exponent_is_negative
448: ? flonum_negative_powers_of_ten
449: : flonum_positive_powers_of_ten);
450: for (place_number = 1; /* Place value of this bit of exponent. */
451: decimal_exponent; /* Quit when no more 1 bits in exponent. */
452: decimal_exponent >>= 1
453: , place_number ++)
454: {
455: if (decimal_exponent & 1)
456: {
457: if (place_number > place_number_limit)
458: {
459: /*
460: * The decimal exponent has a magnitude so great that
461: * our tables can't help us fragment it. Although this
462: * routine is in error because it can't imagine a
463: * number that big, signal an error as if it is the
464: * user's fault for presenting such a big number.
465: */
466: return_value = ERROR_EXPONENT_OVERFLOW;
467: /*
468: * quit out of loop gracefully
469: */
470: decimal_exponent = 0;
471: }
472: else
473: {
474: #ifdef TRACE
475: printf("before multiply, place_number = %d., power_of_10_flonum:\n", place_number);
476: flonum_print( & power_of_10_flonum );
477: (void)putchar('\n');
478: #endif
479: flonum_multip ((const_FLONUM_TYPE *)multiplicand + place_number, & power_of_10_flonum, & temporary_flonum);
480: flonum_copy (& temporary_flonum, & power_of_10_flonum);
481: } /* If this bit of decimal_exponent was computable.*/
482: } /* If this bit of decimal_exponent was set. */
483: } /* For each bit of binary representation of exponent */
484: #ifdef TRACE
485: printf( " after computing power_of_10_flonum: " );
486: flonum_print( & power_of_10_flonum );
487: (void)putchar('\n');
488: #endif
489: }
490:
491: }
492:
493: /*
494: * power_of_10_flonum is power of ten in binary (mantissa) , (exponent).
495: * It may be the number 1, in which case we don't NEED to multiply.
496: *
497: * Multiply (decimal digits) by power_of_10_flonum.
498: */
499:
500: flonum_multip ((const_FLONUM_TYPE *)&power_of_10_flonum, & digits_flonum, address_of_generic_floating_point_number);
501: /* Assert sign of the number we made is '+'. */
502: address_of_generic_floating_point_number -> sign = digits_sign_char;
503:
504: } /* If we had any significant digits. */
505: return (return_value);
506: } /* atof_generic () */
507:
508: /* end: atof_generic.c */
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.