Abbreviate RGBLINK errput that includes a src+lineNo

This commit is contained in:
Rangi42
2025-07-15 18:17:01 -04:00
parent ee29579d3e
commit 8bebab1db0
4 changed files with 164 additions and 225 deletions

View File

@@ -5,15 +5,19 @@
#include <stdint.h> #include <stdint.h>
#define warningAt(where, ...) warning(where.src, where.lineNo, __VA_ARGS__)
#define errorAt(where, ...) error(where.src, where.lineNo, __VA_ARGS__)
#define fatalAt(where, ...) fatal(where.src, where.lineNo, __VA_ARGS__)
struct FileStackNode; struct FileStackNode;
[[gnu::format(printf, 3, 4)]] [[gnu::format(printf, 3, 4)]]
void warning(FileStackNode const *where, uint32_t lineNo, char const *fmt, ...); void warning(FileStackNode const *src, uint32_t lineNo, char const *fmt, ...);
[[gnu::format(printf, 1, 2)]] [[gnu::format(printf, 1, 2)]]
void warning(char const *fmt, ...); void warning(char const *fmt, ...);
[[gnu::format(printf, 3, 4)]] [[gnu::format(printf, 3, 4)]]
void error(FileStackNode const *where, uint32_t lineNo, char const *fmt, ...); void error(FileStackNode const *src, uint32_t lineNo, char const *fmt, ...);
[[gnu::format(printf, 1, 2)]] [[gnu::format(printf, 1, 2)]]
void error(char const *fmt, ...); void error(char const *fmt, ...);
[[gnu::format(printf, 1, 2)]] [[gnu::format(printf, 1, 2)]]
@@ -22,7 +26,7 @@ void errorNoDump(char const *fmt, ...);
void argErr(char flag, char const *fmt, ...); void argErr(char flag, char const *fmt, ...);
[[gnu::format(printf, 3, 4), noreturn]] [[gnu::format(printf, 3, 4), noreturn]]
void fatal(FileStackNode const *where, uint32_t lineNo, char const *fmt, ...); void fatal(FileStackNode const *src, uint32_t lineNo, char const *fmt, ...);
[[gnu::format(printf, 1, 2), noreturn]] [[gnu::format(printf, 1, 2), noreturn]]
void fatal(char const *fmt, ...); void fatal(char const *fmt, ...);

View File

