⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 float.c

📁 nasm早期的源代码,比较简单是学习汇编和编译原理的好例子
💻 C
📖 第 1 页 / 共 2 页
字号:
        } else {
            error(ERR_PANIC, "float_round() can't handle rc=%i", rc);
        }
    } else {
        error(ERR_PANIC, "float_round() can't handle sign=%i", sign);
    }
    return false;
}

static int hexval(char c)
{
    if (c >= '0' && c <= '9')
        return c - '0';
    else if (c >= 'a' && c <= 'f')
        return c - 'a' + 10;
    else
        return c - 'A' + 10;
}

static bool ieee_flconvert_hex(const char *string, uint16_t * mant,
                               int32_t * exponent)
{
    static const int log2tbl[16] =
        { -1, 0, 1, 1, 2, 2, 2, 2, 3, 3, 3, 3, 3, 3, 3, 3 };
    uint16_t mult[MANT_WORDS + 1], *mp;
    int ms;
    int32_t twopwr;
    int seendot, seendigit;
    unsigned char c;

    twopwr = 0;
    seendot = seendigit = 0;
    ms = 0;
    mp = NULL;

    memset(mult, 0, sizeof mult);

    while ((c = *string++) != '\0') {
        if (c == '.') {
            if (!seendot)
                seendot = true;
            else {
                error(ERR_NONFATAL,
                      "too many periods in floating-point constant");
                return false;
            }
        } else if (isxdigit(c)) {
            int v = hexval(c);

            if (!seendigit && v) {
                int l = log2tbl[v];

                seendigit = 1;
                mp = mult;
                ms = 15 - l;

                twopwr = seendot ? twopwr - 4 + l : l - 3;
            }

            if (seendigit) {
                if (ms <= 0) {
                    *mp |= v >> -ms;
                    mp++;
                    if (mp > &mult[MANT_WORDS])
                        mp = &mult[MANT_WORDS]; /* Guard slot */
                    ms += 16;
                }
                *mp |= v << ms;
                ms -= 4;

                if (!seendot)
                    twopwr += 4;
            } else {
                if (seendot)
                    twopwr -= 4;
            }
        } else if (c == 'p' || c == 'P') {
            twopwr += atoi(string);
            break;
        } else {
            error(ERR_NONFATAL,
                  "floating-point constant: `%c' is invalid character", c);
            return false;
        }
    }

    if (!seendigit) {
        memset(mant, 0, 2 * MANT_WORDS);        /* Zero */
        *exponent = 0;
    } else {
        memcpy(mant, mult, 2 * MANT_WORDS);
        *exponent = twopwr;
    }

    return true;
}

/*
 * Shift a mantissa to the right by i bits.
 */
static void ieee_shr(uint16_t * mant, int i)
{
    uint16_t n, m;
    int j = 0;
    int sr, sl, offs;

    sr = i%16; sl = 16-sr;
    offs = i/16;

    if (sr == 0) {
	if (offs)
	    for (j = MANT_WORDS-1; j >= offs; j--)
		mant[j] = mant[j-offs];
    } else {
	n = mant[MANT_WORDS-1-offs] >> sr;
	for (j = MANT_WORDS-1; j > offs; j--) {
	    m = mant[j-offs-1];
	    mant[j] = (m << sl) | n;
	    n = m >> sr;
	}
	mant[j--] = n;
    }
    while (j >= 0)
	mant[j--] = 0;
}

#if defined(__i386__) || defined(__x86_64__)
#define put(a,b) (*(uint16_t *)(a) = (b))
#else
#define put(a,b) (((a)[0] = (b)), ((a)[1] = (b) >> 8))
#endif

/* Set a bit, using *bigendian* bit numbering (0 = MSB) */
static void set_bit(uint16_t *mant, int bit)
{
    mant[bit >> 4] |= 1 << (~bit & 15);
}

/* Test a single bit */
static int test_bit(const uint16_t *mant, int bit)
{
    return (mant[bit >> 4] >> (~bit & 15)) & 1;
}

