ref: 64752da42defe06d559d08baf84c31da7bedce5e
parent: e33e6e24132dea1490e3039a6c85194d2b6a7a74
author: ISSOtm <eldredhabert0@gmail.com>
date: Tue Aug 27 23:04:19 EDT 2019
Add "print types" to bracketed symbols Should partially cover #178 and close #270. This allows printing numbers in different bases and without the dollar prefix This is especially useful in macros because the dollar isnt a valid character for symbol names, requiring heavy `STRSUB` usage.
--- a/include/asm/asm.h
+++ b/include/asm/asm.h
@@ -39,6 +39,7 @@
extern struct sSymbol *pPCSymbol;
extern bool oDontExpandStrings;
-size_t symvaluetostring(char *dest, size_t maxLength, char *sym);
+size_t symvaluetostring(char *dest, size_t maxLength, char *sym,
+ const char *mode);
#endif /* RGBDS_ASM_ASM_H */
--- a/src/asm/asmy.y
+++ b/src/asm/asmy.y
@@ -1,7 +1,7 @@
/*
* This file is part of RGBDS.
*
- * Copyright (c) 1997-2018, Carsten Sorensen and RGBDS contributors.
+ * Copyright (c) 1997-2019, Carsten Sorensen and RGBDS contributors.
*
* SPDX-License-Identifier: MIT
*/
@@ -75,7 +75,8 @@
out_NewAbsSection(name, secttype, org, bank);
}
-size_t symvaluetostring(char *dest, size_t maxLength, char *sym)
+size_t symvaluetostring(char *dest, size_t maxLength, char *sym,
+ const char *mode)
{
size_t length;
@@ -83,6 +84,9 @@
char *src = sym_GetStringValue(sym);
size_t i;
+ if (mode)
+ yyerror("Print types are only allowed for numbers");
+
for (i = 0; src[i] != 0; i++) {
if (i >= maxLength)
fatalerror("Symbol value too long to fit buffer");
@@ -94,8 +98,25 @@
} else {
uint32_t value = sym_GetConstantValue(sym);
- int32_t fullLength = snprintf(dest, maxLength + 1, "$%X",
- value);
+ int32_t fullLength;
+
+ /* Special cheat for binary */
+ if (mode && !mode[0]) {
+ char binary[33]; /* 32 bits + 1 terminator */
+ char *write_ptr = binary + 32;
+ fullLength = 0;
+ binary[32] = 0;
+ do {
+ *(--write_ptr) = (value & 1) + '0';
+ value >>= 1;
+ fullLength++;
+ } while(value);
+ strncpy(dest, write_ptr, maxLength + 1);
+ } else {
+ fullLength = snprintf(dest, maxLength + 1,
+ mode ? : "$%X",
+ value);
+ }
if (fullLength < 0) {
fatalerror("snprintf encoding error");
--- a/src/asm/lexer.c
+++ b/src/asm/lexer.c
@@ -1,7 +1,7 @@
/*
* This file is part of RGBDS.
*
- * Copyright (c) 1997-2018, Carsten Sorensen and RGBDS contributors.
+ * Copyright (c) 1997-2019, Carsten Sorensen and RGBDS contributors.
*
* SPDX-License-Identifier: MIT
*/
@@ -599,6 +599,7 @@
char ch;
size_t i = 0;
size_t length, maxLength;
+ const char *mode = NULL;
for (ch = *pLexBuffer;
ch != '}' && ch != '"' && ch != '\n';
@@ -612,16 +613,42 @@
i += length;
else
fatalerror("Illegal character escape '%c'", ch);
+ } else if (ch == ':' && !mode) { /* Only grab 1st colon */
+ /* Use a whitelist of modes, which does prevent the
+ * use of some features such as precision,
+ * but also avoids a security flaw
+ */
+ const char *acceptedModes = "bxXd";
+ /* Binary isn't natively supported,
+ * so it's handled differently
+ */
+ static const char * const formatSpecifiers[] = {
+ "", "%x", "%X", "%d"
+ };
+ /* Prevent reading out of bounds! */
+ const char *designatedMode;
+
+ if (i != 1)
+ fatalerror("Print types are exactly 1 character long");
+
+ designatedMode = strchr(acceptedModes, sym[i - 1]);
+ if (!designatedMode)
+ fatalerror("Illegal print type '%c'",
+ sym[i - 1]);
+ mode = formatSpecifiers[designatedMode - acceptedModes];
+ /* Begin writing the symbol again */
+ i = 0;
} else {
yylex_SymbolWriteChar(sym, i++, ch);
}
}
+ /* Properly terminate the string */
yylex_SymbolWriteChar(sym, i, 0);
/* It's assumed we're writing to a T_STRING */
maxLength = MAXSTRLEN - index;
- length = symvaluetostring(&dest[index], maxLength, sym);
+ length = symvaluetostring(&dest[index], maxLength, sym, mode);
if (*pLexBuffer == '}')
pLexBuffer++;
--- a/src/asm/rgbasm.5
+++ b/src/asm/rgbasm.5
@@ -1079,7 +1079,20 @@
This will examine the type of the symbol and insert its value accordingly.
If symbol is a string symbol, the symbols value is simply copied.
If it's a numeric symbol, the value is converted to hexadecimal notation and
-inserted as a string.
+inserted as a string with a dollar prepended.
+.Pp
+It's possible to change the way numeric symbols are converted by specifying
+a print type like so:
+.Sy {d:symbol}
+Valid print types are:
+.Bl -column -offset indent
+.It Sy Print type Ta Sy Format Ta Sy Example
+.It Li d Ta Decimal Ta 42
+.It Li x Ta Lowercase hexadecimal Ta 2a
+.It Li X Ta Uppercase hexadecimal Ta 2A
+.It Li b Ta Binary Ta 101010
+.Pp
+Note that print types should only be used with numeric values, not strings.
.Pp
HINT: The
.Sy {symbol}