Run clang-format on everything (#1332)

This commit is contained in:
Sylvie
2024-03-04 14:22:49 -05:00
committed by GitHub
parent b004648a13
commit e74073e480
66 changed files with 6091 additions and 4957 deletions

View File

@@ -1,29 +1,30 @@
/* SPDX-License-Identifier: MIT */
#include "asm/charmap.hpp"
#include <errno.h>
#include <new>
#include <map>
#include <new>
#include <stack>
#include <stdint.h>
#include <stdlib.h>
#include <stdio.h>
#include <string>
#include <stdlib.h>
#include <string.h>
#include <string>
#include <vector>
#include "asm/charmap.hpp"
#include "util.hpp"
#include "asm/main.hpp"
#include "asm/output.hpp"
#include "asm/warning.hpp"
#include "util.hpp"
// Charmaps are stored using a structure known as "trie".
// Essentially a tree, where each nodes stores a single character's worth of info:
// whether there exists a mapping that ends at the current character,
struct CharmapNode {
bool isTerminal; // Whether there exists a mapping that ends here
uint8_t value; // If the above is true, its corresponding value
uint8_t value; // If the above is true, its corresponding value
// This MUST be indexes and not pointers, because pointers get invalidated by reallocation!
size_t next[255]; // Indexes of where to go next, 0 = nowhere
};
@@ -38,8 +39,7 @@ static std::map<std::string, Charmap> charmaps;
static Charmap *currentCharmap;
std::stack<Charmap *> charmapStack;
void charmap_New(char const *name, char const *baseName)
{
void charmap_New(char const *name, char const *baseName) {
Charmap *base = nullptr;
if (baseName != nullptr) {
@@ -68,8 +68,7 @@ void charmap_New(char const *name, char const *baseName)
currentCharmap = &charmap;
}
void charmap_Set(char const *name)
{
void charmap_Set(char const *name) {
auto search = charmaps.find(name);
if (search == charmaps.end())
@@ -78,13 +77,11 @@ void charmap_Set(char const *name)
currentCharmap = &search->second;
}
void charmap_Push()
{
void charmap_Push() {
charmapStack.push(currentCharmap);
}
void charmap_Pop()
{
void charmap_Pop() {
if (charmapStack.empty()) {
error("No entries in the charmap stack\n");
return;
@@ -94,8 +91,7 @@ void charmap_Pop()
charmapStack.pop();
}
void charmap_Add(char *mapping, uint8_t value)
{
void charmap_Add(char *mapping, uint8_t value) {
Charmap &charmap = *currentCharmap;
size_t nodeIdx = 0;
@@ -124,8 +120,7 @@ void charmap_Add(char *mapping, uint8_t value)
node.value = value;
}
bool charmap_HasChar(char const *input)
{
bool charmap_HasChar(char const *input) {
Charmap const &charmap = *currentCharmap;
size_t nodeIdx = 0;
@@ -139,14 +134,12 @@ bool charmap_HasChar(char const *input)
return charmap.nodes[nodeIdx].isTerminal;
}
void charmap_Convert(char const *input, std::vector<uint8_t> &output)
{
void charmap_Convert(char const *input, std::vector<uint8_t> &output) {
while (charmap_ConvertNext(input, &output))
;
}
size_t charmap_ConvertNext(char const *&input, std::vector<uint8_t> *output)
{
size_t charmap_ConvertNext(char const *&input, std::vector<uint8_t> *output) {
// The goal is to match the longest mapping possible.
// For that, advance through the trie with each character read.
// If that would lead to a dead end, rewind characters until the last match, and output.
@@ -194,11 +187,13 @@ size_t charmap_ConvertNext(char const *&input, std::vector<uint8_t> *output)
// Warn if this character is not mapped but any others are
if (charmap.nodes.size() > 1)
warning(WARNING_UNMAPPED_CHAR_1, "Unmapped character %s\n",
printChar(firstChar));
warning(WARNING_UNMAPPED_CHAR_1, "Unmapped character %s\n", printChar(firstChar));
else if (charmap.name != DEFAULT_CHARMAP_NAME)
warning(WARNING_UNMAPPED_CHAR_2, "Unmapped character %s not in "
DEFAULT_CHARMAP_NAME " charmap\n", printChar(firstChar));
warning(
WARNING_UNMAPPED_CHAR_2,
"Unmapped character %s not in " DEFAULT_CHARMAP_NAME " charmap\n",
printChar(firstChar)
);
return codepointLen;

View File

@@ -2,20 +2,21 @@
// Fixed-point math routines
#include "asm/fixpoint.hpp"
#include <inttypes.h>
#include <math.h>
#include <stdint.h>
#include "asm/fixpoint.hpp"
#include "asm/symbol.hpp"
#include "asm/warning.hpp"
#ifndef M_PI
#define M_PI 3.14159265358979323846
#define M_PI 3.14159265358979323846
#endif
#define fix2double(i, q) ((double)((i) / pow(2.0, q)))
#define double2fix(d, q) ((int32_t)round((d) * pow(2.0, q)))
#define double2fix(d, q) ((int32_t)round((d)*pow(2.0, q)))
// 2*pi radians == 1 turn
#define turn2rad(f) ((f) * (M_PI * 2))
@@ -23,87 +24,70 @@
uint8_t fixPrecision;
uint8_t fix_Precision()
{
uint8_t fix_Precision() {
return fixPrecision;
}
double fix_PrecisionFactor()
{
double fix_PrecisionFactor() {
return pow(2.0, fixPrecision);
}
int32_t fix_Sin(int32_t i, int32_t q)
{
int32_t fix_Sin(int32_t i, int32_t q) {
return double2fix(sin(turn2rad(fix2double(i, q))), q);
}
int32_t fix_Cos(int32_t i, int32_t q)
{
int32_t fix_Cos(int32_t i, int32_t q) {
return double2fix(cos(turn2rad(fix2double(i, q))), q);
}
int32_t fix_Tan(int32_t i, int32_t q)
{
int32_t fix_Tan(int32_t i, int32_t q) {
return double2fix(tan(turn2rad(fix2double(i, q))), q);
}
int32_t fix_ASin(int32_t i, int32_t q)
{
int32_t fix_ASin(int32_t i, int32_t q) {
return double2fix(rad2turn(asin(fix2double(i, q))), q);
}
int32_t fix_ACos(int32_t i, int32_t q)
{
int32_t fix_ACos(int32_t i, int32_t q) {
return double2fix(rad2turn(acos(fix2double(i, q))), q);
}
int32_t fix_ATan(int32_t i, int32_t q)
{
int32_t fix_ATan(int32_t i, int32_t q) {
return double2fix(rad2turn(atan(fix2double(i, q))), q);
}
int32_t fix_ATan2(int32_t i, int32_t j, int32_t q)
{
int32_t fix_ATan2(int32_t i, int32_t j, int32_t q) {
return double2fix(rad2turn(atan2(fix2double(i, q), fix2double(j, q))), q);
}
int32_t fix_Mul(int32_t i, int32_t j, int32_t q)
{
int32_t fix_Mul(int32_t i, int32_t j, int32_t q) {
return double2fix(fix2double(i, q) * fix2double(j, q), q);
}
int32_t fix_Div(int32_t i, int32_t j, int32_t q)
{
int32_t fix_Div(int32_t i, int32_t j, int32_t q) {
return double2fix(fix2double(i, q) / fix2double(j, q), q);
}
int32_t fix_Mod(int32_t i, int32_t j, int32_t q)
{
int32_t fix_Mod(int32_t i, int32_t j, int32_t q) {
return double2fix(fmod(fix2double(i, q), fix2double(j, q)), q);
}
int32_t fix_Pow(int32_t i, int32_t j, int32_t q)
{
int32_t fix_Pow(int32_t i, int32_t j, int32_t q) {
return double2fix(pow(fix2double(i, q), fix2double(j, q)), q);
}
int32_t fix_Log(int32_t i, int32_t j, int32_t q)
{
int32_t fix_Log(int32_t i, int32_t j, int32_t q) {
return double2fix(log(fix2double(i, q)) / log(fix2double(j, q)), q);
}
int32_t fix_Round(int32_t i, int32_t q)
{
int32_t fix_Round(int32_t i, int32_t q) {
return double2fix(round(fix2double(i, q)), q);
}
int32_t fix_Ceil(int32_t i, int32_t q)
{
int32_t fix_Ceil(int32_t i, int32_t q) {
return double2fix(ceil(fix2double(i, q)), q);
}
int32_t fix_Floor(int32_t i, int32_t q)
{
int32_t fix_Floor(int32_t i, int32_t q) {
return double2fix(floor(fix2double(i, q)), q);
}

View File

@@ -1,5 +1,7 @@
/* SPDX-License-Identifier: MIT */
#include "asm/format.hpp"
#include <assert.h>
#include <inttypes.h>
#include <math.h>
@@ -9,11 +11,9 @@
#include <string.h>
#include "asm/fixpoint.hpp"
#include "asm/format.hpp"
#include "asm/warning.hpp"
void FormatSpec::useCharacter(int c)
{
void FormatSpec::useCharacter(int c) {
if (state == FORMAT_INVALID)
return;
@@ -99,14 +99,12 @@ invalid:
}
}
void FormatSpec::finishCharacters()
{
void FormatSpec::finishCharacters() {
if (!isValid())
state = FORMAT_INVALID;
}
void FormatSpec::printString(char *buf, size_t bufLen, char const *value)
{
void FormatSpec::printString(char *buf, size_t bufLen, char const *value) {
if (isEmpty()) {
// No format was specified
type = 's';
@@ -149,8 +147,7 @@ void FormatSpec::printString(char *buf, size_t bufLen, char const *value)
buf[totalLen] = '\0';
}
void FormatSpec::printNumber(char *buf, size_t bufLen, uint32_t value)
{
void FormatSpec::printNumber(char *buf, size_t bufLen, uint32_t value) {
if (isEmpty()) {
// No format was specified; default to uppercase $hex
type = 'X';
@@ -175,12 +172,12 @@ void FormatSpec::printNumber(char *buf, size_t bufLen, uint32_t value)
}
}
char prefixChar = !prefix ? 0
: type == 'X' ? '$'
: type == 'x' ? '$'
: type == 'b' ? '%'
: type == 'o' ? '&'
: 0;
char prefixChar = !prefix ? 0
: type == 'X' ? '$'
: type == 'x' ? '$'
: type == 'b' ? '%'
: type == 'o' ? '&'
: 0;
char valueBuf[262]; // Max 5 digits + decimal + 255 fraction digits + terminator
@@ -215,15 +212,16 @@ void FormatSpec::printNumber(char *buf, size_t bufLen, uint32_t value)
cappedFracWidth = 255;
}
snprintf(valueBuf, sizeof(valueBuf), "%.*f", (int)cappedFracWidth,
value / fix_PrecisionFactor());
snprintf(
valueBuf, sizeof(valueBuf), "%.*f", (int)cappedFracWidth, value / fix_PrecisionFactor()
);
} else {
char const *spec = type == 'd' ? "%" PRId32
: type == 'u' ? "%" PRIu32
: type == 'X' ? "%" PRIX32
: type == 'x' ? "%" PRIx32
: type == 'o' ? "%" PRIo32
: "%" PRId32;
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);
}

View File

@@ -1,7 +1,7 @@
/* SPDX-License-Identifier: MIT */
#include <sys/stat.h>
#include <new>
#include <assert.h>
#include <errno.h>
#include <inttypes.h>
@@ -15,13 +15,14 @@
#include <variant>
#include <vector>
#include "error.hpp"
#include "platform.hpp" // S_ISDIR (stat macro)
#include "asm/fstack.hpp"
#include "asm/macro.hpp"
#include "asm/main.hpp"
#include "asm/symbol.hpp"
#include "asm/warning.hpp"
#include "error.hpp"
#include "platform.hpp" // S_ISDIR (stat macro)
struct Context {
FileStackNode *fileInfo;
@@ -39,7 +40,7 @@ static std::stack<Context> contextStack;
size_t maxRecursionDepth;
// The first include path for `fstk_FindFile` to try is none at all
static std::vector<std::string> includePaths = { "" };
static std::vector<std::string> includePaths = {""};
static const char *preIncludeName;
@@ -63,8 +64,7 @@ std::string const &FileStackNode::name() const {
return std::get<std::string>(data);
}
static const char *dumpNodeAndParents(FileStackNode const &node)
{
static const char *dumpNodeAndParents(FileStackNode const &node) {
char const *name;
if (node.type == NODE_REPT) {
@@ -73,7 +73,7 @@ static const char *dumpNodeAndParents(FileStackNode const &node)
name = dumpNodeAndParents(*node.parent);
fprintf(stderr, "(%" PRIu32 ") -> %s", node.lineNo, name);
for (uint32_t i = nodeIters.size(); i--; )
for (uint32_t i = nodeIters.size(); i--;)
fprintf(stderr, "::REPT~%" PRIu32, nodeIters[i]);
} else {
name = node.name().c_str();
@@ -87,14 +87,12 @@ static const char *dumpNodeAndParents(FileStackNode const &node)
return name;
}
void FileStackNode::dump(uint32_t curLineNo) const
{
void FileStackNode::dump(uint32_t curLineNo) const {
dumpNodeAndParents(*this);
fprintf(stderr, "(%" PRIu32 ")", curLineNo);
}
void fstk_DumpCurrent()
{
void fstk_DumpCurrent() {
if (contextStack.empty()) {
fputs("at top level", stderr);
return;
@@ -102,8 +100,7 @@ void fstk_DumpCurrent()
contextStack.top().fileInfo->dump(lexer_GetLineNo());
}
FileStackNode *fstk_GetFileStack()
{
FileStackNode *fstk_GetFileStack() {
if (contextStack.empty())
return nullptr;
@@ -117,8 +114,7 @@ FileStackNode *fstk_GetFileStack()
return topNode;
}
char const *fstk_GetFileName()
{
char const *fstk_GetFileName() {
// Iterating via the nodes themselves skips nested REPTs
FileStackNode const *node = contextStack.top().fileInfo;
@@ -127,8 +123,7 @@ char const *fstk_GetFileName()
return node->name().c_str();
}
void fstk_AddIncludePath(char const *path)
{
void fstk_AddIncludePath(char const *path) {
if (path[0] == '\0')
return;
@@ -138,8 +133,7 @@ void fstk_AddIncludePath(char const *path)
str += '/';
}
void fstk_SetPreIncludeFile(char const *path)
{
void fstk_SetPreIncludeFile(char const *path) {
if (preIncludeName)
warnx("Overriding pre-included filename %s", preIncludeName);
preIncludeName = path;
@@ -147,8 +141,7 @@ void fstk_SetPreIncludeFile(char const *path)
printf("Pre-included filename %s\n", preIncludeName);
}
static void printDep(char const *path)
{
static void printDep(char const *path) {
if (dependfile) {
fprintf(dependfile, "%s: %s\n", targetFileName.c_str(), path);
if (generatePhonyDeps)
@@ -156,8 +149,7 @@ static void printDep(char const *path)
}
}
static bool isPathValid(char const *path)
{
static bool isPathValid(char const *path) {
struct stat statbuf;
if (stat(path, &statbuf) != 0)
@@ -167,9 +159,8 @@ static bool isPathValid(char const *path)
return !S_ISDIR(statbuf.st_mode);
}
std::string *fstk_FindFile(char const *path)
{
std::string *fullPath = new(std::nothrow) std::string();
std::string *fstk_FindFile(char const *path) {
std::string *fullPath = new (std::nothrow) std::string();
if (!fullPath) {
error("Failed to allocate string during include path search: %s\n", strerror(errno));
@@ -189,20 +180,22 @@ std::string *fstk_FindFile(char const *path)
return nullptr;
}
bool yywrap()
{
bool yywrap() {
uint32_t ifDepth = lexer_GetIFDepth();
if (ifDepth != 0)
fatalerror("Ended block with %" PRIu32 " unterminated IF construct%s\n",
ifDepth, ifDepth == 1 ? "" : "s");
fatalerror(
"Ended block with %" PRIu32 " unterminated IF construct%s\n",
ifDepth,
ifDepth == 1 ? "" : "s"
);
if (Context &context = contextStack.top(); context.fileInfo->type == NODE_REPT) {
// The context is a REPT or FOR block, which may loop
// If the node is referenced, we can't edit it; duplicate it
if (context.fileInfo->referenced) {
context.fileInfo = new(std::nothrow) FileStackNode(*context.fileInfo);
context.fileInfo = new (std::nothrow) FileStackNode(*context.fileInfo);
if (!context.fileInfo)
fatalerror("Failed to duplicate REPT file node: %s\n", strerror(errno));
// Copy all info but the referencing
@@ -255,8 +248,7 @@ bool yywrap()
// Make sure not to switch the lexer state before calling this, so the saved line no is correct.
// BE CAREFUL! This modifies the file stack directly, you should have set up the file info first.
// Callers should set `contextStack.top().lexerState` after this so it is not `nullptr`.
static Context &newContext(FileStackNode &fileInfo)
{
static Context &newContext(FileStackNode &fileInfo) {
if (contextStack.size() > maxRecursionDepth)
fatalerror("Recursion limit (%zu) exceeded\n", maxRecursionDepth);
@@ -277,15 +269,13 @@ static Context &newContext(FileStackNode &fileInfo)
return context;
}
void fstk_RunInclude(char const *path)
{
void fstk_RunInclude(char const *path) {
std::string *fullPath = fstk_FindFile(path);
if (!fullPath) {
if (generatedMissingIncludes) {
if (verbose)
printf("Aborting (-MG) on INCLUDE file '%s' (%s)\n",
path, strerror(errno));
printf("Aborting (-MG) on INCLUDE file '%s' (%s)\n", path, strerror(errno));
failedOnMissingInclude = true;
} else {
error("Unable to open included file '%s': %s\n", path, strerror(errno));
@@ -293,7 +283,7 @@ void fstk_RunInclude(char const *path)
return;
}
FileStackNode *fileInfo = new(std::nothrow) FileStackNode();
FileStackNode *fileInfo = new (std::nothrow) FileStackNode();
if (!fileInfo) {
error("Failed to alloc file info for INCLUDE: %s\n", strerror(errno));
@@ -317,8 +307,7 @@ void fstk_RunInclude(char const *path)
// Similar to `fstk_RunInclude`, but not subject to `-MG`, and
// calling `lexer_SetState` instead of `lexer_SetStateAtEOL`.
static void runPreIncludeFile()
{
static void runPreIncludeFile() {
if (!preIncludeName)
return;
@@ -329,7 +318,7 @@ static void runPreIncludeFile()
return;
}
FileStackNode *fileInfo = new(std::nothrow) FileStackNode();
FileStackNode *fileInfo = new (std::nothrow) FileStackNode();
if (!fileInfo) {
error("Failed to alloc file info for pre-include: %s\n", strerror(errno));
@@ -348,8 +337,7 @@ static void runPreIncludeFile()
context.uniqueID = macro_UndefUniqueID();
}
void fstk_RunMacro(char const *macroName, MacroArgs &args)
{
void fstk_RunMacro(char const *macroName, MacroArgs &args) {
Symbol *macro = sym_FindExactSymbol(macroName);
if (!macro) {
@@ -362,7 +350,7 @@ void fstk_RunMacro(char const *macroName, MacroArgs &args)
}
contextStack.top().macroArgs = macro_GetCurrentArgs();
FileStackNode *fileInfo = new(std::nothrow) FileStackNode();
FileStackNode *fileInfo = new (std::nothrow) FileStackNode();
if (!fileInfo) {
error("Failed to alloc file info for \"%s\": %s\n", macro->name, strerror(errno));
@@ -383,12 +371,11 @@ void fstk_RunMacro(char const *macroName, MacroArgs &args)
if (macro->src->type == NODE_REPT) {
std::vector<uint32_t> const &srcIters = macro->src->iters();
for (uint32_t i = srcIters.size(); i--; ) {
for (uint32_t i = srcIters.size(); i--;) {
char buf[sizeof("::REPT~4294967295")]; // UINT32_MAX
if (sprintf(buf, "::REPT~%" PRIu32, srcIters[i]) < 0)
fatalerror("Failed to write macro invocation info: %s\n",
strerror(errno));
fatalerror("Failed to write macro invocation info: %s\n", strerror(errno));
fileInfoName.append(buf);
}
}
@@ -398,19 +385,19 @@ void fstk_RunMacro(char const *macroName, MacroArgs &args)
Context &context = newContext(*fileInfo);
std::string_view *macroView = macro->getMacro();
lexer_OpenFileView(context.lexerState, "MACRO", macroView->data(), macroView->size(),
macro->fileLine);
lexer_OpenFileView(
context.lexerState, "MACRO", macroView->data(), macroView->size(), macro->fileLine
);
lexer_SetStateAtEOL(&context.lexerState);
context.uniqueID = macro_UseNewUniqueID();
macro_UseNewArgs(&args);
}
static bool newReptContext(int32_t reptLineNo, char const *body, size_t size)
{
static bool newReptContext(int32_t reptLineNo, char const *body, size_t size) {
uint32_t reptDepth = contextStack.top().fileInfo->type == NODE_REPT
? contextStack.top().fileInfo->iters().size()
: 0;
FileStackNode *fileInfo = new(std::nothrow) FileStackNode();
? contextStack.top().fileInfo->iters().size()
: 0;
FileStackNode *fileInfo = new (std::nothrow) FileStackNode();
if (!fileInfo) {
error("Failed to alloc file info for REPT: %s\n", strerror(errno));
@@ -420,7 +407,9 @@ static bool newReptContext(int32_t reptLineNo, char const *body, size_t size)
fileInfo->data = std::vector<uint32_t>{1};
if (reptDepth) {
// Append all parent iter counts
fileInfo->iters().insert(fileInfo->iters().end(), RANGE(contextStack.top().fileInfo->iters()));
fileInfo->iters().insert(
fileInfo->iters().end(), RANGE(contextStack.top().fileInfo->iters())
);
}
Context &context = newContext(*fileInfo);
@@ -434,8 +423,7 @@ static bool newReptContext(int32_t reptLineNo, char const *body, size_t size)
return true;
}
void fstk_RunRept(uint32_t count, int32_t reptLineNo, char const *body, size_t size)
{
void fstk_RunRept(uint32_t count, int32_t reptLineNo, char const *body, size_t size) {
if (count == 0)
return;
if (!newReptContext(reptLineNo, body, size))
@@ -444,9 +432,15 @@ void fstk_RunRept(uint32_t count, int32_t reptLineNo, char const *body, size_t s
contextStack.top().nbReptIters = count;
}
void fstk_RunFor(char const *symName, int32_t start, int32_t stop, int32_t step,
int32_t reptLineNo, char const *body, size_t size)
{
void fstk_RunFor(
char const *symName,
int32_t start,
int32_t stop,
int32_t step,
int32_t reptLineNo,
char const *body,
size_t size
) {
Symbol *sym = sym_AddVar(symName, start);
if (sym->type != SYM_VAR)
@@ -462,8 +456,9 @@ void fstk_RunFor(char const *symName, int32_t start, int32_t stop, int32_t step,
error("FOR cannot have a step value of 0\n");
if ((step > 0 && start > stop) || (step < 0 && start < stop))
warning(WARNING_BACKWARDS_FOR, "FOR goes backwards from %d to %d by %d\n",
start, stop, step);
warning(
WARNING_BACKWARDS_FOR, "FOR goes backwards from %d to %d by %d\n", start, stop, step
);
if (count == 0)
return;
@@ -479,14 +474,12 @@ void fstk_RunFor(char const *symName, int32_t start, int32_t stop, int32_t step,
context.forName = symName;
}
void fstk_StopRept()
{
void fstk_StopRept() {
// Prevent more iterations
contextStack.top().nbReptIters = 0;
}
bool fstk_Break()
{
bool fstk_Break() {
if (contextStack.top().fileInfo->type != NODE_REPT) {
error("BREAK can only be used inside a REPT/FOR block\n");
return false;
@@ -496,22 +489,20 @@ bool fstk_Break()
return true;
}
void fstk_NewRecursionDepth(size_t newDepth)
{
void fstk_NewRecursionDepth(size_t newDepth) {
if (contextStack.size() > newDepth + 1)
fatalerror("Recursion limit (%zu) exceeded\n", newDepth);
maxRecursionDepth = newDepth;
}
void fstk_Init(char const *mainPath, size_t maxDepth)
{
void fstk_Init(char const *mainPath, size_t maxDepth) {
Context &context = contextStack.emplace();
if (!lexer_OpenFile(context.lexerState, mainPath))
fatalerror("Failed to open main file\n");
lexer_SetState(&context.lexerState);
FileStackNode *fileInfo = new(std::nothrow) FileStackNode();
FileStackNode *fileInfo = new (std::nothrow) FileStackNode();
if (!fileInfo)
fatalerror("Failed to allocate memory for main file info: %s\n", strerror(errno));

File diff suppressed because it is too large Load Diff

View File

@@ -1,14 +1,15 @@
/* SPDX-License-Identifier: MIT */
#include "asm/macro.hpp"
#include <errno.h>
#include <new>
#include <inttypes.h>
#include <new>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <vector>
#include "asm/macro.hpp"
#include "asm/warning.hpp"
#define MAXMACROARGS 99999
@@ -19,8 +20,7 @@ static uint32_t maxUniqueID = 0;
static char uniqueIDBuf[sizeof("_u4294967295")] = {}; // UINT32_MAX
static char *uniqueIDPtr = nullptr;
void MacroArgs::append(std::string s)
{
void MacroArgs::append(std::string s) {
if (s.empty())
warning(WARNING_EMPTY_MACRO_ARG, "Empty macro argument\n");
if (args.size() == MAXMACROARGS)
@@ -28,18 +28,15 @@ void MacroArgs::append(std::string s)
args.push_back(s);
}
MacroArgs *macro_GetCurrentArgs()
{
MacroArgs *macro_GetCurrentArgs() {
return macroArgs;
}
void macro_UseNewArgs(MacroArgs *args)
{
void macro_UseNewArgs(MacroArgs *args) {
macroArgs = args;
}
char const *macro_GetArg(uint32_t i)
{
char const *macro_GetArg(uint32_t i) {
if (!macroArgs)
return nullptr;
@@ -48,8 +45,7 @@ char const *macro_GetArg(uint32_t i)
return realIndex >= macroArgs->args.size() ? nullptr : macroArgs->args[realIndex].c_str();
}
char const *macro_GetAllArgs()
{
char const *macro_GetAllArgs() {
if (!macroArgs)
return nullptr;
@@ -85,13 +81,11 @@ char const *macro_GetAllArgs()
return str;
}
uint32_t macro_GetUniqueID()
{
uint32_t macro_GetUniqueID() {
return uniqueID;
}
char const *macro_GetUniqueIDStr()
{
char const *macro_GetUniqueIDStr() {
// Generate a new unique ID on the first use of `\@`
if (uniqueID == 0)
macro_SetUniqueID(++maxUniqueID);
@@ -99,8 +93,7 @@ char const *macro_GetUniqueIDStr()
return uniqueIDPtr;
}
void macro_SetUniqueID(uint32_t id)
{
void macro_SetUniqueID(uint32_t id) {
uniqueID = id;
if (id == 0 || id == (uint32_t)-1) {
uniqueIDPtr = nullptr;
@@ -112,26 +105,23 @@ void macro_SetUniqueID(uint32_t id)
}
}
uint32_t macro_UseNewUniqueID()
{
uint32_t macro_UseNewUniqueID() {
// A new ID will be generated on the first use of `\@`
macro_SetUniqueID(0);
return uniqueID;
}
uint32_t macro_UndefUniqueID()
{
uint32_t macro_UndefUniqueID() {
// No ID will be generated; use of `\@` is an error
macro_SetUniqueID((uint32_t)-1);
return uniqueID;
}
void macro_ShiftCurrentArgs(int32_t count)
{
void macro_ShiftCurrentArgs(int32_t count) {
if (!macroArgs) {
error("Cannot shift macro arguments outside of a macro\n");
} else if (size_t nbArgs = macroArgs->args.size();
count > 0 && ((uint32_t)count > nbArgs || macroArgs->shift > nbArgs - count)) {
count > 0 && ((uint32_t)count > nbArgs || macroArgs->shift > nbArgs - count)) {
warning(WARNING_MACRO_SHIFT, "Cannot shift macro arguments past their end\n");
macroArgs->shift = nbArgs;
} else if (count < 0 && macroArgs->shift < (uint32_t)-count) {
@@ -142,7 +132,6 @@ void macro_ShiftCurrentArgs(int32_t count)
}
}
uint32_t macro_NbArgs()
{
uint32_t macro_NbArgs() {
return macroArgs->args.size() - macroArgs->shift;
}

View File

@@ -1,5 +1,7 @@
/* SPDX-License-Identifier: MIT */
#include "asm/main.hpp"
#include <ctype.h>
#include <errno.h>
#include <float.h>
@@ -7,43 +9,43 @@
#include <limits.h>
#include <math.h>
#include <stdarg.h>
#include <stdio.h>
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <string>
#include <string.h>
#include <string>
#include <time.h>
#include "error.hpp"
#include "extern/getopt.hpp"
#include "helpers.hpp"
#include "parser.hpp"
#include "version.hpp"
#include "asm/charmap.hpp"
#include "asm/fixpoint.hpp"
#include "asm/format.hpp"
#include "asm/fstack.hpp"
#include "asm/lexer.hpp"
#include "asm/main.hpp"
#include "asm/opt.hpp"
#include "asm/output.hpp"
#include "asm/rpn.hpp"
#include "asm/symbol.hpp"
#include "asm/warning.hpp"
#include "parser.hpp"
#include "extern/getopt.hpp"
#include "helpers.hpp"
#include "error.hpp"
#include "version.hpp"
#ifdef __clang__
#if __has_feature(address_sanitizer) && !defined(__SANITIZE_ADDRESS__)
#define __SANITIZE_ADDRESS__
#endif // __has_feature(address_sanitizer) && !defined(__SANITIZE_ADDRESS__)
#endif // __clang__
#if __has_feature(address_sanitizer) && !defined(__SANITIZE_ADDRESS__)
#define __SANITIZE_ADDRESS__
#endif // __has_feature(address_sanitizer) && !defined(__SANITIZE_ADDRESS__)
#endif // __clang__
#ifdef __SANITIZE_ADDRESS__
// There are known, non-trivial to fix leaks. We would still like to have `make develop'
// detect memory corruption, though.
extern "C" {
char const *__asan_default_options() { return "detect_leaks=0"; }
char const *__asan_default_options() {
return "detect_leaks=0";
}
}
#endif
@@ -65,8 +67,7 @@ bool verbose;
bool warnings; // True to enable warnings, false to disable them.
// Escapes Make-special chars from a string
static std::string make_escape(std::string &str)
{
static std::string make_escape(std::string &str) {
std::string escaped;
size_t pos = 0;
@@ -98,54 +99,53 @@ static int depType; // Variants of `-M`
// This is because long opt matching, even to a single char, is prioritized
// over short opt matching
static option const longopts[] = {
{ "binary-digits", required_argument, nullptr, 'b' },
{ "define", required_argument, nullptr, 'D' },
{ "export-all", no_argument, nullptr, 'E' },
{ "gfx-chars", required_argument, nullptr, 'g' },
{ "nop-after-halt", no_argument, nullptr, 'H' },
{ "halt-without-nop", no_argument, nullptr, 'h' },
{ "include", required_argument, nullptr, 'I' },
{ "preserve-ld", no_argument, nullptr, 'L' },
{ "auto-ldh", no_argument, nullptr, 'l' },
{ "dependfile", required_argument, nullptr, 'M' },
{ "MG", no_argument, &depType, 'G' },
{ "MP", no_argument, &depType, 'P' },
{ "MT", required_argument, &depType, 'T' },
{ "warning", required_argument, nullptr, 'W' },
{ "MQ", required_argument, &depType, 'Q' },
{ "output", required_argument, nullptr, 'o' },
{ "preinclude", required_argument, nullptr, 'P' },
{ "pad-value", required_argument, nullptr, 'p' },
{ "q-precision", required_argument, nullptr, 'Q' },
{ "recursion-depth", required_argument, nullptr, 'r' },
{ "version", no_argument, nullptr, 'V' },
{ "verbose", no_argument, nullptr, 'v' },
{ "warning", required_argument, nullptr, 'W' },
{ "max-errors", required_argument, nullptr, 'X' },
{ nullptr, no_argument, nullptr, 0 }
{"binary-digits", required_argument, nullptr, 'b'},
{"define", required_argument, nullptr, 'D'},
{"export-all", no_argument, nullptr, 'E'},
{"gfx-chars", required_argument, nullptr, 'g'},
{"nop-after-halt", no_argument, nullptr, 'H'},
{"halt-without-nop", no_argument, nullptr, 'h'},
{"include", required_argument, nullptr, 'I'},
{"preserve-ld", no_argument, nullptr, 'L'},
{"auto-ldh", no_argument, nullptr, 'l'},
{"dependfile", required_argument, nullptr, 'M'},
{"MG", no_argument, &depType, 'G'},
{"MP", no_argument, &depType, 'P'},
{"MT", required_argument, &depType, 'T'},
{"warning", required_argument, nullptr, 'W'},
{"MQ", required_argument, &depType, 'Q'},
{"output", required_argument, nullptr, 'o'},
{"preinclude", required_argument, nullptr, 'P'},
{"pad-value", required_argument, nullptr, 'p'},
{"q-precision", required_argument, nullptr, 'Q'},
{"recursion-depth", required_argument, nullptr, 'r'},
{"version", no_argument, nullptr, 'V'},
{"verbose", no_argument, nullptr, 'v'},
{"warning", required_argument, nullptr, 'W'},
{"max-errors", required_argument, nullptr, 'X'},
{nullptr, no_argument, nullptr, 0 }
};
static void printUsage()
{
static void printUsage() {
fputs(
"Usage: rgbasm [-EHhLlVvw] [-b chars] [-D name[=value]] [-g chars] [-I path]\n"
" [-M depend_file] [-MG] [-MP] [-MT target_file] [-MQ target_file]\n"
" [-o out_file] [-P include_file] [-p pad_value] [-Q precision]\n"
" [-r depth] [-W warning] [-X max_errors] <file>\n"
"Useful options:\n"
" -E, --export-all export all labels\n"
" -M, --dependfile <path> set the output dependency file\n"
" -o, --output <path> set the output object file\n"
" -p, --pad-value <value> set the value to use for `ds'\n"
" -V, --version print RGBASM version and exit\n"
" -W, --warning <warning> enable or disable warnings\n"
"\n"
"For help, use `man rgbasm' or go to https://rgbds.gbdev.io/docs/\n",
stderr);
"Usage: rgbasm [-EHhLlVvw] [-b chars] [-D name[=value]] [-g chars] [-I path]\n"
" [-M depend_file] [-MG] [-MP] [-MT target_file] [-MQ target_file]\n"
" [-o out_file] [-P include_file] [-p pad_value] [-Q precision]\n"
" [-r depth] [-W warning] [-X max_errors] <file>\n"
"Useful options:\n"
" -E, --export-all export all labels\n"
" -M, --dependfile <path> set the output dependency file\n"
" -o, --output <path> set the output object file\n"
" -p, --pad-value <value> set the value to use for `ds'\n"
" -V, --version print RGBASM version and exit\n"
" -W, --warning <warning> enable or disable warnings\n"
"\n"
"For help, use `man rgbasm' or go to https://rgbds.gbdev.io/docs/\n",
stderr
);
}
int main(int argc, char *argv[])
{
int main(int argc, char *argv[]) {
time_t now = time(nullptr);
char const *sourceDateEpoch = getenv("SOURCE_DATE_EPOCH");
@@ -213,8 +213,9 @@ int main(int argc, char *argv[])
case 'H':
if (warnOnHaltNop)
warning(WARNING_OBSOLETE,
"Automatic `nop` after `halt` (the `-H` flag) is deprecated\n");
warning(
WARNING_OBSOLETE, "Automatic `nop` after `halt` (the `-H` flag) is deprecated\n"
);
else
errx("`-H` and `-h` don't make sense together");
haltNop = true;
@@ -240,8 +241,10 @@ int main(int argc, char *argv[])
break;
case 'l':
if (warnOnLdOpt)
warning(WARNING_OBSOLETE,
"Automatic `ld` to `ldh` optimization (the `-l` flag) is deprecated\n");
warning(
WARNING_OBSOLETE,
"Automatic `ld` to `ldh` optimization (the `-l` flag) is deprecated\n"
);
else
errx("`-L` and `-l` don't make sense together");
optimizeLoads = true;
@@ -371,7 +374,9 @@ int main(int argc, char *argv[])
targetFileName = objectName;
if (argc == musl_optind) {
fputs("FATAL: Please specify an input file (pass `-` to read from standard input)\n", stderr);
fputs(
"FATAL: Please specify an input file (pass `-` to read from standard input)\n", stderr
);
printUsage();
exit(1);
} else if (argc != musl_optind + 1) {
@@ -387,7 +392,8 @@ int main(int argc, char *argv[])
if (dependfile) {
if (targetFileName.empty())
errx("Dependency files can only be created if a target file is specified with either -o, -MQ or -MT");
errx("Dependency files can only be created if a target file is specified with either "
"-o, -MQ or -MT");
fprintf(dependfile, "%s: %s\n", targetFileName.c_str(), mainFileName);
}

View File

@@ -33,59 +33,48 @@ struct OptStackEntry {
static std::stack<OptStackEntry> stack;
void opt_B(char const chars[2])
{
void opt_B(char const chars[2]) {
lexer_SetBinDigits(chars);
}
void opt_G(char const chars[4])
{
void opt_G(char const chars[4]) {
lexer_SetGfxDigits(chars);
}
void opt_P(uint8_t padByte)
{
void opt_P(uint8_t padByte) {
fillByte = padByte;
}
void opt_Q(uint8_t precision)
{
void opt_Q(uint8_t precision) {
fixPrecision = precision;
}
void opt_R(size_t newDepth)
{
void opt_R(size_t newDepth) {
fstk_NewRecursionDepth(newDepth);
lexer_CheckRecursionDepth();
}
void opt_H(bool warn)
{
void opt_H(bool warn) {
warnOnHaltNop = warn;
}
void opt_h(bool halt)
{
void opt_h(bool halt) {
haltNop = halt;
}
void opt_L(bool optimize)
{
void opt_L(bool optimize) {
optimizeLoads = optimize;
}
void opt_l(bool warn)
{
void opt_l(bool warn) {
warnOnLdOpt = warn;
}
void opt_W(char *flag)
{
void opt_W(char *flag) {
processWarningFlag(flag);
}
void opt_Parse(char *s)
{
void opt_Parse(char *s) {
switch (s[0]) {
case 'b':
if (strlen(&s[1]) == 2)
@@ -239,8 +228,7 @@ void opt_Parse(char *s)
}
}
void opt_Push()
{
void opt_Push() {
OptStackEntry entry;
// Both of these are pulled from lexer.hpp
@@ -273,8 +261,7 @@ void opt_Push()
stack.push(entry);
}
void opt_Pop()
{
void opt_Pop() {
if (stack.empty()) {
error("No entries in the option stack\n");
return;

View File

@@ -2,30 +2,31 @@
// Outputs an objectfile
#include "asm/output.hpp"
#include <algorithm>
#include <assert.h>
#include <deque>
#include <errno.h>
#include <inttypes.h>
#include <stdio.h>
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <string>
#include <string.h>
#include <string>
#include <vector>
#include "error.hpp"
#include "linkdefs.hpp"
#include "asm/charmap.hpp"
#include "asm/fstack.hpp"
#include "asm/main.hpp"
#include "asm/output.hpp"
#include "asm/rpn.hpp"
#include "asm/section.hpp"
#include "asm/symbol.hpp"
#include "asm/warning.hpp"
#include "error.hpp"
#include "linkdefs.hpp"
struct Assertion {
Patch patch;
Section *section;
@@ -42,8 +43,7 @@ static std::deque<Assertion> assertions;
static std::deque<FileStackNode *> fileStackNodes;
// Write a long to a file (little-endian)
static void putlong(uint32_t i, FILE *f)
{
static void putlong(uint32_t i, FILE *f) {
putc(i, f);
putc(i >> 8, f);
putc(i >> 16, f);
@@ -51,15 +51,13 @@ static void putlong(uint32_t i, FILE *f)
}
// Write a NUL-terminated string to a file
static void putstring(char const *s, FILE *f)
{
static void putstring(char const *s, FILE *f) {
while (*s)
putc(*s++, f);
putc(0, f);
}
void out_RegisterNode(FileStackNode *node)
{
void out_RegisterNode(FileStackNode *node) {
// If node is not already registered, register it (and parents), and give it a unique ID
for (; node && node->ID == (uint32_t)-1; node = node->parent) {
node->ID = fileStackNodes.size();
@@ -67,8 +65,7 @@ void out_RegisterNode(FileStackNode *node)
}
}
void out_ReplaceNode(FileStackNode * /* node */)
{
void out_ReplaceNode(FileStackNode * /* node */) {
#if 0
This is code intended to replace a node, which is pretty useless until ref counting is added...
@@ -84,8 +81,7 @@ This is code intended to replace a node, which is pretty useless until ref count
}
// Return a section's ID, or -1 if the section is not in the list
static uint32_t getSectIDIfAny(Section *sect)
{
static uint32_t getSectIDIfAny(Section *sect) {
if (!sect)
return (uint32_t)-1;
@@ -98,8 +94,7 @@ static uint32_t getSectIDIfAny(Section *sect)
}
// Write a patch to a file
static void writepatch(Patch const &patch, FILE *f)
{
static void writepatch(Patch const &patch, FILE *f) {
assert(patch.src->ID != (uint32_t)-1);
putlong(patch.src->ID, f);
putlong(patch.lineNo, f);
@@ -112,8 +107,7 @@ static void writepatch(Patch const &patch, FILE *f)
}
// Write a section to a file
static void writesection(Section const &sect, FILE *f)
{
static void writesection(Section const &sect, FILE *f) {
putstring(sect.name.c_str(), f);
putlong(sect.size, f);
@@ -138,8 +132,7 @@ static void writesection(Section const &sect, FILE *f)
}
// Write a symbol to a file
static void writesymbol(Symbol const &sym, FILE *f)
{
static void writesymbol(Symbol const &sym, FILE *f) {
putstring(sym.name, f);
if (!sym.isDefined()) {
putc(SYMTYPE_IMPORT, f);
@@ -154,8 +147,7 @@ static void writesymbol(Symbol const &sym, FILE *f)
}
}
static void registerSymbol(Symbol &sym)
{
static void registerSymbol(Symbol &sym) {
sym.ID = objectSymbols.size();
objectSymbols.push_back(&sym);
out_RegisterNode(sym.src);
@@ -163,19 +155,17 @@ static void registerSymbol(Symbol &sym)
// Returns a symbol's ID within the object file
// If the symbol does not have one, one is assigned by registering the symbol
static uint32_t getSymbolID(Symbol &sym)
{
static uint32_t getSymbolID(Symbol &sym) {
if (sym.ID == (uint32_t)-1 && !sym_IsPC(&sym))
registerSymbol(sym);
return sym.ID;
}
static void writerpn(std::vector<uint8_t> &rpnexpr, const std::vector<uint8_t> &rpn)
{
static void writerpn(std::vector<uint8_t> &rpnexpr, const std::vector<uint8_t> &rpn) {
char symName[512];
size_t rpnptr = 0;
for (size_t offset = 0; offset < rpn.size(); ) {
for (size_t offset = 0; offset < rpn.size();) {
uint8_t rpndata = rpn[offset++];
switch (rpndata) {
@@ -262,8 +252,7 @@ static void writerpn(std::vector<uint8_t> &rpnexpr, const std::vector<uint8_t> &
}
}
static void initpatch(Patch &patch, uint32_t type, Expression const &expr, uint32_t ofs)
{
static void initpatch(Patch &patch, uint32_t type, Expression const &expr, uint32_t ofs) {
FileStackNode *node = fstk_GetFileStack();
patch.type = type;
@@ -290,8 +279,7 @@ static void initpatch(Patch &patch, uint32_t type, Expression const &expr, uint3
}
// Create a new patch (includes the rpn expr)
void out_CreatePatch(uint32_t type, Expression const &expr, uint32_t ofs, uint32_t pcShift)
{
void out_CreatePatch(uint32_t type, Expression const &expr, uint32_t ofs, uint32_t pcShift) {
// Add the patch to the list
Patch &patch = currentSection->patches.emplace_front();
@@ -304,22 +292,21 @@ void out_CreatePatch(uint32_t type, Expression const &expr, uint32_t ofs, uint32
}
// Creates an assert that will be written to the object file
void out_CreateAssert(enum AssertionType type, Expression const &expr, char const *message, uint32_t ofs)
{
void out_CreateAssert(
enum AssertionType type, Expression const &expr, char const *message, uint32_t ofs
) {
Assertion &assertion = assertions.emplace_front();
initpatch(assertion.patch, type, expr, ofs);
assertion.message = message;
}
static void writeassert(Assertion &assert, FILE *f)
{
static void writeassert(Assertion &assert, FILE *f) {
writepatch(assert.patch, f);
putstring(assert.message.c_str(), f);
}
static void writeFileStackNode(FileStackNode const &node, FILE *f)
{
static void writeFileStackNode(FileStackNode const &node, FILE *f) {
putlong(node.parent ? node.parent->ID : (uint32_t)-1, f);
putlong(node.lineNo, f);
putc(node.type, f);
@@ -330,13 +317,12 @@ static void writeFileStackNode(FileStackNode const &node, FILE *f)
putlong(nodeIters.size(), f);
// Iters are stored by decreasing depth, so reverse the order for output
for (uint32_t i = nodeIters.size(); i--; )
for (uint32_t i = nodeIters.size(); i--;)
putlong(nodeIters[i], f);
}
}
static void registerUnregisteredSymbol(Symbol &sym)
{
static void registerUnregisteredSymbol(Symbol &sym) {
// Check for symbol->src, to skip any built-in symbol from rgbasm
if (sym.src && sym.ID == (uint32_t)-1) {
registerSymbol(sym);
@@ -344,8 +330,7 @@ static void registerUnregisteredSymbol(Symbol &sym)
}
// Write an objectfile
void out_WriteObject()
{
void out_WriteObject() {
FILE *f;
if (strcmp(objectName, "-")) {
@@ -374,9 +359,12 @@ void out_WriteObject()
// The list is supposed to have decrementing IDs
if (it + 1 != fileStackNodes.end() && it[1]->ID != node->ID - 1)
fatalerror("Internal error: fstack node #%" PRIu32 " follows #%" PRIu32
". Please report this to the developers!\n",
it[1]->ID, node->ID);
fatalerror(
"Internal error: fstack node #%" PRIu32 " follows #%" PRIu32
". Please report this to the developers!\n",
it[1]->ID,
node->ID
);
}
for (Symbol const *sym : objectSymbols)
@@ -394,8 +382,7 @@ void out_WriteObject()
}
// Set the objectfilename
void out_SetFileName(char *s)
{
void out_SetFileName(char *s) {
if (objectName)
warnx("Overriding output filename %s", objectName);
objectName = s;

File diff suppressed because it is too large Load Diff

View File

@@ -2,6 +2,8 @@
// Controls RPN expressions for objectfiles
#include "asm/rpn.hpp"
#include <assert.h>
#include <errno.h>
#include <inttypes.h>
@@ -12,18 +14,16 @@
#include <string.h>
#include <vector>
#include "opmath.hpp"
#include "asm/main.hpp"
#include "asm/output.hpp"
#include "asm/rpn.hpp"
#include "asm/section.hpp"
#include "asm/symbol.hpp"
#include "asm/warning.hpp"
#include "opmath.hpp"
// Init a RPN expression
static void initExpression(Expression &expr)
{
static void initExpression(Expression &expr) {
expr.reason = nullptr;
expr.isKnown = true;
expr.isSymbol = false;
@@ -33,8 +33,7 @@ static void initExpression(Expression &expr)
// Makes an expression "not known", also setting its error message
template<typename... Ts>
static void makeUnknown(Expression &expr, Ts ...parts)
{
static void makeUnknown(Expression &expr, Ts... parts) {
expr.isKnown = false;
expr.reason = new std::string();
if (!expr.reason)
@@ -42,10 +41,9 @@ static void makeUnknown(Expression &expr, Ts ...parts)
(expr.reason->append(parts), ...);
}
static uint8_t *reserveSpace(Expression &expr, uint32_t size)
{
static uint8_t *reserveSpace(Expression &expr, uint32_t size) {
if (!expr.rpn) {
expr.rpn = new(std::nothrow) std::vector<uint8_t>();
expr.rpn = new (std::nothrow) std::vector<uint8_t>();
if (!expr.rpn)
fatalerror("Failed to allocate RPN expression: %s\n", strerror(errno));
}
@@ -57,22 +55,19 @@ static uint8_t *reserveSpace(Expression &expr, uint32_t size)
}
// Free the RPN expression
void rpn_Free(Expression &expr)
{
void rpn_Free(Expression &expr) {
delete expr.rpn;
delete expr.reason;
initExpression(expr);
}
// Add symbols, constants and operators to expression
void rpn_Number(Expression &expr, uint32_t val)
{
void rpn_Number(Expression &expr, uint32_t val) {
initExpression(expr);
expr.val = val;
}
void rpn_Symbol(Expression &expr, char const *symName)
{
void rpn_Symbol(Expression &expr, char const *symName) {
Symbol *sym = sym_FindScopedSymbol(symName);
if (sym_IsPC(sym) && !sect_GetSymbolSection()) {
@@ -98,8 +93,7 @@ void rpn_Symbol(Expression &expr, char const *symName)
}
}
static void bankSelf(Expression &expr)
{
static void bankSelf(Expression &expr) {
initExpression(expr);
if (!currentSection) {
@@ -114,8 +108,7 @@ static void bankSelf(Expression &expr)
}
}
void rpn_BankSymbol(Expression &expr, char const *symName)
{
void rpn_BankSymbol(Expression &expr, char const *symName) {
Symbol const *sym = sym_FindScopedSymbol(symName);
// The @ symbol is treated differently.
@@ -147,8 +140,7 @@ void rpn_BankSymbol(Expression &expr, char const *symName)
}
}
void rpn_BankSection(Expression &expr, char const *sectionName)
{
void rpn_BankSection(Expression &expr, char const *sectionName) {
initExpression(expr);
Section *section = sect_FindSectionByName(sectionName);
@@ -167,8 +159,7 @@ void rpn_BankSection(Expression &expr, char const *sectionName)
}
}
void rpn_SizeOfSection(Expression &expr, char const *sectionName)
{
void rpn_SizeOfSection(Expression &expr, char const *sectionName) {
initExpression(expr);
Section *section = sect_FindSectionByName(sectionName);
@@ -187,8 +178,7 @@ void rpn_SizeOfSection(Expression &expr, char const *sectionName)
}
}
void rpn_StartOfSection(Expression &expr, char const *sectionName)
{
void rpn_StartOfSection(Expression &expr, char const *sectionName) {
initExpression(expr);
Section *section = sect_FindSectionByName(sectionName);
@@ -207,8 +197,7 @@ void rpn_StartOfSection(Expression &expr, char const *sectionName)
}
}
void rpn_SizeOfSectionType(Expression &expr, enum SectionType type)
{
void rpn_SizeOfSectionType(Expression &expr, enum SectionType type) {
initExpression(expr);
makeUnknown(expr, "Section type's size is not known");
@@ -219,8 +208,7 @@ void rpn_SizeOfSectionType(Expression &expr, enum SectionType type)
*ptr++ = type;
}
void rpn_StartOfSectionType(Expression &expr, enum SectionType type)
{
void rpn_StartOfSectionType(Expression &expr, enum SectionType type) {
initExpression(expr);
makeUnknown(expr, "Section type's start is not known");
@@ -231,8 +219,7 @@ void rpn_StartOfSectionType(Expression &expr, enum SectionType type)
*ptr++ = type;
}
void rpn_CheckHRAM(Expression &expr, const Expression &src)
{
void rpn_CheckHRAM(Expression &expr, const Expression &src) {
expr = src;
expr.isSymbol = false;
@@ -247,8 +234,7 @@ void rpn_CheckHRAM(Expression &expr, const Expression &src)
}
}
void rpn_CheckRST(Expression &expr, const Expression &src)
{
void rpn_CheckRST(Expression &expr, const Expression &src) {
expr = src;
if (expr.isKnown) {
@@ -264,9 +250,8 @@ void rpn_CheckRST(Expression &expr, const Expression &src)
}
// Checks that an RPN expression's value fits within N bits (signed or unsigned)
void rpn_CheckNBit(Expression const &expr, uint8_t n)
{
assert(n != 0); // That doesn't make sense
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 (expr.isKnown) {
@@ -279,8 +264,7 @@ void rpn_CheckNBit(Expression const &expr, uint8_t n)
}
}
int32_t Expression::getConstVal() const
{
int32_t Expression::getConstVal() const {
if (!isKnown) {
error("Expected constant expression: %s\n", reason->c_str());
return 0;
@@ -288,8 +272,7 @@ int32_t Expression::getConstVal() const
return val;
}
void rpn_LOGNOT(Expression &expr, const Expression &src)
{
void rpn_LOGNOT(Expression &expr, const Expression &src) {
expr = src;
expr.isSymbol = false;
@@ -301,15 +284,13 @@ void rpn_LOGNOT(Expression &expr, const Expression &src)
}
}
Symbol const *Expression::symbolOf() const
{
Symbol const *Expression::symbolOf() const {
if (!isSymbol)
return nullptr;
return sym_FindScopedSymbol((char const *)&(*rpn)[1]);
}
bool Expression::isDiffConstant(Symbol const *sym) const
{
bool Expression::isDiffConstant(Symbol const *sym) const {
// Check if both expressions only refer to a single symbol
Symbol const *sym1 = symbolOf();
@@ -328,8 +309,7 @@ bool Expression::isDiffConstant(Symbol const *sym) const
*
* @return The constant result if it can be computed, or -1 otherwise.
*/
static int32_t tryConstMask(Expression const &lhs, Expression const &rhs)
{
static int32_t tryConstMask(Expression const &lhs, Expression const &rhs) {
Symbol const *lhsSymbol = lhs.symbolOf();
Symbol const *rhsSymbol = lhsSymbol ? nullptr : rhs.symbolOf();
bool lhsIsSymbol = lhsSymbol && lhsSymbol->getSection();
@@ -362,8 +342,9 @@ static int32_t tryConstMask(Expression const &lhs, Expression const &rhs)
return (symbolOfs + sect.alignOfs) & ~unknownBits;
}
void rpn_BinaryOp(enum RPNCommand op, Expression &expr, const Expression &src1, const Expression &src2)
{
void rpn_BinaryOp(
enum RPNCommand op, Expression &expr, const Expression &src1, const Expression &src2
) {
expr.isSymbol = false;
int32_t constMaskVal;
@@ -417,43 +398,47 @@ void rpn_BinaryOp(enum RPNCommand op, Expression &expr, const Expression &src1,
break;
case RPN_SHL:
if (src2.val < 0)
warning(WARNING_SHIFT_AMOUNT,
"Shifting left by negative amount %" PRId32 "\n",
src2.val);
warning(
WARNING_SHIFT_AMOUNT, "Shifting left by negative amount %" PRId32 "\n", src2.val
);
if (src2.val >= 32)
warning(WARNING_SHIFT_AMOUNT,
"Shifting left by large amount %" PRId32 "\n", src2.val);
warning(
WARNING_SHIFT_AMOUNT, "Shifting left by large amount %" PRId32 "\n", src2.val
);
expr.val = op_shift_left(src1.val, src2.val);
break;
case RPN_SHR:
if (src1.val < 0)
warning(WARNING_SHIFT,
"Shifting right negative value %" PRId32 "\n", src1.val);
warning(WARNING_SHIFT, "Shifting right negative value %" PRId32 "\n", src1.val);
if (src2.val < 0)
warning(WARNING_SHIFT_AMOUNT,
"Shifting right by negative amount %" PRId32 "\n",
src2.val);
warning(
WARNING_SHIFT_AMOUNT,
"Shifting right by negative amount %" PRId32 "\n",
src2.val
);
if (src2.val >= 32)
warning(WARNING_SHIFT_AMOUNT,
"Shifting right by large amount %" PRId32 "\n",
src2.val);
warning(
WARNING_SHIFT_AMOUNT, "Shifting right by large amount %" PRId32 "\n", src2.val
);
expr.val = op_shift_right(src1.val, src2.val);
break;
case RPN_USHR:
if (src2.val < 0)
warning(WARNING_SHIFT_AMOUNT,
"Shifting right by negative amount %" PRId32 "\n",
src2.val);
warning(
WARNING_SHIFT_AMOUNT,
"Shifting right by negative amount %" PRId32 "\n",
src2.val
);
if (src2.val >= 32)
warning(WARNING_SHIFT_AMOUNT,
"Shifting right by large amount %" PRId32 "\n",
src2.val);
warning(
WARNING_SHIFT_AMOUNT, "Shifting right by large amount %" PRId32 "\n", src2.val
);
expr.val = op_shift_right_unsigned(src1.val, src2.val);
break;
@@ -465,9 +450,12 @@ void rpn_BinaryOp(enum RPNCommand op, Expression &expr, const Expression &src1,
fatalerror("Division by zero\n");
if (src1.val == INT32_MIN && src2.val == -1) {
warning(WARNING_DIV,
"Division of %" PRId32 " by -1 yields %" PRId32 "\n",
INT32_MIN, INT32_MIN);
warning(
WARNING_DIV,
"Division of %" PRId32 " by -1 yields %" PRId32 "\n",
INT32_MIN,
INT32_MIN
);
expr.val = INT32_MIN;
} else {
expr.val = op_divide(src1.val, src2.val);
@@ -521,8 +509,13 @@ void rpn_BinaryOp(enum RPNCommand op, Expression &expr, const Expression &src1,
// Convert the left-hand expression if it's constant
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)};
uint8_t bytes[] = {
RPN_CONST,
(uint8_t)lval,
(uint8_t)(lval >> 8),
(uint8_t)(lval >> 16),
(uint8_t)(lval >> 24),
};
expr.rpnPatchSize = sizeof(bytes);
expr.rpn = nullptr;
memcpy(reserveSpace(expr, sizeof(bytes)), bytes, sizeof(bytes));
@@ -545,8 +538,13 @@ void rpn_BinaryOp(enum RPNCommand op, Expression &expr, const Expression &src1,
// If the right expression is constant, merge a shim instead
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)};
uint8_t bytes[] = {
RPN_CONST,
(uint8_t)rval,
(uint8_t)(rval >> 8),
(uint8_t)(rval >> 16),
(uint8_t)(rval >> 24),
};
if (src2.isKnown) {
ptr = bytes;
len = sizeof(bytes);
@@ -569,23 +567,20 @@ void rpn_BinaryOp(enum RPNCommand op, Expression &expr, const Expression &src1,
}
}
void rpn_HIGH(Expression &expr, const Expression &src)
{
void rpn_HIGH(Expression &expr, const Expression &src) {
expr = src;
expr.isSymbol = false;
if (expr.isKnown) {
expr.val = (uint32_t)expr.val >> 8 & 0xFF;
} else {
uint8_t bytes[] = {RPN_CONST, 8, 0, 0, 0, RPN_SHR,
RPN_CONST, 0xFF, 0, 0, 0, RPN_AND};
uint8_t bytes[] = {RPN_CONST, 8, 0, 0, 0, RPN_SHR, RPN_CONST, 0xFF, 0, 0, 0, RPN_AND};
expr.rpnPatchSize += sizeof(bytes);
memcpy(reserveSpace(expr, sizeof(bytes)), bytes, sizeof(bytes));
}
}
void rpn_LOW(Expression &expr, const Expression &src)
{
void rpn_LOW(Expression &expr, const Expression &src) {
expr = src;
expr.isSymbol = false;
@@ -599,16 +594,14 @@ void rpn_LOW(Expression &expr, const Expression &src)
}
}
void rpn_ISCONST(Expression &expr, const Expression &src)
{
void rpn_ISCONST(Expression &expr, const Expression &src) {
initExpression(expr);
expr.val = src.isKnown;
expr.isKnown = true;
expr.isSymbol = false;
}
void rpn_NEG(Expression &expr, const Expression &src)
{
void rpn_NEG(Expression &expr, const Expression &src) {
expr = src;
expr.isSymbol = false;
@@ -620,8 +613,7 @@ void rpn_NEG(Expression &expr, const Expression &src)
}
}
void rpn_NOT(Expression &expr, const Expression &src)
{
void rpn_NOT(Expression &expr, const Expression &src) {
expr = src;
expr.isSymbol = false;

View File

@@ -1,5 +1,7 @@
/* SPDX-License-Identifier: MIT */
#include "asm/section.hpp"
#include <algorithm>
#include <assert.h>
#include <deque>
@@ -9,21 +11,20 @@
#include <stack>
#include <stdio.h>
#include <stdlib.h>
#include <string>
#include <string.h>
#include <string>
#include <vector>
#include "error.hpp"
#include "linkdefs.hpp"
#include "asm/fstack.hpp"
#include "asm/main.hpp"
#include "asm/output.hpp"
#include "asm/rpn.hpp"
#include "asm/section.hpp"
#include "asm/symbol.hpp"
#include "asm/warning.hpp"
#include "error.hpp"
#include "linkdefs.hpp"
uint8_t fillByte;
struct UnionStackEntry {
@@ -50,8 +51,7 @@ char const *currentLoadScope = nullptr;
int32_t loadOffset; // Offset into the LOAD section's parent (see sect_GetOutputOffset)
// A quick check to see if we have an initialized section
attr_(warn_unused_result) static bool checksection()
{
attr_(warn_unused_result) static bool checksection() {
if (currentSection)
return true;
@@ -61,35 +61,38 @@ attr_(warn_unused_result) static bool checksection()
// A quick check to see if we have an initialized section that can contain
// this much initialized data
attr_(warn_unused_result) static bool checkcodesection()
{
attr_(warn_unused_result) static bool checkcodesection() {
if (!checksection())
return false;
if (sect_HasData(currentSection->type))
return true;
error("Section '%s' cannot contain code or data (not ROM0 or ROMX)\n",
currentSection->name.c_str());
error(
"Section '%s' cannot contain code or data (not ROM0 or ROMX)\n",
currentSection->name.c_str()
);
return false;
}
attr_(warn_unused_result) static bool checkSectionSize(Section const &sect, uint32_t size)
{
attr_(warn_unused_result) static bool checkSectionSize(Section const &sect, uint32_t size) {
uint32_t maxSize = sectionTypeInfo[sect.type].size;
// If the new size is reasonable, keep going
if (size <= maxSize)
return true;
error("Section '%s' grew too big (max size = 0x%" PRIX32
" bytes, reached 0x%" PRIX32 ").\n", sect.name.c_str(), maxSize, size);
error(
"Section '%s' grew too big (max size = 0x%" PRIX32 " bytes, reached 0x%" PRIX32 ").\n",
sect.name.c_str(),
maxSize,
size
);
return false;
}
// Check if the section has grown too much.
attr_(warn_unused_result) static bool reserveSpace(uint32_t delta_size)
{
attr_(warn_unused_result) static bool reserveSpace(uint32_t delta_size) {
// This check is here to trap broken code that generates sections that are too big and to
// prevent the assembler from generating huge object files or trying to allocate too much
// memory.
@@ -97,20 +100,19 @@ attr_(warn_unused_result) static bool reserveSpace(uint32_t delta_size)
// If the section has already overflowed, skip the check to avoid erroring out ad nauseam
if (currentSection->size != UINT32_MAX
&& !checkSectionSize(*currentSection, curOffset + loadOffset + delta_size))
&& !checkSectionSize(*currentSection, curOffset + loadOffset + delta_size))
// Mark the section as overflowed, to avoid repeating the error
currentSection->size = UINT32_MAX;
if (currentLoadSection && currentLoadSection->size != UINT32_MAX
&& !checkSectionSize(*currentLoadSection, curOffset + delta_size))
&& !checkSectionSize(*currentLoadSection, curOffset + delta_size))
currentLoadSection->size = UINT32_MAX;
return currentSection->size != UINT32_MAX
&& (!currentLoadSection || currentLoadSection->size != UINT32_MAX);
&& (!currentLoadSection || currentLoadSection->size != UINT32_MAX);
}
Section *sect_FindSectionByName(char const *name)
{
Section *sect_FindSectionByName(char const *name) {
for (Section &sect : sectionList) {
if (sect.name == name)
return &sect;
@@ -119,14 +121,15 @@ Section *sect_FindSectionByName(char const *name)
}
#define mask(align) ((1U << (align)) - 1)
#define fail(...) do { \
error(__VA_ARGS__); \
nbSectErrors++; \
} while (0)
#define fail(...) \
do { \
error(__VA_ARGS__); \
nbSectErrors++; \
} while (0)
static unsigned int mergeSectUnion(Section &sect, enum SectionType type, uint32_t org,
uint8_t alignment, uint16_t alignOffset)
{
static unsigned int mergeSectUnion(
Section &sect, enum SectionType type, uint32_t org, uint8_t alignment, uint16_t alignOffset
) {
assert(alignment < 16); // Should be ensured by the caller
unsigned int nbSectErrors = 0;
@@ -138,11 +141,15 @@ static unsigned int mergeSectUnion(Section &sect, enum SectionType type, uint32_
if (org != (uint32_t)-1) {
// If both are fixed, they must be the same
if (sect.org != (uint32_t)-1 && sect.org != org)
fail("Section already declared as fixed at different address $%04"
PRIx32 "\n", sect.org);
fail(
"Section already declared as fixed at different address $%04" PRIx32 "\n", sect.org
);
else if (sect.align != 0 && (mask(sect.align) & (org - sect.alignOfs)))
fail("Section already declared as aligned to %u bytes (offset %"
PRIu16 ")\n", 1U << sect.align, sect.alignOfs);
fail(
"Section already declared as aligned to %u bytes (offset %" PRIu16 ")\n",
1U << sect.align,
sect.alignOfs
);
else
// Otherwise, just override
sect.org = org;
@@ -151,13 +158,18 @@ static unsigned int mergeSectUnion(Section &sect, enum SectionType type, uint32_
// Make sure any fixed address given is compatible
if (sect.org != (uint32_t)-1) {
if ((sect.org - alignOffset) & mask(alignment))
fail("Section already declared as fixed at incompatible address $%04"
PRIx32 "\n", sect.org);
// Check if alignment offsets are compatible
fail(
"Section already declared as fixed at incompatible address $%04" PRIx32 "\n",
sect.org
);
// Check if alignment offsets are compatible
} else if ((alignOffset & mask(sect.align)) != (sect.alignOfs & mask(alignment))) {
fail("Section already declared with incompatible %u"
"-byte alignment (offset %" PRIu16 ")\n",
1U << sect.align, sect.alignOfs);
fail(
"Section already declared with incompatible %u"
"-byte alignment (offset %" PRIu16 ")\n",
1U << sect.align,
sect.alignOfs
);
} else if (alignment > sect.align) {
// If the section is not fixed, its alignment is the largest of both
sect.align = alignment;
@@ -168,8 +180,8 @@ static unsigned int mergeSectUnion(Section &sect, enum SectionType type, uint32_
return nbSectErrors;
}
static unsigned int mergeFragments(Section &sect, uint32_t org, uint8_t alignment, uint16_t alignOffset)
{
static unsigned int
mergeFragments(Section &sect, uint32_t org, uint8_t alignment, uint16_t alignOffset) {
assert(alignment < 16); // Should be ensured by the caller
unsigned int nbSectErrors = 0;
@@ -181,11 +193,16 @@ static unsigned int mergeFragments(Section &sect, uint32_t org, uint8_t alignmen
// If both are fixed, they must be the same
if (sect.org != (uint32_t)-1 && sect.org != curOrg)
fail("Section already declared as fixed at incompatible address $%04"
PRIx32 "\n", sect.org);
fail(
"Section already declared as fixed at incompatible address $%04" PRIx32 "\n",
sect.org
);
else if (sect.align != 0 && (mask(sect.align) & (curOrg - sect.alignOfs)))
fail("Section already declared as aligned to %u bytes (offset %"
PRIu16 ")\n", 1U << sect.align, sect.alignOfs);
fail(
"Section already declared as aligned to %u bytes (offset %" PRIu16 ")\n",
1U << sect.align,
sect.alignOfs
);
else
// Otherwise, just override
sect.org = curOrg;
@@ -199,13 +216,18 @@ static unsigned int mergeFragments(Section &sect, uint32_t org, uint8_t alignmen
// Make sure any fixed address given is compatible
if (sect.org != (uint32_t)-1) {
if ((sect.org - curOfs) & mask(alignment))
fail("Section already declared as fixed at incompatible address $%04"
PRIx32 "\n", sect.org);
// Check if alignment offsets are compatible
fail(
"Section already declared as fixed at incompatible address $%04" PRIx32 "\n",
sect.org
);
// Check if alignment offsets are compatible
} else if ((curOfs & mask(sect.align)) != (sect.alignOfs & mask(alignment))) {
fail("Section already declared with incompatible %u"
"-byte alignment (offset %" PRIu16 ")\n",
1U << sect.align, sect.alignOfs);
fail(
"Section already declared with incompatible %u"
"-byte alignment (offset %" PRIu16 ")\n",
1U << sect.align,
sect.alignOfs
);
} else if (alignment > sect.align) {
// If the section is not fixed, its alignment is the largest of both
sect.align = alignment;
@@ -216,9 +238,15 @@ static unsigned int mergeFragments(Section &sect, uint32_t org, uint8_t alignmen
return nbSectErrors;
}
static void mergeSections(Section &sect, enum SectionType type, uint32_t org, uint32_t bank,
uint8_t alignment, uint16_t alignOffset, enum SectionModifier mod)
{
static void mergeSections(
Section &sect,
enum SectionType type,
uint32_t org,
uint32_t bank,
uint8_t alignment,
uint16_t alignOffset,
enum SectionModifier mod
) {
unsigned int nbSectErrors = 0;
if (type != sect.type)
@@ -230,9 +258,9 @@ static void mergeSections(Section &sect, enum SectionType type, uint32_t org, ui
switch (mod) {
case SECTION_UNION:
case SECTION_FRAGMENT:
nbSectErrors += mod == SECTION_UNION ?
mergeSectUnion(sect, type, org, alignment, alignOffset) :
mergeFragments(sect, org, alignment, alignOffset);
nbSectErrors += mod == SECTION_UNION
? mergeSectUnion(sect, type, org, alignment, alignOffset)
: mergeFragments(sect, org, alignment, alignOffset);
// Common checks
@@ -241,8 +269,7 @@ static void mergeSections(Section &sect, enum SectionType type, uint32_t org, ui
sect.bank = bank;
// If both specify a bank, it must be the same one
else if (bank != (uint32_t)-1 && sect.bank != bank)
fail("Section already declared with different bank %" PRIu32 "\n",
sect.bank);
fail("Section already declared with different bank %" PRIu32 "\n", sect.bank);
break;
case SECTION_NORMAL:
@@ -254,16 +281,26 @@ static void mergeSections(Section &sect, enum SectionType type, uint32_t org, ui
}
if (nbSectErrors)
fatalerror("Cannot create section \"%s\" (%u error%s)\n",
sect.name.c_str(), nbSectErrors, nbSectErrors == 1 ? "" : "s");
fatalerror(
"Cannot create section \"%s\" (%u error%s)\n",
sect.name.c_str(),
nbSectErrors,
nbSectErrors == 1 ? "" : "s"
);
}
#undef fail
// Create a new section, not yet in the list.
static Section *createSection(char const *name, enum SectionType type, uint32_t org, uint32_t bank,
uint8_t alignment, uint16_t alignOffset, enum SectionModifier mod)
{
static Section *createSection(
char const *name,
enum SectionType type,
uint32_t org,
uint32_t bank,
uint8_t alignment,
uint16_t alignOffset,
enum SectionModifier mod
) {
// Add the new section to the list (order doesn't matter)
Section &sect = sectionList.emplace_front();
@@ -286,9 +323,13 @@ static Section *createSection(char const *name, enum SectionType type, uint32_t
}
// Find a section by name and type. If it doesn't exist, create it.
static Section *getSection(char const *name, enum SectionType type, uint32_t org,
SectionSpec const &attrs, enum SectionModifier mod)
{
static Section *getSection(
char const *name,
enum SectionType type,
uint32_t org,
SectionSpec const &attrs,
enum SectionModifier mod
) {
uint32_t bank = attrs.bank;
uint8_t alignment = attrs.alignment;
uint16_t alignOffset = attrs.alignOfs;
@@ -296,29 +337,41 @@ static Section *getSection(char const *name, enum SectionType type, uint32_t org
// First, validate parameters, and normalize them if applicable
if (bank != (uint32_t)-1) {
if (type != SECTTYPE_ROMX && type != SECTTYPE_VRAM
&& type != SECTTYPE_SRAM && type != SECTTYPE_WRAMX)
if (type != SECTTYPE_ROMX && type != SECTTYPE_VRAM && type != SECTTYPE_SRAM
&& type != SECTTYPE_WRAMX)
error("BANK only allowed for ROMX, WRAMX, SRAM, or VRAM sections\n");
else if (bank < sectionTypeInfo[type].firstBank || bank > sectionTypeInfo[type].lastBank)
error("%s bank value $%04" PRIx32 " out of range ($%04" PRIx32 " to $%04"
PRIx32 ")\n", sectionTypeInfo[type].name.c_str(), bank,
sectionTypeInfo[type].firstBank, sectionTypeInfo[type].lastBank);
error(
"%s bank value $%04" PRIx32 " out of range ($%04" PRIx32 " to $%04" PRIx32 ")\n",
sectionTypeInfo[type].name.c_str(),
bank,
sectionTypeInfo[type].firstBank,
sectionTypeInfo[type].lastBank
);
} else if (nbbanks(type) == 1) {
// If the section type only has a single bank, implicitly force it
bank = sectionTypeInfo[type].firstBank;
}
if (alignOffset >= 1 << alignment) {
error("Alignment offset (%" PRIu16 ") must be smaller than alignment size (%u)\n",
alignOffset, 1U << alignment);
error(
"Alignment offset (%" PRIu16 ") must be smaller than alignment size (%u)\n",
alignOffset,
1U << alignment
);
alignOffset = 0;
}
if (org != (uint32_t)-1) {
if (org < sectionTypeInfo[type].startAddr || org > endaddr(type))
error("Section \"%s\"'s fixed address $%04" PRIx32
" is outside of range [$%04" PRIx16 "; $%04" PRIx16 "]\n",
name, org, sectionTypeInfo[type].startAddr, endaddr(type));
error(
"Section \"%s\"'s fixed address $%04" PRIx32 " is outside of range [$%04" PRIx16
"; $%04" PRIx16 "]\n",
name,
org,
sectionTypeInfo[type].startAddr,
endaddr(type)
);
}
if (alignment != 0) {
@@ -331,12 +384,14 @@ static Section *getSection(char const *name, enum SectionType type, uint32_t org
if (org != (uint32_t)-1) {
if ((org - alignOffset) & mask)
error("Section \"%s\"'s fixed address doesn't match its alignment\n",
name);
error("Section \"%s\"'s fixed address doesn't match its alignment\n", name);
alignment = 0; // Ignore it if it's satisfied
} else if (sectionTypeInfo[type].startAddr & mask) {
error("Section \"%s\"'s alignment cannot be attained in %s\n",
name, sectionTypeInfo[type].name.c_str());
error(
"Section \"%s\"'s alignment cannot be attained in %s\n",
name,
sectionTypeInfo[type].name.c_str()
);
alignment = 0; // Ignore it if it's unattainable
org = 0;
} else if (alignment == 16) {
@@ -361,16 +416,14 @@ static Section *getSection(char const *name, enum SectionType type, uint32_t org
}
// Set the current section
static void changeSection()
{
static void changeSection() {
if (!currentUnionStack.empty())
fatalerror("Cannot change the section within a UNION\n");
sym_SetCurrentSymbolScope(nullptr);
}
bool Section::isSizeKnown() const
{
bool Section::isSizeKnown() const {
// SECTION UNION and SECTION FRAGMENT can still grow
if (modifier != SECTION_NORMAL)
return false;
@@ -389,9 +442,13 @@ bool Section::isSizeKnown() const
}
// Set the current section by name and type
void sect_NewSection(char const *name, enum SectionType type, uint32_t org,
SectionSpec const &attrs, enum SectionModifier mod)
{
void sect_NewSection(
char const *name,
enum SectionType type,
uint32_t org,
SectionSpec const &attrs,
enum SectionModifier mod
) {
if (currentLoadSection)
fatalerror("Cannot change the section within a `LOAD` block\n");
@@ -409,9 +466,13 @@ void sect_NewSection(char const *name, enum SectionType type, uint32_t org,
}
// Set the current section by name and type
void sect_SetLoadSection(char const *name, enum SectionType type, uint32_t org,
SectionSpec const &attrs, enum SectionModifier mod)
{
void sect_SetLoadSection(
char const *name,
enum SectionType type,
uint32_t org,
SectionSpec const &attrs,
enum SectionModifier mod
) {
// Important info: currently, UNION and LOAD cannot interact, since UNION is prohibited in
// "code" sections, whereas LOAD is restricted to them.
// Therefore, any interactions are NOT TESTED, so lift either of those restrictions at
@@ -444,8 +505,7 @@ void sect_SetLoadSection(char const *name, enum SectionType type, uint32_t org,
currentLoadSection = sect;
}
void sect_EndLoadSection()
{
void sect_EndLoadSection() {
if (!currentLoadSection) {
error("Found `ENDL` outside of a `LOAD` block\n");
return;
@@ -458,25 +518,21 @@ void sect_EndLoadSection()
sym_SetCurrentSymbolScope(currentLoadScope);
}
Section *sect_GetSymbolSection()
{
Section *sect_GetSymbolSection() {
return currentLoadSection ? currentLoadSection : currentSection;
}
// The offset into the section above
uint32_t sect_GetSymbolOffset()
{
uint32_t sect_GetSymbolOffset() {
return curOffset;
}
uint32_t sect_GetOutputOffset()
{
uint32_t sect_GetOutputOffset() {
return curOffset + loadOffset;
}
// Returns how many bytes need outputting for the specified alignment and offset to succeed
uint32_t sect_GetAlignBytes(uint8_t alignment, uint16_t offset)
{
uint32_t sect_GetAlignBytes(uint8_t alignment, uint16_t offset) {
Section *sect = sect_GetSymbolSection();
if (!sect)
return 0;
@@ -492,11 +548,10 @@ uint32_t sect_GetAlignBytes(uint8_t alignment, uint16_t offset)
// We need `(pcValue + curOffset + return value) % (1 << alignment) == offset`
uint16_t pcValue = isFixed ? sect->org : sect->alignOfs;
return static_cast<uint16_t>(offset - curOffset - pcValue)
% (1u << std::min(alignment, curAlignment));
% (1u << std::min(alignment, curAlignment));
}
void sect_AlignPC(uint8_t alignment, uint16_t offset)
{
void sect_AlignPC(uint8_t alignment, uint16_t offset) {
if (!checksection())
return;
@@ -505,12 +560,16 @@ void sect_AlignPC(uint8_t alignment, uint16_t offset)
if (sect->org != (uint32_t)-1) {
if ((sect->org + curOffset - offset) % alignSize)
error("Section's fixed address fails required alignment (PC = $%04" PRIx32
")\n", sect->org + curOffset);
} else if (sect->align != 0 && (((sect->alignOfs + curOffset) % (1u << sect->align))
- offset) % alignSize) {
error("Section's alignment fails required alignment (offset from section start = $%04"
PRIx32 ")\n", curOffset);
error(
"Section's fixed address fails required alignment (PC = $%04" PRIx32 ")\n",
sect->org + curOffset
);
} else if (sect->align != 0 && (((sect->alignOfs + curOffset) % (1u << sect->align)) - offset) % alignSize) {
error(
"Section's alignment fails required alignment (offset from section start = $%04" PRIx32
")\n",
curOffset
);
} else if (alignment >= 16) {
// Treat an alignment large enough as fixing the address.
// Note that this also ensures that a section's alignment never becomes 16 or greater.
@@ -526,8 +585,7 @@ void sect_AlignPC(uint8_t alignment, uint16_t offset)
}
}
static void growSection(uint32_t growth)
{
static void growSection(uint32_t growth) {
curOffset += growth;
if (curOffset + loadOffset > currentSection->size)
currentSection->size = curOffset + loadOffset;
@@ -535,33 +593,28 @@ static void growSection(uint32_t growth)
currentLoadSection->size = curOffset;
}
static void writebyte(uint8_t byte)
{
static void writebyte(uint8_t byte) {
currentSection->data[sect_GetOutputOffset()] = byte;
growSection(1);
}
static void writeword(uint16_t b)
{
static void writeword(uint16_t b) {
writebyte(b & 0xFF);
writebyte(b >> 8);
}
static void writelong(uint32_t b)
{
static void writelong(uint32_t b) {
writebyte(b & 0xFF);
writebyte(b >> 8);
writebyte(b >> 16);
writebyte(b >> 24);
}
static void createPatch(enum PatchType type, Expression const &expr, uint32_t pcShift)
{
static void createPatch(enum PatchType type, Expression const &expr, uint32_t pcShift) {
out_CreatePatch(type, expr, sect_GetOutputOffset(), pcShift);
}
void sect_StartUnion()
{
void sect_StartUnion() {
// Important info: currently, UNION and LOAD cannot interact, since UNION is prohibited in
// "code" sections, whereas LOAD is restricted to them.
// Therefore, any interactions are NOT TESTED, so lift either of those restrictions at
@@ -576,11 +629,10 @@ void sect_StartUnion()
return;
}
currentUnionStack.push({ .start = curOffset, .size = 0 });
currentUnionStack.push({.start = curOffset, .size = 0});
}
static void endUnionMember()
{
static void endUnionMember() {
UnionStackEntry &member = currentUnionStack.top();
uint32_t memberSize = curOffset - member.start;
@@ -589,8 +641,7 @@ static void endUnionMember()
curOffset = member.start;
}
void sect_NextUnionMember()
{
void sect_NextUnionMember() {
if (currentUnionStack.empty()) {
error("Found NEXTU outside of a UNION construct\n");
return;
@@ -598,8 +649,7 @@ void sect_NextUnionMember()
endUnionMember();
}
void sect_EndUnion()
{
void sect_EndUnion() {
if (currentUnionStack.empty()) {
error("Found ENDU outside of a UNION construct\n");
return;
@@ -609,15 +659,13 @@ void sect_EndUnion()
currentUnionStack.pop();
}
void sect_CheckUnionClosed()
{
void sect_CheckUnionClosed() {
if (!currentUnionStack.empty())
error("Unterminated UNION construct\n");
}
// Output an absolute byte
void sect_AbsByte(uint8_t b)
{
void sect_AbsByte(uint8_t b) {
if (!checkcodesection())
return;
if (!reserveSpace(1))
@@ -626,8 +674,7 @@ void sect_AbsByte(uint8_t b)
writebyte(b);
}
void sect_AbsByteGroup(uint8_t const *s, size_t length)
{
void sect_AbsByteGroup(uint8_t const *s, size_t length) {
if (!checkcodesection())
return;
if (!reserveSpace(length))
@@ -637,8 +684,7 @@ void sect_AbsByteGroup(uint8_t const *s, size_t length)
writebyte(*s++);
}
void sect_AbsWordGroup(uint8_t const *s, size_t length)
{
void sect_AbsWordGroup(uint8_t const *s, size_t length) {
if (!checkcodesection())
return;
if (!reserveSpace(length * 2))
@@ -648,8 +694,7 @@ void sect_AbsWordGroup(uint8_t const *s, size_t length)
writeword(*s++);
}
void sect_AbsLongGroup(uint8_t const *s, size_t length)
{
void sect_AbsLongGroup(uint8_t const *s, size_t length) {
if (!checkcodesection())
return;
if (!reserveSpace(length * 4))
@@ -660,8 +705,7 @@ void sect_AbsLongGroup(uint8_t const *s, size_t length)
}
// Skip this many bytes
void sect_Skip(uint32_t skip, bool ds)
{
void sect_Skip(uint32_t skip, bool ds) {
if (!checksection())
return;
if (!reserveSpace(skip))
@@ -671,8 +715,13 @@ void sect_Skip(uint32_t skip, bool ds)
growSection(skip);
} else {
if (!ds)
warning(WARNING_EMPTY_DATA_DIRECTIVE, "%s directive without data in ROM\n",
(skip == 4) ? "DL" : (skip == 2) ? "DW" : "DB");
warning(
WARNING_EMPTY_DATA_DIRECTIVE,
"%s directive without data in ROM\n",
(skip == 4) ? "DL"
: (skip == 2) ? "DW"
: "DB"
);
// We know we're in a code SECTION
while (skip--)
writebyte(fillByte);
@@ -681,8 +730,7 @@ void sect_Skip(uint32_t skip, bool ds)
// Output a relocatable byte. Checking will be done to see if it
// is an absolute value in disguise.
void sect_RelByte(Expression &expr, uint32_t pcShift)
{
void sect_RelByte(Expression &expr, uint32_t pcShift) {
if (!checkcodesection())
return;
if (!reserveSpace(1))
@@ -699,8 +747,7 @@ void sect_RelByte(Expression &expr, uint32_t pcShift)
// Output several copies of a relocatable byte. Checking will be done to see if
// it is an absolute value in disguise.
void sect_RelBytes(uint32_t n, std::vector<Expression> &exprs)
{
void sect_RelBytes(uint32_t n, std::vector<Expression> &exprs) {
if (!checkcodesection())
return;
if (!reserveSpace(n))
@@ -723,8 +770,7 @@ void sect_RelBytes(uint32_t n, std::vector<Expression> &exprs)
// Output a relocatable word. Checking will be done to see if
// it's an absolute value in disguise.
void sect_RelWord(Expression &expr, uint32_t pcShift)
{
void sect_RelWord(Expression &expr, uint32_t pcShift) {
if (!checkcodesection())
return;
if (!reserveSpace(2))
@@ -741,8 +787,7 @@ void sect_RelWord(Expression &expr, uint32_t pcShift)
// Output a relocatable longword. Checking will be done to see if
// is an absolute value in disguise.
void sect_RelLong(Expression &expr, uint32_t pcShift)
{
void sect_RelLong(Expression &expr, uint32_t pcShift) {
if (!checkcodesection())
return;
if (!reserveSpace(2))
@@ -759,8 +804,7 @@ void sect_RelLong(Expression &expr, uint32_t pcShift)
// Output a PC-relative relocatable byte. Checking will be done to see if it
// is an absolute value in disguise.
void sect_PCRelByte(Expression &expr, uint32_t pcShift)
{
void sect_PCRelByte(Expression &expr, uint32_t pcShift) {
if (!checkcodesection())
return;
if (!reserveSpace(1))
@@ -782,8 +826,7 @@ void sect_PCRelByte(Expression &expr, uint32_t pcShift)
offset = sym->getValue() - (pc->getValue() + 1);
if (offset < -128 || offset > 127) {
error("jr target out of reach (expected -129 < %" PRId16 " < 128)\n",
offset);
error("jr target out of reach (expected -129 < %" PRId16 " < 128)\n", offset);
writebyte(0);
} else {
writebyte(offset);
@@ -793,8 +836,7 @@ void sect_PCRelByte(Expression &expr, uint32_t pcShift)
}
// Output a binary file
void sect_BinaryFile(char const *s, int32_t startPos)
{
void sect_BinaryFile(char const *s, int32_t startPos) {
if (startPos < 0) {
error("Start position cannot be negative (%" PRId32 ")\n", startPos);
startPos = 0;
@@ -834,8 +876,7 @@ void sect_BinaryFile(char const *s, int32_t startPos)
goto cleanup;
} else {
if (errno != ESPIPE)
error("Error determining size of INCBIN file '%s': %s\n",
s, strerror(errno));
error("Error determining size of INCBIN file '%s': %s\n", s, strerror(errno));
// The file isn't seekable, so we'll just skip bytes
while (startPos--)
(void)fgetc(f);
@@ -854,8 +895,7 @@ cleanup:
fclose(f);
}
void sect_BinaryFileSlice(char const *s, int32_t start_pos, int32_t length)
{
void sect_BinaryFileSlice(char const *s, int32_t start_pos, int32_t length) {
if (start_pos < 0) {
error("Start position cannot be negative (%" PRId32 ")\n", start_pos);
start_pos = 0;
@@ -900,16 +940,20 @@ void sect_BinaryFileSlice(char const *s, int32_t start_pos, int32_t length)
}
if ((start_pos + length) > fsize) {
error("Specified range in INCBIN is out of bounds (%" PRIu32 " + %" PRIu32
" > %" PRIu32 ")\n", start_pos, length, fsize);
error(
"Specified range in INCBIN is out of bounds (%" PRIu32 " + %" PRIu32 " > %" PRIu32
")\n",
start_pos,
length,
fsize
);
goto cleanup;
}
fseek(f, start_pos, SEEK_SET);
} else {
if (errno != ESPIPE)
error("Error determining size of INCBIN file '%s': %s\n",
s, strerror(errno));
error("Error determining size of INCBIN file '%s': %s\n", s, strerror(errno));
// The file isn't seekable, so we'll just skip bytes
while (start_pos--)
(void)fgetc(f);
@@ -923,8 +967,7 @@ void sect_BinaryFileSlice(char const *s, int32_t start_pos, int32_t length)
} else if (ferror(f)) {
error("Error reading INCBIN file '%s': %s\n", s, strerror(errno));
} else {
error("Premature end of file (%" PRId32 " bytes left to read)\n",
length + 1);
error("Premature end of file (%" PRId32 " bytes left to read)\n", length + 1);
}
}
@@ -933,15 +976,14 @@ cleanup:
}
// Section stack routines
void sect_PushSection()
{
void sect_PushSection() {
sectionStack.push_front({
.section = currentSection,
.loadSection = currentLoadSection,
.scope = sym_GetCurrentSymbolScope(),
.offset = curOffset,
.loadOffset = loadOffset,
.unionStack = {},
.section = currentSection,
.loadSection = currentLoadSection,
.scope = sym_GetCurrentSymbolScope(),
.offset = curOffset,
.loadOffset = loadOffset,
.unionStack = {},
});
// Reset the section scope
@@ -951,8 +993,7 @@ void sect_PushSection()
std::swap(currentUnionStack, sectionStack.front().unionStack);
}
void sect_PopSection()
{
void sect_PopSection() {
if (sectionStack.empty())
fatalerror("No entries in the section stack\n");
@@ -971,8 +1012,7 @@ void sect_PopSection()
std::swap(currentUnionStack, entry.unionStack);
}
void sect_EndSection()
{
void sect_EndSection() {
if (!currentSection)
fatalerror("Cannot end the section outside of a SECTION\n");

View File

@@ -1,5 +1,7 @@
/* SPDX-License-Identifier: MIT */
#include "asm/symbol.hpp"
#include <assert.h>
#include <errno.h>
#include <inttypes.h>
@@ -7,26 +9,25 @@
#include <map>
#include <stdint.h>
#include <stdio.h>
#include <string>
#include <string.h>
#include <string>
#include <string_view>
#include <time.h>
#include <variant>
#include "error.hpp"
#include "helpers.hpp"
#include "util.hpp"
#include "version.hpp"
#include "asm/fixpoint.hpp"
#include "asm/fstack.hpp"
#include "asm/macro.hpp"
#include "asm/main.hpp"
#include "asm/output.hpp"
#include "asm/section.hpp"
#include "asm/symbol.hpp"
#include "util.hpp"
#include "asm/warning.hpp"
#include "error.hpp"
#include "helpers.hpp"
#include "version.hpp"
std::map<std::string, Symbol> symbols;
static const char *labelScope; // Current section's label scope
@@ -38,19 +39,16 @@ static char savedTIMESTAMP_ISO8601_LOCAL[256];
static char savedTIMESTAMP_ISO8601_UTC[256];
static bool exportAll;
bool sym_IsPC(Symbol const *sym)
{
bool sym_IsPC(Symbol const *sym) {
return sym == PCSymbol;
}
void sym_ForEach(void (*callback)(Symbol &))
{
void sym_ForEach(void (*callback)(Symbol &)) {
for (auto &it : symbols)
callback(it.second);
}
static int32_t Callback_NARG()
{
static int32_t Callback_NARG() {
if (!macro_GetCurrentArgs()) {
error("_NARG does not make sense outside of a macro\n");
return 0;
@@ -58,15 +56,13 @@ static int32_t Callback_NARG()
return macro_NbArgs();
}
static int32_t CallbackPC()
{
static int32_t CallbackPC() {
Section const *section = sect_GetSymbolSection();
return section ? section->org + sect_GetSymbolOffset() : 0;
}
int32_t Symbol::getValue() const
{
int32_t Symbol::getValue() const {
assert(std::holds_alternative<int32_t>(data) || std::holds_alternative<int32_t (*)()>(data));
if (int32_t const *value = std::get_if<int32_t>(&data); value) {
// TODO: do not use section's org directly
@@ -75,29 +71,28 @@ int32_t Symbol::getValue() const
return getOutputValue();
}
int32_t Symbol::getOutputValue() const
{
return std::visit(Visitor{
[](int32_t value) -> int32_t { return value; },
[](int32_t (*callback)()) -> int32_t { return callback(); },
[](auto &) -> int32_t { return 0; }
}, data);
int32_t Symbol::getOutputValue() const {
return std::visit(
Visitor{
[](int32_t value) -> int32_t { return value; },
[](int32_t (*callback)()) -> int32_t { return callback(); },
[](auto &) -> int32_t { return 0; },
},
data
);
}
std::string_view *Symbol::getMacro() const
{
std::string_view *Symbol::getMacro() const {
assert(std::holds_alternative<std::string_view *>(data));
return std::get<std::string_view *>(data);
}
std::string *Symbol::getEqus() const
{
std::string *Symbol::getEqus() const {
assert(std::holds_alternative<std::string *>(data));
return std::get<std::string *>(data);
}
static void dumpFilename(Symbol const &sym)
{
static void dumpFilename(Symbol const &sym) {
if (sym.src)
sym.src->dump(sym.fileLine);
else if (sym.fileLine == 0)
@@ -107,15 +102,13 @@ static void dumpFilename(Symbol const &sym)
}
// Set a symbol's definition filename and line
static void setSymbolFilename(Symbol &sym)
{
sym.src = fstk_GetFileStack(); // This is `nullptr` for built-ins
static void setSymbolFilename(Symbol &sym) {
sym.src = fstk_GetFileStack(); // This is `nullptr` for built-ins
sym.fileLine = sym.src ? lexer_GetLineNo() : 0; // This is 1 for built-ins
}
// Update a symbol's definition filename and line
static void updateSymbolFilename(Symbol &sym)
{
static void updateSymbolFilename(Symbol &sym) {
FileStackNode *oldSrc = sym.src;
setSymbolFilename(sym);
@@ -126,8 +119,7 @@ static void updateSymbolFilename(Symbol &sym)
}
// Create a new symbol by name
static Symbol &createsymbol(char const *symName)
{
static Symbol &createsymbol(char const *symName) {
Symbol &sym = symbols[symName];
if (snprintf(sym.name, MAXSYMLEN + 1, "%s", symName) > MAXSYMLEN)
@@ -144,9 +136,8 @@ static Symbol &createsymbol(char const *symName)
// Creates the full name of a local symbol in a given scope, by prepending
// the name with the parent symbol's name.
static void fullSymbolName(char *output, size_t outputSize,
char const *localName, char const *scopeName)
{
static void
fullSymbolName(char *output, size_t outputSize, char const *localName, char const *scopeName) {
int ret = snprintf(output, outputSize, "%s%s", scopeName, localName);
if (ret < 0)
@@ -155,27 +146,23 @@ static void fullSymbolName(char *output, size_t outputSize,
fatalerror("Symbol name is too long: '%s%s'\n", scopeName, localName);
}
static void assignStringSymbol(Symbol &sym, char const *value)
{
std::string *equs = new(std::nothrow) std::string(value);
static void assignStringSymbol(Symbol &sym, char const *value) {
std::string *equs = new (std::nothrow) std::string(value);
if (!equs)
fatalerror("No memory for string equate: %s\n", strerror(errno));
sym.type = SYM_EQUS;
sym.data = equs;
}
Symbol *sym_FindExactSymbol(char const *symName)
{
Symbol *sym_FindExactSymbol(char const *symName) {
auto search = symbols.find(symName);
return search != symbols.end() ? &search->second : nullptr;
}
Symbol *sym_FindScopedSymbol(char const *symName)
{
Symbol *sym_FindScopedSymbol(char const *symName) {
if (char const *localName = strchr(symName, '.'); localName) {
if (strchr(localName + 1, '.'))
fatalerror("'%s' is a nonsensical reference to a nested local symbol\n",
symName);
fatalerror("'%s' is a nonsensical reference to a nested local symbol\n", symName);
// If auto-scoped local label, expand the name
if (localName == symName) { // Meaning, the name begins with the dot
char fullName[MAXSYMLEN + 1];
@@ -187,8 +174,7 @@ Symbol *sym_FindScopedSymbol(char const *symName)
return sym_FindExactSymbol(symName);
}
Symbol *sym_FindScopedValidSymbol(char const *symName)
{
Symbol *sym_FindScopedValidSymbol(char const *symName) {
Symbol *sym = sym_FindScopedSymbol(symName);
// `@` has no value outside a section
@@ -202,14 +188,12 @@ Symbol *sym_FindScopedValidSymbol(char const *symName)
return sym;
}
Symbol const *sym_GetPC()
{
Symbol const *sym_GetPC() {
return PCSymbol;
}
// Purge a symbol
void sym_Purge(std::string const &symName)
{
void sym_Purge(std::string const &symName) {
Symbol *sym = sym_FindScopedValidSymbol(symName.c_str());
if (!sym) {
@@ -230,8 +214,7 @@ void sym_Purge(std::string const &symName)
}
}
uint32_t sym_GetPCValue()
{
uint32_t sym_GetPCValue() {
Section const *sect = sect_GetSymbolSection();
if (!sect)
@@ -244,8 +227,7 @@ uint32_t sym_GetPCValue()
}
// Return a constant symbol's value, assuming it's defined
uint32_t Symbol::getConstantValue() const
{
uint32_t Symbol::getConstantValue() const {
if (sym_IsPC(this))
return sym_GetPCValue();
@@ -257,8 +239,7 @@ uint32_t Symbol::getConstantValue() const
}
// Return a constant symbol's value
uint32_t sym_GetConstantValue(char const *symName)
{
uint32_t sym_GetConstantValue(char const *symName) {
if (Symbol const *sym = sym_FindScopedSymbol(symName); sym)
return sym->getConstantValue();
@@ -266,13 +247,11 @@ uint32_t sym_GetConstantValue(char const *symName)
return 0;
}
char const *sym_GetCurrentSymbolScope()
{
char const *sym_GetCurrentSymbolScope() {
return labelScope;
}
void sym_SetCurrentSymbolScope(char const *newScope)
{
void sym_SetCurrentSymbolScope(char const *newScope) {
labelScope = newScope;
}
@@ -283,8 +262,7 @@ void sym_SetCurrentSymbolScope(char const *newScope)
* @param symName The name of the symbol to create
* @param numeric If false, the symbol may not have been referenced earlier
*/
static Symbol *createNonrelocSymbol(char const *symName, bool numeric)
{
static Symbol *createNonrelocSymbol(char const *symName, bool numeric) {
Symbol *sym = sym_FindExactSymbol(symName);
if (!sym) {
@@ -306,8 +284,7 @@ static Symbol *createNonrelocSymbol(char const *symName, bool numeric)
}
// Add an equated symbol
Symbol *sym_AddEqu(char const *symName, int32_t value)
{
Symbol *sym_AddEqu(char const *symName, int32_t value) {
Symbol *sym = createNonrelocSymbol(symName, true);
if (!sym)
@@ -319,8 +296,7 @@ Symbol *sym_AddEqu(char const *symName, int32_t value)
return sym;
}
Symbol *sym_RedefEqu(char const *symName, int32_t value)
{
Symbol *sym_RedefEqu(char const *symName, int32_t value) {
Symbol *sym = sym_FindExactSymbol(symName);
if (!sym)
@@ -355,8 +331,7 @@ Symbol *sym_RedefEqu(char const *symName, int32_t value)
* of the string are enough: sym_AddString("M_PI", "3.1415"). This is the same
* as ``` M_PI EQUS "3.1415" ```
*/
Symbol *sym_AddString(char const *symName, char const *value)
{
Symbol *sym_AddString(char const *symName, char const *value) {
Symbol *sym = createNonrelocSymbol(symName, false);
if (!sym)
@@ -366,8 +341,7 @@ Symbol *sym_AddString(char const *symName, char const *value)
return sym;
}
Symbol *sym_RedefString(char const *symName, char const *value)
{
Symbol *sym_RedefString(char const *symName, char const *value) {
Symbol *sym = sym_FindExactSymbol(symName);
if (!sym)
@@ -395,15 +369,15 @@ Symbol *sym_RedefString(char const *symName, char const *value)
}
// Alter a mutable symbol's value
Symbol *sym_AddVar(char const *symName, int32_t value)
{
Symbol *sym_AddVar(char const *symName, int32_t value) {
Symbol *sym = sym_FindExactSymbol(symName);
if (!sym) {
sym = &createsymbol(symName);
} else if (sym->isDefined() && sym->type != SYM_VAR) {
error("'%s' already defined as %s at ",
symName, sym->type == SYM_LABEL ? "label" : "constant");
error(
"'%s' already defined as %s at ", symName, sym->type == SYM_LABEL ? "label" : "constant"
);
dumpFilename(*sym);
putc('\n', stderr);
return sym;
@@ -422,8 +396,7 @@ Symbol *sym_AddVar(char const *symName, int32_t value)
* @param symName The label's full name (so `.name` is invalid)
* @return The created symbol
*/
static Symbol *addLabel(char const *symName)
{
static Symbol *addLabel(char const *symName) {
assert(symName[0] != '.'); // The symbol name must have been expanded prior
Symbol *sym = sym_FindExactSymbol(symName);
@@ -452,8 +425,7 @@ static Symbol *addLabel(char const *symName)
}
// Add a local (`.name` or `Parent.name`) relocatable symbol
Symbol *sym_AddLocalLabel(char const *symName)
{
Symbol *sym_AddLocalLabel(char const *symName) {
// Assuming no dots in `labelScope` if defined
assert(!labelScope || !strchr(labelScope, '.'));
@@ -464,13 +436,11 @@ Symbol *sym_AddLocalLabel(char const *symName)
// Check for something after the dot in `localName`
if (localName[1] == '\0') {
fatalerror("'%s' is a nonsensical reference to an empty local label\n",
symName);
fatalerror("'%s' is a nonsensical reference to an empty local label\n", symName);
}
// Check for more than one dot in `localName`
if (strchr(localName + 1, '.'))
fatalerror("'%s' is a nonsensical reference to a nested local label\n",
symName);
fatalerror("'%s' is a nonsensical reference to a nested local label\n", symName);
if (localName == symName) {
if (!labelScope) {
@@ -486,8 +456,7 @@ Symbol *sym_AddLocalLabel(char const *symName)
}
// Add a relocatable symbol
Symbol *sym_AddLabel(char const *symName)
{
Symbol *sym_AddLabel(char const *symName) {
Symbol *sym = addLabel(symName);
// Set the symbol as the new scope
@@ -499,8 +468,7 @@ Symbol *sym_AddLabel(char const *symName)
static uint32_t anonLabelID;
// Add an anonymous label
Symbol *sym_AddAnonLabel()
{
Symbol *sym_AddAnonLabel() {
if (anonLabelID == UINT32_MAX) {
error("Only %" PRIu32 " anonymous labels can be created!", anonLabelID);
return nullptr;
@@ -513,22 +481,29 @@ Symbol *sym_AddAnonLabel()
}
// Write an anonymous label's name to a buffer
void sym_WriteAnonLabelName(char buf[MAXSYMLEN + 1], uint32_t ofs, bool neg)
{
void sym_WriteAnonLabelName(char buf[MAXSYMLEN + 1], uint32_t ofs, bool neg) {
uint32_t id = 0;
if (neg) {
if (ofs > anonLabelID)
error("Reference to anonymous label %" PRIu32 " before, when only %" PRIu32
" ha%s been created so far\n",
ofs, anonLabelID, anonLabelID == 1 ? "s" : "ve");
error(
"Reference to anonymous label %" PRIu32 " before, when only %" PRIu32
" ha%s been created so far\n",
ofs,
anonLabelID,
anonLabelID == 1 ? "s" : "ve"
);
else
id = anonLabelID - ofs;
} else {
ofs--; // We're referencing symbols that haven't been created yet...
if (ofs > UINT32_MAX - anonLabelID)
error("Reference to anonymous label %" PRIu32 " after, when only %" PRIu32
" may still be created\n", ofs + 1, UINT32_MAX - anonLabelID);
error(
"Reference to anonymous label %" PRIu32 " after, when only %" PRIu32
" may still be created\n",
ofs + 1,
UINT32_MAX - anonLabelID
);
else
id = anonLabelID + ofs;
}
@@ -537,8 +512,7 @@ void sym_WriteAnonLabelName(char buf[MAXSYMLEN + 1], uint32_t ofs, bool neg)
}
// Export a symbol
void sym_Export(char const *symName)
{
void sym_Export(char const *symName) {
if (symName[0] == '!') {
error("Anonymous labels cannot be exported\n");
return;
@@ -553,14 +527,13 @@ void sym_Export(char const *symName)
}
// Add a macro definition
Symbol *sym_AddMacro(char const *symName, int32_t defLineNo, char const *body, size_t size)
{
Symbol *sym_AddMacro(char const *symName, int32_t defLineNo, char const *body, size_t size) {
Symbol *sym = createNonrelocSymbol(symName, false);
if (!sym)
return nullptr;
std::string_view *macro = new(std::nothrow) std::string_view(body, size);
std::string_view *macro = new (std::nothrow) std::string_view(body, size);
if (!macro)
fatalerror("No memory for macro: %s\n", strerror(errno));
sym->type = SYM_MACRO;
@@ -576,8 +549,7 @@ Symbol *sym_AddMacro(char const *symName, int32_t defLineNo, char const *body, s
// Flag that a symbol is referenced in an RPN expression
// and create it if it doesn't exist yet
Symbol *sym_Ref(char const *symName)
{
Symbol *sym_Ref(char const *symName) {
Symbol *sym = sym_FindScopedSymbol(symName);
if (!sym) {
@@ -598,13 +570,11 @@ Symbol *sym_Ref(char const *symName)
}
// Set whether to export all relocatable symbols by default
void sym_SetExportAll(bool set)
{
void sym_SetExportAll(bool set) {
exportAll = set;
}
static Symbol *createBuiltinSymbol(char const *symName)
{
static Symbol *createBuiltinSymbol(char const *symName) {
Symbol *sym = &createsymbol(symName);
sym->isBuiltin = true;
@@ -615,8 +585,7 @@ static Symbol *createBuiltinSymbol(char const *symName)
}
// Initialize the symboltable
void sym_Init(time_t now)
{
void sym_Init(time_t now) {
PCSymbol = createBuiltinSymbol("@");
PCSymbol->type = SYM_LABEL;
PCSymbol->data = CallbackPC;
@@ -627,11 +596,12 @@ void sym_Init(time_t now)
sym_AddVar("_RS", 0)->isBuiltin = true;
#define addSym(fn, name, val) do { \
Symbol *sym = fn(name, val); \
assert(sym); \
sym->isBuiltin = true; \
} while (0)
#define addSym(fn, name, val) \
do { \
Symbol *sym = fn(name, val); \
assert(sym); \
sym->isBuiltin = true; \
} while (0)
#define addNumber(name, val) addSym(sym_AddEqu, name, val)
#define addString(name, val) addSym(sym_AddString, name, val)
@@ -653,15 +623,21 @@ void sym_Init(time_t now)
strftime(savedTIME, sizeof(savedTIME), "\"%H:%M:%S\"", time_local);
strftime(savedDATE, sizeof(savedDATE), "\"%d %B %Y\"", time_local);
strftime(savedTIMESTAMP_ISO8601_LOCAL,
sizeof(savedTIMESTAMP_ISO8601_LOCAL), "\"%Y-%m-%dT%H:%M:%S%z\"",
time_local);
strftime(
savedTIMESTAMP_ISO8601_LOCAL,
sizeof(savedTIMESTAMP_ISO8601_LOCAL),
"\"%Y-%m-%dT%H:%M:%S%z\"",
time_local
);
const tm *time_utc = gmtime(&now);
strftime(savedTIMESTAMP_ISO8601_UTC,
sizeof(savedTIMESTAMP_ISO8601_UTC), "\"%Y-%m-%dT%H:%M:%SZ\"",
time_utc);
strftime(
savedTIMESTAMP_ISO8601_UTC,
sizeof(savedTIMESTAMP_ISO8601_UTC),
"\"%Y-%m-%dT%H:%M:%SZ\"",
time_utc
);
addString("__TIME__", savedTIME);
addString("__DATE__", savedDATE);

View File

@@ -1,5 +1,7 @@
/* SPDX-License-Identifier: MIT */
#include "asm/warning.hpp"
#include <inttypes.h>
#include <limits.h>
#include <stdarg.h>
@@ -8,48 +10,46 @@
#include <stdlib.h>
#include <string.h>
#include "asm/fstack.hpp"
#include "asm/main.hpp"
#include "asm/warning.hpp"
#include "error.hpp"
#include "itertools.hpp"
#include "asm/fstack.hpp"
#include "asm/main.hpp"
unsigned int nbErrors = 0;
unsigned int maxErrors = 0;
static const enum WarningState defaultWarnings[ARRAY_SIZE(warningStates)] = {
WARNING_ENABLED, // WARNING_ASSERT
WARNING_DISABLED, // WARNING_BACKWARDS_FOR
WARNING_DISABLED, // WARNING_BUILTIN_ARG
WARNING_DISABLED, // WARNING_CHARMAP_REDEF
WARNING_DISABLED, // WARNING_DIV
WARNING_DISABLED, // WARNING_EMPTY_DATA_DIRECTIVE
WARNING_DISABLED, // WARNING_EMPTY_MACRO_ARG
WARNING_DISABLED, // WARNING_EMPTY_STRRPL
WARNING_DISABLED, // WARNING_LARGE_CONSTANT
WARNING_DISABLED, // WARNING_LONG_STR
WARNING_DISABLED, // WARNING_MACRO_SHIFT
WARNING_ENABLED, // WARNING_NESTED_COMMENT
WARNING_ENABLED, // WARNING_OBSOLETE
WARNING_DISABLED, // WARNING_SHIFT
WARNING_DISABLED, // WARNING_SHIFT_AMOUNT
WARNING_ENABLED, // WARNING_USER
WARNING_ENABLED, // WARNING_ASSERT
WARNING_DISABLED, // WARNING_BACKWARDS_FOR
WARNING_DISABLED, // WARNING_BUILTIN_ARG
WARNING_DISABLED, // WARNING_CHARMAP_REDEF
WARNING_DISABLED, // WARNING_DIV
WARNING_DISABLED, // WARNING_EMPTY_DATA_DIRECTIVE
WARNING_DISABLED, // WARNING_EMPTY_MACRO_ARG
WARNING_DISABLED, // WARNING_EMPTY_STRRPL
WARNING_DISABLED, // WARNING_LARGE_CONSTANT
WARNING_DISABLED, // WARNING_LONG_STR
WARNING_DISABLED, // WARNING_MACRO_SHIFT
WARNING_ENABLED, // WARNING_NESTED_COMMENT
WARNING_ENABLED, // WARNING_OBSOLETE
WARNING_DISABLED, // WARNING_SHIFT
WARNING_DISABLED, // WARNING_SHIFT_AMOUNT
WARNING_ENABLED, // WARNING_USER
WARNING_ENABLED, // WARNING_NUMERIC_STRING_1
WARNING_DISABLED, // WARNING_NUMERIC_STRING_2
WARNING_ENABLED, // WARNING_TRUNCATION_1
WARNING_DISABLED, // WARNING_TRUNCATION_2
WARNING_ENABLED, // WARNING_UNMAPPED_CHAR_1
WARNING_DISABLED, // WARNING_UNMAPPED_CHAR_2
WARNING_ENABLED, // WARNING_NUMERIC_STRING_1
WARNING_DISABLED, // WARNING_NUMERIC_STRING_2
WARNING_ENABLED, // WARNING_TRUNCATION_1
WARNING_DISABLED, // WARNING_TRUNCATION_2
WARNING_ENABLED, // WARNING_UNMAPPED_CHAR_1
WARNING_DISABLED, // WARNING_UNMAPPED_CHAR_2
};
enum WarningState warningStates[ARRAY_SIZE(warningStates)];
bool warningsAreErrors; // Set if `-Werror` was specified
static enum WarningState warningState(enum WarningID id)
{
static enum WarningState warningState(enum WarningID id) {
// Check if warnings are globally disabled
if (!warnings)
return WARNING_DISABLED;
@@ -68,35 +68,35 @@ static enum WarningState warningState(enum WarningID id)
}
static const char * const warningFlags[NB_WARNINGS] = {
"assert",
"backwards-for",
"builtin-args",
"charmap-redef",
"div",
"empty-data-directive",
"empty-macro-arg",
"empty-strrpl",
"large-constant",
"long-string",
"macro-shift",
"nested-comment",
"obsolete",
"shift",
"shift-amount",
"user",
"assert",
"backwards-for",
"builtin-args",
"charmap-redef",
"div",
"empty-data-directive",
"empty-macro-arg",
"empty-strrpl",
"large-constant",
"long-string",
"macro-shift",
"nested-comment",
"obsolete",
"shift",
"shift-amount",
"user",
// Parametric warnings
"numeric-string",
"numeric-string",
"truncation",
"truncation",
"unmapped-char",
"unmapped-char",
// Parametric warnings
"numeric-string",
"numeric-string",
"truncation",
"truncation",
"unmapped-char",
"unmapped-char",
// Meta warnings
"all",
"extra",
"everything", // Especially useful for testing
// Meta warnings
"all",
"extra",
"everything", // Especially useful for testing
};
static const struct {
@@ -104,13 +104,12 @@ static const struct {
uint8_t nbLevels;
uint8_t defaultLevel;
} paramWarnings[] = {
{ "numeric-string", 2, 1 },
{ "truncation", 2, 2 },
{ "unmapped-char", 2, 1 },
{"numeric-string", 2, 1},
{"truncation", 2, 2},
{"unmapped-char", 2, 1},
};
static bool tryProcessParamWarning(char const *flag, uint8_t param, enum WarningState state)
{
static bool tryProcessParamWarning(char const *flag, uint8_t param, enum WarningState state) {
enum WarningID baseID = PARAM_WARNINGS_START;
for (size_t i = 0; i < ARRAY_SIZE(paramWarnings); i++) {
@@ -126,17 +125,19 @@ static bool tryProcessParamWarning(char const *flag, uint8_t param, enum Warning
param = paramWarnings[i].defaultLevel;
} else if (param > maxParam) {
if (param != 255) // Don't warn if already capped
warnx("Got parameter %" PRIu8
" for warning flag \"%s\", but the maximum is %"
PRIu8 "; capping.\n",
param, flag, maxParam);
warnx(
"Got parameter %" PRIu8
" for warning flag \"%s\", but the maximum is %" PRIu8 "; capping.\n",
param,
flag,
maxParam
);
param = maxParam;
}
// Set the first <param> to enabled/error, and disable the rest
for (uint8_t ofs = 0; ofs < maxParam; ofs++) {
warningStates[baseID + ofs] =
ofs < param ? state : WARNING_DISABLED;
warningStates[baseID + ofs] = ofs < param ? state : WARNING_DISABLED;
}
return true;
}
@@ -146,73 +147,70 @@ static bool tryProcessParamWarning(char const *flag, uint8_t param, enum Warning
return false;
}
enum MetaWarningCommand {
META_WARNING_DONE = NB_WARNINGS
};
enum MetaWarningCommand { META_WARNING_DONE = NB_WARNINGS };
// Warnings that probably indicate an error
static uint8_t const _wallCommands[] = {
WARNING_BACKWARDS_FOR,
WARNING_BUILTIN_ARG,
WARNING_CHARMAP_REDEF,
WARNING_EMPTY_DATA_DIRECTIVE,
WARNING_EMPTY_STRRPL,
WARNING_LARGE_CONSTANT,
WARNING_LONG_STR,
WARNING_NESTED_COMMENT,
WARNING_OBSOLETE,
WARNING_NUMERIC_STRING_1,
WARNING_UNMAPPED_CHAR_1,
META_WARNING_DONE
WARNING_BACKWARDS_FOR,
WARNING_BUILTIN_ARG,
WARNING_CHARMAP_REDEF,
WARNING_EMPTY_DATA_DIRECTIVE,
WARNING_EMPTY_STRRPL,
WARNING_LARGE_CONSTANT,
WARNING_LONG_STR,
WARNING_NESTED_COMMENT,
WARNING_OBSOLETE,
WARNING_NUMERIC_STRING_1,
WARNING_UNMAPPED_CHAR_1,
META_WARNING_DONE,
};
// Warnings that are less likely to indicate an error
static uint8_t const _wextraCommands[] = {
WARNING_EMPTY_MACRO_ARG,
WARNING_MACRO_SHIFT,
WARNING_NESTED_COMMENT,
WARNING_OBSOLETE,
WARNING_NUMERIC_STRING_2,
WARNING_TRUNCATION_1,
WARNING_TRUNCATION_2,
WARNING_UNMAPPED_CHAR_1,
WARNING_UNMAPPED_CHAR_2,
META_WARNING_DONE
WARNING_EMPTY_MACRO_ARG,
WARNING_MACRO_SHIFT,
WARNING_NESTED_COMMENT,
WARNING_OBSOLETE,
WARNING_NUMERIC_STRING_2,
WARNING_TRUNCATION_1,
WARNING_TRUNCATION_2,
WARNING_UNMAPPED_CHAR_1,
WARNING_UNMAPPED_CHAR_2,
META_WARNING_DONE,
};
// Literally everything. Notably useful for testing
static uint8_t const _weverythingCommands[] = {
WARNING_BACKWARDS_FOR,
WARNING_BUILTIN_ARG,
WARNING_DIV,
WARNING_EMPTY_DATA_DIRECTIVE,
WARNING_EMPTY_MACRO_ARG,
WARNING_EMPTY_STRRPL,
WARNING_LARGE_CONSTANT,
WARNING_LONG_STR,
WARNING_MACRO_SHIFT,
WARNING_NESTED_COMMENT,
WARNING_OBSOLETE,
WARNING_SHIFT,
WARNING_SHIFT_AMOUNT,
WARNING_NUMERIC_STRING_1,
WARNING_NUMERIC_STRING_2,
WARNING_TRUNCATION_1,
WARNING_TRUNCATION_2,
WARNING_UNMAPPED_CHAR_1,
WARNING_UNMAPPED_CHAR_2,
// WARNING_USER,
META_WARNING_DONE
WARNING_BACKWARDS_FOR,
WARNING_BUILTIN_ARG,
WARNING_DIV,
WARNING_EMPTY_DATA_DIRECTIVE,
WARNING_EMPTY_MACRO_ARG,
WARNING_EMPTY_STRRPL,
WARNING_LARGE_CONSTANT,
WARNING_LONG_STR,
WARNING_MACRO_SHIFT,
WARNING_NESTED_COMMENT,
WARNING_OBSOLETE,
WARNING_SHIFT,
WARNING_SHIFT_AMOUNT,
WARNING_NUMERIC_STRING_1,
WARNING_NUMERIC_STRING_2,
WARNING_TRUNCATION_1,
WARNING_TRUNCATION_2,
WARNING_UNMAPPED_CHAR_1,
WARNING_UNMAPPED_CHAR_2,
// WARNING_USER,
META_WARNING_DONE,
};
static uint8_t const *metaWarningCommands[NB_META_WARNINGS] = {
_wallCommands,
_wextraCommands,
_weverythingCommands
_wallCommands,
_wextraCommands,
_weverythingCommands,
};
void processWarningFlag(char *flag)
{
void processWarningFlag(char *flag) {
static bool setError = false;
// First, try to match against a "meta" warning
@@ -221,11 +219,11 @@ void processWarningFlag(char *flag)
if (!strcmp(flag, warningFlags[id])) {
// We got a match!
if (setError)
errx("Cannot make meta warning \"%s\" into an error",
flag);
errx("Cannot make meta warning \"%s\" into an error", flag);
for (uint8_t const *ptr = metaWarningCommands[id - META_WARNINGS_START];
*ptr != META_WARNING_DONE; ptr++) {
*ptr != META_WARNING_DONE;
ptr++) {
// Warning flag, set without override
if (warningStates[*ptr] == WARNING_DEFAULT)
warningStates[*ptr] = WARNING_ENABLED;
@@ -252,16 +250,16 @@ void processWarningFlag(char *flag)
setError = false;
return;
// Otherwise, allow parsing as another flag
// Otherwise, allow parsing as another flag
}
}
// Well, it's either a normal warning or a mistake
enum WarningState state = setError ? WARNING_ERROR
// Not an error, then check if this is a negation
: strncmp(flag, "no-", strlen("no-")) ? WARNING_ENABLED
: WARNING_DISABLED;
// Not an error, then check if this is a negation
: strncmp(flag, "no-", strlen("no-")) ? WARNING_ENABLED
: WARNING_DISABLED;
char *rootFlag = state == WARNING_DISABLED ? flag + strlen("no-") : flag;
// Is this a "parametric" warning?
@@ -284,8 +282,7 @@ void processWarningFlag(char *flag)
// Avoid overflowing!
if (param > UINT8_MAX - (*ptr - '0')) {
if (!warned)
warnx("Invalid warning flag \"%s\": capping parameter at 255\n",
flag);
warnx("Invalid warning flag \"%s\": capping parameter at 255\n", flag);
warned = true; // Only warn once, cap always
param = 255;
continue;
@@ -303,8 +300,7 @@ void processWarningFlag(char *flag)
return;
}
*equals = '\0'; // Truncate the param at the '='
if (tryProcessParamWarning(rootFlag, param,
param == 0 ? WARNING_DISABLED : state))
if (tryProcessParamWarning(rootFlag, param, param == 0 ? WARNING_DISABLED : state))
return;
}
}
@@ -327,9 +323,9 @@ void processWarningFlag(char *flag)
warnx("Unknown warning `%s`", flag);
}
void printDiag(char const *fmt, va_list args, char const *type,
char const *flagfmt, char const *flag)
{
void printDiag(
char const *fmt, va_list args, char const *type, char const *flagfmt, char const *flag
) {
fputs(type, stderr);
fputs(": ", stderr);
fstk_DumpCurrent();
@@ -339,8 +335,7 @@ void printDiag(char const *fmt, va_list args, char const *type,
lexer_DumpStringExpansions();
}
void error(char const *fmt, ...)
{
void error(char const *fmt, ...) {
va_list args;
va_start(args, fmt);
@@ -350,12 +345,15 @@ void error(char const *fmt, ...)
// This intentionally makes 0 act as "unlimited" (or at least "limited to sizeof(unsigned)")
nbErrors++;
if (nbErrors == maxErrors)
errx("The maximum of %u error%s was reached (configure with \"-X/--max-errors\"); assembly aborted!",
maxErrors, maxErrors == 1 ? "" : "s");
errx(
"The maximum of %u error%s was reached (configure with \"-X/--max-errors\"); assembly "
"aborted!",
maxErrors,
maxErrors == 1 ? "" : "s"
);
}
[[noreturn]] void fatalerror(char const *fmt, ...)
{
[[noreturn]] void fatalerror(char const *fmt, ...) {
va_list args;
va_start(args, fmt);
@@ -365,8 +363,7 @@ void error(char const *fmt, ...)
exit(1);
}
void warning(enum WarningID id, char const *fmt, ...)
{
void warning(enum WarningID id, char const *fmt, ...) {
char const *flag = warningFlags[id];
va_list args;