/* atof_generic.c - turn a string of digits into a Flonum
- Copyright (C) 1987, 1990, 1991, 1992 Free Software Foundation, Inc.
+ Copyright (C) 1987-2020 Free Software Foundation, Inc.
This file is part of GAS, the GNU Assembler.
GAS is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
- the Free Software Foundation; either version 2, or (at your option)
+ the Free Software Foundation; either version 3, or (at your option)
any later version.
- GAS is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU General Public License for more details.
+ GAS is distributed in the hope that it will be useful, but WITHOUT
+ ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
+ License for more details.
You should have received a copy of the GNU General Public License
- along with GAS; see the file COPYING. If not, write to
- the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
-
-#include <ctype.h>
-#include <string.h>
+ along with GAS; see the file COPYING. If not, write to the Free
+ Software Foundation, 51 Franklin Street - Fifth Floor, Boston, MA
+ 02110-1301, USA. */
#include "as.h"
-
-#ifdef __GNUC__
-#define alloca __builtin_alloca
-#else
-#ifdef sparc
-#include <alloca.h>
-#endif
-#endif
+#include "safe-ctype.h"
#ifndef FALSE
#define FALSE (0)
#define TRUE (1)
#endif
+#ifdef TRACE
+static void flonum_print (const FLONUM_TYPE *);
+#endif
+
+#define ASSUME_DECIMAL_MARK_IS_DOT
+
/***********************************************************************\
* *
* Given a string of decimal digits , with optional decimal *
*/
int
-atof_generic (address_of_string_pointer,
- string_of_decimal_marks,
- string_of_decimal_exponent_marks,
- address_of_generic_floating_point_number)
- /* return pointer to just AFTER number we read. */
- char **address_of_string_pointer;
- /* At most one per number. */
- const char *string_of_decimal_marks;
- const char *string_of_decimal_exponent_marks;
- FLONUM_TYPE *address_of_generic_floating_point_number;
+atof_generic (/* return pointer to just AFTER number we read. */
+ char **address_of_string_pointer,
+ /* At most one per number. */
+ const char *string_of_decimal_marks,
+ const char *string_of_decimal_exponent_marks,
+ FLONUM_TYPE *address_of_generic_floating_point_number)
{
- int return_value; /* 0 means OK. */
+ int return_value; /* 0 means OK. */
char *first_digit;
- /* char *last_digit; JF unused */
- int number_of_digits_before_decimal;
- int number_of_digits_after_decimal;
+ unsigned int number_of_digits_before_decimal;
+ unsigned int number_of_digits_after_decimal;
long decimal_exponent;
- int number_of_digits_available;
+ unsigned int number_of_digits_available;
char digits_sign_char;
/*
char c;
int seen_significant_digit;
+#ifdef ASSUME_DECIMAL_MARK_IS_DOT
+ gas_assert (string_of_decimal_marks[0] == '.'
+ && string_of_decimal_marks[1] == 0);
+#define IS_DECIMAL_MARK(c) ((c) == '.')
+#else
+#define IS_DECIMAL_MARK(c) (0 != strchr (string_of_decimal_marks, (c)))
+#endif
+
first_digit = *address_of_string_pointer;
c = *first_digit;
else
digits_sign_char = '+';
- if ((first_digit[0] == 'n' || first_digit[0] == 'N')
- && (first_digit[1] == 'a' || first_digit[1] == 'A')
- && (first_digit[2] == 'n' || first_digit[2] == 'N'))
- {
- address_of_generic_floating_point_number->sign = 0;
- address_of_generic_floating_point_number->exponent = 0;
- address_of_generic_floating_point_number->leader =
- address_of_generic_floating_point_number->low;
- *address_of_string_pointer = first_digit + 3;
- return 0;
- }
-
- if ((first_digit[0] == 'i' || first_digit[0] == 'I')
- && (first_digit[1] == 'n' || first_digit[1] == 'N')
- && (first_digit[2] == 'f' || first_digit[2] == 'F'))
+ switch (first_digit[0])
{
- address_of_generic_floating_point_number->sign =
- digits_sign_char == '+' ? 'P' : 'N';
- address_of_generic_floating_point_number->exponent = 0;
- address_of_generic_floating_point_number->leader =
- address_of_generic_floating_point_number->low;
-
- if ((first_digit[3] == 'i'
- || first_digit[3] == 'I')
- && (first_digit[4] == 'n'
- || first_digit[4] == 'N')
- && (first_digit[5] == 'i'
- || first_digit[5] == 'I')
- && (first_digit[6] == 't'
- || first_digit[6] == 'T')
- && (first_digit[7] == 'y'
- || first_digit[7] == 'Y'))
+ case 'n':
+ case 'N':
+ if (!strncasecmp ("nan", first_digit, 3))
{
- *address_of_string_pointer = first_digit + 8;
+ address_of_generic_floating_point_number->sign = 0;
+ address_of_generic_floating_point_number->exponent = 0;
+ address_of_generic_floating_point_number->leader =
+ address_of_generic_floating_point_number->low;
+ *address_of_string_pointer = first_digit + 3;
+ return 0;
}
- else
+ break;
+
+ case 'i':
+ case 'I':
+ if (!strncasecmp ("inf", first_digit, 3))
{
- *address_of_string_pointer = first_digit + 3;
+ address_of_generic_floating_point_number->sign =
+ digits_sign_char == '+' ? 'P' : 'N';
+ address_of_generic_floating_point_number->exponent = 0;
+ address_of_generic_floating_point_number->leader =
+ address_of_generic_floating_point_number->low;
+
+ first_digit += 3;
+ if (!strncasecmp ("inity", first_digit, 5))
+ first_digit += 5;
+
+ *address_of_string_pointer = first_digit;
+
+ return 0;
}
- return 0;
+ break;
}
number_of_digits_before_decimal = 0;
seen_significant_digit = 0;
for (p = first_digit;
(((c = *p) != '\0')
- && (!c || !strchr (string_of_decimal_marks, c))
+ && (!c || !IS_DECIMAL_MARK (c))
&& (!c || !strchr (string_of_decimal_exponent_marks, c)));
p++)
{
- if (isdigit (c))
+ if (ISDIGIT (c))
{
if (seen_significant_digit || c > '0')
{
}
else
{
- break; /* p -> char after pre-decimal digits. */
+ break; /* p -> char after pre-decimal digits. */
}
- } /* For each digit before decimal mark. */
+ } /* For each digit before decimal mark. */
#ifndef OLD_FLOAT_READS
/* Ignore trailing 0's after the decimal point. The original code here
- * (ifdef'd out) does not do this, and numbers like
- * 4.29496729600000000000e+09 (2**31)
- * come out inexact for some reason related to length of the digit
- * string.
- */
- if (c && strchr (string_of_decimal_marks, c))
+ (ifdef'd out) does not do this, and numbers like
+ 4.29496729600000000000e+09 (2**31)
+ come out inexact for some reason related to length of the digit
+ string. */
+
+ /* The case number_of_digits_before_decimal = 0 is handled for
+ deleting zeros after decimal. In this case the decimal mark and
+ the first zero digits after decimal mark are skipped. */
+ seen_significant_digit = 0;
+ signed long subtract_decimal_exponent = 0;
+
+ if (c && IS_DECIMAL_MARK (c))
{
- int zeros = 0; /* Length of current string of zeros */
+ unsigned int zeros = 0; /* Length of current string of zeros. */
- for (p++; (c = *p) && isdigit (c); p++)
+ if (number_of_digits_before_decimal == 0)
+ /* Skip decimal mark. */
+ first_digit++;
+
+ for (p++; (c = *p) && ISDIGIT (c); p++)
{
if (c == '0')
{
- zeros++;
+ if (number_of_digits_before_decimal == 0
+ && !seen_significant_digit)
+ {
+ /* Skip '0' and the decimal mark. */
+ first_digit++;
+ subtract_decimal_exponent--;
+ }
+ else
+ zeros++;
}
else
{
+ seen_significant_digit = 1;
number_of_digits_after_decimal += 1 + zeros;
zeros = 0;
}
}
}
#else
- if (c && strchr (string_of_decimal_marks, c))
+ if (c && IS_DECIMAL_MARK (c))
{
for (p++;
(((c = *p) != '\0')
&& (!c || !strchr (string_of_decimal_exponent_marks, c)));
p++)
{
- if (isdigit (c))
+ if (ISDIGIT (c))
{
- /* This may be retracted below. */
+ /* This may be retracted below. */
number_of_digits_after_decimal++;
if ( /* seen_significant_digit || */ c > '0')
}
break;
}
- } /* For each digit after decimal mark. */
+ } /* For each digit after decimal mark. */
}
while (number_of_digits_after_decimal
--number_of_digits_after_decimal;
#endif
+ if (flag_m68k_mri)
+ {
+ while (c == '_')
+ c = *++p;
+ }
if (c && strchr (string_of_decimal_exponent_marks, c))
{
char digits_exponent_sign_char;
c = *++p;
+ if (flag_m68k_mri)
+ {
+ while (c == '_')
+ c = *++p;
+ }
if (c && strchr ("+-", c))
{
digits_exponent_sign_char = c;
for (; (c); c = *++p)
{
- if (isdigit (c))
+ if (ISDIGIT (c))
{
decimal_exponent = decimal_exponent * 10 + c - '0';
/*
}
}
- *address_of_string_pointer = p;
-
+#ifndef OLD_FLOAT_READS
+ /* Subtract_decimal_exponent != 0 when number_of_digits_before_decimal = 0
+ and first digit after decimal is '0'. */
+ decimal_exponent += subtract_decimal_exponent;
+#endif
+ *address_of_string_pointer = p;
number_of_digits_available =
number_of_digits_before_decimal + number_of_digits_after_decimal;
}
else
{
- int count; /* Number of useful digits left to scan. */
+ int count; /* Number of useful digits left to scan. */
+ LITTLENUM_TYPE *temporary_binary_low = NULL;
+ LITTLENUM_TYPE *power_binary_low = NULL;
LITTLENUM_TYPE *digits_binary_low;
unsigned int precision;
unsigned int maximum_useful_digits;
precision = (address_of_generic_floating_point_number->high
- address_of_generic_floating_point_number->low
- + 1); /* Number of destination littlenums. */
-
- /* Includes guard bits (two littlenums worth) */
-#if 0 /* The integer version below is very close, and it doesn't
- require floating point support (which is currently buggy on
- the Alpha). */
- maximum_useful_digits = (((double) (precision - 2))
- * ((double) (LITTLENUM_NUMBER_OF_BITS))
- / (LOG_TO_BASE_2_OF_10))
- + 2; /* 2 :: guard digits. */
-#else
- maximum_useful_digits = (((precision - 2))
- * ( (LITTLENUM_NUMBER_OF_BITS))
- * 1000000 / 3321928)
- + 2; /* 2 :: guard digits. */
-#endif
+ + 1); /* Number of destination littlenums. */
+
+ /* precision includes two littlenums worth of guard bits,
+ so this gives us 10 decimal guard digits here. */
+ maximum_useful_digits = (precision
+ * LITTLENUM_NUMBER_OF_BITS
+ * 1000000 / 3321928
+ + 1); /* round up. */
if (number_of_digits_available > maximum_useful_digits)
{
- (long) number_of_digits_to_use);
more_than_enough_bits_for_digits
- = ((((double) number_of_digits_to_use) * LOG_TO_BASE_2_OF_10) + 1);
+ = (number_of_digits_to_use * 3321928 / 1000000 + 1);
more_than_enough_littlenums_for_digits
= (more_than_enough_bits_for_digits
* sizeof (LITTLENUM_TYPE);
digits_binary_low = (LITTLENUM_TYPE *)
- alloca (size_of_digits_in_chars);
+ xmalloc (size_of_digits_in_chars);
memset ((char *) digits_binary_low, '\0', size_of_digits_in_chars);
- /* Digits_binary_low[] is allocated and zeroed. */
+ /* Digits_binary_low[] is allocated and zeroed. */
/*
* Parse the decimal digits as if * digits_low was in the units position.
for (p = first_digit, count = number_of_digits_to_use; count; p++, --count)
{
c = *p;
- if (isdigit (c))
+ if (ISDIGIT (c))
{
/*
* Multiply by 10. Assume can never overflow.
* We have a GROSS internal error.
* This should never happen.
*/
- as_fatal ("failed sanity check.");
+ as_fatal (_("failed sanity check"));
}
}
else
{
- ++count; /* '.' doesn't alter digits used count. */
+ ++count; /* '.' doesn't alter digits used count. */
}
}
-
/*
* Digits_binary_low[] properly encodes the value of the digits.
* Forget about any high-order littlenums that are 0.
{
/*
- * Compute the mantssa (& exponent) of the power of 10.
- * If sucessful, then multiply the power of 10 by the digits
+ * Compute the mantissa (& exponent) of the power of 10.
+ * If successful, then multiply the power of 10 by the digits
* giving return_binary_mantissa and return_binary_exponent.
*/
- LITTLENUM_TYPE *power_binary_low;
int decimal_exponent_is_negative;
- /* This refers to the "-56" in "12.34E-56". */
+ /* This refers to the "-56" in "12.34E-56". */
/* FALSE: decimal_exponent is positive (or 0) */
/* TRUE: decimal_exponent is negative */
FLONUM_TYPE temporary_flonum;
- LITTLENUM_TYPE *temporary_binary_low;
unsigned int size_of_power_in_littlenums;
unsigned int size_of_power_in_chars;
size_of_power_in_littlenums = precision;
- /* Precision has a built-in fudge factor so we get a few guard bits. */
+ /* Precision has a built-in fudge factor so we get a few guard bits. */
decimal_exponent_is_negative = decimal_exponent < 0;
if (decimal_exponent_is_negative)
decimal_exponent = -decimal_exponent;
}
- /* From now on: the decimal exponent is > 0. Its sign is seperate. */
+ /* From now on: the decimal exponent is > 0. Its sign is separate. */
size_of_power_in_chars = size_of_power_in_littlenums
* sizeof (LITTLENUM_TYPE) + 2;
- power_binary_low = (LITTLENUM_TYPE *) alloca (size_of_power_in_chars);
- temporary_binary_low = (LITTLENUM_TYPE *) alloca (size_of_power_in_chars);
+ power_binary_low = (LITTLENUM_TYPE *) xmalloc (size_of_power_in_chars);
+ temporary_binary_low = (LITTLENUM_TYPE *) xmalloc (size_of_power_in_chars);
+
memset ((char *) power_binary_low, '\0', size_of_power_in_chars);
*power_binary_low = 1;
power_of_10_flonum.exponent = 0;
int place_number_limit;
/* Any 10^(2^n) whose "n" exceeds this */
/* value will fall off the end of */
- /* flonum_XXXX_powers_of_ten[]. */
+ /* flonum_XXXX_powers_of_ten[]. */
int place_number;
const FLONUM_TYPE *multiplicand; /* -> 10^(2^n) */
? flonum_negative_powers_of_ten
: flonum_positive_powers_of_ten);
- for (place_number = 1;/* Place value of this bit of exponent. */
- decimal_exponent;/* Quit when no more 1 bits in exponent. */
+ for (place_number = 1;/* Place value of this bit of exponent. */
+ decimal_exponent;/* Quit when no more 1 bits in exponent. */
decimal_exponent >>= 1, place_number++)
{
if (decimal_exponent & 1)
if (place_number > place_number_limit)
{
/* The decimal exponent has a magnitude so great
- that our tables can't help us fragment it.
- Although this routine is in error because it
- can't imagine a number that big, signal an
- error as if it is the user's fault for
- presenting such a big number. */
+ that our tables can't help us fragment it.
+ Although this routine is in error because it
+ can't imagine a number that big, signal an
+ error as if it is the user's fault for
+ presenting such a big number. */
return_value = ERROR_EXPONENT_OVERFLOW;
/* quit out of loop gracefully */
decimal_exponent = 0;
flonum_print (&power_of_10_flonum);
(void) putchar ('\n');
+#endif
+#ifdef TRACE
+ printf ("multiplier:\n");
+ flonum_print (multiplicand + place_number);
+ (void) putchar ('\n');
#endif
flonum_multip (multiplicand + place_number,
&power_of_10_flonum, &temporary_flonum);
+#ifdef TRACE
+ printf ("after multiply:\n");
+ flonum_print (&temporary_flonum);
+ (void) putchar ('\n');
+#endif
flonum_copy (&temporary_flonum, &power_of_10_flonum);
+#ifdef TRACE
+ printf ("after copy:\n");
+ flonum_print (&power_of_10_flonum);
+ (void) putchar ('\n');
+#endif
} /* If this bit of decimal_exponent was computable.*/
- } /* If this bit of decimal_exponent was set. */
+ } /* If this bit of decimal_exponent was set. */
} /* For each bit of binary representation of exponent */
#ifdef TRACE
- printf (" after computing power_of_10_flonum: ");
+ printf ("after computing power_of_10_flonum:\n");
flonum_print (&power_of_10_flonum);
(void) putchar ('\n');
#endif
}
-
}
/*
*/
flonum_multip (&power_of_10_flonum, &digits_flonum, address_of_generic_floating_point_number);
- /* Assert sign of the number we made is '+'. */
+ /* Assert sign of the number we made is '+'. */
address_of_generic_floating_point_number->sign = digits_sign_char;
+ free (temporary_binary_low);
+ free (power_binary_low);
+ free (digits_binary_low);
}
return return_value;
}
+#ifdef TRACE
+static void
+flonum_print (f)
+ const FLONUM_TYPE *f;
+{
+ LITTLENUM_TYPE *lp;
+ char littlenum_format[10];
+ sprintf (littlenum_format, " %%0%dx", sizeof (LITTLENUM_TYPE) * 2);
+#define print_littlenum(LP) (printf (littlenum_format, LP))
+ printf ("flonum @%p %c e%ld", f, f->sign, f->exponent);
+ if (f->low < f->high)
+ for (lp = f->high; lp >= f->low; lp--)
+ print_littlenum (*lp);
+ else
+ for (lp = f->low; lp <= f->high; lp++)
+ print_littlenum (*lp);
+ printf ("\n");
+ fflush (stdout);
+}
+#endif
+
/* end of atof_generic.c */