/* 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 * $ (hexadecimal) * */ 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; }