diff --git a/include/asm/asm.h b/include/asm/asm.h index 69a1954f..ff5de973 100644 --- a/include/asm/asm.h +++ b/include/asm/asm.h @@ -21,7 +21,6 @@ #include "asm/localasm.h" #include "asm/symbol.h" -#define MAXUNIONS 128 #define MAXMACROARGS 99999 #define MAXINCPATHS 128 @@ -29,9 +28,6 @@ extern int32_t nLineNo; extern uint32_t nTotalLines; extern uint32_t nIFDepth; extern bool skipElif; -extern uint32_t nUnionDepth; -extern uint32_t unionStart[MAXUNIONS]; -extern uint32_t unionSize[MAXUNIONS]; extern char tzCurrentFileName[_MAX_PATH + 1]; extern struct Section *pCurrentSection; extern bool oDontExpandStrings; diff --git a/include/asm/section.h b/include/asm/section.h index 3819d92f..8da63b7e 100644 --- a/include/asm/section.h +++ b/include/asm/section.h @@ -46,10 +46,14 @@ void out_EndLoadSection(void); struct Section *sect_GetSymbolSection(void); uint32_t sect_GetSymbolOffset(void); -void sect_SetSymbolOffset(uint32_t ofs); uint32_t sect_GetOutputOffset(void); void sect_AlignPC(uint8_t alignment, uint16_t offset); +void sect_StartUnion(void); +void sect_NextUnionMember(void); +void sect_EndUnion(void); +void sect_CheckUnionClosed(void); + void out_AbsByte(uint8_t b); void out_AbsByteGroup(uint8_t const *s, int32_t length); void out_Skip(int32_t skip, bool ds); diff --git a/src/asm/asmy.y b/src/asm/asmy.y index 8eec6d4e..511173ce 100644 --- a/src/asm/asmy.y +++ b/src/asm/asmy.y @@ -383,32 +383,6 @@ static void if_skip_to_endc(void) nLineNo--; } -static void startUnion(void) -{ - if (!pCurrentSection) - fatalerror("UNIONs must be inside a SECTION"); - - uint32_t unionIndex = nUnionDepth; - - nUnionDepth++; - if (nUnionDepth > MAXUNIONS) - fatalerror("Too many nested UNIONs"); - - unionStart[unionIndex] = sect_GetOutputOffset(); - unionSize[unionIndex] = 0; -} - -static void updateUnion(void) -{ - uint32_t unionIndex = nUnionDepth - 1; - uint32_t size = sect_GetOutputOffset() - unionStart[unionIndex]; - - if (size > unionSize[unionIndex]) - unionSize[unionIndex] = size; - - sect_SetSymbolOffset(unionStart[unionIndex]); -} - static size_t strlenUTF8(const char *s) { size_t len = 0; @@ -975,26 +949,13 @@ rb : T_LABEL T_POP_RB uconst { } ; -union : T_POP_UNION { startUnion(); } +union : T_POP_UNION { sect_StartUnion(); } ; -nextu : T_POP_NEXTU { - if (nUnionDepth <= 0) - fatalerror("Found NEXTU outside of a UNION construct"); - - updateUnion(); - } +nextu : T_POP_NEXTU { sect_NextUnionMember(); } ; -endu : T_POP_ENDU { - if (nUnionDepth <= 0) - fatalerror("Found ENDU outside of a UNION construct"); - - updateUnion(); - - nUnionDepth--; - sect_SetSymbolOffset(unionStart[nUnionDepth] + unionSize[nUnionDepth]); - } +endu : T_POP_ENDU { sect_EndUnion(); } ; ds : T_POP_DS uconst { out_Skip($2, true); } diff --git a/src/asm/main.c b/src/asm/main.c index 9534a98b..b6103db0 100644 --- a/src/asm/main.c +++ b/src/asm/main.c @@ -40,7 +40,7 @@ const size_t cldefine_entrysize = 2 * sizeof(void *); char **cldefines; clock_t nStartClock, nEndClock; -uint32_t nTotalLines, nIFDepth, nUnionDepth; +uint32_t nTotalLines, nIFDepth; bool skipElif; uint32_t unionStart[128], unionSize[128]; @@ -534,7 +534,6 @@ int main(int argc, char *argv[]) nTotalLines = 0; nIFDepth = 0; skipElif = true; - nUnionDepth = 0; sym_Init(); sym_SetExportAll(exportall); fstk_Init(tzMainfile); @@ -553,10 +552,7 @@ int main(int argc, char *argv[]) errx(1, "Unterminated IF construct (%" PRIu32 " levels)!", nIFDepth); - if (nUnionDepth != 0) { - errx(1, "Unterminated UNION construct (%" PRIu32 " levels)!", - nUnionDepth); - } + sect_CheckUnionClosed(); double timespent; diff --git a/src/asm/section.c b/src/asm/section.c index bf857a77..c248643d 100644 --- a/src/asm/section.c +++ b/src/asm/section.c @@ -28,6 +28,12 @@ uint32_t curOffset; /* Offset into the current section (see sect_GetSymbolOffset static struct Section *currentLoadSection = NULL; uint32_t loadOffset; /* The offset of the LOAD section within its parent */ +struct UnionStackEntry { + uint32_t start; + uint32_t size; + struct UnionStackEntry *next; +} *unionStack = NULL; + /* * A quick check to see if we have an initialized section */ @@ -48,8 +54,6 @@ static inline void checkcodesection(void) if (!sect_HasData(pCurrentSection->nType)) fatalerror("Section '%s' cannot contain code or data (not ROM0 or ROMX)", pCurrentSection->pzName); - else if (nUnionDepth > 0) - fatalerror("UNIONs cannot contain code or data"); } static inline void checkSectionSize(struct Section const *sect, uint32_t size) @@ -302,7 +306,7 @@ static struct Section *getSection(char const *pzName, enum SectionType type, */ static void changeSection(void) { - if (nUnionDepth > 0) + if (unionStack) fatalerror("Cannot change the section within a UNION"); sym_SetCurrentSymbolScope(NULL); @@ -367,11 +371,6 @@ uint32_t sect_GetSymbolOffset(void) return curOffset; } -void sect_SetSymbolOffset(uint32_t ofs) -{ - curOffset = ofs; -} - uint32_t sect_GetOutputOffset(void) { return curOffset + loadOffset; @@ -436,6 +435,56 @@ static inline void createPatch(enum PatchType type, out_CreatePatch(type, expr, sect_GetOutputOffset()); } +void sect_StartUnion(void) +{ + if (!pCurrentSection) + fatalerror("UNIONs must be inside a SECTION"); + if (sect_HasData(pCurrentSection->nType)) + fatalerror("Cannot use UNION inside of ROM0 or ROMX sections"); + struct UnionStackEntry *entry = malloc(sizeof(*entry)); + + if (!entry) + fatalerror("Failed to allocate new union stack entry: %s", strerror(errno)); + entry->start = curOffset; + entry->size = 0; + entry->next = unionStack; + unionStack = entry; +} + +static void endUnionMember(void) +{ + uint32_t memberSize = curOffset - unionStack->start; + + if (memberSize > unionStack->size) + unionStack->size = memberSize; + curOffset = unionStack->start; +} + +void sect_NextUnionMember(void) +{ + if (!unionStack) + fatalerror("Found NEXTU outside of a UNION construct"); + endUnionMember(); +} + +void sect_EndUnion(void) +{ + if (!unionStack) + fatalerror("Found ENDU outside of a UNION construct"); + endUnionMember(); + curOffset += unionStack->size; + struct UnionStackEntry *next = unionStack->next; + + free(unionStack); + unionStack = next; +} + +void sect_CheckUnionClosed(void) +{ + if (unionStack) + fatalerror("Unterminated UNION construct!"); +} + /* * Output an absolute byte */ @@ -469,9 +518,6 @@ void out_Skip(int32_t skip, bool ds) if (!sect_HasData(pCurrentSection->nType)) { growSection(skip); - } else if (nUnionDepth > 0) { - while (skip--) - writebyte(CurrentOptions.fillchar); } else { checkcodesection(); while (skip--)