mirror of
https://github.com/gbdev/rgbds.git
synced 2025-11-20 10:12:06 +00:00
Abbreviate RGBLINK errput that includes a src+lineNo
This commit is contained in:
@@ -5,15 +5,19 @@
|
||||
|
||||
#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;
|
||||
|
||||
[[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)]]
|
||||
void warning(char const *fmt, ...);
|
||||
|
||||
[[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)]]
|
||||
void error(char const *fmt, ...);
|
||||
[[gnu::format(printf, 1, 2)]]
|
||||
@@ -22,7 +26,7 @@ void errorNoDump(char const *fmt, ...);
|
||||
void argErr(char flag, char const *fmt, ...);
|
||||
|
||||
[[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]]
|
||||
void fatal(char const *fmt, ...);
|
||||
|
||||
|
||||
@@ -35,7 +35,7 @@ static bool isError = false;
|
||||
|
||||
static int32_t popRPN(Patch const &patch) {
|
||||
if (rpnStack.empty()) {
|
||||
fatal(patch.src, patch.lineNo, "Internal error, RPN stack empty");
|
||||
fatalAt(patch, "Internal error, RPN stack empty");
|
||||
}
|
||||
|
||||
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) {
|
||||
if (!size--) {
|
||||
fatal(patch.src, patch.lineNo, "Internal error, RPN expression overread");
|
||||
fatalAt(patch, "Internal error, RPN expression overread");
|
||||
}
|
||||
|
||||
return *expression++;
|
||||
@@ -99,7 +99,7 @@ static int32_t computeRPNExpr(Patch const &patch, std::vector<Symbol> const &fil
|
||||
value = popRPN(patch);
|
||||
if (value == 0) {
|
||||
if (!isError) {
|
||||
error(patch.src, patch.lineNo, "Division by 0");
|
||||
errorAt(patch, "Division by 0");
|
||||
isError = true;
|
||||
}
|
||||
popRPN(patch);
|
||||
@@ -112,7 +112,7 @@ static int32_t computeRPNExpr(Patch const &patch, std::vector<Symbol> const &fil
|
||||
value = popRPN(patch);
|
||||
if (value == 0) {
|
||||
if (!isError) {
|
||||
error(patch.src, patch.lineNo, "Modulo by 0");
|
||||
errorAt(patch, "Modulo by 0");
|
||||
isError = true;
|
||||
}
|
||||
popRPN(patch);
|
||||
@@ -128,7 +128,7 @@ static int32_t computeRPNExpr(Patch const &patch, std::vector<Symbol> const &fil
|
||||
value = popRPN(patch);
|
||||
if (value < 0) {
|
||||
if (!isError) {
|
||||
error(patch.src, patch.lineNo, "Exponent by negative value %" PRId32, value);
|
||||
errorAt(patch, "Exponent by negative value %" PRId32, value);
|
||||
isError = true;
|
||||
}
|
||||
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) {
|
||||
error(
|
||||
patch.src,
|
||||
patch.lineNo,
|
||||
errorAt(
|
||||
patch,
|
||||
"Requested BANK() of symbol \"%s\", which was not found",
|
||||
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)) {
|
||||
value = std::get<Label>(symbol->data).section->bank;
|
||||
} else {
|
||||
error(
|
||||
patch.src,
|
||||
patch.lineNo,
|
||||
errorAt(
|
||||
patch,
|
||||
"Requested BANK() of non-label symbol \"%s\"",
|
||||
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)) {}
|
||||
|
||||
if (Section const *sect = sect_GetSection(name); !sect) {
|
||||
error(
|
||||
patch.src,
|
||||
patch.lineNo,
|
||||
"Requested BANK() of section \"%s\", which was not found",
|
||||
name
|
||||
);
|
||||
errorAt(patch, "Requested BANK() of section \"%s\", which was not found", name);
|
||||
isError = true;
|
||||
value = 1;
|
||||
} else {
|
||||
@@ -267,7 +260,7 @@ static int32_t computeRPNExpr(Patch const &patch, std::vector<Symbol> const &fil
|
||||
|
||||
case RPN_BANK_SELF:
|
||||
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;
|
||||
value = 1;
|
||||
} else {
|
||||
@@ -281,12 +274,7 @@ static int32_t computeRPNExpr(Patch const &patch, std::vector<Symbol> const &fil
|
||||
while (getRPNByte(expression, size, patch)) {}
|
||||
|
||||
if (Section const *sect = sect_GetSection(name); !sect) {
|
||||
error(
|
||||
patch.src,
|
||||
patch.lineNo,
|
||||
"Requested SIZEOF() of section \"%s\", which was not found",
|
||||
name
|
||||
);
|
||||
errorAt(patch, "Requested SIZEOF() of section \"%s\", which was not found", name);
|
||||
isError = true;
|
||||
value = 1;
|
||||
} else {
|
||||
@@ -301,12 +289,7 @@ static int32_t computeRPNExpr(Patch const &patch, std::vector<Symbol> const &fil
|
||||
while (getRPNByte(expression, size, patch)) {}
|
||||
|
||||
if (Section const *sect = sect_GetSection(name); !sect) {
|
||||
error(
|
||||
patch.src,
|
||||
patch.lineNo,
|
||||
"Requested STARTOF() of section \"%s\", which was not found",
|
||||
name
|
||||
);
|
||||
errorAt(patch, "Requested STARTOF() of section \"%s\", which was not found", name);
|
||||
isError = true;
|
||||
value = 1;
|
||||
} else {
|
||||
@@ -319,7 +302,7 @@ static int32_t computeRPNExpr(Patch const &patch, std::vector<Symbol> const &fil
|
||||
case RPN_SIZEOF_SECTTYPE:
|
||||
value = getRPNByte(expression, size, patch);
|
||||
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;
|
||||
value = 0;
|
||||
} else {
|
||||
@@ -330,7 +313,7 @@ static int32_t computeRPNExpr(Patch const &patch, std::vector<Symbol> const &fil
|
||||
case RPN_STARTOF_SECTTYPE:
|
||||
value = getRPNByte(expression, size, patch);
|
||||
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;
|
||||
value = 0;
|
||||
} else {
|
||||
@@ -342,20 +325,13 @@ static int32_t computeRPNExpr(Patch const &patch, std::vector<Symbol> const &fil
|
||||
value = popRPN(patch);
|
||||
if (value < 0 || (value > 0xFF && value < 0xFF00) || value > 0xFFFF) {
|
||||
if (!isError) {
|
||||
error(
|
||||
patch.src,
|
||||
patch.lineNo,
|
||||
"Address $%" PRIx32 " for LDH is not in HRAM range",
|
||||
value
|
||||
);
|
||||
errorAt(patch, "Address $%" PRIx32 " for LDH is not in HRAM range", value);
|
||||
isError = true;
|
||||
}
|
||||
value = 0;
|
||||
} else if (value >= 0 && value <= 0xFF) {
|
||||
warning(
|
||||
patch.src,
|
||||
patch.lineNo,
|
||||
"LDH is deprecated with values from $00 to $FF; use $FF00 to $FFFF"
|
||||
warningAt(
|
||||
patch, "LDH is deprecated with values from $00 to $FF; use $FF00 to $FFFF"
|
||||
);
|
||||
}
|
||||
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
|
||||
if (value & ~0x38) {
|
||||
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;
|
||||
}
|
||||
value = 0;
|
||||
@@ -380,7 +356,7 @@ static int32_t computeRPNExpr(Patch const &patch, std::vector<Symbol> const &fil
|
||||
// Acceptable values are 0 to 7
|
||||
if (value & ~0x07) {
|
||||
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;
|
||||
}
|
||||
value = 0;
|
||||
@@ -404,7 +380,7 @@ static int32_t computeRPNExpr(Patch const &patch, std::vector<Symbol> const &fil
|
||||
|
||||
if (value == -1) { // PC
|
||||
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;
|
||||
isError = true;
|
||||
} else {
|
||||
@@ -412,12 +388,7 @@ static int32_t computeRPNExpr(Patch const &patch, std::vector<Symbol> const &fil
|
||||
}
|
||||
} else {
|
||||
if (Symbol const *symbol = getSymbol(fileSymbols, value); !symbol) {
|
||||
error(
|
||||
patch.src,
|
||||
patch.lineNo,
|
||||
"Unknown symbol \"%s\"",
|
||||
fileSymbols[value].name.c_str()
|
||||
);
|
||||
errorAt(patch, "Unknown symbol \"%s\"", fileSymbols[value].name.c_str());
|
||||
sym_DumpLocalAliasedSymbols(fileSymbols[value].name);
|
||||
isError = true;
|
||||
} 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) {
|
||||
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;
|
||||
@@ -451,33 +422,29 @@ void patch_CheckAssertions() {
|
||||
if (!isError && !value) {
|
||||
switch (type) {
|
||||
case ASSERT_FATAL:
|
||||
fatal(
|
||||
assert.patch.src,
|
||||
assert.patch.lineNo,
|
||||
fatalAt(
|
||||
assert.patch,
|
||||
"%s",
|
||||
!assert.message.empty() ? assert.message.c_str() : "assert failure"
|
||||
);
|
||||
case ASSERT_ERROR:
|
||||
error(
|
||||
assert.patch.src,
|
||||
assert.patch.lineNo,
|
||||
errorAt(
|
||||
assert.patch,
|
||||
"%s",
|
||||
!assert.message.empty() ? assert.message.c_str() : "assert failure"
|
||||
);
|
||||
break;
|
||||
case ASSERT_WARN:
|
||||
warning(
|
||||
assert.patch.src,
|
||||
assert.patch.lineNo,
|
||||
warningAt(
|
||||
assert.patch,
|
||||
"%s",
|
||||
!assert.message.empty() ? assert.message.c_str() : "assert failure"
|
||||
);
|
||||
break;
|
||||
}
|
||||
} else if (isError && type == ASSERT_FATAL) {
|
||||
fatal(
|
||||
assert.patch.src,
|
||||
assert.patch.lineNo,
|
||||
fatalAt(
|
||||
assert.patch,
|
||||
"Failed to evaluate assertion%s%s",
|
||||
!assert.message.empty() ? ": " : "",
|
||||
assert.message.c_str()
|
||||
@@ -506,9 +473,8 @@ static void applyFilePatches(Section §ion, Section &dataSection) {
|
||||
auto const &type = types[patch.type];
|
||||
|
||||
if (dataSection.data.size() < offset + type.size) {
|
||||
error(
|
||||
patch.src,
|
||||
patch.lineNo,
|
||||
errorAt(
|
||||
patch,
|
||||
"Patch would write %zu bytes past the end of section \"%s\" (%zu bytes long)",
|
||||
offset + type.size - dataSection.data.size(),
|
||||
dataSection.name.c_str(),
|
||||
@@ -521,9 +487,8 @@ static void applyFilePatches(Section §ion, Section &dataSection) {
|
||||
int16_t jumpOffset = value - address;
|
||||
|
||||
if (!isError && (jumpOffset < -128 || jumpOffset > 127)) {
|
||||
error(
|
||||
patch.src,
|
||||
patch.lineNo,
|
||||
errorAt(
|
||||
patch,
|
||||
"JR target must be between -128 and 127 bytes away, not %" PRId16
|
||||
"; use JP instead",
|
||||
jumpOffset
|
||||
@@ -533,9 +498,8 @@ static void applyFilePatches(Section §ion, Section &dataSection) {
|
||||
} else {
|
||||
// Patch a certain number of bytes
|
||||
if (!isError && (value < type.min || value > type.max)) {
|
||||
error(
|
||||
patch.src,
|
||||
patch.lineNo,
|
||||
errorAt(
|
||||
patch,
|
||||
"Value %" PRId32 "%s is not %u-bit",
|
||||
value,
|
||||
value < 0 ? " (maybe negative?)" : "",
|
||||
|
||||
@@ -25,19 +25,23 @@ enum NumberType {
|
||||
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') {
|
||||
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 int
|
||||
nextLine(std::vector<char> &lineBuf, uint32_t &lineNo, FileStackNode const &where, FILE *file) {
|
||||
static int nextLine(std::vector<char> &lineBuf, Location &where, FILE *file) {
|
||||
int firstChar;
|
||||
for (;;) {
|
||||
++lineNo;
|
||||
++where.lineNo;
|
||||
firstChar = getc(file);
|
||||
lineBuf.clear();
|
||||
|
||||
@@ -46,14 +50,14 @@ static int
|
||||
return EOF;
|
||||
case ';':
|
||||
// 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 {
|
||||
firstChar = getc(file);
|
||||
} while (firstChar != EOF && firstChar != '\r' && firstChar != '\n');
|
||||
[[fallthrough]];
|
||||
case '\r':
|
||||
if (firstChar == '\r' && getc(file) != '\n') {
|
||||
consumeLF(where, lineNo, file);
|
||||
consumeLF(where, file);
|
||||
}
|
||||
[[fallthrough]];
|
||||
case '\n':
|
||||
@@ -67,7 +71,7 @@ static int
|
||||
|
||||
switch (c) {
|
||||
case '\r':
|
||||
consumeLF(where, lineNo, file);
|
||||
consumeLF(where, file);
|
||||
[[fallthrough]];
|
||||
case '\n':
|
||||
case EOF:
|
||||
@@ -79,9 +83,7 @@ static int
|
||||
}
|
||||
|
||||
static uint32_t readNumber(char const *str, char const *&endptr, NumberType base) {
|
||||
uint32_t res = 0;
|
||||
|
||||
for (;;) {
|
||||
for (uint32_t res = 0;;) {
|
||||
static char const *digits = "0123456789ABCDEF";
|
||||
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
|
||||
parseNumber(FileStackNode const &where, uint32_t lineNo, char const *str, NumberType base) {
|
||||
static uint32_t parseNumber(Location const &where, char const *str, NumberType base) {
|
||||
if (str[0] == '\0') {
|
||||
fatal(&where, lineNo, "Expected number, got empty string");
|
||||
fatalAt(where, "Expected number, got empty string");
|
||||
}
|
||||
|
||||
char const *endptr;
|
||||
uint32_t res = readNumber(str, endptr, base);
|
||||
|
||||
if (*endptr != '\0') {
|
||||
fatal(&where, lineNo, "Expected number, got \"%s\"", str);
|
||||
fatalAt(where, "Expected number, got \"%s\"", str);
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
static uint8_t
|
||||
parseByte(FileStackNode const &where, uint32_t lineNo, char const *str, NumberType base) {
|
||||
uint32_t num = parseNumber(where, lineNo, str, base);
|
||||
static uint8_t parseByte(Location const &where, char const *str, NumberType base) {
|
||||
uint32_t num = parseNumber(where, str, base);
|
||||
|
||||
if (num > UINT8_MAX) {
|
||||
fatal(&where, lineNo, "\"%s\" is not a byte", str);
|
||||
fatalAt(where, "\"%s\" is not a byte", str);
|
||||
}
|
||||
return num;
|
||||
}
|
||||
@@ -144,7 +144,9 @@ enum RelocFlags {
|
||||
| 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;
|
||||
line.reserve(256);
|
||||
char const *token;
|
||||
@@ -153,23 +155,22 @@ void sdobj_ReadFile(FileStackNode const &where, FILE *file, std::vector<Symbol>
|
||||
do { \
|
||||
token = strtok((ptr), delim); \
|
||||
if (!token) { \
|
||||
fatal(&where, lineNo, __VA_ARGS__); \
|
||||
fatalAt(where, __VA_ARGS__); \
|
||||
} \
|
||||
} while (0)
|
||||
#define expectEol(...) \
|
||||
do { \
|
||||
token = strtok(nullptr, delim); \
|
||||
if (token) { \
|
||||
fatal(&where, lineNo, __VA_ARGS__); \
|
||||
fatalAt(where, __VA_ARGS__); \
|
||||
} \
|
||||
} while (0)
|
||||
#define expectToken(expected, lineType) \
|
||||
do { \
|
||||
getToken(nullptr, "'%c' line is too short", (lineType)); \
|
||||
if (strcasecmp(token, (expected)) != 0) { \
|
||||
fatal( \
|
||||
&where, \
|
||||
lineNo, \
|
||||
fatalAt( \
|
||||
where, \
|
||||
"Malformed '%c' line: expected \"%s\", got \"%s\"", \
|
||||
(lineType), \
|
||||
(expected), \
|
||||
@@ -178,14 +179,13 @@ void sdobj_ReadFile(FileStackNode const &where, FILE *file, std::vector<Symbol>
|
||||
} \
|
||||
} while (0)
|
||||
|
||||
uint32_t lineNo = 0;
|
||||
int lineType = nextLine(line, lineNo, where, file);
|
||||
int lineType = nextLine(line, where, file);
|
||||
NumberType numberType;
|
||||
|
||||
// The first letter (thus, the line type) identifies the integer type
|
||||
switch (lineType) {
|
||||
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':
|
||||
numberType = HEX;
|
||||
break;
|
||||
@@ -196,9 +196,8 @@ void sdobj_ReadFile(FileStackNode const &where, FILE *file, std::vector<Symbol>
|
||||
numberType = OCT;
|
||||
break;
|
||||
default:
|
||||
fatal(
|
||||
&where,
|
||||
lineNo,
|
||||
fatalAt(
|
||||
where,
|
||||
"This does not look like a SDCC object file (unknown integer format '%c')",
|
||||
lineType
|
||||
);
|
||||
@@ -208,36 +207,36 @@ void sdobj_ReadFile(FileStackNode const &where, FILE *file, std::vector<Symbol>
|
||||
case 'L':
|
||||
break;
|
||||
case 'H':
|
||||
fatal(&where, lineNo, "Big-endian SDCC object files are not supported");
|
||||
fatalAt(where, "Big-endian SDCC object files are not supported");
|
||||
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;
|
||||
|
||||
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') {
|
||||
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
|
||||
|
||||
lineType = nextLine(line, lineNo, where, file);
|
||||
lineType = nextLine(line, where, file);
|
||||
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"
|
||||
|
||||
getToken(line.data(), "Empty 'H' line");
|
||||
uint32_t expectedNbAreas = parseNumber(where, lineNo, token, numberType);
|
||||
uint32_t expectedNbAreas = parseNumber(where, token, numberType);
|
||||
|
||||
expectToken("areas", 'H');
|
||||
|
||||
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);
|
||||
|
||||
expectToken("global", 'H');
|
||||
@@ -256,7 +255,7 @@ void sdobj_ReadFile(FileStackNode const &where, FILE *file, std::vector<Symbol>
|
||||
std::vector<uint8_t> data;
|
||||
|
||||
for (;;) {
|
||||
lineType = nextLine(line, lineNo, where, file);
|
||||
lineType = nextLine(line, where, file);
|
||||
if (lineType == EOF) {
|
||||
break;
|
||||
}
|
||||
@@ -268,21 +267,19 @@ void sdobj_ReadFile(FileStackNode const &where, FILE *file, std::vector<Symbol>
|
||||
|
||||
case 'A': {
|
||||
if (fileSections.size() == expectedNbAreas) {
|
||||
warning(
|
||||
&where, lineNo, "Got more 'A' lines than the expected %" PRIu32, expectedNbAreas
|
||||
);
|
||||
warningAt(where, "Got more 'A' lines than the expected %" PRIu32, expectedNbAreas);
|
||||
}
|
||||
std::unique_ptr<Section> curSection = std::make_unique<Section>();
|
||||
|
||||
curSection->src = &where;
|
||||
curSection->lineNo = lineNo;
|
||||
curSection->src = where.src;
|
||||
curSection->lineNo = where.lineNo;
|
||||
|
||||
getToken(line.data(), "'A' line is too short");
|
||||
assume(strlen(token) != 0); // This should be impossible, tokens are non-empty
|
||||
// The following is required for fragment offsets to be reliably predicted
|
||||
for (FileSection &entry : fileSections) {
|
||||
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
|
||||
@@ -291,12 +288,11 @@ void sdobj_ReadFile(FileStackNode const &where, FILE *file, std::vector<Symbol>
|
||||
|
||||
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) {
|
||||
fatal(
|
||||
&where,
|
||||
lineNo,
|
||||
fatalAt(
|
||||
where,
|
||||
"Area \"%s\" is larger than the GB address space!?",
|
||||
curSection->name.c_str()
|
||||
);
|
||||
@@ -306,9 +302,9 @@ void sdobj_ReadFile(FileStackNode const &where, FILE *file, std::vector<Symbol>
|
||||
expectToken("flags", 'A');
|
||||
|
||||
getToken(nullptr, "'A' line is too short");
|
||||
tmp = parseNumber(where, lineNo, token, numberType);
|
||||
tmp = parseNumber(where, token, numberType);
|
||||
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->isBankFixed = curSection->isAddressFixed;
|
||||
@@ -317,7 +313,7 @@ void sdobj_ReadFile(FileStackNode const &where, FILE *file, std::vector<Symbol>
|
||||
: SECTION_FRAGMENT;
|
||||
// If the section is absolute, its name might not be unique; thus, mangle the name
|
||||
if (curSection->modifier == SECTION_NORMAL) {
|
||||
curSection->name.append(where.name());
|
||||
curSection->name.append(where.src->name());
|
||||
curSection->name.append(" ");
|
||||
}
|
||||
curSection->name.append(sectName);
|
||||
@@ -325,7 +321,7 @@ void sdobj_ReadFile(FileStackNode const &where, FILE *file, std::vector<Symbol>
|
||||
expectToken("addr", 'A');
|
||||
|
||||
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->bank = tmp >> 16;
|
||||
|
||||
@@ -349,7 +345,7 @@ void sdobj_ReadFile(FileStackNode const &where, FILE *file, std::vector<Symbol>
|
||||
} else if (high < 0xE0) {
|
||||
curSection->type = SECTTYPE_WRAMX;
|
||||
} 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) {
|
||||
curSection->type = SECTTYPE_OAM;
|
||||
} else {
|
||||
@@ -368,27 +364,21 @@ void sdobj_ReadFile(FileStackNode const &where, FILE *file, std::vector<Symbol>
|
||||
|
||||
case 'S': {
|
||||
if (fileSymbols.size() == expectedNbSymbols) {
|
||||
error(
|
||||
&where,
|
||||
lineNo,
|
||||
"Got more 'S' lines than the expected %" PRIu32,
|
||||
expectedNbSymbols
|
||||
);
|
||||
errorAt(where, "Got more 'S' lines than the expected %" PRIu32, expectedNbSymbols);
|
||||
break; // Refuse processing the line further.
|
||||
}
|
||||
Symbol &symbol = fileSymbols.emplace_back();
|
||||
|
||||
// Init other members
|
||||
symbol.src = &where;
|
||||
symbol.lineNo = lineNo;
|
||||
symbol.src = where.src;
|
||||
symbol.lineNo = where.lineNo;
|
||||
|
||||
getToken(line.data(), "'S' line is too short");
|
||||
symbol.name = token;
|
||||
|
||||
getToken(nullptr, "'S' line is too short");
|
||||
|
||||
if (int32_t value = parseNumber(where, lineNo, &token[3], numberType);
|
||||
!fileSections.empty()) {
|
||||
if (int32_t value = parseNumber(where, &token[3], numberType); !fileSections.empty()) {
|
||||
// Symbols in sections are labels; their value is an offset
|
||||
Section *section = fileSections.back().section.get();
|
||||
if (section->isAddressFixed) {
|
||||
@@ -408,7 +398,7 @@ void sdobj_ReadFile(FileStackNode const &where, FILE *file, std::vector<Symbol>
|
||||
sym_AddSymbol(symbol);
|
||||
// TODO: hard error if the rest is not zero
|
||||
} 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 {
|
||||
// All symbols are exported
|
||||
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
|
||||
}
|
||||
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()) {
|
||||
@@ -462,16 +452,16 @@ void sdobj_ReadFile(FileStackNode const &where, FILE *file, std::vector<Symbol>
|
||||
case 'T':
|
||||
// Now, time to parse the data!
|
||||
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();
|
||||
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) {
|
||||
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`
|
||||
break;
|
||||
@@ -479,7 +469,7 @@ void sdobj_ReadFile(FileStackNode const &where, FILE *file, std::vector<Symbol>
|
||||
case 'R': {
|
||||
// Supposed to directly follow `T`
|
||||
if (data.empty()) {
|
||||
warning(&where, lineNo, "'R' line with no 'T' line, ignoring");
|
||||
warningAt(where, "'R' line with no 'T' line, ignoring");
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -489,13 +479,12 @@ void sdobj_ReadFile(FileStackNode const &where, FILE *file, std::vector<Symbol>
|
||||
uint16_t areaIdx;
|
||||
|
||||
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");
|
||||
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()) {
|
||||
fatal(
|
||||
&where,
|
||||
lineNo,
|
||||
fatalAt(
|
||||
where,
|
||||
"'R' line references area #%" PRIu16 ", but there are only %zu (so far)",
|
||||
areaIdx,
|
||||
fileSections.size()
|
||||
@@ -509,9 +498,8 @@ void sdobj_ReadFile(FileStackNode const &where, FILE *file, std::vector<Symbol>
|
||||
|
||||
if (section->isAddressFixed) {
|
||||
if (addr < section->org) {
|
||||
fatal(
|
||||
&where,
|
||||
lineNo,
|
||||
fatalAt(
|
||||
where,
|
||||
"'T' line reports address $%04" PRIx16
|
||||
" in \"%s\", which starts at $%04" PRIx16,
|
||||
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.
|
||||
if (data.size() != ADDR_SIZE) {
|
||||
if (addr != *writeIndex) {
|
||||
fatal(
|
||||
&where,
|
||||
lineNo,
|
||||
fatalAt(
|
||||
where,
|
||||
"'T' lines which don't append to their section are not supported (%" PRIu16
|
||||
" != %" PRIu16 ")",
|
||||
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
|
||||
// bytes being patched over.
|
||||
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) {
|
||||
getToken(nullptr, "Incomplete relocation");
|
||||
flags = (flags & 0x0F)
|
||||
| static_cast<uint16_t>(parseByte(where, lineNo, token, numberType))
|
||||
<< 4;
|
||||
| static_cast<uint16_t>(parseByte(where, token, numberType)) << 4;
|
||||
}
|
||||
|
||||
getToken(nullptr, "Incomplete relocation");
|
||||
uint8_t offset = parseByte(where, lineNo, token, numberType);
|
||||
uint8_t offset = parseByte(where, token, numberType);
|
||||
|
||||
if (offset < ADDR_SIZE) {
|
||||
fatal(
|
||||
&where,
|
||||
lineNo,
|
||||
fatalAt(
|
||||
where,
|
||||
"Relocation index cannot point to header (%" PRIu16 " < %u)",
|
||||
offset,
|
||||
ADDR_SIZE
|
||||
);
|
||||
}
|
||||
if (offset >= data.size()) {
|
||||
fatal(
|
||||
&where,
|
||||
lineNo,
|
||||
fatalAt(
|
||||
where,
|
||||
"Relocation index is out of bounds (%" PRIu16 " >= %zu)",
|
||||
offset,
|
||||
data.size()
|
||||
@@ -586,31 +570,30 @@ void sdobj_ReadFile(FileStackNode const &where, FILE *file, std::vector<Symbol>
|
||||
}
|
||||
|
||||
getToken(nullptr, "Incomplete relocation");
|
||||
uint16_t idx = parseByte(where, lineNo, token, numberType);
|
||||
uint16_t idx = parseByte(where, token, numberType);
|
||||
|
||||
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
|
||||
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) {
|
||||
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
|
||||
Patch &patch = section->patches.emplace_back();
|
||||
|
||||
patch.lineNo = lineNo;
|
||||
patch.src = &where;
|
||||
patch.src = where.src;
|
||||
patch.lineNo = where.lineNo;
|
||||
patch.offset = offset - writtenOfs + *writeIndex;
|
||||
if (section->patches.size() > 1) {
|
||||
uint32_t prevOffset = section->patches[section->patches.size() - 2].offset;
|
||||
if (prevOffset >= patch.offset) {
|
||||
fatal(
|
||||
&where,
|
||||
lineNo,
|
||||
fatalAt(
|
||||
where,
|
||||
"Relocs not sorted by offset are not supported (%" PRIu32 " >= %" PRIu32
|
||||
")",
|
||||
prevOffset,
|
||||
@@ -627,9 +610,8 @@ void sdobj_ReadFile(FileStackNode const &where, FILE *file, std::vector<Symbol>
|
||||
|
||||
assume(offset < data.size());
|
||||
if (data.size() - offset < nbBaseBytes) {
|
||||
fatal(
|
||||
&where,
|
||||
lineNo,
|
||||
fatalAt(
|
||||
where,
|
||||
"Reloc would patch out of bounds (%" PRIu8 " > %zu)",
|
||||
nbBaseBytes,
|
||||
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
|
||||
if (flags & 1 << RELOC_ISSYM) {
|
||||
if (idx >= fileSymbols.size()) {
|
||||
fatal(
|
||||
&where,
|
||||
lineNo,
|
||||
fatalAt(
|
||||
where,
|
||||
"Reloc refers to symbol #%" PRIu16 " out of %zu",
|
||||
idx,
|
||||
fileSymbols.size()
|
||||
@@ -665,9 +646,8 @@ void sdobj_ReadFile(FileStackNode const &where, FILE *file, std::vector<Symbol>
|
||||
}
|
||||
}
|
||||
if (idx == fileSymbols.size()) {
|
||||
fatal(
|
||||
&where,
|
||||
lineNo,
|
||||
fatalAt(
|
||||
where,
|
||||
"\"%s\" is missing a reference to \"%s\"",
|
||||
sym.name.c_str(),
|
||||
&sym.name.c_str()[1]
|
||||
@@ -705,9 +685,8 @@ void sdobj_ReadFile(FileStackNode const &where, FILE *file, std::vector<Symbol>
|
||||
}
|
||||
} else {
|
||||
if (idx >= fileSections.size()) {
|
||||
fatal(
|
||||
&where,
|
||||
lineNo,
|
||||
fatalAt(
|
||||
where,
|
||||
"Reloc refers to area #%" PRIu16 " out of %zu",
|
||||
idx,
|
||||
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
|
||||
if (flags & 1 << RELOC_EXPR16) {
|
||||
if (*writeIndex + (offset - writtenOfs) > section->size) {
|
||||
fatal(
|
||||
&where,
|
||||
lineNo,
|
||||
fatalAt(
|
||||
where,
|
||||
"'T' line writes past \"%s\"'s end (%u > %" PRIu16 ")",
|
||||
section->name.c_str(),
|
||||
*writeIndex + (offset - writtenOfs),
|
||||
@@ -810,11 +788,10 @@ void sdobj_ReadFile(FileStackNode const &where, FILE *file, std::vector<Symbol>
|
||||
}
|
||||
} else if (flags & 1 << RELOC_ISPCREL) {
|
||||
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)) {
|
||||
fatal(
|
||||
&where,
|
||||
lineNo,
|
||||
fatalAt(
|
||||
where,
|
||||
"Flags 0x%x are not supported for 16-bit relocs",
|
||||
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()) {
|
||||
assume(data.size() > writtenOfs);
|
||||
if (*writeIndex + (data.size() - writtenOfs) > section->size) {
|
||||
fatal(
|
||||
&where,
|
||||
lineNo,
|
||||
fatalAt(
|
||||
where,
|
||||
"'T' line writes past \"%s\"'s end (%zu > %" PRIu16 ")",
|
||||
section->name.c_str(),
|
||||
*writeIndex + (data.size() - writtenOfs),
|
||||
@@ -844,7 +820,7 @@ void sdobj_ReadFile(FileStackNode const &where, FILE *file, std::vector<Symbol>
|
||||
|
||||
case 'P':
|
||||
default:
|
||||
warning(&where, lineNo, "Unknown/unsupported line type '%c', ignoring", lineType);
|
||||
warningAt(where, "Unknown/unsupported line type '%c', ignoring", lineType);
|
||||
break;
|
||||
}
|
||||
}
|
||||
@@ -854,21 +830,19 @@ void sdobj_ReadFile(FileStackNode const &where, FILE *file, std::vector<Symbol>
|
||||
#undef getToken
|
||||
|
||||
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) {
|
||||
warning(
|
||||
&where,
|
||||
lineNo,
|
||||
warningAt(
|
||||
where,
|
||||
"Expected %" PRIu32 " 'A' lines, got only %zu",
|
||||
expectedNbAreas,
|
||||
fileSections.size()
|
||||
);
|
||||
}
|
||||
if (fileSymbols.size() < expectedNbSymbols) {
|
||||
warning(
|
||||
&where,
|
||||
lineNo,
|
||||
warningAt(
|
||||
where,
|
||||
"Expected %" PRIu32 " 'S' lines, got only %zu",
|
||||
expectedNbSymbols,
|
||||
fileSymbols.size()
|
||||
@@ -888,9 +862,8 @@ void sdobj_ReadFile(FileStackNode const &where, FILE *file, std::vector<Symbol>
|
||||
|
||||
if (!sect_HasData(section->type)) {
|
||||
if (!section->data.empty()) {
|
||||
fatal(
|
||||
&where,
|
||||
lineNo,
|
||||
fatalAt(
|
||||
where,
|
||||
"\"%s\" is implicitly defined as a %s section (being at address $%04" PRIx16
|
||||
"), but it has data! (Was a bad `__at()` value used?)",
|
||||
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()) {
|
||||
fatal(
|
||||
&where,
|
||||
lineNo,
|
||||
fatalAt(
|
||||
where,
|
||||
"\"%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?)",
|
||||
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) {
|
||||
fatal(
|
||||
&where,
|
||||
lineNo,
|
||||
fatalAt(
|
||||
where,
|
||||
"\"%s\" was not fully written (%" PRIu16 " < %" PRIu16 ")",
|
||||
section->name.c_str(),
|
||||
entry.writeIndex,
|
||||
|
||||
@@ -10,11 +10,11 @@
|
||||
static uint32_t nbErrors = 0;
|
||||
|
||||
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);
|
||||
if (where) {
|
||||
where->dump(lineNo);
|
||||
if (src) {
|
||||
src->dump(lineNo);
|
||||
fputs(": ", stderr);
|
||||
}
|
||||
vfprintf(stderr, fmt, args);
|
||||
@@ -39,10 +39,10 @@ static void abortLinking(char const *verb) {
|
||||
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_start(args, fmt);
|
||||
printDiag(where, lineNo, fmt, args, "warning");
|
||||
printDiag(src, lineNo, fmt, args, "warning");
|
||||
va_end(args);
|
||||
}
|
||||
|
||||
@@ -53,10 +53,10 @@ void warning(char const *fmt, ...) {
|
||||
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_start(args, fmt);
|
||||
printDiag(where, lineNo, fmt, args, "error");
|
||||
printDiag(src, lineNo, fmt, args, "error");
|
||||
va_end(args);
|
||||
|
||||
incrementErrors();
|
||||
@@ -93,10 +93,10 @@ void argErr(char flag, char const *fmt, ...) {
|
||||
}
|
||||
|
||||
[[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_start(args, fmt);
|
||||
printDiag(where, lineNo, fmt, args, "FATAL");
|
||||
printDiag(src, lineNo, fmt, args, "FATAL");
|
||||
va_end(args);
|
||||
|
||||
incrementErrors();
|
||||
|
||||
Reference in New Issue
Block a user