mirror of
https://github.com/gbdev/rgbds.git
synced 2025-11-21 18:52:07 +00:00
Implement INCLUDE keyword in linker scripts
This commit is contained in:
@@ -13,6 +13,60 @@
|
|||||||
|
|
||||||
FILE *linkerScript;
|
FILE *linkerScript;
|
||||||
|
|
||||||
|
static uint32_t lineNo;
|
||||||
|
|
||||||
|
static struct {
|
||||||
|
FILE *file;
|
||||||
|
uint32_t lineNo;
|
||||||
|
char const *name;
|
||||||
|
} *fileStack;
|
||||||
|
|
||||||
|
static uint32_t fileStackSize;
|
||||||
|
static uint32_t fileStackIndex;
|
||||||
|
|
||||||
|
static void pushFile(char const *newFileName)
|
||||||
|
{
|
||||||
|
if (fileStackIndex == UINT32_MAX)
|
||||||
|
errx(1, "%s(%u): INCLUDE recursion limit reached",
|
||||||
|
linkerScriptName, lineNo);
|
||||||
|
|
||||||
|
if (fileStackIndex == fileStackSize) {
|
||||||
|
if (!fileStackSize) /* Init file stack */
|
||||||
|
fileStackSize = 4;
|
||||||
|
fileStackSize *= 2;
|
||||||
|
fileStack = realloc(fileStack,
|
||||||
|
sizeof(*fileStack) * fileStackSize);
|
||||||
|
if (!fileStack)
|
||||||
|
err(1, "%s(%u): Internal INCLUDE error",
|
||||||
|
linkerScriptName, lineNo);
|
||||||
|
}
|
||||||
|
|
||||||
|
fileStack[fileStackIndex].file = linkerScript;
|
||||||
|
fileStack[fileStackIndex].lineNo = lineNo;
|
||||||
|
fileStack[fileStackIndex].name = linkerScriptName;
|
||||||
|
fileStackIndex++;
|
||||||
|
|
||||||
|
linkerScript = fopen(newFileName, "r");
|
||||||
|
if (!linkerScript)
|
||||||
|
err(1, "%s(%u): Could not open \"%s\"",
|
||||||
|
linkerScriptName, lineNo, newFileName);
|
||||||
|
lineNo = 1;
|
||||||
|
linkerScriptName = newFileName;
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool popFile(void)
|
||||||
|
{
|
||||||
|
if (!fileStackIndex)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
fileStackIndex--;
|
||||||
|
linkerScript = fileStack[fileStackIndex].file;
|
||||||
|
lineNo = fileStack[fileStackIndex].lineNo;
|
||||||
|
linkerScriptName = fileStack[fileStackIndex].name;
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
static inline bool isWhiteSpace(int c)
|
static inline bool isWhiteSpace(int c)
|
||||||
{
|
{
|
||||||
return c == ' ' || c == '\t';
|
return c == ' ' || c == '\t';
|
||||||
@@ -69,13 +123,23 @@ enum LinkerScriptTokenType {
|
|||||||
TOKEN_NEWLINE,
|
TOKEN_NEWLINE,
|
||||||
TOKEN_COMMAND,
|
TOKEN_COMMAND,
|
||||||
TOKEN_BANK,
|
TOKEN_BANK,
|
||||||
|
TOKEN_INCLUDE,
|
||||||
TOKEN_NUMBER,
|
TOKEN_NUMBER,
|
||||||
TOKEN_SECTION,
|
TOKEN_STRING,
|
||||||
TOKEN_EOF,
|
TOKEN_EOF,
|
||||||
|
|
||||||
TOKEN_INVALID
|
TOKEN_INVALID
|
||||||
};
|
};
|
||||||
|
|
||||||
|
char const *tokenTypes[] = {
|
||||||
|
[TOKEN_NEWLINE] = "newline",
|
||||||
|
[TOKEN_COMMAND] = "command",
|
||||||
|
[TOKEN_BANK] = "bank command",
|
||||||
|
[TOKEN_NUMBER] = "number",
|
||||||
|
[TOKEN_STRING] = "string",
|
||||||
|
[TOKEN_EOF] = "end of file"
|
||||||
|
};
|
||||||
|
|
||||||
enum LinkerScriptCommand {
|
enum LinkerScriptCommand {
|
||||||
COMMAND_ORG,
|
COMMAND_ORG,
|
||||||
COMMAND_ALIGN,
|
COMMAND_ALIGN,
|
||||||
@@ -98,8 +162,6 @@ static char const * const commands[] = {
|
|||||||
[COMMAND_ALIGN] = "ALIGN"
|
[COMMAND_ALIGN] = "ALIGN"
|
||||||
};
|
};
|
||||||
|
|
||||||
static uint32_t lineNo;
|
|
||||||
|
|
||||||
static int readChar(FILE *file)
|
static int readChar(FILE *file)
|
||||||
{
|
{
|
||||||
int curchar = getc_unlocked(file);
|
int curchar = getc_unlocked(file);
|
||||||
@@ -115,7 +177,7 @@ static struct LinkerScriptToken const *nextToken(void)
|
|||||||
int curchar;
|
int curchar;
|
||||||
|
|
||||||
/* If the token has a string, make sure to avoid leaking it */
|
/* If the token has a string, make sure to avoid leaking it */
|
||||||
if (token.type == TOKEN_SECTION)
|
if (token.type == TOKEN_STRING)
|
||||||
free(token.attr.string);
|
free(token.attr.string);
|
||||||
|
|
||||||
/* Skip initial whitespace... */
|
/* Skip initial whitespace... */
|
||||||
@@ -140,8 +202,8 @@ static struct LinkerScriptToken const *nextToken(void)
|
|||||||
if (curchar == '\r')
|
if (curchar == '\r')
|
||||||
readChar(linkerScript); /* Read and discard LF */
|
readChar(linkerScript); /* Read and discard LF */
|
||||||
} else if (curchar == '"') {
|
} else if (curchar == '"') {
|
||||||
/* If we have a string start, this is a section name */
|
/* If we have a string start, this is a string */
|
||||||
token.type = TOKEN_SECTION;
|
token.type = TOKEN_STRING;
|
||||||
token.attr.string = NULL; /* Force initial alloc */
|
token.attr.string = NULL; /* Force initial alloc */
|
||||||
|
|
||||||
size_t size = 0;
|
size_t size = 0;
|
||||||
@@ -160,7 +222,7 @@ static struct LinkerScriptToken const *nextToken(void)
|
|||||||
token.attr.string = realloc(token.attr.string,
|
token.attr.string = realloc(token.attr.string,
|
||||||
capacity);
|
capacity);
|
||||||
if (!token.attr.string)
|
if (!token.attr.string)
|
||||||
err(1, "%s: Failed to allocate memory for section name",
|
err(1, "%s: Failed to allocate memory for string",
|
||||||
__func__);
|
__func__);
|
||||||
}
|
}
|
||||||
token.attr.string[size++] = curchar;
|
token.attr.string[size++] = curchar;
|
||||||
@@ -217,6 +279,12 @@ static struct LinkerScriptToken const *nextToken(void)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (token.type == TOKEN_INVALID) {
|
||||||
|
/* Try to match an include token */
|
||||||
|
if (!strcmp("INCLUDE", str))
|
||||||
|
token.type = TOKEN_INCLUDE;
|
||||||
|
}
|
||||||
|
|
||||||
if (token.type == TOKEN_INVALID) {
|
if (token.type == TOKEN_INVALID) {
|
||||||
/* None of the strings matched, do we have a number? */
|
/* None of the strings matched, do we have a number? */
|
||||||
if (tryParseNumber(str, &token.attr.number))
|
if (tryParseNumber(str, &token.attr.number))
|
||||||
@@ -259,6 +327,7 @@ static void processCommand(enum LinkerScriptCommand command, uint16_t arg,
|
|||||||
enum LinkerScriptParserState {
|
enum LinkerScriptParserState {
|
||||||
PARSER_FIRSTTIME,
|
PARSER_FIRSTTIME,
|
||||||
PARSER_LINESTART,
|
PARSER_LINESTART,
|
||||||
|
PARSER_INCLUDE, /* After an INCLUDE token */
|
||||||
PARSER_LINEEND
|
PARSER_LINEEND
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -318,17 +387,22 @@ struct SectionPlacement *script_NextSection(void)
|
|||||||
trap_;
|
trap_;
|
||||||
|
|
||||||
case TOKEN_EOF:
|
case TOKEN_EOF:
|
||||||
return NULL;
|
if (!popFile())
|
||||||
|
return NULL;
|
||||||
|
parserState = PARSER_LINEEND;
|
||||||
|
break;
|
||||||
|
|
||||||
case TOKEN_NUMBER:
|
case TOKEN_NUMBER:
|
||||||
errx(1, "%s(%u): stray number",
|
errx(1, "%s(%u): stray number \"%u\"",
|
||||||
linkerScriptName, lineNo);
|
linkerScriptName, lineNo,
|
||||||
|
token->attr.number);
|
||||||
|
|
||||||
case TOKEN_NEWLINE:
|
case TOKEN_NEWLINE:
|
||||||
lineNo++;
|
lineNo++;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case TOKEN_SECTION:
|
/* A stray string is a section name */
|
||||||
|
case TOKEN_STRING:
|
||||||
parserState = PARSER_LINEEND;
|
parserState = PARSER_LINEEND;
|
||||||
|
|
||||||
if (type == SECTTYPE_INVALID)
|
if (type == SECTTYPE_INVALID)
|
||||||
@@ -398,18 +472,36 @@ struct SectionPlacement *script_NextSection(void)
|
|||||||
if (token->type != TOKEN_NUMBER)
|
if (token->type != TOKEN_NUMBER)
|
||||||
goto lineend;
|
goto lineend;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
case TOKEN_INCLUDE:
|
||||||
|
parserState = PARSER_INCLUDE;
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
case PARSER_INCLUDE:
|
||||||
|
if (token->type != TOKEN_STRING)
|
||||||
|
errx(1, "%s(%u): Expected a file name after INCLUDE",
|
||||||
|
linkerScriptName, lineNo);
|
||||||
|
|
||||||
|
/* Switch to that file */
|
||||||
|
pushFile(token->attr.string);
|
||||||
|
|
||||||
|
parserState = PARSER_LINESTART;
|
||||||
|
break;
|
||||||
|
|
||||||
case PARSER_LINEEND:
|
case PARSER_LINEEND:
|
||||||
lineend:
|
lineend:
|
||||||
if (token->type == TOKEN_EOF)
|
|
||||||
return NULL;
|
|
||||||
else if (token->type != TOKEN_NEWLINE)
|
|
||||||
errx(1, "Linkerscript line %u: Unexpected token at the end",
|
|
||||||
lineNo);
|
|
||||||
lineNo++;
|
lineNo++;
|
||||||
parserState = PARSER_LINESTART;
|
parserState = PARSER_LINESTART;
|
||||||
|
if (token->type == TOKEN_EOF) {
|
||||||
|
if (!popFile())
|
||||||
|
return NULL;
|
||||||
|
parserState = PARSER_LINEEND;
|
||||||
|
} else if (token->type != TOKEN_NEWLINE)
|
||||||
|
errx(1, "%s(%u): Unexpected %s at the end of the line",
|
||||||
|
linkerScriptName, lineNo,
|
||||||
|
tokenTypes[token->type]);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user