mirror of
https://github.com/gbdev/rgbds.git
synced 2025-11-20 18:22:07 +00:00
Remove now-unnecessary struct keyword (#1320)
C++ acts like structs are `typedef`ed by default We do have to keep `struct stat`, since there's ambiguity with the function also called `stat`.
This commit is contained in:
@@ -35,13 +35,13 @@ struct StrFmtArgList {
|
|||||||
std::vector<std::variant<uint32_t, char *>> *args;
|
std::vector<std::variant<uint32_t, char *>> *args;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct FormatSpec fmt_NewSpec(void);
|
FormatSpec fmt_NewSpec(void);
|
||||||
bool fmt_IsEmpty(struct FormatSpec const *fmt);
|
bool fmt_IsEmpty(FormatSpec const *fmt);
|
||||||
bool fmt_IsValid(struct FormatSpec const *fmt);
|
bool fmt_IsValid(FormatSpec const *fmt);
|
||||||
bool fmt_IsFinished(struct FormatSpec const *fmt);
|
bool fmt_IsFinished(FormatSpec const *fmt);
|
||||||
void fmt_UseCharacter(struct FormatSpec *fmt, int c);
|
void fmt_UseCharacter(FormatSpec *fmt, int c);
|
||||||
void fmt_FinishCharacters(struct FormatSpec *fmt);
|
void fmt_FinishCharacters(FormatSpec *fmt);
|
||||||
void fmt_PrintString(char *buf, size_t bufLen, struct FormatSpec const *fmt, char const *value);
|
void fmt_PrintString(char *buf, size_t bufLen, FormatSpec const *fmt, char const *value);
|
||||||
void fmt_PrintNumber(char *buf, size_t bufLen, struct FormatSpec const *fmt, uint32_t value);
|
void fmt_PrintNumber(char *buf, size_t bufLen, FormatSpec const *fmt, uint32_t value);
|
||||||
|
|
||||||
#endif // RGBDS_FORMAT_SPEC_H
|
#endif // RGBDS_FORMAT_SPEC_H
|
||||||
|
|||||||
@@ -16,7 +16,7 @@
|
|||||||
#include "linkdefs.hpp"
|
#include "linkdefs.hpp"
|
||||||
|
|
||||||
struct FileStackNode {
|
struct FileStackNode {
|
||||||
struct FileStackNode *parent; // Pointer to parent node, for error reporting
|
FileStackNode *parent; // Pointer to parent node, for error reporting
|
||||||
// Line at which the parent context was exited; meaningless for the root level
|
// Line at which the parent context was exited; meaningless for the root level
|
||||||
uint32_t lineNo;
|
uint32_t lineNo;
|
||||||
|
|
||||||
@@ -43,9 +43,9 @@ extern size_t maxRecursionDepth;
|
|||||||
|
|
||||||
struct MacroArgs;
|
struct MacroArgs;
|
||||||
|
|
||||||
void fstk_Dump(struct FileStackNode const *node, uint32_t lineNo);
|
void fstk_Dump(FileStackNode const *node, uint32_t lineNo);
|
||||||
void fstk_DumpCurrent(void);
|
void fstk_DumpCurrent(void);
|
||||||
struct FileStackNode *fstk_GetFileStack(void);
|
FileStackNode *fstk_GetFileStack(void);
|
||||||
// The lifetime of the returned chars is until reaching the end of that file
|
// The lifetime of the returned chars is until reaching the end of that file
|
||||||
char const *fstk_GetFileName(void);
|
char const *fstk_GetFileName(void);
|
||||||
|
|
||||||
@@ -59,7 +59,7 @@ std::string *fstk_FindFile(char const *path);
|
|||||||
|
|
||||||
bool yywrap(void);
|
bool yywrap(void);
|
||||||
void fstk_RunInclude(char const *path);
|
void fstk_RunInclude(char const *path);
|
||||||
void fstk_RunMacro(char const *macroName, struct MacroArgs *args);
|
void fstk_RunMacro(char const *macroName, MacroArgs *args);
|
||||||
void fstk_RunRept(uint32_t count, int32_t reptLineNo, char *body, size_t size);
|
void fstk_RunRept(uint32_t count, int32_t reptLineNo, char *body, size_t size);
|
||||||
void fstk_RunFor(char const *symName, int32_t start, int32_t stop, int32_t step,
|
void fstk_RunFor(char const *symName, int32_t start, int32_t stop, int32_t step,
|
||||||
int32_t reptLineNo, char *body, size_t size);
|
int32_t reptLineNo, char *body, size_t size);
|
||||||
|
|||||||
@@ -60,8 +60,8 @@ struct LexerState {
|
|||||||
// mmap()-dependent IO state
|
// mmap()-dependent IO state
|
||||||
bool isMmapped;
|
bool isMmapped;
|
||||||
union {
|
union {
|
||||||
struct MmappedLexerState mmap; // If mmap()ed
|
MmappedLexerState mmap; // If mmap()ed
|
||||||
struct BufferedLexerState cbuf; // Otherwise
|
BufferedLexerState cbuf; // Otherwise
|
||||||
};
|
};
|
||||||
|
|
||||||
// Common state
|
// Common state
|
||||||
@@ -73,7 +73,7 @@ struct LexerState {
|
|||||||
uint32_t colNo;
|
uint32_t colNo;
|
||||||
int lastToken;
|
int lastToken;
|
||||||
|
|
||||||
std::deque<struct IfStackEntry> ifStack;
|
std::deque<IfStackEntry> ifStack;
|
||||||
|
|
||||||
bool capturing; // Whether the text being lexed should be captured
|
bool capturing; // Whether the text being lexed should be captured
|
||||||
size_t captureSize; // Amount of text captured
|
size_t captureSize; // Amount of text captured
|
||||||
@@ -84,18 +84,18 @@ struct LexerState {
|
|||||||
bool disableInterpolation;
|
bool disableInterpolation;
|
||||||
size_t macroArgScanDistance; // Max distance already scanned for macro args
|
size_t macroArgScanDistance; // Max distance already scanned for macro args
|
||||||
bool expandStrings;
|
bool expandStrings;
|
||||||
std::deque<struct Expansion> expansions; // Front is the innermost current expansion
|
std::deque<Expansion> expansions; // Front is the innermost current expansion
|
||||||
};
|
};
|
||||||
|
|
||||||
extern struct LexerState *lexerState;
|
extern LexerState *lexerState;
|
||||||
extern struct LexerState *lexerStateEOL;
|
extern LexerState *lexerStateEOL;
|
||||||
|
|
||||||
static inline void lexer_SetState(struct LexerState *state)
|
static inline void lexer_SetState(LexerState *state)
|
||||||
{
|
{
|
||||||
lexerState = state;
|
lexerState = state;
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline void lexer_SetStateAtEOL(struct LexerState *state)
|
static inline void lexer_SetStateAtEOL(LexerState *state)
|
||||||
{
|
{
|
||||||
lexerStateEOL = state;
|
lexerStateEOL = state;
|
||||||
}
|
}
|
||||||
@@ -118,11 +118,10 @@ static inline void lexer_SetGfxDigits(char const digits[4])
|
|||||||
}
|
}
|
||||||
|
|
||||||
// `path` is referenced, but not held onto..!
|
// `path` is referenced, but not held onto..!
|
||||||
bool lexer_OpenFile(struct LexerState &state, char const *path);
|
bool lexer_OpenFile(LexerState &state, char const *path);
|
||||||
void lexer_OpenFileView(struct LexerState &state, char const *path, char *buf, size_t size,
|
void lexer_OpenFileView(LexerState &state, char const *path, char *buf, size_t size, uint32_t lineNo);
|
||||||
uint32_t lineNo);
|
|
||||||
void lexer_RestartRept(uint32_t lineNo);
|
void lexer_RestartRept(uint32_t lineNo);
|
||||||
void lexer_CleanupState(struct LexerState &state);
|
void lexer_CleanupState(LexerState &state);
|
||||||
void lexer_Init(void);
|
void lexer_Init(void);
|
||||||
void lexer_SetMode(enum LexerMode mode);
|
void lexer_SetMode(enum LexerMode mode);
|
||||||
void lexer_ToggleStringExpansion(bool enable);
|
void lexer_ToggleStringExpansion(bool enable);
|
||||||
@@ -147,8 +146,8 @@ 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);
|
||||||
bool lexer_CaptureRept(struct CaptureBody *capture);
|
bool lexer_CaptureRept(CaptureBody *capture);
|
||||||
bool lexer_CaptureMacroBody(struct CaptureBody *capture);
|
bool lexer_CaptureMacroBody(CaptureBody *capture);
|
||||||
|
|
||||||
struct AlignmentSpec {
|
struct AlignmentSpec {
|
||||||
uint8_t alignment;
|
uint8_t alignment;
|
||||||
|
|||||||
@@ -12,11 +12,11 @@
|
|||||||
|
|
||||||
struct MacroArgs;
|
struct MacroArgs;
|
||||||
|
|
||||||
struct MacroArgs *macro_GetCurrentArgs(void);
|
MacroArgs *macro_GetCurrentArgs(void);
|
||||||
struct MacroArgs *macro_NewArgs(void);
|
MacroArgs *macro_NewArgs(void);
|
||||||
void macro_AppendArg(struct MacroArgs *args, char *s);
|
void macro_AppendArg(MacroArgs *args, char *s);
|
||||||
void macro_UseNewArgs(struct MacroArgs *args);
|
void macro_UseNewArgs(MacroArgs *args);
|
||||||
void macro_FreeArgs(struct MacroArgs *args);
|
void macro_FreeArgs(MacroArgs *args);
|
||||||
char const *macro_GetArg(uint32_t i);
|
char const *macro_GetArg(uint32_t i);
|
||||||
char const *macro_GetAllArgs(void);
|
char const *macro_GetAllArgs(void);
|
||||||
|
|
||||||
|
|||||||
@@ -12,12 +12,11 @@ struct FileStackNode;
|
|||||||
|
|
||||||
extern const char *objectName;
|
extern const char *objectName;
|
||||||
|
|
||||||
void out_RegisterNode(struct FileStackNode *node);
|
void out_RegisterNode(FileStackNode *node);
|
||||||
void out_ReplaceNode(struct FileStackNode *node);
|
void out_ReplaceNode(FileStackNode *node);
|
||||||
void out_SetFileName(char *s);
|
void out_SetFileName(char *s);
|
||||||
void out_CreatePatch(uint32_t type, struct Expression const *expr, uint32_t ofs, uint32_t pcShift);
|
void out_CreatePatch(uint32_t type, Expression const *expr, uint32_t ofs, uint32_t pcShift);
|
||||||
void out_CreateAssert(enum AssertionType type, struct Expression const *expr,
|
void out_CreateAssert(enum AssertionType type, Expression const *expr, char const *message, uint32_t ofs);
|
||||||
char const *message, uint32_t ofs);
|
|
||||||
void out_WriteObject(void);
|
void out_WriteObject(void);
|
||||||
|
|
||||||
#endif // RGBDS_ASM_OUTPUT_H
|
#endif // RGBDS_ASM_OUTPUT_H
|
||||||
|
|||||||
@@ -8,6 +8,8 @@
|
|||||||
|
|
||||||
#include "linkdefs.hpp"
|
#include "linkdefs.hpp"
|
||||||
|
|
||||||
|
struct Symbol;
|
||||||
|
|
||||||
struct Expression {
|
struct Expression {
|
||||||
int32_t val; // If the expression's value is known, it's here
|
int32_t val; // If the expression's value is known, it's here
|
||||||
std::string *reason; // Why the expression is not known, if it isn't
|
std::string *reason; // Why the expression is not known, if it isn't
|
||||||
@@ -18,41 +20,39 @@ struct Expression {
|
|||||||
};
|
};
|
||||||
|
|
||||||
// Determines if an expression is known at assembly time
|
// Determines if an expression is known at assembly time
|
||||||
static inline bool rpn_isKnown(struct Expression const *expr)
|
static inline bool rpn_isKnown(Expression const *expr)
|
||||||
{
|
{
|
||||||
return expr->isKnown;
|
return expr->isKnown;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Determines if an expression is a symbol suitable for const diffing
|
// Determines if an expression is a symbol suitable for const diffing
|
||||||
static inline bool rpn_isSymbol(const struct Expression *expr)
|
static inline bool rpn_isSymbol(const Expression *expr)
|
||||||
{
|
{
|
||||||
return expr->isSymbol;
|
return expr->isSymbol;
|
||||||
}
|
}
|
||||||
|
|
||||||
void rpn_Symbol(struct Expression *expr, char const *symName);
|
void rpn_Symbol(Expression *expr, char const *symName);
|
||||||
void rpn_Number(struct Expression *expr, uint32_t i);
|
void rpn_Number(Expression *expr, uint32_t i);
|
||||||
void rpn_LOGNOT(struct Expression *expr, const struct Expression *src);
|
void rpn_LOGNOT(Expression *expr, const Expression *src);
|
||||||
struct Symbol const *rpn_SymbolOf(struct Expression const *expr);
|
Symbol const *rpn_SymbolOf(Expression const *expr);
|
||||||
bool rpn_IsDiffConstant(struct Expression const *src, struct Symbol const *symName);
|
bool rpn_IsDiffConstant(Expression const *src, Symbol const *symName);
|
||||||
void rpn_BinaryOp(enum RPNCommand op, struct Expression *expr,
|
void rpn_BinaryOp(enum RPNCommand op, Expression *expr, const Expression *src1, const Expression *src2);
|
||||||
const struct Expression *src1,
|
void rpn_HIGH(Expression *expr, const Expression *src);
|
||||||
const struct Expression *src2);
|
void rpn_LOW(Expression *expr, const Expression *src);
|
||||||
void rpn_HIGH(struct Expression *expr, const struct Expression *src);
|
void rpn_ISCONST(Expression *expr, const Expression *src);
|
||||||
void rpn_LOW(struct Expression *expr, const struct Expression *src);
|
void rpn_NEG(Expression *expr, const Expression *src);
|
||||||
void rpn_ISCONST(struct Expression *expr, const struct Expression *src);
|
void rpn_NOT(Expression *expr, const Expression *src);
|
||||||
void rpn_NEG(struct Expression *expr, const struct Expression *src);
|
void rpn_BankSymbol(Expression *expr, char const *symName);
|
||||||
void rpn_NOT(struct Expression *expr, const struct Expression *src);
|
void rpn_BankSection(Expression *expr, char const *sectionName);
|
||||||
void rpn_BankSymbol(struct Expression *expr, char const *symName);
|
void rpn_BankSelf(Expression *expr);
|
||||||
void rpn_BankSection(struct Expression *expr, char const *sectionName);
|
void rpn_SizeOfSection(Expression *expr, char const *sectionName);
|
||||||
void rpn_BankSelf(struct Expression *expr);
|
void rpn_StartOfSection(Expression *expr, char const *sectionName);
|
||||||
void rpn_SizeOfSection(struct Expression *expr, char const *sectionName);
|
void rpn_SizeOfSectionType(Expression *expr, enum SectionType type);
|
||||||
void rpn_StartOfSection(struct Expression *expr, char const *sectionName);
|
void rpn_StartOfSectionType(Expression *expr, enum SectionType type);
|
||||||
void rpn_SizeOfSectionType(struct Expression *expr, enum SectionType type);
|
void rpn_Free(Expression *expr);
|
||||||
void rpn_StartOfSectionType(struct Expression *expr, enum SectionType type);
|
void rpn_CheckHRAM(Expression *expr, const Expression *src);
|
||||||
void rpn_Free(struct Expression *expr);
|
void rpn_CheckRST(Expression *expr, const Expression *src);
|
||||||
void rpn_CheckHRAM(struct Expression *expr, const struct Expression *src);
|
void rpn_CheckNBit(Expression const *expr, uint8_t n);
|
||||||
void rpn_CheckRST(struct Expression *expr, const struct Expression *src);
|
int32_t rpn_GetConstVal(Expression const *expr);
|
||||||
void rpn_CheckNBit(struct Expression const *expr, uint8_t n);
|
|
||||||
int32_t rpn_GetConstVal(struct Expression const *expr);
|
|
||||||
|
|
||||||
#endif // RGBDS_ASM_RPN_H
|
#endif // RGBDS_ASM_RPN_H
|
||||||
|
|||||||
@@ -17,10 +17,10 @@ struct FileStackNode;
|
|||||||
struct Section;
|
struct Section;
|
||||||
|
|
||||||
struct Patch {
|
struct Patch {
|
||||||
struct FileStackNode const *src;
|
FileStackNode const *src;
|
||||||
uint32_t lineNo;
|
uint32_t lineNo;
|
||||||
uint32_t offset;
|
uint32_t offset;
|
||||||
struct Section *pcSection;
|
Section *pcSection;
|
||||||
uint32_t pcOffset;
|
uint32_t pcOffset;
|
||||||
uint8_t type;
|
uint8_t type;
|
||||||
std::vector<uint8_t> rpn;
|
std::vector<uint8_t> rpn;
|
||||||
@@ -30,14 +30,14 @@ struct Section {
|
|||||||
char *name;
|
char *name;
|
||||||
enum SectionType type;
|
enum SectionType type;
|
||||||
enum SectionModifier modifier;
|
enum SectionModifier modifier;
|
||||||
struct FileStackNode const *src; // Where the section was defined
|
FileStackNode const *src; // Where the section was defined
|
||||||
uint32_t fileLine; // Line where the section was defined
|
uint32_t fileLine; // Line where the section was defined
|
||||||
uint32_t size;
|
uint32_t size;
|
||||||
uint32_t org;
|
uint32_t org;
|
||||||
uint32_t bank;
|
uint32_t bank;
|
||||||
uint8_t align; // Exactly as specified in `ALIGN[]`
|
uint8_t align; // Exactly as specified in `ALIGN[]`
|
||||||
uint16_t alignOfs;
|
uint16_t alignOfs;
|
||||||
std::deque<struct Patch> patches;
|
std::deque<Patch> patches;
|
||||||
std::vector<uint8_t> data;
|
std::vector<uint8_t> data;
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -47,17 +47,17 @@ struct SectionSpec {
|
|||||||
uint16_t alignOfs;
|
uint16_t alignOfs;
|
||||||
};
|
};
|
||||||
|
|
||||||
extern std::deque<struct Section> sectionList;
|
extern std::deque<Section> sectionList;
|
||||||
extern struct Section *currentSection;
|
extern Section *currentSection;
|
||||||
|
|
||||||
struct Section *sect_FindSectionByName(char const *name);
|
Section *sect_FindSectionByName(char const *name);
|
||||||
void sect_NewSection(char const *name, enum SectionType type, uint32_t org,
|
void sect_NewSection(char const *name, enum SectionType type, uint32_t org,
|
||||||
struct SectionSpec const *attributes, enum SectionModifier mod);
|
SectionSpec const *attributes, enum SectionModifier mod);
|
||||||
void sect_SetLoadSection(char const *name, enum SectionType type, uint32_t org,
|
void sect_SetLoadSection(char const *name, enum SectionType type, uint32_t org,
|
||||||
struct SectionSpec const *attributes, enum SectionModifier mod);
|
SectionSpec const *attributes, enum SectionModifier mod);
|
||||||
void sect_EndLoadSection(void);
|
void sect_EndLoadSection(void);
|
||||||
|
|
||||||
struct Section *sect_GetSymbolSection(void);
|
Section *sect_GetSymbolSection(void);
|
||||||
uint32_t sect_GetSymbolOffset(void);
|
uint32_t sect_GetSymbolOffset(void);
|
||||||
uint32_t sect_GetOutputOffset(void);
|
uint32_t sect_GetOutputOffset(void);
|
||||||
uint32_t sect_GetAlignBytes(uint8_t alignment, uint16_t offset);
|
uint32_t sect_GetAlignBytes(uint8_t alignment, uint16_t offset);
|
||||||
@@ -73,11 +73,11 @@ void sect_AbsByteGroup(uint8_t const *s, size_t length);
|
|||||||
void sect_AbsWordGroup(uint8_t const *s, size_t length);
|
void sect_AbsWordGroup(uint8_t const *s, size_t length);
|
||||||
void sect_AbsLongGroup(uint8_t const *s, size_t length);
|
void sect_AbsLongGroup(uint8_t const *s, size_t length);
|
||||||
void sect_Skip(uint32_t skip, bool ds);
|
void sect_Skip(uint32_t skip, bool ds);
|
||||||
void sect_RelByte(struct Expression *expr, uint32_t pcShift);
|
void sect_RelByte(Expression *expr, uint32_t pcShift);
|
||||||
void sect_RelBytes(uint32_t n, std::vector<struct Expression> &exprs);
|
void sect_RelBytes(uint32_t n, std::vector<Expression> &exprs);
|
||||||
void sect_RelWord(struct Expression *expr, uint32_t pcShift);
|
void sect_RelWord(Expression *expr, uint32_t pcShift);
|
||||||
void sect_RelLong(struct Expression *expr, uint32_t pcShift);
|
void sect_RelLong(Expression *expr, uint32_t pcShift);
|
||||||
void sect_PCRelByte(struct Expression *expr, uint32_t pcShift);
|
void sect_PCRelByte(Expression *expr, uint32_t pcShift);
|
||||||
void sect_BinaryFile(char const *s, int32_t startPos);
|
void sect_BinaryFile(char const *s, int32_t startPos);
|
||||||
void sect_BinaryFileSlice(char const *s, int32_t start_pos, int32_t length);
|
void sect_BinaryFileSlice(char const *s, int32_t start_pos, int32_t length);
|
||||||
|
|
||||||
@@ -85,6 +85,6 @@ void sect_EndSection(void);
|
|||||||
void sect_PushSection(void);
|
void sect_PushSection(void);
|
||||||
void sect_PopSection(void);
|
void sect_PopSection(void);
|
||||||
|
|
||||||
bool sect_IsSizeKnown(struct Section const NONNULL(name));
|
bool sect_IsSizeKnown(Section const NONNULL(name));
|
||||||
|
|
||||||
#endif // RGBDS_SECTION_H
|
#endif // RGBDS_SECTION_H
|
||||||
|
|||||||
@@ -23,7 +23,7 @@ enum SymbolType {
|
|||||||
SYM_REF // Forward reference to a label
|
SYM_REF // Forward reference to a label
|
||||||
};
|
};
|
||||||
|
|
||||||
// Only used in an anonymous union by `struct Symbol`
|
// Only used in an anonymous union by `Symbol`
|
||||||
struct strValue {
|
struct strValue {
|
||||||
size_t size;
|
size_t size;
|
||||||
char *value;
|
char *value;
|
||||||
@@ -34,8 +34,8 @@ struct Symbol {
|
|||||||
enum SymbolType type;
|
enum SymbolType type;
|
||||||
bool isExported; // Whether the symbol is to be exported
|
bool isExported; // Whether the symbol is to be exported
|
||||||
bool isBuiltin; // Whether the symbol is a built-in
|
bool isBuiltin; // Whether the symbol is a built-in
|
||||||
struct Section *section;
|
Section *section;
|
||||||
struct FileStackNode *src; // Where the symbol was defined
|
FileStackNode *src; // Where the symbol was defined
|
||||||
uint32_t fileLine; // Line where the symbol was defined
|
uint32_t fileLine; // Line where the symbol was defined
|
||||||
|
|
||||||
bool hasCallback;
|
bool hasCallback;
|
||||||
@@ -44,91 +44,91 @@ struct Symbol {
|
|||||||
int32_t value;
|
int32_t value;
|
||||||
int32_t (*numCallback)(void); // If hasCallback
|
int32_t (*numCallback)(void); // If hasCallback
|
||||||
// For SYM_MACRO
|
// For SYM_MACRO
|
||||||
struct strValue macro;
|
strValue macro;
|
||||||
// For SYM_EQUS
|
// For SYM_EQUS
|
||||||
struct strValue equs;
|
strValue equs;
|
||||||
char const *(*strCallback)(void); // If hasCallback
|
char const *(*strCallback)(void); // If hasCallback
|
||||||
};
|
};
|
||||||
|
|
||||||
uint32_t ID; // ID of the symbol in the object file (-1 if none)
|
uint32_t ID; // ID of the symbol in the object file (-1 if none)
|
||||||
};
|
};
|
||||||
|
|
||||||
bool sym_IsPC(struct Symbol const *sym);
|
bool sym_IsPC(Symbol const *sym);
|
||||||
|
|
||||||
static inline bool sym_IsDefined(struct Symbol const *sym)
|
static inline bool sym_IsDefined(Symbol const *sym)
|
||||||
{
|
{
|
||||||
return sym->type != SYM_REF;
|
return sym->type != SYM_REF;
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline struct Section *sym_GetSection(struct Symbol const *sym)
|
static inline Section *sym_GetSection(Symbol const *sym)
|
||||||
{
|
{
|
||||||
return sym_IsPC(sym) ? sect_GetSymbolSection() : sym->section;
|
return sym_IsPC(sym) ? sect_GetSymbolSection() : sym->section;
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline bool sym_IsConstant(struct Symbol const *sym)
|
static inline bool sym_IsConstant(Symbol const *sym)
|
||||||
{
|
{
|
||||||
if (sym->type == SYM_LABEL) {
|
if (sym->type == SYM_LABEL) {
|
||||||
struct Section const *sect = sym_GetSection(sym);
|
Section const *sect = sym_GetSection(sym);
|
||||||
|
|
||||||
return sect && sect->org != (uint32_t)-1;
|
return sect && sect->org != (uint32_t)-1;
|
||||||
}
|
}
|
||||||
return sym->type == SYM_EQU || sym->type == SYM_VAR;
|
return sym->type == SYM_EQU || sym->type == SYM_VAR;
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline bool sym_IsNumeric(struct Symbol const *sym)
|
static inline bool sym_IsNumeric(Symbol const *sym)
|
||||||
{
|
{
|
||||||
return sym->type == SYM_LABEL || sym->type == SYM_EQU || sym->type == SYM_VAR;
|
return sym->type == SYM_LABEL || sym->type == SYM_EQU || sym->type == SYM_VAR;
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline bool sym_IsLabel(struct Symbol const *sym)
|
static inline bool sym_IsLabel(Symbol const *sym)
|
||||||
{
|
{
|
||||||
return sym->type == SYM_LABEL || sym->type == SYM_REF;
|
return sym->type == SYM_LABEL || sym->type == SYM_REF;
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline bool sym_IsLocal(struct Symbol const *sym)
|
static inline bool sym_IsLocal(Symbol const *sym)
|
||||||
{
|
{
|
||||||
return sym_IsLabel(sym) && strchr(sym->name, '.');
|
return sym_IsLabel(sym) && strchr(sym->name, '.');
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline bool sym_IsExported(struct Symbol const *sym)
|
static inline bool sym_IsExported(Symbol const *sym)
|
||||||
{
|
{
|
||||||
return sym->isExported;
|
return sym->isExported;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Get a string equate's value
|
// Get a string equate's value
|
||||||
static inline char const *sym_GetStringValue(struct Symbol const *sym)
|
static inline char const *sym_GetStringValue(Symbol const *sym)
|
||||||
{
|
{
|
||||||
if (sym->hasCallback)
|
if (sym->hasCallback)
|
||||||
return sym->strCallback();
|
return sym->strCallback();
|
||||||
return sym->equs.value;
|
return sym->equs.value;
|
||||||
}
|
}
|
||||||
|
|
||||||
void sym_ForEach(void (*func)(struct Symbol *));
|
void sym_ForEach(void (*func)(Symbol *));
|
||||||
|
|
||||||
int32_t sym_GetValue(struct Symbol const *sym);
|
int32_t sym_GetValue(Symbol const *sym);
|
||||||
void sym_SetExportAll(bool set);
|
void sym_SetExportAll(bool set);
|
||||||
struct Symbol *sym_AddLocalLabel(char const *symName);
|
Symbol *sym_AddLocalLabel(char const *symName);
|
||||||
struct Symbol *sym_AddLabel(char const *symName);
|
Symbol *sym_AddLabel(char const *symName);
|
||||||
struct Symbol *sym_AddAnonLabel(void);
|
Symbol *sym_AddAnonLabel(void);
|
||||||
void sym_WriteAnonLabelName(char buf[MIN_NB_ELMS(MAXSYMLEN + 1)], uint32_t ofs, bool neg);
|
void sym_WriteAnonLabelName(char buf[MIN_NB_ELMS(MAXSYMLEN + 1)], uint32_t ofs, bool neg);
|
||||||
void sym_Export(char const *symName);
|
void sym_Export(char const *symName);
|
||||||
struct Symbol *sym_AddEqu(char const *symName, int32_t value);
|
Symbol *sym_AddEqu(char const *symName, int32_t value);
|
||||||
struct Symbol *sym_RedefEqu(char const *symName, int32_t value);
|
Symbol *sym_RedefEqu(char const *symName, int32_t value);
|
||||||
struct Symbol *sym_AddVar(char const *symName, int32_t value);
|
Symbol *sym_AddVar(char const *symName, int32_t value);
|
||||||
uint32_t sym_GetPCValue(void);
|
uint32_t sym_GetPCValue(void);
|
||||||
uint32_t sym_GetConstantSymValue(struct Symbol const *sym);
|
uint32_t sym_GetConstantSymValue(Symbol const *sym);
|
||||||
uint32_t sym_GetConstantValue(char const *symName);
|
uint32_t sym_GetConstantValue(char const *symName);
|
||||||
// Find a symbol by exact name, bypassing expansion checks
|
// Find a symbol by exact name, bypassing expansion checks
|
||||||
struct Symbol *sym_FindExactSymbol(char const *symName);
|
Symbol *sym_FindExactSymbol(char const *symName);
|
||||||
// Find a symbol, possibly scoped, by name
|
// Find a symbol, possibly scoped, by name
|
||||||
struct Symbol *sym_FindScopedSymbol(char const *symName);
|
Symbol *sym_FindScopedSymbol(char const *symName);
|
||||||
// Find a scoped symbol by name; do not return `@` or `_NARG` when they have no value
|
// Find a scoped symbol by name; do not return `@` or `_NARG` when they have no value
|
||||||
struct Symbol *sym_FindScopedValidSymbol(char const *symName);
|
Symbol *sym_FindScopedValidSymbol(char const *symName);
|
||||||
struct Symbol const *sym_GetPC(void);
|
Symbol const *sym_GetPC(void);
|
||||||
struct Symbol *sym_AddMacro(char const *symName, int32_t defLineNo, char *body, size_t size);
|
Symbol *sym_AddMacro(char const *symName, int32_t defLineNo, char *body, size_t size);
|
||||||
struct Symbol *sym_Ref(char const *symName);
|
Symbol *sym_Ref(char const *symName);
|
||||||
struct Symbol *sym_AddString(char const *symName, char const *value);
|
Symbol *sym_AddString(char const *symName, char const *value);
|
||||||
struct Symbol *sym_RedefString(char const *symName, char const *value);
|
Symbol *sym_RedefString(char const *symName, char const *value);
|
||||||
void sym_Purge(std::string const &symName);
|
void sym_Purge(std::string const &symName);
|
||||||
void sym_Init(time_t now);
|
void sym_Init(time_t now);
|
||||||
|
|
||||||
|
|||||||
2
include/extern/getopt.hpp
vendored
2
include/extern/getopt.hpp
vendored
@@ -18,7 +18,7 @@ struct option {
|
|||||||
};
|
};
|
||||||
|
|
||||||
int musl_getopt_long_only(int argc, char **argv, char const *optstring,
|
int musl_getopt_long_only(int argc, char **argv, char const *optstring,
|
||||||
const struct option *longopts, int *idx);
|
const option *longopts, int *idx);
|
||||||
|
|
||||||
#define no_argument 0
|
#define no_argument 0
|
||||||
#define required_argument 1
|
#define required_argument 1
|
||||||
|
|||||||
@@ -31,7 +31,7 @@ extern bool isWRAM0Mode;
|
|||||||
extern bool disablePadding;
|
extern bool disablePadding;
|
||||||
|
|
||||||
struct FileStackNode {
|
struct FileStackNode {
|
||||||
struct FileStackNode *parent;
|
FileStackNode *parent;
|
||||||
// Line at which the parent context was exited; meaningless for the root level
|
// Line at which the parent context was exited; meaningless for the root level
|
||||||
uint32_t lineNo;
|
uint32_t lineNo;
|
||||||
|
|
||||||
@@ -60,15 +60,12 @@ struct FileStackNode {
|
|||||||
* Dump a file stack to stderr
|
* Dump a file stack to stderr
|
||||||
* @param node The leaf node to dump the context of
|
* @param node The leaf node to dump the context of
|
||||||
*/
|
*/
|
||||||
std::string const *dumpFileStack(struct FileStackNode const *node);
|
std::string const *dumpFileStack(FileStackNode const *node);
|
||||||
|
|
||||||
void warning(struct FileStackNode const *where, uint32_t lineNo,
|
void warning(FileStackNode const *where, uint32_t lineNo, char const *fmt, ...) format_(printf, 3, 4);
|
||||||
char const *fmt, ...) format_(printf, 3, 4);
|
|
||||||
|
|
||||||
void error(struct FileStackNode const *where, uint32_t lineNo,
|
void error(FileStackNode const *where, uint32_t lineNo, char const *fmt, ...) format_(printf, 3, 4);
|
||||||
char const *fmt, ...) format_(printf, 3, 4);
|
|
||||||
|
|
||||||
[[noreturn]] void fatal(struct FileStackNode const *where, uint32_t lineNo,
|
[[noreturn]] void fatal(FileStackNode const *where, uint32_t lineNo, char const *fmt, ...) format_(printf, 3, 4);
|
||||||
char const *fmt, ...) format_(printf, 3, 4);
|
|
||||||
|
|
||||||
#endif // RGBDS_LINK_MAIN_H
|
#endif // RGBDS_LINK_MAIN_H
|
||||||
|
|||||||
@@ -12,14 +12,14 @@
|
|||||||
* Registers a section for output.
|
* Registers a section for output.
|
||||||
* @param section The section to add
|
* @param section The section to add
|
||||||
*/
|
*/
|
||||||
void out_AddSection(struct Section const *section);
|
void out_AddSection(Section const *section);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Finds an assigned section overlapping another one.
|
* Finds an assigned section overlapping another one.
|
||||||
* @param section The section that is being overlapped
|
* @param section The section that is being overlapped
|
||||||
* @return A section overlapping it
|
* @return A section overlapping it
|
||||||
*/
|
*/
|
||||||
struct Section const *out_OverlappingSection(struct Section const *section);
|
Section const *out_OverlappingSection(Section const *section);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Writes all output (bin, sym, map) files.
|
* Writes all output (bin, sym, map) files.
|
||||||
|
|||||||
@@ -13,17 +13,17 @@
|
|||||||
#include "linkdefs.hpp"
|
#include "linkdefs.hpp"
|
||||||
|
|
||||||
struct Assertion {
|
struct Assertion {
|
||||||
struct Patch patch; // Also used for its `.type`
|
Patch patch; // Also used for its `.type`
|
||||||
std::string message;
|
std::string message;
|
||||||
// This would be redundant with `.section->fileSymbols`... but `section` is sometimes NULL!
|
// This would be redundant with `.section->fileSymbols`... but `section` is sometimes NULL!
|
||||||
std::vector<struct Symbol> *fileSymbols;
|
std::vector<Symbol> *fileSymbols;
|
||||||
};
|
};
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Checks all assertions
|
* Checks all assertions
|
||||||
* @return true if assertion failed
|
* @return true if assertion failed
|
||||||
*/
|
*/
|
||||||
void patch_CheckAssertions(std::deque<struct Assertion> &assertions);
|
void patch_CheckAssertions(std::deque<Assertion> &assertions);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Applies all SECTIONs' patches to them
|
* Applies all SECTIONs' patches to them
|
||||||
|
|||||||
@@ -10,6 +10,6 @@
|
|||||||
struct FileStackNode;
|
struct FileStackNode;
|
||||||
struct Symbol;
|
struct Symbol;
|
||||||
|
|
||||||
void sdobj_ReadFile(struct FileStackNode const *fileName, FILE *file, std::vector<struct Symbol> &fileSymbols);
|
void sdobj_ReadFile(FileStackNode const *fileName, FILE *file, std::vector<Symbol> &fileSymbols);
|
||||||
|
|
||||||
#endif // RGBDS_LINK_SDAS_OBJ_H
|
#endif // RGBDS_LINK_SDAS_OBJ_H
|
||||||
|
|||||||
@@ -16,12 +16,13 @@
|
|||||||
|
|
||||||
struct FileStackNode;
|
struct FileStackNode;
|
||||||
struct Section;
|
struct Section;
|
||||||
|
struct Symbol;
|
||||||
|
|
||||||
struct Patch {
|
struct Patch {
|
||||||
struct FileStackNode const *src;
|
FileStackNode const *src;
|
||||||
uint32_t lineNo;
|
uint32_t lineNo;
|
||||||
uint32_t offset;
|
uint32_t offset;
|
||||||
struct Section const *pcSection;
|
Section const *pcSection;
|
||||||
uint32_t pcSectionID;
|
uint32_t pcSectionID;
|
||||||
uint32_t pcOffset;
|
uint32_t pcOffset;
|
||||||
enum PatchType type;
|
enum PatchType type;
|
||||||
@@ -45,11 +46,11 @@ struct Section {
|
|||||||
uint16_t alignMask;
|
uint16_t alignMask;
|
||||||
uint16_t alignOfs;
|
uint16_t alignOfs;
|
||||||
std::vector<uint8_t> data; // Array of size `size`, or 0 if `type` does not have data
|
std::vector<uint8_t> data; // Array of size `size`, or 0 if `type` does not have data
|
||||||
std::vector<struct Patch> patches;
|
std::vector<Patch> patches;
|
||||||
// Extra info computed during linking
|
// Extra info computed during linking
|
||||||
std::vector<struct Symbol> *fileSymbols;
|
std::vector<Symbol> *fileSymbols;
|
||||||
std::vector<struct Symbol *> symbols;
|
std::vector<Symbol *> symbols;
|
||||||
struct Section *nextu; // The next "component" of this unionized sect
|
Section *nextu; // The next "component" of this unionized sect
|
||||||
};
|
};
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@@ -57,20 +58,20 @@ struct Section {
|
|||||||
* This is to avoid exposing the data structure in which sections are stored.
|
* This is to avoid exposing the data structure in which sections are stored.
|
||||||
* @param callback The function to call for each structure.
|
* @param callback The function to call for each structure.
|
||||||
*/
|
*/
|
||||||
void sect_ForEach(void (*callback)(struct Section *));
|
void sect_ForEach(void (*callback)(Section *));
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Registers a section to be processed.
|
* Registers a section to be processed.
|
||||||
* @param section The section to register.
|
* @param section The section to register.
|
||||||
*/
|
*/
|
||||||
void sect_AddSection(struct Section *section);
|
void sect_AddSection(Section *section);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Finds a section by its name.
|
* Finds a section by its name.
|
||||||
* @param name The name of the section to look for
|
* @param name The name of the section to look for
|
||||||
* @return A pointer to the section, or NULL if it wasn't found
|
* @return A pointer to the section, or NULL if it wasn't found
|
||||||
*/
|
*/
|
||||||
struct Section *sect_GetSection(std::string const &name);
|
Section *sect_GetSection(std::string const &name);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Checks if all sections meet reasonable criteria, such as max size
|
* Checks if all sections meet reasonable criteria, such as max size
|
||||||
|
|||||||
@@ -12,13 +12,14 @@
|
|||||||
#include "linkdefs.hpp"
|
#include "linkdefs.hpp"
|
||||||
|
|
||||||
struct FileStackNode;
|
struct FileStackNode;
|
||||||
|
struct Section;
|
||||||
|
|
||||||
struct Symbol {
|
struct Symbol {
|
||||||
// Info contained in the object files
|
// Info contained in the object files
|
||||||
std::string name;
|
std::string name;
|
||||||
enum ExportLevel type;
|
enum ExportLevel type;
|
||||||
char const *objFileName;
|
char const *objFileName;
|
||||||
struct FileStackNode const *src;
|
FileStackNode const *src;
|
||||||
int32_t lineNo;
|
int32_t lineNo;
|
||||||
int32_t sectionID;
|
int32_t sectionID;
|
||||||
union {
|
union {
|
||||||
@@ -27,16 +28,16 @@ struct Symbol {
|
|||||||
int32_t value;
|
int32_t value;
|
||||||
};
|
};
|
||||||
// Extra info computed during linking
|
// Extra info computed during linking
|
||||||
struct Section *section;
|
Section *section;
|
||||||
};
|
};
|
||||||
|
|
||||||
void sym_AddSymbol(struct Symbol *symbol);
|
void sym_AddSymbol(Symbol *symbol);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Finds a symbol in all the defined symbols.
|
* Finds a symbol in all the defined symbols.
|
||||||
* @param name The name of the symbol to look for
|
* @param name The name of the symbol to look for
|
||||||
* @return A pointer to the symbol, or NULL if not found.
|
* @return A pointer to the symbol, or NULL if not found.
|
||||||
*/
|
*/
|
||||||
struct Symbol *sym_GetSymbol(std::string const &name);
|
Symbol *sym_GetSymbol(std::string const &name);
|
||||||
|
|
||||||
#endif // RGBDS_LINK_SYMBOL_H
|
#endif // RGBDS_LINK_SYMBOL_H
|
||||||
|
|||||||
@@ -30,17 +30,17 @@ struct CharmapNode {
|
|||||||
|
|
||||||
struct Charmap {
|
struct Charmap {
|
||||||
std::string name;
|
std::string name;
|
||||||
std::vector<struct CharmapNode> nodes; // first node is reserved for the root node
|
std::vector<CharmapNode> nodes; // first node is reserved for the root node
|
||||||
};
|
};
|
||||||
|
|
||||||
static std::map<std::string, struct Charmap> charmaps;
|
static std::map<std::string, Charmap> charmaps;
|
||||||
|
|
||||||
static struct Charmap *currentCharmap;
|
static Charmap *currentCharmap;
|
||||||
std::stack<struct Charmap *> charmapStack;
|
std::stack<Charmap *> charmapStack;
|
||||||
|
|
||||||
void charmap_New(char const *name, char const *baseName)
|
void charmap_New(char const *name, char const *baseName)
|
||||||
{
|
{
|
||||||
struct Charmap *base = NULL;
|
Charmap *base = NULL;
|
||||||
|
|
||||||
if (baseName != NULL) {
|
if (baseName != NULL) {
|
||||||
auto search = charmaps.find(baseName);
|
auto search = charmaps.find(baseName);
|
||||||
@@ -57,7 +57,7 @@ void charmap_New(char const *name, char const *baseName)
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Init the new charmap's fields
|
// Init the new charmap's fields
|
||||||
struct Charmap &charmap = charmaps[name];
|
Charmap &charmap = charmaps[name];
|
||||||
|
|
||||||
if (base)
|
if (base)
|
||||||
charmap.nodes = base->nodes; // Copies `base->nodes`
|
charmap.nodes = base->nodes; // Copies `base->nodes`
|
||||||
@@ -96,7 +96,7 @@ void charmap_Pop(void)
|
|||||||
|
|
||||||
void charmap_Add(char *mapping, uint8_t value)
|
void charmap_Add(char *mapping, uint8_t value)
|
||||||
{
|
{
|
||||||
struct Charmap &charmap = *currentCharmap;
|
Charmap &charmap = *currentCharmap;
|
||||||
size_t nodeIdx = 0;
|
size_t nodeIdx = 0;
|
||||||
|
|
||||||
for (; *mapping; mapping++) {
|
for (; *mapping; mapping++) {
|
||||||
@@ -115,7 +115,7 @@ void charmap_Add(char *mapping, uint8_t value)
|
|||||||
nodeIdx = nextIdx;
|
nodeIdx = nextIdx;
|
||||||
}
|
}
|
||||||
|
|
||||||
struct CharmapNode &node = charmap.nodes[nodeIdx];
|
CharmapNode &node = charmap.nodes[nodeIdx];
|
||||||
|
|
||||||
if (node.isTerminal)
|
if (node.isTerminal)
|
||||||
warning(WARNING_CHARMAP_REDEF, "Overriding charmap mapping\n");
|
warning(WARNING_CHARMAP_REDEF, "Overriding charmap mapping\n");
|
||||||
@@ -126,7 +126,7 @@ void charmap_Add(char *mapping, uint8_t value)
|
|||||||
|
|
||||||
bool charmap_HasChar(char const *input)
|
bool charmap_HasChar(char const *input)
|
||||||
{
|
{
|
||||||
struct Charmap const &charmap = *currentCharmap;
|
Charmap const &charmap = *currentCharmap;
|
||||||
size_t nodeIdx = 0;
|
size_t nodeIdx = 0;
|
||||||
|
|
||||||
for (; *input; input++) {
|
for (; *input; input++) {
|
||||||
@@ -151,7 +151,7 @@ size_t charmap_ConvertNext(char const **input, std::vector<uint8_t> *output)
|
|||||||
// For that, advance through the trie with each character read.
|
// For that, advance through the trie with each character read.
|
||||||
// If that would lead to a dead end, rewind characters until the last match, and output.
|
// If that would lead to a dead end, rewind characters until the last match, and output.
|
||||||
// If no match, read a UTF-8 codepoint and output that.
|
// If no match, read a UTF-8 codepoint and output that.
|
||||||
struct Charmap const &charmap = *currentCharmap;
|
Charmap const &charmap = *currentCharmap;
|
||||||
size_t matchIdx = 0;
|
size_t matchIdx = 0;
|
||||||
size_t rewindDistance = 0;
|
size_t rewindDistance = 0;
|
||||||
|
|
||||||
|
|||||||
@@ -12,29 +12,29 @@
|
|||||||
#include "asm/format.hpp"
|
#include "asm/format.hpp"
|
||||||
#include "asm/warning.hpp"
|
#include "asm/warning.hpp"
|
||||||
|
|
||||||
struct FormatSpec fmt_NewSpec(void)
|
FormatSpec fmt_NewSpec(void)
|
||||||
{
|
{
|
||||||
struct FormatSpec fmt = {};
|
FormatSpec fmt = {};
|
||||||
|
|
||||||
return fmt;
|
return fmt;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool fmt_IsEmpty(struct FormatSpec const *fmt)
|
bool fmt_IsEmpty(FormatSpec const *fmt)
|
||||||
{
|
{
|
||||||
return !fmt->state;
|
return !fmt->state;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool fmt_IsValid(struct FormatSpec const *fmt)
|
bool fmt_IsValid(FormatSpec const *fmt)
|
||||||
{
|
{
|
||||||
return fmt->valid || fmt->state == FORMAT_DONE;
|
return fmt->valid || fmt->state == FORMAT_DONE;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool fmt_IsFinished(struct FormatSpec const *fmt)
|
bool fmt_IsFinished(FormatSpec const *fmt)
|
||||||
{
|
{
|
||||||
return fmt->state >= FORMAT_DONE;
|
return fmt->state >= FORMAT_DONE;
|
||||||
}
|
}
|
||||||
|
|
||||||
void fmt_UseCharacter(struct FormatSpec *fmt, int c)
|
void fmt_UseCharacter(FormatSpec *fmt, int c)
|
||||||
{
|
{
|
||||||
if (fmt->state == FORMAT_INVALID)
|
if (fmt->state == FORMAT_INVALID)
|
||||||
return;
|
return;
|
||||||
@@ -121,13 +121,13 @@ invalid:
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void fmt_FinishCharacters(struct FormatSpec *fmt)
|
void fmt_FinishCharacters(FormatSpec *fmt)
|
||||||
{
|
{
|
||||||
if (!fmt_IsValid(fmt))
|
if (!fmt_IsValid(fmt))
|
||||||
fmt->state = FORMAT_INVALID;
|
fmt->state = FORMAT_INVALID;
|
||||||
}
|
}
|
||||||
|
|
||||||
void fmt_PrintString(char *buf, size_t bufLen, struct FormatSpec const *fmt, char const *value)
|
void fmt_PrintString(char *buf, size_t bufLen, FormatSpec const *fmt, char const *value)
|
||||||
{
|
{
|
||||||
if (fmt->sign)
|
if (fmt->sign)
|
||||||
error("Formatting string with sign flag '%c'\n", fmt->sign);
|
error("Formatting string with sign flag '%c'\n", fmt->sign);
|
||||||
@@ -166,7 +166,7 @@ void fmt_PrintString(char *buf, size_t bufLen, struct FormatSpec const *fmt, cha
|
|||||||
buf[totalLen] = '\0';
|
buf[totalLen] = '\0';
|
||||||
}
|
}
|
||||||
|
|
||||||
void fmt_PrintNumber(char *buf, size_t bufLen, struct FormatSpec const *fmt, uint32_t value)
|
void fmt_PrintNumber(char *buf, size_t bufLen, FormatSpec const *fmt, uint32_t value)
|
||||||
{
|
{
|
||||||
if (fmt->type != 'X' && fmt->type != 'x' && fmt->type != 'b' && fmt->type != 'o'
|
if (fmt->type != 'X' && fmt->type != 'x' && fmt->type != 'b' && fmt->type != 'o'
|
||||||
&& fmt->prefix)
|
&& fmt->prefix)
|
||||||
|
|||||||
@@ -23,10 +23,10 @@
|
|||||||
#include "platform.hpp" // S_ISDIR (stat macro)
|
#include "platform.hpp" // S_ISDIR (stat macro)
|
||||||
|
|
||||||
struct Context {
|
struct Context {
|
||||||
struct FileStackNode *fileInfo;
|
FileStackNode *fileInfo;
|
||||||
struct LexerState lexerState;
|
LexerState lexerState;
|
||||||
uint32_t uniqueID;
|
uint32_t uniqueID;
|
||||||
struct MacroArgs *macroArgs; // Macro args are *saved* here
|
MacroArgs *macroArgs; // Macro args are *saved* here
|
||||||
uint32_t nbReptIters;
|
uint32_t nbReptIters;
|
||||||
bool isForLoop;
|
bool isForLoop;
|
||||||
int32_t forValue;
|
int32_t forValue;
|
||||||
@@ -34,7 +34,7 @@ struct Context {
|
|||||||
std::string forName;
|
std::string forName;
|
||||||
};
|
};
|
||||||
|
|
||||||
static std::stack<struct Context> contextStack;
|
static std::stack<Context> contextStack;
|
||||||
size_t maxRecursionDepth;
|
size_t maxRecursionDepth;
|
||||||
|
|
||||||
// The first include path for `fstk_FindFile` to try is none at all
|
// The first include path for `fstk_FindFile` to try is none at all
|
||||||
@@ -42,7 +42,7 @@ static std::vector<std::string> includePaths = { "" };
|
|||||||
|
|
||||||
static const char *preIncludeName;
|
static const char *preIncludeName;
|
||||||
|
|
||||||
static const char *dumpNodeAndParents(struct FileStackNode const *node)
|
static const char *dumpNodeAndParents(FileStackNode const *node)
|
||||||
{
|
{
|
||||||
char const *name;
|
char const *name;
|
||||||
|
|
||||||
@@ -86,7 +86,7 @@ std::string const &FileStackNode::name() const {
|
|||||||
return std::get<std::string>(data);
|
return std::get<std::string>(data);
|
||||||
}
|
}
|
||||||
|
|
||||||
void fstk_Dump(struct FileStackNode const *node, uint32_t lineNo)
|
void fstk_Dump(FileStackNode const *node, uint32_t lineNo)
|
||||||
{
|
{
|
||||||
dumpNodeAndParents(node);
|
dumpNodeAndParents(node);
|
||||||
fprintf(stderr, "(%" PRIu32 ")", lineNo);
|
fprintf(stderr, "(%" PRIu32 ")", lineNo);
|
||||||
@@ -101,15 +101,15 @@ void fstk_DumpCurrent(void)
|
|||||||
fstk_Dump(contextStack.top().fileInfo, lexer_GetLineNo());
|
fstk_Dump(contextStack.top().fileInfo, lexer_GetLineNo());
|
||||||
}
|
}
|
||||||
|
|
||||||
struct FileStackNode *fstk_GetFileStack(void)
|
FileStackNode *fstk_GetFileStack(void)
|
||||||
{
|
{
|
||||||
if (contextStack.empty())
|
if (contextStack.empty())
|
||||||
return NULL;
|
return NULL;
|
||||||
|
|
||||||
struct FileStackNode *topNode = contextStack.top().fileInfo;
|
FileStackNode *topNode = contextStack.top().fileInfo;
|
||||||
|
|
||||||
// Mark node and all of its parents as referenced if not already so they don't get freed
|
// Mark node and all of its parents as referenced if not already so they don't get freed
|
||||||
for (struct FileStackNode *node = topNode; node && !node->referenced; node = node->parent) {
|
for (FileStackNode *node = topNode; node && !node->referenced; node = node->parent) {
|
||||||
node->ID = -1;
|
node->ID = -1;
|
||||||
node->referenced = true;
|
node->referenced = true;
|
||||||
}
|
}
|
||||||
@@ -119,7 +119,7 @@ struct FileStackNode *fstk_GetFileStack(void)
|
|||||||
char const *fstk_GetFileName(void)
|
char const *fstk_GetFileName(void)
|
||||||
{
|
{
|
||||||
// Iterating via the nodes themselves skips nested REPTs
|
// Iterating via the nodes themselves skips nested REPTs
|
||||||
struct FileStackNode const *node = contextStack.top().fileInfo;
|
FileStackNode const *node = contextStack.top().fileInfo;
|
||||||
|
|
||||||
while (node->type != NODE_FILE)
|
while (node->type != NODE_FILE)
|
||||||
node = node->parent;
|
node = node->parent;
|
||||||
@@ -196,12 +196,12 @@ bool yywrap(void)
|
|||||||
fatalerror("Ended block with %" PRIu32 " unterminated IF construct%s\n",
|
fatalerror("Ended block with %" PRIu32 " unterminated IF construct%s\n",
|
||||||
ifDepth, ifDepth == 1 ? "" : "s");
|
ifDepth, ifDepth == 1 ? "" : "s");
|
||||||
|
|
||||||
if (struct Context &context = contextStack.top(); context.fileInfo->type == NODE_REPT) {
|
if (Context &context = contextStack.top(); context.fileInfo->type == NODE_REPT) {
|
||||||
// The context is a REPT or FOR block, which may loop
|
// The context is a REPT or FOR block, which may loop
|
||||||
|
|
||||||
// If the node is referenced, we can't edit it; duplicate it
|
// If the node is referenced, we can't edit it; duplicate it
|
||||||
if (context.fileInfo->referenced) {
|
if (context.fileInfo->referenced) {
|
||||||
context.fileInfo = new(std::nothrow) struct FileStackNode(*context.fileInfo);
|
context.fileInfo = new(std::nothrow) FileStackNode(*context.fileInfo);
|
||||||
if (!context.fileInfo)
|
if (!context.fileInfo)
|
||||||
fatalerror("Failed to duplicate REPT file node: %s\n", strerror(errno));
|
fatalerror("Failed to duplicate REPT file node: %s\n", strerror(errno));
|
||||||
// Copy all info but the referencing
|
// Copy all info but the referencing
|
||||||
@@ -215,7 +215,7 @@ bool yywrap(void)
|
|||||||
// Avoid arithmetic overflow runtime error
|
// Avoid arithmetic overflow runtime error
|
||||||
uint32_t forValue = (uint32_t)context.forValue + (uint32_t)context.forStep;
|
uint32_t forValue = (uint32_t)context.forValue + (uint32_t)context.forStep;
|
||||||
context.forValue = forValue <= INT32_MAX ? forValue : -(int32_t)~forValue - 1;
|
context.forValue = forValue <= INT32_MAX ? forValue : -(int32_t)~forValue - 1;
|
||||||
struct Symbol *sym = sym_AddVar(context.forName.c_str(), context.forValue);
|
Symbol *sym = sym_AddVar(context.forName.c_str(), context.forValue);
|
||||||
|
|
||||||
// This error message will refer to the current iteration
|
// This error message will refer to the current iteration
|
||||||
if (sym->type != SYM_VAR)
|
if (sym->type != SYM_VAR)
|
||||||
@@ -233,7 +233,7 @@ bool yywrap(void)
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
struct Context oldContext = contextStack.top();
|
Context oldContext = contextStack.top();
|
||||||
|
|
||||||
contextStack.pop();
|
contextStack.pop();
|
||||||
|
|
||||||
@@ -256,7 +256,7 @@ bool yywrap(void)
|
|||||||
// Make sure not to switch the lexer state before calling this, so the saved line no is correct.
|
// Make sure not to switch the lexer state before calling this, so the saved line no is correct.
|
||||||
// BE CAREFUL! This modifies the file stack directly, you should have set up the file info first.
|
// BE CAREFUL! This modifies the file stack directly, you should have set up the file info first.
|
||||||
// Callers should set `contextStack.top().lexerState` after this so it is not NULL.
|
// Callers should set `contextStack.top().lexerState` after this so it is not NULL.
|
||||||
static struct Context &newContext(struct FileStackNode *fileInfo)
|
static Context &newContext(FileStackNode *fileInfo)
|
||||||
{
|
{
|
||||||
if (contextStack.size() > maxRecursionDepth)
|
if (contextStack.size() > maxRecursionDepth)
|
||||||
fatalerror("Recursion limit (%zu) exceeded\n", maxRecursionDepth);
|
fatalerror("Recursion limit (%zu) exceeded\n", maxRecursionDepth);
|
||||||
@@ -264,13 +264,13 @@ static struct Context &newContext(struct FileStackNode *fileInfo)
|
|||||||
// Save the current `\@` value, to be restored when this context ends
|
// Save the current `\@` value, to be restored when this context ends
|
||||||
contextStack.top().uniqueID = macro_GetUniqueID();
|
contextStack.top().uniqueID = macro_GetUniqueID();
|
||||||
|
|
||||||
struct FileStackNode *parent = contextStack.top().fileInfo;
|
FileStackNode *parent = contextStack.top().fileInfo;
|
||||||
|
|
||||||
fileInfo->parent = parent;
|
fileInfo->parent = parent;
|
||||||
fileInfo->lineNo = lexer_GetLineNo();
|
fileInfo->lineNo = lexer_GetLineNo();
|
||||||
fileInfo->referenced = false;
|
fileInfo->referenced = false;
|
||||||
|
|
||||||
struct Context &context = contextStack.emplace();
|
Context &context = contextStack.emplace();
|
||||||
|
|
||||||
context.fileInfo = fileInfo;
|
context.fileInfo = fileInfo;
|
||||||
context.isForLoop = false;
|
context.isForLoop = false;
|
||||||
@@ -294,7 +294,7 @@ void fstk_RunInclude(char const *path)
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
struct FileStackNode *fileInfo = new(std::nothrow) struct FileStackNode();
|
FileStackNode *fileInfo = new(std::nothrow) FileStackNode();
|
||||||
|
|
||||||
if (!fileInfo) {
|
if (!fileInfo) {
|
||||||
error("Failed to alloc file info for INCLUDE: %s\n", strerror(errno));
|
error("Failed to alloc file info for INCLUDE: %s\n", strerror(errno));
|
||||||
@@ -305,7 +305,7 @@ void fstk_RunInclude(char const *path)
|
|||||||
delete fullPath;
|
delete fullPath;
|
||||||
|
|
||||||
uint32_t uniqueID = contextStack.top().uniqueID;
|
uint32_t uniqueID = contextStack.top().uniqueID;
|
||||||
struct Context &context = newContext(fileInfo);
|
Context &context = newContext(fileInfo);
|
||||||
|
|
||||||
if (!lexer_OpenFile(context.lexerState, fileInfo->name().c_str()))
|
if (!lexer_OpenFile(context.lexerState, fileInfo->name().c_str()))
|
||||||
fatalerror("Failed to set up lexer for file include\n");
|
fatalerror("Failed to set up lexer for file include\n");
|
||||||
@@ -330,7 +330,7 @@ static void runPreIncludeFile(void)
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
struct FileStackNode *fileInfo = new(std::nothrow) struct FileStackNode();
|
FileStackNode *fileInfo = new(std::nothrow) FileStackNode();
|
||||||
|
|
||||||
if (!fileInfo) {
|
if (!fileInfo) {
|
||||||
error("Failed to alloc file info for pre-include: %s\n", strerror(errno));
|
error("Failed to alloc file info for pre-include: %s\n", strerror(errno));
|
||||||
@@ -340,7 +340,7 @@ static void runPreIncludeFile(void)
|
|||||||
fileInfo->data = *fullPath;
|
fileInfo->data = *fullPath;
|
||||||
delete fullPath;
|
delete fullPath;
|
||||||
|
|
||||||
struct Context &context = newContext(fileInfo);
|
Context &context = newContext(fileInfo);
|
||||||
|
|
||||||
if (!lexer_OpenFile(context.lexerState, fileInfo->name().c_str()))
|
if (!lexer_OpenFile(context.lexerState, fileInfo->name().c_str()))
|
||||||
fatalerror("Failed to set up lexer for file include\n");
|
fatalerror("Failed to set up lexer for file include\n");
|
||||||
@@ -349,9 +349,9 @@ static void runPreIncludeFile(void)
|
|||||||
context.uniqueID = macro_UndefUniqueID();
|
context.uniqueID = macro_UndefUniqueID();
|
||||||
}
|
}
|
||||||
|
|
||||||
void fstk_RunMacro(char const *macroName, struct MacroArgs *args)
|
void fstk_RunMacro(char const *macroName, MacroArgs *args)
|
||||||
{
|
{
|
||||||
struct Symbol *macro = sym_FindExactSymbol(macroName);
|
Symbol *macro = sym_FindExactSymbol(macroName);
|
||||||
|
|
||||||
if (!macro) {
|
if (!macro) {
|
||||||
error("Macro \"%s\" not defined\n", macroName);
|
error("Macro \"%s\" not defined\n", macroName);
|
||||||
@@ -363,7 +363,7 @@ void fstk_RunMacro(char const *macroName, struct MacroArgs *args)
|
|||||||
}
|
}
|
||||||
contextStack.top().macroArgs = macro_GetCurrentArgs();
|
contextStack.top().macroArgs = macro_GetCurrentArgs();
|
||||||
|
|
||||||
struct FileStackNode *fileInfo = new(std::nothrow) struct FileStackNode();
|
FileStackNode *fileInfo = new(std::nothrow) FileStackNode();
|
||||||
|
|
||||||
if (!fileInfo) {
|
if (!fileInfo) {
|
||||||
error("Failed to alloc file info for \"%s\": %s\n", macro->name, strerror(errno));
|
error("Failed to alloc file info for \"%s\": %s\n", macro->name, strerror(errno));
|
||||||
@@ -375,7 +375,7 @@ void fstk_RunMacro(char const *macroName, struct MacroArgs *args)
|
|||||||
// Print the name...
|
// Print the name...
|
||||||
std::string &fileInfoName = fileInfo->name();
|
std::string &fileInfoName = fileInfo->name();
|
||||||
|
|
||||||
for (struct FileStackNode const *node = macro->src; node; node = node->parent) {
|
for (FileStackNode const *node = macro->src; node; node = node->parent) {
|
||||||
if (node->type != NODE_REPT) {
|
if (node->type != NODE_REPT) {
|
||||||
fileInfoName.append(node->name());
|
fileInfoName.append(node->name());
|
||||||
break;
|
break;
|
||||||
@@ -396,7 +396,7 @@ void fstk_RunMacro(char const *macroName, struct MacroArgs *args)
|
|||||||
fileInfoName.append("::");
|
fileInfoName.append("::");
|
||||||
fileInfoName.append(macro->name);
|
fileInfoName.append(macro->name);
|
||||||
|
|
||||||
struct Context &context = newContext(fileInfo);
|
Context &context = newContext(fileInfo);
|
||||||
|
|
||||||
lexer_OpenFileView(context.lexerState, "MACRO", macro->macro.value, macro->macro.size,
|
lexer_OpenFileView(context.lexerState, "MACRO", macro->macro.value, macro->macro.size,
|
||||||
macro->fileLine);
|
macro->fileLine);
|
||||||
@@ -410,7 +410,7 @@ static bool newReptContext(int32_t reptLineNo, char *body, size_t size)
|
|||||||
uint32_t reptDepth = contextStack.top().fileInfo->type == NODE_REPT
|
uint32_t reptDepth = contextStack.top().fileInfo->type == NODE_REPT
|
||||||
? contextStack.top().fileInfo->iters().size()
|
? contextStack.top().fileInfo->iters().size()
|
||||||
: 0;
|
: 0;
|
||||||
struct FileStackNode *fileInfo = new(std::nothrow) struct FileStackNode();
|
FileStackNode *fileInfo = new(std::nothrow) FileStackNode();
|
||||||
|
|
||||||
if (!fileInfo) {
|
if (!fileInfo) {
|
||||||
error("Failed to alloc file info for REPT: %s\n", strerror(errno));
|
error("Failed to alloc file info for REPT: %s\n", strerror(errno));
|
||||||
@@ -423,7 +423,7 @@ static bool newReptContext(int32_t reptLineNo, char *body, size_t size)
|
|||||||
fileInfo->iters().insert(fileInfo->iters().end(), RANGE(contextStack.top().fileInfo->iters()));
|
fileInfo->iters().insert(fileInfo->iters().end(), RANGE(contextStack.top().fileInfo->iters()));
|
||||||
}
|
}
|
||||||
|
|
||||||
struct Context &context = newContext(fileInfo);
|
Context &context = newContext(fileInfo);
|
||||||
|
|
||||||
// Correct our line number, which currently points to the `ENDR` line
|
// Correct our line number, which currently points to the `ENDR` line
|
||||||
context.fileInfo->lineNo = reptLineNo;
|
context.fileInfo->lineNo = reptLineNo;
|
||||||
@@ -447,7 +447,7 @@ void fstk_RunRept(uint32_t count, int32_t reptLineNo, char *body, size_t size)
|
|||||||
void fstk_RunFor(char const *symName, int32_t start, int32_t stop, int32_t step,
|
void fstk_RunFor(char const *symName, int32_t start, int32_t stop, int32_t step,
|
||||||
int32_t reptLineNo, char *body, size_t size)
|
int32_t reptLineNo, char *body, size_t size)
|
||||||
{
|
{
|
||||||
struct Symbol *sym = sym_AddVar(symName, start);
|
Symbol *sym = sym_AddVar(symName, start);
|
||||||
|
|
||||||
if (sym->type != SYM_VAR)
|
if (sym->type != SYM_VAR)
|
||||||
return;
|
return;
|
||||||
@@ -470,7 +470,7 @@ void fstk_RunFor(char const *symName, int32_t start, int32_t stop, int32_t step,
|
|||||||
if (!newReptContext(reptLineNo, body, size))
|
if (!newReptContext(reptLineNo, body, size))
|
||||||
return;
|
return;
|
||||||
|
|
||||||
struct Context &context = contextStack.top();
|
Context &context = contextStack.top();
|
||||||
|
|
||||||
context.nbReptIters = count;
|
context.nbReptIters = count;
|
||||||
context.isForLoop = true;
|
context.isForLoop = true;
|
||||||
@@ -505,13 +505,13 @@ void fstk_NewRecursionDepth(size_t newDepth)
|
|||||||
|
|
||||||
void fstk_Init(char const *mainPath, size_t maxDepth)
|
void fstk_Init(char const *mainPath, size_t maxDepth)
|
||||||
{
|
{
|
||||||
struct Context &context = contextStack.emplace();
|
Context &context = contextStack.emplace();
|
||||||
|
|
||||||
if (!lexer_OpenFile(context.lexerState, mainPath))
|
if (!lexer_OpenFile(context.lexerState, mainPath))
|
||||||
fatalerror("Failed to open main file\n");
|
fatalerror("Failed to open main file\n");
|
||||||
lexer_SetState(&context.lexerState);
|
lexer_SetState(&context.lexerState);
|
||||||
|
|
||||||
struct FileStackNode *fileInfo = new(std::nothrow) struct FileStackNode();
|
FileStackNode *fileInfo = new(std::nothrow) FileStackNode();
|
||||||
|
|
||||||
if (!fileInfo)
|
if (!fileInfo)
|
||||||
fatalerror("Failed to allocate memory for main file info: %s\n", strerror(errno));
|
fatalerror("Failed to allocate memory for main file info: %s\n", strerror(errno));
|
||||||
|
|||||||
@@ -298,10 +298,10 @@ static bool isWhitespace(int c)
|
|||||||
return c == ' ' || c == '\t';
|
return c == ' ' || c == '\t';
|
||||||
}
|
}
|
||||||
|
|
||||||
struct LexerState *lexerState = NULL;
|
LexerState *lexerState = NULL;
|
||||||
struct LexerState *lexerStateEOL = NULL;
|
LexerState *lexerStateEOL = NULL;
|
||||||
|
|
||||||
static void initState(struct LexerState &state)
|
static void initState(LexerState &state)
|
||||||
{
|
{
|
||||||
state.mode = LEXER_NORMAL;
|
state.mode = LEXER_NORMAL;
|
||||||
state.atLineStart = true; // yylex() will init colNo due to this
|
state.atLineStart = true; // yylex() will init colNo due to this
|
||||||
@@ -364,7 +364,7 @@ void lexer_ReachELSEBlock(void)
|
|||||||
lexerState->ifStack.front().reachedElseBlock = true;
|
lexerState->ifStack.front().reachedElseBlock = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool lexer_OpenFile(struct LexerState &state, char const *path)
|
bool lexer_OpenFile(LexerState &state, char const *path)
|
||||||
{
|
{
|
||||||
bool isStdin = !strcmp(path, "-");
|
bool isStdin = !strcmp(path, "-");
|
||||||
struct stat fileInfo;
|
struct stat fileInfo;
|
||||||
@@ -431,7 +431,7 @@ bool lexer_OpenFile(struct LexerState &state, char const *path)
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
void lexer_OpenFileView(struct LexerState &state, char const *path, char *buf, size_t size, uint32_t lineNo)
|
void lexer_OpenFileView(LexerState &state, char const *path, char *buf, size_t size, uint32_t lineNo)
|
||||||
{
|
{
|
||||||
state.path = path; // Used to report read errors in `peekInternal`
|
state.path = path; // Used to report read errors in `peekInternal`
|
||||||
state.isFile = false;
|
state.isFile = false;
|
||||||
@@ -451,7 +451,7 @@ void lexer_RestartRept(uint32_t lineNo)
|
|||||||
lexerState->lineNo = lineNo;
|
lexerState->lineNo = lineNo;
|
||||||
}
|
}
|
||||||
|
|
||||||
void lexer_CleanupState(struct LexerState &state)
|
void lexer_CleanupState(LexerState &state)
|
||||||
{
|
{
|
||||||
// A big chunk of the lexer state soundness is the file stack ("fstack").
|
// A big chunk of the lexer state soundness is the file stack ("fstack").
|
||||||
// Each context in the fstack has its own *unique* lexer state; thus, we always guarantee
|
// Each context in the fstack has its own *unique* lexer state; thus, we always guarantee
|
||||||
@@ -523,7 +523,7 @@ void lexer_CheckRecursionDepth(void)
|
|||||||
fatalerror("Recursion limit (%zu) exceeded\n", maxRecursionDepth);
|
fatalerror("Recursion limit (%zu) exceeded\n", maxRecursionDepth);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void freeExpansion(struct Expansion &expansion)
|
static void freeExpansion(Expansion &expansion)
|
||||||
{
|
{
|
||||||
free(expansion.name);
|
free(expansion.name);
|
||||||
if (expansion.owned)
|
if (expansion.owned)
|
||||||
@@ -573,7 +573,7 @@ static uint32_t readBracketedMacroArgNum(void)
|
|||||||
}
|
}
|
||||||
symName[i] = '\0';
|
symName[i] = '\0';
|
||||||
|
|
||||||
struct Symbol const *sym = sym_FindScopedValidSymbol(symName);
|
Symbol const *sym = sym_FindScopedValidSymbol(symName);
|
||||||
|
|
||||||
if (!sym) {
|
if (!sym) {
|
||||||
error("Bracketed symbol \"%s\" does not exist\n", symName);
|
error("Bracketed symbol \"%s\" does not exist\n", symName);
|
||||||
@@ -654,7 +654,7 @@ static size_t readInternal(size_t bufIndex, size_t nbChars)
|
|||||||
// We only need one character of lookahead, for macro arguments
|
// We only need one character of lookahead, for macro arguments
|
||||||
static int peekInternal(uint8_t distance)
|
static int peekInternal(uint8_t distance)
|
||||||
{
|
{
|
||||||
for (struct Expansion &exp : lexerState->expansions) {
|
for (Expansion &exp : lexerState->expansions) {
|
||||||
// An expansion that has reached its end will have `exp->offset` == `exp->size`,
|
// An expansion that has reached its end will have `exp->offset` == `exp->size`,
|
||||||
// and `peekInternal` will continue with its parent
|
// and `peekInternal` will continue with its parent
|
||||||
assert(exp.offset <= exp.size);
|
assert(exp.offset <= exp.size);
|
||||||
@@ -775,7 +775,7 @@ static void shiftChar(void)
|
|||||||
restart:
|
restart:
|
||||||
if (!lexerState->expansions.empty()) {
|
if (!lexerState->expansions.empty()) {
|
||||||
// Advance within the current expansion
|
// Advance within the current expansion
|
||||||
struct Expansion &expansion = lexerState->expansions.front();
|
Expansion &expansion = lexerState->expansions.front();
|
||||||
|
|
||||||
assert(expansion.offset <= expansion.size);
|
assert(expansion.offset <= expansion.size);
|
||||||
expansion.offset++;
|
expansion.offset++;
|
||||||
@@ -840,7 +840,7 @@ void lexer_DumpStringExpansions(void)
|
|||||||
if (!lexerState)
|
if (!lexerState)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
for (struct Expansion &exp : lexerState->expansions) {
|
for (Expansion &exp : lexerState->expansions) {
|
||||||
// Only register EQUS expansions, not string args
|
// Only register EQUS expansions, not string args
|
||||||
if (exp.name)
|
if (exp.name)
|
||||||
fprintf(stderr, "while expanding symbol \"%s\"\n", exp.name);
|
fprintf(stderr, "while expanding symbol \"%s\"\n", exp.name);
|
||||||
@@ -1184,7 +1184,7 @@ static char const *readInterpolation(size_t depth)
|
|||||||
|
|
||||||
char symName[MAXSYMLEN + 1];
|
char symName[MAXSYMLEN + 1];
|
||||||
size_t i = 0;
|
size_t i = 0;
|
||||||
struct FormatSpec fmt = fmt_NewSpec();
|
FormatSpec fmt = fmt_NewSpec();
|
||||||
bool disableInterpolation = lexerState->disableInterpolation;
|
bool disableInterpolation = lexerState->disableInterpolation;
|
||||||
|
|
||||||
// In a context where `lexerState->disableInterpolation` is true, `peek` will expand
|
// In a context where `lexerState->disableInterpolation` is true, `peek` will expand
|
||||||
@@ -1239,7 +1239,7 @@ static char const *readInterpolation(size_t depth)
|
|||||||
|
|
||||||
static char buf[MAXSTRLEN + 1];
|
static char buf[MAXSTRLEN + 1];
|
||||||
|
|
||||||
struct Symbol const *sym = sym_FindScopedValidSymbol(symName);
|
Symbol const *sym = sym_FindScopedValidSymbol(symName);
|
||||||
|
|
||||||
if (!sym) {
|
if (!sym) {
|
||||||
error("Interpolated symbol \"%s\" does not exist\n", symName);
|
error("Interpolated symbol \"%s\" does not exist\n", symName);
|
||||||
@@ -1881,7 +1881,7 @@ static int yylex_NORMAL(void)
|
|||||||
// Local symbols cannot be string expansions
|
// Local symbols cannot be string expansions
|
||||||
if (tokenType == T_ID && lexerState->expandStrings) {
|
if (tokenType == T_ID && lexerState->expandStrings) {
|
||||||
// Attempt string expansion
|
// Attempt string expansion
|
||||||
struct Symbol const *sym = sym_FindExactSymbol(yylval.symName);
|
Symbol const *sym = sym_FindExactSymbol(yylval.symName);
|
||||||
|
|
||||||
if (sym && sym->type == SYM_EQUS) {
|
if (sym && sym->type == SYM_EQUS) {
|
||||||
char const *s = sym_GetStringValue(sym);
|
char const *s = sym_GetStringValue(sym);
|
||||||
@@ -2286,7 +2286,7 @@ int yylex(void)
|
|||||||
return token;
|
return token;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void startCapture(struct CaptureBody *capture)
|
static void startCapture(CaptureBody *capture)
|
||||||
{
|
{
|
||||||
assert(!lexerState->capturing);
|
assert(!lexerState->capturing);
|
||||||
lexerState->capturing = true;
|
lexerState->capturing = true;
|
||||||
@@ -2306,7 +2306,7 @@ static void startCapture(struct CaptureBody *capture)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void endCapture(struct CaptureBody *capture)
|
static void endCapture(CaptureBody *capture)
|
||||||
{
|
{
|
||||||
// This being NULL means we're capturing from the capture buf, which is `realloc`'d during
|
// This being NULL means we're capturing from the capture buf, which is `realloc`'d during
|
||||||
// the whole capture process, and so MUST be retrieved at the end
|
// the whole capture process, and so MUST be retrieved at the end
|
||||||
@@ -2320,7 +2320,7 @@ static void endCapture(struct CaptureBody *capture)
|
|||||||
lexerState->disableInterpolation = false;
|
lexerState->disableInterpolation = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool lexer_CaptureRept(struct CaptureBody *capture)
|
bool lexer_CaptureRept(CaptureBody *capture)
|
||||||
{
|
{
|
||||||
startCapture(capture);
|
startCapture(capture);
|
||||||
|
|
||||||
@@ -2378,7 +2378,7 @@ finish:
|
|||||||
return c != EOF;
|
return c != EOF;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool lexer_CaptureMacroBody(struct CaptureBody *capture)
|
bool lexer_CaptureMacroBody(CaptureBody *capture)
|
||||||
{
|
{
|
||||||
startCapture(capture);
|
startCapture(capture);
|
||||||
|
|
||||||
|
|||||||
@@ -18,7 +18,7 @@ struct MacroArgs {
|
|||||||
std::vector<char *> args;
|
std::vector<char *> args;
|
||||||
};
|
};
|
||||||
|
|
||||||
static struct MacroArgs *macroArgs = NULL;
|
static MacroArgs *macroArgs = NULL;
|
||||||
static uint32_t uniqueID = 0;
|
static uint32_t uniqueID = 0;
|
||||||
static uint32_t maxUniqueID = 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
|
||||||
@@ -27,14 +27,14 @@ static uint32_t maxUniqueID = 0;
|
|||||||
static char uniqueIDBuf[] = "_u4294967295"; // UINT32_MAX
|
static char uniqueIDBuf[] = "_u4294967295"; // UINT32_MAX
|
||||||
static char *uniqueIDPtr = NULL;
|
static char *uniqueIDPtr = NULL;
|
||||||
|
|
||||||
struct MacroArgs *macro_GetCurrentArgs(void)
|
MacroArgs *macro_GetCurrentArgs(void)
|
||||||
{
|
{
|
||||||
return macroArgs;
|
return macroArgs;
|
||||||
}
|
}
|
||||||
|
|
||||||
struct MacroArgs *macro_NewArgs(void)
|
MacroArgs *macro_NewArgs(void)
|
||||||
{
|
{
|
||||||
struct MacroArgs *args = new(std::nothrow) struct MacroArgs();
|
MacroArgs *args = new(std::nothrow) MacroArgs();
|
||||||
|
|
||||||
if (!args)
|
if (!args)
|
||||||
fatalerror("Unable to register macro arguments: %s\n", strerror(errno));
|
fatalerror("Unable to register macro arguments: %s\n", strerror(errno));
|
||||||
@@ -43,7 +43,7 @@ struct MacroArgs *macro_NewArgs(void)
|
|||||||
return args;
|
return args;
|
||||||
}
|
}
|
||||||
|
|
||||||
void macro_AppendArg(struct MacroArgs *args, char *s)
|
void macro_AppendArg(MacroArgs *args, char *s)
|
||||||
{
|
{
|
||||||
if (s[0] == '\0')
|
if (s[0] == '\0')
|
||||||
warning(WARNING_EMPTY_MACRO_ARG, "Empty macro argument\n");
|
warning(WARNING_EMPTY_MACRO_ARG, "Empty macro argument\n");
|
||||||
@@ -52,12 +52,12 @@ void macro_AppendArg(struct MacroArgs *args, char *s)
|
|||||||
args->args.push_back(s);
|
args->args.push_back(s);
|
||||||
}
|
}
|
||||||
|
|
||||||
void macro_UseNewArgs(struct MacroArgs *args)
|
void macro_UseNewArgs(MacroArgs *args)
|
||||||
{
|
{
|
||||||
macroArgs = args;
|
macroArgs = args;
|
||||||
}
|
}
|
||||||
|
|
||||||
void macro_FreeArgs(struct MacroArgs *args)
|
void macro_FreeArgs(MacroArgs *args)
|
||||||
{
|
{
|
||||||
for (char *arg : args->args)
|
for (char *arg : args->args)
|
||||||
free(arg);
|
free(arg);
|
||||||
|
|||||||
@@ -97,7 +97,7 @@ static int depType; // Variants of `-M`
|
|||||||
// except if it doesn't create any ambiguity (`verbose` versus `version`).
|
// except if it doesn't create any ambiguity (`verbose` versus `version`).
|
||||||
// This is because long opt matching, even to a single char, is prioritized
|
// This is because long opt matching, even to a single char, is prioritized
|
||||||
// over short opt matching
|
// over short opt matching
|
||||||
static struct option const longopts[] = {
|
static option const longopts[] = {
|
||||||
{ "binary-digits", required_argument, NULL, 'b' },
|
{ "binary-digits", required_argument, NULL, 'b' },
|
||||||
{ "define", required_argument, NULL, 'D' },
|
{ "define", required_argument, NULL, 'D' },
|
||||||
{ "export-all", no_argument, NULL, 'E' },
|
{ "export-all", no_argument, NULL, 'E' },
|
||||||
|
|||||||
@@ -31,7 +31,7 @@ struct OptStackEntry {
|
|||||||
enum WarningState warningStates[numWarningStates];
|
enum WarningState warningStates[numWarningStates];
|
||||||
};
|
};
|
||||||
|
|
||||||
static std::stack<struct OptStackEntry> stack;
|
static std::stack<OptStackEntry> stack;
|
||||||
|
|
||||||
void opt_B(char const chars[2])
|
void opt_B(char const chars[2])
|
||||||
{
|
{
|
||||||
@@ -241,7 +241,7 @@ void opt_Parse(char *s)
|
|||||||
|
|
||||||
void opt_Push(void)
|
void opt_Push(void)
|
||||||
{
|
{
|
||||||
struct OptStackEntry entry;
|
OptStackEntry entry;
|
||||||
|
|
||||||
// Both of these are pulled from lexer.hpp
|
// Both of these are pulled from lexer.hpp
|
||||||
entry.binary[0] = binDigits[0];
|
entry.binary[0] = binDigits[0];
|
||||||
@@ -280,7 +280,7 @@ void opt_Pop(void)
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
struct OptStackEntry entry = stack.top();
|
OptStackEntry entry = stack.top();
|
||||||
stack.pop();
|
stack.pop();
|
||||||
|
|
||||||
opt_B(entry.binary);
|
opt_B(entry.binary);
|
||||||
|
|||||||
@@ -28,19 +28,19 @@
|
|||||||
#include "platform.hpp" // strdup
|
#include "platform.hpp" // strdup
|
||||||
|
|
||||||
struct Assertion {
|
struct Assertion {
|
||||||
struct Patch patch;
|
Patch patch;
|
||||||
struct Section *section;
|
Section *section;
|
||||||
std::string message;
|
std::string message;
|
||||||
};
|
};
|
||||||
|
|
||||||
const char *objectName;
|
const char *objectName;
|
||||||
|
|
||||||
// List of symbols to put in the object file
|
// List of symbols to put in the object file
|
||||||
static std::vector<struct Symbol *> objectSymbols;
|
static std::vector<Symbol *> objectSymbols;
|
||||||
|
|
||||||
static std::deque<struct Assertion> assertions;
|
static std::deque<Assertion> assertions;
|
||||||
|
|
||||||
static std::deque<struct FileStackNode *> fileStackNodes;
|
static std::deque<FileStackNode *> fileStackNodes;
|
||||||
|
|
||||||
// Write a long to a file (little-endian)
|
// Write a long to a file (little-endian)
|
||||||
static void putlong(uint32_t i, FILE *f)
|
static void putlong(uint32_t i, FILE *f)
|
||||||
@@ -59,7 +59,7 @@ static void putstring(char const *s, FILE *f)
|
|||||||
putc(0, f);
|
putc(0, f);
|
||||||
}
|
}
|
||||||
|
|
||||||
void out_RegisterNode(struct FileStackNode *node)
|
void out_RegisterNode(FileStackNode *node)
|
||||||
{
|
{
|
||||||
// If node is not already registered, register it (and parents), and give it a unique ID
|
// If node is not already registered, register it (and parents), and give it a unique ID
|
||||||
for (; node && node->ID == (uint32_t)-1; node = node->parent) {
|
for (; node && node->ID == (uint32_t)-1; node = node->parent) {
|
||||||
@@ -68,7 +68,7 @@ void out_RegisterNode(struct FileStackNode *node)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void out_ReplaceNode(struct FileStackNode * /* node */)
|
void out_ReplaceNode(FileStackNode * /* node */)
|
||||||
{
|
{
|
||||||
#if 0
|
#if 0
|
||||||
This is code intended to replace a node, which is pretty useless until ref counting is added...
|
This is code intended to replace a node, which is pretty useless until ref counting is added...
|
||||||
@@ -85,7 +85,7 @@ This is code intended to replace a node, which is pretty useless until ref count
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Return a section's ID, or -1 if the section is not in the list
|
// Return a section's ID, or -1 if the section is not in the list
|
||||||
static uint32_t getSectIDIfAny(struct Section *sect)
|
static uint32_t getSectIDIfAny(Section *sect)
|
||||||
{
|
{
|
||||||
if (!sect)
|
if (!sect)
|
||||||
return (uint32_t)-1;
|
return (uint32_t)-1;
|
||||||
@@ -99,7 +99,7 @@ static uint32_t getSectIDIfAny(struct Section *sect)
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Write a patch to a file
|
// Write a patch to a file
|
||||||
static void writepatch(struct Patch const &patch, FILE *f)
|
static void writepatch(Patch const &patch, FILE *f)
|
||||||
{
|
{
|
||||||
assert(patch.src->ID != (uint32_t)-1);
|
assert(patch.src->ID != (uint32_t)-1);
|
||||||
putlong(patch.src->ID, f);
|
putlong(patch.src->ID, f);
|
||||||
@@ -113,7 +113,7 @@ static void writepatch(struct Patch const &patch, FILE *f)
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Write a section to a file
|
// Write a section to a file
|
||||||
static void writesection(struct Section const §, FILE *f)
|
static void writesection(Section const §, FILE *f)
|
||||||
{
|
{
|
||||||
putstring(sect.name, f);
|
putstring(sect.name, f);
|
||||||
|
|
||||||
@@ -133,13 +133,13 @@ static void writesection(struct Section const §, FILE *f)
|
|||||||
fwrite(sect.data.data(), 1, sect.size, f);
|
fwrite(sect.data.data(), 1, sect.size, f);
|
||||||
putlong(sect.patches.size(), f);
|
putlong(sect.patches.size(), f);
|
||||||
|
|
||||||
for (struct Patch const &patch : sect.patches)
|
for (Patch const &patch : sect.patches)
|
||||||
writepatch(patch, f);
|
writepatch(patch, f);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Write a symbol to a file
|
// Write a symbol to a file
|
||||||
static void writesymbol(struct Symbol const *sym, FILE *f)
|
static void writesymbol(Symbol const *sym, FILE *f)
|
||||||
{
|
{
|
||||||
putstring(sym->name, f);
|
putstring(sym->name, f);
|
||||||
if (!sym_IsDefined(sym)) {
|
if (!sym_IsDefined(sym)) {
|
||||||
@@ -155,7 +155,7 @@ static void writesymbol(struct Symbol const *sym, FILE *f)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void registerSymbol(struct Symbol *sym)
|
static void registerSymbol(Symbol *sym)
|
||||||
{
|
{
|
||||||
sym->ID = objectSymbols.size();
|
sym->ID = objectSymbols.size();
|
||||||
objectSymbols.push_back(sym);
|
objectSymbols.push_back(sym);
|
||||||
@@ -164,7 +164,7 @@ static void registerSymbol(struct Symbol *sym)
|
|||||||
|
|
||||||
// Returns a symbol's ID within the object file
|
// Returns a symbol's ID within the object file
|
||||||
// If the symbol does not have one, one is assigned by registering the symbol
|
// If the symbol does not have one, one is assigned by registering the symbol
|
||||||
static uint32_t getSymbolID(struct Symbol *sym)
|
static uint32_t getSymbolID(Symbol *sym)
|
||||||
{
|
{
|
||||||
if (sym->ID == (uint32_t)-1 && !sym_IsPC(sym))
|
if (sym->ID == (uint32_t)-1 && !sym_IsPC(sym))
|
||||||
registerSymbol(sym);
|
registerSymbol(sym);
|
||||||
@@ -182,7 +182,7 @@ static void writerpn(std::vector<uint8_t> &rpnexpr, const std::vector<uint8_t> &
|
|||||||
uint8_t rpndata = popbyte();
|
uint8_t rpndata = popbyte();
|
||||||
|
|
||||||
switch (rpndata) {
|
switch (rpndata) {
|
||||||
struct Symbol *sym;
|
Symbol *sym;
|
||||||
uint32_t value;
|
uint32_t value;
|
||||||
uint8_t b;
|
uint8_t b;
|
||||||
size_t i;
|
size_t i;
|
||||||
@@ -267,9 +267,9 @@ static void writerpn(std::vector<uint8_t> &rpnexpr, const std::vector<uint8_t> &
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void initpatch(struct Patch &patch, uint32_t type, struct Expression const *expr, uint32_t ofs)
|
static void initpatch(Patch &patch, uint32_t type, Expression const *expr, uint32_t ofs)
|
||||||
{
|
{
|
||||||
struct FileStackNode *node = fstk_GetFileStack();
|
FileStackNode *node = fstk_GetFileStack();
|
||||||
|
|
||||||
patch.type = type;
|
patch.type = type;
|
||||||
patch.src = node;
|
patch.src = node;
|
||||||
@@ -295,10 +295,10 @@ static void initpatch(struct Patch &patch, uint32_t type, struct Expression cons
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Create a new patch (includes the rpn expr)
|
// Create a new patch (includes the rpn expr)
|
||||||
void out_CreatePatch(uint32_t type, struct Expression const *expr, uint32_t ofs, uint32_t pcShift)
|
void out_CreatePatch(uint32_t type, Expression const *expr, uint32_t ofs, uint32_t pcShift)
|
||||||
{
|
{
|
||||||
// Add the patch to the list
|
// Add the patch to the list
|
||||||
struct Patch &patch = currentSection->patches.emplace_front();
|
Patch &patch = currentSection->patches.emplace_front();
|
||||||
|
|
||||||
initpatch(patch, type, expr, ofs);
|
initpatch(patch, type, expr, ofs);
|
||||||
|
|
||||||
@@ -309,22 +309,21 @@ void out_CreatePatch(uint32_t type, struct Expression const *expr, uint32_t ofs,
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Creates an assert that will be written to the object file
|
// Creates an assert that will be written to the object file
|
||||||
void out_CreateAssert(enum AssertionType type, struct Expression const *expr,
|
void out_CreateAssert(enum AssertionType type, Expression const *expr, char const *message, uint32_t ofs)
|
||||||
char const *message, uint32_t ofs)
|
|
||||||
{
|
{
|
||||||
struct Assertion &assertion = assertions.emplace_front();
|
Assertion &assertion = assertions.emplace_front();
|
||||||
|
|
||||||
initpatch(assertion.patch, type, expr, ofs);
|
initpatch(assertion.patch, type, expr, ofs);
|
||||||
assertion.message = message;
|
assertion.message = message;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void writeassert(struct Assertion &assert, FILE *f)
|
static void writeassert(Assertion &assert, FILE *f)
|
||||||
{
|
{
|
||||||
writepatch(assert.patch, f);
|
writepatch(assert.patch, f);
|
||||||
putstring(assert.message.c_str(), f);
|
putstring(assert.message.c_str(), f);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void writeFileStackNode(struct FileStackNode const *node, FILE *f)
|
static void writeFileStackNode(FileStackNode const *node, FILE *f)
|
||||||
{
|
{
|
||||||
putlong(node->parent ? node->parent->ID : (uint32_t)-1, f);
|
putlong(node->parent ? node->parent->ID : (uint32_t)-1, f);
|
||||||
putlong(node->lineNo, f);
|
putlong(node->lineNo, f);
|
||||||
@@ -341,7 +340,7 @@ static void writeFileStackNode(struct FileStackNode const *node, FILE *f)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void registerUnregisteredSymbol(struct Symbol *symbol)
|
static void registerUnregisteredSymbol(Symbol *symbol)
|
||||||
{
|
{
|
||||||
// Check for symbol->src, to skip any built-in symbol from rgbasm
|
// Check for symbol->src, to skip any built-in symbol from rgbasm
|
||||||
if (symbol->src && symbol->ID == (uint32_t)-1) {
|
if (symbol->src && symbol->ID == (uint32_t)-1) {
|
||||||
@@ -374,7 +373,7 @@ void out_WriteObject(void)
|
|||||||
|
|
||||||
putlong(fileStackNodes.size(), f);
|
putlong(fileStackNodes.size(), f);
|
||||||
for (auto it = fileStackNodes.begin(); it != fileStackNodes.end(); it++) {
|
for (auto it = fileStackNodes.begin(); it != fileStackNodes.end(); it++) {
|
||||||
struct FileStackNode const *node = *it;
|
FileStackNode const *node = *it;
|
||||||
|
|
||||||
writeFileStackNode(node, f);
|
writeFileStackNode(node, f);
|
||||||
|
|
||||||
@@ -385,15 +384,15 @@ void out_WriteObject(void)
|
|||||||
it[1]->ID, node->ID);
|
it[1]->ID, node->ID);
|
||||||
}
|
}
|
||||||
|
|
||||||
for (struct Symbol const *sym : objectSymbols)
|
for (Symbol const *sym : objectSymbols)
|
||||||
writesymbol(sym, f);
|
writesymbol(sym, f);
|
||||||
|
|
||||||
for (struct Section § : sectionList)
|
for (Section § : sectionList)
|
||||||
writesection(sect, f);
|
writesection(sect, f);
|
||||||
|
|
||||||
putlong(assertions.size(), f);
|
putlong(assertions.size(), f);
|
||||||
|
|
||||||
for (struct Assertion &assert : assertions)
|
for (Assertion &assert : assertions)
|
||||||
writeassert(assert, f);
|
writeassert(assert, f);
|
||||||
|
|
||||||
fclose(f);
|
fclose(f);
|
||||||
|
|||||||
@@ -31,7 +31,7 @@
|
|||||||
#include "linkdefs.hpp"
|
#include "linkdefs.hpp"
|
||||||
#include "platform.hpp" // strncasecmp, strdup
|
#include "platform.hpp" // strncasecmp, strdup
|
||||||
|
|
||||||
static struct CaptureBody captureBody; // Captures a REPT/FOR or MACRO
|
static CaptureBody captureBody; // Captures a REPT/FOR or MACRO
|
||||||
|
|
||||||
static void upperstring(char *dest, char const *src)
|
static void upperstring(char *dest, char const *src)
|
||||||
{
|
{
|
||||||
@@ -256,7 +256,7 @@ static void strrpl(char *dest, size_t destLen, char const *src, char const *old,
|
|||||||
dest[i] = '\0';
|
dest[i] = '\0';
|
||||||
}
|
}
|
||||||
|
|
||||||
static void initStrFmtArgList(struct StrFmtArgList *args)
|
static void initStrFmtArgList(StrFmtArgList *args)
|
||||||
{
|
{
|
||||||
args->args = new(std::nothrow) std::vector<std::variant<uint32_t, char *>>();
|
args->args = new(std::nothrow) std::vector<std::variant<uint32_t, char *>>();
|
||||||
if (!args->args)
|
if (!args->args)
|
||||||
@@ -264,7 +264,7 @@ static void initStrFmtArgList(struct StrFmtArgList *args)
|
|||||||
strerror(errno));
|
strerror(errno));
|
||||||
}
|
}
|
||||||
|
|
||||||
static void freeStrFmtArgList(struct StrFmtArgList *args)
|
static void freeStrFmtArgList(StrFmtArgList *args)
|
||||||
{
|
{
|
||||||
free(args->format);
|
free(args->format);
|
||||||
for (std::variant<uint32_t, char *> &arg : *args->args) {
|
for (std::variant<uint32_t, char *> &arg : *args->args) {
|
||||||
@@ -297,7 +297,7 @@ static void strfmt(char *dest, size_t destLen, char const *fmt,
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
struct FormatSpec spec = fmt_NewSpec();
|
FormatSpec spec = fmt_NewSpec();
|
||||||
|
|
||||||
while (c != '\0') {
|
while (c != '\0') {
|
||||||
fmt_UseCharacter(&spec, c);
|
fmt_UseCharacter(&spec, c);
|
||||||
@@ -347,7 +347,7 @@ static void strfmt(char *dest, size_t destLen, char const *fmt,
|
|||||||
}
|
}
|
||||||
|
|
||||||
static void compoundAssignment(const char *symName, enum RPNCommand op, int32_t constValue) {
|
static void compoundAssignment(const char *symName, enum RPNCommand op, int32_t constValue) {
|
||||||
struct Expression oldExpr, constExpr, newExpr;
|
Expression oldExpr, constExpr, newExpr;
|
||||||
int32_t newValue;
|
int32_t newValue;
|
||||||
|
|
||||||
rpn_Symbol(&oldExpr, symName);
|
rpn_Symbol(&oldExpr, symName);
|
||||||
@@ -357,9 +357,9 @@ static void compoundAssignment(const char *symName, enum RPNCommand op, int32_t
|
|||||||
sym_AddVar(symName, newValue);
|
sym_AddVar(symName, newValue);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void initDsArgList(std::vector<struct Expression> *&args)
|
static void initDsArgList(std::vector<Expression> *&args)
|
||||||
{
|
{
|
||||||
args = new(std::nothrow) std::vector<struct Expression>();
|
args = new(std::nothrow) std::vector<Expression>();
|
||||||
if (!args)
|
if (!args)
|
||||||
fatalerror("Failed to allocate memory for ds arg list: %s\n", strerror(errno));
|
fatalerror("Failed to allocate memory for ds arg list: %s\n", strerror(errno));
|
||||||
}
|
}
|
||||||
@@ -455,18 +455,18 @@ enum {
|
|||||||
{
|
{
|
||||||
char symName[MAXSYMLEN + 1];
|
char symName[MAXSYMLEN + 1];
|
||||||
char string[MAXSTRLEN + 1];
|
char string[MAXSTRLEN + 1];
|
||||||
struct Expression expr;
|
Expression expr;
|
||||||
int32_t constValue;
|
int32_t constValue;
|
||||||
enum RPNCommand compoundEqual;
|
enum RPNCommand compoundEqual;
|
||||||
enum SectionModifier sectMod;
|
enum SectionModifier sectMod;
|
||||||
struct SectionSpec sectSpec;
|
SectionSpec sectSpec;
|
||||||
struct MacroArgs *macroArg;
|
MacroArgs *macroArg;
|
||||||
enum AssertionType assertType;
|
enum AssertionType assertType;
|
||||||
struct AlignmentSpec alignSpec;
|
AlignmentSpec alignSpec;
|
||||||
std::vector<struct Expression> *dsArgs;
|
std::vector<Expression> *dsArgs;
|
||||||
std::vector<std::string> *purgeArgs;
|
std::vector<std::string> *purgeArgs;
|
||||||
struct ForArgs forArgs;
|
ForArgs forArgs;
|
||||||
struct StrFmtArgList strfmtArgs;
|
StrFmtArgList strfmtArgs;
|
||||||
bool captureTerminated;
|
bool captureTerminated;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -704,7 +704,7 @@ line : plain_directive endofline
|
|||||||
lexer_SetMode(LEXER_NORMAL);
|
lexer_SetMode(LEXER_NORMAL);
|
||||||
lexer_ToggleStringExpansion(true);
|
lexer_ToggleStringExpansion(true);
|
||||||
} endofline {
|
} endofline {
|
||||||
struct Symbol *macro = sym_FindExactSymbol($1);
|
Symbol *macro = sym_FindExactSymbol($1);
|
||||||
|
|
||||||
if (macro && macro->type == SYM_MACRO)
|
if (macro && macro->type == SYM_MACRO)
|
||||||
fprintf(stderr,
|
fprintf(stderr,
|
||||||
@@ -1649,11 +1649,11 @@ string : T_STRING
|
|||||||
freeStrFmtArgList(&$3);
|
freeStrFmtArgList(&$3);
|
||||||
}
|
}
|
||||||
| T_POP_SECTION T_LPAREN scoped_anon_id T_RPAREN {
|
| T_POP_SECTION T_LPAREN scoped_anon_id T_RPAREN {
|
||||||
struct Symbol *sym = sym_FindScopedValidSymbol($3);
|
Symbol *sym = sym_FindScopedValidSymbol($3);
|
||||||
|
|
||||||
if (!sym)
|
if (!sym)
|
||||||
fatalerror("Unknown symbol \"%s\"\n", $3);
|
fatalerror("Unknown symbol \"%s\"\n", $3);
|
||||||
struct Section const *section = sym_GetSection(sym);
|
Section const *section = sym_GetSection(sym);
|
||||||
|
|
||||||
if (!section)
|
if (!section)
|
||||||
fatalerror("\"%s\" does not belong to any section\n", sym->name);
|
fatalerror("\"%s\" does not belong to any section\n", sym->name);
|
||||||
|
|||||||
@@ -23,7 +23,7 @@
|
|||||||
|
|
||||||
// Makes an expression "not known", also setting its error message
|
// Makes an expression "not known", also setting its error message
|
||||||
template<typename... Ts>
|
template<typename... Ts>
|
||||||
static void makeUnknown(struct Expression *expr, Ts ...parts)
|
static void makeUnknown(Expression *expr, Ts ...parts)
|
||||||
{
|
{
|
||||||
expr->isKnown = false;
|
expr->isKnown = false;
|
||||||
expr->reason = new std::string();
|
expr->reason = new std::string();
|
||||||
@@ -32,7 +32,7 @@ static void makeUnknown(struct Expression *expr, Ts ...parts)
|
|||||||
(expr->reason->append(parts), ...);
|
(expr->reason->append(parts), ...);
|
||||||
}
|
}
|
||||||
|
|
||||||
static uint8_t *reserveSpace(struct Expression *expr, uint32_t size)
|
static uint8_t *reserveSpace(Expression *expr, uint32_t size)
|
||||||
{
|
{
|
||||||
if (!expr->rpn) {
|
if (!expr->rpn) {
|
||||||
expr->rpn = new(std::nothrow) std::vector<uint8_t>();
|
expr->rpn = new(std::nothrow) std::vector<uint8_t>();
|
||||||
@@ -47,7 +47,7 @@ static uint8_t *reserveSpace(struct Expression *expr, uint32_t size)
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Init a RPN expression
|
// Init a RPN expression
|
||||||
static void rpn_Init(struct Expression *expr)
|
static void rpn_Init(Expression *expr)
|
||||||
{
|
{
|
||||||
expr->reason = NULL;
|
expr->reason = NULL;
|
||||||
expr->isKnown = true;
|
expr->isKnown = true;
|
||||||
@@ -57,7 +57,7 @@ static void rpn_Init(struct Expression *expr)
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Free the RPN expression
|
// Free the RPN expression
|
||||||
void rpn_Free(struct Expression *expr)
|
void rpn_Free(Expression *expr)
|
||||||
{
|
{
|
||||||
delete expr->rpn;
|
delete expr->rpn;
|
||||||
delete expr->reason;
|
delete expr->reason;
|
||||||
@@ -65,15 +65,15 @@ void rpn_Free(struct Expression *expr)
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Add symbols, constants and operators to expression
|
// Add symbols, constants and operators to expression
|
||||||
void rpn_Number(struct Expression *expr, uint32_t i)
|
void rpn_Number(Expression *expr, uint32_t i)
|
||||||
{
|
{
|
||||||
rpn_Init(expr);
|
rpn_Init(expr);
|
||||||
expr->val = i;
|
expr->val = i;
|
||||||
}
|
}
|
||||||
|
|
||||||
void rpn_Symbol(struct Expression *expr, char const *symName)
|
void rpn_Symbol(Expression *expr, char const *symName)
|
||||||
{
|
{
|
||||||
struct Symbol *sym = sym_FindScopedSymbol(symName);
|
Symbol *sym = sym_FindScopedSymbol(symName);
|
||||||
|
|
||||||
if (sym_IsPC(sym) && !sect_GetSymbolSection()) {
|
if (sym_IsPC(sym) && !sect_GetSymbolSection()) {
|
||||||
error("PC has no value outside a section\n");
|
error("PC has no value outside a section\n");
|
||||||
@@ -98,7 +98,7 @@ void rpn_Symbol(struct Expression *expr, char const *symName)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void rpn_BankSelf(struct Expression *expr)
|
void rpn_BankSelf(Expression *expr)
|
||||||
{
|
{
|
||||||
rpn_Init(expr);
|
rpn_Init(expr);
|
||||||
|
|
||||||
@@ -114,9 +114,9 @@ void rpn_BankSelf(struct Expression *expr)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void rpn_BankSymbol(struct Expression *expr, char const *symName)
|
void rpn_BankSymbol(Expression *expr, char const *symName)
|
||||||
{
|
{
|
||||||
struct Symbol const *sym = sym_FindScopedSymbol(symName);
|
Symbol const *sym = sym_FindScopedSymbol(symName);
|
||||||
|
|
||||||
// The @ symbol is treated differently.
|
// The @ symbol is treated differently.
|
||||||
if (sym_IsPC(sym)) {
|
if (sym_IsPC(sym)) {
|
||||||
@@ -146,11 +146,11 @@ void rpn_BankSymbol(struct Expression *expr, char const *symName)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void rpn_BankSection(struct Expression *expr, char const *sectionName)
|
void rpn_BankSection(Expression *expr, char const *sectionName)
|
||||||
{
|
{
|
||||||
rpn_Init(expr);
|
rpn_Init(expr);
|
||||||
|
|
||||||
struct Section *section = sect_FindSectionByName(sectionName);
|
Section *section = sect_FindSectionByName(sectionName);
|
||||||
|
|
||||||
if (section && section->bank != (uint32_t)-1) {
|
if (section && section->bank != (uint32_t)-1) {
|
||||||
expr->val = section->bank;
|
expr->val = section->bank;
|
||||||
@@ -166,11 +166,11 @@ void rpn_BankSection(struct Expression *expr, char const *sectionName)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void rpn_SizeOfSection(struct Expression *expr, char const *sectionName)
|
void rpn_SizeOfSection(Expression *expr, char const *sectionName)
|
||||||
{
|
{
|
||||||
rpn_Init(expr);
|
rpn_Init(expr);
|
||||||
|
|
||||||
struct Section *section = sect_FindSectionByName(sectionName);
|
Section *section = sect_FindSectionByName(sectionName);
|
||||||
|
|
||||||
if (section && sect_IsSizeKnown(section)) {
|
if (section && sect_IsSizeKnown(section)) {
|
||||||
expr->val = section->size;
|
expr->val = section->size;
|
||||||
@@ -186,11 +186,11 @@ void rpn_SizeOfSection(struct Expression *expr, char const *sectionName)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void rpn_StartOfSection(struct Expression *expr, char const *sectionName)
|
void rpn_StartOfSection(Expression *expr, char const *sectionName)
|
||||||
{
|
{
|
||||||
rpn_Init(expr);
|
rpn_Init(expr);
|
||||||
|
|
||||||
struct Section *section = sect_FindSectionByName(sectionName);
|
Section *section = sect_FindSectionByName(sectionName);
|
||||||
|
|
||||||
if (section && section->org != (uint32_t)-1) {
|
if (section && section->org != (uint32_t)-1) {
|
||||||
expr->val = section->org;
|
expr->val = section->org;
|
||||||
@@ -206,7 +206,7 @@ void rpn_StartOfSection(struct Expression *expr, char const *sectionName)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void rpn_SizeOfSectionType(struct Expression *expr, enum SectionType type)
|
void rpn_SizeOfSectionType(Expression *expr, enum SectionType type)
|
||||||
{
|
{
|
||||||
rpn_Init(expr);
|
rpn_Init(expr);
|
||||||
makeUnknown(expr, "Section type's size is not known");
|
makeUnknown(expr, "Section type's size is not known");
|
||||||
@@ -218,7 +218,7 @@ void rpn_SizeOfSectionType(struct Expression *expr, enum SectionType type)
|
|||||||
*ptr++ = type;
|
*ptr++ = type;
|
||||||
}
|
}
|
||||||
|
|
||||||
void rpn_StartOfSectionType(struct Expression *expr, enum SectionType type)
|
void rpn_StartOfSectionType(Expression *expr, enum SectionType type)
|
||||||
{
|
{
|
||||||
rpn_Init(expr);
|
rpn_Init(expr);
|
||||||
makeUnknown(expr, "Section type's start is not known");
|
makeUnknown(expr, "Section type's start is not known");
|
||||||
@@ -230,7 +230,7 @@ void rpn_StartOfSectionType(struct Expression *expr, enum SectionType type)
|
|||||||
*ptr++ = type;
|
*ptr++ = type;
|
||||||
}
|
}
|
||||||
|
|
||||||
void rpn_CheckHRAM(struct Expression *expr, const struct Expression *src)
|
void rpn_CheckHRAM(Expression *expr, const Expression *src)
|
||||||
{
|
{
|
||||||
*expr = *src;
|
*expr = *src;
|
||||||
expr->isSymbol = false;
|
expr->isSymbol = false;
|
||||||
@@ -246,7 +246,7 @@ void rpn_CheckHRAM(struct Expression *expr, const struct Expression *src)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void rpn_CheckRST(struct Expression *expr, const struct Expression *src)
|
void rpn_CheckRST(Expression *expr, const Expression *src)
|
||||||
{
|
{
|
||||||
*expr = *src;
|
*expr = *src;
|
||||||
|
|
||||||
@@ -263,7 +263,7 @@ void rpn_CheckRST(struct Expression *expr, const struct Expression *src)
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Checks that an RPN expression's value fits within N bits (signed or unsigned)
|
// Checks that an RPN expression's value fits within N bits (signed or unsigned)
|
||||||
void rpn_CheckNBit(struct Expression const *expr, uint8_t n)
|
void rpn_CheckNBit(Expression const *expr, uint8_t n)
|
||||||
{
|
{
|
||||||
assert(n != 0); // That doesn't make sense
|
assert(n != 0); // That doesn't make sense
|
||||||
assert(n < CHAR_BIT * sizeof(int)); // Otherwise `1 << n` is UB
|
assert(n < CHAR_BIT * sizeof(int)); // Otherwise `1 << n` is UB
|
||||||
@@ -278,7 +278,7 @@ void rpn_CheckNBit(struct Expression const *expr, uint8_t n)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
int32_t rpn_GetConstVal(struct Expression const *expr)
|
int32_t rpn_GetConstVal(Expression const *expr)
|
||||||
{
|
{
|
||||||
if (!rpn_isKnown(expr)) {
|
if (!rpn_isKnown(expr)) {
|
||||||
error("Expected constant expression: %s\n", expr->reason->c_str());
|
error("Expected constant expression: %s\n", expr->reason->c_str());
|
||||||
@@ -287,7 +287,7 @@ int32_t rpn_GetConstVal(struct Expression const *expr)
|
|||||||
return expr->val;
|
return expr->val;
|
||||||
}
|
}
|
||||||
|
|
||||||
void rpn_LOGNOT(struct Expression *expr, const struct Expression *src)
|
void rpn_LOGNOT(Expression *expr, const Expression *src)
|
||||||
{
|
{
|
||||||
*expr = *src;
|
*expr = *src;
|
||||||
expr->isSymbol = false;
|
expr->isSymbol = false;
|
||||||
@@ -300,28 +300,27 @@ void rpn_LOGNOT(struct Expression *expr, const struct Expression *src)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
struct Symbol const *rpn_SymbolOf(struct Expression const *expr)
|
Symbol const *rpn_SymbolOf(Expression const *expr)
|
||||||
{
|
{
|
||||||
if (!rpn_isSymbol(expr))
|
if (!rpn_isSymbol(expr))
|
||||||
return NULL;
|
return NULL;
|
||||||
return sym_FindScopedSymbol((char const *)&(*expr->rpn)[1]);
|
return sym_FindScopedSymbol((char const *)&(*expr->rpn)[1]);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool rpn_IsDiffConstant(struct Expression const *src, struct Symbol const *sym)
|
bool rpn_IsDiffConstant(Expression const *src, Symbol const *sym)
|
||||||
{
|
{
|
||||||
// Check if both expressions only refer to a single symbol
|
// Check if both expressions only refer to a single symbol
|
||||||
struct Symbol const *sym1 = rpn_SymbolOf(src);
|
Symbol const *sym1 = rpn_SymbolOf(src);
|
||||||
|
|
||||||
if (!sym1 || !sym || sym1->type != SYM_LABEL || sym->type != SYM_LABEL)
|
if (!sym1 || !sym || sym1->type != SYM_LABEL || sym->type != SYM_LABEL)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
struct Section const *section1 = sym_GetSection(sym1);
|
Section const *section1 = sym_GetSection(sym1);
|
||||||
struct Section const *section2 = sym_GetSection(sym);
|
Section const *section2 = sym_GetSection(sym);
|
||||||
return section1 && (section1 == section2);
|
return section1 && (section1 == section2);
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool isDiffConstant(struct Expression const *src1,
|
static bool isDiffConstant(Expression const *src1, Expression const *src2)
|
||||||
struct Expression const *src2)
|
|
||||||
{
|
{
|
||||||
return rpn_IsDiffConstant(src1, rpn_SymbolOf(src2));
|
return rpn_IsDiffConstant(src1, rpn_SymbolOf(src2));
|
||||||
}
|
}
|
||||||
@@ -333,10 +332,10 @@ static bool isDiffConstant(struct Expression const *src1,
|
|||||||
*
|
*
|
||||||
* @return The constant result if it can be computed, or -1 otherwise.
|
* @return The constant result if it can be computed, or -1 otherwise.
|
||||||
*/
|
*/
|
||||||
static int32_t tryConstMask(struct Expression const *lhs, struct Expression const *rhs)
|
static int32_t tryConstMask(Expression const *lhs, Expression const *rhs)
|
||||||
{
|
{
|
||||||
struct Symbol const *sym = rpn_SymbolOf(lhs);
|
Symbol const *sym = rpn_SymbolOf(lhs);
|
||||||
struct Expression const *expr = rhs;
|
Expression const *expr = rhs;
|
||||||
|
|
||||||
if (!sym || !sym_GetSection(sym)) {
|
if (!sym || !sym_GetSection(sym)) {
|
||||||
// If the lhs isn't a symbol, try again the other way around
|
// If the lhs isn't a symbol, try again the other way around
|
||||||
@@ -351,7 +350,7 @@ static int32_t tryConstMask(struct Expression const *lhs, struct Expression cons
|
|||||||
if (!rpn_isKnown(expr))
|
if (!rpn_isKnown(expr))
|
||||||
return -1;
|
return -1;
|
||||||
// We can now safely use `expr->val`
|
// We can now safely use `expr->val`
|
||||||
struct Section const *sect = sym_GetSection(sym);
|
Section const *sect = sym_GetSection(sym);
|
||||||
int32_t unknownBits = (1 << 16) - (1 << sect->align); // The max alignment is 16
|
int32_t unknownBits = (1 << 16) - (1 << sect->align); // The max alignment is 16
|
||||||
|
|
||||||
// The mask must ignore all unknown bits
|
// The mask must ignore all unknown bits
|
||||||
@@ -366,8 +365,7 @@ static int32_t tryConstMask(struct Expression const *lhs, struct Expression cons
|
|||||||
return (symbolOfs + sect->alignOfs) & ~unknownBits;
|
return (symbolOfs + sect->alignOfs) & ~unknownBits;
|
||||||
}
|
}
|
||||||
|
|
||||||
void rpn_BinaryOp(enum RPNCommand op, struct Expression *expr,
|
void rpn_BinaryOp(enum RPNCommand op, Expression *expr, const Expression *src1, const Expression *src2)
|
||||||
const struct Expression *src1, const struct Expression *src2)
|
|
||||||
{
|
{
|
||||||
expr->isSymbol = false;
|
expr->isSymbol = false;
|
||||||
int32_t constMaskVal;
|
int32_t constMaskVal;
|
||||||
@@ -512,8 +510,8 @@ void rpn_BinaryOp(enum RPNCommand op, struct Expression *expr,
|
|||||||
}
|
}
|
||||||
|
|
||||||
} else if (op == RPN_SUB && isDiffConstant(src1, src2)) {
|
} else if (op == RPN_SUB && isDiffConstant(src1, src2)) {
|
||||||
struct Symbol const *symbol1 = rpn_SymbolOf(src1);
|
Symbol const *symbol1 = rpn_SymbolOf(src1);
|
||||||
struct Symbol const *symbol2 = rpn_SymbolOf(src2);
|
Symbol const *symbol2 = rpn_SymbolOf(src2);
|
||||||
|
|
||||||
expr->val = sym_GetValue(symbol1) - sym_GetValue(symbol2);
|
expr->val = sym_GetValue(symbol1) - sym_GetValue(symbol2);
|
||||||
expr->isKnown = true;
|
expr->isKnown = true;
|
||||||
@@ -574,7 +572,7 @@ void rpn_BinaryOp(enum RPNCommand op, struct Expression *expr,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void rpn_HIGH(struct Expression *expr, const struct Expression *src)
|
void rpn_HIGH(Expression *expr, const Expression *src)
|
||||||
{
|
{
|
||||||
*expr = *src;
|
*expr = *src;
|
||||||
expr->isSymbol = false;
|
expr->isSymbol = false;
|
||||||
@@ -589,7 +587,7 @@ void rpn_HIGH(struct Expression *expr, const struct Expression *src)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void rpn_LOW(struct Expression *expr, const struct Expression *src)
|
void rpn_LOW(Expression *expr, const Expression *src)
|
||||||
{
|
{
|
||||||
*expr = *src;
|
*expr = *src;
|
||||||
expr->isSymbol = false;
|
expr->isSymbol = false;
|
||||||
@@ -604,7 +602,7 @@ void rpn_LOW(struct Expression *expr, const struct Expression *src)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void rpn_ISCONST(struct Expression *expr, const struct Expression *src)
|
void rpn_ISCONST(Expression *expr, const Expression *src)
|
||||||
{
|
{
|
||||||
rpn_Init(expr);
|
rpn_Init(expr);
|
||||||
expr->val = rpn_isKnown(src);
|
expr->val = rpn_isKnown(src);
|
||||||
@@ -612,7 +610,7 @@ void rpn_ISCONST(struct Expression *expr, const struct Expression *src)
|
|||||||
expr->isSymbol = false;
|
expr->isSymbol = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
void rpn_NEG(struct Expression *expr, const struct Expression *src)
|
void rpn_NEG(Expression *expr, const Expression *src)
|
||||||
{
|
{
|
||||||
*expr = *src;
|
*expr = *src;
|
||||||
expr->isSymbol = false;
|
expr->isSymbol = false;
|
||||||
@@ -625,7 +623,7 @@ void rpn_NEG(struct Expression *expr, const struct Expression *src)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void rpn_NOT(struct Expression *expr, const struct Expression *src)
|
void rpn_NOT(Expression *expr, const Expression *src)
|
||||||
{
|
{
|
||||||
*expr = *src;
|
*expr = *src;
|
||||||
expr->isSymbol = false;
|
expr->isSymbol = false;
|
||||||
|
|||||||
@@ -33,20 +33,20 @@ struct UnionStackEntry {
|
|||||||
};
|
};
|
||||||
|
|
||||||
struct SectionStackEntry {
|
struct SectionStackEntry {
|
||||||
struct Section *section;
|
Section *section;
|
||||||
struct Section *loadSection;
|
Section *loadSection;
|
||||||
char const *scope; // Section's symbol scope
|
char const *scope; // Section's symbol scope
|
||||||
uint32_t offset;
|
uint32_t offset;
|
||||||
int32_t loadOffset;
|
int32_t loadOffset;
|
||||||
std::stack<struct UnionStackEntry> unionStack;
|
std::stack<UnionStackEntry> unionStack;
|
||||||
};
|
};
|
||||||
|
|
||||||
std::stack<struct UnionStackEntry> currentUnionStack;
|
std::stack<UnionStackEntry> currentUnionStack;
|
||||||
std::deque<struct SectionStackEntry> sectionStack;
|
std::deque<SectionStackEntry> sectionStack;
|
||||||
std::deque<struct Section> sectionList;
|
std::deque<Section> sectionList;
|
||||||
uint32_t curOffset; // Offset into the current section (see sect_GetSymbolOffset)
|
uint32_t curOffset; // Offset into the current section (see sect_GetSymbolOffset)
|
||||||
struct Section *currentSection = NULL;
|
Section *currentSection = NULL;
|
||||||
static struct Section *currentLoadSection = NULL;
|
static Section *currentLoadSection = NULL;
|
||||||
char const *currentLoadScope = NULL;
|
char const *currentLoadScope = NULL;
|
||||||
int32_t loadOffset; // Offset into the LOAD section's parent (see sect_GetOutputOffset)
|
int32_t loadOffset; // Offset into the LOAD section's parent (see sect_GetOutputOffset)
|
||||||
|
|
||||||
@@ -75,7 +75,7 @@ attr_(warn_unused_result) static bool checkcodesection(void)
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
attr_(warn_unused_result) static bool checkSectionSize(struct Section const *sect, uint32_t size)
|
attr_(warn_unused_result) static bool checkSectionSize(Section const *sect, uint32_t size)
|
||||||
{
|
{
|
||||||
uint32_t maxSize = sectionTypeInfo[sect->type].size;
|
uint32_t maxSize = sectionTypeInfo[sect->type].size;
|
||||||
|
|
||||||
@@ -110,9 +110,9 @@ attr_(warn_unused_result) static bool reserveSpace(uint32_t delta_size)
|
|||||||
&& (!currentLoadSection || currentLoadSection->size != UINT32_MAX);
|
&& (!currentLoadSection || currentLoadSection->size != UINT32_MAX);
|
||||||
}
|
}
|
||||||
|
|
||||||
struct Section *sect_FindSectionByName(char const *name)
|
Section *sect_FindSectionByName(char const *name)
|
||||||
{
|
{
|
||||||
for (struct Section § : sectionList) {
|
for (Section § : sectionList) {
|
||||||
if (strcmp(name, sect.name) == 0)
|
if (strcmp(name, sect.name) == 0)
|
||||||
return §
|
return §
|
||||||
}
|
}
|
||||||
@@ -126,7 +126,7 @@ do { \
|
|||||||
nbSectErrors++; \
|
nbSectErrors++; \
|
||||||
} while (0)
|
} while (0)
|
||||||
|
|
||||||
static unsigned int mergeSectUnion(struct Section *sect, enum SectionType type, uint32_t org,
|
static unsigned int mergeSectUnion(Section *sect, enum SectionType type, uint32_t org,
|
||||||
uint8_t alignment, uint16_t alignOffset)
|
uint8_t alignment, uint16_t alignOffset)
|
||||||
{
|
{
|
||||||
assert(alignment < 16); // Should be ensured by the caller
|
assert(alignment < 16); // Should be ensured by the caller
|
||||||
@@ -171,8 +171,7 @@ static unsigned int mergeSectUnion(struct Section *sect, enum SectionType type,
|
|||||||
return nbSectErrors;
|
return nbSectErrors;
|
||||||
}
|
}
|
||||||
|
|
||||||
static unsigned int mergeFragments(struct Section *sect, uint32_t org, uint8_t alignment,
|
static unsigned int mergeFragments(Section *sect, uint32_t org, uint8_t alignment, uint16_t alignOffset)
|
||||||
uint16_t alignOffset)
|
|
||||||
{
|
{
|
||||||
assert(alignment < 16); // Should be ensured by the caller
|
assert(alignment < 16); // Should be ensured by the caller
|
||||||
unsigned int nbSectErrors = 0;
|
unsigned int nbSectErrors = 0;
|
||||||
@@ -220,7 +219,7 @@ static unsigned int mergeFragments(struct Section *sect, uint32_t org, uint8_t a
|
|||||||
return nbSectErrors;
|
return nbSectErrors;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void mergeSections(struct Section *sect, enum SectionType type, uint32_t org, uint32_t bank,
|
static void mergeSections(Section *sect, enum SectionType type, uint32_t org, uint32_t bank,
|
||||||
uint8_t alignment, uint16_t alignOffset, enum SectionModifier mod)
|
uint8_t alignment, uint16_t alignOffset, enum SectionModifier mod)
|
||||||
{
|
{
|
||||||
unsigned int nbSectErrors = 0;
|
unsigned int nbSectErrors = 0;
|
||||||
@@ -265,12 +264,11 @@ static void mergeSections(struct Section *sect, enum SectionType type, uint32_t
|
|||||||
#undef fail
|
#undef fail
|
||||||
|
|
||||||
// Create a new section, not yet in the list.
|
// Create a new section, not yet in the list.
|
||||||
static struct Section *createSection(char const *name, enum SectionType type,
|
static Section *createSection(char const *name, enum SectionType type, uint32_t org, uint32_t bank,
|
||||||
uint32_t org, uint32_t bank, uint8_t alignment,
|
uint8_t alignment, uint16_t alignOffset, enum SectionModifier mod)
|
||||||
uint16_t alignOffset, enum SectionModifier mod)
|
|
||||||
{
|
{
|
||||||
// Add the new section to the list (order doesn't matter)
|
// Add the new section to the list (order doesn't matter)
|
||||||
struct Section § = sectionList.emplace_front();
|
Section § = sectionList.emplace_front();
|
||||||
|
|
||||||
sect.name = strdup(name);
|
sect.name = strdup(name);
|
||||||
if (sect.name == NULL)
|
if (sect.name == NULL)
|
||||||
@@ -294,8 +292,8 @@ static struct Section *createSection(char const *name, enum SectionType type,
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Find a section by name and type. If it doesn't exist, create it.
|
// Find a section by name and type. If it doesn't exist, create it.
|
||||||
static struct Section *getSection(char const *name, enum SectionType type, uint32_t org,
|
static Section *getSection(char const *name, enum SectionType type, uint32_t org,
|
||||||
struct SectionSpec const *attrs, enum SectionModifier mod)
|
SectionSpec const *attrs, enum SectionModifier mod)
|
||||||
{
|
{
|
||||||
uint32_t bank = attrs->bank;
|
uint32_t bank = attrs->bank;
|
||||||
uint8_t alignment = attrs->alignment;
|
uint8_t alignment = attrs->alignment;
|
||||||
@@ -357,7 +355,7 @@ static struct Section *getSection(char const *name, enum SectionType type, uint3
|
|||||||
|
|
||||||
// Check if another section exists with the same name; merge if yes, otherwise create one
|
// Check if another section exists with the same name; merge if yes, otherwise create one
|
||||||
|
|
||||||
struct Section *sect = sect_FindSectionByName(name);
|
Section *sect = sect_FindSectionByName(name);
|
||||||
|
|
||||||
if (sect) {
|
if (sect) {
|
||||||
mergeSections(sect, type, org, bank, alignment, alignOffset, mod);
|
mergeSections(sect, type, org, bank, alignment, alignOffset, mod);
|
||||||
@@ -379,17 +377,17 @@ static void changeSection(void)
|
|||||||
|
|
||||||
// Set the current section by name and type
|
// Set the current section by name and type
|
||||||
void sect_NewSection(char const *name, enum SectionType type, uint32_t org,
|
void sect_NewSection(char const *name, enum SectionType type, uint32_t org,
|
||||||
struct SectionSpec const *attribs, enum SectionModifier mod)
|
SectionSpec const *attribs, enum SectionModifier mod)
|
||||||
{
|
{
|
||||||
if (currentLoadSection)
|
if (currentLoadSection)
|
||||||
fatalerror("Cannot change the section within a `LOAD` block\n");
|
fatalerror("Cannot change the section within a `LOAD` block\n");
|
||||||
|
|
||||||
for (struct SectionStackEntry &entry : sectionStack) {
|
for (SectionStackEntry &entry : sectionStack) {
|
||||||
if (entry.section && !strcmp(name, entry.section->name))
|
if (entry.section && !strcmp(name, entry.section->name))
|
||||||
fatalerror("Section '%s' is already on the stack\n", name);
|
fatalerror("Section '%s' is already on the stack\n", name);
|
||||||
}
|
}
|
||||||
|
|
||||||
struct Section *sect = getSection(name, type, org, attribs, mod);
|
Section *sect = getSection(name, type, org, attribs, mod);
|
||||||
|
|
||||||
changeSection();
|
changeSection();
|
||||||
curOffset = mod == SECTION_UNION ? 0 : sect->size;
|
curOffset = mod == SECTION_UNION ? 0 : sect->size;
|
||||||
@@ -399,7 +397,7 @@ void sect_NewSection(char const *name, enum SectionType type, uint32_t org,
|
|||||||
|
|
||||||
// Set the current section by name and type
|
// Set the current section by name and type
|
||||||
void sect_SetLoadSection(char const *name, enum SectionType type, uint32_t org,
|
void sect_SetLoadSection(char const *name, enum SectionType type, uint32_t org,
|
||||||
struct SectionSpec const *attribs, enum SectionModifier mod)
|
SectionSpec const *attribs, enum SectionModifier mod)
|
||||||
{
|
{
|
||||||
// Important info: currently, UNION and LOAD cannot interact, since UNION is prohibited in
|
// Important info: currently, UNION and LOAD cannot interact, since UNION is prohibited in
|
||||||
// "code" sections, whereas LOAD is restricted to them.
|
// "code" sections, whereas LOAD is restricted to them.
|
||||||
@@ -424,7 +422,7 @@ void sect_SetLoadSection(char const *name, enum SectionType type, uint32_t org,
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
struct Section *sect = getSection(name, type, org, attribs, mod);
|
Section *sect = getSection(name, type, org, attribs, mod);
|
||||||
|
|
||||||
currentLoadScope = sym_GetCurrentSymbolScope();
|
currentLoadScope = sym_GetCurrentSymbolScope();
|
||||||
changeSection();
|
changeSection();
|
||||||
@@ -447,7 +445,7 @@ void sect_EndLoadSection(void)
|
|||||||
sym_SetCurrentSymbolScope(currentLoadScope);
|
sym_SetCurrentSymbolScope(currentLoadScope);
|
||||||
}
|
}
|
||||||
|
|
||||||
struct Section *sect_GetSymbolSection(void)
|
Section *sect_GetSymbolSection(void)
|
||||||
{
|
{
|
||||||
return currentLoadSection ? currentLoadSection : currentSection;
|
return currentLoadSection ? currentLoadSection : currentSection;
|
||||||
}
|
}
|
||||||
@@ -466,7 +464,7 @@ uint32_t sect_GetOutputOffset(void)
|
|||||||
// Returns how many bytes need outputting for the specified alignment and offset to succeed
|
// Returns how many bytes need outputting for the specified alignment and offset to succeed
|
||||||
uint32_t sect_GetAlignBytes(uint8_t alignment, uint16_t offset)
|
uint32_t sect_GetAlignBytes(uint8_t alignment, uint16_t offset)
|
||||||
{
|
{
|
||||||
struct Section *sect = sect_GetSymbolSection();
|
Section *sect = sect_GetSymbolSection();
|
||||||
if (!sect)
|
if (!sect)
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
@@ -489,7 +487,7 @@ void sect_AlignPC(uint8_t alignment, uint16_t offset)
|
|||||||
if (!checksection())
|
if (!checksection())
|
||||||
return;
|
return;
|
||||||
|
|
||||||
struct Section *sect = sect_GetSymbolSection();
|
Section *sect = sect_GetSymbolSection();
|
||||||
uint32_t alignSize = 1 << alignment; // Size of an aligned "block"
|
uint32_t alignSize = 1 << alignment; // Size of an aligned "block"
|
||||||
|
|
||||||
if (sect->org != (uint32_t)-1) {
|
if (sect->org != (uint32_t)-1) {
|
||||||
@@ -544,7 +542,7 @@ static void writelong(uint32_t b)
|
|||||||
writebyte(b >> 24);
|
writebyte(b >> 24);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void createPatch(enum PatchType type, struct Expression const *expr, uint32_t pcShift)
|
static void createPatch(enum PatchType type, Expression const *expr, uint32_t pcShift)
|
||||||
{
|
{
|
||||||
out_CreatePatch(type, expr, sect_GetOutputOffset(), pcShift);
|
out_CreatePatch(type, expr, sect_GetOutputOffset(), pcShift);
|
||||||
}
|
}
|
||||||
@@ -570,7 +568,7 @@ void sect_StartUnion(void)
|
|||||||
|
|
||||||
static void endUnionMember(void)
|
static void endUnionMember(void)
|
||||||
{
|
{
|
||||||
struct UnionStackEntry &member = currentUnionStack.top();
|
UnionStackEntry &member = currentUnionStack.top();
|
||||||
uint32_t memberSize = curOffset - member.start;
|
uint32_t memberSize = curOffset - member.start;
|
||||||
|
|
||||||
if (memberSize > member.size)
|
if (memberSize > member.size)
|
||||||
@@ -670,7 +668,7 @@ void sect_Skip(uint32_t skip, bool ds)
|
|||||||
|
|
||||||
// Output a relocatable byte. Checking will be done to see if it
|
// Output a relocatable byte. Checking will be done to see if it
|
||||||
// is an absolute value in disguise.
|
// is an absolute value in disguise.
|
||||||
void sect_RelByte(struct Expression *expr, uint32_t pcShift)
|
void sect_RelByte(Expression *expr, uint32_t pcShift)
|
||||||
{
|
{
|
||||||
if (!checkcodesection())
|
if (!checkcodesection())
|
||||||
return;
|
return;
|
||||||
@@ -688,7 +686,7 @@ void sect_RelByte(struct Expression *expr, uint32_t pcShift)
|
|||||||
|
|
||||||
// Output several copies of a relocatable byte. Checking will be done to see if
|
// Output several copies of a relocatable byte. Checking will be done to see if
|
||||||
// it is an absolute value in disguise.
|
// it is an absolute value in disguise.
|
||||||
void sect_RelBytes(uint32_t n, std::vector<struct Expression> &exprs)
|
void sect_RelBytes(uint32_t n, std::vector<Expression> &exprs)
|
||||||
{
|
{
|
||||||
if (!checkcodesection())
|
if (!checkcodesection())
|
||||||
return;
|
return;
|
||||||
@@ -696,7 +694,7 @@ void sect_RelBytes(uint32_t n, std::vector<struct Expression> &exprs)
|
|||||||
return;
|
return;
|
||||||
|
|
||||||
for (uint32_t i = 0; i < n; i++) {
|
for (uint32_t i = 0; i < n; i++) {
|
||||||
struct Expression &expr = exprs[i % exprs.size()];
|
Expression &expr = exprs[i % exprs.size()];
|
||||||
|
|
||||||
if (!rpn_isKnown(&expr)) {
|
if (!rpn_isKnown(&expr)) {
|
||||||
createPatch(PATCHTYPE_BYTE, &expr, i);
|
createPatch(PATCHTYPE_BYTE, &expr, i);
|
||||||
@@ -706,13 +704,13 @@ void sect_RelBytes(uint32_t n, std::vector<struct Expression> &exprs)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
for (struct Expression &expr : exprs)
|
for (Expression &expr : exprs)
|
||||||
rpn_Free(&expr);
|
rpn_Free(&expr);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Output a relocatable word. Checking will be done to see if
|
// Output a relocatable word. Checking will be done to see if
|
||||||
// it's an absolute value in disguise.
|
// it's an absolute value in disguise.
|
||||||
void sect_RelWord(struct Expression *expr, uint32_t pcShift)
|
void sect_RelWord(Expression *expr, uint32_t pcShift)
|
||||||
{
|
{
|
||||||
if (!checkcodesection())
|
if (!checkcodesection())
|
||||||
return;
|
return;
|
||||||
@@ -730,7 +728,7 @@ void sect_RelWord(struct Expression *expr, uint32_t pcShift)
|
|||||||
|
|
||||||
// Output a relocatable longword. Checking will be done to see if
|
// Output a relocatable longword. Checking will be done to see if
|
||||||
// is an absolute value in disguise.
|
// is an absolute value in disguise.
|
||||||
void sect_RelLong(struct Expression *expr, uint32_t pcShift)
|
void sect_RelLong(Expression *expr, uint32_t pcShift)
|
||||||
{
|
{
|
||||||
if (!checkcodesection())
|
if (!checkcodesection())
|
||||||
return;
|
return;
|
||||||
@@ -748,19 +746,19 @@ void sect_RelLong(struct Expression *expr, uint32_t pcShift)
|
|||||||
|
|
||||||
// Output a PC-relative relocatable byte. Checking will be done to see if it
|
// Output a PC-relative relocatable byte. Checking will be done to see if it
|
||||||
// is an absolute value in disguise.
|
// is an absolute value in disguise.
|
||||||
void sect_PCRelByte(struct Expression *expr, uint32_t pcShift)
|
void sect_PCRelByte(Expression *expr, uint32_t pcShift)
|
||||||
{
|
{
|
||||||
if (!checkcodesection())
|
if (!checkcodesection())
|
||||||
return;
|
return;
|
||||||
if (!reserveSpace(1))
|
if (!reserveSpace(1))
|
||||||
return;
|
return;
|
||||||
struct Symbol const *pc = sym_GetPC();
|
Symbol const *pc = sym_GetPC();
|
||||||
|
|
||||||
if (!rpn_IsDiffConstant(expr, pc)) {
|
if (!rpn_IsDiffConstant(expr, pc)) {
|
||||||
createPatch(PATCHTYPE_JR, expr, pcShift);
|
createPatch(PATCHTYPE_JR, expr, pcShift);
|
||||||
writebyte(0);
|
writebyte(0);
|
||||||
} else {
|
} else {
|
||||||
struct Symbol const *sym = rpn_SymbolOf(expr);
|
Symbol const *sym = rpn_SymbolOf(expr);
|
||||||
// The offset wraps (jump from ROM to HRAM, for example)
|
// The offset wraps (jump from ROM to HRAM, for example)
|
||||||
int16_t offset;
|
int16_t offset;
|
||||||
|
|
||||||
@@ -948,7 +946,7 @@ void sect_PopSection(void)
|
|||||||
if (currentLoadSection)
|
if (currentLoadSection)
|
||||||
fatalerror("Cannot change the section within a `LOAD` block\n");
|
fatalerror("Cannot change the section within a `LOAD` block\n");
|
||||||
|
|
||||||
struct SectionStackEntry entry = sectionStack.front();
|
SectionStackEntry entry = sectionStack.front();
|
||||||
sectionStack.pop_front();
|
sectionStack.pop_front();
|
||||||
|
|
||||||
changeSection();
|
changeSection();
|
||||||
@@ -976,7 +974,7 @@ void sect_EndSection(void)
|
|||||||
sym_SetCurrentSymbolScope(NULL);
|
sym_SetCurrentSymbolScope(NULL);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool sect_IsSizeKnown(struct Section const NONNULL(sect))
|
bool sect_IsSizeKnown(Section const NONNULL(sect))
|
||||||
{
|
{
|
||||||
// SECTION UNION and SECTION FRAGMENT can still grow
|
// SECTION UNION and SECTION FRAGMENT can still grow
|
||||||
if (sect->modifier != SECTION_NORMAL)
|
if (sect->modifier != SECTION_NORMAL)
|
||||||
@@ -987,7 +985,7 @@ bool sect_IsSizeKnown(struct Section const NONNULL(sect))
|
|||||||
return false;
|
return false;
|
||||||
|
|
||||||
// Any section on the stack is still growing
|
// Any section on the stack is still growing
|
||||||
for (struct SectionStackEntry &entry : sectionStack) {
|
for (SectionStackEntry &entry : sectionStack) {
|
||||||
if (entry.section && !strcmp(sect->name, entry.section->name))
|
if (entry.section && !strcmp(sect->name, entry.section->name))
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -27,23 +27,23 @@
|
|||||||
#include "helpers.hpp"
|
#include "helpers.hpp"
|
||||||
#include "version.hpp"
|
#include "version.hpp"
|
||||||
|
|
||||||
std::map<std::string, struct Symbol> symbols;
|
std::map<std::string, Symbol> symbols;
|
||||||
|
|
||||||
static const char *labelScope; // Current section's label scope
|
static const char *labelScope; // Current section's label scope
|
||||||
static struct Symbol *PCSymbol;
|
static Symbol *PCSymbol;
|
||||||
static struct Symbol *_NARGSymbol;
|
static Symbol *_NARGSymbol;
|
||||||
static char savedTIME[256];
|
static char savedTIME[256];
|
||||||
static char savedDATE[256];
|
static char savedDATE[256];
|
||||||
static char savedTIMESTAMP_ISO8601_LOCAL[256];
|
static char savedTIMESTAMP_ISO8601_LOCAL[256];
|
||||||
static char savedTIMESTAMP_ISO8601_UTC[256];
|
static char savedTIMESTAMP_ISO8601_UTC[256];
|
||||||
static bool exportAll;
|
static bool exportAll;
|
||||||
|
|
||||||
bool sym_IsPC(struct Symbol const *sym)
|
bool sym_IsPC(Symbol const *sym)
|
||||||
{
|
{
|
||||||
return sym == PCSymbol;
|
return sym == PCSymbol;
|
||||||
}
|
}
|
||||||
|
|
||||||
void sym_ForEach(void (*callback)(struct Symbol *))
|
void sym_ForEach(void (*callback)(Symbol *))
|
||||||
{
|
{
|
||||||
for (auto &it : symbols)
|
for (auto &it : symbols)
|
||||||
callback(&it.second);
|
callback(&it.second);
|
||||||
@@ -60,13 +60,13 @@ static int32_t Callback_NARG(void)
|
|||||||
|
|
||||||
static int32_t CallbackPC(void)
|
static int32_t CallbackPC(void)
|
||||||
{
|
{
|
||||||
struct Section const *section = sect_GetSymbolSection();
|
Section const *section = sect_GetSymbolSection();
|
||||||
|
|
||||||
return section ? section->org + sect_GetSymbolOffset() : 0;
|
return section ? section->org + sect_GetSymbolOffset() : 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Get the value field of a symbol
|
// Get the value field of a symbol
|
||||||
int32_t sym_GetValue(struct Symbol const *sym)
|
int32_t sym_GetValue(Symbol const *sym)
|
||||||
{
|
{
|
||||||
if (sym_IsNumeric(sym) && sym->hasCallback)
|
if (sym_IsNumeric(sym) && sym->hasCallback)
|
||||||
return sym->numCallback();
|
return sym->numCallback();
|
||||||
@@ -78,7 +78,7 @@ int32_t sym_GetValue(struct Symbol const *sym)
|
|||||||
return sym->value;
|
return sym->value;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void dumpFilename(struct Symbol const *sym)
|
static void dumpFilename(Symbol const *sym)
|
||||||
{
|
{
|
||||||
if (sym->src)
|
if (sym->src)
|
||||||
fstk_Dump(sym->src, sym->fileLine);
|
fstk_Dump(sym->src, sym->fileLine);
|
||||||
@@ -89,16 +89,16 @@ static void dumpFilename(struct Symbol const *sym)
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Set a symbol's definition filename and line
|
// Set a symbol's definition filename and line
|
||||||
static void setSymbolFilename(struct Symbol *sym)
|
static void setSymbolFilename(Symbol *sym)
|
||||||
{
|
{
|
||||||
sym->src = fstk_GetFileStack();
|
sym->src = fstk_GetFileStack();
|
||||||
sym->fileLine = sym->src ? lexer_GetLineNo() : 0; // This is (NULL, 1) for built-ins
|
sym->fileLine = sym->src ? lexer_GetLineNo() : 0; // This is (NULL, 1) for built-ins
|
||||||
}
|
}
|
||||||
|
|
||||||
// Update a symbol's definition filename and line
|
// Update a symbol's definition filename and line
|
||||||
static void updateSymbolFilename(struct Symbol *sym)
|
static void updateSymbolFilename(Symbol *sym)
|
||||||
{
|
{
|
||||||
struct FileStackNode *oldSrc = sym->src;
|
FileStackNode *oldSrc = sym->src;
|
||||||
|
|
||||||
setSymbolFilename(sym);
|
setSymbolFilename(sym);
|
||||||
// If the old node was referenced, ensure the new one is
|
// If the old node was referenced, ensure the new one is
|
||||||
@@ -108,9 +108,9 @@ static void updateSymbolFilename(struct Symbol *sym)
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Create a new symbol by name
|
// Create a new symbol by name
|
||||||
static struct Symbol *createsymbol(char const *symName)
|
static Symbol *createsymbol(char const *symName)
|
||||||
{
|
{
|
||||||
struct Symbol &sym = symbols[symName];
|
Symbol &sym = symbols[symName];
|
||||||
|
|
||||||
if (snprintf(sym.name, MAXSYMLEN + 1, "%s", symName) > MAXSYMLEN)
|
if (snprintf(sym.name, MAXSYMLEN + 1, "%s", symName) > MAXSYMLEN)
|
||||||
warning(WARNING_LONG_STR, "Symbol name is too long: '%s'\n", symName);
|
warning(WARNING_LONG_STR, "Symbol name is too long: '%s'\n", symName);
|
||||||
@@ -138,7 +138,7 @@ static void fullSymbolName(char *output, size_t outputSize,
|
|||||||
fatalerror("Symbol name is too long: '%s%s'\n", scopeName, localName);
|
fatalerror("Symbol name is too long: '%s%s'\n", scopeName, localName);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void assignStringSymbol(struct Symbol *sym, char const *value)
|
static void assignStringSymbol(Symbol *sym, char const *value)
|
||||||
{
|
{
|
||||||
char *string = strdup(value);
|
char *string = strdup(value);
|
||||||
|
|
||||||
@@ -150,13 +150,13 @@ static void assignStringSymbol(struct Symbol *sym, char const *value)
|
|||||||
sym->equs.size = strlen(string);
|
sym->equs.size = strlen(string);
|
||||||
}
|
}
|
||||||
|
|
||||||
struct Symbol *sym_FindExactSymbol(char const *symName)
|
Symbol *sym_FindExactSymbol(char const *symName)
|
||||||
{
|
{
|
||||||
auto search = symbols.find(symName);
|
auto search = symbols.find(symName);
|
||||||
return search != symbols.end() ? &search->second : NULL;
|
return search != symbols.end() ? &search->second : NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
struct Symbol *sym_FindScopedSymbol(char const *symName)
|
Symbol *sym_FindScopedSymbol(char const *symName)
|
||||||
{
|
{
|
||||||
if (char const *localName = strchr(symName, '.'); localName) {
|
if (char const *localName = strchr(symName, '.'); localName) {
|
||||||
if (strchr(localName + 1, '.'))
|
if (strchr(localName + 1, '.'))
|
||||||
@@ -173,9 +173,9 @@ struct Symbol *sym_FindScopedSymbol(char const *symName)
|
|||||||
return sym_FindExactSymbol(symName);
|
return sym_FindExactSymbol(symName);
|
||||||
}
|
}
|
||||||
|
|
||||||
struct Symbol *sym_FindScopedValidSymbol(char const *symName)
|
Symbol *sym_FindScopedValidSymbol(char const *symName)
|
||||||
{
|
{
|
||||||
struct Symbol *sym = sym_FindScopedSymbol(symName);
|
Symbol *sym = sym_FindScopedSymbol(symName);
|
||||||
|
|
||||||
// `@` has no value outside a section
|
// `@` has no value outside a section
|
||||||
if (sym == PCSymbol && !sect_GetSymbolSection()) {
|
if (sym == PCSymbol && !sect_GetSymbolSection()) {
|
||||||
@@ -188,12 +188,12 @@ struct Symbol *sym_FindScopedValidSymbol(char const *symName)
|
|||||||
return sym;
|
return sym;
|
||||||
}
|
}
|
||||||
|
|
||||||
struct Symbol const *sym_GetPC(void)
|
Symbol const *sym_GetPC(void)
|
||||||
{
|
{
|
||||||
return PCSymbol;
|
return PCSymbol;
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool isReferenced(struct Symbol const *sym)
|
static bool isReferenced(Symbol const *sym)
|
||||||
{
|
{
|
||||||
return sym->ID != (uint32_t)-1;
|
return sym->ID != (uint32_t)-1;
|
||||||
}
|
}
|
||||||
@@ -201,7 +201,7 @@ static bool isReferenced(struct Symbol const *sym)
|
|||||||
// Purge a symbol
|
// Purge a symbol
|
||||||
void sym_Purge(std::string const &symName)
|
void sym_Purge(std::string const &symName)
|
||||||
{
|
{
|
||||||
struct Symbol *sym = sym_FindScopedValidSymbol(symName.c_str());
|
Symbol *sym = sym_FindScopedValidSymbol(symName.c_str());
|
||||||
|
|
||||||
if (!sym) {
|
if (!sym) {
|
||||||
error("'%s' not defined\n", symName.c_str());
|
error("'%s' not defined\n", symName.c_str());
|
||||||
@@ -223,7 +223,7 @@ void sym_Purge(std::string const &symName)
|
|||||||
|
|
||||||
uint32_t sym_GetPCValue(void)
|
uint32_t sym_GetPCValue(void)
|
||||||
{
|
{
|
||||||
struct Section const *sect = sect_GetSymbolSection();
|
Section const *sect = sect_GetSymbolSection();
|
||||||
|
|
||||||
if (!sect)
|
if (!sect)
|
||||||
error("PC has no value outside a section\n");
|
error("PC has no value outside a section\n");
|
||||||
@@ -235,7 +235,7 @@ uint32_t sym_GetPCValue(void)
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Return a constant symbol's value, assuming it's defined
|
// Return a constant symbol's value, assuming it's defined
|
||||||
uint32_t sym_GetConstantSymValue(struct Symbol const *sym)
|
uint32_t sym_GetConstantSymValue(Symbol const *sym)
|
||||||
{
|
{
|
||||||
if (sym == PCSymbol)
|
if (sym == PCSymbol)
|
||||||
return sym_GetPCValue();
|
return sym_GetPCValue();
|
||||||
@@ -250,7 +250,7 @@ uint32_t sym_GetConstantSymValue(struct Symbol const *sym)
|
|||||||
// Return a constant symbol's value
|
// Return a constant symbol's value
|
||||||
uint32_t sym_GetConstantValue(char const *symName)
|
uint32_t sym_GetConstantValue(char const *symName)
|
||||||
{
|
{
|
||||||
struct Symbol const *sym = sym_FindScopedSymbol(symName);
|
Symbol const *sym = sym_FindScopedSymbol(symName);
|
||||||
|
|
||||||
if (!sym)
|
if (!sym)
|
||||||
error("'%s' not defined\n", symName);
|
error("'%s' not defined\n", symName);
|
||||||
@@ -277,9 +277,9 @@ void sym_SetCurrentSymbolScope(char const *newScope)
|
|||||||
* @param symName The name of the symbol to create
|
* @param symName The name of the symbol to create
|
||||||
* @param numeric If false, the symbol may not have been referenced earlier
|
* @param numeric If false, the symbol may not have been referenced earlier
|
||||||
*/
|
*/
|
||||||
static struct Symbol *createNonrelocSymbol(char const *symName, bool numeric)
|
static Symbol *createNonrelocSymbol(char const *symName, bool numeric)
|
||||||
{
|
{
|
||||||
struct Symbol *sym = sym_FindExactSymbol(symName);
|
Symbol *sym = sym_FindExactSymbol(symName);
|
||||||
|
|
||||||
if (!sym) {
|
if (!sym) {
|
||||||
sym = createsymbol(symName);
|
sym = createsymbol(symName);
|
||||||
@@ -300,9 +300,9 @@ static struct Symbol *createNonrelocSymbol(char const *symName, bool numeric)
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Add an equated symbol
|
// Add an equated symbol
|
||||||
struct Symbol *sym_AddEqu(char const *symName, int32_t value)
|
Symbol *sym_AddEqu(char const *symName, int32_t value)
|
||||||
{
|
{
|
||||||
struct Symbol *sym = createNonrelocSymbol(symName, true);
|
Symbol *sym = createNonrelocSymbol(symName, true);
|
||||||
|
|
||||||
if (!sym)
|
if (!sym)
|
||||||
return NULL;
|
return NULL;
|
||||||
@@ -313,9 +313,9 @@ struct Symbol *sym_AddEqu(char const *symName, int32_t value)
|
|||||||
return sym;
|
return sym;
|
||||||
}
|
}
|
||||||
|
|
||||||
struct Symbol *sym_RedefEqu(char const *symName, int32_t value)
|
Symbol *sym_RedefEqu(char const *symName, int32_t value)
|
||||||
{
|
{
|
||||||
struct Symbol *sym = sym_FindExactSymbol(symName);
|
Symbol *sym = sym_FindExactSymbol(symName);
|
||||||
|
|
||||||
if (!sym)
|
if (!sym)
|
||||||
return sym_AddEqu(symName, value);
|
return sym_AddEqu(symName, value);
|
||||||
@@ -349,9 +349,9 @@ struct Symbol *sym_RedefEqu(char const *symName, int32_t value)
|
|||||||
* of the string are enough: sym_AddString("M_PI", "3.1415"). This is the same
|
* of the string are enough: sym_AddString("M_PI", "3.1415"). This is the same
|
||||||
* as ``` M_PI EQUS "3.1415" ```
|
* as ``` M_PI EQUS "3.1415" ```
|
||||||
*/
|
*/
|
||||||
struct Symbol *sym_AddString(char const *symName, char const *value)
|
Symbol *sym_AddString(char const *symName, char const *value)
|
||||||
{
|
{
|
||||||
struct Symbol *sym = createNonrelocSymbol(symName, false);
|
Symbol *sym = createNonrelocSymbol(symName, false);
|
||||||
|
|
||||||
if (!sym)
|
if (!sym)
|
||||||
return NULL;
|
return NULL;
|
||||||
@@ -360,9 +360,9 @@ struct Symbol *sym_AddString(char const *symName, char const *value)
|
|||||||
return sym;
|
return sym;
|
||||||
}
|
}
|
||||||
|
|
||||||
struct Symbol *sym_RedefString(char const *symName, char const *value)
|
Symbol *sym_RedefString(char const *symName, char const *value)
|
||||||
{
|
{
|
||||||
struct Symbol *sym = sym_FindExactSymbol(symName);
|
Symbol *sym = sym_FindExactSymbol(symName);
|
||||||
|
|
||||||
if (!sym)
|
if (!sym)
|
||||||
return sym_AddString(symName, value);
|
return sym_AddString(symName, value);
|
||||||
@@ -389,9 +389,9 @@ struct Symbol *sym_RedefString(char const *symName, char const *value)
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Alter a mutable symbol's value
|
// Alter a mutable symbol's value
|
||||||
struct Symbol *sym_AddVar(char const *symName, int32_t value)
|
Symbol *sym_AddVar(char const *symName, int32_t value)
|
||||||
{
|
{
|
||||||
struct Symbol *sym = sym_FindExactSymbol(symName);
|
Symbol *sym = sym_FindExactSymbol(symName);
|
||||||
|
|
||||||
if (!sym) {
|
if (!sym) {
|
||||||
sym = createsymbol(symName);
|
sym = createsymbol(symName);
|
||||||
@@ -416,10 +416,10 @@ struct Symbol *sym_AddVar(char const *symName, int32_t value)
|
|||||||
* @param symName The label's full name (so `.name` is invalid)
|
* @param symName The label's full name (so `.name` is invalid)
|
||||||
* @return The created symbol
|
* @return The created symbol
|
||||||
*/
|
*/
|
||||||
static struct Symbol *addLabel(char const *symName)
|
static Symbol *addLabel(char const *symName)
|
||||||
{
|
{
|
||||||
assert(symName[0] != '.'); // The symbol name must have been expanded prior
|
assert(symName[0] != '.'); // The symbol name must have been expanded prior
|
||||||
struct Symbol *sym = sym_FindExactSymbol(symName);
|
Symbol *sym = sym_FindExactSymbol(symName);
|
||||||
|
|
||||||
if (!sym) {
|
if (!sym) {
|
||||||
sym = createsymbol(symName);
|
sym = createsymbol(symName);
|
||||||
@@ -445,7 +445,7 @@ static struct Symbol *addLabel(char const *symName)
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Add a local (`.name` or `Parent.name`) relocatable symbol
|
// Add a local (`.name` or `Parent.name`) relocatable symbol
|
||||||
struct Symbol *sym_AddLocalLabel(char const *symName)
|
Symbol *sym_AddLocalLabel(char const *symName)
|
||||||
{
|
{
|
||||||
// Assuming no dots in `labelScope` if defined
|
// Assuming no dots in `labelScope` if defined
|
||||||
assert(!labelScope || !strchr(labelScope, '.'));
|
assert(!labelScope || !strchr(labelScope, '.'));
|
||||||
@@ -479,9 +479,9 @@ struct Symbol *sym_AddLocalLabel(char const *symName)
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Add a relocatable symbol
|
// Add a relocatable symbol
|
||||||
struct Symbol *sym_AddLabel(char const *symName)
|
Symbol *sym_AddLabel(char const *symName)
|
||||||
{
|
{
|
||||||
struct Symbol *sym = addLabel(symName);
|
Symbol *sym = addLabel(symName);
|
||||||
|
|
||||||
// Set the symbol as the new scope
|
// Set the symbol as the new scope
|
||||||
if (sym)
|
if (sym)
|
||||||
@@ -492,7 +492,7 @@ struct Symbol *sym_AddLabel(char const *symName)
|
|||||||
static uint32_t anonLabelID;
|
static uint32_t anonLabelID;
|
||||||
|
|
||||||
// Add an anonymous label
|
// Add an anonymous label
|
||||||
struct Symbol *sym_AddAnonLabel(void)
|
Symbol *sym_AddAnonLabel(void)
|
||||||
{
|
{
|
||||||
if (anonLabelID == UINT32_MAX) {
|
if (anonLabelID == UINT32_MAX) {
|
||||||
error("Only %" PRIu32 " anonymous labels can be created!", anonLabelID);
|
error("Only %" PRIu32 " anonymous labels can be created!", anonLabelID);
|
||||||
@@ -537,7 +537,7 @@ void sym_Export(char const *symName)
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
struct Symbol *sym = sym_FindScopedSymbol(symName);
|
Symbol *sym = sym_FindScopedSymbol(symName);
|
||||||
|
|
||||||
// If the symbol doesn't exist, create a ref that can be purged
|
// If the symbol doesn't exist, create a ref that can be purged
|
||||||
if (!sym)
|
if (!sym)
|
||||||
@@ -546,9 +546,9 @@ 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 *body, size_t size)
|
Symbol *sym_AddMacro(char const *symName, int32_t defLineNo, char *body, size_t size)
|
||||||
{
|
{
|
||||||
struct Symbol *sym = createNonrelocSymbol(symName, false);
|
Symbol *sym = createNonrelocSymbol(symName, false);
|
||||||
|
|
||||||
if (!sym)
|
if (!sym)
|
||||||
return NULL;
|
return NULL;
|
||||||
@@ -566,9 +566,9 @@ struct Symbol *sym_AddMacro(char const *symName, int32_t defLineNo, char *body,
|
|||||||
|
|
||||||
// Flag that a symbol is referenced in an RPN expression
|
// Flag that a symbol is referenced in an RPN expression
|
||||||
// and create it if it doesn't exist yet
|
// and create it if it doesn't exist yet
|
||||||
struct Symbol *sym_Ref(char const *symName)
|
Symbol *sym_Ref(char const *symName)
|
||||||
{
|
{
|
||||||
struct Symbol *sym = sym_FindScopedSymbol(symName);
|
Symbol *sym = sym_FindScopedSymbol(symName);
|
||||||
|
|
||||||
if (!sym) {
|
if (!sym) {
|
||||||
char fullname[MAXSYMLEN + 1];
|
char fullname[MAXSYMLEN + 1];
|
||||||
@@ -593,9 +593,9 @@ void sym_SetExportAll(bool set)
|
|||||||
exportAll = set;
|
exportAll = set;
|
||||||
}
|
}
|
||||||
|
|
||||||
static struct Symbol *createBuiltinSymbol(char const *symName)
|
static Symbol *createBuiltinSymbol(char const *symName)
|
||||||
{
|
{
|
||||||
struct Symbol *sym = createsymbol(symName);
|
Symbol *sym = createsymbol(symName);
|
||||||
|
|
||||||
sym->isBuiltin = true;
|
sym->isBuiltin = true;
|
||||||
sym->hasCallback = true;
|
sym->hasCallback = true;
|
||||||
@@ -620,7 +620,7 @@ void sym_Init(time_t now)
|
|||||||
sym_AddVar("_RS", 0)->isBuiltin = true;
|
sym_AddVar("_RS", 0)->isBuiltin = true;
|
||||||
|
|
||||||
#define addSym(fn, name, val) do { \
|
#define addSym(fn, name, val) do { \
|
||||||
struct Symbol *sym = fn(name, val); \
|
Symbol *sym = fn(name, val); \
|
||||||
assert(sym); \
|
assert(sym); \
|
||||||
sym->isBuiltin = true; \
|
sym->isBuiltin = true; \
|
||||||
} while (0)
|
} while (0)
|
||||||
@@ -641,7 +641,7 @@ void sym_Init(time_t now)
|
|||||||
now = 0;
|
now = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
const struct tm *time_local = localtime(&now);
|
const tm *time_local = localtime(&now);
|
||||||
|
|
||||||
strftime(savedTIME, sizeof(savedTIME), "\"%H:%M:%S\"", time_local);
|
strftime(savedTIME, sizeof(savedTIME), "\"%H:%M:%S\"", time_local);
|
||||||
strftime(savedDATE, sizeof(savedDATE), "\"%d %B %Y\"", time_local);
|
strftime(savedDATE, sizeof(savedDATE), "\"%d %B %Y\"", time_local);
|
||||||
@@ -649,7 +649,7 @@ void sym_Init(time_t now)
|
|||||||
sizeof(savedTIMESTAMP_ISO8601_LOCAL), "\"%Y-%m-%dT%H:%M:%S%z\"",
|
sizeof(savedTIMESTAMP_ISO8601_LOCAL), "\"%Y-%m-%dT%H:%M:%S%z\"",
|
||||||
time_local);
|
time_local);
|
||||||
|
|
||||||
const struct tm *time_utc = gmtime(&now);
|
const tm *time_utc = gmtime(&now);
|
||||||
|
|
||||||
strftime(savedTIMESTAMP_ISO8601_UTC,
|
strftime(savedTIMESTAMP_ISO8601_UTC,
|
||||||
sizeof(savedTIMESTAMP_ISO8601_UTC), "\"%Y-%m-%dT%H:%M:%SZ\"",
|
sizeof(savedTIMESTAMP_ISO8601_UTC), "\"%Y-%m-%dT%H:%M:%SZ\"",
|
||||||
|
|||||||
8
src/extern/getopt.cpp
vendored
8
src/extern/getopt.cpp
vendored
@@ -120,10 +120,10 @@ static void permute(char **argv, int dest, int src)
|
|||||||
}
|
}
|
||||||
|
|
||||||
static int musl_getopt_long_core(int argc, char **argv, char const *optstring,
|
static int musl_getopt_long_core(int argc, char **argv, char const *optstring,
|
||||||
const struct option *longopts, int *idx, int longonly);
|
const option *longopts, int *idx, int longonly);
|
||||||
|
|
||||||
static int musl_getopt_long(int argc, char **argv, char const *optstring,
|
static int musl_getopt_long(int argc, char **argv, char const *optstring,
|
||||||
const struct option *longopts, int *idx, int longonly)
|
const option *longopts, int *idx, int longonly)
|
||||||
{
|
{
|
||||||
int ret, skipped, resumed;
|
int ret, skipped, resumed;
|
||||||
|
|
||||||
@@ -160,7 +160,7 @@ static int musl_getopt_long(int argc, char **argv, char const *optstring,
|
|||||||
}
|
}
|
||||||
|
|
||||||
static int musl_getopt_long_core(int argc, char **argv, char const *optstring,
|
static int musl_getopt_long_core(int argc, char **argv, char const *optstring,
|
||||||
const struct option *longopts, int *idx, int longonly)
|
const option *longopts, int *idx, int longonly)
|
||||||
{
|
{
|
||||||
musl_optarg = 0;
|
musl_optarg = 0;
|
||||||
if (longopts && argv[musl_optind][0] == '-' &&
|
if (longopts && argv[musl_optind][0] == '-' &&
|
||||||
@@ -260,7 +260,7 @@ static int musl_getopt_long_core(int argc, char **argv, char const *optstring,
|
|||||||
}
|
}
|
||||||
|
|
||||||
int musl_getopt_long_only(int argc, char **argv, char const *optstring,
|
int musl_getopt_long_only(int argc, char **argv, char const *optstring,
|
||||||
const struct option *longopts, int *idx)
|
const option *longopts, int *idx)
|
||||||
{
|
{
|
||||||
return musl_getopt_long(argc, argv, optstring, longopts, idx, 1);
|
return musl_getopt_long(argc, argv, optstring, longopts, idx, 1);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -36,7 +36,7 @@ static const char *optstring = "Ccf:i:jk:l:m:n:Op:r:st:Vv";
|
|||||||
* This is because long opt matching, even to a single char, is prioritized
|
* This is because long opt matching, even to a single char, is prioritized
|
||||||
* over short opt matching
|
* over short opt matching
|
||||||
*/
|
*/
|
||||||
static struct option const longopts[] = {
|
static option const longopts[] = {
|
||||||
{ "color-only", no_argument, NULL, 'C' },
|
{ "color-only", no_argument, NULL, 'C' },
|
||||||
{ "color-compatible", no_argument, NULL, 'c' },
|
{ "color-compatible", no_argument, NULL, 'c' },
|
||||||
{ "fix-spec", required_argument, NULL, 'f' },
|
{ "fix-spec", required_argument, NULL, 'f' },
|
||||||
|
|||||||
@@ -110,7 +110,7 @@ static char const *optstring = "-Aa:b:Cc:Dd:FfhL:mN:n:Oo:Pp:Qq:r:s:Tt:U:uVvx:Z";
|
|||||||
* This is because long opt matching, even to a single char, is prioritized
|
* This is because long opt matching, even to a single char, is prioritized
|
||||||
* over short opt matching
|
* over short opt matching
|
||||||
*/
|
*/
|
||||||
static struct option const longopts[] = {
|
static option const longopts[] = {
|
||||||
{"auto-attr-map", no_argument, NULL, 'A'},
|
{"auto-attr-map", no_argument, NULL, 'A'},
|
||||||
{"output-attr-map", no_argument, NULL, -'A'}, // Deprecated
|
{"output-attr-map", no_argument, NULL, -'A'}, // Deprecated
|
||||||
{"attr-map", required_argument, NULL, 'a'},
|
{"attr-map", required_argument, NULL, 'a'},
|
||||||
|
|||||||
@@ -27,11 +27,11 @@ struct MemoryLocation {
|
|||||||
struct FreeSpace {
|
struct FreeSpace {
|
||||||
uint16_t address;
|
uint16_t address;
|
||||||
uint16_t size;
|
uint16_t size;
|
||||||
struct FreeSpace *next, *prev;
|
FreeSpace *next, *prev;
|
||||||
};
|
};
|
||||||
|
|
||||||
// Table of free space for each bank
|
// Table of free space for each bank
|
||||||
struct FreeSpace *memory[SECTTYPE_INVALID];
|
FreeSpace *memory[SECTTYPE_INVALID];
|
||||||
|
|
||||||
uint64_t nbSectionsToAssign;
|
uint64_t nbSectionsToAssign;
|
||||||
|
|
||||||
@@ -39,13 +39,13 @@ uint64_t nbSectionsToAssign;
|
|||||||
static void initFreeSpace(void)
|
static void initFreeSpace(void)
|
||||||
{
|
{
|
||||||
for (enum SectionType type : EnumSeq(SECTTYPE_INVALID)) {
|
for (enum SectionType type : EnumSeq(SECTTYPE_INVALID)) {
|
||||||
memory[type] = (struct FreeSpace *)malloc(sizeof(*memory[type]) * nbbanks(type));
|
memory[type] = (FreeSpace *)malloc(sizeof(*memory[type]) * nbbanks(type));
|
||||||
if (!memory[type])
|
if (!memory[type])
|
||||||
err("Failed to init free space for region %d", type);
|
err("Failed to init free space for region %d", type);
|
||||||
|
|
||||||
for (uint32_t bank = 0; bank < nbbanks(type); bank++) {
|
for (uint32_t bank = 0; bank < nbbanks(type); bank++) {
|
||||||
memory[type][bank].next =
|
memory[type][bank].next =
|
||||||
(struct FreeSpace *)malloc(sizeof(*memory[type][0].next));
|
(FreeSpace *)malloc(sizeof(*memory[type][0].next));
|
||||||
if (!memory[type][bank].next)
|
if (!memory[type][bank].next)
|
||||||
err("Failed to init free space for region %d bank %" PRIu32,
|
err("Failed to init free space for region %d bank %" PRIu32,
|
||||||
type, bank);
|
type, bank);
|
||||||
@@ -62,14 +62,14 @@ static void initFreeSpace(void)
|
|||||||
* @param section The section to assign
|
* @param section The section to assign
|
||||||
* @param location The location to assign the section to
|
* @param location The location to assign the section to
|
||||||
*/
|
*/
|
||||||
static void assignSection(struct Section *section, struct MemoryLocation const *location)
|
static void assignSection(Section *section, MemoryLocation const *location)
|
||||||
{
|
{
|
||||||
section->org = location->address;
|
section->org = location->address;
|
||||||
section->bank = location->bank;
|
section->bank = location->bank;
|
||||||
|
|
||||||
// Propagate the assigned location to all UNIONs/FRAGMENTs
|
// Propagate the assigned location to all UNIONs/FRAGMENTs
|
||||||
// so `jr` patches in them will have the correct offset
|
// so `jr` patches in them will have the correct offset
|
||||||
for (struct Section *next = section->nextu; next != NULL; next = next->nextu) {
|
for (Section *next = section->nextu; next != NULL; next = next->nextu) {
|
||||||
next->org = section->org;
|
next->org = section->org;
|
||||||
next->bank = section->bank;
|
next->bank = section->bank;
|
||||||
}
|
}
|
||||||
@@ -88,9 +88,8 @@ static void assignSection(struct Section *section, struct MemoryLocation const *
|
|||||||
* @param location The location to attempt placing the section at
|
* @param location The location to attempt placing the section at
|
||||||
* @return True if the location is suitable, false otherwise.
|
* @return True if the location is suitable, false otherwise.
|
||||||
*/
|
*/
|
||||||
static bool isLocationSuitable(struct Section const *section,
|
static bool isLocationSuitable(Section const *section, FreeSpace const *freeSpace,
|
||||||
struct FreeSpace const *freeSpace,
|
MemoryLocation const *location)
|
||||||
struct MemoryLocation const *location)
|
|
||||||
{
|
{
|
||||||
if (section->isAddressFixed && section->org != location->address)
|
if (section->isAddressFixed && section->org != location->address)
|
||||||
return false;
|
return false;
|
||||||
@@ -108,12 +107,11 @@ static bool isLocationSuitable(struct Section const *section,
|
|||||||
/*
|
/*
|
||||||
* Finds a suitable location to place a section at.
|
* Finds a suitable location to place a section at.
|
||||||
* @param section The section to be placed
|
* @param section The section to be placed
|
||||||
* @param location A pointer to a location struct that will be filled
|
* @param location A pointer to a memory location that will be filled
|
||||||
* @return A pointer to the free space encompassing the location, or NULL if
|
* @return A pointer to the free space encompassing the location, or NULL if
|
||||||
* none was found
|
* none was found
|
||||||
*/
|
*/
|
||||||
static struct FreeSpace *getPlacement(struct Section const *section,
|
static FreeSpace *getPlacement(Section const *section, MemoryLocation *location)
|
||||||
struct MemoryLocation *location)
|
|
||||||
{
|
{
|
||||||
static uint16_t curScrambleROM = 0;
|
static uint16_t curScrambleROM = 0;
|
||||||
static uint8_t curScrambleWRAM = 0;
|
static uint8_t curScrambleWRAM = 0;
|
||||||
@@ -137,7 +135,7 @@ static struct FreeSpace *getPlacement(struct Section const *section,
|
|||||||
} else {
|
} else {
|
||||||
location->bank = sectionTypeInfo[section->type].firstBank;
|
location->bank = sectionTypeInfo[section->type].firstBank;
|
||||||
}
|
}
|
||||||
struct FreeSpace *space;
|
FreeSpace *space;
|
||||||
|
|
||||||
for (;;) {
|
for (;;) {
|
||||||
// Switch to the beginning of the next bank
|
// Switch to the beginning of the next bank
|
||||||
@@ -226,9 +224,9 @@ static struct FreeSpace *getPlacement(struct Section const *section,
|
|||||||
* sections of decreasing size.
|
* sections of decreasing size.
|
||||||
* @param section The section to place
|
* @param section The section to place
|
||||||
*/
|
*/
|
||||||
static void placeSection(struct Section *section)
|
static void placeSection(Section *section)
|
||||||
{
|
{
|
||||||
struct MemoryLocation location;
|
MemoryLocation location;
|
||||||
|
|
||||||
// Specially handle 0-byte SECTIONs, as they can't overlap anything
|
// Specially handle 0-byte SECTIONs, as they can't overlap anything
|
||||||
if (section->size == 0) {
|
if (section->size == 0) {
|
||||||
@@ -246,7 +244,7 @@ static void placeSection(struct Section *section)
|
|||||||
|
|
||||||
// Place section using first-fit decreasing algorithm
|
// Place section using first-fit decreasing algorithm
|
||||||
// https://en.wikipedia.org/wiki/Bin_packing_problem#First-fit_algorithm
|
// https://en.wikipedia.org/wiki/Bin_packing_problem#First-fit_algorithm
|
||||||
struct FreeSpace *freeSpace = getPlacement(section, &location);
|
FreeSpace *freeSpace = getPlacement(section, &location);
|
||||||
|
|
||||||
if (freeSpace) {
|
if (freeSpace) {
|
||||||
assignSection(section, &location);
|
assignSection(section, &location);
|
||||||
@@ -266,7 +264,7 @@ static void placeSection(struct Section *section)
|
|||||||
free(freeSpace);
|
free(freeSpace);
|
||||||
} else if (!noLeftSpace && !noRightSpace) {
|
} else if (!noLeftSpace && !noRightSpace) {
|
||||||
// The free space is split in two
|
// The free space is split in two
|
||||||
struct FreeSpace *newSpace = (struct FreeSpace *)malloc(sizeof(*newSpace));
|
FreeSpace *newSpace = (FreeSpace *)malloc(sizeof(*newSpace));
|
||||||
|
|
||||||
if (!newSpace)
|
if (!newSpace)
|
||||||
err("Failed to split new free space");
|
err("Failed to split new free space");
|
||||||
@@ -334,14 +332,14 @@ static void placeSection(struct Section *section)
|
|||||||
#define BANK_CONSTRAINED (1 << 2)
|
#define BANK_CONSTRAINED (1 << 2)
|
||||||
#define ORG_CONSTRAINED (1 << 1)
|
#define ORG_CONSTRAINED (1 << 1)
|
||||||
#define ALIGN_CONSTRAINED (1 << 0)
|
#define ALIGN_CONSTRAINED (1 << 0)
|
||||||
static std::deque<struct Section *> unassignedSections[1 << 3];
|
static std::deque<Section *> unassignedSections[1 << 3];
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Categorize a section depending on how constrained it is
|
* Categorize a section depending on how constrained it is
|
||||||
* This is so the most-constrained sections are placed first
|
* This is so the most-constrained sections are placed first
|
||||||
* @param section The section to categorize
|
* @param section The section to categorize
|
||||||
*/
|
*/
|
||||||
static void categorizeSection(struct Section *section)
|
static void categorizeSection(Section *section)
|
||||||
{
|
{
|
||||||
uint8_t constraints = 0;
|
uint8_t constraints = 0;
|
||||||
|
|
||||||
@@ -353,7 +351,7 @@ static void categorizeSection(struct Section *section)
|
|||||||
else if (section->isAlignFixed)
|
else if (section->isAlignFixed)
|
||||||
constraints |= ALIGN_CONSTRAINED;
|
constraints |= ALIGN_CONSTRAINED;
|
||||||
|
|
||||||
std::deque<struct Section *> §ions = unassignedSections[constraints];
|
std::deque<Section *> §ions = unassignedSections[constraints];
|
||||||
auto pos = sections.begin();
|
auto pos = sections.begin();
|
||||||
|
|
||||||
// Insert section while keeping the list sorted by decreasing size
|
// Insert section while keeping the list sorted by decreasing size
|
||||||
@@ -380,7 +378,7 @@ void assign_AssignSections(void)
|
|||||||
|
|
||||||
// Specially process fully-constrained sections because of overlaying
|
// Specially process fully-constrained sections because of overlaying
|
||||||
verbosePrint("Assigning bank+org-constrained...\n");
|
verbosePrint("Assigning bank+org-constrained...\n");
|
||||||
for (struct Section *section : unassignedSections[BANK_CONSTRAINED | ORG_CONSTRAINED])
|
for (Section *section : unassignedSections[BANK_CONSTRAINED | ORG_CONSTRAINED])
|
||||||
placeSection(section);
|
placeSection(section);
|
||||||
|
|
||||||
// If all sections were fully constrained, we have nothing left to do
|
// If all sections were fully constrained, we have nothing left to do
|
||||||
@@ -392,9 +390,9 @@ void assign_AssignSections(void)
|
|||||||
if (overlayFileName) {
|
if (overlayFileName) {
|
||||||
fprintf(stderr, "FATAL: All sections must be fixed when using an overlay file");
|
fprintf(stderr, "FATAL: All sections must be fixed when using an overlay file");
|
||||||
uint8_t nbSections = 0;
|
uint8_t nbSections = 0;
|
||||||
for (int8_t constraints = BANK_CONSTRAINED | ALIGN_CONSTRAINED;
|
for (int8_t constraints = BANK_CONSTRAINED | ALIGN_CONSTRAINED; constraints >= 0;
|
||||||
constraints >= 0; constraints--) {
|
constraints--) {
|
||||||
for (struct Section *section : unassignedSections[constraints]) {
|
for (Section *section : unassignedSections[constraints]) {
|
||||||
fprintf(stderr, "%c \"%s\"", nbSections == 0 ? ';': ',',
|
fprintf(stderr, "%c \"%s\"", nbSections == 0 ? ';': ',',
|
||||||
section->name.c_str());
|
section->name.c_str());
|
||||||
nbSections++;
|
nbSections++;
|
||||||
@@ -411,9 +409,8 @@ max_out:
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Assign all remaining sections by decreasing constraint order
|
// Assign all remaining sections by decreasing constraint order
|
||||||
for (int8_t constraints = BANK_CONSTRAINED | ALIGN_CONSTRAINED;
|
for (int8_t constraints = BANK_CONSTRAINED | ALIGN_CONSTRAINED; constraints >= 0; constraints--) {
|
||||||
constraints >= 0; constraints--) {
|
for (Section *section : unassignedSections[constraints])
|
||||||
for (struct Section *section : unassignedSections[constraints])
|
|
||||||
placeSection(section);
|
placeSection(section);
|
||||||
|
|
||||||
if (!nbSectionsToAssign)
|
if (!nbSectionsToAssign)
|
||||||
@@ -427,11 +424,10 @@ void assign_Cleanup(void)
|
|||||||
{
|
{
|
||||||
for (enum SectionType type : EnumSeq(SECTTYPE_INVALID)) {
|
for (enum SectionType type : EnumSeq(SECTTYPE_INVALID)) {
|
||||||
for (uint32_t bank = 0; bank < nbbanks(type); bank++) {
|
for (uint32_t bank = 0; bank < nbbanks(type); bank++) {
|
||||||
struct FreeSpace *ptr =
|
FreeSpace *ptr = memory[type][bank].next;
|
||||||
memory[type][bank].next;
|
|
||||||
|
|
||||||
while (ptr) {
|
while (ptr) {
|
||||||
struct FreeSpace *next = ptr->next;
|
FreeSpace *next = ptr->next;
|
||||||
|
|
||||||
free(ptr);
|
free(ptr);
|
||||||
ptr = next;
|
ptr = next;
|
||||||
|
|||||||
@@ -72,7 +72,7 @@ std::string const &FileStackNode::name() const {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Helper function to dump a file stack to stderr
|
// Helper function to dump a file stack to stderr
|
||||||
std::string const *dumpFileStack(struct FileStackNode const *node)
|
std::string const *dumpFileStack(FileStackNode const *node)
|
||||||
{
|
{
|
||||||
std::string const *lastName;
|
std::string const *lastName;
|
||||||
|
|
||||||
@@ -96,7 +96,7 @@ std::string const *dumpFileStack(struct FileStackNode const *node)
|
|||||||
}
|
}
|
||||||
|
|
||||||
void printDiag(char const *fmt, va_list args, char const *type,
|
void printDiag(char const *fmt, va_list args, char const *type,
|
||||||
struct FileStackNode const *where, uint32_t lineNo)
|
FileStackNode const *where, uint32_t lineNo)
|
||||||
{
|
{
|
||||||
fputs(type, stderr);
|
fputs(type, stderr);
|
||||||
fputs(": ", stderr);
|
fputs(": ", stderr);
|
||||||
@@ -108,7 +108,7 @@ void printDiag(char const *fmt, va_list args, char const *type,
|
|||||||
putc('\n', stderr);
|
putc('\n', stderr);
|
||||||
}
|
}
|
||||||
|
|
||||||
void warning(struct FileStackNode const *where, uint32_t lineNo, char const *fmt, ...)
|
void warning(FileStackNode const *where, uint32_t lineNo, char const *fmt, ...)
|
||||||
{
|
{
|
||||||
va_list args;
|
va_list args;
|
||||||
|
|
||||||
@@ -117,7 +117,7 @@ void warning(struct FileStackNode const *where, uint32_t lineNo, char const *fmt
|
|||||||
va_end(args);
|
va_end(args);
|
||||||
}
|
}
|
||||||
|
|
||||||
void error(struct FileStackNode const *where, uint32_t lineNo, char const *fmt, ...)
|
void error(FileStackNode const *where, uint32_t lineNo, char const *fmt, ...)
|
||||||
{
|
{
|
||||||
va_list args;
|
va_list args;
|
||||||
|
|
||||||
@@ -143,7 +143,7 @@ void argErr(char flag, char const *fmt, ...)
|
|||||||
nbErrors++;
|
nbErrors++;
|
||||||
}
|
}
|
||||||
|
|
||||||
[[noreturn]] void fatal(struct FileStackNode const *where, uint32_t lineNo, char const *fmt, ...)
|
[[noreturn]] void fatal(FileStackNode const *where, uint32_t lineNo, char const *fmt, ...)
|
||||||
{
|
{
|
||||||
va_list args;
|
va_list args;
|
||||||
|
|
||||||
@@ -172,7 +172,7 @@ static const char *optstring = "dl:m:Mn:O:o:p:S:s:tVvWwx";
|
|||||||
* This is because long opt matching, even to a single char, is prioritized
|
* This is because long opt matching, even to a single char, is prioritized
|
||||||
* over short opt matching
|
* over short opt matching
|
||||||
*/
|
*/
|
||||||
static struct option const longopts[] = {
|
static option const longopts[] = {
|
||||||
{ "dmg", no_argument, NULL, 'd' },
|
{ "dmg", no_argument, NULL, 'd' },
|
||||||
{ "linkerscript", required_argument, NULL, 'l' },
|
{ "linkerscript", required_argument, NULL, 'l' },
|
||||||
{ "map", required_argument, NULL, 'm' },
|
{ "map", required_argument, NULL, 'm' },
|
||||||
|
|||||||
@@ -25,9 +25,9 @@
|
|||||||
#include "linkdefs.hpp"
|
#include "linkdefs.hpp"
|
||||||
#include "version.hpp"
|
#include "version.hpp"
|
||||||
|
|
||||||
static std::deque<std::vector<struct Symbol>> symbolLists;
|
static std::deque<std::vector<Symbol>> symbolLists;
|
||||||
static std::vector<std::vector<struct FileStackNode>> nodes;
|
static std::vector<std::vector<FileStackNode>> nodes;
|
||||||
static std::deque<struct Assertion> assertions;
|
static std::deque<Assertion> assertions;
|
||||||
|
|
||||||
// Helper functions for reading object files
|
// Helper functions for reading object files
|
||||||
|
|
||||||
@@ -128,10 +128,10 @@ static int64_t readlong(FILE *file)
|
|||||||
* @param i The ID of the node in the array
|
* @param i The ID of the node in the array
|
||||||
* @param fileName The filename to report in errors
|
* @param fileName The filename to report in errors
|
||||||
*/
|
*/
|
||||||
static void readFileStackNode(FILE *file, std::vector<struct FileStackNode> &fileNodes, uint32_t i,
|
static void readFileStackNode(FILE *file, std::vector<FileStackNode> &fileNodes, uint32_t i,
|
||||||
char const *fileName)
|
char const *fileName)
|
||||||
{
|
{
|
||||||
struct FileStackNode &node = fileNodes[i];
|
FileStackNode &node = fileNodes[i];
|
||||||
uint32_t parentID;
|
uint32_t parentID;
|
||||||
|
|
||||||
tryReadlong(parentID, file,
|
tryReadlong(parentID, file,
|
||||||
@@ -167,11 +167,11 @@ static void readFileStackNode(FILE *file, std::vector<struct FileStackNode> &fil
|
|||||||
/*
|
/*
|
||||||
* Reads a symbol from a file.
|
* Reads a symbol from a file.
|
||||||
* @param file The file to read from
|
* @param file The file to read from
|
||||||
* @param symbol The struct to fill
|
* @param symbol The symbol to fill
|
||||||
* @param fileName The filename to report in errors
|
* @param fileName The filename to report in errors
|
||||||
*/
|
*/
|
||||||
static void readSymbol(FILE *file, struct Symbol *symbol, char const *fileName,
|
static void readSymbol(FILE *file, Symbol *symbol, char const *fileName,
|
||||||
std::vector<struct FileStackNode> const &fileNodes)
|
std::vector<FileStackNode> const &fileNodes)
|
||||||
{
|
{
|
||||||
tryReadstring(symbol->name, file, "%s: Cannot read symbol name: %s", fileName);
|
tryReadstring(symbol->name, file, "%s: Cannot read symbol name: %s", fileName);
|
||||||
tryGetc(enum ExportLevel, symbol->type, file, "%s: Cannot read \"%s\"'s type: %s",
|
tryGetc(enum ExportLevel, symbol->type, file, "%s: Cannot read \"%s\"'s type: %s",
|
||||||
@@ -198,12 +198,12 @@ static void readSymbol(FILE *file, struct Symbol *symbol, char const *fileName,
|
|||||||
/*
|
/*
|
||||||
* Reads a patch from a file.
|
* Reads a patch from a file.
|
||||||
* @param file The file to read from
|
* @param file The file to read from
|
||||||
* @param patch The struct to fill
|
* @param patch The patch to fill
|
||||||
* @param fileName The filename to report in errors
|
* @param fileName The filename to report in errors
|
||||||
* @param i The number of the patch to report in errors
|
* @param i The number of the patch to report in errors
|
||||||
*/
|
*/
|
||||||
static void readPatch(FILE *file, struct Patch *patch, char const *fileName, std::string const §Name,
|
static void readPatch(FILE *file, Patch *patch, char const *fileName, std::string const §Name,
|
||||||
uint32_t i, std::vector<struct FileStackNode> const &fileNodes)
|
uint32_t i, std::vector<FileStackNode> const &fileNodes)
|
||||||
{
|
{
|
||||||
uint32_t nodeID, rpnSize;
|
uint32_t nodeID, rpnSize;
|
||||||
enum PatchType type;
|
enum PatchType type;
|
||||||
@@ -243,9 +243,9 @@ static void readPatch(FILE *file, struct Patch *patch, char const *fileName, std
|
|||||||
|
|
||||||
/*
|
/*
|
||||||
* Sets a patch's pcSection from its pcSectionID.
|
* Sets a patch's pcSection from its pcSectionID.
|
||||||
* @param patch The struct to fix
|
* @param patch The patch to fix
|
||||||
*/
|
*/
|
||||||
static void linkPatchToPCSect(struct Patch *patch, std::vector<struct Section *> const &fileSections)
|
static void linkPatchToPCSect(Patch *patch, std::vector<Section *> const &fileSections)
|
||||||
{
|
{
|
||||||
patch->pcSection = patch->pcSectionID != (uint32_t)-1 ? fileSections[patch->pcSectionID]
|
patch->pcSection = patch->pcSectionID != (uint32_t)-1 ? fileSections[patch->pcSectionID]
|
||||||
: NULL;
|
: NULL;
|
||||||
@@ -254,11 +254,11 @@ static void linkPatchToPCSect(struct Patch *patch, std::vector<struct Section *>
|
|||||||
/*
|
/*
|
||||||
* Reads a section from a file.
|
* Reads a section from a file.
|
||||||
* @param file The file to read from
|
* @param file The file to read from
|
||||||
* @param section The struct to fill
|
* @param section The section to fill
|
||||||
* @param fileName The filename to report in errors
|
* @param fileName The filename to report in errors
|
||||||
*/
|
*/
|
||||||
static void readSection(FILE *file, struct Section *section, char const *fileName,
|
static void readSection(FILE *file, Section *section, char const *fileName,
|
||||||
std::vector<struct FileStackNode> const &fileNodes)
|
std::vector<FileStackNode> const &fileNodes)
|
||||||
{
|
{
|
||||||
int32_t tmp;
|
int32_t tmp;
|
||||||
uint8_t byte;
|
uint8_t byte;
|
||||||
@@ -330,7 +330,7 @@ static void readSection(FILE *file, struct Section *section, char const *fileNam
|
|||||||
* @param symbol The symbol to link
|
* @param symbol The symbol to link
|
||||||
* @param section The section to link
|
* @param section The section to link
|
||||||
*/
|
*/
|
||||||
static void linkSymToSect(struct Symbol &symbol, struct Section *section)
|
static void linkSymToSect(Symbol &symbol, Section *section)
|
||||||
{
|
{
|
||||||
uint32_t a = 0, b = section->symbols.size();
|
uint32_t a = 0, b = section->symbols.size();
|
||||||
|
|
||||||
@@ -349,11 +349,11 @@ static void linkSymToSect(struct Symbol &symbol, struct Section *section)
|
|||||||
/*
|
/*
|
||||||
* Reads an assertion from a file
|
* Reads an assertion from a file
|
||||||
* @param file The file to read from
|
* @param file The file to read from
|
||||||
* @param assert The struct to fill
|
* @param assert The assertion to fill
|
||||||
* @param fileName The filename to report in errors
|
* @param fileName The filename to report in errors
|
||||||
*/
|
*/
|
||||||
static void readAssertion(FILE *file, struct Assertion *assert, char const *fileName, uint32_t i,
|
static void readAssertion(FILE *file, Assertion *assert, char const *fileName, uint32_t i,
|
||||||
std::vector<struct FileStackNode> const &fileNodes)
|
std::vector<FileStackNode> const &fileNodes)
|
||||||
{
|
{
|
||||||
char assertName[sizeof("Assertion #4294967295")]; // UINT32_MAX
|
char assertName[sizeof("Assertion #4294967295")]; // UINT32_MAX
|
||||||
|
|
||||||
@@ -363,7 +363,7 @@ static void readAssertion(FILE *file, struct Assertion *assert, char const *file
|
|||||||
tryReadstring(assert->message, file, "%s: Cannot read assertion's message: %s", fileName);
|
tryReadstring(assert->message, file, "%s: Cannot read assertion's message: %s", fileName);
|
||||||
}
|
}
|
||||||
|
|
||||||
static struct Section *getMainSection(struct Section *section)
|
static Section *getMainSection(Section *section)
|
||||||
{
|
{
|
||||||
if (section->modifier != SECTION_NORMAL)
|
if (section->modifier != SECTION_NORMAL)
|
||||||
section = sect_GetSection(section->name);
|
section = sect_GetSection(section->name);
|
||||||
@@ -406,7 +406,7 @@ void obj_ReadFile(char const *fileName, unsigned int fileID)
|
|||||||
.data = fileName
|
.data = fileName
|
||||||
});
|
});
|
||||||
|
|
||||||
std::vector<struct Symbol> &fileSymbols = symbolLists.emplace_front();
|
std::vector<Symbol> &fileSymbols = symbolLists.emplace_front();
|
||||||
|
|
||||||
sdobj_ReadFile(&nodes[fileID].back(), file, fileSymbols);
|
sdobj_ReadFile(&nodes[fileID].back(), file, fileSymbols);
|
||||||
return;
|
return;
|
||||||
@@ -446,13 +446,13 @@ void obj_ReadFile(char const *fileName, unsigned int fileID)
|
|||||||
readFileStackNode(file, nodes[fileID], i, fileName);
|
readFileStackNode(file, nodes[fileID], i, fileName);
|
||||||
|
|
||||||
// This file's symbols, kept to link sections to them
|
// This file's symbols, kept to link sections to them
|
||||||
std::vector<struct Symbol> &fileSymbols = symbolLists.emplace_front(nbSymbols);
|
std::vector<Symbol> &fileSymbols = symbolLists.emplace_front(nbSymbols);
|
||||||
std::vector<uint32_t> nbSymPerSect(nbSections, 0);
|
std::vector<uint32_t> nbSymPerSect(nbSections, 0);
|
||||||
|
|
||||||
verbosePrint("Reading %" PRIu32 " symbols...\n", nbSymbols);
|
verbosePrint("Reading %" PRIu32 " symbols...\n", nbSymbols);
|
||||||
for (uint32_t i = 0; i < nbSymbols; i++) {
|
for (uint32_t i = 0; i < nbSymbols; i++) {
|
||||||
// Read symbol
|
// Read symbol
|
||||||
struct Symbol &symbol = fileSymbols[i];
|
Symbol &symbol = fileSymbols[i];
|
||||||
|
|
||||||
readSymbol(file, &symbol, fileName, nodes[fileID]);
|
readSymbol(file, &symbol, fileName, nodes[fileID]);
|
||||||
|
|
||||||
@@ -463,12 +463,12 @@ void obj_ReadFile(char const *fileName, unsigned int fileID)
|
|||||||
}
|
}
|
||||||
|
|
||||||
// This file's sections, stored in a table to link symbols to them
|
// This file's sections, stored in a table to link symbols to them
|
||||||
std::vector<struct Section *> fileSections(nbSections, NULL);
|
std::vector<Section *> fileSections(nbSections, NULL);
|
||||||
|
|
||||||
verbosePrint("Reading %" PRIu32 " sections...\n", nbSections);
|
verbosePrint("Reading %" PRIu32 " sections...\n", nbSections);
|
||||||
for (uint32_t i = 0; i < nbSections; i++) {
|
for (uint32_t i = 0; i < nbSections; i++) {
|
||||||
// Read section
|
// Read section
|
||||||
fileSections[i] = new(std::nothrow) struct Section();
|
fileSections[i] = new(std::nothrow) Section();
|
||||||
if (!fileSections[i])
|
if (!fileSections[i])
|
||||||
err("%s: Failed to create new section", fileName);
|
err("%s: Failed to create new section", fileName);
|
||||||
|
|
||||||
@@ -483,7 +483,7 @@ void obj_ReadFile(char const *fileName, unsigned int fileID)
|
|||||||
// Give patches' PC section pointers to their sections
|
// Give patches' PC section pointers to their sections
|
||||||
for (uint32_t i = 0; i < nbSections; i++) {
|
for (uint32_t i = 0; i < nbSections; i++) {
|
||||||
if (sect_HasData(fileSections[i]->type)) {
|
if (sect_HasData(fileSections[i]->type)) {
|
||||||
for (struct Patch &patch : fileSections[i]->patches)
|
for (Patch &patch : fileSections[i]->patches)
|
||||||
linkPatchToPCSect(&patch, fileSections);
|
linkPatchToPCSect(&patch, fileSections);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -495,7 +495,7 @@ void obj_ReadFile(char const *fileName, unsigned int fileID)
|
|||||||
if (sectionID == -1) {
|
if (sectionID == -1) {
|
||||||
fileSymbols[i].section = NULL;
|
fileSymbols[i].section = NULL;
|
||||||
} else {
|
} else {
|
||||||
struct Section *section = fileSections[sectionID];
|
Section *section = fileSections[sectionID];
|
||||||
|
|
||||||
// Give the section a pointer to the symbol as well
|
// Give the section a pointer to the symbol as well
|
||||||
linkSymToSect(fileSymbols[i], section);
|
linkSymToSect(fileSymbols[i], section);
|
||||||
@@ -515,7 +515,7 @@ void obj_ReadFile(char const *fileName, unsigned int fileID)
|
|||||||
tryReadlong(nbAsserts, file, "%s: Cannot read number of assertions: %s", fileName);
|
tryReadlong(nbAsserts, file, "%s: Cannot read number of assertions: %s", fileName);
|
||||||
verbosePrint("Reading %" PRIu32 " assertions...\n", nbAsserts);
|
verbosePrint("Reading %" PRIu32 " assertions...\n", nbAsserts);
|
||||||
for (uint32_t i = 0; i < nbAsserts; i++) {
|
for (uint32_t i = 0; i < nbAsserts; i++) {
|
||||||
struct Assertion &assertion = assertions.emplace_front();
|
Assertion &assertion = assertions.emplace_front();
|
||||||
|
|
||||||
readAssertion(file, &assertion, fileName, i, nodes[fileID]);
|
readAssertion(file, &assertion, fileName, i, nodes[fileID]);
|
||||||
linkPatchToPCSect(&assertion.patch, fileSections);
|
linkPatchToPCSect(&assertion.patch, fileSections);
|
||||||
@@ -540,9 +540,9 @@ void obj_Setup(unsigned int nbFiles)
|
|||||||
nodes.resize(nbFiles);
|
nodes.resize(nbFiles);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void freeSection(struct Section *section)
|
static void freeSection(Section *section)
|
||||||
{
|
{
|
||||||
for (struct Section *next; section; section = next) {
|
for (Section *next; section; section = next) {
|
||||||
next = section->nextu;
|
next = section->nextu;
|
||||||
delete section;
|
delete section;
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -30,16 +30,16 @@ FILE *symFile;
|
|||||||
FILE *mapFile;
|
FILE *mapFile;
|
||||||
|
|
||||||
struct SortedSymbol {
|
struct SortedSymbol {
|
||||||
struct Symbol const *sym;
|
Symbol const *sym;
|
||||||
uint16_t addr;
|
uint16_t addr;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct SortedSections {
|
struct SortedSections {
|
||||||
std::deque<struct Section const *> sections;
|
std::deque<Section const *> sections;
|
||||||
std::deque<struct Section const *> zeroLenSections;
|
std::deque<Section const *> zeroLenSections;
|
||||||
};
|
};
|
||||||
|
|
||||||
static std::deque<struct SortedSections> sections[SECTTYPE_INVALID];
|
static std::deque<SortedSections> sections[SECTTYPE_INVALID];
|
||||||
|
|
||||||
// Defines the order in which types are output to the sym and map files
|
// Defines the order in which types are output to the sym and map files
|
||||||
static enum SectionType typeMap[SECTTYPE_INVALID] = {
|
static enum SectionType typeMap[SECTTYPE_INVALID] = {
|
||||||
@@ -53,7 +53,7 @@ static enum SectionType typeMap[SECTTYPE_INVALID] = {
|
|||||||
SECTTYPE_HRAM
|
SECTTYPE_HRAM
|
||||||
};
|
};
|
||||||
|
|
||||||
void out_AddSection(struct Section const *section)
|
void out_AddSection(Section const *section)
|
||||||
{
|
{
|
||||||
static const uint32_t maxNbBanks[SECTTYPE_INVALID] = {
|
static const uint32_t maxNbBanks[SECTTYPE_INVALID] = {
|
||||||
1, // SECTTYPE_WRAM0
|
1, // SECTTYPE_WRAM0
|
||||||
@@ -77,7 +77,7 @@ void out_AddSection(struct Section const *section)
|
|||||||
for (uint32_t i = sections[section->type].size(); i < minNbBanks; i++)
|
for (uint32_t i = sections[section->type].size(); i < minNbBanks; i++)
|
||||||
sections[section->type].emplace_back();
|
sections[section->type].emplace_back();
|
||||||
|
|
||||||
std::deque<struct Section const *> *ptr = section->size
|
std::deque<Section const *> *ptr = section->size
|
||||||
? §ions[section->type][targetBank].sections
|
? §ions[section->type][targetBank].sections
|
||||||
: §ions[section->type][targetBank].zeroLenSections;
|
: §ions[section->type][targetBank].zeroLenSections;
|
||||||
auto pos = ptr->begin();
|
auto pos = ptr->begin();
|
||||||
@@ -88,11 +88,11 @@ void out_AddSection(struct Section const *section)
|
|||||||
ptr->insert(pos, section);
|
ptr->insert(pos, section);
|
||||||
}
|
}
|
||||||
|
|
||||||
struct Section const *out_OverlappingSection(struct Section const *section)
|
Section const *out_OverlappingSection(Section const *section)
|
||||||
{
|
{
|
||||||
uint32_t bank = section->bank - sectionTypeInfo[section->type].firstBank;
|
uint32_t bank = section->bank - sectionTypeInfo[section->type].firstBank;
|
||||||
|
|
||||||
for (struct Section const *ptr : sections[section->type][bank].sections) {
|
for (Section const *ptr : sections[section->type][bank].sections) {
|
||||||
if (ptr->org < section->org + section->size && section->org < ptr->org + ptr->size)
|
if (ptr->org < section->org + section->size && section->org < ptr->org + ptr->size)
|
||||||
return ptr;
|
return ptr;
|
||||||
}
|
}
|
||||||
@@ -159,13 +159,12 @@ static void coverOverlayBanks(uint32_t nbOverlayBanks)
|
|||||||
* @param baseOffset The address of the bank's first byte in GB address space
|
* @param baseOffset The address of the bank's first byte in GB address space
|
||||||
* @param size The size of the bank
|
* @param size The size of the bank
|
||||||
*/
|
*/
|
||||||
static void writeBank(std::deque<struct Section const *> *bankSections, uint16_t baseOffset,
|
static void writeBank(std::deque<Section const *> *bankSections, uint16_t baseOffset, uint16_t size)
|
||||||
uint16_t size)
|
|
||||||
{
|
{
|
||||||
uint16_t offset = 0;
|
uint16_t offset = 0;
|
||||||
|
|
||||||
if (bankSections) {
|
if (bankSections) {
|
||||||
for (struct Section const *section : *bankSections) {
|
for (Section const *section : *bankSections) {
|
||||||
assert(section->offset == 0);
|
assert(section->offset == 0);
|
||||||
// Output padding up to the next SECTION
|
// Output padding up to the next SECTION
|
||||||
while (offset + baseOffset < section->org) {
|
while (offset + baseOffset < section->org) {
|
||||||
@@ -288,7 +287,7 @@ static void printSymName(char const *name)
|
|||||||
|
|
||||||
// Comparator function for `std::stable_sort` to sort symbols
|
// Comparator function for `std::stable_sort` to sort symbols
|
||||||
// Symbols are ordered by address, then by parentage
|
// Symbols are ordered by address, then by parentage
|
||||||
static int compareSymbols(struct SortedSymbol const &sym1, struct SortedSymbol const &sym2)
|
static int compareSymbols(SortedSymbol const &sym1, SortedSymbol const &sym2)
|
||||||
{
|
{
|
||||||
if (sym1.addr != sym2.addr)
|
if (sym1.addr != sym2.addr)
|
||||||
return sym1.addr < sym2.addr ? -1 : 1;
|
return sym1.addr < sym2.addr ? -1 : 1;
|
||||||
@@ -318,16 +317,15 @@ static int compareSymbols(struct SortedSymbol const &sym1, struct SortedSymbol c
|
|||||||
* Write a bank's contents to the sym file
|
* Write a bank's contents to the sym file
|
||||||
* @param bankSections The bank's sections
|
* @param bankSections The bank's sections
|
||||||
*/
|
*/
|
||||||
static void writeSymBank(struct SortedSections const &bankSections,
|
static void writeSymBank(SortedSections const &bankSections, enum SectionType type, uint32_t bank)
|
||||||
enum SectionType type, uint32_t bank)
|
|
||||||
{
|
{
|
||||||
#define forEachSortedSection(sect, ...) do { \
|
#define forEachSortedSection(sect, ...) do { \
|
||||||
for (auto it = bankSections.zeroLenSections.begin(); it != bankSections.zeroLenSections.end(); it++) { \
|
for (auto it = bankSections.zeroLenSections.begin(); it != bankSections.zeroLenSections.end(); it++) { \
|
||||||
for (struct Section const *sect = *it; sect; sect = sect->nextu) \
|
for (Section const *sect = *it; sect; sect = sect->nextu) \
|
||||||
__VA_ARGS__ \
|
__VA_ARGS__ \
|
||||||
} \
|
} \
|
||||||
for (auto it = bankSections.sections.begin(); it != bankSections.sections.end(); it++) { \
|
for (auto it = bankSections.sections.begin(); it != bankSections.sections.end(); it++) { \
|
||||||
for (struct Section const *sect = *it; sect; sect = sect->nextu) \
|
for (Section const *sect = *it; sect; sect = sect->nextu) \
|
||||||
__VA_ARGS__ \
|
__VA_ARGS__ \
|
||||||
} \
|
} \
|
||||||
} while (0)
|
} while (0)
|
||||||
@@ -341,12 +339,12 @@ static void writeSymBank(struct SortedSections const &bankSections,
|
|||||||
if (!nbSymbols)
|
if (!nbSymbols)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
std::vector<struct SortedSymbol> symList;
|
std::vector<SortedSymbol> symList;
|
||||||
|
|
||||||
symList.reserve(nbSymbols);
|
symList.reserve(nbSymbols);
|
||||||
|
|
||||||
forEachSortedSection(sect, {
|
forEachSortedSection(sect, {
|
||||||
for (struct Symbol const *sym : sect->symbols) {
|
for (Symbol const *sym : sect->symbols) {
|
||||||
// Don't output symbols that begin with an illegal character
|
// Don't output symbols that begin with an illegal character
|
||||||
if (!sym->name.empty() && canStartSymName(sym->name[0]))
|
if (!sym->name.empty() && canStartSymName(sym->name[0]))
|
||||||
symList.push_back({ .sym = sym, .addr = (uint16_t)(sym->offset + sect->org) });
|
symList.push_back({ .sym = sym, .addr = (uint16_t)(sym->offset + sect->org) });
|
||||||
@@ -359,7 +357,7 @@ static void writeSymBank(struct SortedSections const &bankSections,
|
|||||||
|
|
||||||
uint32_t symBank = bank + sectionTypeInfo[type].firstBank;
|
uint32_t symBank = bank + sectionTypeInfo[type].firstBank;
|
||||||
|
|
||||||
for (struct SortedSymbol &sym : symList) {
|
for (SortedSymbol &sym : symList) {
|
||||||
fprintf(symFile, "%02" PRIx32 ":%04" PRIx16 " ", symBank, sym.addr);
|
fprintf(symFile, "%02" PRIx32 ":%04" PRIx16 " ", symBank, sym.addr);
|
||||||
printSymName(sym.sym->name.c_str());
|
printSymName(sym.sym->name.c_str());
|
||||||
putc('\n', symFile);
|
putc('\n', symFile);
|
||||||
@@ -379,8 +377,7 @@ static void writeEmptySpace(uint16_t begin, uint16_t end)
|
|||||||
/*
|
/*
|
||||||
* Write a bank's contents to the map file
|
* Write a bank's contents to the map file
|
||||||
*/
|
*/
|
||||||
static void writeMapBank(struct SortedSections const §List, enum SectionType type,
|
static void writeMapBank(SortedSections const §List, enum SectionType type, uint32_t bank)
|
||||||
uint32_t bank)
|
|
||||||
{
|
{
|
||||||
fprintf(mapFile, "\n%s bank #%" PRIu32 ":\n", sectionTypeInfo[type].name.c_str(),
|
fprintf(mapFile, "\n%s bank #%" PRIu32 ":\n", sectionTypeInfo[type].name.c_str(),
|
||||||
bank + sectionTypeInfo[type].firstBank);
|
bank + sectionTypeInfo[type].firstBank);
|
||||||
@@ -395,7 +392,7 @@ static void writeMapBank(struct SortedSections const §List, enum SectionType
|
|||||||
auto &pickedSection = section == sectList.sections.end() ? zeroLenSection
|
auto &pickedSection = section == sectList.sections.end() ? zeroLenSection
|
||||||
: zeroLenSection == sectList.zeroLenSections.end() ? section
|
: zeroLenSection == sectList.zeroLenSections.end() ? section
|
||||||
: (*section)->org < (*zeroLenSection)->org ? section : zeroLenSection;
|
: (*section)->org < (*zeroLenSection)->org ? section : zeroLenSection;
|
||||||
struct Section const *sect = *pickedSection;
|
Section const *sect = *pickedSection;
|
||||||
|
|
||||||
used += sect->size;
|
used += sect->size;
|
||||||
assert(sect->offset == 0);
|
assert(sect->offset == 0);
|
||||||
@@ -416,7 +413,7 @@ static void writeMapBank(struct SortedSections const §List, enum SectionType
|
|||||||
if (!noSymInMap) {
|
if (!noSymInMap) {
|
||||||
// Also print symbols in the following "pieces"
|
// Also print symbols in the following "pieces"
|
||||||
for (uint16_t org = sect->org; sect; sect = sect->nextu) {
|
for (uint16_t org = sect->org; sect; sect = sect->nextu) {
|
||||||
for (struct Symbol *sym : sect->symbols)
|
for (Symbol *sym : sect->symbols)
|
||||||
// Space matches "\tSECTION: $xxxx ..."
|
// Space matches "\tSECTION: $xxxx ..."
|
||||||
fprintf(mapFile, "\t $%04" PRIx32 " = %s\n",
|
fprintf(mapFile, "\t $%04" PRIx32 " = %s\n",
|
||||||
sym->offset + org, sym->name.c_str());
|
sym->offset + org, sym->name.c_str());
|
||||||
|
|||||||
@@ -22,7 +22,7 @@ struct RPNStackEntry {
|
|||||||
bool errorFlag; // Whether the value is a placeholder inserted for error recovery
|
bool errorFlag; // Whether the value is a placeholder inserted for error recovery
|
||||||
};
|
};
|
||||||
|
|
||||||
std::deque<struct RPNStackEntry> rpnStack;
|
std::deque<RPNStackEntry> rpnStack;
|
||||||
|
|
||||||
static void pushRPN(int32_t value, bool comesFromError)
|
static void pushRPN(int32_t value, bool comesFromError)
|
||||||
{
|
{
|
||||||
@@ -33,12 +33,12 @@ static void pushRPN(int32_t value, bool comesFromError)
|
|||||||
// has popped any values with the error flag set.
|
// has popped any values with the error flag set.
|
||||||
static bool isError = false;
|
static bool isError = false;
|
||||||
|
|
||||||
static int32_t popRPN(struct FileStackNode const *node, uint32_t lineNo)
|
static int32_t popRPN(FileStackNode const *node, uint32_t lineNo)
|
||||||
{
|
{
|
||||||
if (rpnStack.empty())
|
if (rpnStack.empty())
|
||||||
fatal(node, lineNo, "Internal error, RPN stack empty");
|
fatal(node, lineNo, "Internal error, RPN stack empty");
|
||||||
|
|
||||||
struct RPNStackEntry entry = rpnStack.front();
|
RPNStackEntry entry = rpnStack.front();
|
||||||
|
|
||||||
rpnStack.pop_front();
|
rpnStack.pop_front();
|
||||||
isError |= entry.errorFlag;
|
isError |= entry.errorFlag;
|
||||||
@@ -48,7 +48,7 @@ static int32_t popRPN(struct FileStackNode const *node, uint32_t lineNo)
|
|||||||
// RPN operators
|
// RPN operators
|
||||||
|
|
||||||
static uint32_t getRPNByte(uint8_t const **expression, int32_t *size,
|
static uint32_t getRPNByte(uint8_t const **expression, int32_t *size,
|
||||||
struct FileStackNode const *node, uint32_t lineNo)
|
FileStackNode const *node, uint32_t lineNo)
|
||||||
{
|
{
|
||||||
if (!(*size)--)
|
if (!(*size)--)
|
||||||
fatal(node, lineNo, "Internal error, RPN expression overread");
|
fatal(node, lineNo, "Internal error, RPN expression overread");
|
||||||
@@ -56,10 +56,10 @@ static uint32_t getRPNByte(uint8_t const **expression, int32_t *size,
|
|||||||
return *(*expression)++;
|
return *(*expression)++;
|
||||||
}
|
}
|
||||||
|
|
||||||
static struct Symbol const *getSymbol(std::vector<struct Symbol> const &symbolList, uint32_t index)
|
static Symbol const *getSymbol(std::vector<Symbol> const &symbolList, uint32_t index)
|
||||||
{
|
{
|
||||||
assert(index != (uint32_t)-1); // PC needs to be handled specially, not here
|
assert(index != (uint32_t)-1); // PC needs to be handled specially, not here
|
||||||
struct Symbol const &symbol = symbolList[index];
|
Symbol const &symbol = symbolList[index];
|
||||||
|
|
||||||
// If the symbol is defined elsewhere...
|
// If the symbol is defined elsewhere...
|
||||||
if (symbol.type == SYMTYPE_IMPORT)
|
if (symbol.type == SYMTYPE_IMPORT)
|
||||||
@@ -76,8 +76,7 @@ static struct Symbol const *getSymbol(std::vector<struct Symbol> const &symbolLi
|
|||||||
* @return isError Set if an error occurred during evaluation, and further
|
* @return isError Set if an error occurred during evaluation, and further
|
||||||
* errors caused by the value should be suppressed.
|
* errors caused by the value should be suppressed.
|
||||||
*/
|
*/
|
||||||
static int32_t computeRPNExpr(struct Patch const *patch,
|
static int32_t computeRPNExpr(Patch const *patch, std::vector<Symbol> const &fileSymbols)
|
||||||
std::vector<struct Symbol> const &fileSymbols)
|
|
||||||
{
|
{
|
||||||
// Small shortcut to avoid a lot of repetition
|
// Small shortcut to avoid a lot of repetition
|
||||||
#define popRPN() popRPN(patch->src, patch->lineNo)
|
#define popRPN() popRPN(patch->src, patch->lineNo)
|
||||||
@@ -99,9 +98,9 @@ static int32_t computeRPNExpr(struct Patch const *patch,
|
|||||||
// So, if there are two `popRPN` in the same expression, make
|
// So, if there are two `popRPN` in the same expression, make
|
||||||
// sure the operation is commutative.
|
// sure the operation is commutative.
|
||||||
switch (command) {
|
switch (command) {
|
||||||
struct Symbol const *symbol;
|
Symbol const *symbol;
|
||||||
char const *name;
|
char const *name;
|
||||||
struct Section const *sect;
|
Section const *sect;
|
||||||
|
|
||||||
case RPN_ADD:
|
case RPN_ADD:
|
||||||
value = popRPN() + popRPN();
|
value = popRPN() + popRPN();
|
||||||
@@ -410,11 +409,11 @@ static int32_t computeRPNExpr(struct Patch const *patch,
|
|||||||
#undef popRPN
|
#undef popRPN
|
||||||
}
|
}
|
||||||
|
|
||||||
void patch_CheckAssertions(std::deque<struct Assertion> &assertions)
|
void patch_CheckAssertions(std::deque<Assertion> &assertions)
|
||||||
{
|
{
|
||||||
verbosePrint("Checking assertions...\n");
|
verbosePrint("Checking assertions...\n");
|
||||||
|
|
||||||
for (struct Assertion &assert : assertions) {
|
for (Assertion &assert : assertions) {
|
||||||
int32_t value = computeRPNExpr(&assert.patch, *assert.fileSymbols);
|
int32_t value = computeRPNExpr(&assert.patch, *assert.fileSymbols);
|
||||||
enum AssertionType type = (enum AssertionType)assert.patch.type;
|
enum AssertionType type = (enum AssertionType)assert.patch.type;
|
||||||
|
|
||||||
@@ -448,10 +447,10 @@ void patch_CheckAssertions(std::deque<struct Assertion> &assertions)
|
|||||||
* @param section The section component to patch
|
* @param section The section component to patch
|
||||||
* @param dataSection The section to patch
|
* @param dataSection The section to patch
|
||||||
*/
|
*/
|
||||||
static void applyFilePatches(struct Section *section, struct Section *dataSection)
|
static void applyFilePatches(Section *section, Section *dataSection)
|
||||||
{
|
{
|
||||||
verbosePrint("Patching section \"%s\"...\n", section->name.c_str());
|
verbosePrint("Patching section \"%s\"...\n", section->name.c_str());
|
||||||
for (struct Patch &patch : section->patches) {
|
for (Patch &patch : section->patches) {
|
||||||
int32_t value = computeRPNExpr(&patch, *section->fileSymbols);
|
int32_t value = computeRPNExpr(&patch, *section->fileSymbols);
|
||||||
uint16_t offset = patch.offset + section->offset;
|
uint16_t offset = patch.offset + section->offset;
|
||||||
|
|
||||||
@@ -497,12 +496,12 @@ static void applyFilePatches(struct Section *section, struct Section *dataSectio
|
|||||||
* Applies all of a section's patches, iterating over "components" of unionized sections
|
* Applies all of a section's patches, iterating over "components" of unionized sections
|
||||||
* @param section The section to patch
|
* @param section The section to patch
|
||||||
*/
|
*/
|
||||||
static void applyPatches(struct Section *section)
|
static void applyPatches(Section *section)
|
||||||
{
|
{
|
||||||
if (!sect_HasData(section->type))
|
if (!sect_HasData(section->type))
|
||||||
return;
|
return;
|
||||||
|
|
||||||
for (struct Section *component = section; component; component = component->nextu)
|
for (Section *component = section; component; component = component->nextu)
|
||||||
applyFilePatches(component, section);
|
applyFilePatches(component, section);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -25,7 +25,7 @@ enum NumberType {
|
|||||||
OCT = 8, // Q
|
OCT = 8, // Q
|
||||||
};
|
};
|
||||||
|
|
||||||
static void consumeLF(struct FileStackNode const *where, uint32_t lineNo, FILE *file) {
|
static void consumeLF(FileStackNode const *where, uint32_t lineNo, FILE *file) {
|
||||||
if (getc(file) != '\n')
|
if (getc(file) != '\n')
|
||||||
fatal(where, lineNo, "Bad line ending (CR without LF)");
|
fatal(where, lineNo, "Bad line ending (CR without LF)");
|
||||||
}
|
}
|
||||||
@@ -33,7 +33,7 @@ static void consumeLF(struct FileStackNode const *where, uint32_t lineNo, FILE *
|
|||||||
static char const *delim = " \f\n\r\t\v"; // Whitespace according to the C and POSIX locales
|
static char const *delim = " \f\n\r\t\v"; // Whitespace according to the C and POSIX locales
|
||||||
|
|
||||||
static int nextLine(std::vector<char> &lineBuf, uint32_t &lineNo,
|
static int nextLine(std::vector<char> &lineBuf, uint32_t &lineNo,
|
||||||
struct FileStackNode const *where, FILE *file) {
|
FileStackNode const *where, FILE *file) {
|
||||||
retry:
|
retry:
|
||||||
++lineNo;
|
++lineNo;
|
||||||
int firstChar = getc(file);
|
int firstChar = getc(file);
|
||||||
@@ -88,7 +88,7 @@ static uint32_t readNumber(char const *restrict str, char const **endptr, enum N
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static uint32_t parseNumber(struct FileStackNode const *where, uint32_t lineNo, char const *restrict str, enum NumberType base) {
|
static uint32_t parseNumber(FileStackNode const *where, uint32_t lineNo, char const *restrict str, enum NumberType base) {
|
||||||
if (str[0] == '\0')
|
if (str[0] == '\0')
|
||||||
fatal(where, lineNo, "Expected number, got empty string");
|
fatal(where, lineNo, "Expected number, got empty string");
|
||||||
|
|
||||||
@@ -100,7 +100,7 @@ static uint32_t parseNumber(struct FileStackNode const *where, uint32_t lineNo,
|
|||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
|
|
||||||
static uint8_t parseByte(struct FileStackNode const *where, uint32_t lineNo, char const *restrict str, enum NumberType base) {
|
static uint8_t parseByte(FileStackNode const *where, uint32_t lineNo, char const *restrict str, enum NumberType base) {
|
||||||
uint32_t num = parseNumber(where, lineNo, str, base);
|
uint32_t num = parseNumber(where, lineNo, str, base);
|
||||||
|
|
||||||
if (num > UINT8_MAX)
|
if (num > UINT8_MAX)
|
||||||
@@ -133,7 +133,7 @@ enum RelocFlags {
|
|||||||
| 1 << RELOC_EXPR24 | 1 << RELOC_BANKBYTE,
|
| 1 << RELOC_EXPR24 | 1 << RELOC_BANKBYTE,
|
||||||
};
|
};
|
||||||
|
|
||||||
void sdobj_ReadFile(struct FileStackNode const *where, FILE *file, std::vector<struct Symbol> &fileSymbols) {
|
void sdobj_ReadFile(FileStackNode const *where, FILE *file, std::vector<Symbol> &fileSymbols) {
|
||||||
std::vector<char> line(256);
|
std::vector<char> line(256);
|
||||||
char const *token;
|
char const *token;
|
||||||
|
|
||||||
@@ -216,10 +216,10 @@ void sdobj_ReadFile(struct FileStackNode const *where, FILE *file, std::vector<s
|
|||||||
// Now, let's parse the rest of the lines as they come!
|
// Now, let's parse the rest of the lines as they come!
|
||||||
|
|
||||||
struct FileSection {
|
struct FileSection {
|
||||||
struct Section *section;
|
Section *section;
|
||||||
uint16_t writeIndex;
|
uint16_t writeIndex;
|
||||||
};
|
};
|
||||||
std::vector<struct FileSection> fileSections;
|
std::vector<FileSection> fileSections;
|
||||||
std::vector<uint8_t> data;
|
std::vector<uint8_t> data;
|
||||||
|
|
||||||
for (;;) {
|
for (;;) {
|
||||||
@@ -236,7 +236,7 @@ void sdobj_ReadFile(struct FileStackNode const *where, FILE *file, std::vector<s
|
|||||||
if (fileSections.size() == expectedNbAreas)
|
if (fileSections.size() == expectedNbAreas)
|
||||||
warning(where, lineNo, "Got more 'A' lines than the expected %" PRIu32,
|
warning(where, lineNo, "Got more 'A' lines than the expected %" PRIu32,
|
||||||
expectedNbAreas);
|
expectedNbAreas);
|
||||||
struct Section *curSection = new(std::nothrow) struct Section();
|
Section *curSection = new(std::nothrow) Section();
|
||||||
|
|
||||||
if (!curSection)
|
if (!curSection)
|
||||||
fatal(where, lineNo, "Failed to alloc new area: %s", strerror(errno));
|
fatal(where, lineNo, "Failed to alloc new area: %s", strerror(errno));
|
||||||
@@ -244,7 +244,7 @@ void sdobj_ReadFile(struct FileStackNode const *where, FILE *file, std::vector<s
|
|||||||
getToken(line.data(), "'A' line is too short");
|
getToken(line.data(), "'A' line is too short");
|
||||||
assert(strlen(token) != 0); // This should be impossible, tokens are non-empty
|
assert(strlen(token) != 0); // This should be impossible, tokens are non-empty
|
||||||
// The following is required for fragment offsets to be reliably predicted
|
// The following is required for fragment offsets to be reliably predicted
|
||||||
for (struct FileSection &entry : fileSections) {
|
for (FileSection &entry : fileSections) {
|
||||||
if (!strcmp(token, entry.section->name.c_str()))
|
if (!strcmp(token, entry.section->name.c_str()))
|
||||||
fatal(where, lineNo, "Area \"%s\" already defined earlier",
|
fatal(where, lineNo, "Area \"%s\" already defined earlier",
|
||||||
token);
|
token);
|
||||||
@@ -327,7 +327,7 @@ void sdobj_ReadFile(struct FileStackNode const *where, FILE *file, std::vector<s
|
|||||||
if (fileSymbols.size() == expectedNbSymbols)
|
if (fileSymbols.size() == expectedNbSymbols)
|
||||||
warning(where, lineNo, "Got more 'S' lines than the expected %" PRIu32,
|
warning(where, lineNo, "Got more 'S' lines than the expected %" PRIu32,
|
||||||
expectedNbSymbols);
|
expectedNbSymbols);
|
||||||
struct Symbol &symbol = fileSymbols.emplace_back();
|
Symbol &symbol = fileSymbols.emplace_back();
|
||||||
|
|
||||||
// Init other members
|
// Init other members
|
||||||
symbol.objFileName = where->name().c_str();
|
symbol.objFileName = where->name().c_str();
|
||||||
@@ -358,7 +358,7 @@ void sdobj_ReadFile(struct FileStackNode const *where, FILE *file, std::vector<s
|
|||||||
} else {
|
} else {
|
||||||
// All symbols are exported
|
// All symbols are exported
|
||||||
symbol.type = SYMTYPE_EXPORT;
|
symbol.type = SYMTYPE_EXPORT;
|
||||||
struct Symbol const *other = sym_GetSymbol(symbol.name);
|
Symbol const *other = sym_GetSymbol(symbol.name);
|
||||||
|
|
||||||
if (other) {
|
if (other) {
|
||||||
// The same symbol can only be defined twice if neither
|
// The same symbol can only be defined twice if neither
|
||||||
@@ -422,7 +422,7 @@ void sdobj_ReadFile(struct FileStackNode const *where, FILE *file, std::vector<s
|
|||||||
fatal(where, lineNo, "'R' line references area #%" PRIu16 ", but there are only %zu (so far)",
|
fatal(where, lineNo, "'R' line references area #%" PRIu16 ", but there are only %zu (so far)",
|
||||||
areaIdx, fileSections.size());
|
areaIdx, fileSections.size());
|
||||||
assert(!fileSections.empty()); // There should be at least one, from the above check
|
assert(!fileSections.empty()); // There should be at least one, from the above check
|
||||||
struct Section *section = fileSections[areaIdx].section;
|
Section *section = fileSections[areaIdx].section;
|
||||||
uint16_t *writeIndex = &fileSections[areaIdx].writeIndex;
|
uint16_t *writeIndex = &fileSections[areaIdx].writeIndex;
|
||||||
uint8_t writtenOfs = ADDR_SIZE; // Bytes before this have been written to `->data`
|
uint8_t writtenOfs = ADDR_SIZE; // Bytes before this have been written to `->data`
|
||||||
uint16_t addr = data[0] | data[1] << 8;
|
uint16_t addr = data[0] | data[1] << 8;
|
||||||
@@ -489,7 +489,7 @@ void sdobj_ReadFile(struct FileStackNode const *where, FILE *file, std::vector<s
|
|||||||
warning(where, lineNo, "Unknown reloc flags 0x%x", flags & ~RELOC_ALL_FLAGS);
|
warning(where, lineNo, "Unknown reloc flags 0x%x", flags & ~RELOC_ALL_FLAGS);
|
||||||
|
|
||||||
// Turn this into a Patch
|
// Turn this into a Patch
|
||||||
struct Patch &patch = section->patches.emplace_back();
|
Patch &patch = section->patches.emplace_back();
|
||||||
|
|
||||||
patch.lineNo = lineNo;
|
patch.lineNo = lineNo;
|
||||||
patch.src = where;
|
patch.src = where;
|
||||||
@@ -520,7 +520,7 @@ void sdobj_ReadFile(struct FileStackNode const *where, FILE *file, std::vector<s
|
|||||||
if (idx >= fileSymbols.size())
|
if (idx >= fileSymbols.size())
|
||||||
fatal(where, lineNo, "Reloc refers to symbol #%" PRIu16 " out of %zu",
|
fatal(where, lineNo, "Reloc refers to symbol #%" PRIu16 " out of %zu",
|
||||||
idx, fileSymbols.size());
|
idx, fileSymbols.size());
|
||||||
struct Symbol const &sym = fileSymbols[idx];
|
Symbol const &sym = fileSymbols[idx];
|
||||||
|
|
||||||
// SDCC has a bunch of "magic symbols" that start with a
|
// SDCC has a bunch of "magic symbols" that start with a
|
||||||
// letter and an underscore. These are not compatibility
|
// letter and an underscore. These are not compatibility
|
||||||
@@ -571,7 +571,7 @@ void sdobj_ReadFile(struct FileStackNode const *where, FILE *file, std::vector<s
|
|||||||
if (fileSections[idx].section->isAddressFixed)
|
if (fileSections[idx].section->isAddressFixed)
|
||||||
baseValue -= fileSections[idx].section->org;
|
baseValue -= fileSections[idx].section->org;
|
||||||
std::string const &name = fileSections[idx].section->name;
|
std::string const &name = fileSections[idx].section->name;
|
||||||
struct Section const *other = sect_GetSection(name);
|
Section const *other = sect_GetSection(name);
|
||||||
|
|
||||||
// Unlike with `s_<AREA>`, referencing an area in this way
|
// Unlike with `s_<AREA>`, referencing an area in this way
|
||||||
// wants the beginning of this fragment, so we must add the
|
// wants the beginning of this fragment, so we must add the
|
||||||
@@ -678,8 +678,8 @@ void sdobj_ReadFile(struct FileStackNode const *where, FILE *file, std::vector<s
|
|||||||
|
|
||||||
nbSectionsToAssign += fileSections.size();
|
nbSectionsToAssign += fileSections.size();
|
||||||
|
|
||||||
for (struct FileSection &entry : fileSections) {
|
for (FileSection &entry : fileSections) {
|
||||||
struct Section *section = entry.section;
|
Section *section = entry.section;
|
||||||
|
|
||||||
// RAM sections can have a size, but don't get any data (they shouldn't have any)
|
// RAM sections can have a size, but don't get any data (they shouldn't have any)
|
||||||
if (entry.writeIndex != section->size && entry.writeIndex != 0)
|
if (entry.writeIndex != section->size && entry.writeIndex != 0)
|
||||||
@@ -690,7 +690,7 @@ void sdobj_ReadFile(struct FileStackNode const *where, FILE *file, std::vector<s
|
|||||||
|
|
||||||
if (section->modifier == SECTION_FRAGMENT) {
|
if (section->modifier == SECTION_FRAGMENT) {
|
||||||
// Add the fragment's offset to all of its symbols
|
// Add the fragment's offset to all of its symbols
|
||||||
for (struct Symbol *symbol : section->symbols)
|
for (Symbol *symbol : section->symbols)
|
||||||
symbol->offset += section->offset;
|
symbol->offset += section->offset;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -13,15 +13,15 @@
|
|||||||
#include "error.hpp"
|
#include "error.hpp"
|
||||||
#include "linkdefs.hpp"
|
#include "linkdefs.hpp"
|
||||||
|
|
||||||
std::map<std::string, struct Section *> sections;
|
std::map<std::string, Section *> sections;
|
||||||
|
|
||||||
void sect_ForEach(void (*callback)(struct Section *))
|
void sect_ForEach(void (*callback)(Section *))
|
||||||
{
|
{
|
||||||
for (auto &it : sections)
|
for (auto &it : sections)
|
||||||
callback(it.second);
|
callback(it.second);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void checkSectUnionCompat(struct Section *target, struct Section *other)
|
static void checkSectUnionCompat(Section *target, Section *other)
|
||||||
{
|
{
|
||||||
if (other->isAddressFixed) {
|
if (other->isAddressFixed) {
|
||||||
if (target->isAddressFixed) {
|
if (target->isAddressFixed) {
|
||||||
@@ -59,7 +59,7 @@ static void checkSectUnionCompat(struct Section *target, struct Section *other)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void checkFragmentCompat(struct Section *target, struct Section *other)
|
static void checkFragmentCompat(Section *target, Section *other)
|
||||||
{
|
{
|
||||||
if (other->isAddressFixed) {
|
if (other->isAddressFixed) {
|
||||||
uint16_t org = other->org - target->size;
|
uint16_t org = other->org - target->size;
|
||||||
@@ -107,7 +107,7 @@ static void checkFragmentCompat(struct Section *target, struct Section *other)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void mergeSections(struct Section *target, struct Section *other, enum SectionModifier mod)
|
static void mergeSections(Section *target, Section *other, enum SectionModifier mod)
|
||||||
{
|
{
|
||||||
// Common checks
|
// Common checks
|
||||||
|
|
||||||
@@ -144,7 +144,7 @@ static void mergeSections(struct Section *target, struct Section *other, enum Se
|
|||||||
if (!other->data.empty()) {
|
if (!other->data.empty()) {
|
||||||
target->data.insert(target->data.end(), RANGE(other->data));
|
target->data.insert(target->data.end(), RANGE(other->data));
|
||||||
// Adjust patches' PC offsets
|
// Adjust patches' PC offsets
|
||||||
for (struct Patch &patch : other->patches)
|
for (Patch &patch : other->patches)
|
||||||
patch.pcOffset += other->offset;
|
patch.pcOffset += other->offset;
|
||||||
} else if (!target->data.empty()) {
|
} else if (!target->data.empty()) {
|
||||||
assert(other->size == 0);
|
assert(other->size == 0);
|
||||||
@@ -159,10 +159,10 @@ static void mergeSections(struct Section *target, struct Section *other, enum Se
|
|||||||
target->nextu = other;
|
target->nextu = other;
|
||||||
}
|
}
|
||||||
|
|
||||||
void sect_AddSection(struct Section *section)
|
void sect_AddSection(Section *section)
|
||||||
{
|
{
|
||||||
// Check if the section already exists
|
// Check if the section already exists
|
||||||
if (struct Section *other = sect_GetSection(section->name); other) {
|
if (Section *other = sect_GetSection(section->name); other) {
|
||||||
if (section->modifier != other->modifier)
|
if (section->modifier != other->modifier)
|
||||||
errx("Section \"%s\" defined as %s and %s", section->name.c_str(),
|
errx("Section \"%s\" defined as %s and %s", section->name.c_str(),
|
||||||
sectionModNames[section->modifier], sectionModNames[other->modifier]);
|
sectionModNames[section->modifier], sectionModNames[other->modifier]);
|
||||||
@@ -179,13 +179,13 @@ void sect_AddSection(struct Section *section)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
struct Section *sect_GetSection(std::string const &name)
|
Section *sect_GetSection(std::string const &name)
|
||||||
{
|
{
|
||||||
auto search = sections.find(name);
|
auto search = sections.find(name);
|
||||||
return search != sections.end() ? search->second : NULL;
|
return search != sections.end() ? search->second : NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void doSanityChecks(struct Section *section)
|
static void doSanityChecks(Section *section)
|
||||||
{
|
{
|
||||||
// Sanity check the section's type
|
// Sanity check the section's type
|
||||||
if (section->type < 0 || section->type >= SECTTYPE_INVALID) {
|
if (section->type < 0 || section->type >= SECTTYPE_INVALID) {
|
||||||
|
|||||||
@@ -11,12 +11,12 @@
|
|||||||
|
|
||||||
#include "error.hpp"
|
#include "error.hpp"
|
||||||
|
|
||||||
std::map<std::string, struct Symbol *> symbols;
|
std::map<std::string, Symbol *> symbols;
|
||||||
|
|
||||||
void sym_AddSymbol(struct Symbol *symbol)
|
void sym_AddSymbol(Symbol *symbol)
|
||||||
{
|
{
|
||||||
// Check if the symbol already exists
|
// Check if the symbol already exists
|
||||||
if (struct Symbol *other = sym_GetSymbol(symbol->name); other) {
|
if (Symbol *other = sym_GetSymbol(symbol->name); other) {
|
||||||
fprintf(stderr, "error: \"%s\" both in %s from ", symbol->name.c_str(), symbol->objFileName);
|
fprintf(stderr, "error: \"%s\" both in %s from ", symbol->name.c_str(), symbol->objFileName);
|
||||||
dumpFileStack(symbol->src);
|
dumpFileStack(symbol->src);
|
||||||
fprintf(stderr, "(%" PRIu32 ") and in %s from ", symbol->lineNo, other->objFileName);
|
fprintf(stderr, "(%" PRIu32 ") and in %s from ", symbol->lineNo, other->objFileName);
|
||||||
@@ -29,7 +29,7 @@ void sym_AddSymbol(struct Symbol *symbol)
|
|||||||
symbols[symbol->name] = symbol;
|
symbols[symbol->name] = symbol;
|
||||||
}
|
}
|
||||||
|
|
||||||
struct Symbol *sym_GetSymbol(std::string const &name)
|
Symbol *sym_GetSymbol(std::string const &name)
|
||||||
{
|
{
|
||||||
auto search = symbols.find(name);
|
auto search = symbols.find(name);
|
||||||
return search != symbols.end() ? search->second : NULL;
|
return search != symbols.end() ? search->second : NULL;
|
||||||
|
|||||||
@@ -7,7 +7,7 @@ using namespace std::literals;
|
|||||||
|
|
||||||
// The default values are the most lax, as they are used as-is by RGBASM; only RGBLINK has the full info,
|
// The default values are the most lax, as they are used as-is by RGBASM; only RGBLINK has the full info,
|
||||||
// so RGBASM's job is only to catch unconditional errors earlier.
|
// so RGBASM's job is only to catch unconditional errors earlier.
|
||||||
struct SectionTypeInfo sectionTypeInfo[SECTTYPE_INVALID] = {
|
SectionTypeInfo sectionTypeInfo[SECTTYPE_INVALID] = {
|
||||||
{ // SECTTYPE_WRAM0
|
{ // SECTTYPE_WRAM0
|
||||||
.name = "WRAM0"s,
|
.name = "WRAM0"s,
|
||||||
.startAddr = 0xC000,
|
.startAddr = 0xC000,
|
||||||
|
|||||||
@@ -56,7 +56,7 @@ static unsigned long long getRandomBits(unsigned count) {
|
|||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void generate_tile_attributes(struct Attributes * restrict attributes) {
|
static void generate_tile_attributes(Attributes * restrict attributes) {
|
||||||
/*
|
/*
|
||||||
* Images have ten colors, grouped into two groups of 5 colors. The palette index indicates two
|
* Images have ten colors, grouped into two groups of 5 colors. The palette index indicates two
|
||||||
* things: which one of those groups will be used, and which colors out of those 5 will be used
|
* things: which one of those groups will be used, and which colors out of those 5 will be used
|
||||||
@@ -162,8 +162,8 @@ static uint8_t _5to8(uint8_t five) {
|
|||||||
|
|
||||||
// Can't mark as `const`, as the array type is otherwise not compatible (augh)
|
// Can't mark as `const`, as the array type is otherwise not compatible (augh)
|
||||||
static void write_image(char const *filename, uint16_t /* const */ palettes[MIN_NB_ELMS(60)][4],
|
static void write_image(char const *filename, uint16_t /* const */ palettes[MIN_NB_ELMS(60)][4],
|
||||||
unsigned char /* const */ (*tileData)[8][8],
|
unsigned char /* const */ (*tileData)[8][8], Attributes const *attributes,
|
||||||
struct Attributes const *attributes, uint8_t width, uint8_t height) {
|
uint8_t width, uint8_t height) {
|
||||||
uint8_t const nbTiles = width * height;
|
uint8_t const nbTiles = width * height;
|
||||||
png_structp png = png_create_write_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL);
|
png_structp png = png_create_write_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL);
|
||||||
png_infop pngInfo = png_create_info_struct(png);
|
png_infop pngInfo = png_create_info_struct(png);
|
||||||
@@ -224,7 +224,7 @@ static void write_image(char const *filename, uint16_t /* const */ palettes[MIN_
|
|||||||
static void generate_random_image(char const *filename) {
|
static void generate_random_image(char const *filename) {
|
||||||
#define MIN_TILES_PER_SIDE 3
|
#define MIN_TILES_PER_SIDE 3
|
||||||
#define MAX_TILES ((MIN_TILES_PER_SIDE + 7) * (MIN_TILES_PER_SIDE + 7))
|
#define MAX_TILES ((MIN_TILES_PER_SIDE + 7) * (MIN_TILES_PER_SIDE + 7))
|
||||||
struct Attributes attributes[MAX_TILES];
|
Attributes attributes[MAX_TILES];
|
||||||
unsigned char tileData[MAX_TILES][8][8];
|
unsigned char tileData[MAX_TILES][8][8];
|
||||||
uint8_t width = getRandomBits(3) + MIN_TILES_PER_SIDE,
|
uint8_t width = getRandomBits(3) + MIN_TILES_PER_SIDE,
|
||||||
height = getRandomBits(3) + MIN_TILES_PER_SIDE;
|
height = getRandomBits(3) + MIN_TILES_PER_SIDE;
|
||||||
|
|||||||
Reference in New Issue
Block a user