From b8385a50e3cffb224e889760a68f6f1c93844d6a Mon Sep 17 00:00:00 2001 From: Rangi <35663410+Rangi42@users.noreply.github.com> Date: Sat, 24 Sep 2022 12:37:16 -0400 Subject: [PATCH] Support `-P/--preinclude` to pre-INCLUDE a file (#1043) Fixes #1041 Co-authored-by: ISSOtm --- contrib/bash_compl/_rgbasm.bash | 1 + contrib/zsh_compl/_rgbasm | 1 + include/asm/fstack.h | 1 + man/rgbasm.1 | 31 ++++++++++++++++++----- man/rgbasm.5 | 7 +++++ src/asm/fstack.c | 45 +++++++++++++++++++++++++++++++++ src/asm/main.c | 11 +++++--- test/asm/preinclude.asm | 3 +++ test/asm/preinclude.err | 4 +++ test/asm/preinclude.flags | 1 + test/asm/preinclude.inc | 11 ++++++++ test/asm/preinclude.out | 7 +++++ test/asm/test.sh | 9 +++++-- 13 files changed, 121 insertions(+), 11 deletions(-) create mode 100644 test/asm/preinclude.asm create mode 100644 test/asm/preinclude.err create mode 100644 test/asm/preinclude.flags create mode 100644 test/asm/preinclude.inc create mode 100644 test/asm/preinclude.out diff --git a/contrib/bash_compl/_rgbasm.bash b/contrib/bash_compl/_rgbasm.bash index 33b48386..10127abc 100755 --- a/contrib/bash_compl/_rgbasm.bash +++ b/contrib/bash_compl/_rgbasm.bash @@ -38,6 +38,7 @@ _rgbasm_completions() { [i]="include:dir" [M]="dependfile:glob-*.mk *.d" [o]="output:glob-*.o" + [P]="preinclude:glob-*.asm *.inc" [p]="pad-value:unk" [Q]="q-precision:unk" [r]="recursion-depth:unk" diff --git a/contrib/zsh_compl/_rgbasm b/contrib/zsh_compl/_rgbasm index a32be84d..4a7588bc 100644 --- a/contrib/zsh_compl/_rgbasm +++ b/contrib/zsh_compl/_rgbasm @@ -55,6 +55,7 @@ local args=( '*'-MT"+[Add a target to the rules]:target:_files -g '*.{d,mk,o}'" '*'-MQ"+[Add a target to the rules]:target:_files -g '*.{d,mk,o}'" '(-o --output)'{-o,--output}'+[Output file]:output file:_files' + '(-P --preinclude)'{-P,--preinclude}"+[Pre-include a file]:include file:_files -g '*.{asm,inc}'" '(-p --pad-value)'{-p,--pad-value}'+[Set padding byte]:padding byte:' '(-Q --q-precision)'{-Q,--q-precision}'+[Set fixed-point precision]:precision:' '(-r --recursion-depth)'{-r,--recursion-depth}'+[Set maximum recursion depth]:depth:' diff --git a/include/asm/fstack.h b/include/asm/fstack.h index 5a3120ad..5f1851a7 100644 --- a/include/asm/fstack.h +++ b/include/asm/fstack.h @@ -58,6 +58,7 @@ struct FileStackNode *fstk_GetFileStack(void); char const *fstk_GetFileName(void); void fstk_AddIncludePath(char const *s); +void fstk_SetPreIncludeFile(char const *s); /* * @param path The user-provided file name * @param fullPath The address of a pointer, which will be made to point at the full path diff --git a/man/rgbasm.1 b/man/rgbasm.1 index bd229d71..f0face69 100644 --- a/man/rgbasm.1 +++ b/man/rgbasm.1 @@ -24,21 +24,21 @@ .Op Fl MT Ar target_file .Op Fl MQ Ar target_file .Op Fl o Ar out_file +.Op Fl P Ar include_file .Op Fl p Ar pad_value .Op Fl Q Ar fix_precision .Op Fl r Ar recursion_depth .Op Fl W Ar warning -.Ar +.Ar asmfile .Sh DESCRIPTION The .Nm program creates an RGB object file from an assembly source file. The input -.Ar file -can be a file path, or +.Ar asmfile +can be a path to a file, or .Cm \- -denoting -.Cm stdin . +to read from standard input. .Pp Note that options can be abbreviated as long as the abbreviation is unambiguous: .Fl Fl verb @@ -87,7 +87,19 @@ instruction immediately after any .Ic halt instruction. .It Fl i Ar path , Fl Fl include Ar path -Add an include path. +Add a new +.Dq include path ; Ar path +must point to a directory. +When a +.Ic INCLUDE +.Pq including the implicit one from Fl P +or +.Ic INCBIN +is attempted, +.Nm +first looks up the provided path from its working directory; if this fails, it tries again from each of the +.Dq include path +directories, in the order they were provided. .It Fl L , Fl Fl preserve-ld By default, .Nm @@ -116,6 +128,7 @@ This makes .Nm assume that missing files are auto-generated: when .Ic INCLUDE +.Pq including the implicit one from Fl P or .Ic INCBIN is attempted on a non-existent file, it is added as a dependency, then @@ -146,6 +159,12 @@ characters, essentially .Sq $ . .It Fl o Ar out_file , Fl Fl output Ar out_file Write an object file to the given filename. +.It Fl P Ar include_file , Fl Fl preinclude Ar include_file +Pre-include a file. +This acts as if a +.Ql Ic INCLUDE Qq Ar include_file +was read before the input +.Ar asmfile . .It Fl p Ar pad_value , Fl Fl pad-value Ar pad_value When padding an image, pad with this value. The default is 0x00. diff --git a/man/rgbasm.5 b/man/rgbasm.5 index 077d527d..8e76e4f1 100644 --- a/man/rgbasm.5 +++ b/man/rgbasm.5 @@ -1972,6 +1972,13 @@ calls infinitely (or until you run out of memory, whichever comes first). .Bd -literal -offset indent INCLUDE "irq.inc" .Ed +.Pp +You may also implicitly +.Ic INCLUDE +a file before the source file with the +.Fl P +option of +.Xr rgbasm 1 . .Ss Conditional assembling The four commands .Ic IF , ELIF , ELSE , diff --git a/src/asm/fstack.c b/src/asm/fstack.c index aadac116..b95f8640 100644 --- a/src/asm/fstack.c +++ b/src/asm/fstack.c @@ -42,6 +42,8 @@ size_t maxRecursionDepth; static unsigned int nbIncPaths = 0; static char const *includePaths[MAXINCPATHS]; +static const char *preIncludeName; + static const char *dumpNodeAndParents(struct FileStackNode const *node) { char const *name; @@ -133,6 +135,11 @@ void fstk_AddIncludePath(char const *path) includePaths[nbIncPaths++] = str; } +void fstk_SetPreIncludeFile(char const *path) +{ + preIncludeName = path; +} + static void printDep(char const *path) { if (dependfile) { @@ -274,6 +281,7 @@ bool yywrap(void) lexer_SetState(contextStack->lexerState); macro_SetUniqueID(contextStack->uniqueID); + return false; } @@ -342,6 +350,41 @@ void fstk_RunInclude(char const *path) contextStack->uniqueID = macro_UndefUniqueID(); } +// Similar to `fstk_RunInclude`, but not subject to `-MG`, and +// calling `lexer_SetState` instead of `lexer_SetStateAtEOL`. +static void runPreIncludeFile(void) +{ + if (!preIncludeName) + return; + + char *fullPath = NULL; + size_t size = 0; + + if (!fstk_FindFile(preIncludeName, &fullPath, &size)) { + free(fullPath); + error("Unable to open included file '%s': %s\n", preIncludeName, strerror(errno)); + return; + } + + struct FileStackNamedNode *fileInfo = malloc(sizeof(*fileInfo) + size); + + if (!fileInfo) { + error("Failed to alloc file info for pre-include: %s\n", strerror(errno)); + return; + } + fileInfo->node.type = NODE_FILE; + strcpy(fileInfo->name, fullPath); + free(fullPath); + + newContext((struct FileStackNode *)fileInfo); + contextStack->lexerState = lexer_OpenFile(fileInfo->name); + if (!contextStack->lexerState) + fatalerror("Failed to set up lexer for file include\n"); + lexer_SetState(contextStack->lexerState); + // We're back at top-level, so most things are reset + contextStack->uniqueID = macro_UndefUniqueID(); +} + void fstk_RunMacro(char const *macroName, struct MacroArgs *args) { struct Symbol *macro = sym_FindExactSymbol(macroName); @@ -563,4 +606,6 @@ void fstk_Init(char const *mainPath, size_t maxDepth) // Make sure that the default of 64 is OK, though assert(DEPTH_LIMIT >= DEFAULT_MAX_DEPTH); #undef DEPTH_LIMIT + + runPreIncludeFile(); } diff --git a/src/asm/main.c b/src/asm/main.c index a1cefb11..1f04c569 100644 --- a/src/asm/main.c +++ b/src/asm/main.c @@ -87,7 +87,7 @@ static char *make_escape(char const *str) } // Short options -static const char *optstring = "b:D:Eg:Hhi:LlM:o:p:Q:r:VvW:w"; +static const char *optstring = "b:D:Eg:Hhi:LlM:o:P:p:Q:r:VvW:w"; // Variables for the long-only options static int depType; // Variants of `-M` @@ -116,6 +116,7 @@ static struct option const longopts[] = { { "MT", required_argument, &depType, 'T' }, { "MQ", required_argument, &depType, 'Q' }, { "output", required_argument, NULL, 'o' }, + { "preinclude", required_argument, NULL, 'P' }, { "pad-value", required_argument, NULL, 'p' }, { "q-precision", required_argument, NULL, 'Q' }, { "recursion-depth", required_argument, NULL, 'r' }, @@ -130,8 +131,8 @@ static void print_usage(void) fputs( "Usage: rgbasm [-EHhLlVvw] [-b chars] [-D name[=value]] [-g chars] [-i path]\n" " [-M depend_file] [-MG] [-MP] [-MT target_file] [-MQ target_file]\n" -" [-o out_file] [-p pad_value] [-Q precision] [-r depth]\n" -" [-W warning] \n" +" [-o out_file] [-P include_file] [-p pad_value] [-Q precision]\n" +" [-r depth] [-W warning] \n" "Useful options:\n" " -E, --export-all export all labels\n" " -M, --dependfile set the output dependency file\n" @@ -254,6 +255,10 @@ int main(int argc, char *argv[]) out_SetFileName(musl_optarg); break; + case 'P': + fstk_SetPreIncludeFile(musl_optarg); + break; + unsigned long padByte; case 'p': padByte = strtoul(musl_optarg, &ep, 0); diff --git a/test/asm/preinclude.asm b/test/asm/preinclude.asm new file mode 100644 index 00000000..41fc8032 --- /dev/null +++ b/test/asm/preinclude.asm @@ -0,0 +1,3 @@ +warn "main {__FILE__}" +def v3 = v1 + v2 +println "{d:v1} + {d:v2} = {d:v3}" diff --git a/test/asm/preinclude.err b/test/asm/preinclude.err new file mode 100644 index 00000000..9b62e52f --- /dev/null +++ b/test/asm/preinclude.err @@ -0,0 +1,4 @@ +warning: preinclude.asm(0) -> preinclude.inc(1): [-Wuser] + pre-include "preinclude.inc" +warning: preinclude.asm(1): [-Wuser] + main "preinclude.asm" diff --git a/test/asm/preinclude.flags b/test/asm/preinclude.flags new file mode 100644 index 00000000..3a0a2380 --- /dev/null +++ b/test/asm/preinclude.flags @@ -0,0 +1 @@ +-Weverything -P preinclude.inc diff --git a/test/asm/preinclude.inc b/test/asm/preinclude.inc new file mode 100644 index 00000000..e38a0a4a --- /dev/null +++ b/test/asm/preinclude.inc @@ -0,0 +1,11 @@ +warn "pre-include {__FILE__}" + +def v1 = 12 +rept 3 + println "rept 3" +endr + +def v2 = 34 +for i, 3 + println "for {d:i}/3" +endr diff --git a/test/asm/preinclude.out b/test/asm/preinclude.out new file mode 100644 index 00000000..68668268 --- /dev/null +++ b/test/asm/preinclude.out @@ -0,0 +1,7 @@ +rept 3 +rept 3 +rept 3 +for 0/3 +for 1/3 +for 2/3 +12 + 34 = 46 diff --git a/test/asm/test.sh b/test/asm/test.sh index 4d06356d..2c6a4123 100755 --- a/test/asm/test.sh +++ b/test/asm/test.sh @@ -76,6 +76,11 @@ if ! diff --strip-trailing-cr syntax-error.err $errput; then fi for i in *.asm; do + flags=${i%.asm}.flags + RGBASMFLAGS=-Weverything + if [ -f $flags ]; then + RGBASMFLAGS="$(head -n 1 "$flags")" # Allow other lines to serve as comments + fi for variant in '' '.pipe'; do echo "${bold}${green}${i%.asm}${variant}...${rescolors}${resbold}" desired_errname=${i%.asm}.err @@ -83,7 +88,7 @@ for i in *.asm; do desired_errname=${i%.asm}.simple.err fi if [ -z "$variant" ]; then - $RGBASM -Weverything -o $o $i > $output 2> $errput + $RGBASM $RGBASMFLAGS -o $o $i > $output 2> $errput desired_output=${i%.asm}.out desired_errput=$desired_errname else @@ -97,7 +102,7 @@ for i in *.asm; do # stdin redirection makes the input an unseekable pipe - a scenario # that's harder to deal with and was broken when the feature was # first implemented. - cat $i | $RGBASM -Weverything -o $o - > $output 2> $errput + cat $i | $RGBASM $RGBASMFLAGS -o $o - > $output 2> $errput # Use two otherwise unused files for temp storage desired_output=$input