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 10, 2021
1 parent 76446e6 commit 0379b56
Show file tree
Hide file tree
Showing 4 changed files with 111 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_PushInlineBlockSection(void);

struct Section *sect_GetSymbolSection(void);
uint32_t sect_GetSymbolOffset(void);
Expand Down
16 changes: 12 additions & 4 deletions src/asm/lexer.c
Original file line number Diff line number Diff line change
Expand Up @@ -1650,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 @@ -1663,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
24 changes: 24 additions & 0 deletions src/asm/parser.y
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,7 @@ int32_t nPCOffset; /* Read by rpn_Symbol */
static uint32_t nListCountEmpty;
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 inlineBlockID = 0; /* Incrementing unique ID for inline block labels */

static void upperstring(char *dest, char const *src)
{
Expand Down Expand Up @@ -406,6 +407,11 @@ enum {
int32_t step;
} forArgs;
struct StrFmtArgList strfmtArgs;
struct {
char name[24]; // space for "inline_block$4294967295" + '\0'
int32_t nPCOffset;
uint32_t nListCountEmpty;
} inlineBlock;
}

%type <sVal> relocexpr
Expand All @@ -429,12 +435,15 @@ enum {
%type <nConstValue> sectorg
%type <sectSpec> sectattrs

%type <inlineBlock> inline_block

%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 @@ -1185,6 +1194,7 @@ reloc_16bit : relocexpr {
warning(WARNING_TRUNCATION, "Expression must be 16-bit\n");
$$ = $1;
}
| inline_block { rpn_Symbol(&$$, $1.name); }
;

reloc_16bit_no_str : relocexpr_no_str {
Expand All @@ -1193,8 +1203,22 @@ reloc_16bit_no_str : relocexpr_no_str {
warning(WARNING_TRUNCATION, "Expression must be 16-bit\n");
$$ = $1;
}
| inline_block { rpn_Symbol(&$$, $1.name); }
;

inline_block : T_2LBRACK T_NEWLINE {
out_PushInlineBlockSection();
sprintf($<inlineBlock>$.name, "inline_block$%" PRIu32, inlineBlockID++);
sym_AddLabel($<inlineBlock>$.name);
$<inlineBlock>$.nPCOffset = nPCOffset;
$<inlineBlock>$.nListCountEmpty = nListCountEmpty;
} lines T_2RBRACK {
out_PopSection();
strcpy($$.name, $<inlineBlock>3.name);
nPCOffset = $<inlineBlock>3.nPCOffset;
nListCountEmpty = $<inlineBlock>3.nListCountEmpty;
}
;

relocexpr : relocexpr_no_str
| string {
Expand Down
103 changes: 74 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,37 @@ void out_EndLoadSection(void)
loadOffset = 0;
}

void out_PushInlineBlockSection(void)
{
checkcodesection();

if (currentLoadSection)
fatalerror("`LOAD` blocks cannot contain inline blocks\n");

struct Section *sect = pCurrentSection;

// Inline blocks are section fragments, so a section
// containing one 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 block section 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 0379b56

Please sign in to comment.