Refactor code that handles when included files are missing

- Single unified routine for erroring out or handling missing dependencies
- Single three-state enum instead of two Booleans for missing dependencies
  (this causes `-MC` to imply `-MG` instead of needing `-MG -MC`)
- Functions than can miss included files return a Boolean for whether the
  parser should `YYACCEPT` and exit
This commit is contained in:
Rangi42
2025-07-18 14:03:23 -04:00
parent b80b30fba1
commit e7d63f5f6b
9 changed files with 72 additions and 76 deletions

View File

@@ -58,9 +58,10 @@ MacroArgs *fstk_GetCurrentMacroArgs();
void fstk_AddIncludePath(std::string const &path); void fstk_AddIncludePath(std::string const &path);
void fstk_SetPreIncludeFile(std::string const &path); void fstk_SetPreIncludeFile(std::string const &path);
std::optional<std::string> fstk_FindFile(std::string const &path); std::optional<std::string> fstk_FindFile(std::string const &path);
bool fstk_FileError(std::string const &path, char const *functionName);
bool yywrap(); bool yywrap();
void fstk_RunInclude(std::string const &path, bool updateStateNow); bool fstk_RunInclude(std::string const &path);
void fstk_RunMacro(std::string const &macroName, std::shared_ptr<MacroArgs> macroArgs); void fstk_RunMacro(std::string const &macroName, std::shared_ptr<MacroArgs> macroArgs);
void fstk_RunRept(uint32_t count, int32_t reptLineNo, ContentSpan const &span); void fstk_RunRept(uint32_t count, int32_t reptLineNo, ContentSpan const &span);
void fstk_RunFor( void fstk_RunFor(

View File

@@ -15,11 +15,16 @@ extern bool verbose;
} \ } \
} while (0) } while (0)
enum MissingInclude {
INC_ERROR, // A missing included file is an error that halts assembly
GEN_EXIT, // A missing included file is assumed to be generated; exit normally
GEN_CONTINUE, // A missing included file is assumed to be generated; continue assembling
};
extern FILE *dependFile; extern FILE *dependFile;
extern std::string targetFileName; extern std::string targetFileName;
extern bool continueAfterMissingIncludes; extern MissingInclude missingIncludeState;
extern bool generatedMissingIncludes;
extern bool failedOnMissingInclude;
extern bool generatePhonyDeps; extern bool generatePhonyDeps;
extern bool failedOnMissingInclude;
#endif // RGBDS_ASM_MAIN_HPP #endif // RGBDS_ASM_MAIN_HPP

View File

@@ -96,8 +96,8 @@ void sect_RelBytes(uint32_t n, std::vector<Expression> const &exprs);
void sect_RelWord(Expression const &expr, uint32_t pcShift); void sect_RelWord(Expression const &expr, uint32_t pcShift);
void sect_RelLong(Expression const &expr, uint32_t pcShift); void sect_RelLong(Expression const &expr, uint32_t pcShift);
void sect_PCRelByte(Expression const &expr, uint32_t pcShift); void sect_PCRelByte(Expression const &expr, uint32_t pcShift);
void sect_BinaryFile(std::string const &name, uint32_t startPos); bool sect_BinaryFile(std::string const &name, uint32_t startPos);
void sect_BinaryFileSlice(std::string const &name, uint32_t startPos, uint32_t length); bool sect_BinaryFileSlice(std::string const &name, uint32_t startPos, uint32_t length);
void sect_EndSection(); void sect_EndSection();
void sect_PushSection(); void sect_PushSection();

View File

@@ -116,7 +116,7 @@ Write
dependencies to dependencies to
.Ar depend_file . .Ar depend_file .
.It Fl MC .It Fl MC
To be used in conjunction with Implies
.Fl MG . .Fl MG .
This makes This makes
.Nm .Nm
@@ -143,7 +143,9 @@ exits normally or continues processing (depending on whether
was enabled) instead of erroring out. was enabled) instead of erroring out.
This feature is used in automatic updating of Makefiles. This feature is used in automatic updating of Makefiles.
.It Fl MP .It Fl MP
When enabled, this causes a phony target to be added for each dependency other than the main file. When enabled, this adds a phony target to the rules emitted by
.Fl M
for each dependency other than the main file.
This prevents This prevents
.Xr make 1 .Xr make 1
from erroring out when dependency files are deleted. from erroring out when dependency files are deleted.

