shithub: rgbds

Download patch

ref: b8385a50e3cffb224e889760a68f6f1c93844d6a
parent: 02923a67f3d023586d127a6fda0b7b03949332b4
author: Rangi <[email protected]>
date: Sat Sep 24 08:37:16 EDT 2022

Support `-P/--preinclude` to pre-INCLUDE a file (#1043)

Fixes #1041

Co-authored-by: ISSOtm <[email protected]>

--- a/contrib/bash_compl/_rgbasm.bash
+++ b/contrib/bash_compl/_rgbasm.bash
@@ -38,6 +38,7 @@
 		[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"
--- a/contrib/zsh_compl/_rgbasm
+++ b/contrib/zsh_compl/_rgbasm
@@ -55,6 +55,7 @@
 	'*'-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:'
--- a/include/asm/fstack.h
+++ b/include/asm/fstack.h
@@ -58,6 +58,7 @@
 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
--- 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 @@
 .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 @@
 .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 @@
 .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.
--- a/man/rgbasm.5
+++ b/man/rgbasm.5
@@ -1972,6 +1972,13 @@
 .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 ,
--- a/src/asm/fstack.c
+++ b/src/asm/fstack.c
@@ -42,6 +42,8 @@
 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 @@
 	includePaths[nbIncPaths++] = str;
 }
 
+void fstk_SetPreIncludeFile(char const *path)
+{
+	preIncludeName = path;
+}
+
 static void printDep(char const *path)
 {
 	if (dependfile) {
@@ -274,6 +281,7 @@
 
 	lexer_SetState(contextStack->lexerState);
 	macro_SetUniqueID(contextStack->uniqueID);
+
 	return false;
 }
 
@@ -342,6 +350,41 @@
 	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 @@
 	// Make sure that the default of 64 is OK, though
 	assert(DEPTH_LIMIT >= DEFAULT_MAX_DEPTH);
 #undef DEPTH_LIMIT
+
+	runPreIncludeFile();
 }
--- a/src/asm/main.c
+++ b/src/asm/main.c
@@ -87,7 +87,7 @@
 }
 
 // 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 @@
 	{ "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 @@
 	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] <file>\n"
+"              [-o out_file] [-P include_file] [-p pad_value] [-Q precision]\n"
+"              [-r depth] [-W warning] <file>\n"
 "Useful options:\n"
 "    -E, --export-all         export all labels\n"
 "    -M, --dependfile <path>  set the output dependency file\n"
@@ -252,6 +253,10 @@
 
 		case 'o':
 			out_SetFileName(musl_optarg);
+			break;
+
+		case 'P':
+			fstk_SetPreIncludeFile(musl_optarg);
 			break;
 
 			unsigned long padByte;
--- /dev/null
+++ b/test/asm/preinclude.asm
@@ -1,0 +1,3 @@
+warn "main {__FILE__}"
+def v3 = v1 + v2
+println "{d:v1} + {d:v2} = {d:v3}"
--- /dev/null
+++ b/test/asm/preinclude.err
@@ -1,0 +1,4 @@
+warning: preinclude.asm(0) -> preinclude.inc(1): [-Wuser]
+    pre-include "preinclude.inc"
+warning: preinclude.asm(1): [-Wuser]
+    main "preinclude.asm"
--- /dev/null
+++ b/test/asm/preinclude.flags
@@ -1,0 +1,1 @@
+-Weverything -P preinclude.inc
--- /dev/null
+++ b/test/asm/preinclude.inc
@@ -1,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
--- /dev/null
+++ b/test/asm/preinclude.out
@@ -1,0 +1,7 @@
+rept 3
+rept 3
+rept 3
+for 0/3
+for 1/3
+for 2/3
+12 + 34 = 46
--- a/test/asm/test.sh
+++ b/test/asm/test.sh
@@ -76,6 +76,11 @@
 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 @@
 			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 @@
 			# 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