/* Report if the mantissa value is all zero */
static bool is_zero(const uint16_t *mant)
{
    int i;

    for (i = 0; i < MANT_WORDS; i++)
	if (mant[i])
	    return false;

    return true;
}

/* Produce standard IEEE formats, with implicit or explicit integer
   bit; this makes the following assumptions:

   - the sign bit is the MSB, followed by the exponent,
     followed by the integer bit if present.
   - the sign bit plus exponent fit in 16 bits.
   - the exponent bias is 2^(n-1)-1 for an n-bit exponent */

struct ieee_format {
    int words;
    int mantissa;               /* Fractional bits in the mantissa */
    int explicit;		/* Explicit integer */
    int exponent;               /* Bits in the exponent */
};

/*
 * The 16- and 128-bit formats are expected to be in IEEE 754r.
 * AMD SSE5 uses the 16-bit format.
 *
 * The 32- and 64-bit formats are the original IEEE 754 formats.
 *
 * The 80-bit format is x87-specific, but widely used.
 */
static const struct ieee_format ieee_16  = { 1,  10, 0,  5 };
static const struct ieee_format ieee_32  = { 2,  23, 0,  8 };
static const struct ieee_format ieee_64  = { 4,  52, 0, 11 };
static const struct ieee_format ieee_80  = { 5,  63, 1, 15 };
static const struct ieee_format ieee_128 = { 8, 112, 0, 15 };

/* Types of values we can generate */
enum floats {
    FL_ZERO,
    FL_DENORMAL,
    FL_NORMAL,
    FL_INFINITY,
    FL_QNAN,
    FL_SNAN
};

static int to_float(const char *str, int sign, uint8_t * result,
                    const struct ieee_format *fmt)
{
    uint16_t mant[MANT_WORDS], *mp;
    int32_t exponent = 0;
    int32_t expmax = 1 << (fmt->exponent - 1);
    uint16_t one_mask = 0x8000 >> ((fmt->exponent+fmt->explicit) % 16);
    int one_pos = (fmt->exponent+fmt->explicit)/16;
    int i;
    int shift;
    enum floats type;
    bool ok;

    sign = (sign < 0 ? 0x8000 : 0);

    if (str[0] == '_') {
	/* Special tokens */

        switch (str[2]) {
        case 'n':              /* __nan__ */
        case 'N':
        case 'q':              /* __qnan__ */
        case 'Q':
	    type = FL_QNAN;
            break;
        case 's':              /* __snan__ */
        case 'S':
	    type = FL_SNAN;
            break;
        case 'i':              /* __infinity__ */
        case 'I':
	    type = FL_INFINITY;
            break;
	default:
	    error(ERR_NONFATAL,
		  "internal error: unknown FP constant token `%s'\n", str);
	    type = FL_QNAN;
	    break;
        }
    } else {
        if (str[0] == '0' && (str[1] == 'x' || str[1] == 'X'))
            ok = ieee_flconvert_hex(str + 2, mant, &exponent);
        else
            ok = ieee_flconvert(str, mant, &exponent);

	if (!ok) {
	    type = FL_QNAN;
	} else if (mant[0] & 0x8000) {
            /*
             * Non-zero.
             */
            exponent--;
            if (exponent >= 2 - expmax && exponent <= expmax) {
		type = FL_NORMAL;
            } else if (exponent < 2 - expmax &&
                       exponent >= 2 - expmax - fmt->mantissa) {
		type = FL_DENORMAL;
            } else if (exponent > 0) {
		if (pass0 == 1)
		    error(ERR_WARNING|ERR_WARN_FL_OVERFLOW,
			  "overflow in floating-point constant");
		type = FL_INFINITY;
	    } else {
		/* underflow */
		if (pass0 == 1)
		    error(ERR_WARNING|ERR_WARN_FL_UNDERFLOW,
			  "underflow in floating-point constant");
		type = FL_ZERO;
	    }
	} else {
	    /* Zero */
	    type = FL_ZERO;
	}
    }

    switch (type) {
    case FL_ZERO:
    zero:
	memset(mant, 0, sizeof mant);
	break;

    case FL_DENORMAL:
    {
	shift = -(exponent + expmax - 2 - fmt->exponent)
	    + fmt->explicit;
	ieee_shr(mant, shift);
	ieee_round(sign, mant, fmt->words);
	if (mant[one_pos] & one_mask) {
	    /* One's position is set, we rounded up into normal range */
	    exponent = 1;
	    if (!fmt->explicit)
		mant[one_pos] &= ~one_mask;	/* remove explicit one */
	    mant[0] |= exponent << (15 - fmt->exponent);
	} else {
	    if (daz || is_zero(mant)) {
		/* Flush denormals to zero */
		if (pass0 == 1)
		    error(ERR_WARNING|ERR_WARN_FL_UNDERFLOW,
			  "underflow in floating-point constant");
		goto zero;
	    } else {
		if (pass0 == 1)
		    error(ERR_WARNING|ERR_WARN_FL_DENORM,
			  "denormal floating-point constant");
	    }
	}
	break;
    }

    case FL_NORMAL:
	exponent += expmax - 1;
	ieee_shr(mant, fmt->exponent+fmt->explicit);
	ieee_round(sign, mant, fmt->words);
	/* did we scale up by one? */
	if (test_bit(mant, fmt->exponent+fmt->explicit-1)) {
	    ieee_shr(mant, 1);
	    exponent++;
	    if (exponent >= (expmax << 1)-1) {
		if (pass0 == 1)
		    error(ERR_WARNING|ERR_WARN_FL_OVERFLOW,
			  "overflow in floating-point constant");
		type = FL_INFINITY;
		goto overflow;
	    }
	}
	
	if (!fmt->explicit)
	    mant[one_pos] &= ~one_mask;	/* remove explicit one */
	mant[0] |= exponent << (15 - fmt->exponent);
	break;

    case FL_INFINITY:
    case FL_QNAN:
    case FL_SNAN:
    overflow:
	memset(mant, 0, sizeof mant);
	mant[0] = ((1 << fmt->exponent)-1) << (15 - fmt->exponent);
	if (fmt->explicit)
	    mant[one_pos] |= one_mask;
	if (type == FL_QNAN)
	    set_bit(mant, fmt->exponent+fmt->explicit+1);
	else if (type == FL_SNAN)
	    set_bit(mant, fmt->exponent+fmt->explicit+fmt->mantissa);
	break;
    }

    mant[0] |= sign;

    for (mp = &mant[fmt->words], i = 0; i < fmt->words; i++) {
        uint16_t m = *--mp;
        put(result, m);
        result += 2;
    }

    return 1;                   /* success */
}

