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_SetPreIncludeFile(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();
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_RunRept(uint32_t count, int32_t reptLineNo, ContentSpan const &span);
void fstk_RunFor(

View File

@@ -15,11 +15,16 @@ extern bool verbose;
} \
} 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 std::string targetFileName;
extern bool continueAfterMissingIncludes;
extern bool generatedMissingIncludes;
extern bool failedOnMissingInclude;
extern MissingInclude missingIncludeState;
extern bool generatePhonyDeps;
extern bool failedOnMissingInclude;
#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_RelLong(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);
void sect_BinaryFileSlice(std::string const &name, uint32_t startPos, uint32_t length);
bool sect_BinaryFile(std::string const &name, uint32_t startPos);
bool sect_BinaryFileSlice(std::string const &name, uint32_t startPos, uint32_t length);
void sect_EndSection();
void sect_PushSection();

View File

@@ -116,7 +116,7 @@ Write
dependencies to
.Ar depend_file .
.It Fl MC
To be used in conjunction with
Implies
.Fl MG .
This makes
.Nm
@@ -143,7 +143,9 @@ exits normally or continues processing (depending on whether
was enabled) instead of erroring out.
This feature is used in automatic updating of Makefiles.
.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
.Xr make 1
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;
if (generatedMissingIncludes) {
if (missingIncludeState != INC_ERROR) {
printDep(path);
}
return std::nullopt;
@@ -302,26 +302,30 @@ static Context &newReptContext(int32_t reptLineNo, ContentSpan const &span, uint
return context;
}
void fstk_RunInclude(std::string const &path, bool preInclude) {
std::optional<std::string> fullPath = fstk_FindFile(path);
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 {
error("Unable to open included file '%s': %s", path.c_str(), strerror(errno));
bool fstk_FileError(std::string const &path, char const *functionName) {
if (missingIncludeState == INC_ERROR) {
error("Error opening %s file '%s': %s", functionName, path.c_str(), strerror(errno));
} else {
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;
}
newFileContext(*fullPath, false);
bool fstk_RunInclude(std::string const &path) {
if (std::optional<std::string> fullPath = fstk_FindFile(path); fullPath) {
newFileContext(*fullPath, false);
return false;
}
return fstk_FileError(path, "INCLUDE");
}
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;
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,14 +24,14 @@
#include "asm/symbol.hpp"
#include "asm/warning.hpp"
FILE *dependFile = nullptr; // -M
bool continueAfterMissingIncludes = false; // -MC
bool generatedMissingIncludes = false; // -MG
bool generatePhonyDeps = false; // -MP
std::string targetFileName; // -MQ, -MT
bool failedOnMissingInclude = false;
bool verbose = false; // -v
FILE *dependFile = nullptr; // -M
MissingInclude missingIncludeState = INC_ERROR; // -MC, -MG
bool generatePhonyDeps = false; // -MP
std::string targetFileName; // -MQ, -MT
bool failedOnMissingInclude = false;
// Escapes Make-special chars from a string
static std::string make_escape(std::string &str) {
std::string escaped;
@@ -371,11 +371,11 @@ int main(int argc, char *argv[]) {
case 0:
switch (depType) {
case 'C':
continueAfterMissingIncludes = true;
missingIncludeState = GEN_CONTINUE;
break;
case 'G':
generatedMissingIncludes = true;
missingIncludeState = GEN_EXIT;
break;
case 'P':

View File

@@ -1139,8 +1139,7 @@ export_def:
include:
label POP_INCLUDE string endofline {
fstk_RunInclude($3, false);
if (failedOnMissingInclude && !continueAfterMissingIncludes) {
if (fstk_RunInclude($3)) {
YYACCEPT;
}
}
@@ -1148,20 +1147,17 @@ include:
incbin:
POP_INCBIN string {
sect_BinaryFile($2, 0);
if (failedOnMissingInclude && !continueAfterMissingIncludes) {
if (sect_BinaryFile($2, 0)) {
YYACCEPT;
}
}
| POP_INCBIN string COMMA uconst {
sect_BinaryFile($2, $4);
if (failedOnMissingInclude && !continueAfterMissingIncludes) {
if (sect_BinaryFile($2, $4)) {
YYACCEPT;
}
}
| POP_INCBIN string COMMA uconst COMMA uconst {
sect_BinaryFileSlice($2, $4, $6);
if (failedOnMissingInclude && !continueAfterMissingIncludes) {
if (sect_BinaryFileSlice($2, $4, $6)) {
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()) {
return;
return false;
}
FILE *file = nullptr;
@@ -884,24 +884,14 @@ void sect_BinaryFile(std::string const &name, uint32_t startPos) {
file = fopen(fullPath->c_str(), "rb");
}
if (!file) {
if (generatedMissingIncludes) {
// 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;
return fstk_FileError(name, "INCBIN");
}
Defer closeFile{[&] { fclose(file); }};
if (fseek(file, 0, SEEK_END) != -1) {
if (startPos > ftell(file)) {
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
fseek(file, startPos, SEEK_SET);
@@ -913,7 +903,7 @@ void sect_BinaryFile(std::string const &name, uint32_t startPos) {
while (startPos--) {
if (fgetc(file) == EOF) {
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)) {
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()) {
return;
return false;
}
if (length == 0) { // Don't even bother with 0-byte slices
return;
return false;
}
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");
}
if (!file) {
if (generatedMissingIncludes) {
// 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;
return fstk_FileError(name, "INCBIN");
}
Defer closeFile{[&] { fclose(file); }};
if (fseek(file, 0, SEEK_END) != -1) {
if (long fsize = ftell(file); startPos > fsize) {
error("Specified start position is greater than length of file '%s'", name.c_str());
return;
return false;
} else if (startPos + length > fsize) {
error(
"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,
fsize
);
return;
return false;
}
// The file is seekable; skip to the specified start position
fseek(file, startPos, SEEK_SET);
@@ -979,7 +960,7 @@ void sect_BinaryFileSlice(std::string const &name, uint32_t startPos, uint32_t l
while (startPos--) {
if (fgetc(file) == EOF) {
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() {

View File

@@ -1,3 +1,3 @@
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!