Skip to content

Commit 2a13b40

Browse files
committed
Implement [[ inline fragments ]]
Fixes gbdev#500
1 parent 88e1cc7 commit 2a13b40

File tree

4 files changed

+106
-38
lines changed

4 files changed

+106
-38
lines changed

include/asm/section.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,7 @@ void out_NewSection(char const *name, uint32_t secttype, uint32_t org,
4545
void out_SetLoadSection(char const *name, uint32_t secttype, uint32_t org,
4646
struct SectionSpec const *attributes);
4747
void out_EndLoadSection(void);
48+
void out_PushInlineFragmentSection(void);
4849

4950
struct Section *sect_GetSymbolSection(void);
5051
uint32_t sect_GetSymbolOffset(void);

src/asm/lexer.c

Lines changed: 14 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1251,6 +1251,8 @@ static void readGfxConstant(void)
12511251

12521252
static bool startsIdentifier(int c)
12531253
{
1254+
// Anonymous labels internally start with '!'
1255+
// Section fragment labels internally start with '$'
12541256
return (c <= 'Z' && c >= 'A') || (c <= 'z' && c >= 'a') || c == '.' || c == '_';
12551257
}
12561258

@@ -1648,10 +1650,6 @@ static int yylex_NORMAL(void)
16481650
yylval.tzSym[1] = '\0';
16491651
return T_ID;
16501652

1651-
case '[':
1652-
return T_LBRACK;
1653-
case ']':
1654-
return T_RBRACK;
16551653
case '(':
16561654
return T_LPAREN;
16571655
case ')':
@@ -1661,6 +1659,18 @@ static int yylex_NORMAL(void)
16611659

16621660
/* Handle ambiguous 1- or 2-char tokens */
16631661

1662+
case '[': /* Either [ or [[ */
1663+
if (peek(0) == '[') {
1664+
shiftChars(1);
1665+
return T_2LBRACK;
1666+
}
1667+
return T_LBRACK;
1668+
case ']': /* Either ] or ]] */
1669+
if (peek(0) == ']') {
1670+
shiftChars(1);
1671+
return T_2RBRACK;
1672+
}
1673+
return T_RBRACK;
16641674
case '*': /* Either MUL or EXP */
16651675
if (peek(0) == '*') {
16661676
shiftChars(1);

src/asm/parser.y

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,7 @@
3838

3939
static bool executeElseBlock; /* If this is set, ELIFs cannot be executed anymore */
4040
static struct CaptureBody captureBody; /* Captures a REPT/FOR or MACRO */
41+
static uint32_t inlineFragmentID = 0; /* Incrementing unique ID for inline fragment labels */
4142

4243
static void upperstring(char *dest, char const *src)
4344
{
@@ -404,6 +405,7 @@ enum {
404405
} forArgs;
405406
struct StrFmtArgList strfmtArgs;
406407
bool hasEmpty; // Whether `db`, `dw`, `dl` argument lists contain any empty entries
408+
char inlineFragmentName[12]; // space for "$4294967295" + '\0'
407409
}
408410

409411
%type <sVal> relocexpr
@@ -430,12 +432,15 @@ enum {
430432
%type <nConstValue> sectorg
431433
%type <sectSpec> sectattrs
432434

435+
%type <inlineFragmentName> inline_fragment
436+
433437
%token <nConstValue> T_NUMBER "number"
434438
%token <tzString> T_STRING "string"
435439

436440
%token T_COMMA ","
437441
%token T_COLON ":"
438442
%token T_LBRACK "[" T_RBRACK "]"
443+
%token T_2LBRACK "[[" T_2RBRACK "]]"
439444
%token T_LPAREN "(" T_RPAREN ")"
440445
%token T_NEWLINE "newline"
441446

@@ -1206,6 +1211,7 @@ reloc_16bit : relocexpr {
12061211
warning(WARNING_TRUNCATION, "Expression must be 16-bit\n");
12071212
$$ = $1;
12081213
}
1214+
| inline_fragment { rpn_Symbol(&$$, $1); }
12091215
;
12101216

12111217
reloc_16bit_no_str : relocexpr_no_str {
@@ -1214,8 +1220,18 @@ reloc_16bit_no_str : relocexpr_no_str {
12141220
warning(WARNING_TRUNCATION, "Expression must be 16-bit\n");
12151221
$$ = $1;
12161222
}
1223+
| inline_fragment { rpn_Symbol(&$$, $1); }
12171224
;
12181225

1226+
inline_fragment : T_2LBRACK {
1227+
out_PushInlineFragmentSection();
1228+
sprintf($<inlineFragmentName>$, "$%" PRIu32, inlineFragmentID++);
1229+
sym_AddLabel($<inlineFragmentName>$);
1230+
} asmfile T_2RBRACK {
1231+
out_PopSection();
1232+
strcpy($$, $<inlineFragmentName>2);
1233+
}
1234+
;
12191235

12201236
relocexpr : relocexpr_no_str
12211237
| string {

src/asm/section.c

Lines changed: 75 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -249,7 +249,48 @@ static void mergeSections(struct Section *sect, enum SectionType type, uint32_t
249249
#undef fail
250250

251251
/*
252-
* Find a section by name and type. If it doesn't exist, create it
252+
* Create a new section, not yet in the list.
253+
*/
254+
static struct Section *createSection(char const *name, enum SectionType type,
255+
uint32_t org, uint32_t bank, uint8_t alignment,
256+
uint16_t alignOffset, enum SectionModifier mod)
257+
{
258+
struct Section *sect = malloc(sizeof(*sect));
259+
260+
if (sect == NULL)
261+
fatalerror("Not enough memory for section: %s\n", strerror(errno));
262+
263+
sect->name = strdup(name);
264+
if (sect->name == NULL)
265+
fatalerror("Not enough memory for section name: %s\n", strerror(errno));
266+
267+
sect->type = type;
268+
sect->modifier = mod;
269+
sect->size = 0;
270+
sect->org = org;
271+
sect->bank = bank;
272+
sect->align = alignment;
273+
sect->alignOfs = alignOffset;
274+
sect->next = NULL;
275+
sect->patches = NULL;
276+
277+
/* It is only needed to allocate memory for ROM sections. */
278+
if (sect_HasData(type)) {
279+
uint32_t sectsize;
280+
281+
sectsize = maxsize[type];
282+
sect->data = malloc(sectsize);
283+
if (sect->data == NULL)
284+
fatalerror("Not enough memory for section: %s\n", strerror(errno));
285+
} else {
286+
sect->data = NULL;
287+
}
288+
289+
return sect;
290+
}
291+
292+
/*
293+
* Find a section by name and type. If it doesn't exist, create it.
253294
*/
254295
static struct Section *getSection(char const *name, enum SectionType type, uint32_t org,
255296
struct SectionSpec const *attrs, enum SectionModifier mod)
@@ -317,42 +358,13 @@ static struct Section *getSection(char const *name, enum SectionType type, uint3
317358

318359
if (sect) {
319360
mergeSections(sect, type, org, bank, alignment, alignOffset, mod);
320-
return sect;
321-
}
322-
323-
sect = malloc(sizeof(*sect));
324-
if (sect == NULL)
325-
fatalerror("Not enough memory for section: %s\n", strerror(errno));
326-
327-
sect->name = strdup(name);
328-
if (sect->name == NULL)
329-
fatalerror("Not enough memory for section name: %s\n", strerror(errno));
330-
331-
sect->type = type;
332-
sect->modifier = mod;
333-
sect->size = 0;
334-
sect->org = org;
335-
sect->bank = bank;
336-
sect->align = alignment;
337-
sect->alignOfs = alignOffset;
338-
sect->patches = NULL;
339-
340-
/* It is only needed to allocate memory for ROM sections. */
341-
if (sect_HasData(type)) {
342-
uint32_t sectsize;
343-
344-
sectsize = maxsize[type];
345-
sect->data = malloc(sectsize);
346-
if (sect->data == NULL)
347-
fatalerror("Not enough memory for section: %s\n", strerror(errno));
348361
} else {
349-
sect->data = NULL;
362+
sect = createSection(name, type, org, bank, alignment, alignOffset, mod);
363+
// Add the new section to the list (order doesn't matter)
364+
sect->next = pSectionList;
365+
pSectionList = sect;
350366
}
351367

352-
// Add the new section to the list (order doesn't matter)
353-
sect->next = pSectionList;
354-
pSectionList = sect;
355-
356368
return sect;
357369
}
358370

@@ -416,6 +428,35 @@ void out_EndLoadSection(void)
416428
loadOffset = 0;
417429
}
418430

431+
void out_PushInlineFragmentSection(void)
432+
{
433+
checkcodesection();
434+
435+
if (currentLoadSection)
436+
fatalerror("`LOAD` blocks cannot contain inline fragments\n");
437+
438+
struct Section *sect = pCurrentSection;
439+
440+
// A section containing an inline fragment has to become a fragment too
441+
sect->modifier = SECTION_FRAGMENT;
442+
443+
out_PushSection();
444+
445+
// `SECTION "...", ROM0, BANK[0]` is not allowed
446+
uint32_t bank = sect->bank == 0 ? -1 : sect->bank;
447+
448+
struct Section *newSect = createSection(sect->name, sect->type, -1, bank, 0, 0,
449+
SECTION_FRAGMENT);
450+
451+
// Add the new section fragment to the list (after the section containing it)
452+
newSect->next = sect->next;
453+
sect->next = newSect;
454+
455+
changeSection();
456+
curOffset = newSect->size;
457+
pCurrentSection = newSect;
458+
}
459+
419460
struct Section *sect_GetSymbolSection(void)
420461
{
421462
return currentLoadSection ? currentLoadSection : pCurrentSection;

0 commit comments

Comments
 (0)