Skip to content

Commit

Permalink
Implement [[ inline fragments ]]
Browse files Browse the repository at this point in the history
Fixes gbdev#500
  • Loading branch information
Rangi42 committed Feb 11, 2021
1 parent 88e1cc7 commit ddbb53f
Show file tree
Hide file tree
Showing 14 changed files with 192 additions and 38 deletions.
1 change: 1 addition & 0 deletions include/asm/section.h
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down
18 changes: 14 additions & 4 deletions src/asm/lexer.c
Original file line number Diff line number Diff line change
Expand Up @@ -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 == '_';
}

Expand Down Expand Up @@ -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 ')':
Expand All @@ -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);
Expand Down
16 changes: 16 additions & 0 deletions src/asm/parser.y
Original file line number Diff line number Diff line change
Expand Up @@ -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)
{
Expand Down Expand Up @@ -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 <sVal> relocexpr
Expand All @@ -430,12 +432,15 @@ enum {
%type <nConstValue> sectorg
%type <sectSpec> sectattrs

%type <inlineFragmentName> inline_fragment

%token <nConstValue> T_NUMBER "number"
%token <tzString> 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"

Expand Down Expand Up @@ -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 {
Expand All @@ -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($<inlineFragmentName>$, "$%" PRIu32, inlineFragmentID++);
sym_AddLabel($<inlineFragmentName>$);
} asmfile T_2RBRACK {
out_PopSection();
strcpy($$, $<inlineFragmentName>2);
}
;

relocexpr : relocexpr_no_str
| string {
Expand Down
109 changes: 75 additions & 34 deletions src/asm/section.c
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down Expand Up @@ -317,42 +358,13 @@ static struct Section *getSection(char const *name, enum SectionType type, uint3

if (sect) {
mergeSections(sect, type, org, bank, alignment, alignOffset, mod);
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;
pSectionList = sect;
}

// Add the new section to the list (order doesn't matter)
sect->next = pSectionList;
pSectionList = sect;

return sect;
}

Expand Down Expand Up @@ -416,6 +428,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 new 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;
Expand Down
14 changes: 14 additions & 0 deletions test/asm/inline-fragment-in-load.asm
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
SECTION "OAMDMACode", ROM0
OAMDMACode:
LOAD "hOAMDMA", HRAM
hOAMDMA::
ldh [$ff46], a
ld a, 40
jp [[
: dec a
jr nz, :-
ret
]]
.end
ENDL
OAMDMACodeEnd:
2 changes: 2 additions & 0 deletions test/asm/inline-fragment-in-load.err
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
FATAL: inline-fragment-in-load.asm(7):
`LOAD` blocks cannot contain inline fragments
Empty file.
9 changes: 9 additions & 0 deletions test/asm/inline-fragment-in-ram.asm
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
SECTION "RAM", WRAM0

wFoo:: db
wBar:: ds 3
println "ok"
wQux:: dw [[
ds 4
println "inline"
]]
2 changes: 2 additions & 0 deletions test/asm/inline-fragment-in-ram.err
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
FATAL: inline-fragment-in-ram.asm(6):
Section 'RAM' cannot contain code or data (not ROM0 or ROMX)
1 change: 1 addition & 0 deletions test/asm/inline-fragment-in-ram.out
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
ok
58 changes: 58 additions & 0 deletions test/asm/inline-fragments.asm
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
SECTION "1", ROM0[0]

VERSION EQU $11
GetVersion::
ld a, [ [[db VERSION]] ]
ret

SECTION "2", ROM0, ALIGN[4]

text: MACRO
db \1, 0
ENDM

text_pointer: MACRO
dw [[ text \1 ]]
ENDM

GetText::
ld hl, [[
dw [[ db "Alpha", 0 ]]
dw [[ text "Beta" ]]
text_pointer "Gamma"
dw 0
]]
ld c, a
ld b, 0
add hl, bc
add hl, bc
ld a, [hli]
ld h, [hl]
ld l, a
ret

SECTION "C", ROM0

Foo::
call [[ jp [[ jp [[ ret ]] ]] ]]
call [[
Label::
call GetVersion
MYTEXT EQU 3
ld a, MYTEXT
call GetText
ld b, h
ld c, l
ret
]]
jp [[
Bar:
inc hl
.loop
halt
: dec l
jr nz, :-
dec h
jr nz, .loop
ret
]]
Empty file added test/asm/inline-fragments.err
Empty file.
Empty file added test/asm/inline-fragments.out
Empty file.
Binary file added test/asm/inline-fragments.out.bin
Binary file not shown.

0 comments on commit ddbb53f

Please sign in to comment.