View File

@@ -146,7 +146,7 @@ std::optional<std::string> fstk_FindFile(std::string const &path) {
} }
errno = ENOENT; errno = ENOENT;
if (generatedMissingIncludes) { if (missingIncludeState != INC_ERROR) {
printDep(path); printDep(path);
} }
return std::nullopt; return std::nullopt;
@@ -302,26 +302,30 @@ static Context &newReptContext(int32_t reptLineNo, ContentSpan const &span, uint
return context; return context;
} }
void fstk_RunInclude(std::string const &path, bool preInclude) { bool fstk_FileError(std::string const &path, char const *functionName) {
std::optional<std::string> fullPath = fstk_FindFile(path); if (missingIncludeState == INC_ERROR) {
error("Error opening %s file '%s': %s", functionName, path.c_str(), strerror(errno));
if (!fullPath) {
if (generatedMissingIncludes && !preInclude) {
// LCOV_EXCL_START
if (!continueAfterMissingIncludes) {
verbosePrint(
"Aborting (-MG) on INCLUDE file '%s' (%s)\n", path.c_str(), strerror(errno)
);
}
// LCOV_EXCL_STOP
failedOnMissingInclude = true;
} else { } else {
error("Unable to open included file '%s': %s", path.c_str(), strerror(errno)); failedOnMissingInclude = true;
// LCOV_EXCL_START
if (missingIncludeState == GEN_EXIT) {
verbosePrint(
"Aborting (-MG) on %s file '%s' (%s)\n", functionName, path.c_str(), strerror(errno)
);
return true;
} }
return; assume(missingIncludeState == GEN_CONTINUE);
// LCOV_EXCL_STOP
}
return false;
} }
bool fstk_RunInclude(std::string const &path) {
if (std::optional<std::string> fullPath = fstk_FindFile(path); fullPath) {
newFileContext(*fullPath, false); newFileContext(*fullPath, false);
return false;
}
return fstk_FileError(path, "INCLUDE");
} }
void fstk_RunMacro(std::string const &macroName, std::shared_ptr<MacroArgs> macroArgs) { void fstk_RunMacro(std::string const &macroName, std::shared_ptr<MacroArgs> macroArgs) {
@@ -410,6 +414,12 @@ void fstk_Init(std::string const &mainPath, size_t maxDepth) {
maxRecursionDepth = maxDepth; maxRecursionDepth = maxDepth;
if (!preIncludeName.empty()) { if (!preIncludeName.empty()) {
fstk_RunInclude(preIncludeName, true); if (std::optional<std::string> fullPath = fstk_FindFile(preIncludeName); fullPath) {
newFileContext(*fullPath, false);
} else {
error(
"Error reading pre-included file '%s': %s", preIncludeName.c_str(), strerror(errno)
);
}
} }
} }

View File

@@ -24,13 +24,13 @@
#include "asm/symbol.hpp" #include "asm/symbol.hpp"
#include "asm/warning.hpp" #include "asm/warning.hpp"
bool verbose = false; // -v
FILE *dependFile = nullptr; // -M FILE *dependFile = nullptr; // -M
bool continueAfterMissingIncludes = false; // -MC MissingInclude missingIncludeState = INC_ERROR; // -MC, -MG
bool generatedMissingIncludes = false; // -MG
bool generatePhonyDeps = false; // -MP bool generatePhonyDeps = false; // -MP
std::string targetFileName; // -MQ, -MT std::string targetFileName; // -MQ, -MT
bool failedOnMissingInclude = false; bool failedOnMissingInclude = false;
bool verbose = false; // -v
// Escapes Make-special chars from a string // Escapes Make-special chars from a string
static std::string make_escape(std::string &str) { static std::string make_escape(std::string &str) {
@@ -371,11 +371,11 @@ int main(int argc, char *argv[]) {
case 0: case 0:
switch (depType) { switch (depType) {
case 'C': case 'C':
continueAfterMissingIncludes = true; missingIncludeState = GEN_CONTINUE;
break; break;
case 'G': case 'G':
generatedMissingIncludes = true; missingIncludeState = GEN_EXIT;
break; break;
case 'P': case 'P':

View File

@@ -1139,8 +1139,7 @@ export_def:
include: include:
label POP_INCLUDE string endofline { label POP_INCLUDE string endofline {
fstk_RunInclude($3, false); if (fstk_RunInclude($3)) {
if (failedOnMissingInclude && !continueAfterMissingIncludes) {
YYACCEPT; YYACCEPT;
} }
} }
@@ -1148,20 +1147,17 @@ include:
incbin: incbin:
POP_INCBIN string { POP_INCBIN string {
sect_BinaryFile($2, 0); if (sect_BinaryFile($2, 0)) {
if (failedOnMissingInclude && !continueAfterMissingIncludes) {
YYACCEPT; YYACCEPT;
} }
} }
| POP_INCBIN string COMMA uconst { | POP_INCBIN string COMMA uconst {
sect_BinaryFile($2, $4); if (sect_BinaryFile($2, $4)) {
if (failedOnMissingInclude && !continueAfterMissingIncludes) {
YYACCEPT; YYACCEPT;
} }
} }
| POP_INCBIN string COMMA uconst COMMA uconst { | POP_INCBIN string COMMA uconst COMMA uconst {
sect_BinaryFileSlice($2, $4, $6); if (sect_BinaryFileSlice($2, $4, $6)) {
if (failedOnMissingInclude && !continueAfterMissingIncludes) {
YYACCEPT; YYACCEPT;
} }
} }

View File

@@ -874,9 +874,9 @@ void sect_PCRelByte(Expression const &expr, uint32_t pcShift) {
} }
} }
void sect_BinaryFile(std::string const &name, uint32_t startPos) { bool sect_BinaryFile(std::string const &name, uint32_t startPos) {
if (!requireCodeSection()) { if (!requireCodeSection()) {
return; return false;
} }
FILE *file = nullptr; FILE *file = nullptr;
@@ -884,24 +884,14 @@ void sect_BinaryFile(std::string const &name, uint32_t startPos) {
file = fopen(fullPath->c_str(), "rb"); file = fopen(fullPath->c_str(), "rb");
} }
if (!file) { if (!file) {
if (generatedMissingIncludes) { return fstk_FileError(name, "INCBIN");
// LCOV_EXCL_START
if (verbose && !continueAfterMissingIncludes) {
printf("Aborting (-MG) on INCBIN file '%s' (%s)\n", name.c_str(), strerror(errno));
}
// LCOV_EXCL_STOP
failedOnMissingInclude = true;
} else {
error("Error opening INCBIN file '%s': %s", name.c_str(), strerror(errno));
}
return;
} }
Defer closeFile{[&] { fclose(file); }}; Defer closeFile{[&] { fclose(file); }};
if (fseek(file, 0, SEEK_END) != -1) { if (fseek(file, 0, SEEK_END) != -1) {
if (startPos > ftell(file)) { if (startPos > ftell(file)) {
error("Specified start position is greater than length of file '%s'", name.c_str()); error("Specified start position is greater than length of file '%s'", name.c_str());
return; return false;
} }
// The file is seekable; skip to the specified start position // The file is seekable; skip to the specified start position
fseek(file, startPos, SEEK_SET); fseek(file, startPos, SEEK_SET);
@@ -913,7 +903,7 @@ void sect_BinaryFile(std::string const &name, uint32_t startPos) {
while (startPos--) { while (startPos--) {
if (fgetc(file) == EOF) { if (fgetc(file) == EOF) {
error("Specified start position is greater than length of file '%s'", name.c_str()); error("Specified start position is greater than length of file '%s'", name.c_str());
return; return false;
} }
} }
} }
@@ -925,14 +915,15 @@ void sect_BinaryFile(std::string const &name, uint32_t startPos) {
if (ferror(file)) { if (ferror(file)) {
error("Error reading INCBIN file '%s': %s", name.c_str(), strerror(errno)); error("Error reading INCBIN file '%s': %s", name.c_str(), strerror(errno));
} }
return false;
} }
void sect_BinaryFileSlice(std::string const &name, uint32_t startPos, uint32_t length) { bool sect_BinaryFileSlice(std::string const &name, uint32_t startPos, uint32_t length) {
if (!requireCodeSection()) { if (!requireCodeSection()) {
return; return false;
} }
if (length == 0) { // Don't even bother with 0-byte slices if (length == 0) { // Don't even bother with 0-byte slices
return; return false;
} }
FILE *file = nullptr; FILE *file = nullptr;
@@ -940,24 +931,14 @@ void sect_BinaryFileSlice(std::string const &name, uint32_t startPos, uint32_t l
file = fopen(fullPath->c_str(), "rb"); file = fopen(fullPath->c_str(), "rb");
} }
if (!file) { if (!file) {
if (generatedMissingIncludes) { return fstk_FileError(name, "INCBIN");
// LCOV_EXCL_START
if (verbose && !continueAfterMissingIncludes) {
printf("Aborting (-MG) on INCBIN file '%s' (%s)\n", name.c_str(), strerror(errno));
}
// LCOV_EXCL_STOP
failedOnMissingInclude = true;
} else {
error("Error opening INCBIN file '%s': %s", name.c_str(), strerror(errno));
}
return;
} }
Defer closeFile{[&] { fclose(file); }}; Defer closeFile{[&] { fclose(file); }};
if (fseek(file, 0, SEEK_END) != -1) { if (fseek(file, 0, SEEK_END) != -1) {
if (long fsize = ftell(file); startPos > fsize) { if (long fsize = ftell(file); startPos > fsize) {
error("Specified start position is greater than length of file '%s'", name.c_str()); error("Specified start position is greater than length of file '%s'", name.c_str());
return; return false;
} else if (startPos + length > fsize) { } else if (startPos + length > fsize) {
error( error(
"Specified range in INCBIN file '%s' is out of bounds (%" PRIu32 " + %" PRIu32 "Specified range in INCBIN file '%s' is out of bounds (%" PRIu32 " + %" PRIu32
@@ -967,7 +948,7 @@ void sect_BinaryFileSlice(std::string const &name, uint32_t startPos, uint32_t l
length, length,
fsize fsize
); );
return; return false;
} }
// The file is seekable; skip to the specified start position // The file is seekable; skip to the specified start position
fseek(file, startPos, SEEK_SET); fseek(file, startPos, SEEK_SET);
@@ -979,7 +960,7 @@ void sect_BinaryFileSlice(std::string const &name, uint32_t startPos, uint32_t l
while (startPos--) { while (startPos--) {
if (fgetc(file) == EOF) { if (fgetc(file) == EOF) {
error("Specified start position is greater than length of file '%s'", name.c_str()); error("Specified start position is greater than length of file '%s'", name.c_str());
return; return false;
} }
} }
} }
@@ -997,6 +978,7 @@ void sect_BinaryFileSlice(std::string const &name, uint32_t startPos, uint32_t l
); );
} }
} }
return false;
} }
void sect_PushSection() { void sect_PushSection() {

View File

@@ -1,3 +1,3 @@
error: nonexist-include.asm(1): error: nonexist-include.asm(1):
Unable to open included file 'nonexist-include.inc': No such file or directory Error opening INCLUDE file 'nonexist-include.inc': No such file or directory
Assembly aborted with 1 error! Assembly aborted with 1 error!