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
|
||||
};
|
||||
|
||||
struct FormatSpec {
|
||||
class FormatSpec {
|
||||
enum FormatState state;
|
||||
int sign;
|
||||
bool prefix;
|
||||
@@ -26,15 +26,16 @@ struct FormatSpec {
|
||||
size_t fracWidth;
|
||||
int type;
|
||||
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
|
||||
|
||||
@@ -36,6 +36,8 @@ struct FileStackNode {
|
||||
// File name for files, file::macro name for macros
|
||||
std::string &name();
|
||||
std::string const &name() const;
|
||||
|
||||
void dump(uint32_t curLineNo) const;
|
||||
};
|
||||
|
||||
#define DEFAULT_MAX_DEPTH 64
|
||||
@@ -43,7 +45,6 @@ extern size_t maxRecursionDepth;
|
||||
|
||||
struct MacroArgs;
|
||||
|
||||
void fstk_Dump(FileStackNode const *node, uint32_t lineNo);
|
||||
void fstk_DumpCurrent();
|
||||
FileStackNode *fstk_GetFileStack();
|
||||
// The lifetime of the returned chars is until reaching the end of that file
|
||||
|
||||
@@ -5,18 +5,22 @@
|
||||
|
||||
#include <stdint.h>
|
||||
#include <stdlib.h>
|
||||
#include <vector>
|
||||
|
||||
#include "asm/warning.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_NewArgs();
|
||||
void macro_AppendArg(MacroArgs *args, char *s);
|
||||
void macro_UseNewArgs(MacroArgs *args);
|
||||
void macro_FreeArgs(MacroArgs *args);
|
||||
char const *macro_GetArg(uint32_t i);
|
||||
char const *macro_GetAllArgs();
|
||||
|
||||
|
||||
@@ -13,29 +13,19 @@ struct Symbol;
|
||||
struct Expression {
|
||||
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
|
||||
bool isKnown; // Whether the expression's value is known
|
||||
bool isSymbol; // Whether the expression represents a symbol
|
||||
bool isKnown; // Whether the expression's value is known at assembly time
|
||||
bool isSymbol; // Whether the expression represents a symbol suitable for const diffing
|
||||
std::vector<uint8_t> *rpn; // Bytes serializing the RPN expression
|
||||
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_Number(Expression *expr, uint32_t i);
|
||||
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_HIGH(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_SizeOfSectionType(Expression *expr, enum SectionType type);
|
||||
void rpn_StartOfSectionType(Expression *expr, enum SectionType type);
|
||||
|
||||
void rpn_Free(Expression *expr);
|
||||
|
||||
void rpn_CheckHRAM(Expression *expr, const Expression *src);
|
||||
void rpn_CheckRST(Expression *expr, const Expression *src);
|
||||
void rpn_CheckNBit(Expression const *expr, uint8_t n);
|
||||
int32_t rpn_GetConstVal(Expression const *expr);
|
||||
|
||||
#endif // RGBDS_ASM_RPN_H
|
||||
|
||||
@@ -8,7 +8,6 @@
|
||||
#include <vector>
|
||||
|
||||
#include "linkdefs.hpp"
|
||||
#include "platform.hpp" // NONNULL
|
||||
|
||||
extern uint8_t fillByte;
|
||||
|
||||
@@ -39,6 +38,8 @@ struct Section {
|
||||
uint16_t alignOfs;
|
||||
std::deque<Patch> patches;
|
||||
std::vector<uint8_t> data;
|
||||
|
||||
bool isSizeKnown() const;
|
||||
};
|
||||
|
||||
struct SectionSpec {
|
||||
@@ -85,6 +86,4 @@ void sect_EndSection();
|
||||
void sect_PushSection();
|
||||
void sect_PopSection();
|
||||
|
||||
bool sect_IsSizeKnown(Section const NONNULL(name));
|
||||
|
||||
#endif // RGBDS_SECTION_H
|
||||
|
||||
@@ -29,6 +29,9 @@ struct strValue {
|
||||
char *value;
|
||||
};
|
||||
|
||||
struct Symbol; // For the `sym_IsPC` forward declaration
|
||||
bool sym_IsPC(Symbol const *sym); // For the inline `getSection` method
|
||||
|
||||
struct Symbol {
|
||||
char name[MAXSYMLEN + 1];
|
||||
enum SymbolType type;
|
||||
@@ -40,7 +43,7 @@ struct Symbol {
|
||||
|
||||
bool hasCallback;
|
||||
union {
|
||||
// If sym_IsNumeric
|
||||
// If isNumeric()
|
||||
int32_t value;
|
||||
int32_t (*numCallback)(); // If hasCallback
|
||||
// For SYM_MACRO
|
||||
@@ -51,61 +54,28 @@ struct Symbol {
|
||||
};
|
||||
|
||||
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; }
|
||||
bool isLabel() const { return type == SYM_LABEL || type == SYM_REF; }
|
||||
|
||||
static inline bool sym_IsDefined(Symbol const *sym)
|
||||
{
|
||||
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);
|
||||
|
||||
return sect && sect->org != (uint32_t)-1;
|
||||
bool isConstant() const {
|
||||
if (type == SYM_LABEL) {
|
||||
Section const *sect = getSection();
|
||||
return sect && sect->org != (uint32_t)-1;
|
||||
}
|
||||
return type == SYM_EQU || type == SYM_VAR;
|
||||
}
|
||||
return sym->type == SYM_EQU || sym->type == SYM_VAR;
|
||||
}
|
||||
|
||||
static inline bool sym_IsNumeric(Symbol const *sym)
|
||||
{
|
||||
return sym->type == SYM_LABEL || sym->type == SYM_EQU || sym->type == SYM_VAR;
|
||||
}
|
||||
Section *getSection() const { return sym_IsPC(this) ? sect_GetSymbolSection() : section; }
|
||||
|
||||
static inline bool sym_IsLabel(Symbol const *sym)
|
||||
{
|
||||
return sym->type == SYM_LABEL || sym->type == SYM_REF;
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
int32_t getValue() const;
|
||||
uint32_t getConstantValue() const;
|
||||
char const *getStringValue() const { return hasCallback ? strCallback() : equs.value; }
|
||||
};
|
||||
|
||||
void sym_ForEach(void (*func)(Symbol *));
|
||||
|
||||
int32_t sym_GetValue(Symbol const *sym);
|
||||
void sym_SetExportAll(bool set);
|
||||
Symbol *sym_AddLocalLabel(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_AddVar(char const *symName, int32_t value);
|
||||
uint32_t sym_GetPCValue();
|
||||
uint32_t sym_GetConstantSymValue(Symbol const *sym);
|
||||
uint32_t sym_GetConstantValue(char const *symName);
|
||||
// Find a symbol by exact name, bypassing expansion checks
|
||||
Symbol *sym_FindExactSymbol(char const *symName);
|
||||
|
||||
@@ -30,6 +30,12 @@ extern bool beVerbose;
|
||||
extern bool isWRAM0Mode;
|
||||
extern bool disablePadding;
|
||||
|
||||
// Helper macro for printing verbose-mode messages
|
||||
#define verbosePrint(...) do { \
|
||||
if (beVerbose) \
|
||||
fprintf(stderr, __VA_ARGS__); \
|
||||
} while (0)
|
||||
|
||||
struct FileStackNode {
|
||||
FileStackNode *parent;
|
||||
// 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
|
||||
std::string &name();
|
||||
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 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);
|
||||
|
||||
#endif // RGBDS_LINK_MAIN_H
|
||||
|
||||
@@ -12,63 +12,41 @@
|
||||
#include "asm/format.hpp"
|
||||
#include "asm/warning.hpp"
|
||||
|
||||
FormatSpec fmt_NewSpec()
|
||||
void FormatSpec::useCharacter(int c)
|
||||
{
|
||||
FormatSpec fmt = {};
|
||||
|
||||
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)
|
||||
if (state == FORMAT_INVALID)
|
||||
return;
|
||||
|
||||
switch (c) {
|
||||
// sign
|
||||
case ' ':
|
||||
case '+':
|
||||
if (fmt->state > FORMAT_SIGN)
|
||||
if (state > FORMAT_SIGN)
|
||||
goto invalid;
|
||||
fmt->state = FORMAT_PREFIX;
|
||||
fmt->sign = c;
|
||||
state = FORMAT_PREFIX;
|
||||
sign = c;
|
||||
break;
|
||||
|
||||
// prefix
|
||||
case '#':
|
||||
if (fmt->state > FORMAT_PREFIX)
|
||||
if (state > FORMAT_PREFIX)
|
||||
goto invalid;
|
||||
fmt->state = FORMAT_ALIGN;
|
||||
fmt->prefix = true;
|
||||
state = FORMAT_ALIGN;
|
||||
prefix = true;
|
||||
break;
|
||||
|
||||
// align
|
||||
case '-':
|
||||
if (fmt->state > FORMAT_ALIGN)
|
||||
if (state > FORMAT_ALIGN)
|
||||
goto invalid;
|
||||
fmt->state = FORMAT_WIDTH;
|
||||
fmt->alignLeft = true;
|
||||
state = FORMAT_WIDTH;
|
||||
alignLeft = true;
|
||||
break;
|
||||
|
||||
// pad and width
|
||||
case '0':
|
||||
if (fmt->state < FORMAT_WIDTH)
|
||||
fmt->padZero = true;
|
||||
if (state < FORMAT_WIDTH)
|
||||
padZero = true;
|
||||
// fallthrough
|
||||
case '1':
|
||||
case '2':
|
||||
@@ -79,23 +57,23 @@ void fmt_UseCharacter(FormatSpec *fmt, int c)
|
||||
case '7':
|
||||
case '8':
|
||||
case '9':
|
||||
if (fmt->state < FORMAT_WIDTH) {
|
||||
fmt->state = FORMAT_WIDTH;
|
||||
fmt->width = c - '0';
|
||||
} else if (fmt->state == FORMAT_WIDTH) {
|
||||
fmt->width = fmt->width * 10 + (c - '0');
|
||||
} else if (fmt->state == FORMAT_FRAC) {
|
||||
fmt->fracWidth = fmt->fracWidth * 10 + (c - '0');
|
||||
if (state < FORMAT_WIDTH) {
|
||||
state = FORMAT_WIDTH;
|
||||
width = c - '0';
|
||||
} else if (state == FORMAT_WIDTH) {
|
||||
width = width * 10 + (c - '0');
|
||||
} else if (state == FORMAT_FRAC) {
|
||||
fracWidth = fracWidth * 10 + (c - '0');
|
||||
} else {
|
||||
goto invalid;
|
||||
}
|
||||
break;
|
||||
|
||||
case '.':
|
||||
if (fmt->state > FORMAT_WIDTH)
|
||||
if (state > FORMAT_WIDTH)
|
||||
goto invalid;
|
||||
fmt->state = FORMAT_FRAC;
|
||||
fmt->hasFrac = true;
|
||||
state = FORMAT_FRAC;
|
||||
hasFrac = true;
|
||||
break;
|
||||
|
||||
// type
|
||||
@@ -107,41 +85,46 @@ void fmt_UseCharacter(FormatSpec *fmt, int c)
|
||||
case 'o':
|
||||
case 'f':
|
||||
case 's':
|
||||
if (fmt->state >= FORMAT_DONE)
|
||||
if (state >= FORMAT_DONE)
|
||||
goto invalid;
|
||||
fmt->state = FORMAT_DONE;
|
||||
fmt->valid = true;
|
||||
fmt->type = c;
|
||||
state = FORMAT_DONE;
|
||||
valid = true;
|
||||
type = c;
|
||||
break;
|
||||
|
||||
default:
|
||||
invalid:
|
||||
fmt->state = FORMAT_INVALID;
|
||||
fmt->valid = false;
|
||||
state = FORMAT_INVALID;
|
||||
valid = false;
|
||||
}
|
||||
}
|
||||
|
||||
void fmt_FinishCharacters(FormatSpec *fmt)
|
||||
void FormatSpec::finishCharacters()
|
||||
{
|
||||
if (!fmt_IsValid(fmt))
|
||||
fmt->state = FORMAT_INVALID;
|
||||
if (!isValid())
|
||||
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)
|
||||
error("Formatting string with sign flag '%c'\n", fmt->sign);
|
||||
if (fmt->prefix)
|
||||
if (isEmpty()) {
|
||||
// No format was specified
|
||||
type = 's';
|
||||
}
|
||||
|
||||
if (sign)
|
||||
error("Formatting string with sign flag '%c'\n", sign);
|
||||
if (prefix)
|
||||
error("Formatting string with prefix flag '#'\n");
|
||||
if (fmt->padZero)
|
||||
if (padZero)
|
||||
error("Formatting string with padding flag '0'\n");
|
||||
if (fmt->hasFrac)
|
||||
if (hasFrac)
|
||||
error("Formatting string with fractional width\n");
|
||||
if (fmt->type != 's')
|
||||
error("Formatting string as type '%c'\n", fmt->type);
|
||||
if (type != 's')
|
||||
error("Formatting string as type '%c'\n", type);
|
||||
|
||||
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
|
||||
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;
|
||||
|
||||
if (fmt->alignLeft) {
|
||||
if (alignLeft) {
|
||||
memcpy(buf, value, len);
|
||||
for (size_t i = len; i < totalLen; i++)
|
||||
buf[i] = ' ';
|
||||
@@ -166,37 +149,42 @@ void fmt_PrintString(char *buf, size_t bufLen, FormatSpec const *fmt, char const
|
||||
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'
|
||||
&& fmt->prefix)
|
||||
error("Formatting type '%c' with prefix flag '#'\n", fmt->type);
|
||||
if (fmt->type != 'f' && fmt->hasFrac)
|
||||
error("Formatting type '%c' with fractional width\n", fmt->type);
|
||||
if (fmt->type == 's')
|
||||
if (isEmpty()) {
|
||||
// No format was specified; default to uppercase $hex
|
||||
type = 'X';
|
||||
prefix = true;
|
||||
}
|
||||
|
||||
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");
|
||||
|
||||
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;
|
||||
|
||||
if (v < 0 && v != INT32_MIN) {
|
||||
sign = '-';
|
||||
signChar = '-';
|
||||
value = -v;
|
||||
}
|
||||
}
|
||||
|
||||
char prefix = !fmt->prefix ? 0
|
||||
: fmt->type == 'X' ? '$'
|
||||
: fmt->type == 'x' ? '$'
|
||||
: fmt->type == 'b' ? '%'
|
||||
: fmt->type == 'o' ? '&'
|
||||
char prefixChar = !prefix ? 0
|
||||
: type == 'X' ? '$'
|
||||
: type == 'x' ? '$'
|
||||
: type == 'b' ? '%'
|
||||
: type == 'o' ? '&'
|
||||
: 0;
|
||||
|
||||
char valueBuf[262]; // Max 5 digits + decimal + 255 fraction digits + terminator
|
||||
|
||||
if (fmt->type == 'b') {
|
||||
if (type == 'b') {
|
||||
// Special case for binary
|
||||
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[j] = c;
|
||||
}
|
||||
} else if (fmt->type == 'f') {
|
||||
} else if (type == 'f') {
|
||||
// Special case for fixed-point
|
||||
|
||||
// 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) {
|
||||
error("Fractional width %zu too long, limiting to 255\n",
|
||||
fracWidth);
|
||||
fracWidth = 255;
|
||||
if (cappedFracWidth > 255) {
|
||||
error("Fractional width %zu too long, limiting to 255\n", cappedFracWidth);
|
||||
cappedFracWidth = 255;
|
||||
}
|
||||
|
||||
snprintf(valueBuf, sizeof(valueBuf), "%.*f", (int)fracWidth,
|
||||
snprintf(valueBuf, sizeof(valueBuf), "%.*f", (int)cappedFracWidth,
|
||||
value / fix_PrecisionFactor());
|
||||
} else {
|
||||
char const *spec = fmt->type == 'd' ? "%" PRId32
|
||||
: fmt->type == 'u' ? "%" PRIu32
|
||||
: fmt->type == 'X' ? "%" PRIX32
|
||||
: fmt->type == 'x' ? "%" PRIx32
|
||||
: fmt->type == 'o' ? "%" PRIo32
|
||||
char const *spec = type == 'd' ? "%" PRId32
|
||||
: type == 'u' ? "%" PRIu32
|
||||
: type == 'X' ? "%" PRIX32
|
||||
: type == 'x' ? "%" PRIx32
|
||||
: type == 'o' ? "%" PRIo32
|
||||
: "%" PRId32;
|
||||
|
||||
snprintf(valueBuf, sizeof(valueBuf), spec, value);
|
||||
}
|
||||
|
||||
size_t len = strlen(valueBuf);
|
||||
size_t numLen = (sign != 0) + (prefix != 0) + len;
|
||||
size_t totalLen = fmt->width > numLen ? fmt->width : numLen;
|
||||
size_t numLen = (signChar != 0) + (prefixChar != 0) + len;
|
||||
size_t totalLen = width > numLen ? width : numLen;
|
||||
|
||||
if (totalLen > bufLen - 1) { // bufLen includes terminator
|
||||
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 pos = 0;
|
||||
|
||||
if (fmt->alignLeft) {
|
||||
if (sign)
|
||||
buf[pos++] = sign;
|
||||
if (prefix)
|
||||
buf[pos++] = prefix;
|
||||
if (alignLeft) {
|
||||
if (signChar)
|
||||
buf[pos++] = signChar;
|
||||
if (prefixChar)
|
||||
buf[pos++] = prefixChar;
|
||||
memcpy(buf + pos, valueBuf, len);
|
||||
for (size_t i = pos + len; i < totalLen; i++)
|
||||
buf[i] = ' ';
|
||||
} else {
|
||||
if (fmt->padZero) {
|
||||
if (padZero) {
|
||||
// sign, then prefix, then zero padding
|
||||
if (sign)
|
||||
buf[pos++] = sign;
|
||||
if (prefix)
|
||||
buf[pos++] = prefix;
|
||||
if (signChar)
|
||||
buf[pos++] = signChar;
|
||||
if (prefixChar)
|
||||
buf[pos++] = prefixChar;
|
||||
for (size_t i = 0; i < padLen; i++)
|
||||
buf[pos++] = '0';
|
||||
} else {
|
||||
// space padding, then sign, then prefix
|
||||
for (size_t i = 0; i < padLen; i++)
|
||||
buf[pos++] = ' ';
|
||||
if (sign)
|
||||
buf[pos++] = sign;
|
||||
if (prefix)
|
||||
buf[pos++] = prefix;
|
||||
if (signChar)
|
||||
buf[pos++] = signChar;
|
||||
if (prefixChar)
|
||||
buf[pos++] = prefixChar;
|
||||
}
|
||||
memcpy(buf + pos, valueBuf, len);
|
||||
}
|
||||
|
||||
@@ -42,6 +42,26 @@ static std::vector<std::string> includePaths = { "" };
|
||||
|
||||
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)
|
||||
{
|
||||
char const *name;
|
||||
@@ -66,30 +86,10 @@ static const char *dumpNodeAndParents(FileStackNode const *node)
|
||||
return name;
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
void fstk_Dump(FileStackNode const *node, uint32_t lineNo)
|
||||
void FileStackNode::dump(uint32_t curLineNo) const
|
||||
{
|
||||
dumpNodeAndParents(node);
|
||||
fprintf(stderr, "(%" PRIu32 ")", lineNo);
|
||||
dumpNodeAndParents(this);
|
||||
fprintf(stderr, "(%" PRIu32 ")", curLineNo);
|
||||
}
|
||||
|
||||
void fstk_DumpCurrent()
|
||||
@@ -98,7 +98,7 @@ void fstk_DumpCurrent()
|
||||
fputs("at top level", stderr);
|
||||
return;
|
||||
}
|
||||
fstk_Dump(contextStack.top().fileInfo, lexer_GetLineNo());
|
||||
contextStack.top().fileInfo->dump(lexer_GetLineNo());
|
||||
}
|
||||
|
||||
FileStackNode *fstk_GetFileStack()
|
||||
@@ -240,7 +240,7 @@ bool yywrap()
|
||||
lexer_CleanupState(oldContext.lexerState);
|
||||
// Restore args if a macro (not REPT) saved them
|
||||
if (oldContext.fileInfo->type == NODE_MACRO) {
|
||||
macro_FreeArgs(macro_GetCurrentArgs());
|
||||
macro_GetCurrentArgs()->clear();
|
||||
macro_UseNewArgs(contextStack.top().macroArgs);
|
||||
}
|
||||
// Free the file stack node
|
||||
|
||||
@@ -579,12 +579,12 @@ static uint32_t readBracketedMacroArgNum()
|
||||
error("Bracketed symbol \"%s\" does not exist\n", symName);
|
||||
num = 0;
|
||||
symbolError = true;
|
||||
} else if (!sym_IsNumeric(sym)) {
|
||||
} else if (!sym->isNumeric()) {
|
||||
error("Bracketed symbol \"%s\" is not numeric\n", symName);
|
||||
num = 0;
|
||||
symbolError = true;
|
||||
} else {
|
||||
num = sym_GetConstantSymValue(sym);
|
||||
num = sym->getConstantValue();
|
||||
}
|
||||
} else {
|
||||
empty = true;
|
||||
@@ -1184,7 +1184,7 @@ static char const *readInterpolation(size_t depth)
|
||||
|
||||
char symName[MAXSYMLEN + 1];
|
||||
size_t i = 0;
|
||||
FormatSpec fmt = fmt_NewSpec();
|
||||
FormatSpec fmt{};
|
||||
bool disableInterpolation = lexerState->disableInterpolation;
|
||||
|
||||
// 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 == '}') {
|
||||
shiftChar();
|
||||
break;
|
||||
} else if (c == ':' && !fmt_IsFinished(&fmt)) { // Format spec, only once
|
||||
} else if (c == ':' && !fmt.isFinished()) { // Format spec, only once
|
||||
shiftChar();
|
||||
if (i == sizeof(symName)) {
|
||||
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';
|
||||
for (size_t j = 0; j < i; j++)
|
||||
fmt_UseCharacter(&fmt, symName[j]);
|
||||
fmt_FinishCharacters(&fmt);
|
||||
if (!fmt_IsValid(&fmt))
|
||||
fmt.useCharacter(symName[j]);
|
||||
fmt.finishCharacters();
|
||||
if (!fmt.isValid())
|
||||
error("Invalid format spec '%s'\n", symName);
|
||||
i = 0; // Now that format has been set, restart at beginning of string
|
||||
} else {
|
||||
@@ -1244,18 +1244,10 @@ static char const *readInterpolation(size_t depth)
|
||||
if (!sym) {
|
||||
error("Interpolated symbol \"%s\" does not exist\n", symName);
|
||||
} else if (sym->type == SYM_EQUS) {
|
||||
if (fmt_IsEmpty(&fmt))
|
||||
// No format was specified
|
||||
fmt.type = 's';
|
||||
fmt_PrintString(buf, sizeof(buf), &fmt, sym_GetStringValue(sym));
|
||||
fmt.printString(buf, sizeof(buf), sym->getStringValue());
|
||||
return buf;
|
||||
} else if (sym_IsNumeric(sym)) {
|
||||
if (fmt_IsEmpty(&fmt)) {
|
||||
// No format was specified; default to uppercase $hex
|
||||
fmt.type = 'X';
|
||||
fmt.prefix = true;
|
||||
}
|
||||
fmt_PrintNumber(buf, sizeof(buf), &fmt, sym_GetConstantSymValue(sym));
|
||||
} else if (sym->isNumeric()) {
|
||||
fmt.printNumber(buf, sizeof(buf), sym->getConstantValue());
|
||||
return buf;
|
||||
} else {
|
||||
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);
|
||||
|
||||
if (sym && sym->type == SYM_EQUS) {
|
||||
char const *s = sym_GetStringValue(sym);
|
||||
char const *s = sym->getStringValue();
|
||||
|
||||
assert(s);
|
||||
if (s[0])
|
||||
|
||||
@@ -13,11 +13,6 @@
|
||||
|
||||
#define MAXMACROARGS 99999
|
||||
|
||||
struct MacroArgs {
|
||||
unsigned int shift;
|
||||
std::vector<char *> args;
|
||||
};
|
||||
|
||||
static MacroArgs *macroArgs = nullptr;
|
||||
static uint32_t uniqueID = 0;
|
||||
static uint32_t maxUniqueID = 0;
|
||||
@@ -27,42 +22,31 @@ static uint32_t maxUniqueID = 0;
|
||||
static char uniqueIDBuf[] = "_u4294967295"; // UINT32_MAX
|
||||
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()
|
||||
{
|
||||
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)
|
||||
{
|
||||
macroArgs = args;
|
||||
}
|
||||
|
||||
void macro_FreeArgs(MacroArgs *args)
|
||||
{
|
||||
for (char *arg : args->args)
|
||||
free(arg);
|
||||
}
|
||||
|
||||
char const *macro_GetArg(uint32_t i)
|
||||
{
|
||||
if (!macroArgs)
|
||||
|
||||
@@ -142,7 +142,7 @@ static void writesection(Section const §, FILE *f)
|
||||
static void writesymbol(Symbol const *sym, FILE *f)
|
||||
{
|
||||
putstring(sym->name, f);
|
||||
if (!sym_IsDefined(sym)) {
|
||||
if (!sym->isDefined()) {
|
||||
putc(SYMTYPE_IMPORT, f);
|
||||
} else {
|
||||
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);
|
||||
putlong(sym->src->ID, f);
|
||||
putlong(sym->fileLine, f);
|
||||
putlong(getSectIDIfAny(sym_GetSection(sym)), f);
|
||||
putlong(getSectIDIfAny(sym->getSection()), 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
|
||||
sym = sym_FindExactSymbol(symName);
|
||||
if (sym_IsConstant(sym)) {
|
||||
if (sym->isConstant()) {
|
||||
writebyte(RPN_CONST);
|
||||
value = sym_GetConstantValue(symName);
|
||||
} else {
|
||||
@@ -280,7 +280,7 @@ static void initpatch(Patch &patch, uint32_t type, Expression const *expr, uint3
|
||||
patch.pcSection = sect_GetSymbolSection();
|
||||
patch.pcOffset = sect_GetSymbolOffset();
|
||||
|
||||
if (rpn_isKnown(expr)) {
|
||||
if (expr->isKnown) {
|
||||
// If the RPN expr's value is known, output a constant directly
|
||||
patch.rpn.resize(5);
|
||||
patch.rpn[0] = RPN_CONST;
|
||||
|
||||
@@ -71,7 +71,7 @@
|
||||
char const *rep);
|
||||
static void initStrFmtArgList(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);
|
||||
static void compoundAssignment(const char *symName, enum RPNCommand op, int32_t constValue);
|
||||
static void initDsArgList(std::vector<Expression> *&args);
|
||||
@@ -503,10 +503,14 @@ macro : T_ID {
|
||||
;
|
||||
|
||||
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 {
|
||||
macro_AppendArg($$, strdup($2));
|
||||
$$->append(strdup($2));
|
||||
}
|
||||
;
|
||||
|
||||
@@ -705,7 +709,7 @@ assert_type : %empty { $$ = ASSERT_ERROR; }
|
||||
;
|
||||
|
||||
assert : T_POP_ASSERT assert_type relocexpr {
|
||||
if (!rpn_isKnown(&$3)) {
|
||||
if (!$3.isKnown) {
|
||||
out_CreateAssert($2, &$3, "", sect_GetOutputOffset());
|
||||
} else if ($3.val == 0) {
|
||||
failAssert($2);
|
||||
@@ -713,7 +717,7 @@ assert : T_POP_ASSERT assert_type relocexpr {
|
||||
rpn_Free(&$3);
|
||||
}
|
||||
| T_POP_ASSERT assert_type relocexpr T_COMMA string {
|
||||
if (!rpn_isKnown(&$3)) {
|
||||
if (!$3.isKnown) {
|
||||
out_CreateAssert($2, &$3, $5, sect_GetOutputOffset());
|
||||
} else if ($3.val == 0) {
|
||||
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(); }
|
||||
@@ -1319,7 +1323,7 @@ string : T_STRING
|
||||
|
||||
if (!sym)
|
||||
fatalerror("Unknown symbol \"%s\"\n", $3);
|
||||
Section const *section = sym_GetSection(sym);
|
||||
Section const *section = sym->getSection();
|
||||
|
||||
if (!section)
|
||||
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
|
||||
| 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");
|
||||
}
|
||||
;
|
||||
@@ -1642,7 +1646,7 @@ z80_ld_mem : T_Z80_LD op_mem_ind T_COMMA T_MODE_SP {
|
||||
sect_RelWord(&$2, 1);
|
||||
}
|
||||
| T_Z80_LD op_mem_ind T_COMMA T_MODE_A {
|
||||
if (optimizeLoads && rpn_isKnown(&$2)
|
||||
if (optimizeLoads && $2.isKnown
|
||||
&& $2.val >= 0xFF00) {
|
||||
if (warnOnLdOpt) {
|
||||
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 {
|
||||
if ($2 == REG_A) {
|
||||
if (optimizeLoads && rpn_isKnown(&$4)
|
||||
&& $4.val >= 0xFF00) {
|
||||
if (optimizeLoads && $4.isKnown && $4.val >= 0xFF00) {
|
||||
if (warnOnLdOpt) {
|
||||
warnOnLdOpt = false;
|
||||
warning(WARNING_OBSOLETE,
|
||||
@@ -1795,7 +1798,7 @@ z80_rrca : T_Z80_RRCA { sect_AbsByte(0x0F); }
|
||||
|
||||
z80_rst : T_Z80_RST reloc_8bit {
|
||||
rpn_CheckRST(&$2, &$2);
|
||||
if (!rpn_isKnown(&$2))
|
||||
if (!$2.isKnown)
|
||||
sect_RelByte(&$2, 0);
|
||||
else
|
||||
sect_AbsByte(0xC7 | $2.val);
|
||||
@@ -2197,14 +2200,14 @@ static void freeStrFmtArgList(StrFmtArgList *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)
|
||||
{
|
||||
size_t a = 0;
|
||||
size_t i = 0;
|
||||
|
||||
while (i < destLen) {
|
||||
int c = *fmt++;
|
||||
int c = *spec++;
|
||||
|
||||
if (c == '\0') {
|
||||
break;
|
||||
@@ -2213,27 +2216,27 @@ static void strfmt(char *dest, size_t destLen, char const *fmt,
|
||||
continue;
|
||||
}
|
||||
|
||||
c = *fmt++;
|
||||
c = *spec++;
|
||||
|
||||
if (c == '%') {
|
||||
dest[i++] = c;
|
||||
continue;
|
||||
}
|
||||
|
||||
FormatSpec spec = fmt_NewSpec();
|
||||
FormatSpec fmt{};
|
||||
|
||||
while (c != '\0') {
|
||||
fmt_UseCharacter(&spec, c);
|
||||
if (fmt_IsFinished(&spec))
|
||||
fmt.useCharacter(c);
|
||||
if (fmt.isFinished())
|
||||
break;
|
||||
c = *fmt++;
|
||||
c = *spec++;
|
||||
}
|
||||
|
||||
if (fmt_IsEmpty(&spec)) {
|
||||
if (fmt.isEmpty()) {
|
||||
error("STRFMT: Illegal '%%' at end of format string\n");
|
||||
dest[i++] = '%';
|
||||
break;
|
||||
} else if (!fmt_IsValid(&spec)) {
|
||||
} else if (!fmt.isValid()) {
|
||||
error("STRFMT: Invalid format spec for argument %zu\n", a + 1);
|
||||
dest[i++] = '%';
|
||||
a++;
|
||||
@@ -2249,8 +2252,8 @@ static void strfmt(char *dest, size_t destLen, char const *fmt,
|
||||
static char buf[MAXSTRLEN + 1];
|
||||
|
||||
std::visit(Visitor{
|
||||
[&](uint32_t num) { fmt_PrintNumber(buf, sizeof(buf), &spec, num); },
|
||||
[&](char *str) { fmt_PrintString(buf, sizeof(buf), &spec, str); },
|
||||
[&](uint32_t num) { fmt.printNumber(buf, sizeof(buf), num); },
|
||||
[&](char *str) { fmt.printString(buf, sizeof(buf), str); },
|
||||
}, arg);
|
||||
|
||||
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_Number(&constExpr, constValue);
|
||||
rpn_BinaryOp(op, &newExpr, &oldExpr, &constExpr);
|
||||
newValue = rpn_GetConstVal(&newExpr);
|
||||
newValue = newExpr.getConstVal();
|
||||
sym_AddVar(symName, newValue);
|
||||
}
|
||||
|
||||
|
||||
136
src/asm/rpn.cpp
136
src/asm/rpn.cpp
@@ -21,6 +21,16 @@
|
||||
|
||||
#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
|
||||
template<typename... Ts>
|
||||
static void makeUnknown(Expression *expr, Ts ...parts)
|
||||
@@ -46,28 +56,18 @@ static uint8_t *reserveSpace(Expression *expr, uint32_t size)
|
||||
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
|
||||
void rpn_Free(Expression *expr)
|
||||
{
|
||||
delete expr->rpn;
|
||||
delete expr->reason;
|
||||
rpn_Init(expr);
|
||||
initExpression(expr);
|
||||
}
|
||||
|
||||
// Add symbols, constants and operators to expression
|
||||
void rpn_Number(Expression *expr, uint32_t i)
|
||||
{
|
||||
rpn_Init(expr);
|
||||
initExpression(expr);
|
||||
expr->val = i;
|
||||
}
|
||||
|
||||
@@ -78,8 +78,8 @@ void rpn_Symbol(Expression *expr, char const *symName)
|
||||
if (sym_IsPC(sym) && !sect_GetSymbolSection()) {
|
||||
error("PC has no value outside a section\n");
|
||||
rpn_Number(expr, 0);
|
||||
} else if (!sym || !sym_IsConstant(sym)) {
|
||||
rpn_Init(expr);
|
||||
} else if (!sym || !sym->isConstant()) {
|
||||
initExpression(expr);
|
||||
expr->isSymbol = true;
|
||||
|
||||
if (sym_IsPC(sym))
|
||||
@@ -100,7 +100,7 @@ void rpn_Symbol(Expression *expr, char const *symName)
|
||||
|
||||
void rpn_BankSelf(Expression *expr)
|
||||
{
|
||||
rpn_Init(expr);
|
||||
initExpression(expr);
|
||||
|
||||
if (!currentSection) {
|
||||
error("PC has no bank outside a section\n");
|
||||
@@ -124,22 +124,23 @@ void rpn_BankSymbol(Expression *expr, char const *symName)
|
||||
return;
|
||||
}
|
||||
|
||||
rpn_Init(expr);
|
||||
if (sym && !sym_IsLabel(sym)) {
|
||||
initExpression(expr);
|
||||
if (sym && !sym->isLabel()) {
|
||||
error("BANK argument must be a label\n");
|
||||
} else {
|
||||
sym = sym_Ref(symName);
|
||||
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
|
||||
expr->val = sym_GetSection(sym)->bank;
|
||||
expr->val = sym->getSection()->bank;
|
||||
} else {
|
||||
makeUnknown(expr, "\"", symName, "\"'s bank is not known");
|
||||
expr->rpnPatchSize += 5; // opcode + 4-byte sect ID
|
||||
|
||||
size_t nameLen = strlen(sym->name) + 1; // Room for NUL!
|
||||
uint8_t *ptr = reserveSpace(expr, nameLen + 1);
|
||||
|
||||
*ptr++ = RPN_BANK_SYM;
|
||||
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)
|
||||
{
|
||||
rpn_Init(expr);
|
||||
initExpression(expr);
|
||||
|
||||
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)
|
||||
{
|
||||
rpn_Init(expr);
|
||||
initExpression(expr);
|
||||
|
||||
Section *section = sect_FindSectionByName(sectionName);
|
||||
|
||||
if (section && sect_IsSizeKnown(section)) {
|
||||
if (section && section->isSizeKnown()) {
|
||||
expr->val = section->size;
|
||||
} else {
|
||||
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)
|
||||
{
|
||||
rpn_Init(expr);
|
||||
initExpression(expr);
|
||||
|
||||
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)
|
||||
{
|
||||
rpn_Init(expr);
|
||||
initExpression(expr);
|
||||
makeUnknown(expr, "Section type's size is not known");
|
||||
|
||||
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)
|
||||
{
|
||||
rpn_Init(expr);
|
||||
initExpression(expr);
|
||||
makeUnknown(expr, "Section type's start is not known");
|
||||
|
||||
uint8_t *ptr = reserveSpace(expr, 2);
|
||||
@@ -235,7 +236,7 @@ void rpn_CheckHRAM(Expression *expr, const Expression *src)
|
||||
*expr = *src;
|
||||
expr->isSymbol = false;
|
||||
|
||||
if (!rpn_isKnown(expr)) {
|
||||
if (!expr->isKnown) {
|
||||
expr->rpnPatchSize++;
|
||||
*reserveSpace(expr, 1) = RPN_HRAM;
|
||||
} else if (expr->val >= 0xFF00 && expr->val <= 0xFFFF) {
|
||||
@@ -250,7 +251,7 @@ void rpn_CheckRST(Expression *expr, const Expression *src)
|
||||
{
|
||||
*expr = *src;
|
||||
|
||||
if (rpn_isKnown(expr)) {
|
||||
if (expr->isKnown) {
|
||||
// A valid RST address must be masked with 0x38
|
||||
if (expr->val & ~0x38)
|
||||
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 < CHAR_BIT * sizeof(int)); // Otherwise `1 << n` is UB
|
||||
|
||||
if (rpn_isKnown(expr)) {
|
||||
if (expr->isKnown) {
|
||||
int32_t val = expr->val;
|
||||
|
||||
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)) {
|
||||
error("Expected constant expression: %s\n", expr->reason->c_str());
|
||||
if (!isKnown) {
|
||||
error("Expected constant expression: %s\n", reason->c_str());
|
||||
return 0;
|
||||
}
|
||||
return expr->val;
|
||||
return val;
|
||||
}
|
||||
|
||||
void rpn_LOGNOT(Expression *expr, const Expression *src)
|
||||
@@ -292,7 +293,7 @@ void rpn_LOGNOT(Expression *expr, const Expression *src)
|
||||
*expr = *src;
|
||||
expr->isSymbol = false;
|
||||
|
||||
if (rpn_isKnown(expr)) {
|
||||
if (expr->isKnown) {
|
||||
expr->val = !expr->val;
|
||||
} else {
|
||||
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 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
|
||||
Symbol const *sym1 = rpn_SymbolOf(src);
|
||||
Symbol const *sym1 = symbolOf();
|
||||
|
||||
if (!sym1 || !sym || sym1->type != SYM_LABEL || sym->type != SYM_LABEL)
|
||||
return false;
|
||||
|
||||
Section const *section1 = sym_GetSection(sym1);
|
||||
Section const *section2 = sym_GetSection(sym);
|
||||
Section const *section1 = sym1->getSection();
|
||||
Section const *section2 = sym->getSection();
|
||||
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
|
||||
* 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)
|
||||
{
|
||||
Symbol const *sym = rpn_SymbolOf(lhs);
|
||||
Symbol const *sym = lhs->symbolOf();
|
||||
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
|
||||
sym = rpn_SymbolOf(rhs);
|
||||
sym = rhs->symbolOf();
|
||||
expr = lhs;
|
||||
|
||||
if (!sym || !sym_GetSection(sym))
|
||||
if (!sym || !sym->getSection())
|
||||
return -1;
|
||||
}
|
||||
assert(sym_IsNumeric(sym));
|
||||
assert(sym->isNumeric());
|
||||
|
||||
if (!rpn_isKnown(expr))
|
||||
if (!expr->isKnown)
|
||||
return -1;
|
||||
// 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
|
||||
|
||||
// The mask must ignore all unknown bits
|
||||
if ((expr->val & unknownBits) != 0)
|
||||
return -1;
|
||||
|
||||
// `sym_GetValue()` attempts to add the section's address,
|
||||
// but that's "-1" because the section is floating (otherwise we wouldn't be here)
|
||||
// `sym->getValue()` attempts to add the section's address, but that's "-1"
|
||||
// because the section is floating (otherwise we wouldn't be here)
|
||||
assert(sect->org == (uint32_t)-1);
|
||||
int32_t symbolOfs = sym_GetValue(sym) + 1;
|
||||
int32_t symbolOfs = sym->getValue() + 1;
|
||||
|
||||
return (symbolOfs + sect->alignOfs) & ~unknownBits;
|
||||
}
|
||||
@@ -371,9 +367,9 @@ void rpn_BinaryOp(enum RPNCommand op, Expression *expr, const Expression *src1,
|
||||
int32_t constMaskVal;
|
||||
|
||||
// First, check if the expression is known
|
||||
expr->isKnown = rpn_isKnown(src1) && rpn_isKnown(src2);
|
||||
if (rpn_isKnown(expr)) {
|
||||
rpn_Init(expr); // Init the expression to something sane
|
||||
expr->isKnown = src1->isKnown && src2->isKnown;
|
||||
if (expr->isKnown) {
|
||||
initExpression(expr); // Init the expression to something sane
|
||||
|
||||
// If both expressions are known, just compute the value
|
||||
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);
|
||||
}
|
||||
|
||||
} else if (op == RPN_SUB && isDiffConstant(src1, src2)) {
|
||||
Symbol const *symbol1 = rpn_SymbolOf(src1);
|
||||
Symbol const *symbol2 = rpn_SymbolOf(src2);
|
||||
} else if (op == RPN_SUB && src1->isDiffConstant(src2->symbolOf())) {
|
||||
Symbol const *symbol1 = src1->symbolOf();
|
||||
Symbol const *symbol2 = src2->symbolOf();
|
||||
|
||||
expr->val = sym_GetValue(symbol1) - sym_GetValue(symbol2);
|
||||
expr->val = symbol1->getValue() - symbol2->getValue();
|
||||
expr->isKnown = true;
|
||||
} else if (op == RPN_AND && (constMaskVal = tryConstMask(src1, src2)) != -1) {
|
||||
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
|
||||
|
||||
// Convert the left-hand expression if it's constant
|
||||
if (rpn_isKnown(src1)) {
|
||||
if (src1->isKnown) {
|
||||
uint32_t lval = src1->val;
|
||||
uint8_t bytes[] = {RPN_CONST, (uint8_t)lval, (uint8_t)(lval >> 8),
|
||||
(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;
|
||||
uint8_t bytes[] = {RPN_CONST, (uint8_t)rval, (uint8_t)(rval >> 8),
|
||||
(uint8_t)(rval >> 16), (uint8_t)(rval >> 24)};
|
||||
if (rpn_isKnown(src2)) {
|
||||
if (src2->isKnown) {
|
||||
ptr = bytes;
|
||||
len = sizeof(bytes);
|
||||
patchSize = sizeof(bytes);
|
||||
@@ -577,7 +573,7 @@ void rpn_HIGH(Expression *expr, const Expression *src)
|
||||
*expr = *src;
|
||||
expr->isSymbol = false;
|
||||
|
||||
if (rpn_isKnown(expr)) {
|
||||
if (expr->isKnown) {
|
||||
expr->val = (uint32_t)expr->val >> 8 & 0xFF;
|
||||
} else {
|
||||
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->isSymbol = false;
|
||||
|
||||
if (rpn_isKnown(expr)) {
|
||||
if (expr->isKnown) {
|
||||
expr->val = expr->val & 0xFF;
|
||||
} else {
|
||||
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)
|
||||
{
|
||||
rpn_Init(expr);
|
||||
expr->val = rpn_isKnown(src);
|
||||
initExpression(expr);
|
||||
expr->val = src->isKnown;
|
||||
expr->isKnown = true;
|
||||
expr->isSymbol = false;
|
||||
}
|
||||
@@ -615,7 +611,7 @@ void rpn_NEG(Expression *expr, const Expression *src)
|
||||
*expr = *src;
|
||||
expr->isSymbol = false;
|
||||
|
||||
if (rpn_isKnown(expr)) {
|
||||
if (expr->isKnown) {
|
||||
expr->val = -(uint32_t)expr->val;
|
||||
} else {
|
||||
expr->rpnPatchSize++;
|
||||
@@ -628,7 +624,7 @@ void rpn_NOT(Expression *expr, const Expression *src)
|
||||
*expr = *src;
|
||||
expr->isSymbol = false;
|
||||
|
||||
if (rpn_isKnown(expr)) {
|
||||
if (expr->isKnown) {
|
||||
expr->val = ~expr->val;
|
||||
} else {
|
||||
expr->rpnPatchSize++;
|
||||
|
||||
@@ -250,7 +250,7 @@ static void mergeSections(Section *sect, enum SectionType type, uint32_t org, ui
|
||||
|
||||
case SECTION_NORMAL:
|
||||
fail("Section already defined previously at ");
|
||||
fstk_Dump(sect->src, sect->fileLine);
|
||||
sect->src->dump(sect->fileLine);
|
||||
putc('\n', stderr);
|
||||
break;
|
||||
}
|
||||
@@ -375,6 +375,25 @@ static void changeSection()
|
||||
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
|
||||
void sect_NewSection(char const *name, enum SectionType type, uint32_t org,
|
||||
SectionSpec const *attribs, enum SectionModifier mod)
|
||||
@@ -675,7 +694,7 @@ void sect_RelByte(Expression *expr, uint32_t pcShift)
|
||||
if (!reserveSpace(1))
|
||||
return;
|
||||
|
||||
if (!rpn_isKnown(expr)) {
|
||||
if (!expr->isKnown) {
|
||||
createPatch(PATCHTYPE_BYTE, expr, pcShift);
|
||||
writebyte(0);
|
||||
} else {
|
||||
@@ -696,7 +715,7 @@ void sect_RelBytes(uint32_t n, std::vector<Expression> &exprs)
|
||||
for (uint32_t i = 0; i < n; i++) {
|
||||
Expression &expr = exprs[i % exprs.size()];
|
||||
|
||||
if (!rpn_isKnown(&expr)) {
|
||||
if (!expr.isKnown) {
|
||||
createPatch(PATCHTYPE_BYTE, &expr, i);
|
||||
writebyte(0);
|
||||
} else {
|
||||
@@ -717,7 +736,7 @@ void sect_RelWord(Expression *expr, uint32_t pcShift)
|
||||
if (!reserveSpace(2))
|
||||
return;
|
||||
|
||||
if (!rpn_isKnown(expr)) {
|
||||
if (!expr->isKnown) {
|
||||
createPatch(PATCHTYPE_WORD, expr, pcShift);
|
||||
writeword(0);
|
||||
} else {
|
||||
@@ -735,7 +754,7 @@ void sect_RelLong(Expression *expr, uint32_t pcShift)
|
||||
if (!reserveSpace(2))
|
||||
return;
|
||||
|
||||
if (!rpn_isKnown(expr)) {
|
||||
if (!expr->isKnown) {
|
||||
createPatch(PATCHTYPE_LONG, expr, pcShift);
|
||||
writelong(0);
|
||||
} else {
|
||||
@@ -754,11 +773,11 @@ void sect_PCRelByte(Expression *expr, uint32_t pcShift)
|
||||
return;
|
||||
Symbol const *pc = sym_GetPC();
|
||||
|
||||
if (!rpn_IsDiffConstant(expr, pc)) {
|
||||
if (!expr->isDiffConstant(pc)) {
|
||||
createPatch(PATCHTYPE_JR, expr, pcShift);
|
||||
writebyte(0);
|
||||
} else {
|
||||
Symbol const *sym = rpn_SymbolOf(expr);
|
||||
Symbol const *sym = expr->symbolOf();
|
||||
// The offset wraps (jump from ROM to HRAM, for example)
|
||||
int16_t offset;
|
||||
|
||||
@@ -766,7 +785,7 @@ void sect_PCRelByte(Expression *expr, uint32_t pcShift)
|
||||
if (sym == pc)
|
||||
offset = -2; // PC as operand to `jr` is lower than reference PC by 2
|
||||
else
|
||||
offset = sym_GetValue(sym) - (sym_GetValue(pc) + 1);
|
||||
offset = sym->getValue() - (pc->getValue() + 1);
|
||||
|
||||
if (offset < -128 || offset > 127) {
|
||||
error("jr target out of reach (expected -129 < %" PRId16 " < 128)\n",
|
||||
@@ -973,22 +992,3 @@ void sect_EndSection()
|
||||
currentSection = 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
|
||||
int32_t sym_GetValue(Symbol const *sym)
|
||||
int32_t Symbol::getValue() const
|
||||
{
|
||||
if (sym_IsNumeric(sym) && sym->hasCallback)
|
||||
return sym->numCallback();
|
||||
if (isNumeric() && hasCallback)
|
||||
return numCallback();
|
||||
|
||||
if (sym->type == SYM_LABEL)
|
||||
if (type == SYM_LABEL)
|
||||
// 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)
|
||||
{
|
||||
if (sym->src)
|
||||
fstk_Dump(sym->src, sym->fileLine);
|
||||
sym->src->dump(sym->fileLine);
|
||||
else if (sym->fileLine == 0)
|
||||
fputs("<command-line>", stderr);
|
||||
else
|
||||
@@ -178,7 +178,7 @@ Symbol *sym_FindScopedValidSymbol(char const *symName)
|
||||
Symbol *sym = sym_FindScopedSymbol(symName);
|
||||
|
||||
// `@` has no value outside a section
|
||||
if (sym == PCSymbol && !sect_GetSymbolSection()) {
|
||||
if (sym_IsPC(sym) && !sect_GetSymbolSection()) {
|
||||
return nullptr;
|
||||
}
|
||||
// `_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
|
||||
uint32_t sym_GetConstantSymValue(Symbol const *sym)
|
||||
uint32_t Symbol::getConstantValue() const
|
||||
{
|
||||
if (sym == PCSymbol)
|
||||
if (sym_IsPC(this))
|
||||
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 a constant symbol's value
|
||||
uint32_t sym_GetConstantValue(char const *symName)
|
||||
{
|
||||
Symbol const *sym = sym_FindScopedSymbol(symName);
|
||||
|
||||
if (!sym)
|
||||
error("'%s' not defined\n", symName);
|
||||
else
|
||||
return sym_GetConstantSymValue(sym);
|
||||
if (Symbol const *sym = sym_FindScopedSymbol(symName); sym)
|
||||
return sym->getConstantValue();
|
||||
|
||||
error("'%s' not defined\n", symName);
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -283,7 +280,7 @@ static Symbol *createNonrelocSymbol(char const *symName, bool numeric)
|
||||
|
||||
if (!sym) {
|
||||
sym = createsymbol(symName);
|
||||
} else if (sym_IsDefined(sym)) {
|
||||
} else if (sym->isDefined()) {
|
||||
error("'%s' already defined at ", symName);
|
||||
dumpFilename(sym);
|
||||
putc('\n', stderr);
|
||||
@@ -320,7 +317,7 @@ Symbol *sym_RedefEqu(char const *symName, int32_t value)
|
||||
if (!sym)
|
||||
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);
|
||||
dumpFilename(sym);
|
||||
putc('\n', stderr);
|
||||
@@ -368,7 +365,7 @@ Symbol *sym_RedefString(char const *symName, char const *value)
|
||||
return sym_AddString(symName, value);
|
||||
|
||||
if (sym->type != SYM_EQUS) {
|
||||
if (sym_IsDefined(sym))
|
||||
if (sym->isDefined())
|
||||
error("'%s' already defined as non-EQUS at ", symName);
|
||||
else
|
||||
error("'%s' already referenced at ", symName);
|
||||
@@ -395,7 +392,7 @@ Symbol *sym_AddVar(char const *symName, int32_t value)
|
||||
|
||||
if (!sym) {
|
||||
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 ",
|
||||
symName, sym->type == SYM_LABEL ? "label" : "constant");
|
||||
dumpFilename(sym);
|
||||
@@ -423,7 +420,7 @@ static Symbol *addLabel(char const *symName)
|
||||
|
||||
if (!sym) {
|
||||
sym = createsymbol(symName);
|
||||
} else if (sym_IsDefined(sym)) {
|
||||
} else if (sym->isDefined()) {
|
||||
error("'%s' already defined at ", symName);
|
||||
dumpFilename(sym);
|
||||
putc('\n', stderr);
|
||||
|
||||
@@ -72,23 +72,23 @@ std::string const &FileStackNode::name() const {
|
||||
}
|
||||
|
||||
// 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;
|
||||
|
||||
if (node->parent) {
|
||||
lastName = dumpFileStack(node->parent);
|
||||
if (parent) {
|
||||
lastName = parent->dumpFileStack();
|
||||
// REPT nodes use their parent's name
|
||||
if (node->type != NODE_REPT)
|
||||
lastName = &node->name();
|
||||
fprintf(stderr, "(%" PRIu32 ") -> %s", node->lineNo, lastName->c_str());
|
||||
if (node->type == NODE_REPT) {
|
||||
for (uint32_t iter : node->iters())
|
||||
if (type != NODE_REPT)
|
||||
lastName = &name();
|
||||
fprintf(stderr, "(%" PRIu32 ") -> %s", lineNo, lastName->c_str());
|
||||
if (type == NODE_REPT) {
|
||||
for (uint32_t iter : iters())
|
||||
fprintf(stderr, "::REPT~%" PRIu32, iter);
|
||||
}
|
||||
} else {
|
||||
assert(node->type != NODE_REPT);
|
||||
lastName = &node->name();
|
||||
assert(type != NODE_REPT);
|
||||
lastName = &name();
|
||||
fputs(lastName->c_str(), stderr);
|
||||
}
|
||||
|
||||
@@ -101,7 +101,7 @@ void printDiag(char const *fmt, va_list args, char const *type,
|
||||
fputs(type, stderr);
|
||||
fputs(": ", stderr);
|
||||
if (where) {
|
||||
dumpFileStack(where);
|
||||
where->dumpFileStack();
|
||||
fprintf(stderr, "(%" PRIu32 "): ", lineNo);
|
||||
}
|
||||
vfprintf(stderr, fmt, args);
|
||||
|
||||
@@ -18,9 +18,9 @@ void sym_AddSymbol(Symbol *symbol)
|
||||
// Check if the symbol already exists
|
||||
if (Symbol *other = sym_GetSymbol(symbol->name); other) {
|
||||
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);
|
||||
dumpFileStack(other->src);
|
||||
other->src->dumpFileStack();
|
||||
fprintf(stderr, "(%" PRIu32 ")\n", other->lineNo);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user