mirror of
https://github.com/gbdev/rgbds.git
synced 2025-11-20 18:22:07 +00:00
Factor out a single parseNumber utility function (#1839)
This commit is contained in:
@@ -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);
|
||||
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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)) {
|
||||
|
||||
Reference in New Issue
Block a user