cfconv.c

来自「开放源码的编译器open watcom 1.6.0版的源代码」· C语言 代码 · 共 590 行 · 第 1/2 页

C
590
字号
/****************************************************************************
*
*                            Open Watcom Project
*
*    Portions Copyright (c) 1983-2002 Sybase, Inc. All Rights Reserved.
*
*  ========================================================================
*
*    This file contains Original Code and/or Modifications of Original
*    Code as defined in and that are subject to the Sybase Open Watcom
*    Public License version 1.0 (the 'License'). You may not use this file
*    except in compliance with the License. BY USING THIS FILE YOU AGREE TO
*    ALL TERMS AND CONDITIONS OF THE LICENSE. A copy of the License is
*    provided with the Original Code and Modifications, and is also
*    available at www.sybase.com/developer/opensource.
*
*    The Original Code and all software distributed under the License are
*    distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
*    EXPRESS OR IMPLIED, AND SYBASE AND ALL CONTRIBUTORS HEREBY DISCLAIM
*    ALL SUCH WARRANTIES, INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF
*    MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR
*    NON-INFRINGEMENT. Please see the License for the specific language
*    governing rights and limitations under the License.
*
*  ========================================================================
*
* Description:  WHEN YOU FIGURE OUT WHAT THIS FILE DOES, PLEASE
*               DESCRIBE IT HERE!
*
****************************************************************************/


#include <string.h>
#include <stddef.h>
#include "watcom.h"
#include "cfloat.h"
#include "machine.h"
#include "i64.h"

#define NULLCHAR        '\0'

extern  unsigned_32     U32ModDiv(unsigned_32*,unsigned_32);

#define _IsDigit( ch ) ( ch >= '0' && ch <= '9' )

extern  signed_64       CFGetDec64( char *bstart ) {
/**************************************************/

    signed_64   number;
    signed_64   ten;
    signed_64   temp;

    I32ToI64( 0, &number );
    I32ToI64( 10, &ten );
    while( _IsDigit( *bstart ) ) {
        U64Mul( &number, &ten, &number );
        I32ToI64( *bstart++ - '0', &temp );
        U64Add( &number, &temp, &number );
    }
    return( number );
}

extern  signed_32       CFGetDec32( char *bstart ) {
/**************************************************/

    signed_32   number;

    number = 0;
    while( _IsDigit( *bstart ) ) {
        number = number * 10 + *bstart++ - '0';
    }
    return( number );
}

static  signed_16       CFGetDec16( char *bstart ) {
/**************************************************/

    signed_16   number;

    number = 0;
    while( _IsDigit( *bstart ) ) {
        number = number * 10 + *bstart++ - '0';
    }
    return( number );
}

extern  char    *CFCnvFS( cfloat *f, char *buffer, int maxlen ) {
/***************************************************************/

    int         len;

    len = f->len - 1;
    if( len + 5 + I16DIGITS > maxlen ) {
        len = maxlen - 5 - I16DIGITS;
    }
    if( f->sign == -1 ) {
        *buffer++ = '-';
    }
    *buffer++ = f->mant[0];
    *buffer++ = '.';                            /* don't forget decimal point!*/
    memcpy( buffer, &f->mant[1], len );         /* copy mantissa*/
    buffer += len;
    *buffer++ = 'E';
    len = f->exp - 1;
    if( len < 0 ) {
        *buffer++ = '-';
        len = -len;
    }
    buffer[ 2 ] = len % 10 + '0';
    len /= 10;
    buffer[ 1 ] = len % 10 + '0';
    len /= 10;
    buffer[ 0 ] = len + '0';
    buffer[ 3 ] = NULLCHAR;
    buffer += 3;
    return( buffer );
}

