Refactor structs to use methods instead of functions (#1322)

This commit is contained in:
Sylvie
2024-03-01 13:11:45 -05:00
committed by GitHub
parent e14ba664ea
commit 1ac3c0262f
18 changed files with 364 additions and 446 deletions

View File

@@ -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

View File

@@ -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

View 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();

View File

@@ -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

View File

@@ -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

View File

@@ -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);
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);
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; }
bool isConstant() const {
if (type == SYM_LABEL) {
Section const *sect = getSection();
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)
{
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);

View File

@@ -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

View File

@@ -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);
}

View File

@@ -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

View File

@@ -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])

View File

@@ -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)

View File

@@ -142,7 +142,7 @@ static void writesection(Section const &sect, 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;

View File

@@ -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);
}

View File

@@ -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++;

View File

@@ -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;
}

View File

@@ -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 (Symbol const *sym = sym_FindScopedSymbol(symName); sym)
return sym->getConstantValue();
if (!sym)
error("'%s' not defined\n", symName);
else
return sym_GetConstantSymValue(sym);
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);

View File

@@ -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);

View File

@@ -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);
}