home *** CD-ROM | disk | FTP | other *** search
/ OpenStep 4.2J (Developer) / os42jdev.iso / NextDeveloper / Source / GNU / cctools / as / atof-generic.c < prev    next >
C/C++ Source or Header  |  1993-09-09  |  16KB  |  509 lines

  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 */
  509.