Skip to content

Commit

Permalink
Implement [[ inline code blocks ]]
Browse files Browse the repository at this point in the history
Fixes #500
  • Loading branch information
Rangi42 committed Jan 24, 2021
1 parent 6623b1d commit faeb5d5
Show file tree
Hide file tree
Showing 4 changed files with 100 additions and 4 deletions.
3 changes: 3 additions & 0 deletions include/asm/section.h
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,9 @@ void sect_NextUnionMember(void);
void sect_EndUnion(void);
void sect_CheckUnionClosed(void);

char *sect_StartInlineBlock(void);
void sect_EndInlineBlock(void);

void out_AbsByte(uint8_t b);
void out_AbsByteGroup(uint8_t const *s, int32_t length);
void out_AbsWordGroup(uint8_t const *s, int32_t length);
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
27 changes: 27 additions & 0 deletions src/asm/parser.y
Original file line number Diff line number Diff line change
Expand Up @@ -406,6 +406,11 @@ enum {
int32_t step;
} forArgs;
struct StrFmtArgList strfmtArgs;
struct {
char *name;
int32_t nPCOffset;
uint32_t nListCountEmpty;
} inlineBlock;
}

%type <sVal> relocexpr
Expand All @@ -429,12 +434,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 +1193,10 @@ reloc_16bit : relocexpr {
warning(WARNING_TRUNCATION, "Expression must be 16-bit\n");
$$ = $1;
}
| inline_block {
rpn_Symbol(&$$, $1.name);
free($1.name);
}
;

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

inline_block : T_2LBRACK T_NEWLINE {
$<inlineBlock>$.name = sect_StartInlineBlock();
$<inlineBlock>$.nPCOffset = nPCOffset;
$<inlineBlock>$.nListCountEmpty = nListCountEmpty;
} lines T_2RBRACK {
sect_EndInlineBlock();
$$.name = $<inlineBlock>3.name;
nPCOffset = $<inlineBlock>3.nPCOffset;
nListCountEmpty = $<inlineBlock>3.nListCountEmpty;
}
;

relocexpr : relocexpr_no_str
| string {
Expand Down
58 changes: 58 additions & 0 deletions src/asm/section.c
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,8 @@ uint32_t curOffset; /* Offset into the current section (see sect_GetSymbolOffset
static struct Section *currentLoadSection = NULL;
uint32_t loadOffset; /* The offset of the LOAD section within its parent */

static uint32_t inlineBlockID = 0; /* Incrementing unique ID for inline block labels */

struct UnionStackEntry {
uint32_t start;
uint32_t size;
Expand Down Expand Up @@ -492,6 +494,62 @@ void sect_CheckUnionClosed(void)
error("Unterminated UNION construct!\n");
}

char *sect_StartInlineBlock(void)
{
checkcodesection();

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

struct Section *sect = pCurrentSection;

/*
* Inline blocks are section fragments, so the section containing them
* has to become a fragment too.
*/
sect->modifier = SECTION_FRAGMENT;

struct SectionSpec attrs;

// 'SECTION "...", ROM0, BANK[0]' is not allowed
attrs.bank = sect->bank == 0 ? -1 : sect->bank;
attrs.alignment = 0;
attrs.alignOfs = 0;

/*
* Initialize the inline block's section with a unique name so out_NewSection
* won't just find the current existing section.
*/
char *name = malloc(24); // space for "inline_block$4294967295" + '\0'

if (name == NULL)
fatalerror("Not enough memory for inline block name: %s\n", strerror(errno));

sprintf(name, "inline_block$%" PRIu32, inlineBlockID++);

out_PushSection();
out_NewSection(name, sect->type, -1, &attrs, SECTION_FRAGMENT);

/*
* Rename the inline block's section fragment to match the current section
* so they'll be merged.
*/
free(pCurrentSection->name);
pCurrentSection->name = strdup(sect->name);
if (pCurrentSection->name == NULL)
fatalerror("Not enough memory for inline block name: %s\n", strerror(errno));

// Label the start of the inline block to get its address.
sym_AddLabel(name);

return name;
}

void sect_EndInlineBlock(void)
{
out_PopSection();
}

/*
* Output an absolute byte
*/
Expand Down

0 comments on commit faeb5d5

Please sign in to comment.