@@ -35,7 +35,7 @@ static bool isError = false;
static int32_t popRPN(Patch const &patch) { static int32_t popRPN(Patch const &patch) {
if (rpnStack.empty()) { if (rpnStack.empty()) {
fatal(patch.src, patch.lineNo, "Internal error, RPN stack empty"); fatalAt(patch, "Internal error, RPN stack empty");
} }
RPNStackEntry entry = rpnStack.front(); RPNStackEntry entry = rpnStack.front();
@@ -49,7 +49,7 @@ static int32_t popRPN(Patch const &patch) {
static uint32_t getRPNByte(uint8_t const *&expression, int32_t &size, Patch const &patch) { static uint32_t getRPNByte(uint8_t const *&expression, int32_t &size, Patch const &patch) {
if (!size--) { if (!size--) {
fatal(patch.src, patch.lineNo, "Internal error, RPN expression overread"); fatalAt(patch, "Internal error, RPN expression overread");
} }
return *expression++; return *expression++;
@@ -99,7 +99,7 @@ static int32_t computeRPNExpr(Patch const &patch, std::vector<Symbol> const &fil
value = popRPN(patch); value = popRPN(patch);
if (value == 0) { if (value == 0) {
if (!isError) { if (!isError) {
error(patch.src, patch.lineNo, "Division by 0"); errorAt(patch, "Division by 0");
isError = true; isError = true;
} }
popRPN(patch); popRPN(patch);
@@ -112,7 +112,7 @@ static int32_t computeRPNExpr(Patch const &patch, std::vector<Symbol> const &fil
value = popRPN(patch); value = popRPN(patch);
if (value == 0) { if (value == 0) {
if (!isError) { if (!isError) {
error(patch.src, patch.lineNo, "Modulo by 0"); errorAt(patch, "Modulo by 0");
isError = true; isError = true;
} }
popRPN(patch); popRPN(patch);
@@ -128,7 +128,7 @@ static int32_t computeRPNExpr(Patch const &patch, std::vector<Symbol> const &fil
value = popRPN(patch); value = popRPN(patch);
if (value < 0) { if (value < 0) {
if (!isError) { if (!isError) {
error(patch.src, patch.lineNo, "Exponent by negative value %" PRId32, value); errorAt(patch, "Exponent by negative value %" PRId32, value);
isError = true; isError = true;
} }
popRPN(patch); popRPN(patch);
@@ -222,9 +222,8 @@ static int32_t computeRPNExpr(Patch const &patch, std::vector<Symbol> const &fil
} }
if (Symbol const *symbol = getSymbol(fileSymbols, value); !symbol) { if (Symbol const *symbol = getSymbol(fileSymbols, value); !symbol) {
error( errorAt(
patch.src, patch,
patch.lineNo,
"Requested BANK() of symbol \"%s\", which was not found", "Requested BANK() of symbol \"%s\", which was not found",
fileSymbols[value].name.c_str() fileSymbols[value].name.c_str()
); );
@@ -233,9 +232,8 @@ static int32_t computeRPNExpr(Patch const &patch, std::vector<Symbol> const &fil
} else if (std::holds_alternative<Label>(symbol->data)) { } else if (std::holds_alternative<Label>(symbol->data)) {
value = std::get<Label>(symbol->data).section->bank; value = std::get<Label>(symbol->data).section->bank;
} else { } else {
error( errorAt(
patch.src, patch,
patch.lineNo,
"Requested BANK() of non-label symbol \"%s\"", "Requested BANK() of non-label symbol \"%s\"",
fileSymbols[value].name.c_str() fileSymbols[value].name.c_str()
); );
@@ -251,12 +249,7 @@ static int32_t computeRPNExpr(Patch const &patch, std::vector<Symbol> const &fil
while (getRPNByte(expression, size, patch)) {} while (getRPNByte(expression, size, patch)) {}
if (Section const *sect = sect_GetSection(name); !sect) { if (Section const *sect = sect_GetSection(name); !sect) {
error( errorAt(patch, "Requested BANK() of section \"%s\", which was not found", name);
patch.src,
patch.lineNo,
"Requested BANK() of section \"%s\", which was not found",
name
);
isError = true; isError = true;
value = 1; value = 1;
} else { } else {
@@ -267,7 +260,7 @@ static int32_t computeRPNExpr(Patch const &patch, std::vector<Symbol> const &fil
case RPN_BANK_SELF: case RPN_BANK_SELF:
if (!patch.pcSection) { if (!patch.pcSection) {
error(patch.src, patch.lineNo, "PC has no bank outside of a section"); errorAt(patch, "PC has no bank outside of a section");
isError = true; isError = true;
value = 1; value = 1;
} else { } else {
@@ -281,12 +274,7 @@ static int32_t computeRPNExpr(Patch const &patch, std::vector<Symbol> const &fil
while (getRPNByte(expression, size, patch)) {} while (getRPNByte(expression, size, patch)) {}
if (Section const *sect = sect_GetSection(name); !sect) { if (Section const *sect = sect_GetSection(name); !sect) {
error( errorAt(patch, "Requested SIZEOF() of section \"%s\", which was not found", name);
patch.src,
patch.lineNo,
"Requested SIZEOF() of section \"%s\", which was not found",
name
);
isError = true; isError = true;
value = 1; value = 1;
} else { } else {
@@ -301,12 +289,7 @@ static int32_t computeRPNExpr(Patch const &patch, std::vector<Symbol> const &fil
while (getRPNByte(expression, size, patch)) {} while (getRPNByte(expression, size, patch)) {}
if (Section const *sect = sect_GetSection(name); !sect) { if (Section const *sect = sect_GetSection(name); !sect) {
error( errorAt(patch, "Requested STARTOF() of section \"%s\", which was not found", name);
patch.src,
patch.lineNo,
"Requested STARTOF() of section \"%s\", which was not found",
name
);
isError = true; isError = true;
value = 1; value = 1;
} else { } else {
@@ -319,7 +302,7 @@ static int32_t computeRPNExpr(Patch const &patch, std::vector<Symbol> const &fil
case RPN_SIZEOF_SECTTYPE: case RPN_SIZEOF_SECTTYPE:
value = getRPNByte(expression, size, patch); value = getRPNByte(expression, size, patch);
if (value < 0 || value >= SECTTYPE_INVALID) { if (value < 0 || value >= SECTTYPE_INVALID) {
error(patch.src, patch.lineNo, "Requested SIZEOF() an invalid section type"); errorAt(patch, "Requested SIZEOF() an invalid section type");
isError = true; isError = true;
value = 0; value = 0;
} else { } else {
@@ -330,7 +313,7 @@ static int32_t computeRPNExpr(Patch const &patch, std::vector<Symbol> const &fil
case RPN_STARTOF_SECTTYPE: case RPN_STARTOF_SECTTYPE:
value = getRPNByte(expression, size, patch); value = getRPNByte(expression, size, patch);
if (value < 0 || value >= SECTTYPE_INVALID) { if (value < 0 || value >= SECTTYPE_INVALID) {
error(patch.src, patch.lineNo, "Requested STARTOF() an invalid section type"); errorAt(patch, "Requested STARTOF() an invalid section type");
isError = true; isError = true;
value = 0; value = 0;
} else { } else {
@@ -342,20 +325,13 @@ static int32_t computeRPNExpr(Patch const &patch, std::vector<Symbol> const &fil
value = popRPN(patch); value = popRPN(patch);
if (value < 0 || (value > 0xFF && value < 0xFF00) || value > 0xFFFF) { if (value < 0 || (value > 0xFF && value < 0xFF00) || value > 0xFFFF) {
if (!isError) { if (!isError) {
error( errorAt(patch, "Address $%" PRIx32 " for LDH is not in HRAM range", value);
patch.src,
patch.lineNo,
"Address $%" PRIx32 " for LDH is not in HRAM range",
value
);
isError = true; isError = true;
} }
value = 0; value = 0;
} else if (value >= 0 && value <= 0xFF) { } else if (value >= 0 && value <= 0xFF) {
warning( warningAt(
patch.src, patch, "LDH is deprecated with values from $00 to $FF; use $FF00 to $FFFF"
patch.lineNo,
"LDH is deprecated with values from $00 to $FF; use $FF00 to $FFFF"
); );
} }
value &= 0xFF; value &= 0xFF;
@@ -366,7 +342,7 @@ static int32_t computeRPNExpr(Patch const &patch, std::vector<Symbol> const &fil
// Acceptable values are 0x00, 0x08, 0x10, ..., 0x38 // Acceptable values are 0x00, 0x08, 0x10, ..., 0x38
if (value & ~0x38) { if (value & ~0x38) {
if (!isError) { if (!isError) {
error(patch.src, patch.lineNo, "Value $%" PRIx32 " is not a RST vector", value); errorAt(patch, "Value $%" PRIx32 " is not a RST vector", value);
isError = true; isError = true;
} }
value = 0; value = 0;
@@ -380,7 +356,7 @@ static int32_t computeRPNExpr(Patch const &patch, std::vector<Symbol> const &fil
// Acceptable values are 0 to 7 // Acceptable values are 0 to 7
if (value & ~0x07) { if (value & ~0x07) {
if (!isError) { if (!isError) {
error(patch.src, patch.lineNo, "Value $%" PRIx32 " is not a bit index", value); errorAt(patch, "Value $%" PRIx32 " is not a bit index", value);
isError = true; isError = true;
} }
value = 0; value = 0;
@@ -404,7 +380,7 @@ static int32_t computeRPNExpr(Patch const &patch, std::vector<Symbol> const &fil
if (value == -1) { // PC if (value == -1) { // PC
if (!patch.pcSection) { if (!patch.pcSection) {
error(patch.src, patch.lineNo, "PC has no value outside of a section"); errorAt(patch, "PC has no value outside of a section");
value = 0; value = 0;
isError = true; isError = true;
} else { } else {
@@ -412,12 +388,7 @@ static int32_t computeRPNExpr(Patch const &patch, std::vector<Symbol> const &fil
} }
} else { } else {
if (Symbol const *symbol = getSymbol(fileSymbols, value); !symbol) { if (Symbol const *symbol = getSymbol(fileSymbols, value); !symbol) {
error( errorAt(patch, "Unknown symbol \"%s\"", fileSymbols[value].name.c_str());
patch.src,
patch.lineNo,
"Unknown symbol \"%s\"",
fileSymbols[value].name.c_str()
);
sym_DumpLocalAliasedSymbols(fileSymbols[value].name); sym_DumpLocalAliasedSymbols(fileSymbols[value].name);
isError = true; isError = true;
} else if (std::holds_alternative<Label>(symbol->data)) { } else if (std::holds_alternative<Label>(symbol->data)) {
@@ -434,7 +405,7 @@ static int32_t computeRPNExpr(Patch const &patch, std::vector<Symbol> const &fil
} }
if (rpnStack.size() > 1) { if (rpnStack.size() > 1) {
error(patch.src, patch.lineNo, "RPN stack has %zu entries on exit, not 1", rpnStack.size()); errorAt(patch, "RPN stack has %zu entries on exit, not 1", rpnStack.size());
} }
isError = false; isError = false;
@@ -451,33 +422,29 @@ void patch_CheckAssertions() {
if (!isError && !value) { if (!isError && !value) {
switch (type) { switch (type) {
case ASSERT_FATAL: case ASSERT_FATAL:
fatal( fatalAt(
assert.patch.src, assert.patch,
assert.patch.lineNo,
"%s", "%s",
!assert.message.empty() ? assert.message.c_str() : "assert failure" !assert.message.empty() ? assert.message.c_str() : "assert failure"
); );
case ASSERT_ERROR: case ASSERT_ERROR:
error( errorAt(
assert.patch.src, assert.patch,
assert.patch.lineNo,
"%s", "%s",
!assert.message.empty() ? assert.message.c_str() : "assert failure" !assert.message.empty() ? assert.message.c_str() : "assert failure"
); );
break; break;
case ASSERT_WARN: case ASSERT_WARN:
warning( warningAt(
assert.patch.src, assert.patch,
assert.patch.lineNo,
"%s", "%s",
!assert.message.empty() ? assert.message.c_str() : "assert failure" !assert.message.empty() ? assert.message.c_str() : "assert failure"
); );
break; break;
} }
} else if (isError && type == ASSERT_FATAL) { } else if (isError && type == ASSERT_FATAL) {
fatal( fatalAt(
assert.patch.src, assert.patch,
assert.patch.lineNo,
"Failed to evaluate assertion%s%s", "Failed to evaluate assertion%s%s",
!assert.message.empty() ? ": " : "", !assert.message.empty() ? ": " : "",
assert.message.c_str() assert.message.c_str()
@@ -506,9 +473,8 @@ static void applyFilePatches(Section &section, Section &dataSection) {
auto const &type = types[patch.type]; auto const &type = types[patch.type];
if (dataSection.data.size() < offset + type.size) { if (dataSection.data.size() < offset + type.size) {
error( errorAt(
patch.src, patch,
patch.lineNo,
"Patch would write %zu bytes past the end of section \"%s\" (%zu bytes long)", "Patch would write %zu bytes past the end of section \"%s\" (%zu bytes long)",
offset + type.size - dataSection.data.size(), offset + type.size - dataSection.data.size(),
dataSection.name.c_str(), dataSection.name.c_str(),
@@ -521,9 +487,8 @@ static void applyFilePatches(Section &section, Section &dataSection) {
int16_t jumpOffset = value - address; int16_t jumpOffset = value - address;
if (!isError && (jumpOffset < -128 || jumpOffset > 127)) { if (!isError && (jumpOffset < -128 || jumpOffset > 127)) {
error( errorAt(
patch.src, patch,
patch.lineNo,
"JR target must be between -128 and 127 bytes away, not %" PRId16 "JR target must be between -128 and 127 bytes away, not %" PRId16
"; use JP instead", "; use JP instead",
jumpOffset jumpOffset
@@ -533,9 +498,8 @@ static void applyFilePatches(Section &section, Section &dataSection) {
} else { } else {
// Patch a certain number of bytes // Patch a certain number of bytes
if (!isError && (value < type.min || value > type.max)) { if (!isError && (value < type.min || value > type.max)) {
error( errorAt(
patch.src, patch,
patch.lineNo,
"Value %" PRId32 "%s is not %u-bit", "Value %" PRId32 "%s is not %u-bit",
value, value,
value < 0 ? " (maybe negative?)" : "", value < 0 ? " (maybe negative?)" : "",

View File

@@ -25,19 +25,23 @@ enum NumberType {
OCT = 8, // Q OCT = 8, // Q
}; };
static void consumeLF(FileStackNode const &where, uint32_t lineNo, FILE *file) { struct Location {
FileStackNode const *src;
uint32_t lineNo;
};
static void consumeLF(Location const &where, FILE *file) {
if (getc(file) != '\n') { if (getc(file) != '\n') {
fatal(&where, lineNo, "Bad line ending (CR without LF)"); fatalAt(where, "Bad line ending (CR without LF)");
} }
} }
static char const *delim = " \f\n\r\t\v"; // Whitespace according to the C and POSIX locales static char const *delim = " \f\n\r\t\v"; // Whitespace according to the C and POSIX locales
static int static int nextLine(std::vector<char> &lineBuf, Location &where, FILE *file) {
nextLine(std::vector<char> &lineBuf, uint32_t &lineNo, FileStackNode const &where, FILE *file) {
int firstChar; int firstChar;
for (;;) { for (;;) {
++lineNo; ++where.lineNo;
firstChar = getc(file); firstChar = getc(file);
lineBuf.clear(); lineBuf.clear();
@@ -46,14 +50,14 @@ static int
return EOF; return EOF;
case ';': case ';':
// Discard comment line // Discard comment line
// TODO: if `;!FILE [...]` on the first line (`lineNo`), return it // TODO: if `;!FILE [...]` on the first line (`where.lineNo`), return it
do { do {
firstChar = getc(file); firstChar = getc(file);
} while (firstChar != EOF && firstChar != '\r' && firstChar != '\n'); } while (firstChar != EOF && firstChar != '\r' && firstChar != '\n');
[[fallthrough]]; [[fallthrough]];
case '\r': case '\r':
if (firstChar == '\r' && getc(file) != '\n') { if (firstChar == '\r' && getc(file) != '\n') {
consumeLF(where, lineNo, file); consumeLF(where, file);
} }
[[fallthrough]]; [[fallthrough]];
case '\n': case '\n':
@@ -67,7 +71,7 @@ static int
switch (c) { switch (c) {
case '\r': case '\r':
consumeLF(where, lineNo, file); consumeLF(where, file);
[[fallthrough]]; [[fallthrough]];
case '\n': case '\n':
case EOF: case EOF:
@@ -79,9 +83,7 @@ static int
} }
static uint32_t readNumber(char const *str, char const *&endptr, NumberType base) { static uint32_t readNumber(char const *str, char const *&endptr, NumberType base) {
uint32_t res = 0; for (uint32_t res = 0;;) {
for (;;) {
static char const *digits = "0123456789ABCDEF"; static char const *digits = "0123456789ABCDEF";
char const *ptr = strchr(digits, toupper(*str)); char const *ptr = strchr(digits, toupper(*str));
@@ -94,27 +96,25 @@ static uint32_t readNumber(char const *str, char const *&endptr, NumberType base
} }
} }
static uint32_t static uint32_t parseNumber(Location const &where, char const *str, NumberType base) {
parseNumber(FileStackNode const &where, uint32_t lineNo, char const *str, NumberType base) {
if (str[0] == '\0') { if (str[0] == '\0') {
fatal(&where, lineNo, "Expected number, got empty string"); fatalAt(where, "Expected number, got empty string");
} }
char const *endptr; char const *endptr;
uint32_t res = readNumber(str, endptr, base); uint32_t res = readNumber(str, endptr, base);
if (*endptr != '\0') { if (*endptr != '\0') {
fatal(&where, lineNo, "Expected number, got \"%s\"", str); fatalAt(where, "Expected number, got \"%s\"", str);
} }
return res; return res;
} }
static uint8_t static uint8_t parseByte(Location const &where, char const *str, NumberType base) {
parseByte(FileStackNode const &where, uint32_t lineNo, char const *str, NumberType base) { uint32_t num = parseNumber(where, str, base);
uint32_t num = parseNumber(where, lineNo, str, base);
if (num > UINT8_MAX) { if (num > UINT8_MAX) {
fatal(&where, lineNo, "\"%s\" is not a byte", str); fatalAt(where, "\"%s\" is not a byte", str);
} }
return num; return num;
} }
@@ -144,7 +144,9 @@ enum RelocFlags {
| 1 << RELOC_WHICHBYTE | 1 << RELOC_EXPR24 | 1 << RELOC_BANKBYTE, | 1 << RELOC_WHICHBYTE | 1 << RELOC_EXPR24 | 1 << RELOC_BANKBYTE,
}; };
void sdobj_ReadFile(FileStackNode const &where, FILE *file, std::vector<Symbol> &fileSymbols) { void sdobj_ReadFile(FileStackNode const &src, FILE *file, std::vector<Symbol> &fileSymbols) {
Location where{.src = &src, .lineNo = 0};
std::vector<char> line; std::vector<char> line;
line.reserve(256); line.reserve(256);
char const *token; char const *token;
@@ -153,23 +155,22 @@ void sdobj_ReadFile(FileStackNode const &where, FILE *file, std::vector<Symbol>
do { \ do { \
token = strtok((ptr), delim); \ token = strtok((ptr), delim); \
if (!token) { \ if (!token) { \
fatal(&where, lineNo, __VA_ARGS__); \ fatalAt(where, __VA_ARGS__); \
} \ } \
} while (0) } while (0)
#define expectEol(...) \ #define expectEol(...) \
do { \ do { \
token = strtok(nullptr, delim); \ token = strtok(nullptr, delim); \
if (token) { \ if (token) { \
fatal(&where, lineNo, __VA_ARGS__); \ fatalAt(where, __VA_ARGS__); \
} \ } \
} while (0) } while (0)
#define expectToken(expected, lineType) \ #define expectToken(expected, lineType) \
do { \ do { \
getToken(nullptr, "'%c' line is too short", (lineType)); \ getToken(nullptr, "'%c' line is too short", (lineType)); \
if (strcasecmp(token, (expected)) != 0) { \ if (strcasecmp(token, (expected)) != 0) { \
fatal( \ fatalAt( \
&where, \ where, \
lineNo, \
"Malformed '%c' line: expected \"%s\", got \"%s\"", \ "Malformed '%c' line: expected \"%s\", got \"%s\"", \
(lineType), \ (lineType), \
(expected), \ (expected), \
@@ -178,14 +179,13 @@ void sdobj_ReadFile(FileStackNode const &where, FILE *file, std::vector<Symbol>
} \ } \
} while (0) } while (0)
uint32_t lineNo = 0; int lineType = nextLine(line, where, file);
int lineType = nextLine(line, lineNo, where, file);
NumberType numberType; NumberType numberType;
// The first letter (thus, the line type) identifies the integer type // The first letter (thus, the line type) identifies the integer type
switch (lineType) { switch (lineType) {
case EOF: case EOF:
fatal(&where, lineNo, "SDCC object only contains comments and empty lines"); fatalAt(where, "SDCC object only contains comments and empty lines");
case 'X': case 'X':
numberType = HEX; numberType = HEX;
break; break;
@@ -196,9 +196,8 @@ void sdobj_ReadFile(FileStackNode const &where, FILE *file, std::vector<Symbol>
numberType = OCT; numberType = OCT;
break; break;
default: default:
fatal( fatalAt(
&where, where,
lineNo,
"This does not look like a SDCC object file (unknown integer format '%c')", "This does not look like a SDCC object file (unknown integer format '%c')",
lineType lineType
); );
@@ -208,36 +207,36 @@ void sdobj_ReadFile(FileStackNode const &where, FILE *file, std::vector<Symbol>
case 'L': case 'L':
break; break;
case 'H': case 'H':
fatal(&where, lineNo, "Big-endian SDCC object files are not supported"); fatalAt(where, "Big-endian SDCC object files are not supported");
default: default:
fatal(&where, lineNo, "Unknown endianness type '%c'", line[0]); fatalAt(where, "Unknown endianness type '%c'", line[0]);
} }
static constexpr uint8_t ADDR_SIZE = 3; static constexpr uint8_t ADDR_SIZE = 3;
if (line[1] != '0' + ADDR_SIZE) { if (line[1] != '0' + ADDR_SIZE) {
fatal(&where, lineNo, "Unknown or unsupported address size '%c'", line[1]); fatalAt(where, "Unknown or unsupported address size '%c'", line[1]);
} }
if (line[2] != '\0') { if (line[2] != '\0') {
warning(&where, lineNo, "Ignoring unknown characters (\"%s\") in first line", &line[2]); warningAt(where, "Ignoring unknown characters (\"%s\") in first line", &line[2]);
} }
// Header line // Header line
lineType = nextLine(line, lineNo, where, file); lineType = nextLine(line, where, file);
if (lineType != 'H') { if (lineType != 'H') {
fatal(&where, lineNo, "Expected header line, got '%c' line", lineType); fatalAt(where, "Expected header line, got '%c' line", lineType);
} }
// Expected format: "A areas S global symbols" // Expected format: "A areas S global symbols"
getToken(line.data(), "Empty 'H' line"); getToken(line.data(), "Empty 'H' line");
uint32_t expectedNbAreas = parseNumber(where, lineNo, token, numberType); uint32_t expectedNbAreas = parseNumber(where, token, numberType);
expectToken("areas", 'H'); expectToken("areas", 'H');
getToken(nullptr, "'H' line is too short"); getToken(nullptr, "'H' line is too short");
uint32_t expectedNbSymbols = parseNumber(where, lineNo, token, numberType); uint32_t expectedNbSymbols = parseNumber(where, token, numberType);
fileSymbols.reserve(expectedNbSymbols); fileSymbols.reserve(expectedNbSymbols);
expectToken("global", 'H'); expectToken("global", 'H');
@@ -256,7 +255,7 @@ void sdobj_ReadFile(FileStackNode const &where, FILE *file, std::vector<Symbol>
std::vector<uint8_t> data; std::vector<uint8_t> data;
for (;;) { for (;;) {
lineType = nextLine(line, lineNo, where, file); lineType = nextLine(line, where, file);
if (lineType == EOF) { if (lineType == EOF) {
break; break;
} }
@@ -268,21 +267,19 @@ void sdobj_ReadFile(FileStackNode const &where, FILE *file, std::vector<Symbol>
case 'A': { case 'A': {
if (fileSections.size() == expectedNbAreas) { if (fileSections.size() == expectedNbAreas) {
warning( warningAt(where, "Got more 'A' lines than the expected %" PRIu32, expectedNbAreas);
&where, lineNo, "Got more 'A' lines than the expected %" PRIu32, expectedNbAreas
);
} }
std::unique_ptr<Section> curSection = std::make_unique<Section>(); std::unique_ptr<Section> curSection = std::make_unique<Section>();
curSection->src = &where; curSection->src = where.src;
curSection->lineNo = lineNo; curSection->lineNo = where.lineNo;
getToken(line.data(), "'A' line is too short"); getToken(line.data(), "'A' line is too short");
assume(strlen(token) != 0); // This should be impossible, tokens are non-empty assume(strlen(token) != 0); // This should be impossible, tokens are non-empty
// The following is required for fragment offsets to be reliably predicted // The following is required for fragment offsets to be reliably predicted
for (FileSection &entry : fileSections) { for (FileSection &entry : fileSections) {
if (!strcmp(token, entry.section->name.c_str())) { if (!strcmp(token, entry.section->name.c_str())) {
fatal(&where, lineNo, "Area \"%s\" already defined earlier", token); fatalAt(where, "Area \"%s\" already defined earlier", token);
} }
} }
char const *sectName = token; // We'll deal with the section's name depending on type char const *sectName = token; // We'll deal with the section's name depending on type
@@ -291,12 +288,11 @@ void sdobj_ReadFile(FileStackNode const &where, FILE *file, std::vector<Symbol>
getToken(nullptr, "'A' line is too short"); getToken(nullptr, "'A' line is too short");
uint32_t tmp = parseNumber(where, lineNo, token, numberType); uint32_t tmp = parseNumber(where, token, numberType);
if (tmp > UINT16_MAX) { if (tmp > UINT16_MAX) {
fatal( fatalAt(
&where, where,
lineNo,
"Area \"%s\" is larger than the GB address space!?", "Area \"%s\" is larger than the GB address space!?",
curSection->name.c_str() curSection->name.c_str()
); );
@@ -306,9 +302,9 @@ void sdobj_ReadFile(FileStackNode const &where, FILE *file, std::vector<Symbol>
expectToken("flags", 'A'); expectToken("flags", 'A');
getToken(nullptr, "'A' line is too short"); getToken(nullptr, "'A' line is too short");
tmp = parseNumber(where, lineNo, token, numberType); tmp = parseNumber(where, token, numberType);
if (tmp & (1 << AREA_PAGING)) { if (tmp & (1 << AREA_PAGING)) {
fatal(&where, lineNo, "Paging is not supported"); fatalAt(where, "Paging is not supported");
} }
curSection->isAddressFixed = tmp & (1 << AREA_ISABS); curSection->isAddressFixed = tmp & (1 << AREA_ISABS);
curSection->isBankFixed = curSection->isAddressFixed; curSection->isBankFixed = curSection->isAddressFixed;
@@ -317,7 +313,7 @@ void sdobj_ReadFile(FileStackNode const &where, FILE *file, std::vector<Symbol>
: SECTION_FRAGMENT; : SECTION_FRAGMENT;
// If the section is absolute, its name might not be unique; thus, mangle the name // If the section is absolute, its name might not be unique; thus, mangle the name
if (curSection->modifier == SECTION_NORMAL) { if (curSection->modifier == SECTION_NORMAL) {
curSection->name.append(where.name()); curSection->name.append(where.src->name());
curSection->name.append(" "); curSection->name.append(" ");
} }
curSection->name.append(sectName); curSection->name.append(sectName);
@@ -325,7 +321,7 @@ void sdobj_ReadFile(FileStackNode const &where, FILE *file, std::vector<Symbol>
expectToken("addr", 'A'); expectToken("addr", 'A');
getToken(nullptr, "'A' line is too short"); getToken(nullptr, "'A' line is too short");
tmp = parseNumber(where, lineNo, token, numberType); tmp = parseNumber(where, token, numberType);
curSection->org = tmp; // Truncation keeps the address portion only curSection->org = tmp; // Truncation keeps the address portion only
curSection->bank = tmp >> 16; curSection->bank = tmp >> 16;
@@ -349,7 +345,7 @@ void sdobj_ReadFile(FileStackNode const &where, FILE *file, std::vector<Symbol>
} else if (high < 0xE0) { } else if (high < 0xE0) {
curSection->type = SECTTYPE_WRAMX; curSection->type = SECTTYPE_WRAMX;
} else if (high < 0xFE) { } else if (high < 0xFE) {
fatal(&where, lineNo, "Areas in echo RAM are not supported"); fatalAt(where, "Areas in echo RAM are not supported");
} else if (high < 0xFF) { } else if (high < 0xFF) {
curSection->type = SECTTYPE_OAM; curSection->type = SECTTYPE_OAM;
} else { } else {
@@ -368,27 +364,21 @@ void sdobj_ReadFile(FileStackNode const &where, FILE *file, std::vector<Symbol>
case 'S': { case 'S': {
if (fileSymbols.size() == expectedNbSymbols) { if (fileSymbols.size() == expectedNbSymbols) {
error( errorAt(where, "Got more 'S' lines than the expected %" PRIu32, expectedNbSymbols);
&where,
lineNo,
"Got more 'S' lines than the expected %" PRIu32,
expectedNbSymbols
);
break; // Refuse processing the line further. break; // Refuse processing the line further.
} }
Symbol &symbol = fileSymbols.emplace_back(); Symbol &symbol = fileSymbols.emplace_back();
// Init other members // Init other members
symbol.src = &where; symbol.src = where.src;
symbol.lineNo = lineNo; symbol.lineNo = where.lineNo;
getToken(line.data(), "'S' line is too short"); getToken(line.data(), "'S' line is too short");
symbol.name = token; symbol.name = token;
getToken(nullptr, "'S' line is too short"); getToken(nullptr, "'S' line is too short");
if (int32_t value = parseNumber(where, lineNo, &token[3], numberType); if (int32_t value = parseNumber(where, &token[3], numberType); !fileSections.empty()) {
!fileSections.empty()) {
// Symbols in sections are labels; their value is an offset // Symbols in sections are labels; their value is an offset
Section *section = fileSections.back().section.get(); Section *section = fileSections.back().section.get();
if (section->isAddressFixed) { if (section->isAddressFixed) {
@@ -408,7 +398,7 @@ void sdobj_ReadFile(FileStackNode const &where, FILE *file, std::vector<Symbol>
sym_AddSymbol(symbol); sym_AddSymbol(symbol);
// TODO: hard error if the rest is not zero // TODO: hard error if the rest is not zero
} else if (token[0] != 'D' && token[0] != 'd') { } else if (token[0] != 'D' && token[0] != 'd') {
fatal(&where, lineNo, "'S' line is neither \"Def\" nor \"Ref\""); fatalAt(where, "'S' line is neither \"Def\" nor \"Ref\"");
} else { } else {
// All symbols are exported // All symbols are exported
symbol.type = SYMTYPE_EXPORT; symbol.type = SYMTYPE_EXPORT;
@@ -448,7 +438,7 @@ void sdobj_ReadFile(FileStackNode const &where, FILE *file, std::vector<Symbol>
// the name must not be modified // the name must not be modified
} }
if (strncasecmp(&token[1], "ef", literal_strlen("ef")) != 0) { if (strncasecmp(&token[1], "ef", literal_strlen("ef")) != 0) {
fatal(&where, lineNo, "'S' line is neither \"Def\" nor \"Ref\""); fatalAt(where, "'S' line is neither \"Def\" nor \"Ref\"");
} }
if (!fileSections.empty()) { if (!fileSections.empty()) {
@@ -462,16 +452,16 @@ void sdobj_ReadFile(FileStackNode const &where, FILE *file, std::vector<Symbol>
case 'T': case 'T':
// Now, time to parse the data! // Now, time to parse the data!
if (!data.empty()) { if (!data.empty()) {
warning(&where, lineNo, "Previous 'T' line had no 'R' line (ignored)"); warningAt(where, "Previous 'T' line had no 'R' line (ignored)");
} }
data.clear(); data.clear();
for (token = strtok(line.data(), delim); token; token = strtok(nullptr, delim)) { for (token = strtok(line.data(), delim); token; token = strtok(nullptr, delim)) {
data.push_back(parseByte(where, lineNo, token, numberType)); data.push_back(parseByte(where, token, numberType));
} }
if (data.size() < ADDR_SIZE) { if (data.size() < ADDR_SIZE) {
fatal(&where, lineNo, "'T' line is too short"); fatalAt(where, "'T' line is too short");
} }
// Importantly, now we know that there is "pending data" in `data` // Importantly, now we know that there is "pending data" in `data`
break; break;
@@ -479,7 +469,7 @@ void sdobj_ReadFile(FileStackNode const &where, FILE *file, std::vector<Symbol>
case 'R': { case 'R': {
// Supposed to directly follow `T` // Supposed to directly follow `T`
if (data.empty()) { if (data.empty()) {
warning(&where, lineNo, "'R' line with no 'T' line, ignoring"); warningAt(where, "'R' line with no 'T' line, ignoring");
break; break;
} }
@@ -489,13 +479,12 @@ void sdobj_ReadFile(FileStackNode const &where, FILE *file, std::vector<Symbol>
uint16_t areaIdx; uint16_t areaIdx;
getToken(nullptr, "'R' line is too short"); getToken(nullptr, "'R' line is too short");
areaIdx = parseByte(where, lineNo, token, numberType); areaIdx = parseByte(where, token, numberType);
getToken(nullptr, "'R' line is too short"); getToken(nullptr, "'R' line is too short");
areaIdx |= static_cast<uint16_t>(parseByte(where, lineNo, token, numberType)) << 8; areaIdx |= static_cast<uint16_t>(parseByte(where, token, numberType)) << 8;
if (areaIdx >= fileSections.size()) { if (areaIdx >= fileSections.size()) {
fatal( fatalAt(
&where, where,
lineNo,
"'R' line references area #%" PRIu16 ", but there are only %zu (so far)", "'R' line references area #%" PRIu16 ", but there are only %zu (so far)",
areaIdx, areaIdx,
fileSections.size() fileSections.size()
@@ -509,9 +498,8 @@ void sdobj_ReadFile(FileStackNode const &where, FILE *file, std::vector<Symbol>
if (section->isAddressFixed) { if (section->isAddressFixed) {
if (addr < section->org) { if (addr < section->org) {
fatal( fatalAt(
&where, where,
lineNo,
"'T' line reports address $%04" PRIx16 "'T' line reports address $%04" PRIx16
" in \"%s\", which starts at $%04" PRIx16, " in \"%s\", which starts at $%04" PRIx16,
addr, addr,
@@ -525,9 +513,8 @@ void sdobj_ReadFile(FileStackNode const &where, FILE *file, std::vector<Symbol>
// ignore those. "Empty" lines shouldn't trigger allocation, either. // ignore those. "Empty" lines shouldn't trigger allocation, either.
if (data.size() != ADDR_SIZE) { if (data.size() != ADDR_SIZE) {
if (addr != *writeIndex) { if (addr != *writeIndex) {
fatal( fatalAt(
&where, where,
lineNo,
"'T' lines which don't append to their section are not supported (%" PRIu16 "'T' lines which don't append to their section are not supported (%" PRIu16
" != %" PRIu16 ")", " != %" PRIu16 ")",
addr, addr,
@@ -554,31 +541,28 @@ void sdobj_ReadFile(FileStackNode const &where, FILE *file, std::vector<Symbol>
// appropriate RPN expression (depending on flags), plus an addition for the // appropriate RPN expression (depending on flags), plus an addition for the
// bytes being patched over. // bytes being patched over.
while ((token = strtok(nullptr, delim)) != nullptr) { while ((token = strtok(nullptr, delim)) != nullptr) {
uint16_t flags = parseByte(where, lineNo, token, numberType); uint16_t flags = parseByte(where, token, numberType);
if ((flags & 0xF0) == 0xF0) { if ((flags & 0xF0) == 0xF0) {
getToken(nullptr, "Incomplete relocation"); getToken(nullptr, "Incomplete relocation");
flags = (flags & 0x0F) flags = (flags & 0x0F)
| static_cast<uint16_t>(parseByte(where, lineNo, token, numberType)) | static_cast<uint16_t>(parseByte(where, token, numberType)) << 4;
<< 4;
} }
getToken(nullptr, "Incomplete relocation"); getToken(nullptr, "Incomplete relocation");
uint8_t offset = parseByte(where, lineNo, token, numberType); uint8_t offset = parseByte(where, token, numberType);
if (offset < ADDR_SIZE) { if (offset < ADDR_SIZE) {
fatal( fatalAt(
&where, where,
lineNo,
"Relocation index cannot point to header (%" PRIu16 " < %u)", "Relocation index cannot point to header (%" PRIu16 " < %u)",
offset, offset,
ADDR_SIZE ADDR_SIZE
); );
} }
if (offset >= data.size()) { if (offset >= data.size()) {
fatal( fatalAt(
&where, where,
lineNo,
"Relocation index is out of bounds (%" PRIu16 " >= %zu)", "Relocation index is out of bounds (%" PRIu16 " >= %zu)",
offset, offset,
data.size() data.size()
@@ -586,31 +570,30 @@ void sdobj_ReadFile(FileStackNode const &where, FILE *file, std::vector<Symbol>
} }
getToken(nullptr, "Incomplete relocation"); getToken(nullptr, "Incomplete relocation");
uint16_t idx = parseByte(where, lineNo, token, numberType); uint16_t idx = parseByte(where, token, numberType);
getToken(nullptr, "Incomplete relocation"); getToken(nullptr, "Incomplete relocation");
idx |= static_cast<uint16_t>(parseByte(where, lineNo, token, numberType)); idx |= static_cast<uint16_t>(parseByte(where, token, numberType));
// Loudly fail on unknown flags // Loudly fail on unknown flags
if (flags & (1 << RELOC_ZPAGE | 1 << RELOC_NPAGE)) { if (flags & (1 << RELOC_ZPAGE | 1 << RELOC_NPAGE)) {
fatal(&where, lineNo, "Paging flags are not supported"); fatalAt(where, "Paging flags are not supported");
} }
if (flags & ~RELOC_ALL_FLAGS) { if (flags & ~RELOC_ALL_FLAGS) {
warning(&where, lineNo, "Unknown reloc flags 0x%x", flags & ~RELOC_ALL_FLAGS); warningAt(where, "Unknown reloc flags 0x%x", flags & ~RELOC_ALL_FLAGS);
} }
// Turn this into a Patch // Turn this into a Patch
Patch &patch = section->patches.emplace_back(); Patch &patch = section->patches.emplace_back();
patch.lineNo = lineNo; patch.src = where.src;
patch.src = &where; patch.lineNo = where.lineNo;
patch.offset = offset - writtenOfs + *writeIndex; patch.offset = offset - writtenOfs + *writeIndex;
if (section->patches.size() > 1) { if (section->patches.size() > 1) {
uint32_t prevOffset = section->patches[section->patches.size() - 2].offset; uint32_t prevOffset = section->patches[section->patches.size() - 2].offset;
if (prevOffset >= patch.offset) { if (prevOffset >= patch.offset) {
fatal( fatalAt(
&where, where,
lineNo,
"Relocs not sorted by offset are not supported (%" PRIu32 " >= %" PRIu32 "Relocs not sorted by offset are not supported (%" PRIu32 " >= %" PRIu32
")", ")",
prevOffset, prevOffset,
@@ -627,9 +610,8 @@ void sdobj_ReadFile(FileStackNode const &where, FILE *file, std::vector<Symbol>
assume(offset < data.size()); assume(offset < data.size());
if (data.size() - offset < nbBaseBytes) { if (data.size() - offset < nbBaseBytes) {
fatal( fatalAt(
&where, where,
lineNo,
"Reloc would patch out of bounds (%" PRIu8 " > %zu)", "Reloc would patch out of bounds (%" PRIu8 " > %zu)",
nbBaseBytes, nbBaseBytes,
data.size() - offset data.size() - offset
@@ -643,9 +625,8 @@ void sdobj_ReadFile(FileStackNode const &where, FILE *file, std::vector<Symbol>
// Generate a RPN expression from the info and flags // Generate a RPN expression from the info and flags
if (flags & 1 << RELOC_ISSYM) { if (flags & 1 << RELOC_ISSYM) {
if (idx >= fileSymbols.size()) { if (idx >= fileSymbols.size()) {
fatal( fatalAt(
&where, where,
lineNo,
"Reloc refers to symbol #%" PRIu16 " out of %zu", "Reloc refers to symbol #%" PRIu16 " out of %zu",
idx, idx,
fileSymbols.size() fileSymbols.size()
@@ -665,9 +646,8 @@ void sdobj_ReadFile(FileStackNode const &where, FILE *file, std::vector<Symbol>
} }
} }
if (idx == fileSymbols.size()) { if (idx == fileSymbols.size()) {
fatal( fatalAt(
&where, where,
lineNo,
"\"%s\" is missing a reference to \"%s\"", "\"%s\" is missing a reference to \"%s\"",
sym.name.c_str(), sym.name.c_str(),
&sym.name.c_str()[1] &sym.name.c_str()[1]
@@ -705,9 +685,8 @@ void sdobj_ReadFile(FileStackNode const &where, FILE *file, std::vector<Symbol>
} }
} else { } else {
if (idx >= fileSections.size()) { if (idx >= fileSections.size()) {
fatal( fatalAt(
&where, where,
lineNo,
"Reloc refers to area #%" PRIu16 " out of %zu", "Reloc refers to area #%" PRIu16 " out of %zu",
idx, idx,
fileSections.size() fileSections.size()
@@ -759,9 +738,8 @@ void sdobj_ReadFile(FileStackNode const &where, FILE *file, std::vector<Symbol>
// are present, so we must skip two of them // are present, so we must skip two of them
if (flags & 1 << RELOC_EXPR16) { if (flags & 1 << RELOC_EXPR16) {
if (*writeIndex + (offset - writtenOfs) > section->size) { if (*writeIndex + (offset - writtenOfs) > section->size) {
fatal( fatalAt(
&where, where,
lineNo,
"'T' line writes past \"%s\"'s end (%u > %" PRIu16 ")", "'T' line writes past \"%s\"'s end (%u > %" PRIu16 ")",
section->name.c_str(), section->name.c_str(),
*writeIndex + (offset - writtenOfs), *writeIndex + (offset - writtenOfs),
@@ -810,11 +788,10 @@ void sdobj_ReadFile(FileStackNode const &where, FILE *file, std::vector<Symbol>
} }
} else if (flags & 1 << RELOC_ISPCREL) { } else if (flags & 1 << RELOC_ISPCREL) {
assume(patch.type == PATCHTYPE_WORD); assume(patch.type == PATCHTYPE_WORD);
fatal(&where, lineNo, "16-bit PC-relative relocations are not supported"); fatalAt(where, "16-bit PC-relative relocations are not supported");
} else if (flags & (1 << RELOC_EXPR16 | 1 << RELOC_EXPR24)) { } else if (flags & (1 << RELOC_EXPR16 | 1 << RELOC_EXPR24)) {
fatal( fatalAt(
&where, where,
lineNo,
"Flags 0x%x are not supported for 16-bit relocs", "Flags 0x%x are not supported for 16-bit relocs",
flags & (1 << RELOC_EXPR16 | 1 << RELOC_EXPR24) flags & (1 << RELOC_EXPR16 | 1 << RELOC_EXPR24)
); );
@@ -825,9 +802,8 @@ void sdobj_ReadFile(FileStackNode const &where, FILE *file, std::vector<Symbol>
if (writtenOfs != data.size()) { if (writtenOfs != data.size()) {
assume(data.size() > writtenOfs); assume(data.size() > writtenOfs);
if (*writeIndex + (data.size() - writtenOfs) > section->size) { if (*writeIndex + (data.size() - writtenOfs) > section->size) {
fatal( fatalAt(
&where, where,
lineNo,
"'T' line writes past \"%s\"'s end (%zu > %" PRIu16 ")", "'T' line writes past \"%s\"'s end (%zu > %" PRIu16 ")",
section->name.c_str(), section->name.c_str(),
*writeIndex + (data.size() - writtenOfs), *writeIndex + (data.size() - writtenOfs),
@@ -844,7 +820,7 @@ void sdobj_ReadFile(FileStackNode const &where, FILE *file, std::vector<Symbol>
case 'P': case 'P':
default: default:
warning(&where, lineNo, "Unknown/unsupported line type '%c', ignoring", lineType); warningAt(where, "Unknown/unsupported line type '%c', ignoring", lineType);
break; break;
} }
} }
@@ -854,21 +830,19 @@ void sdobj_ReadFile(FileStackNode const &where, FILE *file, std::vector<Symbol>
#undef getToken #undef getToken
if (!data.empty()) { if (!data.empty()) {
warning(&where, lineNo, "Last 'T' line had no 'R' line (ignored)"); warningAt(where, "Last 'T' line had no 'R' line (ignored)");
} }
if (fileSections.size() < expectedNbAreas) { if (fileSections.size() < expectedNbAreas) {
warning( warningAt(
&where, where,
lineNo,
"Expected %" PRIu32 " 'A' lines, got only %zu", "Expected %" PRIu32 " 'A' lines, got only %zu",
expectedNbAreas, expectedNbAreas,
fileSections.size() fileSections.size()
); );
} }
if (fileSymbols.size() < expectedNbSymbols) { if (fileSymbols.size() < expectedNbSymbols) {
warning( warningAt(
&where, where,
lineNo,
"Expected %" PRIu32 " 'S' lines, got only %zu", "Expected %" PRIu32 " 'S' lines, got only %zu",
expectedNbSymbols, expectedNbSymbols,
fileSymbols.size() fileSymbols.size()
@@ -888,9 +862,8 @@ void sdobj_ReadFile(FileStackNode const &where, FILE *file, std::vector<Symbol>
if (!sect_HasData(section->type)) { if (!sect_HasData(section->type)) {
if (!section->data.empty()) { if (!section->data.empty()) {
fatal( fatalAt(
&where, where,
lineNo,
"\"%s\" is implicitly defined as a %s section (being at address $%04" PRIx16 "\"%s\" is implicitly defined as a %s section (being at address $%04" PRIx16
"), but it has data! (Was a bad `__at()` value used?)", "), but it has data! (Was a bad `__at()` value used?)",
section->name.c_str(), section->name.c_str(),
@@ -899,9 +872,8 @@ void sdobj_ReadFile(FileStackNode const &where, FILE *file, std::vector<Symbol>
); );
} }
} else if (section->size != 0 && section->data.empty()) { } else if (section->size != 0 && section->data.empty()) {
fatal( fatalAt(
&where, where,
lineNo,
"\"%s\" is implicitly defined as a %s section (being at address $%04" PRIx16 "\"%s\" is implicitly defined as a %s section (being at address $%04" PRIx16
"), but it doesn't have any data! (Was a bad `__at()` value used?)", "), but it doesn't have any data! (Was a bad `__at()` value used?)",
section->name.c_str(), section->name.c_str(),
@@ -912,9 +884,8 @@ void sdobj_ReadFile(FileStackNode const &where, FILE *file, std::vector<Symbol>
} }
if (entry.writeIndex != 0 && entry.writeIndex != section->size) { if (entry.writeIndex != 0 && entry.writeIndex != section->size) {
fatal( fatalAt(
&where, where,
lineNo,
"\"%s\" was not fully written (%" PRIu16 " < %" PRIu16 ")", "\"%s\" was not fully written (%" PRIu16 " < %" PRIu16 ")",
section->name.c_str(), section->name.c_str(),
entry.writeIndex, entry.writeIndex,

View File

@@ -10,11 +10,11 @@
static uint32_t nbErrors = 0; static uint32_t nbErrors = 0;
static void printDiag( static void printDiag(
FileStackNode const *where, uint32_t lineNo, char const *fmt, va_list args, char const *type FileStackNode const *src, uint32_t lineNo, char const *fmt, va_list args, char const *type
) { ) {
fprintf(stderr, "%s: ", type); fprintf(stderr, "%s: ", type);
if (where) { if (src) {
where->dump(lineNo); src->dump(lineNo);
fputs(": ", stderr); fputs(": ", stderr);
} }
vfprintf(stderr, fmt, args); vfprintf(stderr, fmt, args);
@@ -39,10 +39,10 @@ static void abortLinking(char const *verb) {
exit(1); exit(1);
} }
void warning(FileStackNode const *where, uint32_t lineNo, char const *fmt, ...) { void warning(FileStackNode const *src, uint32_t lineNo, char const *fmt, ...) {
va_list args; va_list args;
va_start(args, fmt); va_start(args, fmt);
printDiag(where, lineNo, fmt, args, "warning"); printDiag(src, lineNo, fmt, args, "warning");
va_end(args); va_end(args);
} }
@@ -53,10 +53,10 @@ void warning(char const *fmt, ...) {
va_end(args); va_end(args);
} }
void error(FileStackNode const *where, uint32_t lineNo, char const *fmt, ...) { void error(FileStackNode const *src, uint32_t lineNo, char const *fmt, ...) {
va_list args; va_list args;
va_start(args, fmt); va_start(args, fmt);
printDiag(where, lineNo, fmt, args, "error"); printDiag(src, lineNo, fmt, args, "error");
va_end(args); va_end(args);
incrementErrors(); incrementErrors();
@@ -93,10 +93,10 @@ void argErr(char flag, char const *fmt, ...) {
} }
[[noreturn]] [[noreturn]]
void fatal(FileStackNode const *where, uint32_t lineNo, char const *fmt, ...) { void fatal(FileStackNode const *src, uint32_t lineNo, char const *fmt, ...) {
va_list args; va_list args;
va_start(args, fmt); va_start(args, fmt);
printDiag(where, lineNo, fmt, args, "FATAL"); printDiag(src, lineNo, fmt, args, "FATAL");
va_end(args); va_end(args);
incrementErrors(); incrementErrors();