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...
This commit is contained in:
ISSOtm
2020-07-31 18:24:44 +02:00
parent 7c895f8a1b
commit e11f25024e
15 changed files with 343 additions and 432 deletions

View File

@@ -72,7 +72,7 @@ rgbasm_obj := \
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 \

View File

@@ -41,13 +41,7 @@ struct sContext {
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 @@ void fstk_RunRept(uint32_t count, int32_t nReptLineNo, char const *body, size_t
* @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 */

View File

@@ -31,7 +31,8 @@ static inline void lexer_SetStateAtEOL(struct LexerState *state)
}
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_GetLineNo(void);
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 */

View File

@@ -28,6 +28,7 @@ char const *macro_GetArg(uint32_t i);
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);

View File

@@ -45,7 +45,7 @@ struct Symbol {
};
struct { /* For SYM_MACRO */
size_t macroSize;
char const *macro;
char *macro;
};
};
@@ -117,7 +117,7 @@ uint32_t sym_GetPCValue(void);
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);

View File

@@ -597,21 +597,21 @@ load : T_POP_LOAD string ',' sectiontype sectorg sectattrs {
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"));
}
;

View File

@@ -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);
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;
if (*end++ != '/')
*end++ = '/';
*end = '\0';
includePaths[nbIncPaths++] = str;
}
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;
}
}
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;
}
int32_t fstk_GetLine(void)
{
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)
static void printDep(char const *path)
{
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 @@ bool fstk_FindFile(char const *path, char **fullPath, size_t *size)
}
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 @@ bool fstk_FindFile(char const *path, char **fullPath, size_t *size)
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 @@ bool fstk_FindFile(char const *path, char **fullPath, size_t *size)
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;
}
static void printContext(FILE *stream, struct Context const *context)
{
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);
}
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;
}
uint32_t fstk_GetLine(void)
{
return lexer_GetLineNo();
}
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;
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;
}
}
/*
* Initialize the filestack routines
*/
void fstk_Init(char *pFileName)
{
char tzSymFileName[_MAX_PATH + 1 + 2];
char *c = pFileName;
int fileNameIndex = 0;
tzSymFileName[fileNameIndex++] = '"';
// 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++] = '\\';
}
tzSymFileName[fileNameIndex++] = *c;
++c;
}
tzSymFileName[fileNameIndex++] = '"';
tzSymFileName[fileNameIndex] = '\0';
sym_AddString("__FILE__", tzSymFileName);
pFileStack = NULL;
nFileStackDepth = 0;
nMacroCount = 0;
nCurrentStatus = STAT_isInclude;
}

View File

@@ -258,6 +258,8 @@ struct LexerState {
};
/* Common state */
bool isFile;
enum LexerMode mode;
bool atLineStart;
uint32_t lineNo;
@@ -278,6 +280,21 @@ struct LexerState {
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 @@ struct LexerState *lexer_OpenFile(char const *path)
}
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 @@ struct LexerState *lexer_OpenFile(char const *path)
state->index = 0;
}
state->mode = LEXER_NORMAL;
state->atLineStart = true; /* yylex() will init colNo due to this */
state->lineNo = 0;
state->lastToken = 0;
state->capturing = false;
state->captureBuf = NULL;
state->nbChars = 0;
state->expandStrings = true;
state->expansions = NULL;
state->expansionOfs = 0;
initState(state);
state->lineNo = 0; /* Will be incremented at first line start */
return state;
}
struct LexerState *lexer_OpenFileView(void)
struct LexerState *lexer_OpenFileView(char *buf, size_t size, uint32_t lineNo)
{
return NULL;
struct LexerState *state = malloc(sizeof(*state));
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;
}
void lexer_RestartRept(uint32_t lineNo)
{
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 @@ static void beginExpansion(size_t distance, uint8_t skip,
#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 @@ static void beginExpansion(size_t distance, uint8_t skip,
*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 @@ static int yylex_NORMAL(void)
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 @@ static int yylex_SKIP_TO_ENDC(void)
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 yylex(void)
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,16 +1584,18 @@ int yylex(void)
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;
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();

View File

@@ -29,7 +29,8 @@ struct MacroArgs {
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,15 +108,23 @@ char const *macro_GetUniqueIDStr(void)
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)
{
if (macroArgs->shift != macroArgs->nbArgs)

View File

@@ -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 @@ int main(int argc, char *argv[])
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 @@ int main(int argc, char *argv[])
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 @@ int main(int argc, char *argv[])
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 @@ int main(int argc, char *argv[])
nIFDepth = 0;
sym_Init();
sym_SetExportAll(exportall);
fstk_Init(tzMainfile);
opt_ParseDefines();
charmap_New("main", NULL);

View File

@@ -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 @@ static struct Patch *allocpatch(uint32_t type, struct Expression const *expr,
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();

View File

@@ -477,7 +477,7 @@ void sym_Export(char const *symName)
/*
* 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);

1
test/asm/file-sym.asm Normal file
View File

@@ -0,0 +1 @@
PRINTT "{__FILE__}\n"

0
test/asm/file-sym.err Normal file
View File

1
test/asm/file-sym.out Normal file
View File

@@ -0,0 +1 @@
"test/asm/file-sym.asm"