Implement compact file stacks in object files

Gets rid of `open_memstream`, enabling Windows compatibility again
Also fixes #491 as a nice bonus!
This commit is contained in:
ISSOtm
2020-09-29 03:40:15 +02:00
parent 930080f556
commit 5a65188ca9
23 changed files with 796 additions and 365 deletions

View File

@@ -29,27 +29,83 @@
struct Context {
struct Context *parent;
struct Context *child;
struct FileStackNode *fileInfo;
struct LexerState *lexerState;
uint32_t uniqueID;
char const *fileName;
char *fileNameBuf;
uint32_t lineNo; /* Line number at which the context was EXITED */
struct Symbol const *macro;
struct MacroArgs *macroArgs; /* Macro args are *saved* here */
uint32_t nbReptIters; /* If zero, this isn't a REPT block */
size_t reptDepth;
uint32_t reptIters[];
uint32_t nbReptIters;
};
static struct Context *contextStack;
static struct Context *topLevelContext;
static size_t contextDepth = 0;
#define DEFAULT_MAX_DEPTH 64
size_t nMaxRecursionDepth;
static unsigned int nbIncPaths = 0;
static char const *includePaths[MAXINCPATHS];
char const *dumpNodeAndParents(struct FileStackNode const *node)
{
char const *name;
if (node->type == NODE_REPT) {
assert(node->parent); /* REPT nodes should always have a parent */
struct FileStackReptNode const *reptInfo = (struct FileStackReptNode const *)node;
name = dumpNodeAndParents(node->parent);
fprintf(stderr, "(%" PRIu32 ") -> %s", node->lineNo, name);
for (uint32_t i = reptInfo->reptDepth; i--; )
fprintf(stderr, "::REPT~%" PRIu32, reptInfo->iters[i]);
} else {
name = ((struct FileStackNamedNode const *)node)->name;
if (node->parent) {
dumpNodeAndParents(node->parent);
fprintf(stderr, "(%" PRIu32 ") -> %s", node->lineNo, name);
} else {
fputs(name, stderr);
}
}
return name;
}
void fstk_Dump(struct FileStackNode const *node, uint32_t lineNo)
{
dumpNodeAndParents(node);
fprintf(stderr, "(%" PRIu32 ")", lineNo);
}
void fstk_DumpCurrent(void)
{
if (!contextStack) {
fputs("at top level", stderr);
return;
}
fstk_Dump(contextStack->fileInfo, lexer_GetLineNo());
}
struct FileStackNode *fstk_GetFileStack(void)
{
struct FileStackNode *node = contextStack->fileInfo;
/* Mark node and all of its parents as referenced if not already so they don't get freed */
while (node && !node->referenced) {
node->ID = -1;
node->referenced = true;
node = node->parent;
}
return contextStack->fileInfo;
}
char const *fstk_GetFileName(void)
{
/* Iterating via the nodes themselves skips nested REPTs */
struct FileStackNode const *node = contextStack->fileInfo;
while (node->type != NODE_FILE)
node = node->parent;
return ((struct FileStackNamedNode const *)node)->name;
}
void fstk_AddIncludePath(char const *path)
{
if (path[0] == '\0')
@@ -141,12 +197,28 @@ bool fstk_FindFile(char const *path, char **fullPath, size_t *size)
bool yywrap(void)
{
if (contextStack->nbReptIters) { /* The context is a REPT block, which may loop */
contextStack->reptIters[contextStack->reptDepth - 1]++;
if (contextStack->fileInfo->type == NODE_REPT) { /* The context is a REPT block, which may loop */
struct FileStackReptNode *fileInfo = (struct FileStackReptNode *)contextStack->fileInfo;
/* If the node is referenced, we can't edit it; duplicate it */
if (contextStack->fileInfo->referenced) {
struct FileStackReptNode *copy = malloc(sizeof(*copy) + sizeof(copy->iters[0]) * fileInfo->reptDepth);
if (!copy)
fatalerror("Failed to duplicate REPT file node: %s\n", strerror(errno));
/* Copy all info but the referencing */
*copy = *fileInfo;
copy->node.next = NULL;
copy->node.referenced = false;
fileInfo = copy;
contextStack->fileInfo = (struct FileStackNode *)fileInfo;
}
fileInfo->iters[0]++;
/* If this wasn't the last iteration, wrap instead of popping */
if (contextStack->reptIters[contextStack->reptDepth - 1]
<= contextStack->nbReptIters) {
lexer_RestartRept(contextStack->parent->lineNo);
if (fileInfo->iters[0] <= contextStack->nbReptIters) {
lexer_RestartRept(contextStack->fileInfo->lineNo);
contextStack->uniqueID = macro_UseNewUniqueID();
return false;
}
@@ -155,44 +227,52 @@ bool yywrap(void)
}
dbgPrint("Popping context\n");
/* Free an `INCLUDE`'s path */
if (contextStack->fileNameBuf)
free(contextStack->fileNameBuf);
struct Context *context = contextStack;
contextStack = contextStack->parent;
contextDepth--;
lexer_DeleteState(contextStack->child->lexerState);
lexer_DeleteState(context->lexerState);
/* Restore args if a macro (not REPT) saved them */
if (contextStack->child->nbReptIters == 0 && contextStack->child->macro) {
if (context->fileInfo->type == NODE_MACRO) {
dbgPrint("Restoring macro args %p\n", contextStack->macroArgs);
macro_UseNewArgs(contextStack->macroArgs);
}
/* Free the file stack node */
if (!context->fileInfo->referenced)
free(context->fileInfo);
/* Free the entry and make its parent the current entry */
free(contextStack->child);
free(context);
contextStack->child = NULL;
lexer_SetState(contextStack->lexerState);
macro_SetUniqueID(contextStack->uniqueID);
return false;
}
static void newContext(uint32_t reptDepth)
/*
* Make sure not to switch the lexer state before calling this, so the saved line no is correct
* BE CAREFUL!! This modifies the file stack directly, you should have set up the file info first
*/
static void newContext(struct FileStackNode *fileInfo)
{
if (++contextDepth >= nMaxRecursionDepth)
fatalerror("Recursion limit (%zu) exceeded\n", nMaxRecursionDepth);
contextStack->child = malloc(sizeof(*contextStack->child)
+ reptDepth * sizeof(contextStack->reptIters[0]));
if (!contextStack->child)
struct Context *context = malloc(sizeof(*context));
if (!context)
fatalerror("Failed to allocate memory for new context: %s\n", strerror(errno));
fileInfo->parent = contextStack->fileInfo;
fileInfo->lineNo = 0; /* Init to a default value, see struct definition for info */
fileInfo->referenced = false;
fileInfo->lineNo = lexer_GetLineNo();
context->fileInfo = fileInfo;
/*
* Link new entry to its parent so it's reachable later
* ERRORS SHOULD NOT OCCUR AFTER THIS!!
*/
context->parent = contextStack;
contextStack = context;
contextStack->lineNo = lexer_GetLineNo();
/* Link new entry to its parent so it's reachable later */
contextStack->child->parent = contextStack;
contextStack = contextStack->child;
contextStack->child = NULL;
contextStack->reptDepth = reptDepth;
}
void fstk_RunInclude(char const *path)
@@ -212,21 +292,27 @@ void fstk_RunInclude(char const *path)
}
dbgPrint("Full path: \"%s\"\n", fullPath);
newContext(0);
contextStack->lexerState = lexer_OpenFile(fullPath);
struct FileStackNamedNode *fileInfo = malloc(sizeof(*fileInfo) + size);
if (!fileInfo) {
error("Failed to alloc file info for INCLUDE: %s\n", strerror(errno));
return;
}
fileInfo->node.type = NODE_FILE;
strcpy(fileInfo->name, fullPath);
free(fullPath);
newContext((struct FileStackNode *)fileInfo);
contextStack->lexerState = lexer_OpenFile(fileInfo->name);
if (!contextStack->lexerState)
fatalerror("Failed to set up lexer for file include\n");
lexer_SetStateAtEOL(contextStack->lexerState);
/* We're back at top-level, so most things are reset */
contextStack->uniqueID = 0;
macro_SetUniqueID(0);
contextStack->fileName = fullPath;
contextStack->fileNameBuf = fullPath;
contextStack->macro = NULL;
contextStack->nbReptIters = 0;
}
void fstk_RunMacro(char *macroName, struct MacroArgs *args)
void fstk_RunMacro(char const *macroName, struct MacroArgs *args)
{
dbgPrint("Running macro \"%s\"\n", macroName);
@@ -242,7 +328,53 @@ void fstk_RunMacro(char *macroName, struct MacroArgs *args)
}
contextStack->macroArgs = macro_GetCurrentArgs();
newContext(0);
/* Compute total length of this node's name: <base name>::<macro> */
size_t reptNameLen = 0;
struct FileStackNode const *node = macro->src;
if (node->type == NODE_REPT) {
struct FileStackReptNode const *reptNode = (struct FileStackReptNode const *)node;
/* 4294967295 = 2^32 - 1, aka UINT32_MAX */
reptNameLen += reptNode->reptDepth * strlen("::REPT~4294967295");
/* Look for next named node */
do {
node = node->parent;
} while (node->type == NODE_REPT);
}
struct FileStackNamedNode const *baseNode = (struct FileStackNamedNode const *)node;
size_t baseLen = strlen(baseNode->name);
size_t macroNameLen = strlen(macro->name);
struct FileStackNamedNode *fileInfo = malloc(sizeof(*fileInfo) + baseLen
+ reptNameLen + 2 + macroNameLen + 1);
if (!fileInfo) {
error("Failed to alloc file info for \"%s\": %s\n", macro->name, strerror(errno));
return;
}
fileInfo->node.type = NODE_MACRO;
/* Print the name... */
char *dest = fileInfo->name;
memcpy(dest, baseNode->name, baseLen);
dest += baseLen;
if (node->type == NODE_REPT) {
struct FileStackReptNode const *reptNode = (struct FileStackReptNode const *)node;
for (uint32_t i = reptNode->reptDepth; i--; ) {
int nbChars = sprintf(dest, "::REPT~%" PRIu32, reptNode->iters[i]);
if (nbChars < 0)
fatalerror("Failed to write macro invocation info: %s\n",
strerror(errno));
dest += nbChars;
}
}
*dest++ = ':';
*dest++ = ':';
memcpy(dest, macro->name, macroNameLen + 1);
newContext((struct FileStackNode *)fileInfo);
/* Line minus 1 because buffer begins with a newline */
contextStack->lexerState = lexer_OpenFileView(macro->macro, macro->macroSize,
macro->fileLine - 1);
@@ -250,143 +382,93 @@ void fstk_RunMacro(char *macroName, struct MacroArgs *args)
fatalerror("Failed to set up lexer for macro invocation\n");
lexer_SetStateAtEOL(contextStack->lexerState);
contextStack->uniqueID = macro_UseNewUniqueID();
contextStack->fileName = macro->fileName;
contextStack->fileNameBuf = NULL;
contextStack->macro = macro;
contextStack->nbReptIters = 0;
macro_UseNewArgs(args);
}
void fstk_RunRept(uint32_t count, int32_t nReptLineNo, char *body, size_t size)
void fstk_RunRept(uint32_t count, int32_t reptLineNo, char *body, size_t size)
{
dbgPrint("Running REPT(%" PRIu32 ")\n", count);
if (count == 0)
return;
uint32_t reptDepth = contextStack->reptDepth;
newContext(reptDepth + 1);
contextStack->lexerState = lexer_OpenFileView(body, size, nReptLineNo);
uint32_t reptDepth = contextStack->fileInfo->type == NODE_REPT
? ((struct FileStackReptNode *)contextStack->fileInfo)->reptDepth
: 0;
struct FileStackReptNode *fileInfo = malloc(sizeof(*fileInfo)
+ (reptDepth + 1) * sizeof(fileInfo->iters[0]));
if (!fileInfo) {
error("Failed to alloc file info for REPT: %s\n", strerror(errno));
return;
}
fileInfo->node.type = NODE_REPT;
fileInfo->reptDepth = reptDepth + 1;
fileInfo->iters[0] = 1;
if (reptDepth)
/* Copy all parent iter counts */
memcpy(&fileInfo->iters[1],
((struct FileStackReptNode *)contextStack->fileInfo)->iters,
reptDepth * sizeof(fileInfo->iters[0]));
newContext((struct FileStackNode *)fileInfo);
/* Correct our line number, which currently points to the `ENDR` line */
contextStack->fileInfo->lineNo = reptLineNo;
contextStack->lexerState = lexer_OpenFileView(body, size, reptLineNo);
if (!contextStack->lexerState)
fatalerror("Failed to set up lexer for macro invocation\n");
fatalerror("Failed to set up lexer for rept block\n");
lexer_SetStateAtEOL(contextStack->lexerState);
contextStack->uniqueID = macro_UseNewUniqueID();
contextStack->fileName = contextStack->parent->fileName;
contextStack->fileNameBuf = NULL;
contextStack->macro = contextStack->parent->macro; /* Inherit */
contextStack->nbReptIters = count;
/* Copy all of parent's iters, and add ours */
if (reptDepth)
memcpy(contextStack->reptIters, contextStack->parent->reptIters,
sizeof(contextStack->reptIters[0]) * reptDepth);
contextStack->reptIters[reptDepth] = 1;
/* Correct our parent's line number, which currently points to the `ENDR` line */
contextStack->parent->lineNo = nReptLineNo;
}
static void printContext(FILE *stream, struct Context const *context)
void fstk_Init(char const *mainPath, size_t maxRecursionDepth)
{
fprintf(stream, "%s", context->fileName);
if (context->macro)
fprintf(stream, "::%s", context->macro->name);
for (size_t i = 0; i < context->reptDepth; i++)
fprintf(stream, "::REPT~%" PRIu32, context->reptIters[i]);
fprintf(stream, "(%" PRId32 ")", context->lineNo);
}
struct LexerState *state = lexer_OpenFile(mainPath);
static void dumpToStream(FILE *stream)
{
struct Context *context = topLevelContext;
while (context != contextStack) {
printContext(stream, context);
fprintf(stream, " -> ");
context = context->child;
}
contextStack->lineNo = lexer_GetLineNo();
printContext(stream, contextStack);
}
void fstk_Dump(void)
{
dumpToStream(stderr);
}
char *fstk_DumpToStr(void)
{
char *str;
size_t size;
/* `open_memstream` is specified to always include a '\0' at the end of the buffer! */
FILE *stream = open_memstream(&str, &size);
if (!stream)
fatalerror("Failed to dump file stack to string: %s\n", strerror(errno));
dumpToStream(stream);
fclose(stream);
return str;
}
char const *fstk_GetFileName(void)
{
/* FIXME: this is awful, but all callees copy the buffer anyways */
static char fileName[_MAX_PATH + 1];
size_t remainingChars = _MAX_PATH + 1;
char *dest = fileName;
char const *src = contextStack->fileName;
#define append(...) do { \
int nbChars = snprintf(dest, remainingChars, __VA_ARGS__); \
\
if (nbChars >= remainingChars) \
fatalerror("File stack entry too large\n"); \
remainingChars -= nbChars; \
dest += nbChars; \
} while (0)
while (*src && --remainingChars) /* Leave room for terminator */
*dest++ = *src++;
if (remainingChars && contextStack->macro)
append("::%s", contextStack->macro->name);
for (size_t i = 0; i < contextStack->reptDepth; i++)
append("::REPT~%" PRIu32, contextStack->reptIters[i]);
*dest = '\0';
return fileName;
}
uint32_t fstk_GetLine(void)
{
return lexer_GetLineNo();
}
void fstk_Init(char *mainPath, size_t maxRecursionDepth)
{
topLevelContext = malloc(sizeof(*topLevelContext));
if (!topLevelContext)
fatalerror("Failed to allocate memory for initial context: %s\n", strerror(errno));
topLevelContext->parent = NULL;
topLevelContext->child = NULL;
topLevelContext->lexerState = lexer_OpenFile(mainPath);
if (!topLevelContext->lexerState)
if (!state)
fatalerror("Failed to open main file!\n");
lexer_SetState(topLevelContext->lexerState);
topLevelContext->uniqueID = 0;
lexer_SetState(state);
char const *fileName = lexer_GetFileName();
size_t len = strlen(fileName);
struct Context *context = malloc(sizeof(*contextStack));
struct FileStackNamedNode *fileInfo = malloc(sizeof(*fileInfo) + len + 1);
if (!context)
fatalerror("Failed to allocate memory for main context: %s\n", strerror(errno));
if (!fileInfo)
fatalerror("Failed to allocate memory for main file info: %s\n", strerror(errno));
context->fileInfo = (struct FileStackNode *)fileInfo;
/* lineNo and reptIter are unused on the top-level context */
context->fileInfo->parent = NULL;
context->fileInfo->referenced = false;
context->fileInfo->type = NODE_FILE;
memcpy(fileInfo->name, fileName, len + 1);
context->parent = NULL;
context->lexerState = state;
context->uniqueID = 0;
macro_SetUniqueID(0);
topLevelContext->fileName = lexer_GetFileName();
topLevelContext->fileNameBuf = NULL;
topLevelContext->macro = NULL;
topLevelContext->nbReptIters = 0;
topLevelContext->reptDepth = 0;
context->nbReptIters = 0;
contextStack = topLevelContext;
/* Now that it's set up properly, register the context */
contextStack = context;
if (maxRecursionDepth
> (SIZE_MAX - sizeof(*contextStack)) / sizeof(contextStack->reptIters[0])) {
error("Recursion depth may not be higher than %zu, defaulting to 64\n",
(SIZE_MAX - sizeof(*contextStack)) / sizeof(contextStack->reptIters[0]));
nMaxRecursionDepth = 64;
/*
* Check that max recursion depth won't allow overflowing node `malloc`s
* This assumes that the rept node is larger
*/
#define DEPTH_LIMIT ((SIZE_MAX - sizeof(struct FileStackReptNode)) / sizeof(uint32_t))
if (maxRecursionDepth > DEPTH_LIMIT) {
error("Recursion depth may not be higher than %zu, defaulting to "
EXPAND_AND_STR(DEFAULT_MAX_DEPTH) "\n", DEPTH_LIMIT);
nMaxRecursionDepth = DEFAULT_MAX_DEPTH;
} else {
nMaxRecursionDepth = maxRecursionDepth;
}
/* Make sure that the default of 64 is OK, though */
assert(DEPTH_LIMIT >= DEFAULT_MAX_DEPTH);
#undef DEPTH_LIMIT
}

View File

@@ -12,6 +12,7 @@
#include <assert.h>
#include <errno.h>
#include <inttypes.h>
#include <stdio.h>
#include <stdint.h>
#include <stdlib.h>
@@ -33,7 +34,8 @@
#include "platform.h" // strdup
struct Patch {
char *tzFilename;
struct FileStackNode const *src;
uint32_t lineNo;
uint32_t nOffset;
struct Section *pcSection;
uint32_t pcOffset;
@@ -62,19 +64,17 @@ static uint32_t nbSymbols = 0; /* Length of the above list */
static struct Assertion *assertions = NULL;
static struct FileStackNode *fileStackNodes = NULL;
/*
* Count the number of sections used in this object
*/
static uint32_t countsections(void)
{
struct Section *sect;
uint32_t count = 0;
sect = pSectionList;
while (sect) {
for (struct Section const *sect = pSectionList; sect; sect = sect->next)
count++;
sect = sect->next;
}
return count;
}
@@ -129,16 +129,60 @@ static void fputstring(char const *s, FILE *f)
fputc(0, f);
}
static uint32_t getNbFileStackNodes(void)
{
return fileStackNodes ? fileStackNodes->ID + 1 : 0;
}
void out_RegisterNode(struct FileStackNode *node)
{
/* If node is not already registered, register it (and parents), and give it a unique ID */
while (node->ID == -1) {
node->ID = getNbFileStackNodes();
if (node->ID == -1)
fatalerror("Reached too many file stack nodes; try splitting the file up\n");
node->next = fileStackNodes;
fileStackNodes = node;
/* Also register the node's parents */
node = node->parent;
if (!node)
break;
}
}
void out_ReplaceNode(struct FileStackNode *node)
{
(void)node;
#if 0
This is code intended to replace a node, which is pretty useless until ref counting is added...
struct FileStackNode **ptr = &fileStackNodes;
/*
* The linked list is supposed to have decrementing IDs, so iterate with less memory reads,
* to hopefully hit the cache less. A debug check is added after, in case a change is made
* that breaks this assumption.
*/
for (uint32_t i = fileStackNodes->ID; i != node->ID; i--)
ptr = &(*ptr)->next;
assert((*ptr)->ID == node->ID);
node->next = (*ptr)->next;
assert(!node->next || node->next->ID == node->ID - 1); /* Catch inconsistencies early */
/* TODO: unreference the node */
*ptr = node;
#endif
}
/*
* Return a section's ID
*/
static uint32_t getsectid(struct Section const *sect)
{
struct Section const *sec;
struct Section const *sec = pSectionList;
uint32_t ID = 0;
sec = pSectionList;
while (sec) {
if (sec == sect)
return ID;
@@ -159,7 +203,10 @@ static uint32_t getSectIDIfAny(struct Section const *sect)
*/
static void writepatch(struct Patch const *patch, FILE *f)
{
fputstring(patch->tzFilename, f);
assert(patch->src->ID != -1);
fputlong(patch->src->ID, f);
fputlong(patch->lineNo, f);
fputlong(patch->nOffset, f);
fputlong(getSectIDIfAny(patch->pcSection), f);
fputlong(patch->pcOffset, f);
@@ -206,26 +253,35 @@ static void writesymbol(struct Symbol const *sym, FILE *f)
if (!sym_IsDefined(sym)) {
fputc(SYMTYPE_IMPORT, f);
} else {
assert(sym->src->ID != -1);
fputc(sym->isExported ? SYMTYPE_EXPORT : SYMTYPE_LOCAL, f);
fputstring(sym->fileName, f);
fputlong(sym->src->ID, f);
fputlong(sym->fileLine, f);
fputlong(getSectIDIfAny(sym_GetSection(sym)), f);
fputlong(sym->value, f);
}
}
static void registerSymbol(struct Symbol *sym)
{
*objectSymbolsTail = sym;
objectSymbolsTail = &sym->next;
out_RegisterNode(sym->src);
if (nbSymbols == -1)
fatalerror("Registered too many symbols (%" PRIu32
"); try splitting up your files\n", (uint32_t)-1);
sym->ID = nbSymbols++;
}
/*
* Returns a symbol's ID within the object file
* If the symbol does not have one, one is assigned by registering the symbol
*/
static uint32_t getSymbolID(struct Symbol *sym)
{
if (sym->ID == -1) {
sym->ID = nbSymbols++;
*objectSymbolsTail = sym;
objectSymbolsTail = &sym->next;
}
if (sym->ID == -1 && !sym_IsPC(sym))
registerSymbol(sym);
return sym->ID;
}
@@ -303,22 +359,25 @@ static void writerpn(uint8_t *rpnexpr, uint32_t *rpnptr, uint8_t *rpn,
/*
* Allocate a new patch structure and link it into the list
* WARNING: all patches are assumed to eventually be written, so the file stack node is registered
*/
static struct Patch *allocpatch(uint32_t type, struct Expression const *expr,
uint32_t ofs)
static struct Patch *allocpatch(uint32_t type, struct Expression const *expr, uint32_t ofs)
{
struct Patch *patch = malloc(sizeof(struct Patch));
uint32_t rpnSize = expr->isKnown ? 5 : expr->nRPNPatchSize;
struct FileStackNode *node = fstk_GetFileStack();
if (!patch)
fatalerror("No memory for patch: %s\n", strerror(errno));
patch->pRPN = malloc(sizeof(*patch->pRPN) * rpnSize);
patch->pRPN = malloc(sizeof(*patch->pRPN) * rpnSize);
if (!patch->pRPN)
fatalerror("No memory for patch's RPN expression: %s\n", strerror(errno));
patch->type = type;
patch->tzFilename = fstk_DumpToStr();
patch->src = node;
out_RegisterNode(node);
patch->lineNo = lexer_GetLineNo();
patch->nOffset = ofs;
patch->pcSection = sect_GetSymbolSection();
patch->pcOffset = sect_GetSymbolOffset();
@@ -382,13 +441,28 @@ static void writeassert(struct Assertion *assert, FILE *f)
fputstring(assert->message, f);
}
static void writeFileStackNode(struct FileStackNode const *node, FILE *f)
{
fputlong(node->parent ? node->parent->ID : -1, f);
fputlong(node->lineNo, f);
fputc(node->type, f);
if (node->type != NODE_REPT) {
fputstring(((struct FileStackNamedNode const *)node)->name, f);
} else {
struct FileStackReptNode const *reptNode = (struct FileStackReptNode const *)node;
fputlong(reptNode->reptDepth, f);
/* Iters are stored by decreasing depth, so reverse the order for output */
for (uint32_t i = reptNode->reptDepth; i--; )
fputlong(reptNode->iters[i], f);
}
}
static void registerExportedSymbol(struct Symbol *symbol, void *arg)
{
(void)arg;
if (sym_IsExported(symbol) && symbol->ID == -1) {
*objectSymbolsTail = symbol;
objectSymbolsTail = &symbol->next;
nbSymbols++;
registerSymbol(symbol);
}
}
@@ -411,6 +485,15 @@ void out_WriteObject(void)
fputlong(nbSymbols, f);
fputlong(countsections(), f);
fputlong(getNbFileStackNodes(), f);
for (struct FileStackNode const *node = fileStackNodes; node; node = node->next) {
writeFileStackNode(node, f);
if (node->next && node->next->ID != node->ID - 1)
fatalerror("Internal error: fstack node #%" PRIu32 " follows #%" PRIu32
". Please report this to the developers!\n",
node->next->ID, node->ID);
}
for (struct Symbol const *sym = objectSymbols; sym; sym = sym->next)
writesymbol(sym, f);

View File

@@ -258,8 +258,8 @@ static int32_t shift(int32_t shiftee, int32_t amount)
if (amount >= 0) {
// Left shift
if (amount >= 32) {
warning(WARNING_SHIFT_AMOUNT, "Shifting left by large amount %" PRId32 "\n",
amount);
warning(WARNING_SHIFT_AMOUNT, "Shifting left by large amount %"
PRId32 "\n", amount);
return 0;
} else {

View File

@@ -23,6 +23,7 @@
#include "asm/macro.h"
#include "asm/main.h"
#include "asm/mymath.h"
#include "asm/output.h"
#include "asm/section.h"
#include "asm/symbol.h"
#include "asm/util.h"
@@ -121,7 +122,7 @@ static char const *Callback__FILE__(void)
buf[j - 1] = '\\';
buf[j] = fileName[i];
}
/* Write everything after the loop, to ensure everything has been allocated */
/* Write everything after the loop, to ensure the buffer has been allocated */
buf[0] = '"';
buf[j++] = '"';
buf[j] = '\0';
@@ -150,15 +151,35 @@ int32_t sym_GetValue(struct Symbol const *sym)
return sym->value;
}
static void dumpFilename(struct Symbol const *sym)
{
if (!sym->src)
fputs("<builtin>", stderr);
else
fstk_Dump(sym->src, sym->fileLine);
}
/*
* Set a symbol's definition filename and line
*/
static void setSymbolFilename(struct Symbol *sym)
{
sym->src = fstk_GetFileStack();
sym->fileLine = lexer_GetLineNo();
}
/*
* Update a symbol's definition filename and line
*/
static void updateSymbolFilename(struct Symbol *sym)
{
if (snprintf(sym->fileName, _MAX_PATH + 1, "%s",
fstk_GetFileName()) > _MAX_PATH)
fatalerror("%s: File name is too long: '%s'\n", __func__, fstk_GetFileName());
sym->fileLine = fstk_GetLine();
struct FileStackNode *oldSrc = sym->src;
setSymbolFilename(sym);
/* If the old node was referenced, ensure the new one is */
if (oldSrc->referenced && oldSrc->ID != -1)
out_RegisterNode(sym->src);
/* TODO: unref the old node, and use `out_ReplaceNode` instead if deleting it */
}
/*
@@ -178,7 +199,7 @@ static struct Symbol *createsymbol(char const *s)
symbol->isBuiltin = false;
symbol->hasCallback = false;
symbol->section = NULL;
updateSymbolFilename(symbol);
setSymbolFilename(symbol);
symbol->ID = -1;
symbol->next = NULL;
@@ -253,6 +274,7 @@ void sym_Purge(char const *symName)
labelScope = NULL;
hash_RemoveElement(symbols, symbol->name);
/* TODO: ideally, also unref the file stack nodes */
free(symbol);
}
}
@@ -338,9 +360,11 @@ static struct Symbol *createNonrelocSymbol(char const *symbolName)
if (!symbol)
symbol = createsymbol(symbolName);
else if (sym_IsDefined(symbol))
error("'%s' already defined at %s(%" PRIu32 ")\n", symbolName,
symbol->fileName, symbol->fileLine);
else if (sym_IsDefined(symbol)) {
error("'%s' already defined at ", symbolName);
dumpFilename(symbol);
putc('\n', stderr);
}
return symbol;
}
@@ -395,15 +419,17 @@ struct Symbol *sym_AddSet(char const *symName, int32_t value)
{
struct Symbol *sym = findsymbol(symName, NULL);
if (sym == NULL)
if (sym == NULL) {
sym = createsymbol(symName);
else if (sym_IsDefined(sym) && sym->type != SYM_SET)
error("'%s' already defined as %s at %s(%" PRIu32 ")\n",
symName, sym->type == SYM_LABEL ? "label" : "constant",
sym->fileName, sym->fileLine);
else
/* TODO: can the scope be incorrect when talking over refs? */
} else if (sym_IsDefined(sym) && sym->type != SYM_SET) {
error("'%s' already defined as %s at ",
symName, sym->type == SYM_LABEL ? "label" : "constant");
dumpFilename(sym);
putc('\n', stderr);
} else {
/* TODO: can the scope be incorrect when taking over refs? */
updateSymbolFilename(sym);
}
sym->type = SYM_SET;
sym->value = value;
@@ -424,9 +450,12 @@ static struct Symbol *addLabel(char const *name)
if (!sym) {
sym = createsymbol(name);
} else if (sym_IsDefined(sym)) {
error("'%s' already defined in %s(%" PRIu32 ")\n",
name, sym->fileName, sym->fileLine);
error("'%s' already defined at ", name);
dumpFilename(sym);
putc('\n', stderr);
return NULL;
} else {
updateSymbolFilename(sym);
}
/* If the symbol already exists as a ref, just "take over" it */
sym->type = SYM_LABEL;
@@ -434,7 +463,6 @@ static struct Symbol *addLabel(char const *name)
if (exportall)
sym->isExported = true;
sym->section = sect_GetSymbolSection();
updateSymbolFilename(sym);
if (sym && !sym->section)
error("Label \"%s\" created outside of a SECTION\n", name);
@@ -517,7 +545,7 @@ struct Symbol *sym_AddMacro(char const *symName, int32_t defLineNo, char *body,
sym->type = SYM_MACRO;
sym->macroSize = size;
sym->macro = body;
updateSymbolFilename(sym);
setSymbolFilename(sym); /* TODO: is this really necessary? */
/*
* The symbol is created at the line after the `endm`,
* override this with the actual definition line
@@ -577,10 +605,11 @@ static inline struct Symbol *createBuiltinSymbol(char const *name)
sym->isBuiltin = true;
sym->hasCallback = true;
strcpy(sym->fileName, "<builtin>");
sym->src = NULL;
sym->fileLine = 0;
return sym;
}
/*
* Initialize the symboltable
*/

View File

@@ -202,7 +202,7 @@ void printDiag(const char *fmt, va_list args, char const *type,
char const *flagfmt, char const *flag)
{
fputs(type, stderr);
fstk_Dump();
fstk_DumpCurrent();
fprintf(stderr, flagfmt, flag);
vfprintf(stderr, fmt, args);
lexer_DumpStringExpansions();