0
0
mirror of https://github.com/netwide-assembler/nasm.git synced 2025-11-08 23:27:15 -05:00
Files
nasm/nasmlib/readnum.c
H. Peter Anvin (Intel) f4f7d18c06 error: factor out error functions into separate files
Tidy up a *lot* of code by moving error functions into separate source
files. This required breaking out some of the assembler-only files
into a separate library, as it conflicts with stubs in the
disassembler.

Signed-off-by: H. Peter Anvin (Intel) <hpa@zytor.com>
2025-11-07 14:42:33 -08:00

126 lines
2.8 KiB
C

/* SPDX-License-Identifier: BSD-2-Clause */
/* Copyright 1996-2025 The NASM Authors - All Rights Reserved */
/*
* nasmlib.c library routines for the Netwide Assembler
*/
#include "compiler.h"
#include "nctype.h"
#include "nasmlib.h"
#include "nasm.h"
#include "error.h"
#define lib_isnumchar(c) (nasm_isalnum(c) || (c) == '$' || (c) == '_')
int64_t readnum(const char *str, bool *error)
{
const char *r = str, *q;
int32_t pradix, sradix, radix;
int plen, slen, len;
uint64_t result, checklimit;
int digit, last;
bool warn = false;
int sign = 1;
if (error)
*error = true;
while (nasm_isspace(*r))
r++; /* find start of number */
/*
* If the number came from make_tok_num (as a result of an %assign), it
* might have a '-' built into it (rather than in a preceding token).
*/
if (*r == '-') {
r++;
sign = -1;
}
q = r;
while (lib_isnumchar(*q))
q++; /* find end of number */
len = q-r;
if (!len) {
/* Not numeric */
return 0;
}
/*
* Handle radix formats:
*
* 0<radix-letter><string>
* $<string> (hexadecimal)
* <string><radix-letter>
*/
pradix = sradix = 0;
plen = slen = 0;
if (len > 2 && *r == '0' && (pradix = radix_letter(r[1])) != 0) {
plen = 2;
} else if (len > 1 && *r == '$' && globl.dollarhex) {
/* Warning here would probably duplicate warnings */
pradix = 16, plen = 1;
}
if (len > 1 && (sradix = radix_letter(q[-1])) != 0)
slen = 1;
if (pradix > sradix) {
radix = pradix;
r += plen;
} else if (sradix > pradix) {
radix = sradix;
q -= slen;
} else {
/* Either decimal, or invalid -- if invalid, we'll trip up
further down. */
radix = 10;
}
/*
* `checklimit' must be 2**64 / radix. We can't do that in
* 64-bit arithmetic, which we're (probably) using, so we
* cheat: since we know that all radices we use are even, we
* can divide 2**63 by radix/2 instead.
*/
checklimit = UINT64_C(0x8000000000000000) / (radix >> 1);
/*
* Calculate the highest allowable value for the last digit of a
* 64-bit constant... in radix 10, it is 6, otherwise it is 0
*/
last = (radix == 10 ? 6 : 0);
result = 0;
while (*r && r < q) {
if (*r != '_') {
if (*r < '0' || (*r > '9' && *r < 'A')
|| (digit = numvalue(*r)) >= radix) {
return 0;
}
if (result > checklimit ||
(result == checklimit && digit >= last)) {
warn = true;
}
result = radix * result + digit;
}
r++;
}
if (warn) {
nasm_warn(WARN_NUMBER_OVERFLOW,
"numeric constant %s does not fit in 64 bits",
str);
}
if (error)
*error = false;
return result * sign;
}