mirror of
https://github.com/gbdev/rgbds.git
synced 2025-11-20 18:22:07 +00:00
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:
2
Makefile
2
Makefile
@@ -72,7 +72,7 @@ rgbasm_obj := \
|
|||||||
src/hashmap.o \
|
src/hashmap.o \
|
||||||
src/linkdefs.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 := \
|
rgblink_obj := \
|
||||||
src/link/assign.o \
|
src/link/assign.o \
|
||||||
|
|||||||
@@ -41,13 +41,7 @@ struct sContext {
|
|||||||
|
|
||||||
extern unsigned int nMaxRecursionDepth;
|
extern unsigned int nMaxRecursionDepth;
|
||||||
|
|
||||||
void fstk_RunInclude(char *tzFileName);
|
void fstk_AddIncludePath(char const *s);
|
||||||
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);
|
|
||||||
/**
|
/**
|
||||||
* @param path The user-provided file name
|
* @param path The user-provided file name
|
||||||
* @param fullPath The address of a pointer, which will be made to point at the full path
|
* @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
|
* @return True if the file was found, false if no path worked
|
||||||
*/
|
*/
|
||||||
bool fstk_FindFile(char const *path, char **fullPath, size_t *size);
|
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 */
|
#endif /* RGBDS_ASM_FSTACK_H */
|
||||||
|
|||||||
@@ -31,7 +31,8 @@ static inline void lexer_SetStateAtEOL(struct LexerState *state)
|
|||||||
}
|
}
|
||||||
|
|
||||||
struct LexerState *lexer_OpenFile(char const *path);
|
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_DeleteState(struct LexerState *state);
|
||||||
void lexer_Init(void);
|
void lexer_Init(void);
|
||||||
|
|
||||||
@@ -50,7 +51,7 @@ uint32_t lexer_GetLineNo(void);
|
|||||||
uint32_t lexer_GetColNo(void);
|
uint32_t lexer_GetColNo(void);
|
||||||
void lexer_DumpStringExpansions(void);
|
void lexer_DumpStringExpansions(void);
|
||||||
int yylex(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);
|
char const *name);
|
||||||
|
|
||||||
#endif /* RGBDS_ASM_LEXER_H */
|
#endif /* RGBDS_ASM_LEXER_H */
|
||||||
|
|||||||
@@ -28,6 +28,7 @@ char const *macro_GetArg(uint32_t i);
|
|||||||
uint32_t macro_GetUniqueID(void);
|
uint32_t macro_GetUniqueID(void);
|
||||||
char const *macro_GetUniqueIDStr(void);
|
char const *macro_GetUniqueIDStr(void);
|
||||||
void macro_SetUniqueID(uint32_t id);
|
void macro_SetUniqueID(uint32_t id);
|
||||||
|
uint32_t macro_UseNewUniqueID(void);
|
||||||
void macro_ShiftCurrentArgs(void);
|
void macro_ShiftCurrentArgs(void);
|
||||||
uint32_t macro_NbArgs(void);
|
uint32_t macro_NbArgs(void);
|
||||||
|
|
||||||
|
|||||||
@@ -45,7 +45,7 @@ struct Symbol {
|
|||||||
};
|
};
|
||||||
struct { /* For SYM_MACRO */
|
struct { /* For SYM_MACRO */
|
||||||
size_t macroSize;
|
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_GetConstantSymValue(struct Symbol const *sym);
|
||||||
uint32_t sym_GetConstantValue(char const *s);
|
uint32_t sym_GetConstantValue(char const *s);
|
||||||
struct Symbol *sym_FindSymbol(char const *symName);
|
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_Ref(char const *symName);
|
||||||
struct Symbol *sym_AddString(char const *symName, char const *value);
|
struct Symbol *sym_AddString(char const *symName, char const *value);
|
||||||
uint32_t sym_GetDefinedValue(char const *s);
|
uint32_t sym_GetDefinedValue(char const *s);
|
||||||
|
|||||||
@@ -597,21 +597,21 @@ load : T_POP_LOAD string ',' sectiontype sectorg sectattrs {
|
|||||||
|
|
||||||
rept : T_POP_REPT uconst {
|
rept : T_POP_REPT uconst {
|
||||||
uint32_t nDefinitionLineNo = lexer_GetLineNo();
|
uint32_t nDefinitionLineNo = lexer_GetLineNo();
|
||||||
char const *body;
|
char *body;
|
||||||
size_t size;
|
size_t size;
|
||||||
lexer_CaptureBlock(T_POP_REPT, T_POP_ENDR, &body, &size,
|
lexer_CaptureBlock(T_POP_REPT, T_POP_ENDR, &body, &size,
|
||||||
"REPT block");
|
"REPT block");
|
||||||
fstk_RunRept($2, nDefinitionLineNo, body, size);
|
fstk_RunRept($2, nDefinitionLineNo, body, size - strlen("ENDR"));
|
||||||
}
|
}
|
||||||
;
|
;
|
||||||
|
|
||||||
macrodef : T_LABEL ':' T_POP_MACRO {
|
macrodef : T_LABEL ':' T_POP_MACRO {
|
||||||
int32_t nDefinitionLineNo = lexer_GetLineNo();
|
int32_t nDefinitionLineNo = lexer_GetLineNo();
|
||||||
char const *body;
|
char *body;
|
||||||
size_t size;
|
size_t size;
|
||||||
lexer_CaptureBlock(T_POP_MACRO, T_POP_ENDM, &body, &size,
|
lexer_CaptureBlock(T_POP_MACRO, T_POP_ENDM, &body, &size,
|
||||||
"macro definition");
|
"macro definition");
|
||||||
sym_AddMacro($1, nDefinitionLineNo, body, size);
|
sym_AddMacro($1, nDefinitionLineNo, body, size - strlen("ENDM"));
|
||||||
}
|
}
|
||||||
;
|
;
|
||||||
|
|
||||||
|
|||||||
604
src/asm/fstack.c
604
src/asm/fstack.c
@@ -6,318 +6,82 @@
|
|||||||
* SPDX-License-Identifier: MIT
|
* SPDX-License-Identifier: MIT
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/*
|
#include <sys/stat.h>
|
||||||
* FileStack routines
|
#include <assert.h>
|
||||||
*/
|
|
||||||
|
|
||||||
#include <errno.h>
|
#include <errno.h>
|
||||||
#include <inttypes.h>
|
#include <inttypes.h>
|
||||||
#include <limits.h>
|
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <string.h>
|
|
||||||
#include <sys/stat.h>
|
|
||||||
#include <sys/types.h>
|
|
||||||
|
|
||||||
#include "asm/fstack.h"
|
#include "asm/fstack.h"
|
||||||
#include "asm/lexer.h"
|
|
||||||
#include "asm/macro.h"
|
#include "asm/macro.h"
|
||||||
#include "asm/main.h"
|
#include "asm/main.h"
|
||||||
#include "asm/output.h"
|
#include "asm/symbol.h"
|
||||||
#include "asm/warning.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)
|
static struct Context *contextStack;
|
||||||
#include "types.h"
|
static struct Context *topLevelContext;
|
||||||
|
static unsigned int contextDepth = 0;
|
||||||
static struct sContext *pFileStack;
|
|
||||||
static unsigned int nFileStackDepth;
|
|
||||||
unsigned int nMaxRecursionDepth;
|
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 unsigned int nbIncPaths = 0;
|
||||||
static uint32_t nCurrentREPTBlockSize;
|
static char const *includePaths[MAXINCPATHS];
|
||||||
static uint32_t nCurrentREPTBlockCount;
|
|
||||||
static int32_t nCurrentREPTBodyFirstLine;
|
|
||||||
static int32_t nCurrentREPTBodyLastLine;
|
|
||||||
|
|
||||||
uint32_t ulMacroReturnValue;
|
void fstk_AddIncludePath(char const *path)
|
||||||
|
|
||||||
/*
|
|
||||||
* 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)
|
|
||||||
{
|
{
|
||||||
struct sContext **ppFileStack;
|
if (path[0] == '\0')
|
||||||
|
return;
|
||||||
if (++nFileStackDepth > nMaxRecursionDepth)
|
if (nbIncPaths >= MAXINCPATHS) {
|
||||||
fatalerror("Recursion limit (%u) exceeded\n", nMaxRecursionDepth);
|
error("Too many include directories passed from command line\n");
|
||||||
|
return;
|
||||||
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__);
|
|
||||||
}
|
}
|
||||||
(*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)
|
static void printDep(char const *path)
|
||||||
{
|
|
||||||
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)
|
|
||||||
{
|
{
|
||||||
if (dependfile) {
|
if (dependfile) {
|
||||||
fprintf(dependfile, "%s: %s\n", tzTargetFileName, fileName);
|
fprintf(dependfile, "%s: %s\n", tzTargetFileName, path);
|
||||||
if (oGeneratePhonyDeps)
|
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;
|
struct stat statbuf;
|
||||||
|
|
||||||
if (stat(pathname, &statbuf) != 0)
|
if (stat(path, &statbuf) != 0)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
/* Reject directories */
|
/* Reject directories */
|
||||||
@@ -335,8 +99,8 @@ bool fstk_FindFile(char const *path, char **fullPath, size_t *size)
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (*fullPath) {
|
if (*fullPath) {
|
||||||
for (size_t i = 0; i <= NextIncPath; ++i) {
|
for (size_t i = 0; i <= nbIncPaths; ++i) {
|
||||||
char *incPath = i ? IncludePaths[i - 1] : "";
|
char const *incPath = i ? includePaths[i - 1] : "";
|
||||||
int len = snprintf(*fullPath, *size, "%s%s", incPath, path);
|
int len = snprintf(*fullPath, *size, "%s%s", incPath, path);
|
||||||
|
|
||||||
/* Oh how I wish `asnprintf` was standard... */
|
/* 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",
|
error("snprintf error during include path search: %s\n",
|
||||||
strerror(errno));
|
strerror(errno));
|
||||||
} else if (isPathValid(*fullPath)) {
|
} else if (isPathValid(*fullPath)) {
|
||||||
printdep(*fullPath);
|
printDep(*fullPath);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -363,114 +127,210 @@ bool fstk_FindFile(char const *path, char **fullPath, size_t *size)
|
|||||||
|
|
||||||
errno = ENOENT;
|
errno = ENOENT;
|
||||||
if (oGeneratedMissingIncludes)
|
if (oGeneratedMissingIncludes)
|
||||||
printdep(path);
|
printDep(path);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
bool yywrap(void)
|
||||||
* Set up an include file for parsing
|
{
|
||||||
*/
|
if (contextStack->nbReptIters) { /* The context is a REPT block, which may loop */
|
||||||
void fstk_RunInclude(char *tzFileName)
|
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;
|
char *fullPath = NULL;
|
||||||
size_t size = 0;
|
size_t size = 0;
|
||||||
|
|
||||||
if (!fstk_FindFile(tzFileName, &fullPath, &size)) {
|
if (!fstk_FindFile(path, &fullPath, &size)) {
|
||||||
if (oGeneratedMissingIncludes)
|
|
||||||
oFailedOnMissingInclude = true;
|
|
||||||
else
|
|
||||||
error("Unable to open included file '%s': %s\n",
|
|
||||||
tzFileName, strerror(errno));
|
|
||||||
free(fullPath);
|
free(fullPath);
|
||||||
|
error("Unable to open included file '%s': %s\n", path, strerror(errno));
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
pushcontext();
|
newContext(0);
|
||||||
nCurrentStatus = STAT_isInclude;
|
contextStack->lexerState = lexer_OpenFile(fullPath);
|
||||||
if (verbose)
|
if (!contextStack->lexerState)
|
||||||
printf("Assembling %s\n", fullPath);
|
fatalerror("Failed to set up lexer for file include\n");
|
||||||
|
lexer_SetStateAtEOL(contextStack->lexerState);
|
||||||
struct LexerState *state = lexer_OpenFile(fullPath);
|
/* We're back at top-level, so most things are reset */
|
||||||
|
contextStack->uniqueID = 0;
|
||||||
if (!state)
|
macro_SetUniqueID(0);
|
||||||
/* If lexer had an error, it already reported it */
|
contextStack->fileName = fullPath;
|
||||||
fatalerror("Failed to open file for INCLUDE\n"); /* TODO: make this non-fatal? */
|
contextStack->macro = NULL;
|
||||||
lexer_SetStateAtEOL(state);
|
contextStack->nbReptIters = 0;
|
||||||
free(fullPath);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
void fstk_RunMacro(char *macroName, struct MacroArgs *args)
|
||||||
* Set up a macro for parsing
|
|
||||||
*/
|
|
||||||
void fstk_RunMacro(char *s, struct MacroArgs *args)
|
|
||||||
{
|
{
|
||||||
struct Symbol const *sym = sym_FindSymbol(s);
|
struct Symbol *macro = sym_FindSymbol(macroName);
|
||||||
|
|
||||||
if (sym == NULL) {
|
if (!macro) {
|
||||||
error("Macro \"%s\" not defined\n", s);
|
error("Macro \"%s\" not defined\n", macroName);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (sym->type != SYM_MACRO) {
|
if (macro->type != SYM_MACRO) {
|
||||||
error("\"%s\" is not a macro\n", s);
|
error("\"%s\" is not a macro\n", macroName);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
pushcontext();
|
|
||||||
macro_SetUniqueID(nMacroCount++);
|
|
||||||
/* Minus 1 because there is a newline at the beginning of the buffer */
|
|
||||||
macro_UseNewArgs(args);
|
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;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
void fstk_RunRept(uint32_t count, int32_t nReptLineNo, char *body, size_t size)
|
||||||
* Set up a repeat block for parsing
|
|
||||||
*/
|
|
||||||
void fstk_RunRept(uint32_t count, int32_t nReptLineNo, char const *body, size_t size)
|
|
||||||
{
|
{
|
||||||
if (count) {
|
uint32_t reptDepth = contextStack->reptDepth;
|
||||||
pushcontext();
|
|
||||||
macro_SetUniqueID(nMacroCount++);
|
newContext(reptDepth + 1);
|
||||||
nCurrentREPTBlockCount = count;
|
contextStack->lexerState = lexer_OpenFileView(body, size, nReptLineNo);
|
||||||
nCurrentStatus = STAT_isREPTBlock;
|
if (!contextStack->lexerState)
|
||||||
nCurrentREPTBlockSize = size;
|
fatalerror("Failed to set up lexer for macro invocation\n");
|
||||||
pCurrentREPTBlock = body;
|
lexer_SetStateAtEOL(contextStack->lexerState);
|
||||||
nCurrentREPTBodyFirstLine = nReptLineNo + 1;
|
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;
|
|
||||||
}
|
|
||||||
|
|||||||
@@ -258,6 +258,8 @@ struct LexerState {
|
|||||||
};
|
};
|
||||||
|
|
||||||
/* Common state */
|
/* Common state */
|
||||||
|
bool isFile;
|
||||||
|
|
||||||
enum LexerMode mode;
|
enum LexerMode mode;
|
||||||
bool atLineStart;
|
bool atLineStart;
|
||||||
uint32_t lineNo;
|
uint32_t lineNo;
|
||||||
@@ -278,6 +280,21 @@ struct LexerState {
|
|||||||
struct LexerState *lexerState = NULL;
|
struct LexerState *lexerState = NULL;
|
||||||
struct LexerState *lexerStateEOL = 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)
|
struct LexerState *lexer_OpenFile(char const *path)
|
||||||
{
|
{
|
||||||
bool isStdin = !strcmp(path, "-");
|
bool isStdin = !strcmp(path, "-");
|
||||||
@@ -292,6 +309,7 @@ struct LexerState *lexer_OpenFile(char const *path)
|
|||||||
}
|
}
|
||||||
state->path = path;
|
state->path = path;
|
||||||
|
|
||||||
|
state->isFile = true;
|
||||||
state->fd = isStdin ? STDIN_FILENO : open(path, O_RDONLY);
|
state->fd = isStdin ? STDIN_FILENO : open(path, O_RDONLY);
|
||||||
if (state->fd == -1) {
|
if (state->fd == -1) {
|
||||||
error("Failed to open file \"%s\": %s\n", path, strerror(errno));
|
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->index = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
state->mode = LEXER_NORMAL;
|
initState(state);
|
||||||
state->atLineStart = true; /* yylex() will init colNo due to this */
|
state->lineNo = 0; /* Will be incremented at first line start */
|
||||||
state->lineNo = 0;
|
|
||||||
state->lastToken = 0;
|
|
||||||
|
|
||||||
state->capturing = false;
|
|
||||||
state->captureBuf = NULL;
|
|
||||||
|
|
||||||
state->nbChars = 0;
|
|
||||||
state->expandStrings = true;
|
|
||||||
state->expansions = NULL;
|
|
||||||
state->expansionOfs = 0;
|
|
||||||
return state;
|
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)
|
void lexer_DeleteState(struct LexerState *state)
|
||||||
{
|
{
|
||||||
if (state->isMmapped)
|
if (!state->isMmapped)
|
||||||
munmap(state->ptr, state->size);
|
|
||||||
else
|
|
||||||
close(state->fd);
|
close(state->fd);
|
||||||
|
else if (state->isFile)
|
||||||
|
munmap(state->ptr, state->size);
|
||||||
free(state);
|
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_PRE_NEST(exp) (exp)->totalLen += size
|
||||||
#define LOOKUP_POST_NEST(exp) do { \
|
#define LOOKUP_POST_NEST(exp) do { \
|
||||||
if (++depth >= nMaxRecursionDepth) \
|
if (++depth >= nMaxRecursionDepth) \
|
||||||
fatalerror("Recursion limit (%u) exceeded", nMaxRecursionDepth); \
|
fatalerror("Recursion limit (%u) exceeded\n", nMaxRecursionDepth); \
|
||||||
} while (0)
|
} while (0)
|
||||||
lookupExpansion(parent, distance);
|
lookupExpansion(parent, distance);
|
||||||
#undef LOOKUP_PRE_NEST
|
#undef LOOKUP_PRE_NEST
|
||||||
@@ -536,7 +567,7 @@ static void beginExpansion(size_t distance, uint8_t skip,
|
|||||||
|
|
||||||
*insertPoint = malloc(sizeof(**insertPoint));
|
*insertPoint = malloc(sizeof(**insertPoint));
|
||||||
if (!*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)->firstChild = NULL;
|
||||||
(*insertPoint)->next = NULL; /* Expansions are always performed left to right */
|
(*insertPoint)->next = NULL; /* Expansions are always performed left to right */
|
||||||
(*insertPoint)->name = strdup(name);
|
(*insertPoint)->name = strdup(name);
|
||||||
@@ -1417,10 +1448,6 @@ static int yylex_NORMAL(void)
|
|||||||
return '\n';
|
return '\n';
|
||||||
|
|
||||||
case EOF:
|
case EOF:
|
||||||
/* Captures end at their buffer's boundary no matter what */
|
|
||||||
if (!lexerState->capturing) {
|
|
||||||
/* TODO: use `yywrap()` */
|
|
||||||
}
|
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
/* Handle identifiers... or error out */
|
/* Handle identifiers... or error out */
|
||||||
@@ -1520,6 +1547,7 @@ static int yylex_SKIP_TO_ENDC(void)
|
|||||||
|
|
||||||
int yylex(void)
|
int yylex(void)
|
||||||
{
|
{
|
||||||
|
restart:
|
||||||
if (lexerState->atLineStart
|
if (lexerState->atLineStart
|
||||||
/* Newlines read within an expansion should not increase the line count */
|
/* Newlines read within an expansion should not increase the line count */
|
||||||
&& (!lexerState->expansions || lexerState->expansions->distance)) {
|
&& (!lexerState->expansions || lexerState->expansions->distance)) {
|
||||||
@@ -1536,8 +1564,17 @@ int yylex(void)
|
|||||||
int token = lexerModeFuncs[lexerState->mode]();
|
int token = lexerModeFuncs[lexerState->mode]();
|
||||||
|
|
||||||
/* Make sure to terminate files with a line feed */
|
/* Make sure to terminate files with a line feed */
|
||||||
if (token == 0 && lexerState->lastToken != '\n')
|
if (token == 0) {
|
||||||
token = '\n';
|
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->lastToken = token;
|
||||||
|
|
||||||
lexerState->atLineStart = false;
|
lexerState->atLineStart = false;
|
||||||
@@ -1547,16 +1584,18 @@ int yylex(void)
|
|||||||
return token;
|
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)
|
char const *name)
|
||||||
{
|
{
|
||||||
|
assert(!lexerState->expansions);
|
||||||
|
|
||||||
lexerState->capturing = true;
|
lexerState->capturing = true;
|
||||||
lexerState->captureSize = 0;
|
lexerState->captureSize = 0;
|
||||||
unsigned int level = 0;
|
unsigned int level = 0;
|
||||||
char *captureStart;
|
char *captureStart;
|
||||||
|
|
||||||
if (lexerState->isMmapped) {
|
if (lexerState->isMmapped) {
|
||||||
captureStart = lexerState->ptr;
|
captureStart = &lexerState->ptr[lexerState->offset];
|
||||||
} else {
|
} else {
|
||||||
lexerState->captureCapacity = 128; /* The initial size will be twice that */
|
lexerState->captureCapacity = 128; /* The initial size will be twice that */
|
||||||
reallocCaptureBuf();
|
reallocCaptureBuf();
|
||||||
|
|||||||
@@ -29,7 +29,8 @@ struct MacroArgs {
|
|||||||
sizeof(((struct MacroArgs){0}).args[0]) * (nbArgs))
|
sizeof(((struct MacroArgs){0}).args[0]) * (nbArgs))
|
||||||
|
|
||||||
static struct MacroArgs *macroArgs = NULL;
|
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
|
* 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
|
* 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)
|
void macro_SetUniqueID(uint32_t id)
|
||||||
{
|
{
|
||||||
uniqueID = id;
|
uniqueID = id;
|
||||||
if (id == -1) {
|
if (id == 0) {
|
||||||
uniqueIDPtr = NULL;
|
uniqueIDPtr = NULL;
|
||||||
} else {
|
} else {
|
||||||
|
if (uniqueID > maxUniqueID)
|
||||||
|
maxUniqueID = uniqueID;
|
||||||
/* The buffer is guaranteed to be the correct size */
|
/* The buffer is guaranteed to be the correct size */
|
||||||
sprintf(uniqueIDBuf, "_%" PRIu32, id);
|
sprintf(uniqueIDBuf, "_%" PRIu32, id);
|
||||||
uniqueIDPtr = uniqueIDBuf;
|
uniqueIDPtr = uniqueIDBuf;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
uint32_t macro_UseNewUniqueID(void)
|
||||||
|
{
|
||||||
|
macro_SetUniqueID(++maxUniqueID);
|
||||||
|
return maxUniqueID;
|
||||||
|
}
|
||||||
|
|
||||||
void macro_ShiftCurrentArgs(void)
|
void macro_ShiftCurrentArgs(void)
|
||||||
{
|
{
|
||||||
if (macroArgs->shift != macroArgs->nbArgs)
|
if (macroArgs->shift != macroArgs->nbArgs)
|
||||||
|
|||||||
@@ -23,8 +23,10 @@
|
|||||||
#include "asm/lexer.h"
|
#include "asm/lexer.h"
|
||||||
#include "asm/main.h"
|
#include "asm/main.h"
|
||||||
#include "asm/output.h"
|
#include "asm/output.h"
|
||||||
|
#include "asm/rpn.h"
|
||||||
#include "asm/symbol.h"
|
#include "asm/symbol.h"
|
||||||
#include "asm/warning.h"
|
#include "asm/warning.h"
|
||||||
|
#include "asmy.h"
|
||||||
|
|
||||||
#include "extern/err.h"
|
#include "extern/err.h"
|
||||||
#include "extern/getopt.h"
|
#include "extern/getopt.h"
|
||||||
@@ -32,8 +34,6 @@
|
|||||||
#include "helpers.h"
|
#include "helpers.h"
|
||||||
#include "version.h"
|
#include "version.h"
|
||||||
|
|
||||||
extern int yyparse(void);
|
|
||||||
|
|
||||||
size_t cldefines_index;
|
size_t cldefines_index;
|
||||||
size_t cldefines_numindices;
|
size_t cldefines_numindices;
|
||||||
size_t cldefines_bufsize;
|
size_t cldefines_bufsize;
|
||||||
@@ -307,11 +307,11 @@ int main(int argc, char *argv[])
|
|||||||
yydebug = 1;
|
yydebug = 1;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
nMaxRecursionDepth = 64;
|
|
||||||
oGeneratePhonyDeps = false;
|
oGeneratePhonyDeps = false;
|
||||||
oGeneratedMissingIncludes = false;
|
oGeneratedMissingIncludes = false;
|
||||||
oFailedOnMissingInclude = false;
|
oFailedOnMissingInclude = false;
|
||||||
tzTargetFileName = NULL;
|
tzTargetFileName = NULL;
|
||||||
|
uint32_t maxRecursionDepth = 64;
|
||||||
size_t nTargetFileNameLen = 0;
|
size_t nTargetFileNameLen = 0;
|
||||||
|
|
||||||
DefaultOptions.gbgfx[0] = '0';
|
DefaultOptions.gbgfx[0] = '0';
|
||||||
@@ -390,7 +390,7 @@ int main(int argc, char *argv[])
|
|||||||
|
|
||||||
break;
|
break;
|
||||||
case 'r':
|
case 'r':
|
||||||
nMaxRecursionDepth = strtoul(optarg, &ep, 0);
|
maxRecursionDepth = strtoul(optarg, &ep, 0);
|
||||||
|
|
||||||
if (optarg[0] == '\0' || *ep != '\0')
|
if (optarg[0] == '\0' || *ep != '\0')
|
||||||
errx(1, "Invalid argument for option 'r'");
|
errx(1, "Invalid argument for option 'r'");
|
||||||
@@ -483,13 +483,9 @@ int main(int argc, char *argv[])
|
|||||||
fprintf(dependfile, "%s: %s\n", tzTargetFileName, tzMainfile);
|
fprintf(dependfile, "%s: %s\n", tzTargetFileName, tzMainfile);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Init lexer; important to do first, since that's what provides the file name, line, etc */
|
/* Init file stack; important to do first, since it provides the file name, line, etc */
|
||||||
struct LexerState *state = lexer_OpenFile(tzMainfile);
|
|
||||||
|
|
||||||
if (!state)
|
|
||||||
fatalerror("Failed to open main file!\n");
|
|
||||||
lexer_Init();
|
lexer_Init();
|
||||||
lexer_SetState(state);
|
fstk_Init(tzMainfile, maxRecursionDepth);
|
||||||
|
|
||||||
nStartClock = clock();
|
nStartClock = clock();
|
||||||
|
|
||||||
@@ -497,7 +493,6 @@ int main(int argc, char *argv[])
|
|||||||
nIFDepth = 0;
|
nIFDepth = 0;
|
||||||
sym_Init();
|
sym_Init();
|
||||||
sym_SetExportAll(exportall);
|
sym_SetExportAll(exportall);
|
||||||
fstk_Init(tzMainfile);
|
|
||||||
|
|
||||||
opt_ParseDefines();
|
opt_ParseDefines();
|
||||||
charmap_New("main", NULL);
|
charmap_New("main", NULL);
|
||||||
|
|||||||
@@ -33,7 +33,7 @@
|
|||||||
#include "platform.h" // strdup
|
#include "platform.h" // strdup
|
||||||
|
|
||||||
struct Patch {
|
struct Patch {
|
||||||
char tzFilename[_MAX_PATH + 1];
|
char *tzFilename;
|
||||||
uint32_t nOffset;
|
uint32_t nOffset;
|
||||||
struct Section *pcSection;
|
struct Section *pcSection;
|
||||||
uint32_t pcOffset;
|
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));
|
fatalerror("No memory for patch's RPN expression: %s\n", strerror(errno));
|
||||||
|
|
||||||
patch->type = type;
|
patch->type = type;
|
||||||
fstk_DumpToStr(patch->tzFilename, sizeof(patch->tzFilename));
|
patch->tzFilename = fstk_DumpToStr();
|
||||||
patch->nOffset = ofs;
|
patch->nOffset = ofs;
|
||||||
patch->pcSection = sect_GetSymbolSection();
|
patch->pcSection = sect_GetSymbolSection();
|
||||||
patch->pcOffset = sect_GetSymbolOffset();
|
patch->pcOffset = sect_GetSymbolOffset();
|
||||||
|
|||||||
@@ -477,7 +477,7 @@ void sym_Export(char const *symName)
|
|||||||
/*
|
/*
|
||||||
* Add a macro definition
|
* 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);
|
struct Symbol *sym = createNonrelocSymbol(symName);
|
||||||
|
|
||||||
|
|||||||
1
test/asm/file-sym.asm
Normal file
1
test/asm/file-sym.asm
Normal file
@@ -0,0 +1 @@
|
|||||||
|
PRINTT "{__FILE__}\n"
|
||||||
0
test/asm/file-sym.err
Normal file
0
test/asm/file-sym.err
Normal file
1
test/asm/file-sym.out
Normal file
1
test/asm/file-sym.out
Normal file
@@ -0,0 +1 @@
|
|||||||
|
"test/asm/file-sym.asm"
|
||||||
Reference in New Issue
Block a user