static  void            DoConvert( cfloat *number, char *bstart ) {
/*****************************************************************/


    int         len;
    char        *fptr;
    int         sgn;
    int         expon;

    for(;;) {
        if( *bstart != ' ' ) break;
        bstart++;
    }
    sgn = 1;
    if( *bstart  == '-' ) {
        sgn = -1;
        bstart++;
    } else if( *bstart == '+' ) {
        bstart++;
    }
    expon = 0;
    len = 0;
    fptr = number->mant;
    if( _IsDigit( *bstart ) ) {
        for(;;) {                /* scan before decimal point*/
            *fptr++ = *bstart++;
            len++;
            expon++;
            if( !_IsDigit( *bstart ) ) break;
        }
        if( *bstart == '.' ) {
            bstart++;
            for(;;) {            /* scan after decimal point*/
                if( !_IsDigit( *bstart ) ) break;
                *fptr++ = *bstart++;
                len++;
            }
        }
    } else {
        if( *bstart != '.' ) return;
        ++bstart;
        if( !_IsDigit( *bstart ) ) return;
        for(;;) {                /* scan after decimal point*/
            *fptr++ = *bstart++;
            len++;
            if( !_IsDigit( *bstart ) ) break;
        }
    }
    if( *bstart == 'E' || *bstart == 'e' ) {
        if( *++bstart == '-' ) {
            expon -= CFGetDec16( ++bstart );
        } else {
            if( *bstart == '+' ) {
                bstart++;
            }
            expon += CFGetDec16( bstart );
        }
    }
    number->sign = sgn;
    number->len = len;             /* fill in length*/
    number->exp = expon;
    CFClean( number );
}


extern  cfloat  *CFCnvSF( char *bstart, char *bend ) {
/****************************************************/

/* Syntax accepted by this converter:*/
/**/
/* { at least 0 blanks }  < - | + >*/
/*               { at least 1 digit } < . { at least 0 digits } >*/
/*       or      . { at least 1 digit }*/
/*               < E | e < - | + > { at least 1 digit } >*/

    cfloat      *number;
    char        saved;

    saved = *bend;
    if( saved != NULLCHAR ) {
        *bend = NULLCHAR;                  /* KLUGE!!!*/
    }
    number = CFAlloc( bend - bstart );
    DoConvert( number, bstart );
    if( saved != NULLCHAR ) {
        *bend = saved;                     /* un-KLUGE*/
    }
    return( number );
}

extern  cfloat  *CFCopy( cfloat *old ) {
/***************************************/

    cfloat      *new;

    new = CFAlloc( old->len );
    memcpy( new, old, offsetof( cfloat, mant ) + old->len + 1 );
    return( new );
}

extern  cfloat  *CFTrunc( cfloat *f ) {
/*************************************/

    cfloat      *new;
    int         len;

    len = f->exp;
    if( len <= 0 ) return( CFAlloc( 1 ) );
    new = CFCopy( f );
    if( new->len <= len ) return( new );
    new->len = len;
    new->mant[ len ] = NULLCHAR;
    return( new );
}

extern  cfloat  *CFRound( cfloat *f ) {
/*************************************/

    cfloat      *trim;
    cfloat      *addto;
    cfloat      *new;
    int         len;

    len = f->exp;
    if( len < 0 ) return( CFAlloc( 1 ) );
    if( f->len <= len ) return( CFCopy( f ) );
    trim = CFTrunc( f );
    if( f->mant[ len ] < '5' ) return( trim );
    if( f->sign < 0 && f->len == ( len + 1 ) ) return( trim );
    addto = CFAlloc( 1 );
    addto->sign = f->sign;
    addto->mant[0] = '1';
    new = CFAdd( trim, addto );
    CFFree( trim );
    CFFree( addto );
    return( new );
}

static  cfloat  *CFCnvLongToF( signed_32 data, cf_bool is_signed ) {
/******************************************************************/

    cfloat              *new;
    int                 len;
    signed_8            sign;
    char                *digit;
    unsigned_32         dividend;
    char                mant[I32DIGITS+1];

    if( data == 0 ) return( CFAlloc( 0 ) );
    if( is_signed != CF_FALSE && -data == data ) {
        /* Aha! It's  -MaxNegI32 */
        new = CFCopy( (cfloat *)&MaxNegI32 );
        new->sign = -1;
        return( new );
    }
    sign = 1;
    if( data < 0 && is_signed ) {
        data = -data;
        sign = -1;
    }
    len = 0;
    digit = &mant[ I32DIGITS ];
    *digit = NULLCHAR;
    dividend = data;
    while( dividend != 0 ) {
        *--digit = U32ModDiv( &dividend, 10 ) + '0';
        ++len;
    }
    if( len > I16DIGITS ) {
        new = CFAlloc( I32DIGITS );
    } else {
        new = CFAlloc( I16DIGITS );
    }
    memcpy( new->mant, digit, len + 1 );
    new->sign = sign;
    new->exp = len;
    new->len = len;

⌨️ 快捷键说明

复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?