Implement REDEF to allow redefining EQUS string equates

Fixes #677
This commit is contained in:
Rangi
2021-01-01 14:28:59 -05:00
committed by Eldred Habert
parent 18f3c8ff9a
commit 9d2d5cfcfe
8 changed files with 99 additions and 11 deletions

View File

@@ -270,6 +270,7 @@ static struct KeywordMapping {
{"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 @@ struct KeywordDictNode {
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)

View File

@@ -425,6 +425,7 @@ static inline void failAssertMsg(enum AssertionType type, char const *msg)
%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 @@ simple_pseudoop : include
| warn
| assert
| purge
| redef
| pops
| pushs
| popo
@@ -877,6 +879,15 @@ purge : T_POP_PURGE {
}
;
redef : T_POP_REDEF {
lexer_ToggleStringExpansion(false);
} scoped_id {
lexer_ToggleStringExpansion(true);
} T_POP_EQUS string {
sym_RedefString($3, $6);
}
;
purge_list : purge_list_entry
| purge_list T_COMMA purge_list_entry
;

View File

@@ -929,7 +929,7 @@ or its synonym
.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,8 +1008,23 @@ pusha EQUS "push af\[rs]npush bc\[rs]npush de\[rs]npush hl\[rs]n"
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
.Ic EQUS

View File

@@ -222,6 +222,19 @@ static void fullSymbolName(char *output, size_t outputSize,
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 @@ void sym_Purge(char const *symName)
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_AddEqu(char const *symName, int32_t value)
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;
}