ref: 9d2d5cfcfe4d647cb0a8a5363653e05b115f9940
parent: 18f3c8ff9aa4e0b7cf4c565dbc585b53f3c5efdb
author: Rangi <remy.oukaour+rangi42@gmail.com>
date: Fri Jan 1 09:28:59 EST 2021
Implement `REDEF` to allow redefining `EQUS` string equates Fixes #677
--- a/include/asm/symbol.h
+++ b/include/asm/symbol.h
@@ -140,6 +140,7 @@
struct Symbol *sym_AddMacro(char const *symName, int32_t defLineNo, char *body, size_t size);
struct Symbol *sym_Ref(char const *symName);
struct Symbol *sym_AddString(char const *symName, char const *value);
+struct Symbol *sym_RedefString(char const *symName, char const *value);
void sym_Purge(char const *symName);
void sym_Init(time_t now);
--- a/src/asm/lexer.c
+++ b/src/asm/lexer.c
@@ -270,6 +270,7 @@
{"RW", T_POP_RW},
{"EQU", T_POP_EQU},
{"EQUS", T_POP_EQUS},
+ {"REDEF", T_POP_REDEF},
/* Handled before in list of CPU instructions */
/* {"SET", T_POP_SET}, */
@@ -490,7 +491,7 @@
uint16_t children[0x60 - ' '];
struct KeywordMapping const *keyword;
/* Since the keyword structure is invariant, the min number of nodes is known at compile time */
-} keywordDict[352] = {0}; /* Make sure to keep this correct when adding keywords! */
+} keywordDict[356] = {0}; /* Make sure to keep this correct when adding keywords! */
/* Convert a char into its index into the dict */
static inline uint8_t dictIndex(char c)
--- a/src/asm/parser.y
+++ b/src/asm/parser.y
@@ -425,6 +425,7 @@
%token T_POP_FATAL
%token T_POP_ASSERT T_POP_STATIC_ASSERT
%token T_POP_PURGE
+%token T_POP_REDEF
%token T_POP_POPS
%token T_POP_PUSHS
%token T_POP_POPO
@@ -645,6 +646,7 @@
| warn
| assert
| purge
+ | redef
| pops
| pushs
| popo
@@ -874,6 +876,15 @@
lexer_ToggleStringExpansion(false);
} purge_list {
lexer_ToggleStringExpansion(true);
+ }
+;
+
+redef : T_POP_REDEF {
+ lexer_ToggleStringExpansion(false);
+ } scoped_id {
+ lexer_ToggleStringExpansion(true);
+ } T_POP_EQUS string {
+ sym_RedefString($3, $6);
}
;
--- a/src/asm/rgbasm.5
+++ b/src/asm/rgbasm.5
@@ -929,7 +929,7 @@
.Ic = ,
defines constant symbols like
.Ic EQU ,
-but those constants can be re-defined.
+but those constants can be redefined.
This is useful for variables in macros, for counters, etc.
.Bd -literal -offset indent
ARRAY_SIZE EQU 4
@@ -1008,7 +1008,22 @@
Note that colons
.Ql \&:
following the name are not allowed.
+.Pp
String equates can't be exported or imported.
+.Pp
+String equates, like
+.Ic EQU
+constants, cannot be redefined.
+However, the
+.Ic REDEF
+keyword will define or redefine a string symbol.
+For example:
+.Bd -literal -offset indent
+s EQUS "Hello, "
+REDEF s EQUS "{s}world!"
+; prints "Hello, world!"
+PRINTT "{s}\n"
+.Ed
.Pp
.Sy Important note :
An
--- a/src/asm/symbol.c
+++ b/src/asm/symbol.c
@@ -222,6 +222,19 @@
fatalerror("Symbol name is too long: '%s%s'\n", scopeName, localName);
}
+static void assignStringSymbol(struct Symbol *sym, char const *value)
+{
+ char *string = strdup(value);
+
+ if (string == NULL)
+ fatalerror("No memory for string equate: %s\n", strerror(errno));
+
+ sym->type = SYM_EQUS;
+ /* TODO: use other fields */
+ sym->macro = string;
+ sym->macroSize = strlen(string);
+}
+
struct Symbol *sym_FindExactSymbol(char const *name)
{
return hash_GetElement(symbols, name);
@@ -283,6 +296,11 @@
if (symbol->name == labelScope)
labelScope = NULL;
+ /*
+ * FIXME: this leaks symbol->macro for SYM_EQUS and SYM_MACRO, but this can't
+ * free(symbol->macro) because the expansion may be purging itself.
+ */
+
hash_RemoveElement(symbols, symbol->name);
/* TODO: ideally, also unref the file stack nodes */
free(symbol);
@@ -390,17 +408,30 @@
struct Symbol *sym_AddString(char const *symName, char const *value)
{
struct Symbol *sym = createNonrelocSymbol(symName);
- size_t len = strlen(value);
- char *string = malloc(len + 1);
- if (string == NULL)
- fatalerror("No memory for string equate: %s\n", strerror(errno));
- strcpy(string, value);
+ assignStringSymbol(sym, value);
- sym->type = SYM_EQUS;
- /* TODO: use other fields */
- sym->macroSize = len;
- sym->macro = string;
+ return sym;
+}
+
+struct Symbol *sym_RedefString(char const *symName, char const *value)
+{
+ struct Symbol *sym = sym_FindExactSymbol(symName);
+
+ if (!sym) {
+ sym = createsymbol(symName);
+ } else if (sym->type != SYM_EQUS) {
+ error("'%s' already defined as non-EQUS at ", symName);
+ dumpFilename(sym);
+ putc('\n', stderr);
+ }
+
+ /*
+ * FIXME: this leaks the previous sym->macro value, but this can't
+ * free(sym->macro) because the expansion may be redefining itself.
+ */
+
+ assignStringSymbol(sym, value);
return sym;
}
--- /dev/null
+++ b/test/asm/redef-equs.asm
@@ -1,0 +1,23 @@
+s EQUS "Hello, "
+REDEF s EQUS "{s}world!"
+; prints "Hello, world!"
+PRINTT "{s}\n"
+
+list: MACRO
+LIST_NAME EQUS "\1"
+REDEF {LIST_NAME} EQUS "["
+REPT _NARG - 1
+REDEF {LIST_NAME} EQUS "{{LIST_NAME}}\2;"
+SHIFT
+ENDR
+REDEF {LIST_NAME} EQUS "{{LIST_NAME}}]"
+PURGE LIST_NAME
+ENDM
+
+ list FOO
+ PRINTT "{FOO}\n"
+ list FOO, 1, A, 2, B
+ PRINTT "{FOO}\n"
+
+N EQU 42
+REDEF N EQUS "X"
--- /dev/null
+++ b/test/asm/redef-equs.err
@@ -1,0 +1,3 @@
+ERROR: redef-equs.asm(23):
+ 'N' already defined as non-EQUS at redef-equs.asm(22)
+error: Assembly aborted (1 errors)!
--- /dev/null
+++ b/test/asm/redef-equs.out
@@ -1,0 +1,3 @@
+Hello, world!
+[]
+[1;A;2;B;]