Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Implement INCLUDE_ONCE directive #1481

Merged
merged 4 commits into from
Sep 8, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 7 additions & 1 deletion include/asm/fstack.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,12 @@

#include "asm/lexer.hpp"

enum IncludeType {
INCLUDE_NORMAL,
INCLUDE_PRE,
INCLUDE_ONCE
};

struct FileStackNode {
FileStackNodeType type;
Either<
Expand Down Expand Up @@ -64,7 +70,7 @@ void fstk_SetPreIncludeFile(std::string const &path);
std::optional<std::string> fstk_FindFile(std::string const &path);

bool yywrap();
void fstk_RunInclude(std::string const &path, bool updateStateNow);
void fstk_RunInclude(std::string const &path, IncludeType type);
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(
Expand Down
12 changes: 11 additions & 1 deletion man/rgbasm.5
Original file line number Diff line number Diff line change
Expand Up @@ -2158,7 +2158,17 @@ calls infinitely (or until you run out of memory, whichever comes first).
INCLUDE "irq.inc"
.Ed
.Pp
You may also implicitly
You may also ensure a file only gets included once by using
.Ic INCLUDE_ONCE
instead of
.Ic INCLUDE .
This will skip including a file if it has already been included before (with
.Ic INCLUDE ,
.Ic INCLUDE_ONCE ,
or
.Fl P ) .
.Pp
You can implicitly
.Ic INCLUDE
a file before the source file with the
.Fl P
Expand Down
28 changes: 24 additions & 4 deletions src/asm/fstack.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -6,9 +6,11 @@
#include <errno.h>
#include <inttypes.h>
#include <memory>
#include <set>
#include <stack>
#include <stdio.h>
#include <stdlib.h>
#include <utility>

#include "error.hpp"
#include "helpers.hpp"
Expand Down Expand Up @@ -45,8 +47,8 @@ size_t maxRecursionDepth;

// The first include path for `fstk_FindFile` to try is none at all
static std::vector<std::string> includePaths = {""};

static std::string preIncludeName;
static std::set<std::pair<dev_t, ino_t>> includedFiles;

std::string const &FileStackNode::dump(uint32_t curLineNo) const {
if (data.holds<std::vector<uint32_t>>()) {
Expand Down Expand Up @@ -291,11 +293,11 @@ static Context &newReptContext(int32_t reptLineNo, ContentSpan const &span, uint
return context;
}

void fstk_RunInclude(std::string const &path, bool preInclude) {
void fstk_RunInclude(std::string const &path, IncludeType type) {
std::optional<std::string> fullPath = fstk_FindFile(path);

if (!fullPath) {
if (generatedMissingIncludes && !preInclude) {
if (generatedMissingIncludes && type != INCLUDE_PRE) {
if (verbose)
printf("Aborting (-MG) on INCLUDE file '%s' (%s)\n", path.c_str(), strerror(errno));
failedOnMissingInclude = true;
Expand All @@ -305,6 +307,24 @@ void fstk_RunInclude(std::string const &path, bool preInclude) {
return;
}

// The pair of device ID and serial number uniquely identify a file, with `stat()`
// following symbolic links to identify the actual file.
struct stat statBuf;
if (stat(fullPath->c_str(), &statBuf) != 0) {
error("Failed to stat file '%s': %s\n", fullPath->c_str(), strerror(errno));
return;
}
std::pair<dev_t, ino_t> inode{statBuf.st_dev, statBuf.st_ino};

if (type == INCLUDE_ONCE && includedFiles.find(inode) != includedFiles.end()) {
if (verbose) {
printf("File '%s' already included, skipping INCLUDE_ONCE", path.c_str());
}
return;
}

includedFiles.insert(inode);

if (!newFileContext(*fullPath, false))
fatalerror("Failed to set up lexer for file include\n");
}
Expand Down Expand Up @@ -395,5 +415,5 @@ void fstk_Init(std::string const &mainPath, size_t maxDepth) {
maxRecursionDepth = maxDepth;

if (!preIncludeName.empty())
fstk_RunInclude(preIncludeName, true);
fstk_RunInclude(preIncludeName, INCLUDE_PRE);
}
1 change: 1 addition & 0 deletions src/asm/lexer.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -256,6 +256,7 @@ static std::unordered_map<std::string, int, CaseInsensitive, CaseInsensitive> ke
{"INCHARMAP", T_(OP_INCHARMAP) },

{"INCLUDE", T_(POP_INCLUDE) },
{"INCLUDE_ONCE", T_(POP_INCLUDE_ONCE) },
{"PRINT", T_(POP_PRINT) },
{"PRINTLN", T_(POP_PRINTLN) },
{"EXPORT", T_(POP_EXPORT) },
Expand Down
12 changes: 11 additions & 1 deletion src/asm/parser.y
Original file line number Diff line number Diff line change
Expand Up @@ -236,6 +236,7 @@
%token POP_IF "IF"
%token POP_INCBIN "INCBIN"
%token POP_INCLUDE "INCLUDE"
%token POP_INCLUDE_ONCE "INCLUDE_ONCE"
%token POP_LOAD "LOAD"
%token POP_MACRO "MACRO"
%token POP_NEWCHARMAP "NEWCHARMAP"
Expand Down Expand Up @@ -464,6 +465,7 @@ line_directive:
| for
| break
| include
| include_once
| if
// It's important that all of these require being at line start for `skipIfBlock`
| elif
Expand Down Expand Up @@ -1140,7 +1142,15 @@ export_def:

include:
label POP_INCLUDE string endofline {
fstk_RunInclude($3, false);
fstk_RunInclude($3, INCLUDE_NORMAL);
if (failedOnMissingInclude)
YYACCEPT;
}
;

include_once:
label POP_INCLUDE_ONCE string endofline {
fstk_RunInclude($3, INCLUDE_ONCE);
if (failedOnMissingInclude)
YYACCEPT;
}
Expand Down
3 changes: 3 additions & 0 deletions test/asm/include-once.asm
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
INCLUDE_ONCE "include-once.inc"
INCLUDE_ONCE "include-once.inc"
INCLUDE_ONCE "include-link.inc"
1 change: 1 addition & 0 deletions test/asm/include-once.inc
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
DEF HELLO EQU 1
5 changes: 4 additions & 1 deletion test/asm/test.sh
Original file line number Diff line number Diff line change
Expand Up @@ -11,9 +11,12 @@ input="$(mktemp)"
output="$(mktemp)"
errput="$(mktemp)"

# Create a symbolic link for the `include-once.asm` test case.
ln include-once.inc include-link.inc

# Immediate expansion is the desired behavior.
# shellcheck disable=SC2064
trap "rm -f ${o@Q} ${gb@Q} ${input@Q} ${output@Q} ${errput@Q}" EXIT
trap "rm -f ${o@Q} ${gb@Q} ${input@Q} ${output@Q} ${errput@Q} include-link.inc" EXIT

tests=0
failed=0
Expand Down