diff --git a/include/asm/symbol.h b/include/asm/symbol.h index 6ed35c67b..729ec28f3 100644 --- a/include/asm/symbol.h +++ b/include/asm/symbol.h @@ -120,6 +120,7 @@ struct Symbol *sym_AddAnonLabel(void); void sym_WriteAnonLabelName(char buf[MIN_NB_ELMS(MAXSYMLEN + 1)], uint32_t ofs, bool neg); void sym_Export(char const *symName); struct Symbol *sym_AddEqu(char const *symName, int32_t value); +struct Symbol *sym_RedefEqu(char const *symName, int32_t value); struct Symbol *sym_AddSet(char const *symName, int32_t value); uint32_t sym_GetPCValue(void); uint32_t sym_GetConstantSymValue(struct Symbol const *sym); diff --git a/src/asm/parser.y b/src/asm/parser.y index 9423ea1f0..31d7feab2 100644 --- a/src/asm/parser.y +++ b/src/asm/parser.y @@ -851,6 +851,7 @@ directive : endc | warn | assert | def_equ + | redef_equ | def_set | def_rb | def_rw @@ -1118,6 +1119,11 @@ def_equ : def_id T_POP_EQU const { } ; +redef_equ : redef_id T_POP_EQU const { + sym_RedefEqu($1, $3); + } +; + def_set : def_id set_or_equal const { sym_AddSet($1, $3); } diff --git a/src/asm/rgbasm.5 b/src/asm/rgbasm.5 index 086206061..f21a72ebf 100644 --- a/src/asm/rgbasm.5 +++ b/src/asm/rgbasm.5 @@ -967,6 +967,26 @@ def SCREEN_HEIGHT equ 144 Note that colons .Ql \&: following the name are not allowed. +.Pp +If you +.Em really +need to, the +.Ic REDEF +keyword will define or redefine a constant symbol. +This can be used, for example, to update a constant using a macro, without making it mutable in general. +.Bd -literal -offset indent + def NUM_ITEMS equ 0 +MACRO add_item + redef NUM_ITEMS equ NUM_ITEMS + 1 + def ITEM_{02x:NUM_ITEMS} equ \1 +ENDM + add_item 1 + add_item 4 + add_item 9 + add_item 16 + assert NUM_ITEMS == 4 + assert ITEM_04 == 16 +.Ed .Ss Mutable constants .Ic SET , or its synonym diff --git a/src/asm/symbol.c b/src/asm/symbol.c index 3982e4722..1c70b04ea 100644 --- a/src/asm/symbol.c +++ b/src/asm/symbol.c @@ -397,6 +397,30 @@ struct Symbol *sym_AddEqu(char const *symName, int32_t value) return sym; } +struct Symbol *sym_RedefEqu(char const *symName, int32_t value) +{ + struct Symbol *sym = sym_FindExactSymbol(symName); + + if (!sym) + return sym_AddEqu(symName, value); + + if (sym_IsDefined(sym) && sym->type != SYM_EQU) { + error("'%s' already defined as non-EQU at ", symName); + dumpFilename(sym); + putc('\n', stderr); + return NULL; + } else if (sym->isBuiltin) { + error("Built-in symbol '%s' cannot be redefined\n", symName); + return NULL; + } + + updateSymbolFilename(sym); + sym->type = SYM_EQU; + sym->value = value; + + return sym; +} + /* * Add a string equated symbol. * diff --git a/test/asm/def.asm b/test/asm/def.asm index 4e896c709..076113de6 100644 --- a/test/asm/def.asm +++ b/test/asm/def.asm @@ -26,4 +26,5 @@ def constant equ 6*7 ; fails redef string equs "there" println "{string}" -redef constant equ 6*9 ; syntax error +redef constant equ 6*9 + println constant diff --git a/test/asm/def.err b/test/asm/def.err index 2fe3ac940..29812c306 100644 --- a/test/asm/def.err +++ b/test/asm/def.err @@ -1,5 +1,3 @@ ERROR: def.asm(23): 'constant' already defined at def.asm(10) -ERROR: def.asm(29): - syntax error, unexpected EQU, expecting SET or = or EQUS -error: Assembly aborted (2 errors)! +error: Assembly aborted (1 error)! diff --git a/test/asm/def.out b/test/asm/def.out index e09b8df47..0ecc9660a 100644 --- a/test/asm/def.out +++ b/test/asm/def.out @@ -7,3 +7,4 @@ here $0 $1 $5 $9 $2A there +$36 diff --git a/test/asm/redef-equ.asm b/test/asm/redef-equ.asm new file mode 100644 index 000000000..1598d43ae --- /dev/null +++ b/test/asm/redef-equ.asm @@ -0,0 +1,23 @@ +DEF n EQU 0 +REDEF n EQU 1 +; prints "$1" +PRINTLN n + +list: MACRO +LIST_NAME EQUS "\1" +DEF LENGTH_{LIST_NAME} EQU 0 +ENDM + +item: MACRO +REDEF LENGTH_{LIST_NAME} EQU LENGTH_{LIST_NAME} + 1 +DEF {LIST_NAME}_{d:LENGTH_{LIST_NAME}} EQU \1 +ENDM + + list SQUARES + item 1 + item 4 + item 9 + println LENGTH_SQUARES, SQUARES_1, SQUARES_2, SQUARES_3 + +N EQUS "X" +REDEF N EQU 42 diff --git a/test/asm/redef-equ.err b/test/asm/redef-equ.err new file mode 100644 index 000000000..5dce53567 --- /dev/null +++ b/test/asm/redef-equ.err @@ -0,0 +1,3 @@ +ERROR: redef-equ.asm(23): + 'N' already defined as non-EQU at redef-equ.asm(22) +error: Assembly aborted (1 error)! diff --git a/test/asm/redef-equ.out b/test/asm/redef-equ.out new file mode 100644 index 000000000..aec9ed58f --- /dev/null +++ b/test/asm/redef-equ.out @@ -0,0 +1,2 @@ +$1 +$3$1$4$9 diff --git a/test/asm/reference-undefined-equs.asm b/test/asm/reference-undefined-equs.asm new file mode 100644 index 000000000..aaed3bd46 --- /dev/null +++ b/test/asm/reference-undefined-equs.asm @@ -0,0 +1,5 @@ +SECTION "sec", ROM0[0] + db s1, s2 + +def s1 equs "1" +redef s2 equs "2" diff --git a/test/asm/reference-undefined-equs.err b/test/asm/reference-undefined-equs.err new file mode 100644 index 000000000..b2657d06a --- /dev/null +++ b/test/asm/reference-undefined-equs.err @@ -0,0 +1,5 @@ +ERROR: reference-undefined-equs.asm(4): + 's1' already referenced at reference-undefined-equs.asm(2) +ERROR: reference-undefined-equs.asm(5): + 's2' already referenced at reference-undefined-equs.asm(2) +error: Assembly aborted (2 errors)! diff --git a/test/asm/reference-undefined-equs.out b/test/asm/reference-undefined-equs.out new file mode 100644 index 000000000..e69de29bb diff --git a/test/asm/reference-undefined-sym.asm b/test/asm/reference-undefined-sym.asm index e12c22747..06650528b 100644 --- a/test/asm/reference-undefined-sym.asm +++ b/test/asm/reference-undefined-sym.asm @@ -1,4 +1,7 @@ SECTION "sec", ROM0[0] - db X + db x1, x2, y1, y2 -X = 2 +def x1 = 1 +redef x2 = 2 +def y1 equ 3 +redef y2 equ 4 diff --git a/test/asm/reference-undefined-sym.out.bin b/test/asm/reference-undefined-sym.out.bin index e69de29bb..82090ee2c 100644 --- a/test/asm/reference-undefined-sym.out.bin +++ b/test/asm/reference-undefined-sym.out.bin @@ -0,0 +1 @@ + \ No newline at end of file