0
0
mirror of https://github.com/netwide-assembler/nasm.git synced 2025-10-10 00:25:06 -04:00
Files
nasm/nasmlib/readnum.c
H. Peter Anvin a8bcdb641b Warnings: disaggregate from source and tidy up documentation
The idea of putting the warnings in the source code was a nice one,
really, but it ended up being a nightmare from the perspective of
build dependencies. Disaggregate them, and tweak the documentation for
easier reading.

Signed-off-by: H. Peter Anvin (Intel) <hpa@zytor.com>
2025-10-04 13:46:39 -07:00

133 lines
3.0 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 "error.h"
#include "nasm.h" /* For globl.dollarhex */
#define lib_isnumchar(c) (nasm_isalnum(c) || (c) == '$' || (c) == '_')
void warn_dollar_hex(void)
{
nasm_warn(WARN_NUMBER_DEPRECATED_HEX,
"$ prefix for hexadecimal is deprecated");
}
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;
}