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 e327f30
Show file tree
Hide file tree
Showing 4 changed files with 103 additions and 33 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
101 changes: 72 additions & 29 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 @@ -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;
Expand Down Expand Up @@ -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;
Expand Down

0 comments on commit e327f30

Please sign in to comment.