diff --git a/include/asm/section.h b/include/asm/section.h index 9f0efd92b9..4469144da1 100644 --- a/include/asm/section.h +++ b/include/asm/section.h @@ -45,6 +45,7 @@ void out_NewSection(char const *name, uint32_t secttype, uint32_t org, void out_SetLoadSection(char const *name, uint32_t secttype, uint32_t org, struct SectionSpec const *attributes); void out_EndLoadSection(void); +void out_PushInlineFragmentSection(void); struct Section *sect_GetSymbolSection(void); uint32_t sect_GetSymbolOffset(void); diff --git a/src/asm/lexer.c b/src/asm/lexer.c index c29fc26b2f..dd3e58cf65 100644 --- a/src/asm/lexer.c +++ b/src/asm/lexer.c @@ -1251,6 +1251,8 @@ static void readGfxConstant(void) static bool startsIdentifier(int c) { + // Anonymous labels internally start with '!' + // Section fragment labels internally start with '$' return (c <= 'Z' && c >= 'A') || (c <= 'z' && c >= 'a') || c == '.' || c == '_'; } @@ -1648,10 +1650,6 @@ static int yylex_NORMAL(void) yylval.tzSym[1] = '\0'; return T_ID; - case '[': - return T_LBRACK; - case ']': - return T_RBRACK; case '(': return T_LPAREN; case ')': @@ -1661,6 +1659,18 @@ static int yylex_NORMAL(void) /* Handle ambiguous 1- or 2-char tokens */ + case '[': /* Either [ or [[ */ + if (peek(0) == '[') { + shiftChars(1); + return T_2LBRACK; + } + return T_LBRACK; + case ']': /* Either ] or ]] */ + if (peek(0) == ']') { + shiftChars(1); + return T_2RBRACK; + } + return T_RBRACK; case '*': /* Either MUL or EXP */ if (peek(0) == '*') { shiftChars(1); diff --git a/src/asm/parser.y b/src/asm/parser.y index c0e2b1419f..740c48b835 100644 --- a/src/asm/parser.y +++ b/src/asm/parser.y @@ -38,6 +38,7 @@ static bool executeElseBlock; /* If this is set, ELIFs cannot be executed anymore */ static struct CaptureBody captureBody; /* Captures a REPT/FOR or MACRO */ +static uint32_t inlineFragmentID = 0; /* Incrementing unique ID for inline fragment labels */ static void upperstring(char *dest, char const *src) { @@ -404,6 +405,7 @@ enum { } forArgs; struct StrFmtArgList strfmtArgs; bool hasEmpty; // Whether `db`, `dw`, `dl` argument lists contain any empty entries + char inlineFragmentName[12]; // space for "$4294967295" + '\0' } %type relocexpr @@ -430,12 +432,15 @@ enum { %type sectorg %type sectattrs +%type inline_fragment + %token T_NUMBER "number" %token T_STRING "string" %token T_COMMA "," %token T_COLON ":" %token T_LBRACK "[" T_RBRACK "]" +%token T_2LBRACK "[[" T_2RBRACK "]]" %token T_LPAREN "(" T_RPAREN ")" %token T_NEWLINE "newline" @@ -1206,6 +1211,7 @@ reloc_16bit : relocexpr { warning(WARNING_TRUNCATION, "Expression must be 16-bit\n"); $$ = $1; } + | inline_fragment { rpn_Symbol(&$$, $1); } ; reloc_16bit_no_str : relocexpr_no_str { @@ -1214,8 +1220,18 @@ reloc_16bit_no_str : relocexpr_no_str { warning(WARNING_TRUNCATION, "Expression must be 16-bit\n"); $$ = $1; } + | inline_fragment { rpn_Symbol(&$$, $1); } ; +inline_fragment : T_2LBRACK { + out_PushInlineFragmentSection(); + sprintf($$, "$%" PRIu32, inlineFragmentID++); + sym_AddLabel($$); + } asmfile T_2RBRACK { + out_PopSection(); + strcpy($$, $2); + } +; relocexpr : relocexpr_no_str | string { diff --git a/src/asm/section.c b/src/asm/section.c index e77018eacb..f67b657688 100644 --- a/src/asm/section.c +++ b/src/asm/section.c @@ -249,7 +249,48 @@ static void mergeSections(struct Section *sect, enum SectionType type, uint32_t #undef fail /* - * Find a section by name and type. If it doesn't exist, create it + * Create a new section, not yet in the list. + */ +static struct Section *createSection(char const *name, enum SectionType type, + uint32_t org, uint32_t bank, uint8_t alignment, + uint16_t alignOffset, enum SectionModifier mod) +{ + struct Section *sect = malloc(sizeof(*sect)); + + if (sect == NULL) + fatalerror("Not enough memory for section: %s\n", strerror(errno)); + + sect->name = strdup(name); + if (sect->name == NULL) + fatalerror("Not enough memory for section name: %s\n", strerror(errno)); + + sect->type = type; + sect->modifier = mod; + sect->size = 0; + sect->org = org; + sect->bank = bank; + sect->align = alignment; + sect->alignOfs = alignOffset; + sect->next = NULL; + sect->patches = NULL; + + /* It is only needed to allocate memory for ROM sections. */ + if (sect_HasData(type)) { + uint32_t sectsize; + + sectsize = maxsize[type]; + sect->data = malloc(sectsize); + if (sect->data == NULL) + fatalerror("Not enough memory for section: %s\n", strerror(errno)); + } else { + sect->data = NULL; + } + + return sect; +} + +/* + * Find a section by name and type. If it doesn't exist, create it. */ static struct Section *getSection(char const *name, enum SectionType type, uint32_t org, struct SectionSpec const *attrs, enum SectionModifier mod) @@ -320,34 +361,7 @@ static struct Section *getSection(char const *name, enum SectionType type, uint3 return sect; } - sect = malloc(sizeof(*sect)); - if (sect == NULL) - fatalerror("Not enough memory for section: %s\n", strerror(errno)); - - sect->name = strdup(name); - if (sect->name == NULL) - fatalerror("Not enough memory for section name: %s\n", strerror(errno)); - - sect->type = type; - sect->modifier = mod; - sect->size = 0; - sect->org = org; - sect->bank = bank; - sect->align = alignment; - sect->alignOfs = alignOffset; - sect->patches = NULL; - - /* It is only needed to allocate memory for ROM sections. */ - if (sect_HasData(type)) { - uint32_t sectsize; - - sectsize = maxsize[type]; - sect->data = malloc(sectsize); - if (sect->data == NULL) - fatalerror("Not enough memory for section: %s\n", strerror(errno)); - } else { - sect->data = NULL; - } + sect = createSection(name, type, org, bank, alignment, alignOffset, mod); // Add the new section to the list (order doesn't matter) sect->next = pSectionList; @@ -416,6 +430,35 @@ void out_EndLoadSection(void) loadOffset = 0; } +void out_PushInlineFragmentSection(void) +{ + checkcodesection(); + + if (currentLoadSection) + fatalerror("`LOAD` blocks cannot contain inline fragments\n"); + + struct Section *sect = pCurrentSection; + + // A section containing an inline fragment has to become a fragment too + sect->modifier = SECTION_FRAGMENT; + + out_PushSection(); + + // 'SECTION "...", ROM0, BANK[0]' is not allowed + uint32_t bank = sect->bank == 0 ? -1 : sect->bank; + + struct Section *newSect = createSection(sect->name, sect->type, -1, bank, 0, 0, + SECTION_FRAGMENT); + + // Add the inline section fragment to the list (after the section containing it) + newSect->next = sect->next; + sect->next = newSect; + + changeSection(); + curOffset = newSect->size; + pCurrentSection = newSect; +} + struct Section *sect_GetSymbolSection(void) { return currentLoadSection ? currentLoadSection : pCurrentSection;