shithub: rgbds

Download patch

ref: 8c0275480c680ce610c9f4ce7d121197152a879c
parent: 76d6ef869582a3c714a4b8c7839c2d445b4bfcb1
author: Rangi <35663410+Rangi42@users.noreply.github.com>
date: Tue Feb 16 14:01:23 EST 2021

Allow `ds` to take multiple values to repeat for a count (#725)

Fixes #722

--- a/include/asm/lexer.h
+++ b/include/asm/lexer.h
@@ -83,4 +83,11 @@
 void lexer_CaptureRept(struct CaptureBody *capture);
 void lexer_CaptureMacroBody(struct CaptureBody *capture);
 
+#define INITIAL_DS_ARG_SIZE 2
+struct DsArgList {
+	size_t nbArgs;
+	size_t capacity;
+	struct Expression *args;
+};
+
 #endif /* RGBDS_ASM_LEXER_H */
--- a/include/asm/section.h
+++ b/include/asm/section.h
@@ -64,7 +64,7 @@
 void out_Skip(int32_t skip, bool ds);
 void out_String(char const *s);
 void out_RelByte(struct Expression *expr, uint32_t pcShift);
-void out_RelBytes(struct Expression *expr, uint32_t n);
+void out_RelBytes(uint32_t n, struct Expression *exprs, size_t size);
 void out_RelWord(struct Expression *expr, uint32_t pcShift);
 void out_RelLong(struct Expression *expr, uint32_t pcShift);
 void out_PCRelByte(struct Expression *expr, uint32_t pcShift);
--- a/src/asm/parser.y
+++ b/src/asm/parser.y
@@ -310,6 +310,33 @@
 	dest[i] = '\0';
 }
 
