ref: e11f25024e619c9c1fdd6d3a2cf577f937fa13f9
parent: 7c895f8a1b02e433f9790d43f1376ae163b3dbe8
author: ISSOtm <eldredhabert0@gmail.com>
date: Fri Jul 31 14:24:44 EDT 2020
Add test for built-in file symbol It's currently defined in fstack.c, making it more prone to accidental dropping. Let's not repeat the 0.3.9 scenario...
--- a/Makefile
+++ b/Makefile
@@ -72,7 +72,7 @@
src/hashmap.o \
src/linkdefs.o
-src/asm/lexer.o: src/asm/asmy.h
+src/asm/lexer.o src/asm/main.o: src/asm/asmy.h
rgblink_obj := \
src/link/assign.o \
--- a/include/asm/fstack.h
+++ b/include/asm/fstack.h
@@ -41,13 +41,7 @@
extern unsigned int nMaxRecursionDepth;
-void fstk_RunInclude(char *tzFileName);
-void fstk_Init(char *s);
-void fstk_Dump(void);
-void fstk_DumpToStr(char *buf, size_t len);
-void fstk_AddIncludePath(char *s);
-void fstk_RunMacro(char *s, struct MacroArgs *args);
-void fstk_RunRept(uint32_t count, int32_t nReptLineNo, char const *body, size_t size);
+void fstk_AddIncludePath(char const *s);
/**
* @param path The user-provided file name
* @param fullPath The address of a pointer, which will be made to point at the full path
@@ -56,6 +50,16 @@
* @return True if the file was found, false if no path worked
*/
bool fstk_FindFile(char const *path, char **fullPath, size_t *size);
-int32_t fstk_GetLine(void);
+
+bool yywrap(void);
+void fstk_RunInclude(char const *path);
+void fstk_RunMacro(char *macroName, struct MacroArgs *args);
+void fstk_RunRept(uint32_t count, int32_t nReptLineNo, char *body, size_t size);
+
+void fstk_Dump(void);
+char *fstk_DumpToStr(void);
+uint32_t fstk_GetLine(void);
+
+void fstk_Init(char *mainPath, uint32_t maxRecursionDepth);
#endif /* RGBDS_ASM_FSTACK_H */
--- a/include/asm/lexer.h
+++ b/include/asm/lexer.h
@@ -31,7 +31,8 @@
}
struct LexerState *lexer_OpenFile(char const *path);
-struct LexerState *lexer_OpenFileView(void);
+struct LexerState *lexer_OpenFileView(char *buf, size_t size, uint32_t lineNo);
+void lexer_RestartRept(uint32_t lineNo);
void lexer_DeleteState(struct LexerState *state);
void lexer_Init(void);
@@ -50,7 +51,7 @@
uint32_t lexer_GetColNo(void);
void lexer_DumpStringExpansions(void);
int yylex(void);
-void lexer_CaptureBlock(int blockStartToken, int blockEndToken, char const **capture, size_t *size,
+void lexer_CaptureBlock(int blockStartToken, int blockEndToken, char **capture, size_t *size,
char const *name);
#endif /* RGBDS_ASM_LEXER_H */
--- a/include/asm/macro.h
+++ b/include/asm/macro.h
@@ -28,6 +28,7 @@
uint32_t macro_GetUniqueID(void);
char const *macro_GetUniqueIDStr(void);
void macro_SetUniqueID(uint32_t id);
+uint32_t macro_UseNewUniqueID(void);
void macro_ShiftCurrentArgs(void);
uint32_t macro_NbArgs(void);
--- a/include/asm/symbol.h
+++ b/include/asm/symbol.h
@@ -45,7 +45,7 @@
};
struct { /* For SYM_MACRO */
size_t macroSize;
- char const *macro;
+ char *macro;
};
};
@@ -117,7 +117,7 @@
uint32_t sym_GetConstantSymValue(struct Symbol const *sym);
uint32_t sym_GetConstantValue(char const *s);
struct Symbol *sym_FindSymbol(char const *symName);
-struct Symbol *sym_AddMacro(char const *symName, int32_t defLineNo, char const *body, size_t size);
+struct Symbol *sym_AddMacro(char const *symName, int32_t defLineNo, char *body, size_t size);
struct Symbol *sym_Ref(char const *symName);
struct Symbol *sym_AddString(char const *symName, char const *value);
uint32_t sym_GetDefinedValue(char const *s);
--- a/src/asm/asmy.y
+++ b/src/asm/asmy.y
@@ -597,21 +597,21 @@
rept : T_POP_REPT uconst {
uint32_t nDefinitionLineNo = lexer_GetLineNo();
- char const *body;
+ char *body;
size_t size;
lexer_CaptureBlock(T_POP_REPT, T_POP_ENDR, &body, &size,
"REPT block");
- fstk_RunRept($2, nDefinitionLineNo, body, size);
+ fstk_RunRept($2, nDefinitionLineNo, body, size - strlen("ENDR"));
}
;
macrodef : T_LABEL ':' T_POP_MACRO {
int32_t nDefinitionLineNo = lexer_GetLineNo();
- char const *body;
+ char *body;
size_t size;
lexer_CaptureBlock(T_POP_MACRO, T_POP_ENDM, &body, &size,
"macro definition");
- sym_AddMacro($1, nDefinitionLineNo, body, size);
+ sym_AddMacro($1, nDefinitionLineNo, body, size - strlen("ENDM"));
}
;
--- a/src/asm/fstack.c
+++ b/src/asm/fstack.c
@@ -6,318 +6,82 @@
* SPDX-License-Identifier: MIT
*/
-/*
- * FileStack routines
- */
-
+#include <sys/stat.h>
+#include <assert.h>
#include <errno.h>
#include <inttypes.h>
-#include <limits.h>
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
-#include <string.h>
-#include <sys/stat.h>
-#include <sys/types.h>
#include "asm/fstack.h"
-#include "asm/lexer.h"
#include "asm/macro.h"
#include "asm/main.h"
-#include "asm/output.h"
+#include "asm/symbol.h"
#include "asm/warning.h"
+#include "platform.h" /* S_ISDIR (stat macro) */
-#include "extern/err.h"
+struct Context {
+ struct Context *parent;
+ struct Context *child;
+ struct LexerState *lexerState;
+ uint32_t uniqueID;
+ char *fileName;
+ uint32_t lineNo; /* Line number at which the context was EXITED */
+ struct Symbol const *macro;
+ uint32_t nbReptIters; /* If zero, this isn't a REPT block */
+ size_t reptDepth;
+ uint32_t reptIters[];
+};
-#include "platform.h" // S_ISDIR (stat macro)
-#include "types.h"
-
-static struct sContext *pFileStack;
-static unsigned int nFileStackDepth;
+static struct Context *contextStack;
+static struct Context *topLevelContext;
+static unsigned int contextDepth = 0;
unsigned int nMaxRecursionDepth;
-static struct Symbol const *pCurrentMacro;
-static uint32_t nCurrentStatus;
-static char IncludePaths[MAXINCPATHS][_MAX_PATH + 1];
-static int32_t NextIncPath;
-static uint32_t nMacroCount;
-static char const *pCurrentREPTBlock;
-static uint32_t nCurrentREPTBlockSize;
-static uint32_t nCurrentREPTBlockCount;
-static int32_t nCurrentREPTBodyFirstLine;
-static int32_t nCurrentREPTBodyLastLine;
+static unsigned int nbIncPaths = 0;
+static char const *includePaths[MAXINCPATHS];
-uint32_t ulMacroReturnValue;
-
-/*
- * defines for nCurrentStatus
- */
-#define STAT_isInclude 0 /* 'Normal' state as well */
-#define STAT_isMacro 1
-#define STAT_isMacroArg 2
-#define STAT_isREPTBlock 3
-
-/* Max context stack size */
-
-/*
- * Context push and pop
- */
-static void pushcontext(void)
+void fstk_AddIncludePath(char const *path)
{
- struct sContext **ppFileStack;
-
- if (++nFileStackDepth > nMaxRecursionDepth)
- fatalerror("Recursion limit (%u) exceeded\n", nMaxRecursionDepth);
-
- ppFileStack = &pFileStack;
- while (*ppFileStack)
- ppFileStack = &((*ppFileStack)->next);
-
- *ppFileStack = malloc(sizeof(struct sContext));
-
- if (*ppFileStack == NULL)
- fatalerror("No memory for context\n");
-
- (*ppFileStack)->next = NULL;
- (*ppFileStack)->nLine = lexer_GetLineNo();
-
- switch ((*ppFileStack)->nStatus = nCurrentStatus) {
- case STAT_isMacroArg:
- case STAT_isMacro:
- (*ppFileStack)->macroArgs = macro_GetCurrentArgs();
- (*ppFileStack)->pMacro = pCurrentMacro;
- break;
- case STAT_isInclude:
- break;
- case STAT_isREPTBlock:
- (*ppFileStack)->macroArgs = macro_GetCurrentArgs();
- (*ppFileStack)->pREPTBlock = pCurrentREPTBlock;
- (*ppFileStack)->nREPTBlockSize = nCurrentREPTBlockSize;
- (*ppFileStack)->nREPTBlockCount = nCurrentREPTBlockCount;
- (*ppFileStack)->nREPTBodyFirstLine = nCurrentREPTBodyFirstLine;
- (*ppFileStack)->nREPTBodyLastLine = nCurrentREPTBodyLastLine;
- break;
- default:
- fatalerror("%s: Internal error.\n", __func__);
+ if (path[0] == '\0')
+ return;
+ if (nbIncPaths >= MAXINCPATHS) {
+ error("Too many include directories passed from command line\n");
+ return;
}
- (*ppFileStack)->uniqueID = macro_GetUniqueID();
-}
+ size_t len = strlen(path);
+ size_t allocSize = len + (path[len - 1] != '/') + 1;
+ char *str = malloc(allocSize);
-static int32_t popcontext(void)
-{
- struct sContext *pLastFile, **ppLastFile;
-
- if (nCurrentStatus == STAT_isREPTBlock) {
- if (--nCurrentREPTBlockCount) {
- char *pREPTIterationWritePtr;
- unsigned long nREPTIterationNo;
- int nNbCharsWritten;
- int nNbCharsLeft;
-
- macro_SetUniqueID(nMacroCount++);
-
- /* Increment REPT count in file path */
- pREPTIterationWritePtr =
- strrchr(lexer_GetFileName(), '~') + 1;
- nREPTIterationNo =
- strtoul(pREPTIterationWritePtr, NULL, 10);
- nNbCharsLeft = sizeof(lexer_GetFileName())
- - (pREPTIterationWritePtr - lexer_GetFileName());
- nNbCharsWritten = snprintf(pREPTIterationWritePtr,
- nNbCharsLeft, "%lu",
- nREPTIterationNo + 1);
- if (nNbCharsWritten >= nNbCharsLeft) {
- /*
- * The string is probably corrupted somehow,
- * revert the change to avoid a bad error
- * output.
- */
- sprintf(pREPTIterationWritePtr, "%lu",
- nREPTIterationNo);
- fatalerror("Cannot write REPT count to file path\n");
- }
-
- return 0;
- }
+ if (!str) {
+ /* Attempt to continue without that path */
+ error("Failed to allocate new include path: %s\n", strerror(errno));
+ return;
}
+ memcpy(str, path, len);
+ char *end = str + len - 1;
- pLastFile = pFileStack;
- if (pLastFile == NULL)
- return 1;
-
- ppLastFile = &pFileStack;
- while (pLastFile->next) {
- ppLastFile = &(pLastFile->next);
- pLastFile = *ppLastFile;
- }
-
- lexer_DeleteState(lexer_GetState());
- lexer_SetState(pLastFile->lexerState);
-
- switch (pLastFile->nStatus) {
- struct MacroArgs *args;
-
- case STAT_isMacroArg:
- case STAT_isMacro:
- args = macro_GetCurrentArgs();
- if (nCurrentStatus == STAT_isMacro) {
- macro_FreeArgs(args);
- free(args);
- }
- macro_UseNewArgs(pLastFile->macroArgs);
- pCurrentMacro = pLastFile->pMacro;
- break;
- case STAT_isInclude:
- break;
- case STAT_isREPTBlock:
- args = macro_GetCurrentArgs();
- if (nCurrentStatus == STAT_isMacro) {
- macro_FreeArgs(args);
- free(args);
- }
- macro_UseNewArgs(pLastFile->macroArgs);
- pCurrentREPTBlock = pLastFile->pREPTBlock;
- nCurrentREPTBlockSize = pLastFile->nREPTBlockSize;
- nCurrentREPTBlockCount = pLastFile->nREPTBlockCount;
- nCurrentREPTBodyFirstLine = pLastFile->nREPTBodyFirstLine;
- break;
- default:
- fatalerror("%s: Internal error.\n", __func__);
- }
- macro_SetUniqueID(pLastFile->uniqueID);
-
- nCurrentStatus = pLastFile->nStatus;
-
- nFileStackDepth--;
-
- free(*ppLastFile);
- *ppLastFile = NULL;
- return 0;
+ if (*end++ != '/')
+ *end++ = '/';
+ *end = '\0';
+ includePaths[nbIncPaths++] = str;
}
-int32_t fstk_GetLine(void)
+static void printDep(char const *path)
{
- struct sContext *pLastFile, **ppLastFile;
-
- switch (nCurrentStatus) {
- case STAT_isInclude:
- /* This is the normal mode, also used when including a file. */
- return lexer_GetLineNo();
- case STAT_isMacro:
- break; /* Peek top file of the stack */
- case STAT_isMacroArg:
- return lexer_GetLineNo(); /* ??? */
- case STAT_isREPTBlock:
- break; /* Peek top file of the stack */
- default:
- fatalerror("%s: Internal error.\n", __func__);
- }
-
- pLastFile = pFileStack;
-
- if (pLastFile != NULL) {
- while (pLastFile->next) {
- ppLastFile = &(pLastFile->next);
- pLastFile = *ppLastFile;
- }
- return pLastFile->nLine;
- }
-
- /*
- * This is only reached if the lexer is in REPT or MACRO mode but there
- * are no saved contexts with the origin of said REPT or MACRO.
- */
- fatalerror("%s: Internal error.\n", __func__);
-}
-
-int yywrap(void)
-{
- return popcontext();
-}
-
-/*
- * Dump the context stack to stderr
- */
-void fstk_Dump(void)
-{
- const struct sContext *pLastFile;
-
- pLastFile = pFileStack;
-
- while (pLastFile) {
- fprintf(stderr, "%s(%" PRId32 ") -> ", pLastFile->tzFileName,
- pLastFile->nLine);
- pLastFile = pLastFile->next;
- }
- char const *fileName = lexer_GetFileName();
-
- if (fileName)
- fprintf(stderr, "%s(%" PRId32 ",%" PRId32 "): ",
- fileName, lexer_GetLineNo(), lexer_GetColNo());
-}
-
-void fstk_DumpToStr(char *buf, size_t buflen)
-{
- const struct sContext *pLastFile = pFileStack;
- int retcode;
- size_t len = buflen;
-
- while (pLastFile) {
- retcode = snprintf(&buf[buflen - len], len, "%s(%" PRId32 ") -> ",
- pLastFile->tzFileName, pLastFile->nLine);
- if (retcode < 0)
- fatalerror("Failed to dump file stack to string: %s\n", strerror(errno));
- else if (retcode >= len)
- len = 0;
- else
- len -= retcode;
- pLastFile = pLastFile->next;
- }
-
- retcode = snprintf(&buf[buflen - len], len, "%s(%" PRId32 ")",
- lexer_GetFileName(), lexer_GetLineNo());
- if (retcode < 0)
- fatalerror("Failed to dump file stack to string: %s\n", strerror(errno));
- else if (retcode >= len)
- len = 0;
- else
- len -= retcode;
-
- if (!len)
- warning(WARNING_LONG_STR, "File stack dump too long, got truncated\n");
-}
-
-/*
- * Extra includepath stuff
- */
-void fstk_AddIncludePath(char *s)
-{
- if (NextIncPath == MAXINCPATHS)
- fatalerror("Too many include directories passed from command line\n");
-
- // Find last occurrence of slash; is it at the end of the string?
- char const *lastSlash = strrchr(s, '/');
- char const *pattern = lastSlash && *(lastSlash + 1) == 0 ? "%s" : "%s/";
-
- if (snprintf(IncludePaths[NextIncPath++], _MAX_PATH, pattern,
- s) >= _MAX_PATH)
- fatalerror("Include path too long '%s'\n", s);
-}
-
-static void printdep(const char *fileName)
-{
if (dependfile) {
- fprintf(dependfile, "%s: %s\n", tzTargetFileName, fileName);
+ fprintf(dependfile, "%s: %s\n", tzTargetFileName, path);
if (oGeneratePhonyDeps)
- fprintf(dependfile, "%s:\n", fileName);
+ fprintf(dependfile, "%s:\n", path);
}
}
-static bool isPathValid(char const *pathname)
+static bool isPathValid(char const *path)
{
struct stat statbuf;
- if (stat(pathname, &statbuf) != 0)
+ if (stat(path, &statbuf) != 0)
return false;
/* Reject directories */
@@ -335,8 +99,8 @@
}
if (*fullPath) {
- for (size_t i = 0; i <= NextIncPath; ++i) {
- char *incPath = i ? IncludePaths[i - 1] : "";
+ for (size_t i = 0; i <= nbIncPaths; ++i) {
+ char const *incPath = i ? includePaths[i - 1] : "";
int len = snprintf(*fullPath, *size, "%s%s", incPath, path);
/* Oh how I wish `asnprintf` was standard... */
@@ -355,7 +119,7 @@
error("snprintf error during include path search: %s\n",
strerror(errno));
} else if (isPathValid(*fullPath)) {
- printdep(*fullPath);
+ printDep(*fullPath);
return true;
}
}
@@ -363,114 +127,210 @@
errno = ENOENT;
if (oGeneratedMissingIncludes)
- printdep(path);
+ printDep(path);
return false;
}
-/*
- * Set up an include file for parsing
- */
-void fstk_RunInclude(char *tzFileName)
+bool yywrap(void)
{
+ if (contextStack->nbReptIters) { /* The context is a REPT block, which may loop */
+ contextStack->reptIters[contextStack->reptDepth - 1]++;
+ /* If this wasn't the last iteration, wrap instead of popping */
+ if (contextStack->reptIters[contextStack->reptDepth - 1]
+ <= contextStack->nbReptIters) {
+ lexer_RestartRept(contextStack->parent->lineNo);
+ contextStack->uniqueID = macro_UseNewUniqueID();
+ return false;
+ }
+ } else if (!contextStack->parent) {
+ return true;
+ }
+ contextStack = contextStack->parent;
+ contextDepth--;
+
+ lexer_DeleteState(contextStack->child->lexerState);
+ /* If at top level (= not in macro or in REPT), free the file name */
+ if (!contextStack->macro && contextStack->reptIters == 0)
+ free(contextStack->child->fileName);
+ /* Free the entry and make its parent the current entry */
+ free(contextStack->child);
+
+ contextStack->child = NULL;
+ lexer_SetState(contextStack->lexerState);
+ return false;
+}
+
+static void newContext(uint32_t reptDepth)
+{
+ if (++contextDepth >= nMaxRecursionDepth)
+ fatalerror("Recursion limit (%u) exceeded\n", nMaxRecursionDepth);
+ contextStack->child = malloc(sizeof(*contextStack->child)
+ + reptDepth * sizeof(contextStack->reptIters[0]));
+ if (!contextStack->child)
+ fatalerror("Failed to allocate memory for new context: %s\n", strerror(errno));
+
+ 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)
+{
char *fullPath = NULL;
size_t size = 0;
- if (!fstk_FindFile(tzFileName, &fullPath, &size)) {
- if (oGeneratedMissingIncludes)
- oFailedOnMissingInclude = true;
- else
- error("Unable to open included file '%s': %s\n",
- tzFileName, strerror(errno));
+ if (!fstk_FindFile(path, &fullPath, &size)) {
free(fullPath);
+ error("Unable to open included file '%s': %s\n", path, strerror(errno));
return;
}
- pushcontext();
- nCurrentStatus = STAT_isInclude;
- if (verbose)
- printf("Assembling %s\n", fullPath);
-
- struct LexerState *state = lexer_OpenFile(fullPath);
-
- if (!state)
- /* If lexer had an error, it already reported it */
- fatalerror("Failed to open file for INCLUDE\n"); /* TODO: make this non-fatal? */
- lexer_SetStateAtEOL(state);
- free(fullPath);
+ newContext(0);
+ contextStack->lexerState = lexer_OpenFile(fullPath);
+ 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->macro = NULL;
+ contextStack->nbReptIters = 0;
}
-/*
- * Set up a macro for parsing
- */
-void fstk_RunMacro(char *s, struct MacroArgs *args)
+void fstk_RunMacro(char *macroName, struct MacroArgs *args)
{
- struct Symbol const *sym = sym_FindSymbol(s);
+ struct Symbol *macro = sym_FindSymbol(macroName);
- if (sym == NULL) {
- error("Macro \"%s\" not defined\n", s);
+ if (!macro) {
+ error("Macro \"%s\" not defined\n", macroName);
return;
}
- if (sym->type != SYM_MACRO) {
- error("\"%s\" is not a macro\n", s);
+ if (macro->type != SYM_MACRO) {
+ error("\"%s\" is not a macro\n", macroName);
return;
}
-
- pushcontext();
- macro_SetUniqueID(nMacroCount++);
- /* Minus 1 because there is a newline at the beginning of the buffer */
macro_UseNewArgs(args);
- nCurrentStatus = STAT_isMacro;
- pCurrentMacro = sym;
+ newContext(0);
+ contextStack->lexerState = lexer_OpenFileView(macro->macro,
+ macro->macroSize, macro->fileLine);
+ if (!contextStack->lexerState)
+ fatalerror("Failed to set up lexer for macro invocation\n");
+ lexer_SetStateAtEOL(contextStack->lexerState);
+ contextStack->uniqueID = macro_UseNewUniqueID();
+ contextStack->fileName = macro->fileName;
+ contextStack->macro = macro;
+ contextStack->nbReptIters = 0;
}
-/*
- * Set up a repeat block for parsing
- */
-void fstk_RunRept(uint32_t count, int32_t nReptLineNo, char const *body, size_t size)
+void fstk_RunRept(uint32_t count, int32_t nReptLineNo, char *body, size_t size)
{
- if (count) {
- pushcontext();
- macro_SetUniqueID(nMacroCount++);
- nCurrentREPTBlockCount = count;
- nCurrentStatus = STAT_isREPTBlock;
- nCurrentREPTBlockSize = size;
- pCurrentREPTBlock = body;
- nCurrentREPTBodyFirstLine = nReptLineNo + 1;
- }
+ uint32_t reptDepth = contextStack->reptDepth;
+
+ newContext(reptDepth + 1);
+ contextStack->lexerState = lexer_OpenFileView(body, size, nReptLineNo);
+ if (!contextStack->lexerState)
+ fatalerror("Failed to set up lexer for macro invocation\n");
+ lexer_SetStateAtEOL(contextStack->lexerState);
+ contextStack->uniqueID = macro_UseNewUniqueID();
+ contextStack->fileName = contextStack->parent->fileName;
+ 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;
}
-/*
- * Initialize the filestack routines
- */
-void fstk_Init(char *pFileName)
+static void printContext(FILE *stream, struct Context const *context)
{
- char tzSymFileName[_MAX_PATH + 1 + 2];
+ 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);
+}
- char *c = pFileName;
- int fileNameIndex = 0;
+static void dumpToStream(FILE *stream)
+{
+ struct Context *context = topLevelContext;
- tzSymFileName[fileNameIndex++] = '"';
+ while (context != contextStack) {
+ printContext(stream, context);
+ fprintf(stream, " -> ");
+ context = context->child;
+ }
+ contextStack->lineNo = lexer_GetLineNo();
+ printContext(stream, contextStack);
+}
- // minus 2 to account for trailing "\"\0"
- // minus 1 to avoid a buffer overflow in extreme cases
- while (*c && fileNameIndex < sizeof(tzSymFileName) - 2 - 1) {
- if (*c == '"') {
- tzSymFileName[fileNameIndex++] = '\\';
- }
+void fstk_Dump(void)
+{
+ dumpToStream(stderr);
+}
- tzSymFileName[fileNameIndex++] = *c;
- ++c;
- }
+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);
- tzSymFileName[fileNameIndex++] = '"';
- tzSymFileName[fileNameIndex] = '\0';
+ if (!stream)
+ fatalerror("Failed to dump file stack to string: %s\n", strerror(errno));
+ dumpToStream(stream);
+ fclose(stream);
+ return str;
+}
- sym_AddString("__FILE__", tzSymFileName);
+uint32_t fstk_GetLine(void)
+{
+ return lexer_GetLineNo();
+}
- pFileStack = NULL;
- nFileStackDepth = 0;
+void fstk_Init(char *mainPath, uint32_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)
+ fatalerror("Failed to open main file!\n");
+ lexer_SetState(topLevelContext->lexerState);
+ topLevelContext->uniqueID = 0;
+ macro_SetUniqueID(0);
+ topLevelContext->fileName = mainPath;
+ topLevelContext->macro = NULL;
+ topLevelContext->nbReptIters = 0;
+ topLevelContext->reptDepth = 0;
- nMacroCount = 0;
- nCurrentStatus = STAT_isInclude;
+ contextStack = topLevelContext;
+
+#if 0
+ if (maxRecursionDepth
+ > (SIZE_MAX - sizeof(*contextStack)) / sizeof(contextStack->reptIters[0])) {
+#else
+ /* If this holds, then GCC raises a warning about the `if` above being dead code */
+ static_assert(UINT32_MAX
+ <= (SIZE_MAX - sizeof(*contextStack)) / sizeof(contextStack->reptIters[0]));
+ if (0) {
+#endif
+ error("Recursion depth may not be higher than %zu, defaulting to 64\n",
+ (SIZE_MAX - sizeof(*contextStack)) / sizeof(contextStack->reptIters[0]));
+ nMaxRecursionDepth = 64;
+ } else {
+ nMaxRecursionDepth = maxRecursionDepth;
+ }
}
--- a/src/asm/lexer.c
+++ b/src/asm/lexer.c
@@ -258,6 +258,8 @@
};
/* Common state */
+ bool isFile;
+
enum LexerMode mode;
bool atLineStart;
uint32_t lineNo;
@@ -278,6 +280,21 @@
struct LexerState *lexerState = NULL;
struct LexerState *lexerStateEOL = NULL;
+static void initState(struct LexerState *state)
+{
+ state->mode = LEXER_NORMAL;
+ state->atLineStart = true; /* yylex() will init colNo due to this */
+ state->lastToken = 0;
+
+ state->capturing = false;
+ state->captureBuf = NULL;
+
+ state->nbChars = 0;
+ state->expandStrings = true;
+ state->expansions = NULL;
+ state->expansionOfs = 0;
+}
+
struct LexerState *lexer_OpenFile(char const *path)
{
bool isStdin = !strcmp(path, "-");
@@ -292,6 +309,7 @@
}
state->path = path;
+ state->isFile = true;
state->fd = isStdin ? STDIN_FILENO : open(path, O_RDONLY);
if (state->fd == -1) {
error("Failed to open file \"%s\": %s\n", path, strerror(errno));
@@ -345,32 +363,45 @@
state->index = 0;
}
- state->mode = LEXER_NORMAL;
- state->atLineStart = true; /* yylex() will init colNo due to this */
- state->lineNo = 0;
- state->lastToken = 0;
+ initState(state);
+ state->lineNo = 0; /* Will be incremented at first line start */
+ return state;
+}
- state->capturing = false;
- state->captureBuf = NULL;
+struct LexerState *lexer_OpenFileView(char *buf, size_t size, uint32_t lineNo)
+{
+ struct LexerState *state = malloc(sizeof(*state));
- state->nbChars = 0;
- state->expandStrings = true;
- state->expansions = NULL;
- state->expansionOfs = 0;
+ if (!state) {
+ error("Failed to allocate memory for lexer state: %s", strerror(errno));
+ return NULL;
+ }
+ // TODO: init `path`
+
+ state->isFile = false;
+ state->isMmapped = true; /* It's not *really* mmap()ed, but it behaves the same */
+ state->ptr = buf;
+ state->size = size;
+ state->offset = 0;
+
+ initState(state);
+ state->lineNo = lineNo; /* Will be incremented at first line start */
return state;
}
-struct LexerState *lexer_OpenFileView(void)
+void lexer_RestartRept(uint32_t lineNo)
{
- return NULL;
+ lexerState->offset = 0;
+ initState(lexerState);
+ lexerState->lineNo = lineNo;
}
void lexer_DeleteState(struct LexerState *state)
{
- if (state->isMmapped)
- munmap(state->ptr, state->size);
- else
+ if (!state->isMmapped)
close(state->fd);
+ else if (state->isFile)
+ munmap(state->ptr, state->size);
free(state);
}
@@ -523,7 +554,7 @@
#define LOOKUP_PRE_NEST(exp) (exp)->totalLen += size
#define LOOKUP_POST_NEST(exp) do { \
if (++depth >= nMaxRecursionDepth) \
- fatalerror("Recursion limit (%u) exceeded", nMaxRecursionDepth); \
+ fatalerror("Recursion limit (%u) exceeded\n", nMaxRecursionDepth); \
} while (0)
lookupExpansion(parent, distance);
#undef LOOKUP_PRE_NEST
@@ -536,7 +567,7 @@
*insertPoint = malloc(sizeof(**insertPoint));
if (!*insertPoint)
- fatalerror("Unable to allocate new expansion: %s", strerror(errno));
+ fatalerror("Unable to allocate new expansion: %s\n", strerror(errno));
(*insertPoint)->firstChild = NULL;
(*insertPoint)->next = NULL; /* Expansions are always performed left to right */
(*insertPoint)->name = strdup(name);
@@ -1417,10 +1448,6 @@
return '\n';
case EOF:
- /* Captures end at their buffer's boundary no matter what */
- if (!lexerState->capturing) {
- /* TODO: use `yywrap()` */
- }
return 0;
/* Handle identifiers... or error out */
@@ -1520,6 +1547,7 @@
int yylex(void)
{
+restart:
if (lexerState->atLineStart
/* Newlines read within an expansion should not increase the line count */
&& (!lexerState->expansions || lexerState->expansions->distance)) {
@@ -1536,8 +1564,17 @@
int token = lexerModeFuncs[lexerState->mode]();
/* Make sure to terminate files with a line feed */
- if (token == 0 && lexerState->lastToken != '\n')
- token = '\n';
+ if (token == 0) {
+ if (lexerState->lastToken != '\n') {
+ token = '\n';
+ } else { /* Try to switch to new buffer; if it succeeds, scan again */
+ /* Captures end at their buffer's boundary no matter what */
+ if (!lexerState->capturing) {
+ if (!yywrap())
+ goto restart;
+ }
+ }
+ }
lexerState->lastToken = token;
lexerState->atLineStart = false;
@@ -1547,9 +1584,11 @@
return token;
}
-void lexer_CaptureBlock(int blockStartToken, int blockEndToken, char const **capture, size_t *size,
+void lexer_CaptureBlock(int blockStartToken, int blockEndToken, char **capture, size_t *size,
char const *name)
{
+ assert(!lexerState->expansions);
+
lexerState->capturing = true;
lexerState->captureSize = 0;
unsigned int level = 0;
@@ -1556,7 +1595,7 @@
char *captureStart;
if (lexerState->isMmapped) {
- captureStart = lexerState->ptr;
+ captureStart = &lexerState->ptr[lexerState->offset];
} else {
lexerState->captureCapacity = 128; /* The initial size will be twice that */
reallocCaptureBuf();
--- a/src/asm/macro.c
+++ b/src/asm/macro.c
@@ -29,7 +29,8 @@
sizeof(((struct MacroArgs){0}).args[0]) * (nbArgs))
static struct MacroArgs *macroArgs = NULL;
-static uint32_t uniqueID = -1;
+static uint32_t uniqueID = 0;
+static uint32_t maxUniqueID = 0;
/*
* The initialization is somewhat harmful, since it is never used, but it
* guarantees the size of the buffer will be correct. I was unable to find a
@@ -107,13 +108,21 @@
void macro_SetUniqueID(uint32_t id)
{
uniqueID = id;
- if (id == -1) {
+ if (id == 0) {
uniqueIDPtr = NULL;
} else {
+ if (uniqueID > maxUniqueID)
+ maxUniqueID = uniqueID;
/* The buffer is guaranteed to be the correct size */
sprintf(uniqueIDBuf, "_%" PRIu32, id);
uniqueIDPtr = uniqueIDBuf;
}
+}
+
+uint32_t macro_UseNewUniqueID(void)
+{
+ macro_SetUniqueID(++maxUniqueID);
+ return maxUniqueID;
}
void macro_ShiftCurrentArgs(void)
--- a/src/asm/main.c
+++ b/src/asm/main.c
@@ -23,8 +23,10 @@
#include "asm/lexer.h"
#include "asm/main.h"
#include "asm/output.h"
+#include "asm/rpn.h"
#include "asm/symbol.h"
#include "asm/warning.h"
+#include "asmy.h"
#include "extern/err.h"
#include "extern/getopt.h"
@@ -32,8 +34,6 @@
#include "helpers.h"
#include "version.h"
-extern int yyparse(void);
-
size_t cldefines_index;
size_t cldefines_numindices;
size_t cldefines_bufsize;
@@ -307,11 +307,11 @@
yydebug = 1;
#endif
- nMaxRecursionDepth = 64;
oGeneratePhonyDeps = false;
oGeneratedMissingIncludes = false;
oFailedOnMissingInclude = false;
tzTargetFileName = NULL;
+ uint32_t maxRecursionDepth = 64;
size_t nTargetFileNameLen = 0;
DefaultOptions.gbgfx[0] = '0';
@@ -390,7 +390,7 @@
break;
case 'r':
- nMaxRecursionDepth = strtoul(optarg, &ep, 0);
+ maxRecursionDepth = strtoul(optarg, &ep, 0);
if (optarg[0] == '\0' || *ep != '\0')
errx(1, "Invalid argument for option 'r'");
@@ -483,13 +483,9 @@
fprintf(dependfile, "%s: %s\n", tzTargetFileName, tzMainfile);
}
- /* Init lexer; important to do first, since that's what provides the file name, line, etc */
- struct LexerState *state = lexer_OpenFile(tzMainfile);
-
- if (!state)
- fatalerror("Failed to open main file!\n");
+ /* Init file stack; important to do first, since it provides the file name, line, etc */
lexer_Init();
- lexer_SetState(state);
+ fstk_Init(tzMainfile, maxRecursionDepth);
nStartClock = clock();
@@ -497,7 +493,6 @@
nIFDepth = 0;
sym_Init();
sym_SetExportAll(exportall);
- fstk_Init(tzMainfile);
opt_ParseDefines();
charmap_New("main", NULL);
--- a/src/asm/output.c
+++ b/src/asm/output.c
@@ -33,7 +33,7 @@
#include "platform.h" // strdup
struct Patch {
- char tzFilename[_MAX_PATH + 1];
+ char *tzFilename;
uint32_t nOffset;
struct Section *pcSection;
uint32_t pcOffset;
@@ -318,7 +318,7 @@
fatalerror("No memory for patch's RPN expression: %s\n", strerror(errno));
patch->type = type;
- fstk_DumpToStr(patch->tzFilename, sizeof(patch->tzFilename));
+ patch->tzFilename = fstk_DumpToStr();
patch->nOffset = ofs;
patch->pcSection = sect_GetSymbolSection();
patch->pcOffset = sect_GetSymbolOffset();
--- a/src/asm/symbol.c
+++ b/src/asm/symbol.c
@@ -477,7 +477,7 @@
/*
* Add a macro definition
*/
-struct Symbol *sym_AddMacro(char const *symName, int32_t defLineNo, char const *body, size_t size)
+struct Symbol *sym_AddMacro(char const *symName, int32_t defLineNo, char *body, size_t size)
{
struct Symbol *sym = createNonrelocSymbol(symName);
--- /dev/null
+++ b/test/asm/file-sym.asm
@@ -1,0 +1,1 @@
+PRINTT "{__FILE__}\n"
--- /dev/null
+++ b/test/asm/file-sym.out
@@ -1,0 +1,1 @@
+"test/asm/file-sym.asm"