int float_const(const char *number, int32_t sign, uint8_t * result,
                int bytes, efunc err)
{
    error = err;

    switch (bytes) {
    case 2:
        return to_float(number, sign, result, &ieee_16);
    case 4:
        return to_float(number, sign, result, &ieee_32);
    case 8:
        return to_float(number, sign, result, &ieee_64);
    case 10:
        return to_float(number, sign, result, &ieee_80);
    case 16:
        return to_float(number, sign, result, &ieee_128);
    default:
        error(ERR_PANIC, "strange value %d passed to float_const", bytes);
        return 0;
    }
}

/* Set floating-point options */
int float_option(const char *option)
{
    if (!nasm_stricmp(option, "daz")) {
	daz = true;
	return 0;
    } else if (!nasm_stricmp(option, "nodaz")) {
	daz = false;
	return 0;
    } else if (!nasm_stricmp(option, "near")) {
	rc = FLOAT_RC_NEAR;
	return 0;
    } else if (!nasm_stricmp(option, "down")) {
	rc = FLOAT_RC_DOWN;
	return 0;
    } else if (!nasm_stricmp(option, "up")) {
	rc = FLOAT_RC_UP;
	return 0;
    } else if (!nasm_stricmp(option, "zero")) {
	rc = FLOAT_RC_ZERO;
	return 0;
    } else if (!nasm_stricmp(option, "default")) {
	rc = FLOAT_RC_NEAR;
	daz = false;
	return 0;
    } else {
	return -1;		/* Unknown option */
    }
}

⌨️ 快捷键说明

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