+static void initDsArgList(struct DsArgList *args)
+{
+	args->nbArgs = 0;
+	args->capacity = INITIAL_DS_ARG_SIZE;
+	args->args = malloc(args->capacity * sizeof(*args->args));
+	if (!args->args)
+		fatalerror("Failed to allocate memory for ds arg list: %s\n",
+			   strerror(errno));
+}
+
+static size_t nextDsArgListIndex(struct DsArgList *args)
+{
+	if (args->nbArgs == args->capacity) {
+		args->capacity = (args->capacity + 1) * 2;
+		args->args = realloc(args->args, args->capacity * sizeof(*args->args));
+		if (!args->args)
+			fatalerror("realloc error while resizing ds arg list: %s\n",
+				   strerror(errno));
+	}
+	return args->nbArgs++;
+}
+
+static void freeDsArgList(struct DsArgList *args)
+{
+	free(args->args);
+}
+
 static inline void failAssert(enum AssertionType type)
 {
 	switch (type) {
@@ -397,6 +424,7 @@
 	struct SectionSpec sectSpec;
 	struct MacroArgs *macroArg;
 	enum AssertionType assertType;
+	struct DsArgList dsArgs;
 	struct {
 		int32_t start;
 		int32_t stop;
@@ -537,6 +565,8 @@
 %type	<sectMod> sectmod
 %type	<macroArg> macroargs
 
+%type	<dsArgs> ds_args
+
 %type	<forArgs> for_args
 
 %token	T_Z80_ADC "adc" T_Z80_ADD "add" T_Z80_AND "and"
@@ -946,11 +976,26 @@
 ;
 
 ds		: T_POP_DS uconst	{ out_Skip($2, true); }
-		| T_POP_DS uconst T_COMMA reloc_8bit {
-			out_RelBytes(&$4, $2);
+		| T_POP_DS uconst T_COMMA ds_args {
+			out_RelBytes($2, $4.args, $4.nbArgs);
+			freeDsArgList(&$4);
 		}
 ;
 
+ds_args		: reloc_8bit {
+			initDsArgList(&$$);
+			size_t i = nextDsArgListIndex(&$$);
+
+			$$.args[i] = $1;
+		}
+		| ds_args T_COMMA reloc_8bit {
+			size_t i = nextDsArgListIndex(&$1);
+
+			$1.args[i] = $3;
+			$$ = $1;
+		}
+;
+
 /* Authorize empty entries if there is only one */
 db		: T_POP_DB constlist_8bit_entry T_COMMA constlist_8bit {
 			if ($2 || $4)
@@ -1265,7 +1310,7 @@
 		| relocexpr T_OP_XOR relocexpr {
 			rpn_BinaryOp(RPN_XOR, &$$, &$1, &$3);
 		}
-		| relocexpr T_OP_OR relocexpr	 {
+		| relocexpr T_OP_OR relocexpr {
 			rpn_BinaryOp(RPN_OR, &$$, &$1, &$3);
 		}
 		| relocexpr T_OP_AND relocexpr {
--- a/src/asm/rgbasm.5
+++ b/src/asm/rgbasm.5
@@ -1239,10 +1239,13 @@
 If you do not want this special handling, enclose the string in parentheses.
 .Pp
 .Ic DS
-can also be used to fill a region of memory with some value.
-The following produces 42 times the byte $FF:
+can also be used to fill a region of memory with some repeated values.
+For example:
 .Bd -literal -offset indent
-DS 42, $FF
+; outputs 3 bytes: $AA, $AA, $AA
+DS 3, $AA
+; outputs 7 bytes: $BB, $CC, $BB, $CC, $BB, $CC, $BB
+DS 7, $BB, $CC
 .Ed
 .Pp
 You can also use
--- a/src/asm/section.c
+++ b/src/asm/section.c
@@ -637,12 +637,14 @@
  * Output several copies of a relocatable byte. Checking will be done to see if
  * it is an absolute value in disguise.
  */
-void out_RelBytes(struct Expression *expr, uint32_t n)
+void out_RelBytes(uint32_t n, struct Expression *exprs, size_t size)
 {
 	checkcodesection();
 	reserveSpace(n);
 
 	for (uint32_t i = 0; i < n; i++) {
+		struct Expression *expr = &exprs[i % size];
+
 		if (!rpn_isKnown(expr)) {
 			createPatch(PATCHTYPE_BYTE, expr, i);
 			writebyte(0);
@@ -650,7 +652,9 @@
 			writebyte(expr->nVal);
 		}
 	}
-	rpn_Free(expr);
+
+	for (size_t i = 0; i < size; i++)
+		rpn_Free(&exprs[i]);
 }
 
 /*
--- a/test/asm/ds-@.asm
+++ b/test/asm/ds-@.asm
@@ -1,14 +1,14 @@
 SECTION "test fixed", ROM0[0]
 
 FixedStart:
-	ds 8, (@ - FixedStart) * 2 + zero
-	ds 8, (@ - FixedStart) * 2 + zero
+	ds 6, (@ - FixedStart) * 2 + zero
+	ds 10, (@ - FixedStart) + zero, (@ - FixedStart) * 3 + zero, (@ - FixedStart) * 4 + zero
 
 SECTION "test floating", ROM0
 
 FloatingStart:
-	ds 8, (@ - FloatingStart) * 2 + zero
-	ds 8, (@ - FloatingStart) * 2 + zero
+	ds 6, (@ - FloatingStart) * 2 + zero
+	ds 10, (@ - FloatingStart) + zero, (@ - FloatingStart) * 3 + zero, (@ - FloatingStart) * 4 + zero
 
 SECTION "zero", ROM0[0]
 zero:
binary files a/test/asm/ds-@.out.bin b/test/asm/ds-@.out.bin differ
--- a/test/asm/ds-byte.asm
+++ b/test/asm/ds-byte.asm
@@ -6,3 +6,4 @@
 	ds 5, .other - Label - 5 ; Expressions should work...
 	ds 60, .last - Label     ; ...even if not constant
 .last
+	ds 11, $67, $89
--- a/test/asm/ds-byte.out.bin
+++ b/test/asm/ds-byte.out.bin
@@ -1,1 +1,1 @@
-****�����EEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEE
\ No newline at end of file
+****�����EEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEg�g�g�g�g�g
\ No newline at end of file