mirror of
https://github.com/gbdev/rgbds.git
synced 2025-11-20 10:12:06 +00:00
@@ -140,6 +140,7 @@ struct Symbol const *sym_GetPC(void);
|
|||||||
struct Symbol *sym_AddMacro(char const *symName, int32_t defLineNo, char *body, size_t size);
|
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_Ref(char const *symName);
|
||||||
struct Symbol *sym_AddString(char const *symName, char const *value);
|
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_Purge(char const *symName);
|
||||||
void sym_Init(time_t now);
|
void sym_Init(time_t now);
|
||||||
|
|
||||||
|
|||||||
@@ -270,6 +270,7 @@ static struct KeywordMapping {
|
|||||||
{"RW", T_POP_RW},
|
{"RW", T_POP_RW},
|
||||||
{"EQU", T_POP_EQU},
|
{"EQU", T_POP_EQU},
|
||||||
{"EQUS", T_POP_EQUS},
|
{"EQUS", T_POP_EQUS},
|
||||||
|
{"REDEF", T_POP_REDEF},
|
||||||
|
|
||||||
/* Handled before in list of CPU instructions */
|
/* Handled before in list of CPU instructions */
|
||||||
/* {"SET", T_POP_SET}, */
|
/* {"SET", T_POP_SET}, */
|
||||||
@@ -490,7 +491,7 @@ struct KeywordDictNode {
|
|||||||
uint16_t children[0x60 - ' '];
|
uint16_t children[0x60 - ' '];
|
||||||
struct KeywordMapping const *keyword;
|
struct KeywordMapping const *keyword;
|
||||||
/* Since the keyword structure is invariant, the min number of nodes is known at compile time */
|
/* 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 */
|
/* Convert a char into its index into the dict */
|
||||||
static inline uint8_t dictIndex(char c)
|
static inline uint8_t dictIndex(char c)
|
||||||
|
|||||||
@@ -425,6 +425,7 @@ static inline void failAssertMsg(enum AssertionType type, char const *msg)
|
|||||||
%token T_POP_FATAL
|
%token T_POP_FATAL
|
||||||
%token T_POP_ASSERT T_POP_STATIC_ASSERT
|
%token T_POP_ASSERT T_POP_STATIC_ASSERT
|
||||||
%token T_POP_PURGE
|
%token T_POP_PURGE
|
||||||
|
%token T_POP_REDEF
|
||||||
%token T_POP_POPS
|
%token T_POP_POPS
|
||||||
%token T_POP_PUSHS
|
%token T_POP_PUSHS
|
||||||
%token T_POP_POPO
|
%token T_POP_POPO
|
||||||
@@ -645,6 +646,7 @@ simple_pseudoop : include
|
|||||||
| warn
|
| warn
|
||||||
| assert
|
| assert
|
||||||
| purge
|
| purge
|
||||||
|
| redef
|
||||||
| pops
|
| pops
|
||||||
| pushs
|
| pushs
|
||||||
| popo
|
| 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 : purge_list_entry
|
||||||
| purge_list T_COMMA purge_list_entry
|
| purge_list T_COMMA purge_list_entry
|
||||||
;
|
;
|
||||||
|
|||||||
@@ -929,7 +929,7 @@ or its synonym
|
|||||||
.Ic = ,
|
.Ic = ,
|
||||||
defines constant symbols like
|
defines constant symbols like
|
||||||
.Ic EQU ,
|
.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.
|
This is useful for variables in macros, for counters, etc.
|
||||||
.Bd -literal -offset indent
|
.Bd -literal -offset indent
|
||||||
ARRAY_SIZE EQU 4
|
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
|
Note that colons
|
||||||
.Ql \&:
|
.Ql \&:
|
||||||
following the name are not allowed.
|
following the name are not allowed.
|
||||||
|
.Pp
|
||||||
String equates can't be exported or imported.
|
String equates can't be exported or imported.
|
||||||
.Pp
|
.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 :
|
.Sy Important note :
|
||||||
An
|
An
|
||||||
.Ic EQUS
|
.Ic EQUS
|
||||||
|
|||||||
@@ -222,6 +222,19 @@ static void fullSymbolName(char *output, size_t outputSize,
|
|||||||
fatalerror("Symbol name is too long: '%s%s'\n", scopeName, localName);
|
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)
|
struct Symbol *sym_FindExactSymbol(char const *name)
|
||||||
{
|
{
|
||||||
return hash_GetElement(symbols, name);
|
return hash_GetElement(symbols, name);
|
||||||
@@ -283,6 +296,11 @@ void sym_Purge(char const *symName)
|
|||||||
if (symbol->name == labelScope)
|
if (symbol->name == labelScope)
|
||||||
labelScope = NULL;
|
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);
|
hash_RemoveElement(symbols, symbol->name);
|
||||||
/* TODO: ideally, also unref the file stack nodes */
|
/* TODO: ideally, also unref the file stack nodes */
|
||||||
free(symbol);
|
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_AddString(char const *symName, char const *value)
|
||||||
{
|
{
|
||||||
struct Symbol *sym = createNonrelocSymbol(symName);
|
struct Symbol *sym = createNonrelocSymbol(symName);
|
||||||
size_t len = strlen(value);
|
|
||||||
char *string = malloc(len + 1);
|
|
||||||
|
|
||||||
if (string == NULL)
|
assignStringSymbol(sym, value);
|
||||||
fatalerror("No memory for string equate: %s\n", strerror(errno));
|
|
||||||
strcpy(string, value);
|
|
||||||
|
|
||||||
sym->type = SYM_EQUS;
|
return sym;
|
||||||
/* TODO: use other fields */
|
}
|
||||||
sym->macroSize = len;
|
|
||||||
sym->macro = string;
|
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;
|
return sym;
|
||||||
}
|
}
|
||||||
|
|||||||
23
test/asm/redef-equs.asm
Normal file
23
test/asm/redef-equs.asm
Normal file
@@ -0,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"
|
||||||
3
test/asm/redef-equs.err
Normal file
3
test/asm/redef-equs.err
Normal file
@@ -0,0 +1,3 @@
|
|||||||
|
ERROR: redef-equs.asm(23):
|
||||||
|
'N' already defined as non-EQUS at redef-equs.asm(22)
|
||||||
|
error: Assembly aborted (1 errors)!
|
||||||
3
test/asm/redef-equs.out
Normal file
3
test/asm/redef-equs.out
Normal file
@@ -0,0 +1,3 @@
|
|||||||
|
Hello, world!
|
||||||
|
[]
|
||||||
|
[1;A;2;B;]
|
||||||
Reference in New Issue
Block a user