mirror of
https://github.com/gbdev/rgbds.git
synced 2025-11-20 18:22:07 +00:00
Use a Defer struct to close files and restore lexer state with RAII (#1379)
This commit is contained in:
@@ -86,4 +86,12 @@ static inline int clz(unsigned int x) {
|
|||||||
// For lack of <ranges>, this adds some more brevity
|
// For lack of <ranges>, this adds some more brevity
|
||||||
#define RANGE(s) std::begin(s), std::end(s)
|
#define RANGE(s) std::begin(s), std::end(s)
|
||||||
|
|
||||||
|
// For ad-hoc RAII in place of a `defer` statement or cross-platform `__attribute__((cleanup))`
|
||||||
|
template<typename T>
|
||||||
|
struct Defer {
|
||||||
|
T deferred;
|
||||||
|
Defer(T func) : deferred(func) {}
|
||||||
|
~Defer() { deferred(); }
|
||||||
|
};
|
||||||
|
|
||||||
#endif // HELPERS_H
|
#endif // HELPERS_H
|
||||||
|
|||||||
@@ -1,7 +1,6 @@
|
|||||||
/* SPDX-License-Identifier: MIT */
|
/* SPDX-License-Identifier: MIT */
|
||||||
|
|
||||||
#include "asm/fstack.hpp"
|
#include "asm/fstack.hpp"
|
||||||
|
|
||||||
#include <sys/stat.h>
|
#include <sys/stat.h>
|
||||||
|
|
||||||
#include <assert.h>
|
#include <assert.h>
|
||||||
|
|||||||
@@ -90,6 +90,8 @@ static void mapFile(void *&mappingAddr, int fd, std::string const &path, size_t
|
|||||||
|
|
||||||
#endif // !( defined(_MSC_VER) || defined(__MINGW32__) )
|
#endif // !( defined(_MSC_VER) || defined(__MINGW32__) )
|
||||||
|
|
||||||
|
using namespace std::literals;
|
||||||
|
|
||||||
// Bison 3.6 changed token "types" to "kinds"; cast to int for simple compatibility
|
// Bison 3.6 changed token "types" to "kinds"; cast to int for simple compatibility
|
||||||
#define T_(name) (int)yy::parser::token::name
|
#define T_(name) (int)yy::parser::token::name
|
||||||
|
|
||||||
@@ -526,9 +528,12 @@ static bool continuesIdentifier(int c);
|
|||||||
static uint32_t readBracketedMacroArgNum() {
|
static uint32_t readBracketedMacroArgNum() {
|
||||||
bool disableMacroArgs = lexerState->disableMacroArgs;
|
bool disableMacroArgs = lexerState->disableMacroArgs;
|
||||||
bool disableInterpolation = lexerState->disableInterpolation;
|
bool disableInterpolation = lexerState->disableInterpolation;
|
||||||
|
|
||||||
lexerState->disableMacroArgs = false;
|
lexerState->disableMacroArgs = false;
|
||||||
lexerState->disableInterpolation = false;
|
lexerState->disableInterpolation = false;
|
||||||
|
Defer restoreExpansions{[&] {
|
||||||
|
lexerState->disableMacroArgs = disableMacroArgs;
|
||||||
|
lexerState->disableInterpolation = disableInterpolation;
|
||||||
|
}};
|
||||||
|
|
||||||
uint32_t num = 0;
|
uint32_t num = 0;
|
||||||
int c = peek();
|
int c = peek();
|
||||||
@@ -573,11 +578,9 @@ static uint32_t readBracketedMacroArgNum() {
|
|||||||
} else if (num == 0 && !symbolError) {
|
} else if (num == 0 && !symbolError) {
|
||||||
error("Invalid bracketed macro argument '\\<0>'\n");
|
error("Invalid bracketed macro argument '\\<0>'\n");
|
||||||
return 0;
|
return 0;
|
||||||
}
|
} else {
|
||||||
|
|
||||||
lexerState->disableMacroArgs = disableMacroArgs;
|
|
||||||
lexerState->disableInterpolation = disableInterpolation;
|
|
||||||
return num;
|
return num;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static std::shared_ptr<std::string> readMacroArg(char name) {
|
static std::shared_ptr<std::string> readMacroArg(char name) {
|
||||||
@@ -817,6 +820,15 @@ static void handleCRLF(int c) {
|
|||||||
shiftChar();
|
shiftChar();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static auto scopedDisableExpansions() {
|
||||||
|
lexerState->disableMacroArgs = true;
|
||||||
|
lexerState->disableInterpolation = true;
|
||||||
|
return Defer{[&] {
|
||||||
|
lexerState->disableMacroArgs = false;
|
||||||
|
lexerState->disableInterpolation = false;
|
||||||
|
}};
|
||||||
|
}
|
||||||
|
|
||||||
// "Services" provided by the lexer to the rest of the program
|
// "Services" provided by the lexer to the rest of the program
|
||||||
|
|
||||||
uint32_t lexer_GetLineNo() {
|
uint32_t lexer_GetLineNo() {
|
||||||
@@ -841,15 +853,14 @@ void lexer_DumpStringExpansions() {
|
|||||||
// Functions to discard non-tokenized characters
|
// Functions to discard non-tokenized characters
|
||||||
|
|
||||||
static void discardBlockComment() {
|
static void discardBlockComment() {
|
||||||
lexerState->disableMacroArgs = true;
|
Defer reenableExpansions = scopedDisableExpansions();
|
||||||
lexerState->disableInterpolation = true;
|
|
||||||
for (;;) {
|
for (;;) {
|
||||||
int c = nextChar();
|
int c = nextChar();
|
||||||
|
|
||||||
switch (c) {
|
switch (c) {
|
||||||
case EOF:
|
case EOF:
|
||||||
error("Unterminated block comment\n");
|
error("Unterminated block comment\n");
|
||||||
goto finish;
|
return;
|
||||||
case '\r':
|
case '\r':
|
||||||
// Handle CRLF before nextLine() since shiftChar updates colNo
|
// Handle CRLF before nextLine() since shiftChar updates colNo
|
||||||
handleCRLF(c);
|
handleCRLF(c);
|
||||||
@@ -866,29 +877,23 @@ static void discardBlockComment() {
|
|||||||
case '*':
|
case '*':
|
||||||
if (peek() == '/') {
|
if (peek() == '/') {
|
||||||
shiftChar();
|
shiftChar();
|
||||||
goto finish;
|
return;
|
||||||
}
|
}
|
||||||
// fallthrough
|
// fallthrough
|
||||||
default:
|
default:
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
finish:
|
|
||||||
lexerState->disableMacroArgs = false;
|
|
||||||
lexerState->disableInterpolation = false;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void discardComment() {
|
static void discardComment() {
|
||||||
lexerState->disableMacroArgs = true;
|
Defer reenableExpansions = scopedDisableExpansions();
|
||||||
lexerState->disableInterpolation = true;
|
|
||||||
for (;; shiftChar()) {
|
for (;; shiftChar()) {
|
||||||
int c = peek();
|
int c = peek();
|
||||||
|
|
||||||
if (c == EOF || c == '\r' || c == '\n')
|
if (c == EOF || c == '\r' || c == '\n')
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
lexerState->disableMacroArgs = false;
|
|
||||||
lexerState->disableInterpolation = false;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void discardLineContinuation() {
|
static void discardLineContinuation() {
|
||||||
@@ -1229,13 +1234,10 @@ static void appendEscapedSubstring(std::string &yylval, std::string const &str)
|
|||||||
}
|
}
|
||||||
|
|
||||||
static std::string readString(bool raw) {
|
static std::string readString(bool raw) {
|
||||||
lexerState->disableMacroArgs = true;
|
Defer reenableExpansions = scopedDisableExpansions();
|
||||||
lexerState->disableInterpolation = true;
|
|
||||||
|
|
||||||
std::string yylval;
|
|
||||||
bool multiline = false;
|
|
||||||
|
|
||||||
// We reach this function after reading a single quote, but we also support triple quotes
|
// We reach this function after reading a single quote, but we also support triple quotes
|
||||||
|
bool multiline = false;
|
||||||
if (peek() == '"') {
|
if (peek() == '"') {
|
||||||
shiftChar();
|
shiftChar();
|
||||||
if (peek() == '"') {
|
if (peek() == '"') {
|
||||||
@@ -1244,17 +1246,17 @@ static std::string readString(bool raw) {
|
|||||||
multiline = true;
|
multiline = true;
|
||||||
} else {
|
} else {
|
||||||
// "" is an empty string, skip the loop
|
// "" is an empty string, skip the loop
|
||||||
goto finish;
|
return ""s;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
for (;;) {
|
for (std::string yylval = ""s;;) {
|
||||||
int c = peek();
|
int c = peek();
|
||||||
|
|
||||||
// '\r', '\n' or EOF ends a single-line string early
|
// '\r', '\n' or EOF ends a single-line string early
|
||||||
if (c == EOF || (!multiline && (c == '\r' || c == '\n'))) {
|
if (c == EOF || (!multiline && (c == '\r' || c == '\n'))) {
|
||||||
error("Unterminated string\n");
|
error("Unterminated string\n");
|
||||||
break;
|
return yylval;
|
||||||
}
|
}
|
||||||
|
|
||||||
// We'll be staying in the string, so we can safely consume the char
|
// We'll be staying in the string, so we can safely consume the char
|
||||||
@@ -1281,7 +1283,7 @@ static std::string readString(bool raw) {
|
|||||||
}
|
}
|
||||||
shiftChar();
|
shiftChar();
|
||||||
}
|
}
|
||||||
goto finish;
|
return yylval;
|
||||||
|
|
||||||
case '\\': // Character escape or macro arg
|
case '\\': // Character escape or macro arg
|
||||||
if (raw)
|
if (raw)
|
||||||
@@ -1364,21 +1366,13 @@ static std::string readString(bool raw) {
|
|||||||
|
|
||||||
yylval += c;
|
yylval += c;
|
||||||
}
|
}
|
||||||
|
|
||||||
finish:
|
|
||||||
lexerState->disableMacroArgs = false;
|
|
||||||
lexerState->disableInterpolation = false;
|
|
||||||
|
|
||||||
return yylval;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void appendStringLiteral(std::string &yylval, bool raw) {
|
static void appendStringLiteral(std::string &yylval, bool raw) {
|
||||||
lexerState->disableMacroArgs = true;
|
Defer reenableExpansions = scopedDisableExpansions();
|
||||||
lexerState->disableInterpolation = true;
|
|
||||||
|
|
||||||
bool multiline = false;
|
|
||||||
|
|
||||||
// We reach this function after reading a single quote, but we also support triple quotes
|
// We reach this function after reading a single quote, but we also support triple quotes
|
||||||
|
bool multiline = false;
|
||||||
yylval += '"';
|
yylval += '"';
|
||||||
if (peek() == '"') {
|
if (peek() == '"') {
|
||||||
yylval += '"';
|
yylval += '"';
|
||||||
@@ -1390,7 +1384,7 @@ static void appendStringLiteral(std::string &yylval, bool raw) {
|
|||||||
multiline = true;
|
multiline = true;
|
||||||
} else {
|
} else {
|
||||||
// "" is an empty string, skip the loop
|
// "" is an empty string, skip the loop
|
||||||
goto finish;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1400,7 +1394,7 @@ static void appendStringLiteral(std::string &yylval, bool raw) {
|
|||||||
// '\r', '\n' or EOF ends a single-line string early
|
// '\r', '\n' or EOF ends a single-line string early
|
||||||
if (c == EOF || (!multiline && (c == '\r' || c == '\n'))) {
|
if (c == EOF || (!multiline && (c == '\r' || c == '\n'))) {
|
||||||
error("Unterminated string\n");
|
error("Unterminated string\n");
|
||||||
break;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// We'll be staying in the string, so we can safely consume the char
|
// We'll be staying in the string, so we can safely consume the char
|
||||||
@@ -1428,7 +1422,7 @@ static void appendStringLiteral(std::string &yylval, bool raw) {
|
|||||||
shiftChar();
|
shiftChar();
|
||||||
}
|
}
|
||||||
yylval += '"';
|
yylval += '"';
|
||||||
goto finish;
|
return;
|
||||||
|
|
||||||
case '\\': // Character escape or macro arg
|
case '\\': // Character escape or macro arg
|
||||||
if (raw)
|
if (raw)
|
||||||
@@ -1506,10 +1500,6 @@ static void appendStringLiteral(std::string &yylval, bool raw) {
|
|||||||
|
|
||||||
yylval += c;
|
yylval += c;
|
||||||
}
|
}
|
||||||
|
|
||||||
finish:
|
|
||||||
lexerState->disableMacroArgs = false;
|
|
||||||
lexerState->disableInterpolation = false;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Lexer core
|
// Lexer core
|
||||||
@@ -1981,12 +1971,11 @@ finish:
|
|||||||
static Token skipIfBlock(bool toEndc) {
|
static Token skipIfBlock(bool toEndc) {
|
||||||
lexer_SetMode(LEXER_NORMAL);
|
lexer_SetMode(LEXER_NORMAL);
|
||||||
uint32_t startingDepth = lexer_GetIFDepth();
|
uint32_t startingDepth = lexer_GetIFDepth();
|
||||||
Token token;
|
|
||||||
bool atLineStart = lexerState->atLineStart;
|
|
||||||
|
|
||||||
// Prevent expanding macro args and symbol interpolation in this state
|
bool atLineStart = lexerState->atLineStart;
|
||||||
lexerState->disableMacroArgs = true;
|
Defer notAtLineStart{[&] { lexerState->atLineStart = false; }};
|
||||||
lexerState->disableInterpolation = true;
|
|
||||||
|
Defer reenableExpansions = scopedDisableExpansions();
|
||||||
|
|
||||||
for (;;) {
|
for (;;) {
|
||||||
if (atLineStart) {
|
if (atLineStart) {
|
||||||
@@ -2000,8 +1989,7 @@ static Token skipIfBlock(bool toEndc) {
|
|||||||
|
|
||||||
if (startsIdentifier(c)) {
|
if (startsIdentifier(c)) {
|
||||||
shiftChar();
|
shiftChar();
|
||||||
token = readIdentifier(c);
|
switch (Token token = readIdentifier(c); token.type) {
|
||||||
switch (token.type) {
|
|
||||||
case T_(POP_IF):
|
case T_(POP_IF):
|
||||||
lexer_IncIFDepth();
|
lexer_IncIFDepth();
|
||||||
break;
|
break;
|
||||||
@@ -2010,7 +1998,7 @@ static Token skipIfBlock(bool toEndc) {
|
|||||||
if (lexer_ReachedELSEBlock())
|
if (lexer_ReachedELSEBlock())
|
||||||
fatalerror("Found ELIF after an ELSE block\n");
|
fatalerror("Found ELIF after an ELSE block\n");
|
||||||
if (!toEndc && lexer_GetIFDepth() == startingDepth)
|
if (!toEndc && lexer_GetIFDepth() == startingDepth)
|
||||||
goto finish;
|
return token;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case T_(POP_ELSE):
|
case T_(POP_ELSE):
|
||||||
@@ -2018,12 +2006,12 @@ static Token skipIfBlock(bool toEndc) {
|
|||||||
fatalerror("Found ELSE after an ELSE block\n");
|
fatalerror("Found ELSE after an ELSE block\n");
|
||||||
lexer_ReachELSEBlock();
|
lexer_ReachELSEBlock();
|
||||||
if (!toEndc && lexer_GetIFDepth() == startingDepth)
|
if (!toEndc && lexer_GetIFDepth() == startingDepth)
|
||||||
goto finish;
|
return token;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case T_(POP_ENDC):
|
case T_(POP_ENDC):
|
||||||
if (lexer_GetIFDepth() == startingDepth)
|
if (lexer_GetIFDepth() == startingDepth)
|
||||||
goto finish;
|
return token;
|
||||||
lexer_DecIFDepth();
|
lexer_DecIFDepth();
|
||||||
break;
|
break;
|
||||||
|
|
||||||
@@ -2039,8 +2027,7 @@ static Token skipIfBlock(bool toEndc) {
|
|||||||
int c = nextChar();
|
int c = nextChar();
|
||||||
|
|
||||||
if (c == EOF) {
|
if (c == EOF) {
|
||||||
token = Token(T_(YYEOF));
|
return Token(T_(YYEOF));
|
||||||
goto finish;
|
|
||||||
} else if (c == '\\') {
|
} else if (c == '\\') {
|
||||||
// Unconditionally skip the next char, including line continuations
|
// Unconditionally skip the next char, including line continuations
|
||||||
c = nextChar();
|
c = nextChar();
|
||||||
@@ -2056,13 +2043,6 @@ static Token skipIfBlock(bool toEndc) {
|
|||||||
}
|
}
|
||||||
} while (!atLineStart);
|
} while (!atLineStart);
|
||||||
}
|
}
|
||||||
|
|
||||||
finish:
|
|
||||||
lexerState->disableMacroArgs = false;
|
|
||||||
lexerState->disableInterpolation = false;
|
|
||||||
lexerState->atLineStart = false;
|
|
||||||
|
|
||||||
return token;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static Token yylex_SKIP_TO_ELIF() {
|
static Token yylex_SKIP_TO_ELIF() {
|
||||||
@@ -2076,11 +2056,11 @@ static Token yylex_SKIP_TO_ENDC() {
|
|||||||
static Token yylex_SKIP_TO_ENDR() {
|
static Token yylex_SKIP_TO_ENDR() {
|
||||||
lexer_SetMode(LEXER_NORMAL);
|
lexer_SetMode(LEXER_NORMAL);
|
||||||
int depth = 1;
|
int depth = 1;
|
||||||
bool atLineStart = lexerState->atLineStart;
|
|
||||||
|
|
||||||
// Prevent expanding macro args and symbol interpolation in this state
|
bool atLineStart = lexerState->atLineStart;
|
||||||
lexerState->disableMacroArgs = true;
|
Defer notAtLineStart{[&] { lexerState->atLineStart = false; }};
|
||||||
lexerState->disableInterpolation = true;
|
|
||||||
|
Defer reenableExpansions = scopedDisableExpansions();
|
||||||
|
|
||||||
for (;;) {
|
for (;;) {
|
||||||
if (atLineStart) {
|
if (atLineStart) {
|
||||||
@@ -2104,7 +2084,7 @@ static Token yylex_SKIP_TO_ENDR() {
|
|||||||
case T_(POP_ENDR):
|
case T_(POP_ENDR):
|
||||||
depth--;
|
depth--;
|
||||||
if (!depth)
|
if (!depth)
|
||||||
goto finish;
|
return Token(T_(YYEOF)); // yywrap() will finish the REPT/FOR loop
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case T_(POP_IF):
|
case T_(POP_IF):
|
||||||
@@ -2127,7 +2107,7 @@ static Token yylex_SKIP_TO_ENDR() {
|
|||||||
int c = nextChar();
|
int c = nextChar();
|
||||||
|
|
||||||
if (c == EOF) {
|
if (c == EOF) {
|
||||||
goto finish;
|
return Token(T_(YYEOF));
|
||||||
} else if (c == '\\') {
|
} else if (c == '\\') {
|
||||||
// Unconditionally skip the next char, including line continuations
|
// Unconditionally skip the next char, including line continuations
|
||||||
c = nextChar();
|
c = nextChar();
|
||||||
@@ -2143,14 +2123,6 @@ static Token yylex_SKIP_TO_ENDR() {
|
|||||||
}
|
}
|
||||||
} while (!atLineStart);
|
} while (!atLineStart);
|
||||||
}
|
}
|
||||||
|
|
||||||
finish:
|
|
||||||
lexerState->disableMacroArgs = false;
|
|
||||||
lexerState->disableInterpolation = false;
|
|
||||||
lexerState->atLineStart = false;
|
|
||||||
|
|
||||||
// yywrap() will finish the REPT/FOR loop
|
|
||||||
return Token(T_(YYEOF));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
yy::parser::symbol_type yylex() {
|
yy::parser::symbol_type yylex() {
|
||||||
@@ -2195,11 +2167,9 @@ static Capture startCapture() {
|
|||||||
// The following assertion checks that.
|
// The following assertion checks that.
|
||||||
assert(lexerState->atLineStart);
|
assert(lexerState->atLineStart);
|
||||||
|
|
||||||
assert(!lexerState->capturing);
|
assert(!lexerState->capturing && lexerState->captureBuf == nullptr);
|
||||||
lexerState->capturing = true;
|
lexerState->capturing = true;
|
||||||
lexerState->captureSize = 0;
|
lexerState->captureSize = 0;
|
||||||
lexerState->disableMacroArgs = true;
|
|
||||||
lexerState->disableInterpolation = true;
|
|
||||||
|
|
||||||
Capture capture = {.lineNo = lexer_GetLineNo(), .body = nullptr, .size = 0};
|
Capture capture = {.lineNo = lexer_GetLineNo(), .body = nullptr, .size = 0};
|
||||||
if (auto *mmap = std::get_if<MmappedContent>(&lexerState->content);
|
if (auto *mmap = std::get_if<MmappedContent>(&lexerState->content);
|
||||||
@@ -2231,13 +2201,13 @@ static void endCapture(Capture &capture) {
|
|||||||
|
|
||||||
lexerState->capturing = false;
|
lexerState->capturing = false;
|
||||||
lexerState->captureBuf = nullptr;
|
lexerState->captureBuf = nullptr;
|
||||||
lexerState->disableMacroArgs = false;
|
|
||||||
lexerState->disableInterpolation = false;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Capture lexer_CaptureRept() {
|
Capture lexer_CaptureRept() {
|
||||||
Capture capture = startCapture();
|
Capture capture = startCapture();
|
||||||
|
|
||||||
|
Defer reenableExpansions = scopedDisableExpansions();
|
||||||
|
|
||||||
size_t depth = 0;
|
size_t depth = 0;
|
||||||
int c = EOF;
|
int c = EOF;
|
||||||
|
|
||||||
@@ -2258,10 +2228,11 @@ Capture lexer_CaptureRept() {
|
|||||||
|
|
||||||
case T_(POP_ENDR):
|
case T_(POP_ENDR):
|
||||||
if (!depth) {
|
if (!depth) {
|
||||||
|
endCapture(capture);
|
||||||
// The final ENDR has been captured, but we don't want it!
|
// The final ENDR has been captured, but we don't want it!
|
||||||
// We know we have read exactly "ENDR", not e.g. an EQUS
|
// We know we have read exactly "ENDR", not e.g. an EQUS
|
||||||
lexerState->captureSize -= strlen("ENDR");
|
capture.size -= strlen("ENDR");
|
||||||
goto finish;
|
return capture;
|
||||||
}
|
}
|
||||||
depth--;
|
depth--;
|
||||||
break;
|
break;
|
||||||
@@ -2275,26 +2246,22 @@ Capture lexer_CaptureRept() {
|
|||||||
for (;; c = nextChar()) {
|
for (;; c = nextChar()) {
|
||||||
if (c == EOF) {
|
if (c == EOF) {
|
||||||
error("Unterminated REPT/FOR block\n");
|
error("Unterminated REPT/FOR block\n");
|
||||||
goto finish;
|
endCapture(capture);
|
||||||
|
capture.body = nullptr; // Indicates that it reached EOF before an ENDR
|
||||||
|
return capture;
|
||||||
} else if (c == '\n' || c == '\r') {
|
} else if (c == '\n' || c == '\r') {
|
||||||
handleCRLF(c);
|
handleCRLF(c);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
finish:
|
|
||||||
endCapture(capture);
|
|
||||||
|
|
||||||
if (c == EOF)
|
|
||||||
capture.body = nullptr; // Indicates that it reached EOF before an ENDR terminated it
|
|
||||||
|
|
||||||
return capture;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Capture lexer_CaptureMacro() {
|
Capture lexer_CaptureMacro() {
|
||||||
Capture capture = startCapture();
|
Capture capture = startCapture();
|
||||||
|
|
||||||
|
Defer reenableExpansions = scopedDisableExpansions();
|
||||||
|
|
||||||
// If the file is `mmap`ed, we need not to unmap it to keep access to the macro
|
// If the file is `mmap`ed, we need not to unmap it to keep access to the macro
|
||||||
if (auto *mmap = std::get_if<MmappedContent>(&lexerState->content); mmap)
|
if (auto *mmap = std::get_if<MmappedContent>(&lexerState->content); mmap)
|
||||||
mmap->isReferenced = true;
|
mmap->isReferenced = true;
|
||||||
@@ -2311,10 +2278,11 @@ Capture lexer_CaptureMacro() {
|
|||||||
if (startsIdentifier(c)) {
|
if (startsIdentifier(c)) {
|
||||||
switch (readIdentifier(c).type) {
|
switch (readIdentifier(c).type) {
|
||||||
case T_(POP_ENDM):
|
case T_(POP_ENDM):
|
||||||
|
endCapture(capture);
|
||||||
// The ENDM has been captured, but we don't want it!
|
// The ENDM has been captured, but we don't want it!
|
||||||
// We know we have read exactly "ENDM", not e.g. an EQUS
|
// We know we have read exactly "ENDM", not e.g. an EQUS
|
||||||
lexerState->captureSize -= strlen("ENDM");
|
capture.size -= strlen("ENDM");
|
||||||
goto finish;
|
return capture;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
break;
|
break;
|
||||||
@@ -2325,19 +2293,13 @@ Capture lexer_CaptureMacro() {
|
|||||||
for (;; c = nextChar()) {
|
for (;; c = nextChar()) {
|
||||||
if (c == EOF) {
|
if (c == EOF) {
|
||||||
error("Unterminated macro definition\n");
|
error("Unterminated macro definition\n");
|
||||||
goto finish;
|
endCapture(capture);
|
||||||
|
capture.body = nullptr; // Indicates that it reached EOF before an ENDM
|
||||||
|
return capture;
|
||||||
} else if (c == '\n' || c == '\r') {
|
} else if (c == '\n' || c == '\r') {
|
||||||
handleCRLF(c);
|
handleCRLF(c);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
finish:
|
|
||||||
endCapture(capture);
|
|
||||||
|
|
||||||
if (c == EOF)
|
|
||||||
capture.body = nullptr; // Indicates that it reached EOF before an ENDM terminated it
|
|
||||||
|
|
||||||
return capture;
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -12,6 +12,7 @@
|
|||||||
#include <vector>
|
#include <vector>
|
||||||
|
|
||||||
#include "error.hpp"
|
#include "error.hpp"
|
||||||
|
#include "helpers.hpp" // Defer
|
||||||
|
|
||||||
#include "asm/fstack.hpp"
|
#include "asm/fstack.hpp"
|
||||||
#include "asm/lexer.hpp"
|
#include "asm/lexer.hpp"
|
||||||
@@ -304,7 +305,6 @@ static void writeFileStackNode(FileStackNode const &node, FILE *file) {
|
|||||||
// Write an objectfile
|
// Write an objectfile
|
||||||
void out_WriteObject() {
|
void out_WriteObject() {
|
||||||
FILE *file;
|
FILE *file;
|
||||||
|
|
||||||
if (objectName != "-") {
|
if (objectName != "-") {
|
||||||
file = fopen(objectName.c_str(), "wb");
|
file = fopen(objectName.c_str(), "wb");
|
||||||
} else {
|
} else {
|
||||||
@@ -313,6 +313,7 @@ void out_WriteObject() {
|
|||||||
}
|
}
|
||||||
if (!file)
|
if (!file)
|
||||||
err("Failed to open object file '%s'", objectName.c_str());
|
err("Failed to open object file '%s'", objectName.c_str());
|
||||||
|
Defer closeFile{[&] { fclose(file); }};
|
||||||
|
|
||||||
// Also write symbols that weren't written above
|
// Also write symbols that weren't written above
|
||||||
sym_ForEach(registerUnregisteredSymbol);
|
sym_ForEach(registerUnregisteredSymbol);
|
||||||
@@ -349,8 +350,6 @@ void out_WriteObject() {
|
|||||||
|
|
||||||
for (Assertion &assert : assertions)
|
for (Assertion &assert : assertions)
|
||||||
writeassert(assert, file);
|
writeassert(assert, file);
|
||||||
|
|
||||||
fclose(file);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Set the objectfilename
|
// Set the objectfilename
|
||||||
|
|||||||
@@ -833,8 +833,9 @@ void sect_BinaryFile(std::string const &name, int32_t startPos) {
|
|||||||
if (!checkcodesection())
|
if (!checkcodesection())
|
||||||
return;
|
return;
|
||||||
|
|
||||||
std::optional<std::string> fullPath = fstk_FindFile(name);
|
FILE *file = nullptr;
|
||||||
FILE *file = fullPath ? fopen(fullPath->c_str(), "rb") : nullptr;
|
if (std::optional<std::string> fullPath = fstk_FindFile(name); fullPath)
|
||||||
|
file = fopen(fullPath->c_str(), "rb");
|
||||||
if (!file) {
|
if (!file) {
|
||||||
if (generatedMissingIncludes) {
|
if (generatedMissingIncludes) {
|
||||||
if (verbose)
|
if (verbose)
|
||||||
@@ -845,6 +846,7 @@ void sect_BinaryFile(std::string const &name, int32_t startPos) {
|
|||||||
error("Error opening INCBIN file '%s': %s\n", name.c_str(), strerror(errno));
|
error("Error opening INCBIN file '%s': %s\n", name.c_str(), strerror(errno));
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
Defer closeFile{[&] { fclose(file); }};
|
||||||
|
|
||||||
int32_t fsize = -1;
|
int32_t fsize = -1;
|
||||||
int byte;
|
int byte;
|
||||||
@@ -854,12 +856,12 @@ void sect_BinaryFile(std::string const &name, int32_t startPos) {
|
|||||||
|
|
||||||
if (startPos > fsize) {
|
if (startPos > fsize) {
|
||||||
error("Specified start position is greater than length of file\n");
|
error("Specified start position is greater than length of file\n");
|
||||||
goto cleanup;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
fseek(file, startPos, SEEK_SET);
|
fseek(file, startPos, SEEK_SET);
|
||||||
if (!reserveSpace(fsize - startPos))
|
if (!reserveSpace(fsize - startPos))
|
||||||
goto cleanup;
|
return;
|
||||||
} else {
|
} else {
|
||||||
if (errno != ESPIPE)
|
if (errno != ESPIPE)
|
||||||
error(
|
error(
|
||||||
@@ -878,9 +880,6 @@ void sect_BinaryFile(std::string const &name, int32_t startPos) {
|
|||||||
|
|
||||||
if (ferror(file))
|
if (ferror(file))
|
||||||
error("Error reading INCBIN file '%s': %s\n", name.c_str(), strerror(errno));
|
error("Error reading INCBIN file '%s': %s\n", name.c_str(), strerror(errno));
|
||||||
|
|
||||||
cleanup:
|
|
||||||
fclose(file);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void sect_BinaryFileSlice(std::string const &name, int32_t startPos, int32_t length) {
|
void sect_BinaryFileSlice(std::string const &name, int32_t startPos, int32_t length) {
|
||||||
@@ -901,8 +900,9 @@ void sect_BinaryFileSlice(std::string const &name, int32_t startPos, int32_t len
|
|||||||
if (!reserveSpace(length))
|
if (!reserveSpace(length))
|
||||||
return;
|
return;
|
||||||
|
|
||||||
std::optional<std::string> fullPath = fstk_FindFile(name);
|
FILE *file = nullptr;
|
||||||
FILE *file = fullPath ? fopen(fullPath->c_str(), "rb") : nullptr;
|
if (std::optional<std::string> fullPath = fstk_FindFile(name); fullPath)
|
||||||
|
file = fopen(fullPath->c_str(), "rb");
|
||||||
if (!file) {
|
if (!file) {
|
||||||
if (generatedMissingIncludes) {
|
if (generatedMissingIncludes) {
|
||||||
if (verbose)
|
if (verbose)
|
||||||
@@ -913,6 +913,7 @@ void sect_BinaryFileSlice(std::string const &name, int32_t startPos, int32_t len
|
|||||||
}
|
}
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
Defer closeFile{[&] { fclose(file); }};
|
||||||
|
|
||||||
int32_t fsize;
|
int32_t fsize;
|
||||||
|
|
||||||
@@ -921,7 +922,7 @@ void sect_BinaryFileSlice(std::string const &name, int32_t startPos, int32_t len
|
|||||||
|
|
||||||
if (startPos > fsize) {
|
if (startPos > fsize) {
|
||||||
error("Specified start position is greater than length of file\n");
|
error("Specified start position is greater than length of file\n");
|
||||||
goto cleanup;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if ((startPos + length) > fsize) {
|
if ((startPos + length) > fsize) {
|
||||||
@@ -932,7 +933,7 @@ void sect_BinaryFileSlice(std::string const &name, int32_t startPos, int32_t len
|
|||||||
length,
|
length,
|
||||||
fsize
|
fsize
|
||||||
);
|
);
|
||||||
goto cleanup;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
fseek(file, startPos, SEEK_SET);
|
fseek(file, startPos, SEEK_SET);
|
||||||
@@ -957,9 +958,6 @@ void sect_BinaryFileSlice(std::string const &name, int32_t startPos, int32_t len
|
|||||||
error("Premature end of file (%" PRId32 " bytes left to read)\n", length + 1);
|
error("Premature end of file (%" PRId32 " bytes left to read)\n", length + 1);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
cleanup:
|
|
||||||
fclose(file);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Section stack routines
|
// Section stack routines
|
||||||
|
|||||||
@@ -1166,31 +1166,29 @@ static void processFile(int input, int output, char const *name, off_t fileSize)
|
|||||||
|
|
||||||
static bool processFilename(char const *name) {
|
static bool processFilename(char const *name) {
|
||||||
nbErrors = 0;
|
nbErrors = 0;
|
||||||
|
|
||||||
if (!strcmp(name, "-")) {
|
if (!strcmp(name, "-")) {
|
||||||
(void)setmode(STDIN_FILENO, O_BINARY);
|
(void)setmode(STDIN_FILENO, O_BINARY);
|
||||||
(void)setmode(STDOUT_FILENO, O_BINARY);
|
(void)setmode(STDOUT_FILENO, O_BINARY);
|
||||||
name = "<stdin>";
|
name = "<stdin>";
|
||||||
processFile(STDIN_FILENO, STDOUT_FILENO, name, 0);
|
processFile(STDIN_FILENO, STDOUT_FILENO, name, 0);
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
// POSIX specifies that the results of O_RDWR on a FIFO are undefined.
|
// POSIX specifies that the results of O_RDWR on a FIFO are undefined.
|
||||||
// However, this is necessary to avoid a TOCTTOU, if the file was changed between
|
// However, this is necessary to avoid a TOCTTOU, if the file was changed between
|
||||||
// `stat()` and `open(O_RDWR)`, which could trigger the UB anyway.
|
// `stat()` and `open(O_RDWR)`, which could trigger the UB anyway.
|
||||||
// Thus, we're going to hope that either the `open` fails, or it succeeds but IO
|
// Thus, we're going to hope that either the `open` fails, or it succeeds but IO
|
||||||
// operations may fail, all of which we handle.
|
// operations may fail, all of which we handle.
|
||||||
int input = open(name, O_RDWR | O_BINARY);
|
if (int input = open(name, O_RDWR | O_BINARY); input == -1) {
|
||||||
struct stat stat;
|
|
||||||
|
|
||||||
if (input == -1) {
|
|
||||||
report("FATAL: Failed to open \"%s\" for reading+writing: %s\n", name, strerror(errno));
|
report("FATAL: Failed to open \"%s\" for reading+writing: %s\n", name, strerror(errno));
|
||||||
goto finish;
|
} else {
|
||||||
}
|
Defer closeInput{[&] { close(input); }};
|
||||||
|
struct stat stat;
|
||||||
if (fstat(input, &stat) == -1) {
|
if (fstat(input, &stat) == -1) {
|
||||||
report("FATAL: Failed to stat \"%s\": %s\n", name, strerror(errno));
|
report("FATAL: Failed to stat \"%s\": %s\n", name, strerror(errno));
|
||||||
} else if (!S_ISREG(stat.st_mode)) { // TODO: Do we want to support other types?
|
} else if (!S_ISREG(stat.st_mode)) { // TODO: Do we want to support other types?
|
||||||
report(
|
report(
|
||||||
"FATAL: \"%s\" is not a regular file, and thus cannot be modified in-place\n", name
|
"FATAL: \"%s\" is not a regular file, and thus cannot be modified in-place\n",
|
||||||
|
name
|
||||||
);
|
);
|
||||||
} else if (stat.st_size < 0x150) {
|
} else if (stat.st_size < 0x150) {
|
||||||
// This check is in theory redundant with the one in `processFile`, but it
|
// This check is in theory redundant with the one in `processFile`, but it
|
||||||
@@ -1203,10 +1201,9 @@ static bool processFilename(char const *name) {
|
|||||||
} else {
|
} else {
|
||||||
processFile(input, input, name, stat.st_size);
|
processFile(input, input, name, stat.st_size);
|
||||||
}
|
}
|
||||||
|
|
||||||
close(input);
|
|
||||||
}
|
}
|
||||||
finish:
|
}
|
||||||
|
|
||||||
if (nbErrors)
|
if (nbErrors)
|
||||||
fprintf(
|
fprintf(
|
||||||
stderr,
|
stderr,
|
||||||
|
|||||||
@@ -1113,7 +1113,7 @@ void process() {
|
|||||||
case ProtoPalette::THEY_BIGGER:
|
case ProtoPalette::THEY_BIGGER:
|
||||||
// Do nothing, they already contain us
|
// Do nothing, they already contain us
|
||||||
attrs.protoPaletteID = n;
|
attrs.protoPaletteID = n;
|
||||||
goto contained;
|
goto continue_visiting_tiles; // Can't `continue` from within a nested loop
|
||||||
|
|
||||||
case ProtoPalette::NEITHER:
|
case ProtoPalette::NEITHER:
|
||||||
break; // Keep going
|
break; // Keep going
|
||||||
@@ -1139,7 +1139,7 @@ void process() {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
protoPalettes.push_back(tileColors);
|
protoPalettes.push_back(tileColors);
|
||||||
contained:;
|
continue_visiting_tiles:;
|
||||||
}
|
}
|
||||||
|
|
||||||
options.verbosePrint(
|
options.verbosePrint(
|
||||||
|
|||||||
@@ -393,7 +393,7 @@ void assign_AssignSections() {
|
|||||||
fprintf(stderr, "%c \"%s\"", nbSections == 0 ? ';' : ',', section->name.c_str());
|
fprintf(stderr, "%c \"%s\"", nbSections == 0 ? ';' : ',', section->name.c_str());
|
||||||
nbSections++;
|
nbSections++;
|
||||||
if (nbSections == 10)
|
if (nbSections == 10)
|
||||||
goto max_out;
|
goto max_out; // Can't `break` out of a nested loop
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -320,7 +320,7 @@ static void parseScrambleSpec(char const *spec) {
|
|||||||
argErr('S', "Cannot imply limit for region \"%.*s\"", regionNamePrintLen, regionName);
|
argErr('S', "Cannot imply limit for region \"%.*s\"", regionNamePrintLen, regionName);
|
||||||
}
|
}
|
||||||
|
|
||||||
next:
|
next: // Can't `continue` a `for` loop with this nontrivial iteration logic
|
||||||
if (spec) {
|
if (spec) {
|
||||||
assert(*spec == ',' || *spec == '\0');
|
assert(*spec == ',' || *spec == '\0');
|
||||||
if (*spec == ',')
|
if (*spec == ',')
|
||||||
|
|||||||
@@ -473,7 +473,6 @@ static void readAssertion(
|
|||||||
|
|
||||||
void obj_ReadFile(char const *fileName, unsigned int fileID) {
|
void obj_ReadFile(char const *fileName, unsigned int fileID) {
|
||||||
FILE *file;
|
FILE *file;
|
||||||
|
|
||||||
if (strcmp(fileName, "-")) {
|
if (strcmp(fileName, "-")) {
|
||||||
file = fopen(fileName, "rb");
|
file = fopen(fileName, "rb");
|
||||||
} else {
|
} else {
|
||||||
@@ -482,6 +481,7 @@ void obj_ReadFile(char const *fileName, unsigned int fileID) {
|
|||||||
}
|
}
|
||||||
if (!file)
|
if (!file)
|
||||||
err("Failed to open file \"%s\"", fileName);
|
err("Failed to open file \"%s\"", fileName);
|
||||||
|
Defer closeFile{[&] { fclose(file); }};
|
||||||
|
|
||||||
// First, check if the object is a RGBDS object or a SDCC one. If the first byte is 'R',
|
// First, check if the object is a RGBDS object or a SDCC one. If the first byte is 'R',
|
||||||
// we'll assume it's a RGBDS object file, and otherwise, that it's a SDCC object file.
|
// we'll assume it's a RGBDS object file, and otherwise, that it's a SDCC object file.
|
||||||
@@ -630,8 +630,6 @@ void obj_ReadFile(char const *fileName, unsigned int fileID) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fclose(file);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void obj_CheckAssertions() {
|
void obj_CheckAssertions() {
|
||||||
|
|||||||
@@ -199,6 +199,10 @@ static void writeROM() {
|
|||||||
if (!outputFile)
|
if (!outputFile)
|
||||||
err("Failed to open output file \"%s\"", outputFileName);
|
err("Failed to open output file \"%s\"", outputFileName);
|
||||||
}
|
}
|
||||||
|
Defer closeOutputFile{[&] {
|
||||||
|
if (outputFile)
|
||||||
|
fclose(outputFile);
|
||||||
|
}};
|
||||||
|
|
||||||
if (overlayFileName) {
|
if (overlayFileName) {
|
||||||
if (strcmp(overlayFileName, "-")) {
|
if (strcmp(overlayFileName, "-")) {
|
||||||
@@ -210,6 +214,10 @@ static void writeROM() {
|
|||||||
if (!overlayFile)
|
if (!overlayFile)
|
||||||
err("Failed to open overlay file \"%s\"", overlayFileName);
|
err("Failed to open overlay file \"%s\"", overlayFileName);
|
||||||
}
|
}
|
||||||
|
Defer closeOverlayFile{[&] {
|
||||||
|
if (overlayFile)
|
||||||
|
fclose(overlayFile);
|
||||||
|
}};
|
||||||
|
|
||||||
uint32_t nbOverlayBanks = checkOverlaySize();
|
uint32_t nbOverlayBanks = checkOverlaySize();
|
||||||
|
|
||||||
@@ -230,11 +238,6 @@ static void writeROM() {
|
|||||||
sectionTypeInfo[SECTTYPE_ROMX].size
|
sectionTypeInfo[SECTTYPE_ROMX].size
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (outputFile)
|
|
||||||
fclose(outputFile);
|
|
||||||
if (overlayFile)
|
|
||||||
fclose(overlayFile);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Checks whether this character is legal as the first character of a symbol's name in a sym file
|
// Checks whether this character is legal as the first character of a symbol's name in a sym file
|
||||||
@@ -533,6 +536,7 @@ static void writeSym() {
|
|||||||
}
|
}
|
||||||
if (!symFile)
|
if (!symFile)
|
||||||
err("Failed to open sym file \"%s\"", symFileName);
|
err("Failed to open sym file \"%s\"", symFileName);
|
||||||
|
Defer closeSymFile{[&] { fclose(symFile); }};
|
||||||
|
|
||||||
fputs("; File generated by rgblink\n", symFile);
|
fputs("; File generated by rgblink\n", symFile);
|
||||||
|
|
||||||
@@ -542,8 +546,6 @@ static void writeSym() {
|
|||||||
for (uint32_t bank = 0; bank < sections[type].size(); bank++)
|
for (uint32_t bank = 0; bank < sections[type].size(); bank++)
|
||||||
writeSymBank(sections[type][bank], type, bank);
|
writeSymBank(sections[type][bank], type, bank);
|
||||||
}
|
}
|
||||||
|
|
||||||
fclose(symFile);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Writes the map file, if applicable.
|
// Writes the map file, if applicable.
|
||||||
@@ -559,6 +561,7 @@ static void writeMap() {
|
|||||||
}
|
}
|
||||||
if (!mapFile)
|
if (!mapFile)
|
||||||
err("Failed to open map file \"%s\"", mapFileName);
|
err("Failed to open map file \"%s\"", mapFileName);
|
||||||
|
Defer closeMapFile{[&] { fclose(mapFile); }};
|
||||||
|
|
||||||
writeMapSummary();
|
writeMapSummary();
|
||||||
|
|
||||||
@@ -568,8 +571,6 @@ static void writeMap() {
|
|||||||
for (uint32_t bank = 0; bank < sections[type].size(); bank++)
|
for (uint32_t bank = 0; bank < sections[type].size(); bank++)
|
||||||
writeMapBank(sections[type][bank], type, bank);
|
writeMapBank(sections[type][bank], type, bank);
|
||||||
}
|
}
|
||||||
|
|
||||||
fclose(mapFile);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void out_WriteFiles() {
|
void out_WriteFiles() {
|
||||||
|
|||||||
@@ -225,7 +225,6 @@ static uint8_t parseHexDigit(int c) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
yy::parser::symbol_type yylex() {
|
yy::parser::symbol_type yylex() {
|
||||||
try_again: // Can't use a `do {} while(0)` loop, otherwise compilers (wrongly) think it can end.
|
|
||||||
auto &context = lexerStack.back();
|
auto &context = lexerStack.back();
|
||||||
auto c = context.file.sbumpc();
|
auto c = context.file.sbumpc();
|
||||||
|
|
||||||
@@ -245,7 +244,7 @@ try_again: // Can't use a `do {} while(0)` loop, otherwise compilers (wrongly) t
|
|||||||
// Basically yywrap().
|
// Basically yywrap().
|
||||||
if (lexerStack.size() != 1) {
|
if (lexerStack.size() != 1) {
|
||||||
lexerStack.pop_back();
|
lexerStack.pop_back();
|
||||||
goto try_again;
|
return yylex();
|
||||||
} else if (!atEof) {
|
} else if (!atEof) {
|
||||||
// Inject a newline at EOF, to avoid errors for files that don't end with one.
|
// Inject a newline at EOF, to avoid errors for files that don't end with one.
|
||||||
atEof = true;
|
atEof = true;
|
||||||
@@ -353,7 +352,7 @@ try_again: // Can't use a `do {} while(0)` loop, otherwise compilers (wrongly) t
|
|||||||
}
|
}
|
||||||
|
|
||||||
scriptError(context, "Unknown keyword \"%s\"", ident.c_str());
|
scriptError(context, "Unknown keyword \"%s\"", ident.c_str());
|
||||||
goto try_again; // Try lexing another token.
|
return yylex();
|
||||||
} else {
|
} else {
|
||||||
scriptError(context, "Unexpected character '%s'", printChar(c));
|
scriptError(context, "Unexpected character '%s'", printChar(c));
|
||||||
// Keep reading characters until the EOL, to avoid reporting too many errors.
|
// Keep reading characters until the EOL, to avoid reporting too many errors.
|
||||||
@@ -363,7 +362,7 @@ try_again: // Can't use a `do {} while(0)` loop, otherwise compilers (wrongly) t
|
|||||||
}
|
}
|
||||||
context.file.sbumpc();
|
context.file.sbumpc();
|
||||||
}
|
}
|
||||||
goto try_again;
|
return yylex();
|
||||||
}
|
}
|
||||||
// Not marking as unreachable; this will generate a warning if any codepath forgets to return.
|
// Not marking as unreachable; this will generate a warning if any codepath forgets to return.
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -797,6 +797,10 @@ void sdobj_ReadFile(FileStackNode const &where, FILE *file, std::vector<Symbol>
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#undef expectEol
|
||||||
|
#undef expectToken
|
||||||
|
#undef getToken
|
||||||
|
|
||||||
if (!data.empty())
|
if (!data.empty())
|
||||||
warning(&where, lineNo, "Last 'T' line had no 'R' line (ignored)");
|
warning(&where, lineNo, "Last 'T' line had no 'R' line (ignored)");
|
||||||
if (fileSections.size() < expectedNbAreas)
|
if (fileSections.size() < expectedNbAreas)
|
||||||
@@ -841,10 +845,4 @@ void sdobj_ReadFile(FileStackNode const &where, FILE *file, std::vector<Symbol>
|
|||||||
// Calling `sect_AddSection` invalidates the contents of `fileSections`!
|
// Calling `sect_AddSection` invalidates the contents of `fileSections`!
|
||||||
sect_AddSection(std::move(section));
|
sect_AddSection(std::move(section));
|
||||||
}
|
}
|
||||||
|
|
||||||
#undef expectEol
|
|
||||||
#undef expectToken
|
|
||||||
#undef getToken
|
|
||||||
|
|
||||||
fclose(file);
|
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user