Annotation of GNUtools/cctools/as/atof-generic.c, revision 1.1

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

unix.superglobalmegacorp.com

This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.