Factor out a single parseNumber utility function (#1839)

This commit is contained in:
Rangi
2025-09-22 15:15:24 -04:00
committed by GitHub
parent c8d22d8744
commit 634fd853d1
18 changed files with 304 additions and 337 deletions

View File

@@ -106,10 +106,6 @@ static yy::parser::symbol_type parseDecNumber(int c) {
return yy::parser::make_number(number);
}
static bool isBinDigit(int c) {
return c == '0' || c == '1';
}
static yy::parser::symbol_type parseBinNumber(char const *prefix) {
LexerStackEntry &context = lexerStack.back();
int c = context.file.sgetc();
@@ -167,7 +163,7 @@ static yy::parser::symbol_type parseHexNumber(char const *prefix) {
return yy::parser::make_number(number);
}
static yy::parser::symbol_type parseNumber(int c) {
static yy::parser::symbol_type parseAnyNumber(int c) {
LexerStackEntry &context = lexerStack.back();
if (c == '0') {
switch (context.file.sgetc()) {
@@ -265,7 +261,7 @@ yy::parser::symbol_type yylex() {
} else if (c == '&') {
return parseOctNumber("'&'");
} else if (isDigit(c)) {
return parseNumber(c);
return parseAnyNumber(c);
} else if (isLetter(c)) {
std::string keyword = readKeyword(c);

View File

@@ -4,6 +4,7 @@
#include <inttypes.h>
#include <limits.h>
#include <optional>
#include <stdarg.h>
#include <stdint.h>
#include <stdio.h>
@@ -265,21 +266,18 @@ static void parseScrambleSpec(char *spec) {
uint16_t limit = search->second.second;
if (regionSize) {
char *endptr;
unsigned long value = strtoul(regionSize, &endptr, 0);
if (*endptr != '\0') {
char const *ptr = regionSize + skipBlankSpace(regionSize);
if (std::optional<uint64_t> value = parseWholeNumber(ptr); !value) {
fatal("Invalid region size limit \"%s\" for option '-S'", regionSize);
}
if (value > limit) {
} else if (*value > limit) {
fatal(
"%s region size for option '-S' must be between 0 and %" PRIu16,
search->first.c_str(),
limit
);
} else {
limit = *value;
}
limit = value;
} else if (search->second.first != &options.scrambleWRAMX) {
// Only WRAMX limit can be implied, since ROMX and SRAM size may vary.
fatal("Missing %s region size limit for option '-S'", search->first.c_str());
@@ -353,21 +351,16 @@ int main(int argc, char *argv[]) {
options.outputFileName = musl_optarg;
break;
case 'p': {
char *endptr;
unsigned long value = strtoul(musl_optarg, &endptr, 0);
if (musl_optarg[0] == '\0' || *endptr != '\0') {
case 'p':
if (std::optional<uint64_t> value = parseWholeNumber(musl_optarg); !value) {
fatal("Invalid argument for option '-p'");
}
if (value > 0xFF) {
} else if (*value > 0xFF) {
fatal("Argument for option '-p' must be between 0 and 0xFF");
} else {
options.padValue = *value;
options.hasPadValue = true;
}
options.padValue = value;
options.hasPadValue = true;
break;
}
case 'S':
parseScrambleSpec(musl_optarg);

View File

@@ -2,9 +2,9 @@
#include "link/sdas_obj.hpp"
#include <ctype.h>
#include <inttypes.h>
#include <memory>
#include <optional>
#include <stdint.h>
#include <stdio.h>
#include <string.h>
@@ -15,18 +15,13 @@
#include "helpers.hpp" // assume, literal_strlen
#include "linkdefs.hpp"
#include "platform.hpp"
#include "util.hpp" // parseWholeNumber
#include "link/fstack.hpp"
#include "link/section.hpp"
#include "link/symbol.hpp"
#include "link/warning.hpp"
enum NumberType {
HEX = 16, // X
DEC = 10, // D
OCT = 8, // Q
};
struct Location {
FileStackNode const *src;
uint32_t lineNo;
@@ -84,36 +79,26 @@ static int nextLine(std::vector<char> &lineBuf, Location &where, FILE *file) {
}
}
static uint32_t readNumber(char const *str, char const *&endptr, NumberType base) {
for (uint32_t res = 0;;) {
static char const *digits = "0123456789ABCDEF";
char const *ptr = strchr(digits, toupper(*str));
static uint64_t readNumber(Location const &where, char const *str, NumberBase base) {
std::optional<uint64_t> res = parseWholeNumber(str, base);
if (!ptr || ptr - digits >= base) {
endptr = str;
return res;
}
++str;
res = res * base + (ptr - digits);
}
}
static uint32_t parseNumber(Location const &where, char const *str, NumberType base) {
if (str[0] == '\0') {
fatalAt(where, "Expected number, got empty string");
}
char const *endptr;
uint32_t res = readNumber(str, endptr, base);
if (*endptr != '\0') {
if (!res) {
fatalAt(where, "Expected number, got \"%s\"", str);
}
return res;
return *res;
}
static uint8_t parseByte(Location const &where, char const *str, NumberType base) {
uint32_t num = parseNumber(where, str, base);
static uint32_t readInt(Location const &where, char const *str, NumberBase base) {
uint64_t num = readNumber(where, str, base);
if (num > UINT32_MAX) {
fatalAt(where, "\"%s\" is not an int", str);
}
return num;
}
static uint8_t readByte(Location const &where, char const *str, NumberBase base) {
uint64_t num = readNumber(where, str, base);
if (num > UINT8_MAX) {
fatalAt(where, "\"%s\" is not a byte", str);
@@ -184,18 +169,18 @@ void sdobj_ReadFile(FileStackNode const &src, FILE *file, std::vector<Symbol> &f
int lineType = nextLine(line, where, file);
// The first letter (thus, the line type) identifies the integer type
NumberType numberType;
NumberBase numberBase;
switch (lineType) {
case EOF:
fatalAt(where, "SDCC object only contains comments and empty lines");
case 'X':
numberType = HEX;
numberBase = BASE_16;
break;
case 'D':
numberType = DEC;
numberBase = BASE_10;
break;
case 'Q':
numberType = OCT;
numberBase = BASE_8;
break;
default:
fatalAt(
@@ -239,12 +224,12 @@ void sdobj_ReadFile(FileStackNode const &src, FILE *file, std::vector<Symbol> &f
// Expected format: "A areas S global symbols"
getToken(line.data(), "Empty 'H' line");
uint32_t expectedNbAreas = parseNumber(where, token, numberType);
uint32_t expectedNbAreas = readInt(where, token, numberBase);
expectToken("areas", 'H');
getToken(nullptr, "'H' line is too short");
uint32_t expectedNbSymbols = parseNumber(where, token, numberType);
uint32_t expectedNbSymbols = readInt(where, token, numberBase);
fileSymbols.reserve(expectedNbSymbols);
expectToken("global", 'H');
@@ -296,7 +281,7 @@ void sdobj_ReadFile(FileStackNode const &src, FILE *file, std::vector<Symbol> &f
getToken(nullptr, "'A' line is too short");
uint32_t tmp = parseNumber(where, token, numberType);
uint32_t tmp = readInt(where, token, numberBase);
if (tmp > UINT16_MAX) {
fatalAt(
@@ -310,7 +295,7 @@ void sdobj_ReadFile(FileStackNode const &src, FILE *file, std::vector<Symbol> &f
expectToken("flags", 'A');
getToken(nullptr, "'A' line is too short");
tmp = parseNumber(where, token, numberType);
tmp = readInt(where, token, numberBase);
if (tmp & (1 << AREA_PAGING)) {
fatalAt(where, "Paging is not supported");
}
@@ -329,7 +314,7 @@ void sdobj_ReadFile(FileStackNode const &src, FILE *file, std::vector<Symbol> &f
expectToken("addr", 'A');
getToken(nullptr, "'A' line is too short");
tmp = parseNumber(where, token, numberType);
tmp = readInt(where, token, numberBase);
curSection->org = tmp; // Truncation keeps the address portion only
curSection->bank = tmp >> 16;
@@ -386,7 +371,7 @@ void sdobj_ReadFile(FileStackNode const &src, FILE *file, std::vector<Symbol> &f
getToken(nullptr, "'S' line is too short");
if (int32_t value = parseNumber(where, &token[3], numberType); !fileSections.empty()) {
if (int32_t value = readInt(where, &token[3], numberBase); !fileSections.empty()) {
// Symbols in sections are labels; their value is an offset
Section *section = fileSections.back().section.get();
if (section->isAddressFixed) {
@@ -465,7 +450,7 @@ void sdobj_ReadFile(FileStackNode const &src, FILE *file, std::vector<Symbol> &f
data.clear();
for (token = strtok(line.data(), delim); token; token = strtok(nullptr, delim)) {
data.push_back(parseByte(where, token, numberType));
data.push_back(readByte(where, token, numberBase));
}
if (data.size() < addrSize) {
@@ -487,9 +472,9 @@ void sdobj_ReadFile(FileStackNode const &src, FILE *file, std::vector<Symbol> &f
uint16_t areaIdx;
getToken(nullptr, "'R' line is too short");
areaIdx = parseByte(where, token, numberType);
areaIdx = readByte(where, token, numberBase);
getToken(nullptr, "'R' line is too short");
areaIdx |= static_cast<uint16_t>(parseByte(where, token, numberType)) << 8;
areaIdx |= static_cast<uint16_t>(readByte(where, token, numberBase)) << 8;
if (areaIdx >= fileSections.size()) {
fatalAt(
where,
@@ -549,16 +534,16 @@ void sdobj_ReadFile(FileStackNode const &src, FILE *file, std::vector<Symbol> &f
// appropriate RPN expression (depending on flags), plus an addition for the
// bytes being patched over.
while ((token = strtok(nullptr, delim)) != nullptr) {
uint16_t flags = parseByte(where, token, numberType);
uint16_t flags = readByte(where, token, numberBase);
if ((flags & 0xF0) == 0xF0) {
getToken(nullptr, "Incomplete relocation");
flags = (flags & 0x0F)
| static_cast<uint16_t>(parseByte(where, token, numberType)) << 4;
| static_cast<uint16_t>(readByte(where, token, numberBase)) << 4;
}
getToken(nullptr, "Incomplete relocation");
uint8_t offset = parseByte(where, token, numberType);
uint8_t offset = readByte(where, token, numberBase);
if (offset < addrSize) {
fatalAt(
@@ -578,10 +563,10 @@ void sdobj_ReadFile(FileStackNode const &src, FILE *file, std::vector<Symbol> &f
}
getToken(nullptr, "Incomplete relocation");
uint16_t idx = parseByte(where, token, numberType);
uint16_t idx = readByte(where, token, numberBase);
getToken(nullptr, "Incomplete relocation");
idx |= static_cast<uint16_t>(parseByte(where, token, numberType));
idx |= static_cast<uint16_t>(readByte(where, token, numberBase));
// Loudly fail on unknown flags
if (flags & (1 << RELOC_ZPAGE | 1 << RELOC_NPAGE)) {