mirror of
https://github.com/gbdev/rgbds.git
synced 2025-11-20 10:12:06 +00:00
Refactor structs to use methods instead of functions (#1322)
This commit is contained in:
@@ -15,7 +15,7 @@ enum FormatState {
|
|||||||
FORMAT_INVALID, // got unexpected character
|
FORMAT_INVALID, // got unexpected character
|
||||||
};
|
};
|
||||||
|
|
||||||
struct FormatSpec {
|
class FormatSpec {
|
||||||
enum FormatState state;
|
enum FormatState state;
|
||||||
int sign;
|
int sign;
|
||||||
bool prefix;
|
bool prefix;
|
||||||
@@ -26,15 +26,16 @@ struct FormatSpec {
|
|||||||
size_t fracWidth;
|
size_t fracWidth;
|
||||||
int type;
|
int type;
|
||||||
bool valid;
|
bool valid;
|
||||||
|
|
||||||
|
public:
|
||||||
|
bool isEmpty() const { return !state; }
|
||||||
|
bool isValid() const { return valid || state == FORMAT_DONE; }
|
||||||
|
bool isFinished() const { return state >= FORMAT_DONE;}
|
||||||
|
|
||||||
|
void useCharacter(int c);
|
||||||
|
void finishCharacters();
|
||||||
|
void printString(char *buf, size_t bufLen, char const *value);
|
||||||
|
void printNumber(char *buf, size_t bufLen, uint32_t value);
|
||||||
};
|
};
|
||||||
|
|
||||||
FormatSpec fmt_NewSpec();
|
|
||||||
bool fmt_IsEmpty(FormatSpec const *fmt);
|
|
||||||
bool fmt_IsValid(FormatSpec const *fmt);
|
|
||||||
bool fmt_IsFinished(FormatSpec const *fmt);
|
|
||||||
void fmt_UseCharacter(FormatSpec *fmt, int c);
|
|
||||||
void fmt_FinishCharacters(FormatSpec *fmt);
|
|
||||||
void fmt_PrintString(char *buf, size_t bufLen, FormatSpec const *fmt, char const *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
|
||||||
|
|||||||
@@ -36,6 +36,8 @@ struct FileStackNode {
|
|||||||
// File name for files, file::macro name for macros
|
// File name for files, file::macro name for macros
|
||||||
std::string &name();
|
std::string &name();
|
||||||
std::string const &name() const;
|
std::string const &name() const;
|
||||||
|
|
||||||
|
void dump(uint32_t curLineNo) const;
|
||||||
};
|
};
|
||||||
|
|
||||||
#define DEFAULT_MAX_DEPTH 64
|
#define DEFAULT_MAX_DEPTH 64
|
||||||
@@ -43,7 +45,6 @@ extern size_t maxRecursionDepth;
|
|||||||
|
|
||||||
struct MacroArgs;
|
struct MacroArgs;
|
||||||
|
|
||||||
void fstk_Dump(FileStackNode const *node, uint32_t lineNo);
|
|
||||||
void fstk_DumpCurrent();
|
void fstk_DumpCurrent();
|
||||||
FileStackNode *fstk_GetFileStack();
|
FileStackNode *fstk_GetFileStack();
|
||||||
// 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
|
||||||
|
|||||||
@@ -5,18 +5,22 @@
|
|||||||
|
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
#include "asm/warning.hpp"
|
#include "asm/warning.hpp"
|
||||||
|
|
||||||
#include "helpers.hpp"
|
#include "helpers.hpp"
|
||||||
|
|
||||||
struct MacroArgs;
|
struct MacroArgs {
|
||||||
|
unsigned int shift;
|
||||||
|
std::vector<char *> args;
|
||||||
|
|
||||||
|
void append(char *s);
|
||||||
|
void clear();
|
||||||
|
};
|
||||||
|
|
||||||
MacroArgs *macro_GetCurrentArgs();
|
MacroArgs *macro_GetCurrentArgs();
|
||||||
MacroArgs *macro_NewArgs();
|
|
||||||
void macro_AppendArg(MacroArgs *args, char *s);
|
|
||||||
void macro_UseNewArgs(MacroArgs *args);
|
void macro_UseNewArgs(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();
|
char const *macro_GetAllArgs();
|
||||||
|
|
||||||
|
|||||||
@@ -13,29 +13,19 @@ 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
|
||||||
bool isKnown; // Whether the expression's value is known
|
bool isKnown; // Whether the expression's value is known at assembly time
|
||||||
bool isSymbol; // Whether the expression represents a symbol
|
bool isSymbol; // Whether the expression represents a symbol suitable for const diffing
|
||||||
std::vector<uint8_t> *rpn; // Bytes serializing the RPN expression
|
std::vector<uint8_t> *rpn; // Bytes serializing the RPN expression
|
||||||
uint32_t rpnPatchSize; // Size the expression will take in the object file
|
uint32_t rpnPatchSize; // Size the expression will take in the object file
|
||||||
|
|
||||||
|
int32_t getConstVal() const;
|
||||||
|
Symbol const *symbolOf() const;
|
||||||
|
bool isDiffConstant(Symbol const *symName) const;
|
||||||
};
|
};
|
||||||
|
|
||||||
// Determines if an expression is known at assembly time
|
|
||||||
static inline bool rpn_isKnown(Expression const *expr)
|
|
||||||
{
|
|
||||||
return expr->isKnown;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Determines if an expression is a symbol suitable for const diffing
|
|
||||||
static inline bool rpn_isSymbol(const Expression *expr)
|
|
||||||
{
|
|
||||||
return expr->isSymbol;
|
|
||||||
}
|
|
||||||
|
|
||||||
void rpn_Symbol(Expression *expr, char const *symName);
|
void rpn_Symbol(Expression *expr, char const *symName);
|
||||||
void rpn_Number(Expression *expr, uint32_t i);
|
void rpn_Number(Expression *expr, uint32_t i);
|
||||||
void rpn_LOGNOT(Expression *expr, const Expression *src);
|
void rpn_LOGNOT(Expression *expr, const Expression *src);
|
||||||
Symbol const *rpn_SymbolOf(Expression const *expr);
|
|
||||||
bool rpn_IsDiffConstant(Expression const *src, Symbol const *symName);
|
|
||||||
void rpn_BinaryOp(enum RPNCommand op, Expression *expr, const Expression *src1, const Expression *src2);
|
void rpn_BinaryOp(enum RPNCommand op, Expression *expr, const Expression *src1, const Expression *src2);
|
||||||
void rpn_HIGH(Expression *expr, const Expression *src);
|
void rpn_HIGH(Expression *expr, const Expression *src);
|
||||||
void rpn_LOW(Expression *expr, const Expression *src);
|
void rpn_LOW(Expression *expr, const Expression *src);
|
||||||
@@ -49,10 +39,11 @@ void rpn_SizeOfSection(Expression *expr, char const *sectionName);
|
|||||||
void rpn_StartOfSection(Expression *expr, char const *sectionName);
|
void rpn_StartOfSection(Expression *expr, char const *sectionName);
|
||||||
void rpn_SizeOfSectionType(Expression *expr, enum SectionType type);
|
void rpn_SizeOfSectionType(Expression *expr, enum SectionType type);
|
||||||
void rpn_StartOfSectionType(Expression *expr, enum SectionType type);
|
void rpn_StartOfSectionType(Expression *expr, enum SectionType type);
|
||||||
|
|
||||||
void rpn_Free(Expression *expr);
|
void rpn_Free(Expression *expr);
|
||||||
|
|
||||||
void rpn_CheckHRAM(Expression *expr, const Expression *src);
|
void rpn_CheckHRAM(Expression *expr, const Expression *src);
|
||||||
void rpn_CheckRST(Expression *expr, const Expression *src);
|
void rpn_CheckRST(Expression *expr, const Expression *src);
|
||||||
void rpn_CheckNBit(Expression const *expr, uint8_t n);
|
void rpn_CheckNBit(Expression const *expr, uint8_t n);
|
||||||
int32_t rpn_GetConstVal(Expression const *expr);
|
|
||||||
|
|
||||||
#endif // RGBDS_ASM_RPN_H
|
#endif // RGBDS_ASM_RPN_H
|
||||||
|
|||||||
@@ -8,7 +8,6 @@
|
|||||||
#include <vector>
|
#include <vector>
|
||||||
|
|
||||||
#include "linkdefs.hpp"
|
#include "linkdefs.hpp"
|
||||||
#include "platform.hpp" // NONNULL
|
|
||||||
|
|
||||||
extern uint8_t fillByte;
|
extern uint8_t fillByte;
|
||||||
|
|
||||||
@@ -39,6 +38,8 @@ struct Section {
|
|||||||
uint16_t alignOfs;
|
uint16_t alignOfs;
|
||||||
std::deque<Patch> patches;
|
std::deque<Patch> patches;
|
||||||
std::vector<uint8_t> data;
|
std::vector<uint8_t> data;
|
||||||
|
|
||||||
|
bool isSizeKnown() const;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct SectionSpec {
|
struct SectionSpec {
|
||||||
@@ -85,6 +86,4 @@ void sect_EndSection();
|
|||||||
void sect_PushSection();
|
void sect_PushSection();
|
||||||
void sect_PopSection();
|
void sect_PopSection();
|
||||||
|
|
||||||
bool sect_IsSizeKnown(Section const NONNULL(name));
|
|
||||||
|
|
||||||
#endif // RGBDS_SECTION_H
|
#endif // RGBDS_SECTION_H
|
||||||
|
|||||||
@@ -29,6 +29,9 @@ struct strValue {
|
|||||||
char *value;
|
char *value;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
struct Symbol; // For the `sym_IsPC` forward declaration
|
||||||
|
bool sym_IsPC(Symbol const *sym); // For the inline `getSection` method
|
||||||
|
|
||||||
struct Symbol {
|
struct Symbol {
|
||||||
char name[MAXSYMLEN + 1];
|
char name[MAXSYMLEN + 1];
|
||||||
enum SymbolType type;
|
enum SymbolType type;
|
||||||
@@ -40,7 +43,7 @@ struct Symbol {
|
|||||||
|
|
||||||
bool hasCallback;
|
bool hasCallback;
|
||||||
union {
|
union {
|
||||||
// If sym_IsNumeric
|
// If isNumeric()
|
||||||
int32_t value;
|
int32_t value;
|
||||||
int32_t (*numCallback)(); // If hasCallback
|
int32_t (*numCallback)(); // If hasCallback
|
||||||
// For SYM_MACRO
|
// For SYM_MACRO
|
||||||
@@ -51,61 +54,28 @@ struct Symbol {
|
|||||||
};
|
};
|
||||||
|
|
||||||
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(Symbol const *sym);
|
bool isDefined() const { return type != SYM_REF; }
|
||||||
|
bool isNumeric() const { return type == SYM_LABEL || type == SYM_EQU || type == SYM_VAR; }
|
||||||
static inline bool sym_IsDefined(Symbol const *sym)
|
bool isLabel() const { return type == SYM_LABEL || type == SYM_REF; }
|
||||||
{
|
|
||||||
return sym->type != SYM_REF;
|
|
||||||
}
|
|
||||||
|
|
||||||
static inline Section *sym_GetSection(Symbol const *sym)
|
|
||||||
{
|
|
||||||
return sym_IsPC(sym) ? sect_GetSymbolSection() : sym->section;
|
|
||||||
}
|
|
||||||
|
|
||||||
static inline bool sym_IsConstant(Symbol const *sym)
|
|
||||||
{
|
|
||||||
if (sym->type == SYM_LABEL) {
|
|
||||||
Section const *sect = sym_GetSection(sym);
|
|
||||||
|
|
||||||
|
bool isConstant() const {
|
||||||
|
if (type == SYM_LABEL) {
|
||||||
|
Section const *sect = getSection();
|
||||||
return sect && sect->org != (uint32_t)-1;
|
return sect && sect->org != (uint32_t)-1;
|
||||||
}
|
}
|
||||||
return sym->type == SYM_EQU || sym->type == SYM_VAR;
|
return type == SYM_EQU || type == SYM_VAR;
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline bool sym_IsNumeric(Symbol const *sym)
|
Section *getSection() const { return sym_IsPC(this) ? sect_GetSymbolSection() : section; }
|
||||||
{
|
|
||||||
return sym->type == SYM_LABEL || sym->type == SYM_EQU || sym->type == SYM_VAR;
|
|
||||||
}
|
|
||||||
|
|
||||||
static inline bool sym_IsLabel(Symbol const *sym)
|
int32_t getValue() const;
|
||||||
{
|
uint32_t getConstantValue() const;
|
||||||
return sym->type == SYM_LABEL || sym->type == SYM_REF;
|
char const *getStringValue() const { return hasCallback ? strCallback() : equs.value; }
|
||||||
}
|
};
|
||||||
|
|
||||||
static inline bool sym_IsLocal(Symbol const *sym)
|
|
||||||
{
|
|
||||||
return sym_IsLabel(sym) && strchr(sym->name, '.');
|
|
||||||
}
|
|
||||||
|
|
||||||
static inline bool sym_IsExported(Symbol const *sym)
|
|
||||||
{
|
|
||||||
return sym->isExported;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Get a string equate's value
|
|
||||||
static inline char const *sym_GetStringValue(Symbol const *sym)
|
|
||||||
{
|
|
||||||
if (sym->hasCallback)
|
|
||||||
return sym->strCallback();
|
|
||||||
return sym->equs.value;
|
|
||||||
}
|
|
||||||
|
|
||||||
void sym_ForEach(void (*func)(Symbol *));
|
void sym_ForEach(void (*func)(Symbol *));
|
||||||
|
|
||||||
int32_t sym_GetValue(Symbol const *sym);
|
|
||||||
void sym_SetExportAll(bool set);
|
void sym_SetExportAll(bool set);
|
||||||
Symbol *sym_AddLocalLabel(char const *symName);
|
Symbol *sym_AddLocalLabel(char const *symName);
|
||||||
Symbol *sym_AddLabel(char const *symName);
|
Symbol *sym_AddLabel(char const *symName);
|
||||||
@@ -116,7 +86,6 @@ Symbol *sym_AddEqu(char const *symName, int32_t value);
|
|||||||
Symbol *sym_RedefEqu(char const *symName, int32_t value);
|
Symbol *sym_RedefEqu(char const *symName, int32_t value);
|
||||||
Symbol *sym_AddVar(char const *symName, int32_t value);
|
Symbol *sym_AddVar(char const *symName, int32_t value);
|
||||||
uint32_t sym_GetPCValue();
|
uint32_t sym_GetPCValue();
|
||||||
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
|
||||||
Symbol *sym_FindExactSymbol(char const *symName);
|
Symbol *sym_FindExactSymbol(char const *symName);
|
||||||
|
|||||||
@@ -30,6 +30,12 @@ extern bool beVerbose;
|
|||||||
extern bool isWRAM0Mode;
|
extern bool isWRAM0Mode;
|
||||||
extern bool disablePadding;
|
extern bool disablePadding;
|
||||||
|
|
||||||
|
// Helper macro for printing verbose-mode messages
|
||||||
|
#define verbosePrint(...) do { \
|
||||||
|
if (beVerbose) \
|
||||||
|
fprintf(stderr, __VA_ARGS__); \
|
||||||
|
} while (0)
|
||||||
|
|
||||||
struct FileStackNode {
|
struct FileStackNode {
|
||||||
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
|
||||||
@@ -48,24 +54,12 @@ struct FileStackNode {
|
|||||||
// File name for files, file::macro name for macros
|
// File name for files, file::macro name for macros
|
||||||
std::string &name();
|
std::string &name();
|
||||||
std::string const &name() const;
|
std::string const &name() const;
|
||||||
|
|
||||||
|
std::string const *dumpFileStack() const;
|
||||||
};
|
};
|
||||||
|
|
||||||
// Helper macro for printing verbose-mode messages
|
|
||||||
#define verbosePrint(...) do { \
|
|
||||||
if (beVerbose) \
|
|
||||||
fprintf(stderr, __VA_ARGS__); \
|
|
||||||
} while (0)
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Dump a file stack to stderr
|
|
||||||
* @param node The leaf node to dump the context of
|
|
||||||
*/
|
|
||||||
std::string const *dumpFileStack(FileStackNode const *node);
|
|
||||||
|
|
||||||
void warning(FileStackNode const *where, uint32_t lineNo, char const *fmt, ...) format_(printf, 3, 4);
|
void warning(FileStackNode const *where, uint32_t lineNo, char const *fmt, ...) format_(printf, 3, 4);
|
||||||
|
|
||||||
void error(FileStackNode const *where, uint32_t lineNo, char const *fmt, ...) format_(printf, 3, 4);
|
void error(FileStackNode const *where, uint32_t lineNo, char const *fmt, ...) format_(printf, 3, 4);
|
||||||
|
|
||||||
[[noreturn]] void fatal(FileStackNode const *where, uint32_t lineNo, char const *fmt, ...) format_(printf, 3, 4);
|
[[noreturn]] void fatal(FileStackNode const *where, uint32_t lineNo, char const *fmt, ...) format_(printf, 3, 4);
|
||||||
|
|
||||||
#endif // RGBDS_LINK_MAIN_H
|
#endif // RGBDS_LINK_MAIN_H
|
||||||
|
|||||||
@@ -12,63 +12,41 @@
|
|||||||
#include "asm/format.hpp"
|
#include "asm/format.hpp"
|
||||||
#include "asm/warning.hpp"
|
#include "asm/warning.hpp"
|
||||||
|
|
||||||
FormatSpec fmt_NewSpec()
|
void FormatSpec::useCharacter(int c)
|
||||||
{
|
{
|
||||||
FormatSpec fmt = {};
|
if (state == FORMAT_INVALID)
|
||||||
|
|
||||||
return fmt;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool fmt_IsEmpty(FormatSpec const *fmt)
|
|
||||||
{
|
|
||||||
return !fmt->state;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool fmt_IsValid(FormatSpec const *fmt)
|
|
||||||
{
|
|
||||||
return fmt->valid || fmt->state == FORMAT_DONE;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool fmt_IsFinished(FormatSpec const *fmt)
|
|
||||||
{
|
|
||||||
return fmt->state >= FORMAT_DONE;
|
|
||||||
}
|
|
||||||
|
|
||||||
void fmt_UseCharacter(FormatSpec *fmt, int c)
|
|
||||||
{
|
|
||||||
if (fmt->state == FORMAT_INVALID)
|
|
||||||
return;
|
return;
|
||||||
|
|
||||||
switch (c) {
|
switch (c) {
|
||||||
// sign
|
// sign
|
||||||
case ' ':
|
case ' ':
|
||||||
case '+':
|
case '+':
|
||||||
if (fmt->state > FORMAT_SIGN)
|
if (state > FORMAT_SIGN)
|
||||||
goto invalid;
|
goto invalid;
|
||||||
fmt->state = FORMAT_PREFIX;
|
state = FORMAT_PREFIX;
|
||||||
fmt->sign = c;
|
sign = c;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
// prefix
|
// prefix
|
||||||
case '#':
|
case '#':
|
||||||
if (fmt->state > FORMAT_PREFIX)
|
if (state > FORMAT_PREFIX)
|
||||||
goto invalid;
|
goto invalid;
|
||||||
fmt->state = FORMAT_ALIGN;
|
state = FORMAT_ALIGN;
|
||||||
fmt->prefix = true;
|
prefix = true;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
// align
|
// align
|
||||||
case '-':
|
case '-':
|
||||||
if (fmt->state > FORMAT_ALIGN)
|
if (state > FORMAT_ALIGN)
|
||||||
goto invalid;
|
goto invalid;
|
||||||
fmt->state = FORMAT_WIDTH;
|
state = FORMAT_WIDTH;
|
||||||
fmt->alignLeft = true;
|
alignLeft = true;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
// pad and width
|
// pad and width
|
||||||
case '0':
|
case '0':
|
||||||
if (fmt->state < FORMAT_WIDTH)
|
if (state < FORMAT_WIDTH)
|
||||||
fmt->padZero = true;
|
padZero = true;
|
||||||
// fallthrough
|
// fallthrough
|
||||||
case '1':
|
case '1':
|
||||||
case '2':
|
case '2':
|
||||||
@@ -79,23 +57,23 @@ void fmt_UseCharacter(FormatSpec *fmt, int c)
|
|||||||
case '7':
|
case '7':
|
||||||
case '8':
|
case '8':
|
||||||
case '9':
|
case '9':
|
||||||
if (fmt->state < FORMAT_WIDTH) {
|
if (state < FORMAT_WIDTH) {
|
||||||
fmt->state = FORMAT_WIDTH;
|
state = FORMAT_WIDTH;
|
||||||
fmt->width = c - '0';
|
width = c - '0';
|
||||||
} else if (fmt->state == FORMAT_WIDTH) {
|
} else if (state == FORMAT_WIDTH) {
|
||||||
fmt->width = fmt->width * 10 + (c - '0');
|
width = width * 10 + (c - '0');
|
||||||
} else if (fmt->state == FORMAT_FRAC) {
|
} else if (state == FORMAT_FRAC) {
|
||||||
fmt->fracWidth = fmt->fracWidth * 10 + (c - '0');
|
fracWidth = fracWidth * 10 + (c - '0');
|
||||||
} else {
|
} else {
|
||||||
goto invalid;
|
goto invalid;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case '.':
|
case '.':
|
||||||
if (fmt->state > FORMAT_WIDTH)
|
if (state > FORMAT_WIDTH)
|
||||||
goto invalid;
|
goto invalid;
|
||||||
fmt->state = FORMAT_FRAC;
|
state = FORMAT_FRAC;
|
||||||
fmt->hasFrac = true;
|
hasFrac = true;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
// type
|
// type
|
||||||
@@ -107,41 +85,46 @@ void fmt_UseCharacter(FormatSpec *fmt, int c)
|
|||||||
case 'o':
|
case 'o':
|
||||||
case 'f':
|
case 'f':
|
||||||
case 's':
|
case 's':
|
||||||
if (fmt->state >= FORMAT_DONE)
|
if (state >= FORMAT_DONE)
|
||||||
goto invalid;
|
goto invalid;
|
||||||
fmt->state = FORMAT_DONE;
|
state = FORMAT_DONE;
|
||||||
fmt->valid = true;
|
valid = true;
|
||||||
fmt->type = c;
|
type = c;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
invalid:
|
invalid:
|
||||||
fmt->state = FORMAT_INVALID;
|
state = FORMAT_INVALID;
|
||||||
fmt->valid = false;
|
valid = false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void fmt_FinishCharacters(FormatSpec *fmt)
|
void FormatSpec::finishCharacters()
|
||||||
{
|
{
|
||||||
if (!fmt_IsValid(fmt))
|
if (!isValid())
|
||||||
fmt->state = FORMAT_INVALID;
|
state = FORMAT_INVALID;
|
||||||
}
|
}
|
||||||
|
|
||||||
void fmt_PrintString(char *buf, size_t bufLen, FormatSpec const *fmt, char const *value)
|
void FormatSpec::printString(char *buf, size_t bufLen, char const *value)
|
||||||
{
|
{
|
||||||
if (fmt->sign)
|
if (isEmpty()) {
|
||||||
error("Formatting string with sign flag '%c'\n", fmt->sign);
|
// No format was specified
|
||||||
if (fmt->prefix)
|
type = 's';
|
||||||
|
}
|
||||||
|
|
||||||
|
if (sign)
|
||||||
|
error("Formatting string with sign flag '%c'\n", sign);
|
||||||
|
if (prefix)
|
||||||
error("Formatting string with prefix flag '#'\n");
|
error("Formatting string with prefix flag '#'\n");
|
||||||
if (fmt->padZero)
|
if (padZero)
|
||||||
error("Formatting string with padding flag '0'\n");
|
error("Formatting string with padding flag '0'\n");
|
||||||
if (fmt->hasFrac)
|
if (hasFrac)
|
||||||
error("Formatting string with fractional width\n");
|
error("Formatting string with fractional width\n");
|
||||||
if (fmt->type != 's')
|
if (type != 's')
|
||||||
error("Formatting string as type '%c'\n", fmt->type);
|
error("Formatting string as type '%c'\n", type);
|
||||||
|
|
||||||
size_t len = strlen(value);
|
size_t len = strlen(value);
|
||||||
size_t totalLen = fmt->width > len ? fmt->width : len;
|
size_t totalLen = width > len ? width : len;
|
||||||
|
|
||||||
if (totalLen > bufLen - 1) { // bufLen includes terminator
|
if (totalLen > bufLen - 1) { // bufLen includes terminator
|
||||||
error("Formatted string value too long\n");
|
error("Formatted string value too long\n");
|
||||||
@@ -153,7 +136,7 @@ void fmt_PrintString(char *buf, size_t bufLen, FormatSpec const *fmt, char const
|
|||||||
|
|
||||||
size_t padLen = totalLen - len;
|
size_t padLen = totalLen - len;
|
||||||
|
|
||||||
if (fmt->alignLeft) {
|
if (alignLeft) {
|
||||||
memcpy(buf, value, len);
|
memcpy(buf, value, len);
|
||||||
for (size_t i = len; i < totalLen; i++)
|
for (size_t i = len; i < totalLen; i++)
|
||||||
buf[i] = ' ';
|
buf[i] = ' ';
|
||||||
@@ -166,37 +149,42 @@ void fmt_PrintString(char *buf, size_t bufLen, FormatSpec const *fmt, char const
|
|||||||
buf[totalLen] = '\0';
|
buf[totalLen] = '\0';
|
||||||
}
|
}
|
||||||
|
|
||||||
void fmt_PrintNumber(char *buf, size_t bufLen, FormatSpec const *fmt, uint32_t value)
|
void FormatSpec::printNumber(char *buf, size_t bufLen, uint32_t value)
|
||||||
{
|
{
|
||||||
if (fmt->type != 'X' && fmt->type != 'x' && fmt->type != 'b' && fmt->type != 'o'
|
if (isEmpty()) {
|
||||||
&& fmt->prefix)
|
// No format was specified; default to uppercase $hex
|
||||||
error("Formatting type '%c' with prefix flag '#'\n", fmt->type);
|
type = 'X';
|
||||||
if (fmt->type != 'f' && fmt->hasFrac)
|
prefix = true;
|
||||||
error("Formatting type '%c' with fractional width\n", fmt->type);
|
}
|
||||||
if (fmt->type == 's')
|
|
||||||
|
if (type != 'X' && type != 'x' && type != 'b' && type != 'o' && prefix)
|
||||||
|
error("Formatting type '%c' with prefix flag '#'\n", type);
|
||||||
|
if (type != 'f' && hasFrac)
|
||||||
|
error("Formatting type '%c' with fractional width\n", type);
|
||||||
|
if (type == 's')
|
||||||
error("Formatting number as type 's'\n");
|
error("Formatting number as type 's'\n");
|
||||||
|
|
||||||
char sign = fmt->sign; // 0 or ' ' or '+'
|
char signChar = sign; // 0 or ' ' or '+'
|
||||||
|
|
||||||
if (fmt->type == 'd' || fmt->type == 'f') {
|
if (type == 'd' || type == 'f') {
|
||||||
int32_t v = value;
|
int32_t v = value;
|
||||||
|
|
||||||
if (v < 0 && v != INT32_MIN) {
|
if (v < 0 && v != INT32_MIN) {
|
||||||
sign = '-';
|
signChar = '-';
|
||||||
value = -v;
|
value = -v;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
char prefix = !fmt->prefix ? 0
|
char prefixChar = !prefix ? 0
|
||||||
: fmt->type == 'X' ? '$'
|
: type == 'X' ? '$'
|
||||||
: fmt->type == 'x' ? '$'
|
: type == 'x' ? '$'
|
||||||
: fmt->type == 'b' ? '%'
|
: type == 'b' ? '%'
|
||||||
: fmt->type == 'o' ? '&'
|
: type == 'o' ? '&'
|
||||||
: 0;
|
: 0;
|
||||||
|
|
||||||
char valueBuf[262]; // Max 5 digits + decimal + 255 fraction digits + terminator
|
char valueBuf[262]; // Max 5 digits + decimal + 255 fraction digits + terminator
|
||||||
|
|
||||||
if (fmt->type == 'b') {
|
if (type == 'b') {
|
||||||
// Special case for binary
|
// Special case for binary
|
||||||
char *ptr = valueBuf;
|
char *ptr = valueBuf;
|
||||||
|
|
||||||
@@ -216,34 +204,33 @@ void fmt_PrintNumber(char *buf, size_t bufLen, FormatSpec const *fmt, uint32_t v
|
|||||||
valueBuf[i] = valueBuf[j];
|
valueBuf[i] = valueBuf[j];
|
||||||
valueBuf[j] = c;
|
valueBuf[j] = c;
|
||||||
}
|
}
|
||||||
} else if (fmt->type == 'f') {
|
} else if (type == 'f') {
|
||||||
// Special case for fixed-point
|
// Special case for fixed-point
|
||||||
|
|
||||||
// Default fractional width (C++'s is 6 for "%f"; here 5 is enough for Q16.16)
|
// Default fractional width (C++'s is 6 for "%f"; here 5 is enough for Q16.16)
|
||||||
size_t fracWidth = fmt->hasFrac ? fmt->fracWidth : 5;
|
size_t cappedFracWidth = hasFrac ? fracWidth : 5;
|
||||||
|
|
||||||
if (fracWidth > 255) {
|
if (cappedFracWidth > 255) {
|
||||||
error("Fractional width %zu too long, limiting to 255\n",
|
error("Fractional width %zu too long, limiting to 255\n", cappedFracWidth);
|
||||||
fracWidth);
|
cappedFracWidth = 255;
|
||||||
fracWidth = 255;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
snprintf(valueBuf, sizeof(valueBuf), "%.*f", (int)fracWidth,
|
snprintf(valueBuf, sizeof(valueBuf), "%.*f", (int)cappedFracWidth,
|
||||||
value / fix_PrecisionFactor());
|
value / fix_PrecisionFactor());
|
||||||
} else {
|
} else {
|
||||||
char const *spec = fmt->type == 'd' ? "%" PRId32
|
char const *spec = type == 'd' ? "%" PRId32
|
||||||
: fmt->type == 'u' ? "%" PRIu32
|
: type == 'u' ? "%" PRIu32
|
||||||
: fmt->type == 'X' ? "%" PRIX32
|
: type == 'X' ? "%" PRIX32
|
||||||
: fmt->type == 'x' ? "%" PRIx32
|
: type == 'x' ? "%" PRIx32
|
||||||
: fmt->type == 'o' ? "%" PRIo32
|
: type == 'o' ? "%" PRIo32
|
||||||
: "%" PRId32;
|
: "%" PRId32;
|
||||||
|
|
||||||
snprintf(valueBuf, sizeof(valueBuf), spec, value);
|
snprintf(valueBuf, sizeof(valueBuf), spec, value);
|
||||||
}
|
}
|
||||||
|
|
||||||
size_t len = strlen(valueBuf);
|
size_t len = strlen(valueBuf);
|
||||||
size_t numLen = (sign != 0) + (prefix != 0) + len;
|
size_t numLen = (signChar != 0) + (prefixChar != 0) + len;
|
||||||
size_t totalLen = fmt->width > numLen ? fmt->width : numLen;
|
size_t totalLen = width > numLen ? width : numLen;
|
||||||
|
|
||||||
if (totalLen > bufLen - 1) { // bufLen includes terminator
|
if (totalLen > bufLen - 1) { // bufLen includes terminator
|
||||||
error("Formatted numeric value too long\n");
|
error("Formatted numeric value too long\n");
|
||||||
@@ -258,31 +245,31 @@ void fmt_PrintNumber(char *buf, size_t bufLen, FormatSpec const *fmt, uint32_t v
|
|||||||
size_t padLen = totalLen - numLen;
|
size_t padLen = totalLen - numLen;
|
||||||
size_t pos = 0;
|
size_t pos = 0;
|
||||||
|
|
||||||
if (fmt->alignLeft) {
|
if (alignLeft) {
|
||||||
if (sign)
|
if (signChar)
|
||||||
buf[pos++] = sign;
|
buf[pos++] = signChar;
|
||||||
if (prefix)
|
if (prefixChar)
|
||||||
buf[pos++] = prefix;
|
buf[pos++] = prefixChar;
|
||||||
memcpy(buf + pos, valueBuf, len);
|
memcpy(buf + pos, valueBuf, len);
|
||||||
for (size_t i = pos + len; i < totalLen; i++)
|
for (size_t i = pos + len; i < totalLen; i++)
|
||||||
buf[i] = ' ';
|
buf[i] = ' ';
|
||||||
} else {
|
} else {
|
||||||
if (fmt->padZero) {
|
if (padZero) {
|
||||||
// sign, then prefix, then zero padding
|
// sign, then prefix, then zero padding
|
||||||
if (sign)
|
if (signChar)
|
||||||
buf[pos++] = sign;
|
buf[pos++] = signChar;
|
||||||
if (prefix)
|
if (prefixChar)
|
||||||
buf[pos++] = prefix;
|
buf[pos++] = prefixChar;
|
||||||
for (size_t i = 0; i < padLen; i++)
|
for (size_t i = 0; i < padLen; i++)
|
||||||
buf[pos++] = '0';
|
buf[pos++] = '0';
|
||||||
} else {
|
} else {
|
||||||
// space padding, then sign, then prefix
|
// space padding, then sign, then prefix
|
||||||
for (size_t i = 0; i < padLen; i++)
|
for (size_t i = 0; i < padLen; i++)
|
||||||
buf[pos++] = ' ';
|
buf[pos++] = ' ';
|
||||||
if (sign)
|
if (signChar)
|
||||||
buf[pos++] = sign;
|
buf[pos++] = signChar;
|
||||||
if (prefix)
|
if (prefixChar)
|
||||||
buf[pos++] = prefix;
|
buf[pos++] = prefixChar;
|
||||||
}
|
}
|
||||||
memcpy(buf + pos, valueBuf, len);
|
memcpy(buf + pos, valueBuf, len);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -42,6 +42,26 @@ static std::vector<std::string> includePaths = { "" };
|
|||||||
|
|
||||||
static const char *preIncludeName;
|
static const char *preIncludeName;
|
||||||
|
|
||||||
|
std::vector<uint32_t> &FileStackNode::iters() {
|
||||||
|
assert(std::holds_alternative<std::vector<uint32_t>>(data));
|
||||||
|
return std::get<std::vector<uint32_t>>(data);
|
||||||
|
}
|
||||||
|
|
||||||
|
std::vector<uint32_t> const &FileStackNode::iters() const {
|
||||||
|
assert(std::holds_alternative<std::vector<uint32_t>>(data));
|
||||||
|
return std::get<std::vector<uint32_t>>(data);
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string &FileStackNode::name() {
|
||||||
|
assert(std::holds_alternative<std::string>(data));
|
||||||
|
return std::get<std::string>(data);
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string const &FileStackNode::name() const {
|
||||||
|
assert(std::holds_alternative<std::string>(data));
|
||||||
|
return std::get<std::string>(data);
|
||||||
|
}
|
||||||
|
|
||||||
static const char *dumpNodeAndParents(FileStackNode const *node)
|
static const char *dumpNodeAndParents(FileStackNode const *node)
|
||||||
{
|
{
|
||||||
char const *name;
|
char const *name;
|
||||||
@@ -66,30 +86,10 @@ static const char *dumpNodeAndParents(FileStackNode const *node)
|
|||||||
return name;
|
return name;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::vector<uint32_t> &FileStackNode::iters() {
|
void FileStackNode::dump(uint32_t curLineNo) const
|
||||||
assert(std::holds_alternative<std::vector<uint32_t>>(data));
|
|
||||||
return std::get<std::vector<uint32_t>>(data);
|
|
||||||
}
|
|
||||||
|
|
||||||
std::vector<uint32_t> const &FileStackNode::iters() const {
|
|
||||||
assert(std::holds_alternative<std::vector<uint32_t>>(data));
|
|
||||||
return std::get<std::vector<uint32_t>>(data);
|
|
||||||
}
|
|
||||||
|
|
||||||
std::string &FileStackNode::name() {
|
|
||||||
assert(std::holds_alternative<std::string>(data));
|
|
||||||
return std::get<std::string>(data);
|
|
||||||
}
|
|
||||||
|
|
||||||
std::string const &FileStackNode::name() const {
|
|
||||||
assert(std::holds_alternative<std::string>(data));
|
|
||||||
return std::get<std::string>(data);
|
|
||||||
}
|
|
||||||
|
|
||||||
void fstk_Dump(FileStackNode const *node, uint32_t lineNo)
|
|
||||||
{
|
{
|
||||||
dumpNodeAndParents(node);
|
dumpNodeAndParents(this);
|
||||||
fprintf(stderr, "(%" PRIu32 ")", lineNo);
|
fprintf(stderr, "(%" PRIu32 ")", curLineNo);
|
||||||
}
|
}
|
||||||
|
|
||||||
void fstk_DumpCurrent()
|
void fstk_DumpCurrent()
|
||||||
@@ -98,7 +98,7 @@ void fstk_DumpCurrent()
|
|||||||
fputs("at top level", stderr);
|
fputs("at top level", stderr);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
fstk_Dump(contextStack.top().fileInfo, lexer_GetLineNo());
|
contextStack.top().fileInfo->dump(lexer_GetLineNo());
|
||||||
}
|
}
|
||||||
|
|
||||||
FileStackNode *fstk_GetFileStack()
|
FileStackNode *fstk_GetFileStack()
|
||||||
@@ -240,7 +240,7 @@ bool yywrap()
|
|||||||
lexer_CleanupState(oldContext.lexerState);
|
lexer_CleanupState(oldContext.lexerState);
|
||||||
// Restore args if a macro (not REPT) saved them
|
// Restore args if a macro (not REPT) saved them
|
||||||
if (oldContext.fileInfo->type == NODE_MACRO) {
|
if (oldContext.fileInfo->type == NODE_MACRO) {
|
||||||
macro_FreeArgs(macro_GetCurrentArgs());
|
macro_GetCurrentArgs()->clear();
|
||||||
macro_UseNewArgs(contextStack.top().macroArgs);
|
macro_UseNewArgs(contextStack.top().macroArgs);
|
||||||
}
|
}
|
||||||
// Free the file stack node
|
// Free the file stack node
|
||||||
|
|||||||
@@ -579,12 +579,12 @@ static uint32_t readBracketedMacroArgNum()
|
|||||||
error("Bracketed symbol \"%s\" does not exist\n", symName);
|
error("Bracketed symbol \"%s\" does not exist\n", symName);
|
||||||
num = 0;
|
num = 0;
|
||||||
symbolError = true;
|
symbolError = true;
|
||||||
} else if (!sym_IsNumeric(sym)) {
|
} else if (!sym->isNumeric()) {
|
||||||
error("Bracketed symbol \"%s\" is not numeric\n", symName);
|
error("Bracketed symbol \"%s\" is not numeric\n", symName);
|
||||||
num = 0;
|
num = 0;
|
||||||
symbolError = true;
|
symbolError = true;
|
||||||
} else {
|
} else {
|
||||||
num = sym_GetConstantSymValue(sym);
|
num = sym->getConstantValue();
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
empty = true;
|
empty = true;
|
||||||
@@ -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;
|
||||||
FormatSpec fmt = fmt_NewSpec();
|
FormatSpec fmt{};
|
||||||
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
|
||||||
@@ -1208,7 +1208,7 @@ static char const *readInterpolation(size_t depth)
|
|||||||
} else if (c == '}') {
|
} else if (c == '}') {
|
||||||
shiftChar();
|
shiftChar();
|
||||||
break;
|
break;
|
||||||
} else if (c == ':' && !fmt_IsFinished(&fmt)) { // Format spec, only once
|
} else if (c == ':' && !fmt.isFinished()) { // Format spec, only once
|
||||||
shiftChar();
|
shiftChar();
|
||||||
if (i == sizeof(symName)) {
|
if (i == sizeof(symName)) {
|
||||||
warning(WARNING_LONG_STR, "Format spec too long, got truncated\n");
|
warning(WARNING_LONG_STR, "Format spec too long, got truncated\n");
|
||||||
@@ -1216,9 +1216,9 @@ static char const *readInterpolation(size_t depth)
|
|||||||
}
|
}
|
||||||
symName[i] = '\0';
|
symName[i] = '\0';
|
||||||
for (size_t j = 0; j < i; j++)
|
for (size_t j = 0; j < i; j++)
|
||||||
fmt_UseCharacter(&fmt, symName[j]);
|
fmt.useCharacter(symName[j]);
|
||||||
fmt_FinishCharacters(&fmt);
|
fmt.finishCharacters();
|
||||||
if (!fmt_IsValid(&fmt))
|
if (!fmt.isValid())
|
||||||
error("Invalid format spec '%s'\n", symName);
|
error("Invalid format spec '%s'\n", symName);
|
||||||
i = 0; // Now that format has been set, restart at beginning of string
|
i = 0; // Now that format has been set, restart at beginning of string
|
||||||
} else {
|
} else {
|
||||||
@@ -1244,18 +1244,10 @@ static char const *readInterpolation(size_t depth)
|
|||||||
if (!sym) {
|
if (!sym) {
|
||||||
error("Interpolated symbol \"%s\" does not exist\n", symName);
|
error("Interpolated symbol \"%s\" does not exist\n", symName);
|
||||||
} else if (sym->type == SYM_EQUS) {
|
} else if (sym->type == SYM_EQUS) {
|
||||||
if (fmt_IsEmpty(&fmt))
|
fmt.printString(buf, sizeof(buf), sym->getStringValue());
|
||||||
// No format was specified
|
|
||||||
fmt.type = 's';
|
|
||||||
fmt_PrintString(buf, sizeof(buf), &fmt, sym_GetStringValue(sym));
|
|
||||||
return buf;
|
return buf;
|
||||||
} else if (sym_IsNumeric(sym)) {
|
} else if (sym->isNumeric()) {
|
||||||
if (fmt_IsEmpty(&fmt)) {
|
fmt.printNumber(buf, sizeof(buf), sym->getConstantValue());
|
||||||
// No format was specified; default to uppercase $hex
|
|
||||||
fmt.type = 'X';
|
|
||||||
fmt.prefix = true;
|
|
||||||
}
|
|
||||||
fmt_PrintNumber(buf, sizeof(buf), &fmt, sym_GetConstantSymValue(sym));
|
|
||||||
return buf;
|
return buf;
|
||||||
} else {
|
} else {
|
||||||
error("Only numerical and string symbols can be interpolated\n");
|
error("Only numerical and string symbols can be interpolated\n");
|
||||||
@@ -1884,7 +1876,7 @@ static int yylex_NORMAL()
|
|||||||
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();
|
||||||
|
|
||||||
assert(s);
|
assert(s);
|
||||||
if (s[0])
|
if (s[0])
|
||||||
|
|||||||
@@ -13,11 +13,6 @@
|
|||||||
|
|
||||||
#define MAXMACROARGS 99999
|
#define MAXMACROARGS 99999
|
||||||
|
|
||||||
struct MacroArgs {
|
|
||||||
unsigned int shift;
|
|
||||||
std::vector<char *> args;
|
|
||||||
};
|
|
||||||
|
|
||||||
static MacroArgs *macroArgs = nullptr;
|
static MacroArgs *macroArgs = nullptr;
|
||||||
static uint32_t uniqueID = 0;
|
static uint32_t uniqueID = 0;
|
||||||
static uint32_t maxUniqueID = 0;
|
static uint32_t maxUniqueID = 0;
|
||||||
@@ -27,42 +22,31 @@ static uint32_t maxUniqueID = 0;
|
|||||||
static char uniqueIDBuf[] = "_u4294967295"; // UINT32_MAX
|
static char uniqueIDBuf[] = "_u4294967295"; // UINT32_MAX
|
||||||
static char *uniqueIDPtr = nullptr;
|
static char *uniqueIDPtr = nullptr;
|
||||||
|
|
||||||
|
void MacroArgs::append(char *s)
|
||||||
|
{
|
||||||
|
if (s[0] == '\0')
|
||||||
|
warning(WARNING_EMPTY_MACRO_ARG, "Empty macro argument\n");
|
||||||
|
if (args.size() == MAXMACROARGS)
|
||||||
|
error("A maximum of " EXPAND_AND_STR(MAXMACROARGS) " arguments is allowed\n");
|
||||||
|
args.push_back(s);
|
||||||
|
}
|
||||||
|
|
||||||
|
void MacroArgs::clear()
|
||||||
|
{
|
||||||
|
for (char *arg : args)
|
||||||
|
free(arg);
|
||||||
|
}
|
||||||
|
|
||||||
MacroArgs *macro_GetCurrentArgs()
|
MacroArgs *macro_GetCurrentArgs()
|
||||||
{
|
{
|
||||||
return macroArgs;
|
return macroArgs;
|
||||||
}
|
}
|
||||||
|
|
||||||
MacroArgs *macro_NewArgs()
|
|
||||||
{
|
|
||||||
MacroArgs *args = new(std::nothrow) MacroArgs();
|
|
||||||
|
|
||||||
if (!args)
|
|
||||||
fatalerror("Unable to register macro arguments: %s\n", strerror(errno));
|
|
||||||
|
|
||||||
args->shift = 0;
|
|
||||||
return args;
|
|
||||||
}
|
|
||||||
|
|
||||||
void macro_AppendArg(MacroArgs *args, char *s)
|
|
||||||
{
|
|
||||||
if (s[0] == '\0')
|
|
||||||
warning(WARNING_EMPTY_MACRO_ARG, "Empty macro argument\n");
|
|
||||||
if (args->args.size() == MAXMACROARGS)
|
|
||||||
error("A maximum of " EXPAND_AND_STR(MAXMACROARGS) " arguments is allowed\n");
|
|
||||||
args->args.push_back(s);
|
|
||||||
}
|
|
||||||
|
|
||||||
void macro_UseNewArgs(MacroArgs *args)
|
void macro_UseNewArgs(MacroArgs *args)
|
||||||
{
|
{
|
||||||
macroArgs = args;
|
macroArgs = args;
|
||||||
}
|
}
|
||||||
|
|
||||||
void macro_FreeArgs(MacroArgs *args)
|
|
||||||
{
|
|
||||||
for (char *arg : args->args)
|
|
||||||
free(arg);
|
|
||||||
}
|
|
||||||
|
|
||||||
char const *macro_GetArg(uint32_t i)
|
char const *macro_GetArg(uint32_t i)
|
||||||
{
|
{
|
||||||
if (!macroArgs)
|
if (!macroArgs)
|
||||||
|
|||||||
@@ -142,7 +142,7 @@ static void writesection(Section const §, FILE *f)
|
|||||||
static void writesymbol(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()) {
|
||||||
putc(SYMTYPE_IMPORT, f);
|
putc(SYMTYPE_IMPORT, f);
|
||||||
} else {
|
} else {
|
||||||
assert(sym->src->ID != (uint32_t)-1);
|
assert(sym->src->ID != (uint32_t)-1);
|
||||||
@@ -150,7 +150,7 @@ static void writesymbol(Symbol const *sym, FILE *f)
|
|||||||
putc(sym->isExported ? SYMTYPE_EXPORT : SYMTYPE_LOCAL, f);
|
putc(sym->isExported ? SYMTYPE_EXPORT : SYMTYPE_LOCAL, f);
|
||||||
putlong(sym->src->ID, f);
|
putlong(sym->src->ID, f);
|
||||||
putlong(sym->fileLine, f);
|
putlong(sym->fileLine, f);
|
||||||
putlong(getSectIDIfAny(sym_GetSection(sym)), f);
|
putlong(getSectIDIfAny(sym->getSection()), f);
|
||||||
putlong(sym->value, f);
|
putlong(sym->value, f);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -203,7 +203,7 @@ static void writerpn(std::vector<uint8_t> &rpnexpr, const std::vector<uint8_t> &
|
|||||||
|
|
||||||
// The symbol name is always written expanded
|
// The symbol name is always written expanded
|
||||||
sym = sym_FindExactSymbol(symName);
|
sym = sym_FindExactSymbol(symName);
|
||||||
if (sym_IsConstant(sym)) {
|
if (sym->isConstant()) {
|
||||||
writebyte(RPN_CONST);
|
writebyte(RPN_CONST);
|
||||||
value = sym_GetConstantValue(symName);
|
value = sym_GetConstantValue(symName);
|
||||||
} else {
|
} else {
|
||||||
@@ -280,7 +280,7 @@ static void initpatch(Patch &patch, uint32_t type, Expression const *expr, uint3
|
|||||||
patch.pcSection = sect_GetSymbolSection();
|
patch.pcSection = sect_GetSymbolSection();
|
||||||
patch.pcOffset = sect_GetSymbolOffset();
|
patch.pcOffset = sect_GetSymbolOffset();
|
||||||
|
|
||||||
if (rpn_isKnown(expr)) {
|
if (expr->isKnown) {
|
||||||
// If the RPN expr's value is known, output a constant directly
|
// If the RPN expr's value is known, output a constant directly
|
||||||
patch.rpn.resize(5);
|
patch.rpn.resize(5);
|
||||||
patch.rpn[0] = RPN_CONST;
|
patch.rpn[0] = RPN_CONST;
|
||||||
|
|||||||
@@ -71,7 +71,7 @@
|
|||||||
char const *rep);
|
char const *rep);
|
||||||
static void initStrFmtArgList(StrFmtArgList *args);
|
static void initStrFmtArgList(StrFmtArgList *args);
|
||||||
static void freeStrFmtArgList(StrFmtArgList *args);
|
static void freeStrFmtArgList(StrFmtArgList *args);
|
||||||
static void strfmt(char *dest, size_t destLen, char const *fmt,
|
static void strfmt(char *dest, size_t destLen, char const *spec,
|
||||||
std::vector<std::variant<uint32_t, char *>> &args);
|
std::vector<std::variant<uint32_t, char *>> &args);
|
||||||
static void compoundAssignment(const char *symName, enum RPNCommand op, int32_t constValue);
|
static void compoundAssignment(const char *symName, enum RPNCommand op, int32_t constValue);
|
||||||
static void initDsArgList(std::vector<Expression> *&args);
|
static void initDsArgList(std::vector<Expression> *&args);
|
||||||
@@ -503,10 +503,14 @@ macro : T_ID {
|
|||||||
;
|
;
|
||||||
|
|
||||||
macroargs : %empty {
|
macroargs : %empty {
|
||||||
$$ = macro_NewArgs();
|
$$ = new(std::nothrow) MacroArgs();
|
||||||
|
if (!$$)
|
||||||
|
fatalerror("Failed to allocate memory for macro arguments: %s\n",
|
||||||
|
strerror(errno));
|
||||||
|
$$->shift = 0;
|
||||||
}
|
}
|
||||||
| macroargs T_STRING {
|
| macroargs T_STRING {
|
||||||
macro_AppendArg($$, strdup($2));
|
$$->append(strdup($2));
|
||||||
}
|
}
|
||||||
;
|
;
|
||||||
|
|
||||||
@@ -705,7 +709,7 @@ assert_type : %empty { $$ = ASSERT_ERROR; }
|
|||||||
;
|
;
|
||||||
|
|
||||||
assert : T_POP_ASSERT assert_type relocexpr {
|
assert : T_POP_ASSERT assert_type relocexpr {
|
||||||
if (!rpn_isKnown(&$3)) {
|
if (!$3.isKnown) {
|
||||||
out_CreateAssert($2, &$3, "", sect_GetOutputOffset());
|
out_CreateAssert($2, &$3, "", sect_GetOutputOffset());
|
||||||
} else if ($3.val == 0) {
|
} else if ($3.val == 0) {
|
||||||
failAssert($2);
|
failAssert($2);
|
||||||
@@ -713,7 +717,7 @@ assert : T_POP_ASSERT assert_type relocexpr {
|
|||||||
rpn_Free(&$3);
|
rpn_Free(&$3);
|
||||||
}
|
}
|
||||||
| T_POP_ASSERT assert_type relocexpr T_COMMA string {
|
| T_POP_ASSERT assert_type relocexpr T_COMMA string {
|
||||||
if (!rpn_isKnown(&$3)) {
|
if (!$3.isKnown) {
|
||||||
out_CreateAssert($2, &$3, $5, sect_GetOutputOffset());
|
out_CreateAssert($2, &$3, $5, sect_GetOutputOffset());
|
||||||
} else if ($3.val == 0) {
|
} else if ($3.val == 0) {
|
||||||
failAssertMsg($2, $5);
|
failAssertMsg($2, $5);
|
||||||
@@ -1256,13 +1260,13 @@ uconst : const {
|
|||||||
}
|
}
|
||||||
;
|
;
|
||||||
|
|
||||||
const : relocexpr { $$ = rpn_GetConstVal(&$1); }
|
const : relocexpr { $$ = $1.getConstVal(); }
|
||||||
;
|
;
|
||||||
|
|
||||||
const_no_str : relocexpr_no_str { $$ = rpn_GetConstVal(&$1); }
|
const_no_str : relocexpr_no_str { $$ = $1.getConstVal(); }
|
||||||
;
|
;
|
||||||
|
|
||||||
const_8bit : reloc_8bit { $$ = rpn_GetConstVal(&$1); }
|
const_8bit : reloc_8bit { $$ = $1.getConstVal(); }
|
||||||
;
|
;
|
||||||
|
|
||||||
opt_q_arg : %empty { $$ = fix_Precision(); }
|
opt_q_arg : %empty { $$ = fix_Precision(); }
|
||||||
@@ -1319,7 +1323,7 @@ string : T_STRING
|
|||||||
|
|
||||||
if (!sym)
|
if (!sym)
|
||||||
fatalerror("Unknown symbol \"%s\"\n", $3);
|
fatalerror("Unknown symbol \"%s\"\n", $3);
|
||||||
Section const *section = sym_GetSection(sym);
|
Section const *section = sym->getSection();
|
||||||
|
|
||||||
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);
|
||||||
@@ -1605,7 +1609,7 @@ z80_ldio : T_Z80_LDH T_MODE_A T_COMMA op_mem_ind {
|
|||||||
|
|
||||||
c_ind : T_LBRACK T_MODE_C T_RBRACK
|
c_ind : T_LBRACK T_MODE_C T_RBRACK
|
||||||
| T_LBRACK relocexpr T_OP_ADD T_MODE_C T_RBRACK {
|
| T_LBRACK relocexpr T_OP_ADD T_MODE_C T_RBRACK {
|
||||||
if (!rpn_isKnown(&$2) || $2.val != 0xFF00)
|
if (!$2.isKnown || $2.val != 0xFF00)
|
||||||
error("Expected constant expression equal to $FF00 for \"$ff00+c\"\n");
|
error("Expected constant expression equal to $FF00 for \"$ff00+c\"\n");
|
||||||
}
|
}
|
||||||
;
|
;
|
||||||
@@ -1642,7 +1646,7 @@ z80_ld_mem : T_Z80_LD op_mem_ind T_COMMA T_MODE_SP {
|
|||||||
sect_RelWord(&$2, 1);
|
sect_RelWord(&$2, 1);
|
||||||
}
|
}
|
||||||
| T_Z80_LD op_mem_ind T_COMMA T_MODE_A {
|
| T_Z80_LD op_mem_ind T_COMMA T_MODE_A {
|
||||||
if (optimizeLoads && rpn_isKnown(&$2)
|
if (optimizeLoads && $2.isKnown
|
||||||
&& $2.val >= 0xFF00) {
|
&& $2.val >= 0xFF00) {
|
||||||
if (warnOnLdOpt) {
|
if (warnOnLdOpt) {
|
||||||
warnOnLdOpt = false;
|
warnOnLdOpt = false;
|
||||||
@@ -1695,8 +1699,7 @@ z80_ld_a : T_Z80_LD reg_r T_COMMA c_ind {
|
|||||||
}
|
}
|
||||||
| T_Z80_LD reg_r T_COMMA op_mem_ind {
|
| T_Z80_LD reg_r T_COMMA op_mem_ind {
|
||||||
if ($2 == REG_A) {
|
if ($2 == REG_A) {
|
||||||
if (optimizeLoads && rpn_isKnown(&$4)
|
if (optimizeLoads && $4.isKnown && $4.val >= 0xFF00) {
|
||||||
&& $4.val >= 0xFF00) {
|
|
||||||
if (warnOnLdOpt) {
|
if (warnOnLdOpt) {
|
||||||
warnOnLdOpt = false;
|
warnOnLdOpt = false;
|
||||||
warning(WARNING_OBSOLETE,
|
warning(WARNING_OBSOLETE,
|
||||||
@@ -1795,7 +1798,7 @@ z80_rrca : T_Z80_RRCA { sect_AbsByte(0x0F); }
|
|||||||
|
|
||||||
z80_rst : T_Z80_RST reloc_8bit {
|
z80_rst : T_Z80_RST reloc_8bit {
|
||||||
rpn_CheckRST(&$2, &$2);
|
rpn_CheckRST(&$2, &$2);
|
||||||
if (!rpn_isKnown(&$2))
|
if (!$2.isKnown)
|
||||||
sect_RelByte(&$2, 0);
|
sect_RelByte(&$2, 0);
|
||||||
else
|
else
|
||||||
sect_AbsByte(0xC7 | $2.val);
|
sect_AbsByte(0xC7 | $2.val);
|
||||||
@@ -2197,14 +2200,14 @@ static void freeStrFmtArgList(StrFmtArgList *args)
|
|||||||
delete args->args;
|
delete args->args;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void strfmt(char *dest, size_t destLen, char const *fmt,
|
static void strfmt(char *dest, size_t destLen, char const *spec,
|
||||||
std::vector<std::variant<uint32_t, char *>> &args)
|
std::vector<std::variant<uint32_t, char *>> &args)
|
||||||
{
|
{
|
||||||
size_t a = 0;
|
size_t a = 0;
|
||||||
size_t i = 0;
|
size_t i = 0;
|
||||||
|
|
||||||
while (i < destLen) {
|
while (i < destLen) {
|
||||||
int c = *fmt++;
|
int c = *spec++;
|
||||||
|
|
||||||
if (c == '\0') {
|
if (c == '\0') {
|
||||||
break;
|
break;
|
||||||
@@ -2213,27 +2216,27 @@ static void strfmt(char *dest, size_t destLen, char const *fmt,
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
c = *fmt++;
|
c = *spec++;
|
||||||
|
|
||||||
if (c == '%') {
|
if (c == '%') {
|
||||||
dest[i++] = c;
|
dest[i++] = c;
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
FormatSpec spec = fmt_NewSpec();
|
FormatSpec fmt{};
|
||||||
|
|
||||||
while (c != '\0') {
|
while (c != '\0') {
|
||||||
fmt_UseCharacter(&spec, c);
|
fmt.useCharacter(c);
|
||||||
if (fmt_IsFinished(&spec))
|
if (fmt.isFinished())
|
||||||
break;
|
break;
|
||||||
c = *fmt++;
|
c = *spec++;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (fmt_IsEmpty(&spec)) {
|
if (fmt.isEmpty()) {
|
||||||
error("STRFMT: Illegal '%%' at end of format string\n");
|
error("STRFMT: Illegal '%%' at end of format string\n");
|
||||||
dest[i++] = '%';
|
dest[i++] = '%';
|
||||||
break;
|
break;
|
||||||
} else if (!fmt_IsValid(&spec)) {
|
} else if (!fmt.isValid()) {
|
||||||
error("STRFMT: Invalid format spec for argument %zu\n", a + 1);
|
error("STRFMT: Invalid format spec for argument %zu\n", a + 1);
|
||||||
dest[i++] = '%';
|
dest[i++] = '%';
|
||||||
a++;
|
a++;
|
||||||
@@ -2249,8 +2252,8 @@ static void strfmt(char *dest, size_t destLen, char const *fmt,
|
|||||||
static char buf[MAXSTRLEN + 1];
|
static char buf[MAXSTRLEN + 1];
|
||||||
|
|
||||||
std::visit(Visitor{
|
std::visit(Visitor{
|
||||||
[&](uint32_t num) { fmt_PrintNumber(buf, sizeof(buf), &spec, num); },
|
[&](uint32_t num) { fmt.printNumber(buf, sizeof(buf), num); },
|
||||||
[&](char *str) { fmt_PrintString(buf, sizeof(buf), &spec, str); },
|
[&](char *str) { fmt.printString(buf, sizeof(buf), str); },
|
||||||
}, arg);
|
}, arg);
|
||||||
|
|
||||||
i += snprintf(&dest[i], destLen - i, "%s", buf);
|
i += snprintf(&dest[i], destLen - i, "%s", buf);
|
||||||
@@ -2277,7 +2280,7 @@ static void compoundAssignment(const char *symName, enum RPNCommand op, int32_t
|
|||||||
rpn_Symbol(&oldExpr, symName);
|
rpn_Symbol(&oldExpr, symName);
|
||||||
rpn_Number(&constExpr, constValue);
|
rpn_Number(&constExpr, constValue);
|
||||||
rpn_BinaryOp(op, &newExpr, &oldExpr, &constExpr);
|
rpn_BinaryOp(op, &newExpr, &oldExpr, &constExpr);
|
||||||
newValue = rpn_GetConstVal(&newExpr);
|
newValue = newExpr.getConstVal();
|
||||||
sym_AddVar(symName, newValue);
|
sym_AddVar(symName, newValue);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
136
src/asm/rpn.cpp
136
src/asm/rpn.cpp
@@ -21,6 +21,16 @@
|
|||||||
|
|
||||||
#include "opmath.hpp"
|
#include "opmath.hpp"
|
||||||
|
|
||||||
|
// Init a RPN expression
|
||||||
|
static void initExpression(Expression *expr)
|
||||||
|
{
|
||||||
|
expr->reason = nullptr;
|
||||||
|
expr->isKnown = true;
|
||||||
|
expr->isSymbol = false;
|
||||||
|
expr->rpn = nullptr;
|
||||||
|
expr->rpnPatchSize = 0;
|
||||||
|
}
|
||||||
|
|
||||||
// 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(Expression *expr, Ts ...parts)
|
static void makeUnknown(Expression *expr, Ts ...parts)
|
||||||
@@ -46,28 +56,18 @@ static uint8_t *reserveSpace(Expression *expr, uint32_t size)
|
|||||||
return &(*expr->rpn)[curSize];
|
return &(*expr->rpn)[curSize];
|
||||||
}
|
}
|
||||||
|
|
||||||
// Init a RPN expression
|
|
||||||
static void rpn_Init(Expression *expr)
|
|
||||||
{
|
|
||||||
expr->reason = nullptr;
|
|
||||||
expr->isKnown = true;
|
|
||||||
expr->isSymbol = false;
|
|
||||||
expr->rpn = nullptr;
|
|
||||||
expr->rpnPatchSize = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Free the RPN expression
|
// Free the RPN expression
|
||||||
void rpn_Free(Expression *expr)
|
void rpn_Free(Expression *expr)
|
||||||
{
|
{
|
||||||
delete expr->rpn;
|
delete expr->rpn;
|
||||||
delete expr->reason;
|
delete expr->reason;
|
||||||
rpn_Init(expr);
|
initExpression(expr);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Add symbols, constants and operators to expression
|
// Add symbols, constants and operators to expression
|
||||||
void rpn_Number(Expression *expr, uint32_t i)
|
void rpn_Number(Expression *expr, uint32_t i)
|
||||||
{
|
{
|
||||||
rpn_Init(expr);
|
initExpression(expr);
|
||||||
expr->val = i;
|
expr->val = i;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -78,8 +78,8 @@ void rpn_Symbol(Expression *expr, char const *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");
|
||||||
rpn_Number(expr, 0);
|
rpn_Number(expr, 0);
|
||||||
} else if (!sym || !sym_IsConstant(sym)) {
|
} else if (!sym || !sym->isConstant()) {
|
||||||
rpn_Init(expr);
|
initExpression(expr);
|
||||||
expr->isSymbol = true;
|
expr->isSymbol = true;
|
||||||
|
|
||||||
if (sym_IsPC(sym))
|
if (sym_IsPC(sym))
|
||||||
@@ -100,7 +100,7 @@ void rpn_Symbol(Expression *expr, char const *symName)
|
|||||||
|
|
||||||
void rpn_BankSelf(Expression *expr)
|
void rpn_BankSelf(Expression *expr)
|
||||||
{
|
{
|
||||||
rpn_Init(expr);
|
initExpression(expr);
|
||||||
|
|
||||||
if (!currentSection) {
|
if (!currentSection) {
|
||||||
error("PC has no bank outside a section\n");
|
error("PC has no bank outside a section\n");
|
||||||
@@ -124,22 +124,23 @@ void rpn_BankSymbol(Expression *expr, char const *symName)
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
rpn_Init(expr);
|
initExpression(expr);
|
||||||
if (sym && !sym_IsLabel(sym)) {
|
if (sym && !sym->isLabel()) {
|
||||||
error("BANK argument must be a label\n");
|
error("BANK argument must be a label\n");
|
||||||
} else {
|
} else {
|
||||||
sym = sym_Ref(symName);
|
sym = sym_Ref(symName);
|
||||||
assert(sym); // If the symbol didn't exist, it should have been created
|
assert(sym); // If the symbol didn't exist, it should have been created
|
||||||
|
|
||||||
if (sym_GetSection(sym) && sym_GetSection(sym)->bank != (uint32_t)-1) {
|
if (sym->getSection() && sym->getSection()->bank != (uint32_t)-1) {
|
||||||
// Symbol's section is known and bank is fixed
|
// Symbol's section is known and bank is fixed
|
||||||
expr->val = sym_GetSection(sym)->bank;
|
expr->val = sym->getSection()->bank;
|
||||||
} else {
|
} else {
|
||||||
makeUnknown(expr, "\"", symName, "\"'s bank is not known");
|
makeUnknown(expr, "\"", symName, "\"'s bank is not known");
|
||||||
expr->rpnPatchSize += 5; // opcode + 4-byte sect ID
|
expr->rpnPatchSize += 5; // opcode + 4-byte sect ID
|
||||||
|
|
||||||
size_t nameLen = strlen(sym->name) + 1; // Room for NUL!
|
size_t nameLen = strlen(sym->name) + 1; // Room for NUL!
|
||||||
uint8_t *ptr = reserveSpace(expr, nameLen + 1);
|
uint8_t *ptr = reserveSpace(expr, nameLen + 1);
|
||||||
|
|
||||||
*ptr++ = RPN_BANK_SYM;
|
*ptr++ = RPN_BANK_SYM;
|
||||||
memcpy(ptr, sym->name, nameLen);
|
memcpy(ptr, sym->name, nameLen);
|
||||||
}
|
}
|
||||||
@@ -148,7 +149,7 @@ void rpn_BankSymbol(Expression *expr, char const *symName)
|
|||||||
|
|
||||||
void rpn_BankSection(Expression *expr, char const *sectionName)
|
void rpn_BankSection(Expression *expr, char const *sectionName)
|
||||||
{
|
{
|
||||||
rpn_Init(expr);
|
initExpression(expr);
|
||||||
|
|
||||||
Section *section = sect_FindSectionByName(sectionName);
|
Section *section = sect_FindSectionByName(sectionName);
|
||||||
|
|
||||||
@@ -168,11 +169,11 @@ void rpn_BankSection(Expression *expr, char const *sectionName)
|
|||||||
|
|
||||||
void rpn_SizeOfSection(Expression *expr, char const *sectionName)
|
void rpn_SizeOfSection(Expression *expr, char const *sectionName)
|
||||||
{
|
{
|
||||||
rpn_Init(expr);
|
initExpression(expr);
|
||||||
|
|
||||||
Section *section = sect_FindSectionByName(sectionName);
|
Section *section = sect_FindSectionByName(sectionName);
|
||||||
|
|
||||||
if (section && sect_IsSizeKnown(section)) {
|
if (section && section->isSizeKnown()) {
|
||||||
expr->val = section->size;
|
expr->val = section->size;
|
||||||
} else {
|
} else {
|
||||||
makeUnknown(expr, "Section \"", sectionName, "\"'s size is not known");
|
makeUnknown(expr, "Section \"", sectionName, "\"'s size is not known");
|
||||||
@@ -188,7 +189,7 @@ void rpn_SizeOfSection(Expression *expr, char const *sectionName)
|
|||||||
|
|
||||||
void rpn_StartOfSection(Expression *expr, char const *sectionName)
|
void rpn_StartOfSection(Expression *expr, char const *sectionName)
|
||||||
{
|
{
|
||||||
rpn_Init(expr);
|
initExpression(expr);
|
||||||
|
|
||||||
Section *section = sect_FindSectionByName(sectionName);
|
Section *section = sect_FindSectionByName(sectionName);
|
||||||
|
|
||||||
@@ -208,7 +209,7 @@ void rpn_StartOfSection(Expression *expr, char const *sectionName)
|
|||||||
|
|
||||||
void rpn_SizeOfSectionType(Expression *expr, enum SectionType type)
|
void rpn_SizeOfSectionType(Expression *expr, enum SectionType type)
|
||||||
{
|
{
|
||||||
rpn_Init(expr);
|
initExpression(expr);
|
||||||
makeUnknown(expr, "Section type's size is not known");
|
makeUnknown(expr, "Section type's size is not known");
|
||||||
|
|
||||||
uint8_t *ptr = reserveSpace(expr, 2);
|
uint8_t *ptr = reserveSpace(expr, 2);
|
||||||
@@ -220,7 +221,7 @@ void rpn_SizeOfSectionType(Expression *expr, enum SectionType type)
|
|||||||
|
|
||||||
void rpn_StartOfSectionType(Expression *expr, enum SectionType type)
|
void rpn_StartOfSectionType(Expression *expr, enum SectionType type)
|
||||||
{
|
{
|
||||||
rpn_Init(expr);
|
initExpression(expr);
|
||||||
makeUnknown(expr, "Section type's start is not known");
|
makeUnknown(expr, "Section type's start is not known");
|
||||||
|
|
||||||
uint8_t *ptr = reserveSpace(expr, 2);
|
uint8_t *ptr = reserveSpace(expr, 2);
|
||||||
@@ -235,7 +236,7 @@ void rpn_CheckHRAM(Expression *expr, const Expression *src)
|
|||||||
*expr = *src;
|
*expr = *src;
|
||||||
expr->isSymbol = false;
|
expr->isSymbol = false;
|
||||||
|
|
||||||
if (!rpn_isKnown(expr)) {
|
if (!expr->isKnown) {
|
||||||
expr->rpnPatchSize++;
|
expr->rpnPatchSize++;
|
||||||
*reserveSpace(expr, 1) = RPN_HRAM;
|
*reserveSpace(expr, 1) = RPN_HRAM;
|
||||||
} else if (expr->val >= 0xFF00 && expr->val <= 0xFFFF) {
|
} else if (expr->val >= 0xFF00 && expr->val <= 0xFFFF) {
|
||||||
@@ -250,7 +251,7 @@ void rpn_CheckRST(Expression *expr, const Expression *src)
|
|||||||
{
|
{
|
||||||
*expr = *src;
|
*expr = *src;
|
||||||
|
|
||||||
if (rpn_isKnown(expr)) {
|
if (expr->isKnown) {
|
||||||
// A valid RST address must be masked with 0x38
|
// A valid RST address must be masked with 0x38
|
||||||
if (expr->val & ~0x38)
|
if (expr->val & ~0x38)
|
||||||
error("Invalid address $%" PRIx32 " for RST\n", expr->val);
|
error("Invalid address $%" PRIx32 " for RST\n", expr->val);
|
||||||
@@ -268,7 +269,7 @@ 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
|
||||||
|
|
||||||
if (rpn_isKnown(expr)) {
|
if (expr->isKnown) {
|
||||||
int32_t val = expr->val;
|
int32_t val = expr->val;
|
||||||
|
|
||||||
if (val < -(1 << n) || val >= 1 << n)
|
if (val < -(1 << n) || val >= 1 << n)
|
||||||
@@ -278,13 +279,13 @@ void rpn_CheckNBit(Expression const *expr, uint8_t n)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
int32_t rpn_GetConstVal(Expression const *expr)
|
int32_t Expression::getConstVal() const
|
||||||
{
|
{
|
||||||
if (!rpn_isKnown(expr)) {
|
if (!isKnown) {
|
||||||
error("Expected constant expression: %s\n", expr->reason->c_str());
|
error("Expected constant expression: %s\n", reason->c_str());
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
return expr->val;
|
return val;
|
||||||
}
|
}
|
||||||
|
|
||||||
void rpn_LOGNOT(Expression *expr, const Expression *src)
|
void rpn_LOGNOT(Expression *expr, const Expression *src)
|
||||||
@@ -292,7 +293,7 @@ void rpn_LOGNOT(Expression *expr, const Expression *src)
|
|||||||
*expr = *src;
|
*expr = *src;
|
||||||
expr->isSymbol = false;
|
expr->isSymbol = false;
|
||||||
|
|
||||||
if (rpn_isKnown(expr)) {
|
if (expr->isKnown) {
|
||||||
expr->val = !expr->val;
|
expr->val = !expr->val;
|
||||||
} else {
|
} else {
|
||||||
expr->rpnPatchSize++;
|
expr->rpnPatchSize++;
|
||||||
@@ -300,31 +301,26 @@ void rpn_LOGNOT(Expression *expr, const Expression *src)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Symbol const *rpn_SymbolOf(Expression const *expr)
|
Symbol const *Expression::symbolOf() const
|
||||||
{
|
{
|
||||||
if (!rpn_isSymbol(expr))
|
if (!isSymbol)
|
||||||
return nullptr;
|
return nullptr;
|
||||||
return sym_FindScopedSymbol((char const *)&(*expr->rpn)[1]);
|
return sym_FindScopedSymbol((char const *)&(*rpn)[1]);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool rpn_IsDiffConstant(Expression const *src, Symbol const *sym)
|
bool Expression::isDiffConstant(Symbol const *sym) const
|
||||||
{
|
{
|
||||||
// Check if both expressions only refer to a single symbol
|
// Check if both expressions only refer to a single symbol
|
||||||
Symbol const *sym1 = rpn_SymbolOf(src);
|
Symbol const *sym1 = symbolOf();
|
||||||
|
|
||||||
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;
|
||||||
|
|
||||||
Section const *section1 = sym_GetSection(sym1);
|
Section const *section1 = sym1->getSection();
|
||||||
Section const *section2 = sym_GetSection(sym);
|
Section const *section2 = sym->getSection();
|
||||||
return section1 && (section1 == section2);
|
return section1 && (section1 == section2);
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool isDiffConstant(Expression const *src1, Expression const *src2)
|
|
||||||
{
|
|
||||||
return rpn_IsDiffConstant(src1, rpn_SymbolOf(src2));
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Attempts to compute a constant binary AND from non-constant operands
|
* Attempts to compute a constant binary AND from non-constant operands
|
||||||
* This is possible if one operand is a symbol belonging to an `ALIGN[N]` section, and the other is
|
* This is possible if one operand is a symbol belonging to an `ALIGN[N]` section, and the other is
|
||||||
@@ -334,33 +330,33 @@ static bool isDiffConstant(Expression const *src1, Expression const *src2)
|
|||||||
*/
|
*/
|
||||||
static int32_t tryConstMask(Expression const *lhs, Expression const *rhs)
|
static int32_t tryConstMask(Expression const *lhs, Expression const *rhs)
|
||||||
{
|
{
|
||||||
Symbol const *sym = rpn_SymbolOf(lhs);
|
Symbol const *sym = lhs->symbolOf();
|
||||||
Expression const *expr = rhs;
|
Expression const *expr = rhs;
|
||||||
|
|
||||||
if (!sym || !sym_GetSection(sym)) {
|
if (!sym || !sym->getSection()) {
|
||||||
// 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
|
||||||
sym = rpn_SymbolOf(rhs);
|
sym = rhs->symbolOf();
|
||||||
expr = lhs;
|
expr = lhs;
|
||||||
|
|
||||||
if (!sym || !sym_GetSection(sym))
|
if (!sym || !sym->getSection())
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
assert(sym_IsNumeric(sym));
|
assert(sym->isNumeric());
|
||||||
|
|
||||||
if (!rpn_isKnown(expr))
|
if (!expr->isKnown)
|
||||||
return -1;
|
return -1;
|
||||||
// We can now safely use `expr->val`
|
// We can now safely use `expr->val`
|
||||||
Section const *sect = sym_GetSection(sym);
|
Section const *sect = sym->getSection();
|
||||||
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
|
||||||
if ((expr->val & unknownBits) != 0)
|
if ((expr->val & unknownBits) != 0)
|
||||||
return -1;
|
return -1;
|
||||||
|
|
||||||
// `sym_GetValue()` attempts to add the section's address,
|
// `sym->getValue()` attempts to add the section's address, but that's "-1"
|
||||||
// but that's "-1" because the section is floating (otherwise we wouldn't be here)
|
// because the section is floating (otherwise we wouldn't be here)
|
||||||
assert(sect->org == (uint32_t)-1);
|
assert(sect->org == (uint32_t)-1);
|
||||||
int32_t symbolOfs = sym_GetValue(sym) + 1;
|
int32_t symbolOfs = sym->getValue() + 1;
|
||||||
|
|
||||||
return (symbolOfs + sect->alignOfs) & ~unknownBits;
|
return (symbolOfs + sect->alignOfs) & ~unknownBits;
|
||||||
}
|
}
|
||||||
@@ -371,9 +367,9 @@ void rpn_BinaryOp(enum RPNCommand op, Expression *expr, const Expression *src1,
|
|||||||
int32_t constMaskVal;
|
int32_t constMaskVal;
|
||||||
|
|
||||||
// First, check if the expression is known
|
// First, check if the expression is known
|
||||||
expr->isKnown = rpn_isKnown(src1) && rpn_isKnown(src2);
|
expr->isKnown = src1->isKnown && src2->isKnown;
|
||||||
if (rpn_isKnown(expr)) {
|
if (expr->isKnown) {
|
||||||
rpn_Init(expr); // Init the expression to something sane
|
initExpression(expr); // Init the expression to something sane
|
||||||
|
|
||||||
// If both expressions are known, just compute the value
|
// If both expressions are known, just compute the value
|
||||||
uint32_t uleft = src1->val, uright = src2->val;
|
uint32_t uleft = src1->val, uright = src2->val;
|
||||||
@@ -509,11 +505,11 @@ void rpn_BinaryOp(enum RPNCommand op, Expression *expr, const Expression *src1,
|
|||||||
fatalerror("%d is not a binary operator\n", op);
|
fatalerror("%d is not a binary operator\n", op);
|
||||||
}
|
}
|
||||||
|
|
||||||
} else if (op == RPN_SUB && isDiffConstant(src1, src2)) {
|
} else if (op == RPN_SUB && src1->isDiffConstant(src2->symbolOf())) {
|
||||||
Symbol const *symbol1 = rpn_SymbolOf(src1);
|
Symbol const *symbol1 = src1->symbolOf();
|
||||||
Symbol const *symbol2 = rpn_SymbolOf(src2);
|
Symbol const *symbol2 = src2->symbolOf();
|
||||||
|
|
||||||
expr->val = sym_GetValue(symbol1) - sym_GetValue(symbol2);
|
expr->val = symbol1->getValue() - symbol2->getValue();
|
||||||
expr->isKnown = true;
|
expr->isKnown = true;
|
||||||
} else if (op == RPN_AND && (constMaskVal = tryConstMask(src1, src2)) != -1) {
|
} else if (op == RPN_AND && (constMaskVal = tryConstMask(src1, src2)) != -1) {
|
||||||
expr->val = constMaskVal;
|
expr->val = constMaskVal;
|
||||||
@@ -522,7 +518,7 @@ void rpn_BinaryOp(enum RPNCommand op, Expression *expr, const Expression *src1,
|
|||||||
// If it's not known, start computing the RPN expression
|
// If it's not known, start computing the RPN expression
|
||||||
|
|
||||||
// Convert the left-hand expression if it's constant
|
// Convert the left-hand expression if it's constant
|
||||||
if (rpn_isKnown(src1)) {
|
if (src1->isKnown) {
|
||||||
uint32_t lval = src1->val;
|
uint32_t lval = src1->val;
|
||||||
uint8_t bytes[] = {RPN_CONST, (uint8_t)lval, (uint8_t)(lval >> 8),
|
uint8_t bytes[] = {RPN_CONST, (uint8_t)lval, (uint8_t)(lval >> 8),
|
||||||
(uint8_t)(lval >> 16), (uint8_t)(lval >> 24)};
|
(uint8_t)(lval >> 16), (uint8_t)(lval >> 24)};
|
||||||
@@ -550,7 +546,7 @@ void rpn_BinaryOp(enum RPNCommand op, Expression *expr, const Expression *src1,
|
|||||||
uint32_t rval = src2->val;
|
uint32_t rval = src2->val;
|
||||||
uint8_t bytes[] = {RPN_CONST, (uint8_t)rval, (uint8_t)(rval >> 8),
|
uint8_t bytes[] = {RPN_CONST, (uint8_t)rval, (uint8_t)(rval >> 8),
|
||||||
(uint8_t)(rval >> 16), (uint8_t)(rval >> 24)};
|
(uint8_t)(rval >> 16), (uint8_t)(rval >> 24)};
|
||||||
if (rpn_isKnown(src2)) {
|
if (src2->isKnown) {
|
||||||
ptr = bytes;
|
ptr = bytes;
|
||||||
len = sizeof(bytes);
|
len = sizeof(bytes);
|
||||||
patchSize = sizeof(bytes);
|
patchSize = sizeof(bytes);
|
||||||
@@ -577,7 +573,7 @@ void rpn_HIGH(Expression *expr, const Expression *src)
|
|||||||
*expr = *src;
|
*expr = *src;
|
||||||
expr->isSymbol = false;
|
expr->isSymbol = false;
|
||||||
|
|
||||||
if (rpn_isKnown(expr)) {
|
if (expr->isKnown) {
|
||||||
expr->val = (uint32_t)expr->val >> 8 & 0xFF;
|
expr->val = (uint32_t)expr->val >> 8 & 0xFF;
|
||||||
} else {
|
} else {
|
||||||
uint8_t bytes[] = {RPN_CONST, 8, 0, 0, 0, RPN_SHR,
|
uint8_t bytes[] = {RPN_CONST, 8, 0, 0, 0, RPN_SHR,
|
||||||
@@ -592,7 +588,7 @@ void rpn_LOW(Expression *expr, const Expression *src)
|
|||||||
*expr = *src;
|
*expr = *src;
|
||||||
expr->isSymbol = false;
|
expr->isSymbol = false;
|
||||||
|
|
||||||
if (rpn_isKnown(expr)) {
|
if (expr->isKnown) {
|
||||||
expr->val = expr->val & 0xFF;
|
expr->val = expr->val & 0xFF;
|
||||||
} else {
|
} else {
|
||||||
uint8_t bytes[] = {RPN_CONST, 0xFF, 0, 0, 0, RPN_AND};
|
uint8_t bytes[] = {RPN_CONST, 0xFF, 0, 0, 0, RPN_AND};
|
||||||
@@ -604,8 +600,8 @@ void rpn_LOW(Expression *expr, const Expression *src)
|
|||||||
|
|
||||||
void rpn_ISCONST(Expression *expr, const Expression *src)
|
void rpn_ISCONST(Expression *expr, const Expression *src)
|
||||||
{
|
{
|
||||||
rpn_Init(expr);
|
initExpression(expr);
|
||||||
expr->val = rpn_isKnown(src);
|
expr->val = src->isKnown;
|
||||||
expr->isKnown = true;
|
expr->isKnown = true;
|
||||||
expr->isSymbol = false;
|
expr->isSymbol = false;
|
||||||
}
|
}
|
||||||
@@ -615,7 +611,7 @@ void rpn_NEG(Expression *expr, const Expression *src)
|
|||||||
*expr = *src;
|
*expr = *src;
|
||||||
expr->isSymbol = false;
|
expr->isSymbol = false;
|
||||||
|
|
||||||
if (rpn_isKnown(expr)) {
|
if (expr->isKnown) {
|
||||||
expr->val = -(uint32_t)expr->val;
|
expr->val = -(uint32_t)expr->val;
|
||||||
} else {
|
} else {
|
||||||
expr->rpnPatchSize++;
|
expr->rpnPatchSize++;
|
||||||
@@ -628,7 +624,7 @@ void rpn_NOT(Expression *expr, const Expression *src)
|
|||||||
*expr = *src;
|
*expr = *src;
|
||||||
expr->isSymbol = false;
|
expr->isSymbol = false;
|
||||||
|
|
||||||
if (rpn_isKnown(expr)) {
|
if (expr->isKnown) {
|
||||||
expr->val = ~expr->val;
|
expr->val = ~expr->val;
|
||||||
} else {
|
} else {
|
||||||
expr->rpnPatchSize++;
|
expr->rpnPatchSize++;
|
||||||
|
|||||||
@@ -250,7 +250,7 @@ static void mergeSections(Section *sect, enum SectionType type, uint32_t org, ui
|
|||||||
|
|
||||||
case SECTION_NORMAL:
|
case SECTION_NORMAL:
|
||||||
fail("Section already defined previously at ");
|
fail("Section already defined previously at ");
|
||||||
fstk_Dump(sect->src, sect->fileLine);
|
sect->src->dump(sect->fileLine);
|
||||||
putc('\n', stderr);
|
putc('\n', stderr);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@@ -375,6 +375,25 @@ static void changeSection()
|
|||||||
sym_SetCurrentSymbolScope(nullptr);
|
sym_SetCurrentSymbolScope(nullptr);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool Section::isSizeKnown() const
|
||||||
|
{
|
||||||
|
// SECTION UNION and SECTION FRAGMENT can still grow
|
||||||
|
if (modifier != SECTION_NORMAL)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
// The current section (or current load section if within one) is still growing
|
||||||
|
if (this == currentSection || this == currentLoadSection)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
// Any section on the stack is still growing
|
||||||
|
for (SectionStackEntry &entry : sectionStack) {
|
||||||
|
if (entry.section && !strcmp(name, entry.section->name))
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
// 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,
|
||||||
SectionSpec const *attribs, enum SectionModifier mod)
|
SectionSpec const *attribs, enum SectionModifier mod)
|
||||||
@@ -675,7 +694,7 @@ void sect_RelByte(Expression *expr, uint32_t pcShift)
|
|||||||
if (!reserveSpace(1))
|
if (!reserveSpace(1))
|
||||||
return;
|
return;
|
||||||
|
|
||||||
if (!rpn_isKnown(expr)) {
|
if (!expr->isKnown) {
|
||||||
createPatch(PATCHTYPE_BYTE, expr, pcShift);
|
createPatch(PATCHTYPE_BYTE, expr, pcShift);
|
||||||
writebyte(0);
|
writebyte(0);
|
||||||
} else {
|
} else {
|
||||||
@@ -696,7 +715,7 @@ void sect_RelBytes(uint32_t n, std::vector<Expression> &exprs)
|
|||||||
for (uint32_t i = 0; i < n; i++) {
|
for (uint32_t i = 0; i < n; i++) {
|
||||||
Expression &expr = exprs[i % exprs.size()];
|
Expression &expr = exprs[i % exprs.size()];
|
||||||
|
|
||||||
if (!rpn_isKnown(&expr)) {
|
if (!expr.isKnown) {
|
||||||
createPatch(PATCHTYPE_BYTE, &expr, i);
|
createPatch(PATCHTYPE_BYTE, &expr, i);
|
||||||
writebyte(0);
|
writebyte(0);
|
||||||
} else {
|
} else {
|
||||||
@@ -717,7 +736,7 @@ void sect_RelWord(Expression *expr, uint32_t pcShift)
|
|||||||
if (!reserveSpace(2))
|
if (!reserveSpace(2))
|
||||||
return;
|
return;
|
||||||
|
|
||||||
if (!rpn_isKnown(expr)) {
|
if (!expr->isKnown) {
|
||||||
createPatch(PATCHTYPE_WORD, expr, pcShift);
|
createPatch(PATCHTYPE_WORD, expr, pcShift);
|
||||||
writeword(0);
|
writeword(0);
|
||||||
} else {
|
} else {
|
||||||
@@ -735,7 +754,7 @@ void sect_RelLong(Expression *expr, uint32_t pcShift)
|
|||||||
if (!reserveSpace(2))
|
if (!reserveSpace(2))
|
||||||
return;
|
return;
|
||||||
|
|
||||||
if (!rpn_isKnown(expr)) {
|
if (!expr->isKnown) {
|
||||||
createPatch(PATCHTYPE_LONG, expr, pcShift);
|
createPatch(PATCHTYPE_LONG, expr, pcShift);
|
||||||
writelong(0);
|
writelong(0);
|
||||||
} else {
|
} else {
|
||||||
@@ -754,11 +773,11 @@ void sect_PCRelByte(Expression *expr, uint32_t pcShift)
|
|||||||
return;
|
return;
|
||||||
Symbol const *pc = sym_GetPC();
|
Symbol const *pc = sym_GetPC();
|
||||||
|
|
||||||
if (!rpn_IsDiffConstant(expr, pc)) {
|
if (!expr->isDiffConstant(pc)) {
|
||||||
createPatch(PATCHTYPE_JR, expr, pcShift);
|
createPatch(PATCHTYPE_JR, expr, pcShift);
|
||||||
writebyte(0);
|
writebyte(0);
|
||||||
} else {
|
} else {
|
||||||
Symbol const *sym = rpn_SymbolOf(expr);
|
Symbol const *sym = expr->symbolOf();
|
||||||
// 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;
|
||||||
|
|
||||||
@@ -766,7 +785,7 @@ void sect_PCRelByte(Expression *expr, uint32_t pcShift)
|
|||||||
if (sym == pc)
|
if (sym == pc)
|
||||||
offset = -2; // PC as operand to `jr` is lower than reference PC by 2
|
offset = -2; // PC as operand to `jr` is lower than reference PC by 2
|
||||||
else
|
else
|
||||||
offset = sym_GetValue(sym) - (sym_GetValue(pc) + 1);
|
offset = sym->getValue() - (pc->getValue() + 1);
|
||||||
|
|
||||||
if (offset < -128 || offset > 127) {
|
if (offset < -128 || offset > 127) {
|
||||||
error("jr target out of reach (expected -129 < %" PRId16 " < 128)\n",
|
error("jr target out of reach (expected -129 < %" PRId16 " < 128)\n",
|
||||||
@@ -973,22 +992,3 @@ void sect_EndSection()
|
|||||||
currentSection = nullptr;
|
currentSection = nullptr;
|
||||||
sym_SetCurrentSymbolScope(nullptr);
|
sym_SetCurrentSymbolScope(nullptr);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool sect_IsSizeKnown(Section const NONNULL(sect))
|
|
||||||
{
|
|
||||||
// SECTION UNION and SECTION FRAGMENT can still grow
|
|
||||||
if (sect->modifier != SECTION_NORMAL)
|
|
||||||
return false;
|
|
||||||
|
|
||||||
// The current section (or current load section if within one) is still growing
|
|
||||||
if (sect == currentSection || sect == currentLoadSection)
|
|
||||||
return false;
|
|
||||||
|
|
||||||
// Any section on the stack is still growing
|
|
||||||
for (SectionStackEntry &entry : sectionStack) {
|
|
||||||
if (entry.section && !strcmp(sect->name, entry.section->name))
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|||||||
@@ -66,22 +66,22 @@ static int32_t CallbackPC()
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Get the value field of a symbol
|
// Get the value field of a symbol
|
||||||
int32_t sym_GetValue(Symbol const *sym)
|
int32_t Symbol::getValue() const
|
||||||
{
|
{
|
||||||
if (sym_IsNumeric(sym) && sym->hasCallback)
|
if (isNumeric() && hasCallback)
|
||||||
return sym->numCallback();
|
return numCallback();
|
||||||
|
|
||||||
if (sym->type == SYM_LABEL)
|
if (type == SYM_LABEL)
|
||||||
// TODO: do not use section's org directly
|
// TODO: do not use section's org directly
|
||||||
return sym->value + sym_GetSection(sym)->org;
|
return value + getSection()->org;
|
||||||
|
|
||||||
return sym->value;
|
return value;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void dumpFilename(Symbol const *sym)
|
static void dumpFilename(Symbol const *sym)
|
||||||
{
|
{
|
||||||
if (sym->src)
|
if (sym->src)
|
||||||
fstk_Dump(sym->src, sym->fileLine);
|
sym->src->dump(sym->fileLine);
|
||||||
else if (sym->fileLine == 0)
|
else if (sym->fileLine == 0)
|
||||||
fputs("<command-line>", stderr);
|
fputs("<command-line>", stderr);
|
||||||
else
|
else
|
||||||
@@ -178,7 +178,7 @@ Symbol *sym_FindScopedValidSymbol(char const *symName)
|
|||||||
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_IsPC(sym) && !sect_GetSymbolSection()) {
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
// `_NARG` has no value outside a macro
|
// `_NARG` has no value outside a macro
|
||||||
@@ -235,28 +235,25 @@ uint32_t sym_GetPCValue()
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Return a constant symbol's value, assuming it's defined
|
// Return a constant symbol's value, assuming it's defined
|
||||||
uint32_t sym_GetConstantSymValue(Symbol const *sym)
|
uint32_t Symbol::getConstantValue() const
|
||||||
{
|
{
|
||||||
if (sym == PCSymbol)
|
if (sym_IsPC(this))
|
||||||
return sym_GetPCValue();
|
return sym_GetPCValue();
|
||||||
else if (!sym_IsConstant(sym))
|
|
||||||
error("\"%s\" does not have a constant value\n", sym->name);
|
|
||||||
else
|
|
||||||
return sym_GetValue(sym);
|
|
||||||
|
|
||||||
|
if (isConstant())
|
||||||
|
return getValue();
|
||||||
|
|
||||||
|
error("\"%s\" does not have a constant value\n", name);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
// 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)
|
||||||
{
|
{
|
||||||
Symbol const *sym = sym_FindScopedSymbol(symName);
|
if (Symbol const *sym = sym_FindScopedSymbol(symName); sym)
|
||||||
|
return sym->getConstantValue();
|
||||||
|
|
||||||
if (!sym)
|
|
||||||
error("'%s' not defined\n", symName);
|
error("'%s' not defined\n", symName);
|
||||||
else
|
|
||||||
return sym_GetConstantSymValue(sym);
|
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -283,7 +280,7 @@ static Symbol *createNonrelocSymbol(char const *symName, bool numeric)
|
|||||||
|
|
||||||
if (!sym) {
|
if (!sym) {
|
||||||
sym = createsymbol(symName);
|
sym = createsymbol(symName);
|
||||||
} else if (sym_IsDefined(sym)) {
|
} else if (sym->isDefined()) {
|
||||||
error("'%s' already defined at ", symName);
|
error("'%s' already defined at ", symName);
|
||||||
dumpFilename(sym);
|
dumpFilename(sym);
|
||||||
putc('\n', stderr);
|
putc('\n', stderr);
|
||||||
@@ -320,7 +317,7 @@ Symbol *sym_RedefEqu(char const *symName, int32_t value)
|
|||||||
if (!sym)
|
if (!sym)
|
||||||
return sym_AddEqu(symName, value);
|
return sym_AddEqu(symName, value);
|
||||||
|
|
||||||
if (sym_IsDefined(sym) && sym->type != SYM_EQU) {
|
if (sym->isDefined() && sym->type != SYM_EQU) {
|
||||||
error("'%s' already defined as non-EQU at ", symName);
|
error("'%s' already defined as non-EQU at ", symName);
|
||||||
dumpFilename(sym);
|
dumpFilename(sym);
|
||||||
putc('\n', stderr);
|
putc('\n', stderr);
|
||||||
@@ -368,7 +365,7 @@ Symbol *sym_RedefString(char const *symName, char const *value)
|
|||||||
return sym_AddString(symName, value);
|
return sym_AddString(symName, value);
|
||||||
|
|
||||||
if (sym->type != SYM_EQUS) {
|
if (sym->type != SYM_EQUS) {
|
||||||
if (sym_IsDefined(sym))
|
if (sym->isDefined())
|
||||||
error("'%s' already defined as non-EQUS at ", symName);
|
error("'%s' already defined as non-EQUS at ", symName);
|
||||||
else
|
else
|
||||||
error("'%s' already referenced at ", symName);
|
error("'%s' already referenced at ", symName);
|
||||||
@@ -395,7 +392,7 @@ Symbol *sym_AddVar(char const *symName, int32_t value)
|
|||||||
|
|
||||||
if (!sym) {
|
if (!sym) {
|
||||||
sym = createsymbol(symName);
|
sym = createsymbol(symName);
|
||||||
} else if (sym_IsDefined(sym) && sym->type != SYM_VAR) {
|
} else if (sym->isDefined() && sym->type != SYM_VAR) {
|
||||||
error("'%s' already defined as %s at ",
|
error("'%s' already defined as %s at ",
|
||||||
symName, sym->type == SYM_LABEL ? "label" : "constant");
|
symName, sym->type == SYM_LABEL ? "label" : "constant");
|
||||||
dumpFilename(sym);
|
dumpFilename(sym);
|
||||||
@@ -423,7 +420,7 @@ static Symbol *addLabel(char const *symName)
|
|||||||
|
|
||||||
if (!sym) {
|
if (!sym) {
|
||||||
sym = createsymbol(symName);
|
sym = createsymbol(symName);
|
||||||
} else if (sym_IsDefined(sym)) {
|
} else if (sym->isDefined()) {
|
||||||
error("'%s' already defined at ", symName);
|
error("'%s' already defined at ", symName);
|
||||||
dumpFilename(sym);
|
dumpFilename(sym);
|
||||||
putc('\n', stderr);
|
putc('\n', stderr);
|
||||||
|
|||||||
@@ -72,23 +72,23 @@ 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(FileStackNode const *node)
|
std::string const *FileStackNode::dumpFileStack() const
|
||||||
{
|
{
|
||||||
std::string const *lastName;
|
std::string const *lastName;
|
||||||
|
|
||||||
if (node->parent) {
|
if (parent) {
|
||||||
lastName = dumpFileStack(node->parent);
|
lastName = parent->dumpFileStack();
|
||||||
// REPT nodes use their parent's name
|
// REPT nodes use their parent's name
|
||||||
if (node->type != NODE_REPT)
|
if (type != NODE_REPT)
|
||||||
lastName = &node->name();
|
lastName = &name();
|
||||||
fprintf(stderr, "(%" PRIu32 ") -> %s", node->lineNo, lastName->c_str());
|
fprintf(stderr, "(%" PRIu32 ") -> %s", lineNo, lastName->c_str());
|
||||||
if (node->type == NODE_REPT) {
|
if (type == NODE_REPT) {
|
||||||
for (uint32_t iter : node->iters())
|
for (uint32_t iter : iters())
|
||||||
fprintf(stderr, "::REPT~%" PRIu32, iter);
|
fprintf(stderr, "::REPT~%" PRIu32, iter);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
assert(node->type != NODE_REPT);
|
assert(type != NODE_REPT);
|
||||||
lastName = &node->name();
|
lastName = &name();
|
||||||
fputs(lastName->c_str(), stderr);
|
fputs(lastName->c_str(), stderr);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -101,7 +101,7 @@ void printDiag(char const *fmt, va_list args, char const *type,
|
|||||||
fputs(type, stderr);
|
fputs(type, stderr);
|
||||||
fputs(": ", stderr);
|
fputs(": ", stderr);
|
||||||
if (where) {
|
if (where) {
|
||||||
dumpFileStack(where);
|
where->dumpFileStack();
|
||||||
fprintf(stderr, "(%" PRIu32 "): ", lineNo);
|
fprintf(stderr, "(%" PRIu32 "): ", lineNo);
|
||||||
}
|
}
|
||||||
vfprintf(stderr, fmt, args);
|
vfprintf(stderr, fmt, args);
|
||||||
|
|||||||
@@ -18,9 +18,9 @@ void sym_AddSymbol(Symbol *symbol)
|
|||||||
// Check if the symbol already exists
|
// Check if the symbol already exists
|
||||||
if (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);
|
symbol->src->dumpFileStack();
|
||||||
fprintf(stderr, "(%" PRIu32 ") and in %s from ", symbol->lineNo, other->objFileName);
|
fprintf(stderr, "(%" PRIu32 ") and in %s from ", symbol->lineNo, other->objFileName);
|
||||||
dumpFileStack(other->src);
|
other->src->dumpFileStack();
|
||||||
fprintf(stderr, "(%" PRIu32 ")\n", other->lineNo);
|
fprintf(stderr, "(%" PRIu32 ")\n", other->lineNo);
|
||||||
exit(1);
|
exit(1);
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user