mirror of
https://github.com/gbdev/rgbds.git
synced 2025-11-20 18:22:07 +00:00
Make comments more consistent
- Changes most `/* comments */` to `// comments` - Changes `/**` block comments consistently to `/*` - Adds consistent license comments to all files Also renames `T_POP_SET` to `T_Z80_SET`
This commit is contained in:
@@ -21,33 +21,29 @@
|
||||
|
||||
#include "hashmap.h"
|
||||
|
||||
/*
|
||||
* 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,
|
||||
*/
|
||||
// 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 Charnode {
|
||||
bool isTerminal; /* Whether there exists a mapping that ends here */
|
||||
uint8_t value; /* If the above is true, its corresponding value */
|
||||
/* This MUST be indexes and not pointers, because pointers get invalidated by `realloc`!! */
|
||||
size_t next[255]; /* Indexes of where to go next, 0 = nowhere */
|
||||
bool isTerminal; // Whether there exists a mapping that ends here
|
||||
uint8_t value; // If the above is true, its corresponding value
|
||||
// This MUST be indexes and not pointers, because pointers get invalidated by `realloc`!!
|
||||
size_t next[255]; // Indexes of where to go next, 0 = nowhere
|
||||
};
|
||||
|
||||
#define INITIAL_CAPACITY 32
|
||||
|
||||
struct Charmap {
|
||||
char *name;
|
||||
size_t usedNodes; /* How many nodes are being used */
|
||||
size_t capacity; /* How many nodes have been allocated */
|
||||
struct Charnode nodes[]; /* first node is reserved for the root node */
|
||||
size_t usedNodes; // How many nodes are being used
|
||||
size_t capacity; // How many nodes have been allocated
|
||||
struct Charnode nodes[]; // first node is reserved for the root node
|
||||
};
|
||||
|
||||
static HashMap charmaps;
|
||||
|
||||
/*
|
||||
* Store pointers to hashmap nodes, so that there is only one pointer to the memory block
|
||||
* that gets reallocated.
|
||||
*/
|
||||
// Store pointers to hashmap nodes, so that there is only one pointer to the memory block
|
||||
// that gets reallocated.
|
||||
static struct Charmap **currentCharmap;
|
||||
|
||||
struct CharmapStackEntry {
|
||||
@@ -96,7 +92,7 @@ struct Charmap *charmap_New(char const *name, char const *baseName)
|
||||
return charmap;
|
||||
}
|
||||
|
||||
/* Init the new charmap's fields */
|
||||
// Init the new charmap's fields
|
||||
if (base) {
|
||||
resizeCharmap(&charmap, base->capacity);
|
||||
charmap->usedNodes = base->usedNodes;
|
||||
@@ -105,7 +101,7 @@ struct Charmap *charmap_New(char const *name, char const *baseName)
|
||||
} else {
|
||||
resizeCharmap(&charmap, INITIAL_CAPACITY);
|
||||
charmap->usedNodes = 1;
|
||||
initNode(&charmap->nodes[0]); /* Init the root node */
|
||||
initNode(&charmap->nodes[0]); // Init the root node
|
||||
}
|
||||
charmap->name = strdup(name);
|
||||
|
||||
@@ -169,16 +165,16 @@ void charmap_Add(char *mapping, uint8_t value)
|
||||
if (node->next[c]) {
|
||||
node = &charmap->nodes[node->next[c]];
|
||||
} else {
|
||||
/* Register next available node */
|
||||
// Register next available node
|
||||
node->next[c] = charmap->usedNodes;
|
||||
/* If no more nodes are available, get new ones */
|
||||
// If no more nodes are available, get new ones
|
||||
if (charmap->usedNodes == charmap->capacity) {
|
||||
charmap->capacity *= 2;
|
||||
resizeCharmap(currentCharmap, charmap->capacity);
|
||||
charmap = *currentCharmap;
|
||||
}
|
||||
|
||||
/* Switch to and init new node */
|
||||
// Switch to and init new node
|
||||
node = &charmap->nodes[charmap->usedNodes++];
|
||||
initNode(node);
|
||||
}
|
||||
@@ -203,12 +199,10 @@ size_t charmap_Convert(char const *input, uint8_t *output)
|
||||
|
||||
size_t charmap_ConvertNext(char const **input, 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.
|
||||
* If no match, read a UTF-8 codepoint and output that.
|
||||
*/
|
||||
// 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.
|
||||
// If no match, read a UTF-8 codepoint and output that.
|
||||
struct Charmap const *charmap = *currentCharmap;
|
||||
struct Charnode const *node = &charmap->nodes[0];
|
||||
struct Charnode const *match = NULL;
|
||||
|
||||
@@ -6,9 +6,7 @@
|
||||
* SPDX-License-Identifier: MIT
|
||||
*/
|
||||
|
||||
/*
|
||||
* Fixed-point math routines
|
||||
*/
|
||||
// Fixed-point math routines
|
||||
|
||||
#include <inttypes.h>
|
||||
#include <math.h>
|
||||
@@ -30,9 +28,6 @@
|
||||
#define M_PI 3.14159265358979323846
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Print a fixed point value
|
||||
*/
|
||||
void fix_Print(int32_t i)
|
||||
{
|
||||
uint32_t u = i;
|
||||
@@ -47,121 +42,76 @@ void fix_Print(int32_t i)
|
||||
((uint32_t)(fix2double(u) * 100000 + 0.5)) % 100000);
|
||||
}
|
||||
|
||||
/*
|
||||
* Calculate sine
|
||||
*/
|
||||
int32_t fix_Sin(int32_t i)
|
||||
{
|
||||
return double2fix(sin(fdeg2rad(fix2double(i))));
|
||||
}
|
||||
|
||||
/*
|
||||
* Calculate cosine
|
||||
*/
|
||||
int32_t fix_Cos(int32_t i)
|
||||
{
|
||||
return double2fix(cos(fdeg2rad(fix2double(i))));
|
||||
}
|
||||
|
||||
/*
|
||||
* Calculate tangent
|
||||
*/
|
||||
int32_t fix_Tan(int32_t i)
|
||||
{
|
||||
return double2fix(tan(fdeg2rad(fix2double(i))));
|
||||
}
|
||||
|
||||
/*
|
||||
* Calculate arcsine
|
||||
*/
|
||||
int32_t fix_ASin(int32_t i)
|
||||
{
|
||||
return double2fix(rad2fdeg(asin(fix2double(i))));
|
||||
}
|
||||
|
||||
/*
|
||||
* Calculate arccosine
|
||||
*/
|
||||
int32_t fix_ACos(int32_t i)
|
||||
{
|
||||
return double2fix(rad2fdeg(acos(fix2double(i))));
|
||||
}
|
||||
|
||||
/*
|
||||
* Calculate arctangent
|
||||
*/
|
||||
int32_t fix_ATan(int32_t i)
|
||||
{
|
||||
return double2fix(rad2fdeg(atan(fix2double(i))));
|
||||
}
|
||||
|
||||
/*
|
||||
* Calculate atan2
|
||||
*/
|
||||
int32_t fix_ATan2(int32_t i, int32_t j)
|
||||
{
|
||||
return double2fix(rad2fdeg(atan2(fix2double(i), fix2double(j))));
|
||||
}
|
||||
|
||||
/*
|
||||
* Multiplication
|
||||
*/
|
||||
int32_t fix_Mul(int32_t i, int32_t j)
|
||||
{
|
||||
return double2fix(fix2double(i) * fix2double(j));
|
||||
}
|
||||
|
||||
/*
|
||||
* Division
|
||||
*/
|
||||
int32_t fix_Div(int32_t i, int32_t j)
|
||||
{
|
||||
return double2fix(fix2double(i) / fix2double(j));
|
||||
}
|
||||
|
||||
/*
|
||||
* Modulo
|
||||
*/
|
||||
int32_t fix_Mod(int32_t i, int32_t j)
|
||||
{
|
||||
return double2fix(fmod(fix2double(i), fix2double(j)));
|
||||
}
|
||||
|
||||
/*
|
||||
* Power
|
||||
*/
|
||||
int32_t fix_Pow(int32_t i, int32_t j)
|
||||
{
|
||||
return double2fix(pow(fix2double(i), fix2double(j)));
|
||||
}
|
||||
|
||||
/*
|
||||
* Logarithm
|
||||
*/
|
||||
int32_t fix_Log(int32_t i, int32_t j)
|
||||
{
|
||||
return double2fix(log(fix2double(i)) / log(fix2double(j)));
|
||||
}
|
||||
|
||||
/*
|
||||
* Round
|
||||
*/
|
||||
int32_t fix_Round(int32_t i)
|
||||
{
|
||||
return double2fix(round(fix2double(i)));
|
||||
}
|
||||
|
||||
/*
|
||||
* Ceil
|
||||
*/
|
||||
int32_t fix_Ceil(int32_t i)
|
||||
{
|
||||
return double2fix(ceil(fix2double(i)));
|
||||
}
|
||||
|
||||
/*
|
||||
* Floor
|
||||
*/
|
||||
int32_t fix_Floor(int32_t i)
|
||||
{
|
||||
return double2fix(floor(fix2double(i)));
|
||||
|
||||
@@ -46,7 +46,7 @@ void fmt_UseCharacter(struct FormatSpec *fmt, int c)
|
||||
return;
|
||||
|
||||
switch (c) {
|
||||
/* sign */
|
||||
// sign
|
||||
case ' ':
|
||||
case '+':
|
||||
if (fmt->state > FORMAT_SIGN)
|
||||
@@ -55,7 +55,7 @@ void fmt_UseCharacter(struct FormatSpec *fmt, int c)
|
||||
fmt->sign = c;
|
||||
break;
|
||||
|
||||
/* prefix */
|
||||
// prefix
|
||||
case '#':
|
||||
if (fmt->state > FORMAT_PREFIX)
|
||||
goto invalid;
|
||||
@@ -63,7 +63,7 @@ void fmt_UseCharacter(struct FormatSpec *fmt, int c)
|
||||
fmt->prefix = true;
|
||||
break;
|
||||
|
||||
/* align */
|
||||
// align
|
||||
case '-':
|
||||
if (fmt->state > FORMAT_ALIGN)
|
||||
goto invalid;
|
||||
@@ -71,11 +71,11 @@ void fmt_UseCharacter(struct FormatSpec *fmt, int c)
|
||||
fmt->alignLeft = true;
|
||||
break;
|
||||
|
||||
/* pad and width */
|
||||
// pad and width
|
||||
case '0':
|
||||
if (fmt->state < FORMAT_WIDTH)
|
||||
fmt->padZero = true;
|
||||
/* fallthrough */
|
||||
// fallthrough
|
||||
case '1':
|
||||
case '2':
|
||||
case '3':
|
||||
@@ -104,7 +104,7 @@ void fmt_UseCharacter(struct FormatSpec *fmt, int c)
|
||||
fmt->hasFrac = true;
|
||||
break;
|
||||
|
||||
/* type */
|
||||
// type
|
||||
case 'd':
|
||||
case 'u':
|
||||
case 'X':
|
||||
@@ -149,7 +149,7 @@ void fmt_PrintString(char *buf, size_t bufLen, struct FormatSpec const *fmt, cha
|
||||
size_t len = strlen(value);
|
||||
size_t totalLen = fmt->width > len ? fmt->width : len;
|
||||
|
||||
if (totalLen > bufLen - 1) { /* bufLen includes terminator */
|
||||
if (totalLen > bufLen - 1) { // bufLen includes terminator
|
||||
error("Formatted string value too long\n");
|
||||
totalLen = bufLen - 1;
|
||||
if (len > totalLen)
|
||||
@@ -182,7 +182,7 @@ void fmt_PrintNumber(char *buf, size_t bufLen, struct FormatSpec const *fmt, uin
|
||||
if (fmt->type == 's')
|
||||
error("Formatting number as type 's'\n");
|
||||
|
||||
char sign = fmt->sign; /* 0 or ' ' or '+' */
|
||||
char sign = fmt->sign; // 0 or ' ' or '+'
|
||||
|
||||
if (fmt->type == 'd' || fmt->type == 'f') {
|
||||
int32_t v = value;
|
||||
@@ -200,10 +200,10 @@ void fmt_PrintNumber(char *buf, size_t bufLen, struct FormatSpec const *fmt, uin
|
||||
: fmt->type == 'o' ? '&'
|
||||
: 0;
|
||||
|
||||
char valueBuf[262]; /* Max 5 digits + decimal + 255 fraction digits + terminator */
|
||||
char valueBuf[262]; // Max 5 digits + decimal + 255 fraction digits + terminator
|
||||
|
||||
if (fmt->type == 'b') {
|
||||
/* Special case for binary */
|
||||
// Special case for binary
|
||||
char *ptr = valueBuf;
|
||||
|
||||
do {
|
||||
@@ -213,7 +213,7 @@ void fmt_PrintNumber(char *buf, size_t bufLen, struct FormatSpec const *fmt, uin
|
||||
|
||||
*ptr = '\0';
|
||||
|
||||
/* Reverse the digits */
|
||||
// Reverse the digits
|
||||
size_t valueLen = ptr - valueBuf;
|
||||
|
||||
for (size_t i = 0, j = valueLen - 1; i < j; i++, j--) {
|
||||
@@ -223,9 +223,9 @@ void fmt_PrintNumber(char *buf, size_t bufLen, struct FormatSpec const *fmt, uin
|
||||
valueBuf[j] = c;
|
||||
}
|
||||
} else if (fmt->type == 'f') {
|
||||
/* Special case for fixed-point */
|
||||
// Special case for fixed-point
|
||||
|
||||
/* Default fractional width (C's is 6 for "%f"; here 5 is enough) */
|
||||
// Default fractional width (C's is 6 for "%f"; here 5 is enough)
|
||||
size_t fracWidth = fmt->hasFrac ? fmt->fracWidth : 5;
|
||||
|
||||
if (fracWidth > 255) {
|
||||
@@ -250,7 +250,7 @@ void fmt_PrintNumber(char *buf, size_t bufLen, struct FormatSpec const *fmt, uin
|
||||
size_t numLen = !!sign + !!prefix + len;
|
||||
size_t totalLen = fmt->width > numLen ? fmt->width : numLen;
|
||||
|
||||
if (totalLen > bufLen - 1) { /* bufLen includes terminator */
|
||||
if (totalLen > bufLen - 1) { // bufLen includes terminator
|
||||
error("Formatted numeric value too long\n");
|
||||
totalLen = bufLen - 1;
|
||||
if (numLen > totalLen) {
|
||||
@@ -273,7 +273,7 @@ void fmt_PrintNumber(char *buf, size_t bufLen, struct FormatSpec const *fmt, uin
|
||||
buf[i] = ' ';
|
||||
} else {
|
||||
if (fmt->padZero) {
|
||||
/* sign, then prefix, then zero padding */
|
||||
// sign, then prefix, then zero padding
|
||||
if (sign)
|
||||
buf[pos++] = sign;
|
||||
if (prefix)
|
||||
@@ -281,7 +281,7 @@ void fmt_PrintNumber(char *buf, size_t bufLen, struct FormatSpec const *fmt, uin
|
||||
for (size_t i = 0; i < padLen; i++)
|
||||
buf[pos++] = '0';
|
||||
} else {
|
||||
/* space padding, then sign, then prefix */
|
||||
// space padding, then sign, then prefix
|
||||
for (size_t i = 0; i < padLen; i++)
|
||||
buf[pos++] = ' ';
|
||||
if (sign)
|
||||
|
||||
@@ -19,7 +19,7 @@
|
||||
#include "asm/main.h"
|
||||
#include "asm/symbol.h"
|
||||
#include "asm/warning.h"
|
||||
#include "platform.h" /* S_ISDIR (stat macro) */
|
||||
#include "platform.h" // S_ISDIR (stat macro)
|
||||
|
||||
#define MAXINCPATHS 128
|
||||
|
||||
@@ -28,7 +28,7 @@ struct Context {
|
||||
struct FileStackNode *fileInfo;
|
||||
struct LexerState *lexerState;
|
||||
uint32_t uniqueID;
|
||||
struct MacroArgs *macroArgs; /* Macro args are *saved* here */
|
||||
struct MacroArgs *macroArgs; // Macro args are *saved* here
|
||||
uint32_t nbReptIters;
|
||||
int32_t forValue;
|
||||
int32_t forStep;
|
||||
@@ -47,7 +47,7 @@ static const char *dumpNodeAndParents(struct FileStackNode const *node)
|
||||
char const *name;
|
||||
|
||||
if (node->type == NODE_REPT) {
|
||||
assert(node->parent); /* REPT nodes should always have a parent */
|
||||
assert(node->parent); // REPT nodes should always have a parent
|
||||
struct FileStackReptNode const *reptInfo = (struct FileStackReptNode const *)node;
|
||||
|
||||
name = dumpNodeAndParents(node->parent);
|
||||
@@ -88,7 +88,7 @@ struct FileStackNode *fstk_GetFileStack(void)
|
||||
|
||||
struct FileStackNode *node = contextStack->fileInfo;
|
||||
|
||||
/* Mark node and all of its parents as referenced if not already so they don't get freed */
|
||||
// Mark node and all of its parents as referenced if not already so they don't get freed
|
||||
while (node && !node->referenced) {
|
||||
node->ID = -1;
|
||||
node->referenced = true;
|
||||
@@ -99,7 +99,7 @@ struct FileStackNode *fstk_GetFileStack(void)
|
||||
|
||||
char const *fstk_GetFileName(void)
|
||||
{
|
||||
/* Iterating via the nodes themselves skips nested REPTs */
|
||||
// Iterating via the nodes themselves skips nested REPTs
|
||||
struct FileStackNode const *node = contextStack->fileInfo;
|
||||
|
||||
while (node->type != NODE_FILE)
|
||||
@@ -120,7 +120,7 @@ void fstk_AddIncludePath(char const *path)
|
||||
char *str = malloc(allocSize);
|
||||
|
||||
if (!str) {
|
||||
/* Attempt to continue without that path */
|
||||
// Attempt to continue without that path
|
||||
error("Failed to allocate new include path: %s\n", strerror(errno));
|
||||
return;
|
||||
}
|
||||
@@ -149,14 +149,14 @@ static bool isPathValid(char const *path)
|
||||
if (stat(path, &statbuf) != 0)
|
||||
return false;
|
||||
|
||||
/* Reject directories */
|
||||
// Reject directories
|
||||
return !S_ISDIR(statbuf.st_mode);
|
||||
}
|
||||
|
||||
bool fstk_FindFile(char const *path, char **fullPath, size_t *size)
|
||||
{
|
||||
if (!*size) {
|
||||
*size = 64; /* This is arbitrary, really */
|
||||
*size = 64; // This is arbitrary, really
|
||||
*fullPath = realloc(*fullPath, *size);
|
||||
if (!*fullPath)
|
||||
error("realloc error during include path search: %s\n",
|
||||
@@ -174,8 +174,8 @@ bool fstk_FindFile(char const *path, char **fullPath, size_t *size)
|
||||
break;
|
||||
}
|
||||
|
||||
/* Oh how I wish `asnprintf` was standard... */
|
||||
if ((size_t)len >= *size) { /* `len` doesn't include the terminator, `size` does */
|
||||
// Oh how I wish `asnprintf` was standard...
|
||||
if ((size_t)len >= *size) { // `size` includes the terminator, `len` doesn't
|
||||
*size = len + 1;
|
||||
*fullPath = realloc(*fullPath, *size);
|
||||
if (!*fullPath) {
|
||||
@@ -212,17 +212,18 @@ bool yywrap(void)
|
||||
fatalerror("Ended block with %" PRIu32 " unterminated IF construct%s\n",
|
||||
ifDepth, ifDepth == 1 ? "" : "s");
|
||||
|
||||
if (contextStack->fileInfo->type == NODE_REPT) { /* The context is a REPT block, which may loop */
|
||||
if (contextStack->fileInfo->type == NODE_REPT) {
|
||||
// The context is a REPT or FOR block, which may loop
|
||||
struct FileStackReptNode *fileInfo = (struct FileStackReptNode *)contextStack->fileInfo;
|
||||
|
||||
/* If the node is referenced, we can't edit it; duplicate it */
|
||||
// If the node is referenced, we can't edit it; duplicate it
|
||||
if (contextStack->fileInfo->referenced) {
|
||||
size_t size = sizeof(*fileInfo) + sizeof(fileInfo->iters[0]) * fileInfo->reptDepth;
|
||||
struct FileStackReptNode *copy = malloc(size);
|
||||
|
||||
if (!copy)
|
||||
fatalerror("Failed to duplicate REPT file node: %s\n", strerror(errno));
|
||||
/* Copy all info but the referencing */
|
||||
// Copy all info but the referencing
|
||||
memcpy(copy, fileInfo, size);
|
||||
copy->node.next = NULL;
|
||||
copy->node.referenced = false;
|
||||
@@ -231,19 +232,19 @@ bool yywrap(void)
|
||||
contextStack->fileInfo = (struct FileStackNode *)fileInfo;
|
||||
}
|
||||
|
||||
/* If this is a FOR, update the symbol value */
|
||||
// If this is a FOR, update the symbol value
|
||||
if (contextStack->forName && fileInfo->iters[0] <= contextStack->nbReptIters) {
|
||||
contextStack->forValue += contextStack->forStep;
|
||||
struct Symbol *sym = sym_AddVar(contextStack->forName,
|
||||
contextStack->forValue);
|
||||
|
||||
/* This error message will refer to the current iteration */
|
||||
// This error message will refer to the current iteration
|
||||
if (sym->type != SYM_VAR)
|
||||
fatalerror("Failed to update FOR symbol value\n");
|
||||
}
|
||||
/* Advance to the next iteration */
|
||||
// Advance to the next iteration
|
||||
fileInfo->iters[0]++;
|
||||
/* If this wasn't the last iteration, wrap instead of popping */
|
||||
// If this wasn't the last iteration, wrap instead of popping
|
||||
if (fileInfo->iters[0] <= contextStack->nbReptIters) {
|
||||
lexer_RestartRept(contextStack->fileInfo->lineNo);
|
||||
contextStack->uniqueID = macro_UseNewUniqueID();
|
||||
@@ -260,15 +261,15 @@ bool yywrap(void)
|
||||
contextDepth--;
|
||||
|
||||
lexer_DeleteState(context->lexerState);
|
||||
/* Restore args if a macro (not REPT) saved them */
|
||||
// Restore args if a macro (not REPT) saved them
|
||||
if (context->fileInfo->type == NODE_MACRO)
|
||||
macro_UseNewArgs(contextStack->macroArgs);
|
||||
/* Free the file stack node */
|
||||
// Free the file stack node
|
||||
if (!context->fileInfo->referenced)
|
||||
free(context->fileInfo);
|
||||
/* Free the FOR symbol name */
|
||||
// Free the FOR symbol name
|
||||
free(context->forName);
|
||||
/* Free the entry and make its parent the current entry */
|
||||
// Free the entry and make its parent the current entry
|
||||
free(context);
|
||||
|
||||
lexer_SetState(contextStack->lexerState);
|
||||
@@ -276,11 +277,9 @@ bool yywrap(void)
|
||||
return false;
|
||||
}
|
||||
|
||||
/*
|
||||
* 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->lexerState after this so it is not NULL
|
||||
*/
|
||||
// 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->lexerState after this so it is not NULL.
|
||||
static void newContext(struct FileStackNode *fileInfo)
|
||||
{
|
||||
++contextDepth;
|
||||
@@ -291,15 +290,14 @@ static void newContext(struct FileStackNode *fileInfo)
|
||||
if (!context)
|
||||
fatalerror("Failed to allocate memory for new context: %s\n", strerror(errno));
|
||||
fileInfo->parent = contextStack->fileInfo;
|
||||
fileInfo->lineNo = 0; /* Init to a default value, see struct definition for info */
|
||||
fileInfo->lineNo = 0; // Init to a default value, see struct definition for info
|
||||
fileInfo->referenced = false;
|
||||
fileInfo->lineNo = lexer_GetLineNo();
|
||||
context->fileInfo = fileInfo;
|
||||
context->forName = NULL;
|
||||
/*
|
||||
* Link new entry to its parent so it's reachable later
|
||||
* ERRORS SHOULD NOT OCCUR AFTER THIS!!
|
||||
*/
|
||||
|
||||
// Link new entry to its parent so it's reachable later
|
||||
// ERRORS SHOULD NOT OCCUR AFTER THIS!!
|
||||
context->parent = contextStack;
|
||||
contextStack = context;
|
||||
}
|
||||
@@ -337,7 +335,7 @@ void fstk_RunInclude(char const *path)
|
||||
if (!contextStack->lexerState)
|
||||
fatalerror("Failed to set up lexer for file include\n");
|
||||
lexer_SetStateAtEOL(contextStack->lexerState);
|
||||
/* We're back at top-level, so most things are reset */
|
||||
// We're back at top-level, so most things are reset
|
||||
contextStack->uniqueID = 0;
|
||||
macro_SetUniqueID(0);
|
||||
}
|
||||
@@ -356,16 +354,16 @@ void fstk_RunMacro(char const *macroName, struct MacroArgs *args)
|
||||
}
|
||||
contextStack->macroArgs = macro_GetCurrentArgs();
|
||||
|
||||
/* Compute total length of this node's name: <base name>::<macro> */
|
||||
// Compute total length of this node's name: <base name>::<macro>
|
||||
size_t reptNameLen = 0;
|
||||
struct FileStackNode const *node = macro->src;
|
||||
|
||||
if (node->type == NODE_REPT) {
|
||||
struct FileStackReptNode const *reptNode = (struct FileStackReptNode const *)node;
|
||||
|
||||
/* 4294967295 = 2^32 - 1, aka UINT32_MAX */
|
||||
// 4294967295 = 2^32 - 1, aka UINT32_MAX
|
||||
reptNameLen += reptNode->reptDepth * strlen("::REPT~4294967295");
|
||||
/* Look for next named node */
|
||||
// Look for next named node
|
||||
do {
|
||||
node = node->parent;
|
||||
} while (node->type == NODE_REPT);
|
||||
@@ -381,7 +379,7 @@ void fstk_RunMacro(char const *macroName, struct MacroArgs *args)
|
||||
return;
|
||||
}
|
||||
fileInfo->node.type = NODE_MACRO;
|
||||
/* Print the name... */
|
||||
// Print the name...
|
||||
char *dest = fileInfo->name;
|
||||
|
||||
memcpy(dest, baseNode->name, baseLen);
|
||||
@@ -428,13 +426,13 @@ static bool newReptContext(int32_t reptLineNo, char *body, size_t size)
|
||||
fileInfo->reptDepth = reptDepth + 1;
|
||||
fileInfo->iters[0] = 1;
|
||||
if (reptDepth)
|
||||
/* Copy all parent iter counts */
|
||||
// Copy all parent iter counts
|
||||
memcpy(&fileInfo->iters[1],
|
||||
((struct FileStackReptNode *)contextStack->fileInfo)->iters,
|
||||
reptDepth * sizeof(fileInfo->iters[0]));
|
||||
|
||||
newContext((struct FileStackNode *)fileInfo);
|
||||
/* Correct our line number, which currently points to the `ENDR` line */
|
||||
// Correct our line number, which currently points to the `ENDR` line
|
||||
contextStack->fileInfo->lineNo = reptLineNo;
|
||||
|
||||
contextStack->lexerState = lexer_OpenFileView("REPT", body, size, reptLineNo);
|
||||
@@ -492,7 +490,7 @@ void fstk_RunFor(char const *symName, int32_t start, int32_t stop, int32_t step,
|
||||
|
||||
void fstk_StopRept(void)
|
||||
{
|
||||
/* Prevent more iterations */
|
||||
// Prevent more iterations
|
||||
contextStack->nbReptIters = 0;
|
||||
}
|
||||
|
||||
@@ -532,7 +530,7 @@ void fstk_Init(char const *mainPath, size_t maxDepth)
|
||||
fatalerror("Failed to allocate memory for main file info: %s\n", strerror(errno));
|
||||
|
||||
context->fileInfo = (struct FileStackNode *)fileInfo;
|
||||
/* lineNo and reptIter are unused on the top-level context */
|
||||
// lineNo and reptIter are unused on the top-level context
|
||||
context->fileInfo->parent = NULL;
|
||||
context->fileInfo->lineNo = 0; // This still gets written to the object file, so init it
|
||||
context->fileInfo->referenced = false;
|
||||
@@ -548,13 +546,11 @@ void fstk_Init(char const *mainPath, size_t maxDepth)
|
||||
context->forStep = 0;
|
||||
context->forName = NULL;
|
||||
|
||||
/* Now that it's set up properly, register the context */
|
||||
// Now that it's set up properly, register the context
|
||||
contextStack = context;
|
||||
|
||||
/*
|
||||
* Check that max recursion depth won't allow overflowing node `malloc`s
|
||||
* This assumes that the rept node is larger
|
||||
*/
|
||||
// Check that max recursion depth won't allow overflowing node `malloc`s
|
||||
// This assumes that the rept node is larger
|
||||
#define DEPTH_LIMIT ((SIZE_MAX - sizeof(struct FileStackReptNode)) / sizeof(uint32_t))
|
||||
if (maxDepth > DEPTH_LIMIT) {
|
||||
error("Recursion depth may not be higher than %zu, defaulting to "
|
||||
@@ -563,7 +559,7 @@ void fstk_Init(char const *mainPath, size_t maxDepth)
|
||||
} else {
|
||||
maxRecursionDepth = maxDepth;
|
||||
}
|
||||
/* Make sure that the default of 64 is OK, though */
|
||||
// Make sure that the default of 64 is OK, though
|
||||
assert(DEPTH_LIMIT >= DEFAULT_MAX_DEPTH);
|
||||
#undef DEPTH_LIMIT
|
||||
}
|
||||
|
||||
524
src/asm/lexer.c
524
src/asm/lexer.c
File diff suppressed because it is too large
Load Diff
@@ -1,3 +1,10 @@
|
||||
/*
|
||||
* This file is part of RGBDS.
|
||||
*
|
||||
* Copyright (c) 2022, Eldred Habert and RGBDS contributors.
|
||||
*
|
||||
* SPDX-License-Identifier: MIT
|
||||
*/
|
||||
|
||||
#include <assert.h>
|
||||
#include <errno.h>
|
||||
@@ -12,13 +19,11 @@
|
||||
|
||||
#define MAXMACROARGS 99999
|
||||
|
||||
/*
|
||||
* Your average macro invocation does not go past the tens, but some go further
|
||||
* This ensures that sane and slightly insane invocations suffer no penalties,
|
||||
* and the rest is insane and thus will assume responsibility.
|
||||
* Additionally, ~300 bytes (on x64) of memory per level of nesting has been
|
||||
* deemed reasonable. (Halve that on x86.)
|
||||
*/
|
||||
// Your average macro invocation does not go past the tens, but some go further
|
||||
// This ensures that sane and slightly insane invocations suffer no penalties,
|
||||
// and the rest is insane and thus will assume responsibility.
|
||||
// Additionally, ~300 bytes (on x64) of memory per level of nesting has been
|
||||
// deemed reasonable. (Halve that on x86.)
|
||||
#define INITIAL_ARG_SIZE 32
|
||||
struct MacroArgs {
|
||||
unsigned int nbArgs;
|
||||
@@ -33,11 +38,9 @@ struct MacroArgs {
|
||||
static struct MacroArgs *macroArgs = NULL;
|
||||
static uint32_t uniqueID = 0;
|
||||
static uint32_t maxUniqueID = 0;
|
||||
/*
|
||||
* The initialization is somewhat harmful, since it is never used, but it
|
||||
* guarantees the size of the buffer will be correct. I was unable to find a
|
||||
* better solution, but if you have one, please feel free!
|
||||
*/
|
||||
// The initialization is somewhat harmful, since it is never used, but it
|
||||
// guarantees the size of the buffer will be correct. I was unable to find a
|
||||
// better solution, but if you have one, please feel free!
|
||||
static char uniqueIDBuf[] = "_u4294967295"; // UINT32_MAX
|
||||
static char *uniqueIDPtr = NULL;
|
||||
|
||||
@@ -68,7 +71,7 @@ void macro_AppendArg(struct MacroArgs **argPtr, char *s)
|
||||
error("A maximum of " EXPAND_AND_STR(MAXMACROARGS) " arguments is allowed\n");
|
||||
if (macArgs->nbArgs >= macArgs->capacity) {
|
||||
macArgs->capacity *= 2;
|
||||
/* Check that overflow didn't roll us back */
|
||||
// Check that overflow didn't roll us back
|
||||
if (macArgs->capacity <= macArgs->nbArgs)
|
||||
fatalerror("Failed to add new macro argument: capacity overflow\n");
|
||||
macArgs = realloc(macArgs, SIZEOF_ARGS(macArgs->capacity));
|
||||
@@ -112,9 +115,9 @@ char const *macro_GetAllArgs(void)
|
||||
size_t len = 0;
|
||||
|
||||
for (uint32_t i = macroArgs->shift; i < macroArgs->nbArgs; i++)
|
||||
len += strlen(macroArgs->args[i]) + 1; /* 1 for comma */
|
||||
len += strlen(macroArgs->args[i]) + 1; // 1 for comma
|
||||
|
||||
char *str = malloc(len + 1); /* 1 for '\0' */
|
||||
char *str = malloc(len + 1); // 1 for '\0'
|
||||
char *ptr = str;
|
||||
|
||||
if (!str)
|
||||
@@ -126,9 +129,9 @@ char const *macro_GetAllArgs(void)
|
||||
memcpy(ptr, macroArgs->args[i], n);
|
||||
ptr += n;
|
||||
|
||||
/* Commas go between args and after a last empty arg */
|
||||
// Commas go between args and after a last empty arg
|
||||
if (i < macroArgs->nbArgs - 1 || n == 0)
|
||||
*ptr++ = ','; /* no space after comma */
|
||||
*ptr++ = ','; // no space after comma
|
||||
}
|
||||
*ptr = '\0';
|
||||
|
||||
@@ -153,8 +156,8 @@ void macro_SetUniqueID(uint32_t id)
|
||||
} else {
|
||||
if (uniqueID > maxUniqueID)
|
||||
maxUniqueID = uniqueID;
|
||||
/* The buffer is guaranteed to be the correct size */
|
||||
/* This is a valid label fragment, but not a valid numeric */
|
||||
// The buffer is guaranteed to be the correct size
|
||||
// This is a valid label fragment, but not a valid numeric
|
||||
sprintf(uniqueIDBuf, "_u%" PRIu32, id);
|
||||
uniqueIDPtr = uniqueIDBuf;
|
||||
}
|
||||
|
||||
@@ -39,8 +39,8 @@
|
||||
#ifdef __clang__
|
||||
#if __has_feature(address_sanitizer) && !defined(__SANITIZE_ADDRESS__)
|
||||
#define __SANITIZE_ADDRESS__
|
||||
#endif /* __has_feature(address_sanitizer) && !defined(__SANITIZE_ADDRESS__) */
|
||||
#endif /* __clang__ */
|
||||
#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'
|
||||
@@ -63,9 +63,9 @@ bool warnOnHaltNop;
|
||||
bool optimizeLoads;
|
||||
bool warnOnLdOpt;
|
||||
bool verbose;
|
||||
bool warnings; /* True to enable warnings, false to disable them. */
|
||||
bool warnings; // True to enable warnings, false to disable them.
|
||||
|
||||
/* Escapes Make-special chars from a string */
|
||||
// Escapes Make-special chars from a string
|
||||
static char *make_escape(char const *str)
|
||||
{
|
||||
char * const escaped_str = malloc(strlen(str) * 2 + 1);
|
||||
@@ -75,7 +75,7 @@ static char *make_escape(char const *str)
|
||||
err("%s: Failed to allocate memory", __func__);
|
||||
|
||||
while (*str) {
|
||||
/* All dollars needs to be doubled */
|
||||
// All dollars needs to be doubled
|
||||
if (*str == '$')
|
||||
*dest++ = '$';
|
||||
*dest++ = *str++;
|
||||
@@ -85,22 +85,20 @@ static char *make_escape(char const *str)
|
||||
return escaped_str;
|
||||
}
|
||||
|
||||
/* Short options */
|
||||
// Short options
|
||||
static const char *optstring = "b:D:Eg:Hhi:LlM:o:p:r:VvW:w";
|
||||
|
||||
/* Variables for the long-only options */
|
||||
static int depType; /* Variants of `-M` */
|
||||
// Variables for the long-only options
|
||||
static int depType; // Variants of `-M`
|
||||
|
||||
/*
|
||||
* Equivalent long options
|
||||
* Please keep in the same order as short opts
|
||||
*
|
||||
* Also, make sure long opts don't create ambiguity:
|
||||
* A long opt's name should start with the same letter as its short opt,
|
||||
* except if it doesn't create any ambiguity (`verbose` versus `version`).
|
||||
* This is because long opt matching, even to a single char, is prioritized
|
||||
* over short opt matching
|
||||
*/
|
||||
// Equivalent long options
|
||||
// Please keep in the same order as short opts
|
||||
//
|
||||
// Also, make sure long opts don't create ambiguity:
|
||||
// A long opt's name should start with the same letter as its short opt,
|
||||
// except if it doesn't create any ambiguity (`verbose` versus `version`).
|
||||
// This is because long opt matching, even to a single char, is prioritized
|
||||
// over short opt matching
|
||||
static struct option const longopts[] = {
|
||||
{ "binary-digits", required_argument, NULL, 'b' },
|
||||
{ "define", required_argument, NULL, 'D' },
|
||||
@@ -152,10 +150,8 @@ int main(int argc, char *argv[])
|
||||
time_t now = time(NULL);
|
||||
char const *sourceDateEpoch = getenv("SOURCE_DATE_EPOCH");
|
||||
|
||||
/*
|
||||
* Support SOURCE_DATE_EPOCH for reproducible builds
|
||||
* https://reproducible-builds.org/docs/source-date-epoch/
|
||||
*/
|
||||
// Support SOURCE_DATE_EPOCH for reproducible builds
|
||||
// https://reproducible-builds.org/docs/source-date-epoch/
|
||||
if (sourceDateEpoch)
|
||||
now = (time_t)strtoul(sourceDateEpoch, NULL, 0);
|
||||
|
||||
@@ -289,7 +285,7 @@ int main(int argc, char *argv[])
|
||||
warnings = false;
|
||||
break;
|
||||
|
||||
/* Long-only options */
|
||||
// Long-only options
|
||||
case 0:
|
||||
switch (depType) {
|
||||
case 'G':
|
||||
@@ -321,10 +317,10 @@ int main(int argc, char *argv[])
|
||||
}
|
||||
break;
|
||||
|
||||
/* Unrecognized options */
|
||||
// Unrecognized options
|
||||
default:
|
||||
print_usage();
|
||||
/* NOTREACHED */
|
||||
// NOTREACHED
|
||||
}
|
||||
}
|
||||
|
||||
@@ -376,7 +372,7 @@ int main(int argc, char *argv[])
|
||||
if (failedOnMissingInclude)
|
||||
return 0;
|
||||
|
||||
/* If no path specified, don't write file */
|
||||
// If no path specified, don't write file
|
||||
if (objectName != NULL)
|
||||
out_WriteObject();
|
||||
return 0;
|
||||
|
||||
@@ -1,3 +1,11 @@
|
||||
/*
|
||||
* This file is part of RGBDS.
|
||||
*
|
||||
* Copyright (c) 2022, RGBDS contributors.
|
||||
*
|
||||
* SPDX-License-Identifier: MIT
|
||||
*/
|
||||
|
||||
#include <ctype.h>
|
||||
#include <errno.h>
|
||||
#include <stdbool.h>
|
||||
|
||||
@@ -6,9 +6,7 @@
|
||||
* SPDX-License-Identifier: MIT
|
||||
*/
|
||||
|
||||
/*
|
||||
* Outputs an objectfile
|
||||
*/
|
||||
// Outputs an objectfile
|
||||
|
||||
#include <assert.h>
|
||||
#include <errno.h>
|
||||
@@ -54,18 +52,16 @@ char *objectName;
|
||||
|
||||
struct Section *sectionList;
|
||||
|
||||
/* Linked list of symbols to put in the object file */
|
||||
// Linked list of symbols to put in the object file
|
||||
static struct Symbol *objectSymbols = NULL;
|
||||
static struct Symbol **objectSymbolsTail = &objectSymbols;
|
||||
static uint32_t nbSymbols = 0; /* Length of the above list */
|
||||
static uint32_t nbSymbols = 0; // Length of the above list
|
||||
|
||||
static struct Assertion *assertions = NULL;
|
||||
|
||||
static struct FileStackNode *fileStackNodes = NULL;
|
||||
|
||||
/*
|
||||
* Count the number of sections used in this object
|
||||
*/
|
||||
// Count the number of sections used in this object
|
||||
static uint32_t countSections(void)
|
||||
{
|
||||
uint32_t count = 0;
|
||||
@@ -76,9 +72,7 @@ static uint32_t countSections(void)
|
||||
return count;
|
||||
}
|
||||
|
||||
/*
|
||||
* Count the number of patches used in this object
|
||||
*/
|
||||
// Count the number of patches used in this object
|
||||
static uint32_t countPatches(struct Section const *sect)
|
||||
{
|
||||
uint32_t r = 0;
|
||||
@@ -90,9 +84,7 @@ static uint32_t countPatches(struct Section const *sect)
|
||||
return r;
|
||||
}
|
||||
|
||||
/**
|
||||
* Count the number of assertions used in this object
|
||||
*/
|
||||
// Count the number of assertions used in this object
|
||||
static uint32_t countAsserts(void)
|
||||
{
|
||||
struct Assertion *assert = assertions;
|
||||
@@ -105,9 +97,7 @@ static uint32_t countAsserts(void)
|
||||
return count;
|
||||
}
|
||||
|
||||
/*
|
||||
* Write a long to a file (little-endian)
|
||||
*/
|
||||
// Write a long to a file (little-endian)
|
||||
static void putlong(uint32_t i, FILE *f)
|
||||
{
|
||||
putc(i, f);
|
||||
@@ -116,9 +106,7 @@ static void putlong(uint32_t i, FILE *f)
|
||||
putc(i >> 24, f);
|
||||
}
|
||||
|
||||
/*
|
||||
* Write a NULL-terminated string to a file
|
||||
*/
|
||||
// Write a NULL-terminated string to a file
|
||||
static void putstring(char const *s, FILE *f)
|
||||
{
|
||||
while (*s)
|
||||
@@ -133,7 +121,7 @@ static uint32_t getNbFileStackNodes(void)
|
||||
|
||||
void out_RegisterNode(struct FileStackNode *node)
|
||||
{
|
||||
/* If node is not already registered, register it (and parents), and give it a unique ID */
|
||||
// If node is not already registered, register it (and parents), and give it a unique ID
|
||||
while (node->ID == (uint32_t)-1) {
|
||||
node->ID = getNbFileStackNodes();
|
||||
if (node->ID == (uint32_t)-1)
|
||||
@@ -141,7 +129,7 @@ void out_RegisterNode(struct FileStackNode *node)
|
||||
node->next = fileStackNodes;
|
||||
fileStackNodes = node;
|
||||
|
||||
/* Also register the node's parents */
|
||||
// Also register the node's parents
|
||||
node = node->parent;
|
||||
if (!node)
|
||||
break;
|
||||
@@ -156,25 +144,21 @@ This is code intended to replace a node, which is pretty useless until ref count
|
||||
|
||||
struct FileStackNode **ptr = &fileStackNodes;
|
||||
|
||||
/*
|
||||
* The linked list is supposed to have decrementing IDs, so iterate with less memory reads,
|
||||
* to hopefully hit the cache less. A debug check is added after, in case a change is made
|
||||
* that breaks this assumption.
|
||||
*/
|
||||
// The linked list is supposed to have decrementing IDs, so iterate with less memory reads,
|
||||
// to hopefully hit the cache less. A debug check is added after, in case a change is made
|
||||
// that breaks this assumption.
|
||||
for (uint32_t i = fileStackNodes->ID; i != node->ID; i--)
|
||||
ptr = &(*ptr)->next;
|
||||
assert((*ptr)->ID == node->ID);
|
||||
|
||||
node->next = (*ptr)->next;
|
||||
assert(!node->next || node->next->ID == node->ID - 1); /* Catch inconsistencies early */
|
||||
/* TODO: unreference the node */
|
||||
assert(!node->next || node->next->ID == node->ID - 1); // Catch inconsistencies early
|
||||
// TODO: unreference the node
|
||||
*ptr = node;
|
||||
#endif
|
||||
}
|
||||
|
||||
/*
|
||||
* Return a section's ID
|
||||
*/
|
||||
// Return a section's ID
|
||||
static uint32_t getsectid(struct Section const *sect)
|
||||
{
|
||||
struct Section const *sec = sectionList;
|
||||
@@ -195,9 +179,7 @@ static uint32_t getSectIDIfAny(struct Section const *sect)
|
||||
return sect ? getsectid(sect) : (uint32_t)-1;
|
||||
}
|
||||
|
||||
/*
|
||||
* Write a patch to a file
|
||||
*/
|
||||
// Write a patch to a file
|
||||
static void writepatch(struct Patch const *patch, FILE *f)
|
||||
{
|
||||
assert(patch->src->ID != (uint32_t)-1);
|
||||
@@ -211,9 +193,7 @@ static void writepatch(struct Patch const *patch, FILE *f)
|
||||
fwrite(patch->rpn, 1, patch->rpnSize, f);
|
||||
}
|
||||
|
||||
/*
|
||||
* Write a section to a file
|
||||
*/
|
||||
// Write a section to a file
|
||||
static void writesection(struct Section const *sect, FILE *f)
|
||||
{
|
||||
putstring(sect->name, f);
|
||||
@@ -255,9 +235,7 @@ static void freesection(struct Section const *sect)
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Write a symbol to a file
|
||||
*/
|
||||
// Write a symbol to a file
|
||||
static void writesymbol(struct Symbol const *sym, FILE *f)
|
||||
{
|
||||
putstring(sym->name, f);
|
||||
@@ -285,10 +263,8 @@ static void registerSymbol(struct Symbol *sym)
|
||||
sym->ID = nbSymbols++;
|
||||
}
|
||||
|
||||
/*
|
||||
* Returns a symbol's ID within the object file
|
||||
* If the symbol does not have one, one is assigned by registering the symbol
|
||||
*/
|
||||
// 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(struct Symbol *sym)
|
||||
{
|
||||
if (sym->ID == (uint32_t)-1 && !sym_IsPC(sym))
|
||||
@@ -392,10 +368,8 @@ static void writerpn(uint8_t *rpnexpr, uint32_t *rpnptr, uint8_t *rpn,
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Allocate a new patch structure and link it into the list
|
||||
* WARNING: all patches are assumed to eventually be written, so the file stack node is registered
|
||||
*/
|
||||
// Allocate a new patch structure and link it into the list
|
||||
// WARNING: all patches are assumed to eventually be written, so the file stack node is registered
|
||||
static struct Patch *allocpatch(uint32_t type, struct Expression const *expr, uint32_t ofs)
|
||||
{
|
||||
struct Patch *patch = malloc(sizeof(struct Patch));
|
||||
@@ -417,10 +391,10 @@ static struct Patch *allocpatch(uint32_t type, struct Expression const *expr, ui
|
||||
patch->pcSection = sect_GetSymbolSection();
|
||||
patch->pcOffset = sect_GetSymbolOffset();
|
||||
|
||||
/* If the rpnSize's value is known, output a constant RPN rpnSize directly */
|
||||
// If the rpnSize's value is known, output a constant RPN rpnSize directly
|
||||
if (expr->isKnown) {
|
||||
patch->rpnSize = rpnSize;
|
||||
/* Make sure to update `rpnSize` above if modifying this! */
|
||||
// Make sure to update `rpnSize` above if modifying this!
|
||||
patch->rpn[0] = RPN_CONST;
|
||||
patch->rpn[1] = (uint32_t)(expr->val) & 0xFF;
|
||||
patch->rpn[2] = (uint32_t)(expr->val) >> 8;
|
||||
@@ -435,9 +409,7 @@ static struct Patch *allocpatch(uint32_t type, struct Expression const *expr, ui
|
||||
return patch;
|
||||
}
|
||||
|
||||
/*
|
||||
* Create a new patch (includes the rpn expr)
|
||||
*/
|
||||
// Create a new patch (includes the rpn expr)
|
||||
void out_CreatePatch(uint32_t type, struct Expression const *expr, uint32_t ofs, uint32_t pcShift)
|
||||
{
|
||||
struct Patch *patch = allocpatch(type, expr, ofs);
|
||||
@@ -451,9 +423,7 @@ void out_CreatePatch(uint32_t type, struct Expression const *expr, uint32_t ofs,
|
||||
currentSection->patches = patch;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates an assert that will be written to the object file
|
||||
*/
|
||||
// Creates an assert that will be written to the object file
|
||||
bool out_CreateAssert(enum AssertionType type, struct Expression const *expr,
|
||||
char const *message, uint32_t ofs)
|
||||
{
|
||||
@@ -499,7 +469,7 @@ static void writeFileStackNode(struct FileStackNode const *node, FILE *f)
|
||||
struct FileStackReptNode const *reptNode = (struct FileStackReptNode const *)node;
|
||||
|
||||
putlong(reptNode->reptDepth, f);
|
||||
/* Iters are stored by decreasing depth, so reverse the order for output */
|
||||
// Iters are stored by decreasing depth, so reverse the order for output
|
||||
for (uint32_t i = reptNode->reptDepth; i--; )
|
||||
putlong(reptNode->iters[i], f);
|
||||
}
|
||||
@@ -515,9 +485,7 @@ static void registerUnregisteredSymbol(struct Symbol *symbol, void *arg)
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Write an objectfile
|
||||
*/
|
||||
// Write an objectfile
|
||||
void out_WriteObject(void)
|
||||
{
|
||||
FILE *f;
|
||||
@@ -529,7 +497,7 @@ void out_WriteObject(void)
|
||||
if (!f)
|
||||
err("Couldn't write file '%s'", objectName);
|
||||
|
||||
/* Also write symbols that weren't written above */
|
||||
// Also write symbols that weren't written above
|
||||
sym_ForEach(registerUnregisteredSymbol, NULL);
|
||||
|
||||
fprintf(f, RGBDS_OBJECT_VERSION_STRING);
|
||||
@@ -569,9 +537,7 @@ void out_WriteObject(void)
|
||||
fclose(f);
|
||||
}
|
||||
|
||||
/*
|
||||
* Set the objectfilename
|
||||
*/
|
||||
// Set the objectfilename
|
||||
void out_SetFileName(char *s)
|
||||
{
|
||||
objectName = s;
|
||||
|
||||
@@ -36,7 +36,7 @@
|
||||
#include "linkdefs.h"
|
||||
#include "platform.h" // strncasecmp, strdup
|
||||
|
||||
static struct CaptureBody captureBody; /* Captures a REPT/FOR or MACRO */
|
||||
static struct CaptureBody captureBody; // Captures a REPT/FOR or MACRO
|
||||
|
||||
static void upperstring(char *dest, char const *src)
|
||||
{
|
||||
@@ -104,14 +104,14 @@ static size_t strlenUTF8(char const *s)
|
||||
case 1:
|
||||
errorInvalidUTF8Byte(byte, "STRLEN");
|
||||
state = 0;
|
||||
/* fallthrough */
|
||||
// fallthrough
|
||||
case 0:
|
||||
len++;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/* Check for partial code point. */
|
||||
// Check for partial code point.
|
||||
if (state != 0)
|
||||
error("STRLEN: Incomplete UTF-8 character\n");
|
||||
|
||||
@@ -127,13 +127,13 @@ static void strsubUTF8(char *dest, size_t destLen, char const *src, uint32_t pos
|
||||
uint32_t curLen = 0;
|
||||
uint32_t curPos = 1;
|
||||
|
||||
/* Advance to starting position in source string. */
|
||||
// Advance to starting position in source string.
|
||||
while (src[srcIndex] && curPos < pos) {
|
||||
switch (decode(&state, &codep, src[srcIndex])) {
|
||||
case 1:
|
||||
errorInvalidUTF8Byte(src[srcIndex], "STRSUB");
|
||||
state = 0;
|
||||
/* fallthrough */
|
||||
// fallthrough
|
||||
case 0:
|
||||
curPos++;
|
||||
break;
|
||||
@@ -141,21 +141,19 @@ static void strsubUTF8(char *dest, size_t destLen, char const *src, uint32_t pos
|
||||
srcIndex++;
|
||||
}
|
||||
|
||||
/*
|
||||
* A position 1 past the end of the string is allowed, but will trigger the
|
||||
* "Length too big" warning below if the length is nonzero.
|
||||
*/
|
||||
// A position 1 past the end of the string is allowed, but will trigger the
|
||||
// "Length too big" warning below if the length is nonzero.
|
||||
if (!src[srcIndex] && pos > curPos)
|
||||
warning(WARNING_BUILTIN_ARG,
|
||||
"STRSUB: Position %" PRIu32 " is past the end of the string\n", pos);
|
||||
|
||||
/* Copy from source to destination. */
|
||||
// Copy from source to destination.
|
||||
while (src[srcIndex] && destIndex < destLen - 1 && curLen < len) {
|
||||
switch (decode(&state, &codep, src[srcIndex])) {
|
||||
case 1:
|
||||
errorInvalidUTF8Byte(src[srcIndex], "STRSUB");
|
||||
state = 0;
|
||||
/* fallthrough */
|
||||
// fallthrough
|
||||
case 0:
|
||||
curLen++;
|
||||
break;
|
||||
@@ -166,7 +164,7 @@ static void strsubUTF8(char *dest, size_t destLen, char const *src, uint32_t pos
|
||||
if (curLen < len)
|
||||
warning(WARNING_BUILTIN_ARG, "STRSUB: Length too big: %" PRIu32 "\n", len);
|
||||
|
||||
/* Check for partial code point. */
|
||||
// Check for partial code point.
|
||||
if (state != 0)
|
||||
error("STRSUB: Incomplete UTF-8 character\n");
|
||||
|
||||
@@ -187,7 +185,7 @@ static void charsubUTF8(char *dest, char const *src, uint32_t pos)
|
||||
{
|
||||
size_t charLen = 1;
|
||||
|
||||
/* Advance to starting position in source string. */
|
||||
// Advance to starting position in source string.
|
||||
for (uint32_t curPos = 1; charLen && curPos < pos; curPos++)
|
||||
charLen = charmap_ConvertNext(&src, NULL);
|
||||
|
||||
@@ -197,7 +195,7 @@ static void charsubUTF8(char *dest, char const *src, uint32_t pos)
|
||||
warning(WARNING_BUILTIN_ARG,
|
||||
"CHARSUB: Position %" PRIu32 " is past the end of the string\n", pos);
|
||||
|
||||
/* Copy from source to destination. */
|
||||
// Copy from source to destination.
|
||||
memcpy(dest, start, src - start);
|
||||
|
||||
dest[src - start] = '\0';
|
||||
@@ -205,10 +203,8 @@ static void charsubUTF8(char *dest, char const *src, uint32_t pos)
|
||||
|
||||
static uint32_t adjustNegativePos(int32_t pos, size_t len, char const *functionName)
|
||||
{
|
||||
/*
|
||||
* STRSUB and CHARSUB adjust negative `pos` arguments the same way,
|
||||
* such that position -1 is the last character of a string.
|
||||
*/
|
||||
// STRSUB and CHARSUB adjust negative `pos` arguments the same way,
|
||||
// such that position -1 is the last character of a string.
|
||||
if (pos < 0)
|
||||
pos += len + 1;
|
||||
if (pos < 1) {
|
||||
@@ -545,7 +541,7 @@ enum {
|
||||
%left T_OP_SHL T_OP_SHR T_OP_USHR
|
||||
%left T_OP_MUL T_OP_DIV T_OP_MOD
|
||||
|
||||
%precedence NEG /* negation -- unary minus */
|
||||
%precedence NEG // negation -- unary minus
|
||||
|
||||
%token T_OP_EXP "**"
|
||||
%left T_OP_EXP
|
||||
@@ -588,7 +584,6 @@ enum {
|
||||
%type <symName> scoped_id
|
||||
%type <symName> scoped_anon_id
|
||||
%token T_POP_EQU "EQU"
|
||||
%token T_POP_SET "SET"
|
||||
%token T_POP_EQUAL "="
|
||||
%token T_POP_EQUS "EQUS"
|
||||
|
||||
@@ -642,7 +637,7 @@ enum {
|
||||
%type <forArgs> for_args
|
||||
|
||||
%token T_Z80_ADC "adc" T_Z80_ADD "add" T_Z80_AND "and"
|
||||
%token T_Z80_BIT "bit" // There is no T_Z80_SET, only T_POP_SET
|
||||
%token T_Z80_BIT "bit"
|
||||
%token T_Z80_CALL "call" T_Z80_CCF "ccf" T_Z80_CP "cp" T_Z80_CPL "cpl"
|
||||
%token T_Z80_DAA "daa" T_Z80_DEC "dec" T_Z80_DI "di"
|
||||
%token T_Z80_EI "ei"
|
||||
@@ -659,7 +654,7 @@ enum {
|
||||
%token T_Z80_RES "res" T_Z80_RET "ret" T_Z80_RETI "reti" T_Z80_RST "rst"
|
||||
%token T_Z80_RL "rl" T_Z80_RLA "rla" T_Z80_RLC "rlc" T_Z80_RLCA "rlca"
|
||||
%token T_Z80_RR "rr" T_Z80_RRA "rra" T_Z80_RRC "rrc" T_Z80_RRCA "rrca"
|
||||
%token T_Z80_SBC "sbc" T_Z80_SCF "scf" T_Z80_STOP "stop"
|
||||
%token T_Z80_SBC "sbc" T_Z80_SCF "scf" T_Z80_SET "set" T_Z80_STOP "stop"
|
||||
%token T_Z80_SLA "sla" T_Z80_SRA "sra" T_Z80_SRL "srl" T_Z80_SUB "sub"
|
||||
%token T_Z80_SWAP "swap"
|
||||
%token T_Z80_XOR "xor"
|
||||
@@ -707,8 +702,8 @@ plain_directive : label
|
||||
;
|
||||
|
||||
line : plain_directive endofline
|
||||
| line_directive /* Directives that manage newlines themselves */
|
||||
/* Continue parsing the next line on a syntax error */
|
||||
| line_directive // Directives that manage newlines themselves
|
||||
// Continue parsing the next line on a syntax error
|
||||
| error {
|
||||
lexer_SetMode(LEXER_NORMAL);
|
||||
lexer_ToggleStringExpansion(true);
|
||||
@@ -716,7 +711,7 @@ line : plain_directive endofline
|
||||
fstk_StopRept();
|
||||
yyerrok;
|
||||
}
|
||||
/* Hint about unindented macros parsed as labels */
|
||||
// Hint about unindented macros parsed as labels
|
||||
| T_LABEL error {
|
||||
lexer_SetMode(LEXER_NORMAL);
|
||||
lexer_ToggleStringExpansion(true);
|
||||
@@ -731,19 +726,17 @@ line : plain_directive endofline
|
||||
}
|
||||
;
|
||||
|
||||
/*
|
||||
* For "logistical" reasons, these directives must manage newlines themselves.
|
||||
* This is because we need to switch the lexer's mode *after* the newline has been read,
|
||||
* and to avoid causing some grammar conflicts (token reducing is finicky).
|
||||
* This is DEFINITELY one of the more FRAGILE parts of the codebase, handle with care.
|
||||
*/
|
||||
// For "logistical" reasons, these directives must manage newlines themselves.
|
||||
// This is because we need to switch the lexer's mode *after* the newline has been read,
|
||||
// and to avoid causing some grammar conflicts (token reducing is finicky).
|
||||
// This is DEFINITELY one of the more FRAGILE parts of the codebase, handle with care.
|
||||
line_directive : macrodef
|
||||
| rept
|
||||
| for
|
||||
| break
|
||||
| include
|
||||
| if
|
||||
/* It's important that all of these require being at line start for `skipIfBlock` */
|
||||
// It's important that all of these require being at line start for `skipIfBlock`
|
||||
| elif
|
||||
| else
|
||||
;
|
||||
@@ -854,7 +847,7 @@ macroargs : %empty {
|
||||
}
|
||||
;
|
||||
|
||||
/* These commands start with a T_LABEL. */
|
||||
// These commands start with a T_LABEL.
|
||||
assignment_directive : equ
|
||||
| assignment
|
||||
| rb
|
||||
@@ -1300,7 +1293,7 @@ constlist_8bit_entry : reloc_8bit_no_str {
|
||||
sect_RelByte(&$1, 0);
|
||||
}
|
||||
| string {
|
||||
uint8_t *output = malloc(strlen($1)); /* Cannot be larger than that */
|
||||
uint8_t *output = malloc(strlen($1)); // Cannot be larger than that
|
||||
size_t length = charmap_Convert($1, output);
|
||||
|
||||
sect_AbsByteGroup(output, length);
|
||||
@@ -1316,7 +1309,7 @@ constlist_16bit_entry : reloc_16bit_no_str {
|
||||
sect_RelWord(&$1, 0);
|
||||
}
|
||||
| string {
|
||||
uint8_t *output = malloc(strlen($1)); /* Cannot be larger than that */
|
||||
uint8_t *output = malloc(strlen($1)); // Cannot be larger than that
|
||||
size_t length = charmap_Convert($1, output);
|
||||
|
||||
sect_AbsWordGroup(output, length);
|
||||
@@ -1681,7 +1674,7 @@ sectattrs : %empty {
|
||||
$$.alignOfs = $7;
|
||||
}
|
||||
| sectattrs T_COMMA T_OP_BANK T_LBRACK uconst T_RBRACK {
|
||||
/* We cannot check the validity of this now */
|
||||
// We cannot check the validity of this now
|
||||
$$.bank = $5;
|
||||
}
|
||||
;
|
||||
@@ -1998,10 +1991,8 @@ z80_ld_ss : T_Z80_LD T_MODE_BC T_COMMA reloc_16bit {
|
||||
sect_AbsByte(0x01 | (REG_DE << 4));
|
||||
sect_RelWord(&$4, 1);
|
||||
}
|
||||
/*
|
||||
* HL is taken care of in z80_ld_hl
|
||||
* SP is taken care of in z80_ld_sp
|
||||
*/
|
||||
// HL is taken care of in z80_ld_hl
|
||||
// SP is taken care of in z80_ld_sp
|
||||
;
|
||||
|
||||
z80_nop : T_Z80_NOP { sect_AbsByte(0x00); }
|
||||
@@ -2089,7 +2080,7 @@ z80_sbc : T_Z80_SBC op_a_n {
|
||||
z80_scf : T_Z80_SCF { sect_AbsByte(0x37); }
|
||||
;
|
||||
|
||||
z80_set : T_POP_SET const_3bit T_COMMA reg_r {
|
||||
z80_set : T_Z80_SET const_3bit T_COMMA reg_r {
|
||||
sect_AbsByte(0xCB);
|
||||
sect_AbsByte(0xC0 | ($2 << 3) | $4);
|
||||
}
|
||||
|
||||
@@ -6,9 +6,7 @@
|
||||
* SPDX-License-Identifier: MIT
|
||||
*/
|
||||
|
||||
/*
|
||||
* Controls RPN expressions for objectfiles
|
||||
*/
|
||||
// Controls RPN expressions for objectfiles
|
||||
|
||||
#include <assert.h>
|
||||
#include <errno.h>
|
||||
@@ -28,7 +26,7 @@
|
||||
|
||||
#include "opmath.h"
|
||||
|
||||
/* Makes an expression "not known", also setting its error message */
|
||||
// Makes an expression "not known", also setting its error message
|
||||
#define makeUnknown(expr_, ...) do { \
|
||||
struct Expression *_expr = expr_; \
|
||||
_expr->isKnown = false; \
|
||||
@@ -47,17 +45,15 @@
|
||||
|
||||
static uint8_t *reserveSpace(struct Expression *expr, uint32_t size)
|
||||
{
|
||||
/* This assumes the RPN length is always less than the capacity */
|
||||
// This assumes the RPN length is always less than the capacity
|
||||
if (expr->rpnCapacity - expr->rpnLength < size) {
|
||||
/* If there isn't enough room to reserve the space, realloc */
|
||||
// If there isn't enough room to reserve the space, realloc
|
||||
if (!expr->rpn)
|
||||
expr->rpnCapacity = 256; /* Initial size */
|
||||
expr->rpnCapacity = 256; // Initial size
|
||||
while (expr->rpnCapacity - expr->rpnLength < size) {
|
||||
if (expr->rpnCapacity >= MAXRPNLEN)
|
||||
/*
|
||||
* To avoid generating humongous object files, cap the
|
||||
* size of RPN expressions
|
||||
*/
|
||||
// To avoid generating humongous object files, cap the
|
||||
// size of RPN expressions
|
||||
fatalerror("RPN expression cannot grow larger than "
|
||||
EXPAND_AND_STR(MAXRPNLEN) " bytes\n");
|
||||
else if (expr->rpnCapacity > MAXRPNLEN / 2)
|
||||
@@ -77,9 +73,7 @@ static uint8_t *reserveSpace(struct Expression *expr, uint32_t size)
|
||||
return ptr;
|
||||
}
|
||||
|
||||
/*
|
||||
* Init a RPN expression
|
||||
*/
|
||||
// Init a RPN expression
|
||||
static void rpn_Init(struct Expression *expr)
|
||||
{
|
||||
expr->reason = NULL;
|
||||
@@ -91,9 +85,7 @@ static void rpn_Init(struct Expression *expr)
|
||||
expr->rpnPatchSize = 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Free the RPN expression
|
||||
*/
|
||||
// Free the RPN expression
|
||||
void rpn_Free(struct Expression *expr)
|
||||
{
|
||||
free(expr->rpn);
|
||||
@@ -101,9 +93,7 @@ void rpn_Free(struct Expression *expr)
|
||||
rpn_Init(expr);
|
||||
}
|
||||
|
||||
/*
|
||||
* Add symbols, constants and operators to expression
|
||||
*/
|
||||
// Add symbols, constants and operators to expression
|
||||
void rpn_Number(struct Expression *expr, uint32_t i)
|
||||
{
|
||||
rpn_Init(expr);
|
||||
@@ -124,9 +114,9 @@ void rpn_Symbol(struct Expression *expr, char const *symName)
|
||||
makeUnknown(expr, sym_IsPC(sym) ? "PC is not constant at assembly time"
|
||||
: "'%s' is not constant at assembly time", symName);
|
||||
sym = sym_Ref(symName);
|
||||
expr->rpnPatchSize += 5; /* 1-byte opcode + 4-byte symbol ID */
|
||||
expr->rpnPatchSize += 5; // 1-byte opcode + 4-byte symbol ID
|
||||
|
||||
size_t nameLen = strlen(sym->name) + 1; /* Don't forget NUL! */
|
||||
size_t nameLen = strlen(sym->name) + 1; // Don't forget NUL!
|
||||
uint8_t *ptr = reserveSpace(expr, nameLen + 1);
|
||||
*ptr++ = RPN_SYM;
|
||||
memcpy(ptr, sym->name, nameLen);
|
||||
@@ -155,7 +145,7 @@ void rpn_BankSymbol(struct Expression *expr, char const *symName)
|
||||
{
|
||||
struct Symbol const *sym = sym_FindScopedSymbol(symName);
|
||||
|
||||
/* The @ symbol is treated differently. */
|
||||
// The @ symbol is treated differently.
|
||||
if (sym_IsPC(sym)) {
|
||||
rpn_BankSelf(expr);
|
||||
return;
|
||||
@@ -169,13 +159,13 @@ void rpn_BankSymbol(struct Expression *expr, char const *symName)
|
||||
assert(sym); // If the symbol didn't exist, it should have been created
|
||||
|
||||
if (sym_GetSection(sym) && sym_GetSection(sym)->bank != (uint32_t)-1) {
|
||||
/* Symbol's section is known and bank is fixed */
|
||||
// Symbol's section is known and bank is fixed
|
||||
expr->val = sym_GetSection(sym)->bank;
|
||||
} else {
|
||||
makeUnknown(expr, "\"%s\"'s bank is not known", symName);
|
||||
expr->rpnPatchSize += 5; /* opcode + 4-byte sect ID */
|
||||
expr->rpnPatchSize += 5; // opcode + 4-byte sect ID
|
||||
|
||||
size_t nameLen = strlen(sym->name) + 1; /* Room for NUL! */
|
||||
size_t nameLen = strlen(sym->name) + 1; // Room for NUL!
|
||||
uint8_t *ptr = reserveSpace(expr, nameLen + 1);
|
||||
*ptr++ = RPN_BANK_SYM;
|
||||
memcpy(ptr, sym->name, nameLen);
|
||||
@@ -194,7 +184,7 @@ void rpn_BankSection(struct Expression *expr, char const *sectionName)
|
||||
} else {
|
||||
makeUnknown(expr, "Section \"%s\"'s bank is not known", sectionName);
|
||||
|
||||
size_t nameLen = strlen(sectionName) + 1; /* Room for NUL! */
|
||||
size_t nameLen = strlen(sectionName) + 1; // Room for NUL!
|
||||
uint8_t *ptr = reserveSpace(expr, nameLen + 1);
|
||||
|
||||
expr->rpnPatchSize += nameLen + 1;
|
||||
@@ -214,7 +204,7 @@ void rpn_SizeOfSection(struct Expression *expr, char const *sectionName)
|
||||
} else {
|
||||
makeUnknown(expr, "Section \"%s\"'s size is not known", sectionName);
|
||||
|
||||
size_t nameLen = strlen(sectionName) + 1; /* Room for NUL! */
|
||||
size_t nameLen = strlen(sectionName) + 1; // Room for NUL!
|
||||
uint8_t *ptr = reserveSpace(expr, nameLen + 1);
|
||||
|
||||
expr->rpnPatchSize += nameLen + 1;
|
||||
@@ -234,7 +224,7 @@ void rpn_StartOfSection(struct Expression *expr, char const *sectionName)
|
||||
} else {
|
||||
makeUnknown(expr, "Section \"%s\"'s start is not known", sectionName);
|
||||
|
||||
size_t nameLen = strlen(sectionName) + 1; /* Room for NUL! */
|
||||
size_t nameLen = strlen(sectionName) + 1; // Room for NUL!
|
||||
uint8_t *ptr = reserveSpace(expr, nameLen + 1);
|
||||
|
||||
expr->rpnPatchSize += nameLen + 1;
|
||||
@@ -252,7 +242,7 @@ void rpn_CheckHRAM(struct Expression *expr, const struct Expression *src)
|
||||
expr->rpnPatchSize++;
|
||||
*reserveSpace(expr, 1) = RPN_HRAM;
|
||||
} else if (expr->val >= 0xFF00 && expr->val <= 0xFFFF) {
|
||||
/* That range is valid, but only keep the lower byte */
|
||||
// That range is valid, but only keep the lower byte
|
||||
expr->val &= 0xFF;
|
||||
} else if (expr->val < 0 || expr->val > 0xFF) {
|
||||
error("Source address $%" PRIx32 " not between $FF00 to $FFFF\n", expr->val);
|
||||
@@ -264,10 +254,10 @@ void rpn_CheckRST(struct Expression *expr, const struct Expression *src)
|
||||
*expr = *src;
|
||||
|
||||
if (rpn_isKnown(expr)) {
|
||||
/* A valid RST address must be masked with 0x38 */
|
||||
// A valid RST address must be masked with 0x38
|
||||
if (expr->val & ~0x38)
|
||||
error("Invalid address $%" PRIx32 " for RST\n", expr->val);
|
||||
/* The target is in the "0x38" bits, all other bits are set */
|
||||
// The target is in the "0x38" bits, all other bits are set
|
||||
expr->val |= 0xC7;
|
||||
} else {
|
||||
expr->rpnPatchSize++;
|
||||
@@ -275,9 +265,7 @@ void rpn_CheckRST(struct Expression *expr, const struct Expression *src)
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Checks that an RPN expression's value fits within N bits (signed or unsigned)
|
||||
*/
|
||||
// Checks that an RPN expression's value fits within N bits (signed or unsigned)
|
||||
void rpn_CheckNBit(struct Expression const *expr, uint8_t n)
|
||||
{
|
||||
assert(n != 0); // That doesn't make sense
|
||||
@@ -324,7 +312,7 @@ struct Symbol const *rpn_SymbolOf(struct Expression const *expr)
|
||||
|
||||
bool rpn_IsDiffConstant(struct Expression const *src, struct Symbol const *sym)
|
||||
{
|
||||
/* Check if both expressions only refer to a single symbol */
|
||||
// Check if both expressions only refer to a single symbol
|
||||
struct Symbol const *sym1 = rpn_SymbolOf(src);
|
||||
|
||||
if (!sym1 || !sym || sym1->type != SYM_LABEL || sym->type != SYM_LABEL)
|
||||
@@ -341,7 +329,7 @@ static bool isDiffConstant(struct Expression const *src1,
|
||||
return rpn_IsDiffConstant(src1, rpn_SymbolOf(src2));
|
||||
}
|
||||
|
||||
/**
|
||||
/*
|
||||
* Attempts to compute a constant binary AND from non-constant operands
|
||||
* This is possible if one operand is a symbol belonging to an `ALIGN[N]` section, and the other is
|
||||
* a constant that only keeps (some of) the lower N bits.
|
||||
@@ -387,12 +375,12 @@ void rpn_BinaryOp(enum RPNCommand op, struct Expression *expr,
|
||||
expr->isSymbol = false;
|
||||
int32_t constMaskVal;
|
||||
|
||||
/* First, check if the expression is known */
|
||||
// First, check if the expression is known
|
||||
expr->isKnown = src1->isKnown && src2->isKnown;
|
||||
if (expr->isKnown) {
|
||||
rpn_Init(expr); /* Init the expression to something sane */
|
||||
rpn_Init(expr); // Init the expression to something sane
|
||||
|
||||
/* If both expressions are known, just compute the value */
|
||||
// If both expressions are known, just compute the value
|
||||
uint32_t uleft = src1->val, uright = src2->val;
|
||||
|
||||
switch (op) {
|
||||
@@ -537,9 +525,9 @@ void rpn_BinaryOp(enum RPNCommand op, struct Expression *expr,
|
||||
expr->val = constMaskVal;
|
||||
expr->isKnown = true;
|
||||
} else {
|
||||
/* If it's not known, start computing the RPN expression */
|
||||
// If it's not known, start computing the RPN expression
|
||||
|
||||
/* Convert the left-hand expression if it's constant */
|
||||
// Convert the left-hand expression if it's constant
|
||||
if (src1->isKnown) {
|
||||
uint32_t lval = src1->val;
|
||||
uint8_t bytes[] = {RPN_CONST, lval, lval >> 8,
|
||||
@@ -551,11 +539,11 @@ void rpn_BinaryOp(enum RPNCommand op, struct Expression *expr,
|
||||
memcpy(reserveSpace(expr, sizeof(bytes)), bytes,
|
||||
sizeof(bytes));
|
||||
|
||||
/* Use the other expression's un-const reason */
|
||||
// Use the other expression's un-const reason
|
||||
expr->reason = src2->reason;
|
||||
free(src1->reason);
|
||||
} else {
|
||||
/* Otherwise just reuse its RPN buffer */
|
||||
// Otherwise just reuse its RPN buffer
|
||||
expr->rpnPatchSize = src1->rpnPatchSize;
|
||||
expr->rpn = src1->rpn;
|
||||
expr->rpnCapacity = src1->rpnCapacity;
|
||||
@@ -564,12 +552,12 @@ void rpn_BinaryOp(enum RPNCommand op, struct Expression *expr,
|
||||
free(src2->reason);
|
||||
}
|
||||
|
||||
/* Now, merge the right expression into the left one */
|
||||
uint8_t *ptr = src2->rpn; /* Pointer to the right RPN */
|
||||
uint32_t len = src2->rpnLength; /* Size of the right RPN */
|
||||
// Now, merge the right expression into the left one
|
||||
uint8_t *ptr = src2->rpn; // Pointer to the right RPN
|
||||
uint32_t len = src2->rpnLength; // Size of the right RPN
|
||||
uint32_t patchSize = src2->rpnPatchSize;
|
||||
|
||||
/* If the right expression is constant, merge a shim instead */
|
||||
// If the right expression is constant, merge a shim instead
|
||||
uint32_t rval = src2->val;
|
||||
uint8_t bytes[] = {RPN_CONST, rval, rval >> 8, rval >> 16,
|
||||
rval >> 24};
|
||||
@@ -578,13 +566,13 @@ void rpn_BinaryOp(enum RPNCommand op, struct Expression *expr,
|
||||
len = sizeof(bytes);
|
||||
patchSize = sizeof(bytes);
|
||||
}
|
||||
/* Copy the right RPN and append the operator */
|
||||
// Copy the right RPN and append the operator
|
||||
uint8_t *buf = reserveSpace(expr, len + 1);
|
||||
|
||||
memcpy(buf, ptr, len);
|
||||
buf[len] = op;
|
||||
|
||||
free(src2->rpn); /* If there was none, this is `free(NULL)` */
|
||||
free(src2->rpn); // If there was none, this is `free(NULL)`
|
||||
expr->rpnPatchSize += patchSize + 1;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,3 +1,10 @@
|
||||
/*
|
||||
* This file is part of RGBDS.
|
||||
*
|
||||
* Copyright (c) 2022, RGBDS contributors.
|
||||
*
|
||||
* SPDX-License-Identifier: MIT
|
||||
*/
|
||||
|
||||
#include <assert.h>
|
||||
#include <errno.h>
|
||||
@@ -30,7 +37,7 @@ struct UnionStackEntry {
|
||||
struct SectionStackEntry {
|
||||
struct Section *section;
|
||||
struct Section *loadSection;
|
||||
char const *scope; /* Section's symbol scope */
|
||||
char const *scope; // Section's symbol scope
|
||||
uint32_t offset;
|
||||
int32_t loadOffset;
|
||||
struct UnionStackEntry *unionStack;
|
||||
@@ -38,14 +45,12 @@ struct SectionStackEntry {
|
||||
};
|
||||
|
||||
struct SectionStackEntry *sectionStack;
|
||||
uint32_t curOffset; /* Offset into the current section (see sect_GetSymbolOffset) */
|
||||
uint32_t curOffset; // Offset into the current section (see sect_GetSymbolOffset)
|
||||
struct Section *currentSection = NULL;
|
||||
static struct Section *currentLoadSection = NULL;
|
||||
int32_t loadOffset; /* Offset into the LOAD section's parent (see sect_GetOutputOffset) */
|
||||
int32_t loadOffset; // Offset into the LOAD section's parent (see sect_GetOutputOffset)
|
||||
|
||||
/*
|
||||
* A quick check to see if we have an initialized section
|
||||
*/
|
||||
// A quick check to see if we have an initialized section
|
||||
attr_(warn_unused_result) static bool checksection(void)
|
||||
{
|
||||
if (currentSection)
|
||||
@@ -55,10 +60,8 @@ attr_(warn_unused_result) static bool checksection(void)
|
||||
return false;
|
||||
}
|
||||
|
||||
/*
|
||||
* A quick check to see if we have an initialized section that can contain
|
||||
* this much initialized data
|
||||
*/
|
||||
// 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(void)
|
||||
{
|
||||
if (!checksection())
|
||||
@@ -85,17 +88,13 @@ attr_(warn_unused_result) static bool checkSectionSize(struct Section const *sec
|
||||
return false;
|
||||
}
|
||||
|
||||
/*
|
||||
* Check if the section has grown too much.
|
||||
*/
|
||||
// Check if the section has grown too much.
|
||||
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.
|
||||
* A check at the linking stage is still necessary.
|
||||
*/
|
||||
// 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.
|
||||
// A check at the linking stage is still necessary.
|
||||
|
||||
// If the section has already overflowed, skip the check to avoid erroring out ad nauseam
|
||||
if (currentSection->size != UINT32_MAX
|
||||
@@ -133,15 +132,13 @@ static unsigned int mergeSectUnion(struct Section *sect, enum SectionType type,
|
||||
assert(alignment < 16); // Should be ensured by the caller
|
||||
unsigned int nbSectErrors = 0;
|
||||
|
||||
/*
|
||||
* Unionized sections only need "compatible" constraints, and they end up with the strictest
|
||||
* combination of both.
|
||||
*/
|
||||
// Unionized sections only need "compatible" constraints, and they end up with the strictest
|
||||
// combination of both.
|
||||
if (sect_HasData(type))
|
||||
fail("Cannot declare ROM sections as UNION\n");
|
||||
|
||||
if (org != (uint32_t)-1) {
|
||||
/* If both are fixed, they must be the same */
|
||||
// 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);
|
||||
@@ -149,16 +146,16 @@ static unsigned int mergeSectUnion(struct Section *sect, enum SectionType type,
|
||||
fail("Section already declared as aligned to %u bytes (offset %"
|
||||
PRIu16 ")\n", 1U << sect->align, sect->alignOfs);
|
||||
else
|
||||
/* Otherwise, just override */
|
||||
// Otherwise, just override
|
||||
sect->org = org;
|
||||
|
||||
} else if (alignment != 0) {
|
||||
/* Make sure any fixed address given is compatible */
|
||||
// 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 */
|
||||
// Check if alignment offsets are compatible
|
||||
} else if ((alignOffset & mask(sect->align))
|
||||
!= (sect->alignOfs & mask(alignment))) {
|
||||
fail("Section already declared with incompatible %u"
|
||||
@@ -181,15 +178,13 @@ static unsigned int mergeFragments(struct Section *sect, enum SectionType type,
|
||||
assert(alignment < 16); // Should be ensured by the caller
|
||||
unsigned int nbSectErrors = 0;
|
||||
|
||||
/*
|
||||
* Fragments only need "compatible" constraints, and they end up with the strictest
|
||||
* combination of both.
|
||||
* The merging is however performed at the *end* of the original section!
|
||||
*/
|
||||
// Fragments only need "compatible" constraints, and they end up with the strictest
|
||||
// combination of both.
|
||||
// The merging is however performed at the *end* of the original section!
|
||||
if (org != (uint32_t)-1) {
|
||||
uint16_t curOrg = org - sect->size;
|
||||
|
||||
/* If both are fixed, they must be the same */
|
||||
// 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 " (cur addr = %04" PRIx32 ")\n",
|
||||
@@ -198,7 +193,7 @@ static unsigned int mergeFragments(struct Section *sect, enum SectionType type,
|
||||
fail("Section already declared as aligned to %u bytes (offset %"
|
||||
PRIu16 ")\n", 1U << sect->align, sect->alignOfs);
|
||||
else
|
||||
/* Otherwise, just override */
|
||||
// Otherwise, just override
|
||||
sect->org = curOrg;
|
||||
|
||||
} else if (alignment != 0) {
|
||||
@@ -207,12 +202,12 @@ static unsigned int mergeFragments(struct Section *sect, enum SectionType type,
|
||||
if (curOfs < 0)
|
||||
curOfs += 1U << alignment;
|
||||
|
||||
/* Make sure any fixed address given is compatible */
|
||||
// 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 */
|
||||
// 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",
|
||||
@@ -246,10 +241,10 @@ static void mergeSections(struct Section *sect, enum SectionType type, uint32_t
|
||||
|
||||
// Common checks
|
||||
|
||||
/* If the section's bank is unspecified, override it */
|
||||
// If the section's bank is unspecified, override it
|
||||
if (sect->bank == (uint32_t)-1)
|
||||
sect->bank = bank;
|
||||
/* If both specify a bank, it must be the same one */
|
||||
// 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);
|
||||
@@ -270,9 +265,7 @@ static void mergeSections(struct Section *sect, enum SectionType type, uint32_t
|
||||
|
||||
#undef fail
|
||||
|
||||
/*
|
||||
* Create a new section, not yet in the list.
|
||||
*/
|
||||
// Create a new section, not yet in the list.
|
||||
static struct Section *createSection(char const *name, enum SectionType type,
|
||||
uint32_t org, uint32_t bank, uint8_t alignment,
|
||||
uint16_t alignOffset, enum SectionModifier mod)
|
||||
@@ -298,7 +291,7 @@ static struct Section *createSection(char const *name, enum SectionType type,
|
||||
sect->next = NULL;
|
||||
sect->patches = NULL;
|
||||
|
||||
/* It is only needed to allocate memory for ROM sections. */
|
||||
// It is only needed to allocate memory for ROM sections.
|
||||
if (sect_HasData(type)) {
|
||||
sect->data = malloc(sectionTypeInfo[type].size);
|
||||
if (sect->data == NULL)
|
||||
@@ -310,9 +303,7 @@ static struct Section *createSection(char const *name, enum SectionType type,
|
||||
return sect;
|
||||
}
|
||||
|
||||
/*
|
||||
* Find a section by name and type. If it doesn't exist, create it.
|
||||
*/
|
||||
// Find a section by name and type. If it doesn't exist, create it.
|
||||
static struct Section *getSection(char const *name, enum SectionType type, uint32_t org,
|
||||
struct SectionSpec const *attrs, enum SectionModifier mod)
|
||||
{
|
||||
@@ -353,18 +344,18 @@ static struct Section *getSection(char const *name, enum SectionType type, uint3
|
||||
error("Alignment must be between 0 and 16, not %u\n", alignment);
|
||||
alignment = 16;
|
||||
}
|
||||
/* It doesn't make sense to have both alignment and org set */
|
||||
// It doesn't make sense to have both alignment and org set
|
||||
uint32_t mask = mask(alignment);
|
||||
|
||||
if (org != (uint32_t)-1) {
|
||||
if ((org - alignOffset) & mask)
|
||||
error("Section \"%s\"'s fixed address doesn't match its alignment\n",
|
||||
name);
|
||||
alignment = 0; /* Ignore it if it's satisfied */
|
||||
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);
|
||||
alignment = 0; /* Ignore it if it's unattainable */
|
||||
alignment = 0; // Ignore it if it's unattainable
|
||||
org = 0;
|
||||
} else if (alignment == 16) {
|
||||
// Treat an alignment of 16 as being fixed at address 0
|
||||
@@ -390,9 +381,7 @@ static struct Section *getSection(char const *name, enum SectionType type, uint3
|
||||
return sect;
|
||||
}
|
||||
|
||||
/*
|
||||
* Set the current section
|
||||
*/
|
||||
// Set the current section
|
||||
static void changeSection(void)
|
||||
{
|
||||
if (unionStack)
|
||||
@@ -401,9 +390,7 @@ static void changeSection(void)
|
||||
sym_SetCurrentSymbolScope(NULL);
|
||||
}
|
||||
|
||||
/*
|
||||
* Set the current section by name and type
|
||||
*/
|
||||
// Set the current section by name and type
|
||||
void sect_NewSection(char const *name, uint32_t type, uint32_t org,
|
||||
struct SectionSpec const *attribs, enum SectionModifier mod)
|
||||
{
|
||||
@@ -423,9 +410,7 @@ void sect_NewSection(char const *name, uint32_t type, uint32_t org,
|
||||
currentSection = sect;
|
||||
}
|
||||
|
||||
/*
|
||||
* Set the current section by name and type
|
||||
*/
|
||||
// Set the current section by name and type
|
||||
void sect_SetLoadSection(char const *name, uint32_t type, uint32_t org,
|
||||
struct SectionSpec const *attribs, enum SectionModifier mod)
|
||||
{
|
||||
@@ -478,9 +463,7 @@ struct Section *sect_GetSymbolSection(void)
|
||||
return currentLoadSection ? currentLoadSection : currentSection;
|
||||
}
|
||||
|
||||
/*
|
||||
* The offset into the section above
|
||||
*/
|
||||
// The offset into the section above
|
||||
uint32_t sect_GetSymbolOffset(void)
|
||||
{
|
||||
return curOffset;
|
||||
@@ -615,9 +598,7 @@ void sect_CheckUnionClosed(void)
|
||||
error("Unterminated UNION construct!\n");
|
||||
}
|
||||
|
||||
/*
|
||||
* Output an absolute byte
|
||||
*/
|
||||
// Output an absolute byte
|
||||
void sect_AbsByte(uint8_t b)
|
||||
{
|
||||
if (!checkcodesection())
|
||||
@@ -661,9 +642,7 @@ void sect_AbsLongGroup(uint8_t const *s, size_t length)
|
||||
writelong(*s++);
|
||||
}
|
||||
|
||||
/*
|
||||
* Skip this many bytes
|
||||
*/
|
||||
// Skip this many bytes
|
||||
void sect_Skip(uint32_t skip, bool ds)
|
||||
{
|
||||
if (!checksection())
|
||||
@@ -683,9 +662,7 @@ void sect_Skip(uint32_t skip, bool ds)
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Output a NULL terminated string (excluding the NULL-character)
|
||||
*/
|
||||
// Output a NULL terminated string (excluding the NULL-character)
|
||||
void sect_String(char const *s)
|
||||
{
|
||||
if (!checkcodesection())
|
||||
@@ -697,10 +674,8 @@ void sect_String(char const *s)
|
||||
writebyte(*s++);
|
||||
}
|
||||
|
||||
/*
|
||||
* Output a relocatable byte. Checking will be done to see if it
|
||||
* is an absolute value in disguise.
|
||||
*/
|
||||
// Output a relocatable byte. Checking will be done to see if it
|
||||
// is an absolute value in disguise.
|
||||
void sect_RelByte(struct Expression *expr, uint32_t pcShift)
|
||||
{
|
||||
if (!checkcodesection())
|
||||
@@ -717,10 +692,8 @@ void sect_RelByte(struct Expression *expr, uint32_t pcShift)
|
||||
rpn_Free(expr);
|
||||
}
|
||||
|
||||
/*
|
||||
* Output several copies of a relocatable byte. Checking will be done to see if
|
||||
* it is an absolute value in disguise.
|
||||
*/
|
||||
// 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, struct Expression *exprs, size_t size)
|
||||
{
|
||||
if (!checkcodesection())
|
||||
@@ -743,10 +716,8 @@ void sect_RelBytes(uint32_t n, struct Expression *exprs, size_t size)
|
||||
rpn_Free(&exprs[i]);
|
||||
}
|
||||
|
||||
/*
|
||||
* Output a relocatable word. Checking will be done to see if
|
||||
* it's an absolute value in disguise.
|
||||
*/
|
||||
// Output a relocatable word. Checking will be done to see if
|
||||
// it's an absolute value in disguise.
|
||||
void sect_RelWord(struct Expression *expr, uint32_t pcShift)
|
||||
{
|
||||
if (!checkcodesection())
|
||||
@@ -763,10 +734,8 @@ void sect_RelWord(struct Expression *expr, uint32_t pcShift)
|
||||
rpn_Free(expr);
|
||||
}
|
||||
|
||||
/*
|
||||
* Output a relocatable longword. Checking will be done to see if
|
||||
* is an absolute value in disguise.
|
||||
*/
|
||||
// Output a relocatable longword. Checking will be done to see if
|
||||
// is an absolute value in disguise.
|
||||
void sect_RelLong(struct Expression *expr, uint32_t pcShift)
|
||||
{
|
||||
if (!checkcodesection())
|
||||
@@ -783,10 +752,8 @@ void sect_RelLong(struct Expression *expr, uint32_t pcShift)
|
||||
rpn_Free(expr);
|
||||
}
|
||||
|
||||
/*
|
||||
* Output a PC-relative relocatable byte. Checking will be done to see if it
|
||||
* is an absolute value in disguise.
|
||||
*/
|
||||
// Output a PC-relative relocatable byte. Checking will be done to see if it
|
||||
// is an absolute value in disguise.
|
||||
void sect_PCRelByte(struct Expression *expr, uint32_t pcShift)
|
||||
{
|
||||
if (!checkcodesection())
|
||||
@@ -800,12 +767,12 @@ void sect_PCRelByte(struct Expression *expr, uint32_t pcShift)
|
||||
writebyte(0);
|
||||
} else {
|
||||
struct Symbol const *sym = rpn_SymbolOf(expr);
|
||||
/* The offset wraps (jump from ROM to HRAM, for example) */
|
||||
// The offset wraps (jump from ROM to HRAM, for example)
|
||||
int16_t offset;
|
||||
|
||||
/* Offset is relative to the byte *after* the operand */
|
||||
// Offset is relative to the byte *after* the operand
|
||||
if (sym == pc)
|
||||
offset = -2; /* PC as operand to `jr` is lower than reference PC by 2 */
|
||||
offset = -2; // PC as operand to `jr` is lower than reference PC by 2
|
||||
else
|
||||
offset = sym_GetValue(sym) - (sym_GetValue(pc) + 1);
|
||||
|
||||
@@ -820,9 +787,7 @@ void sect_PCRelByte(struct Expression *expr, uint32_t pcShift)
|
||||
rpn_Free(expr);
|
||||
}
|
||||
|
||||
/*
|
||||
* Output a binary file
|
||||
*/
|
||||
// Output a binary file
|
||||
void sect_BinaryFile(char const *s, int32_t startPos)
|
||||
{
|
||||
if (startPos < 0) {
|
||||
@@ -869,7 +834,7 @@ void sect_BinaryFile(char const *s, int32_t startPos)
|
||||
if (errno != ESPIPE)
|
||||
error("Error determining size of INCBIN file '%s': %s\n",
|
||||
s, strerror(errno));
|
||||
/* The file isn't seekable, so we'll just skip bytes */
|
||||
// The file isn't seekable, so we'll just skip bytes
|
||||
while (startPos--)
|
||||
(void)fgetc(f);
|
||||
}
|
||||
@@ -901,7 +866,7 @@ void sect_BinaryFileSlice(char const *s, int32_t start_pos, int32_t length)
|
||||
|
||||
if (!checkcodesection())
|
||||
return;
|
||||
if (length == 0) /* Don't even bother with 0-byte slices */
|
||||
if (length == 0) // Don't even bother with 0-byte slices
|
||||
return;
|
||||
if (!reserveSpace(length))
|
||||
return;
|
||||
@@ -946,7 +911,7 @@ void sect_BinaryFileSlice(char const *s, int32_t start_pos, int32_t length)
|
||||
if (errno != ESPIPE)
|
||||
error("Error determining size of INCBIN file '%s': %s\n",
|
||||
s, strerror(errno));
|
||||
/* The file isn't seekable, so we'll just skip bytes */
|
||||
// The file isn't seekable, so we'll just skip bytes
|
||||
while (start_pos--)
|
||||
(void)fgetc(f);
|
||||
}
|
||||
@@ -968,9 +933,7 @@ cleanup:
|
||||
fclose(f);
|
||||
}
|
||||
|
||||
/*
|
||||
* Section stack routines
|
||||
*/
|
||||
// Section stack routines
|
||||
void sect_PushSection(void)
|
||||
{
|
||||
struct SectionStackEntry *entry = malloc(sizeof(*entry));
|
||||
|
||||
164
src/asm/symbol.c
164
src/asm/symbol.c
@@ -6,9 +6,7 @@
|
||||
* SPDX-License-Identifier: MIT
|
||||
*/
|
||||
|
||||
/*
|
||||
* Symboltable and macroargs stuff
|
||||
*/
|
||||
// Symboltable and macroargs stuff
|
||||
|
||||
#include <assert.h>
|
||||
#include <errno.h>
|
||||
@@ -36,7 +34,7 @@
|
||||
|
||||
HashMap symbols;
|
||||
|
||||
static char const *labelScope; /* Current section's label scope */
|
||||
static const char *labelScope; // Current section's label scope
|
||||
static struct Symbol *PCSymbol;
|
||||
static char savedTIME[256];
|
||||
static char savedDATE[256];
|
||||
@@ -85,36 +83,34 @@ static int32_t Callback__LINE__(void)
|
||||
|
||||
static char const *Callback__FILE__(void)
|
||||
{
|
||||
/*
|
||||
* FIXME: this is dangerous, and here's why this is CURRENTLY okay. It's still bad, fix it.
|
||||
* There are only two call sites for this; one copies the contents directly, the other is
|
||||
* EQUS expansions, which cannot straddle file boundaries. So this should be fine.
|
||||
*/
|
||||
// FIXME: this is dangerous, and here's why this is CURRENTLY okay. It's still bad, fix it.
|
||||
// There are only two call sites for this; one copies the contents directly, the other is
|
||||
// EQUS expansions, which cannot straddle file boundaries. So this should be fine.
|
||||
static char *buf = NULL;
|
||||
static size_t bufsize = 0;
|
||||
char const *fileName = fstk_GetFileName();
|
||||
size_t j = 1;
|
||||
|
||||
assert(fileName[0]);
|
||||
/* The assertion above ensures the loop runs at least once */
|
||||
// The assertion above ensures the loop runs at least once
|
||||
for (size_t i = 0; fileName[i]; i++, j++) {
|
||||
/* Account for the extra backslash inserted below */
|
||||
// Account for the extra backslash inserted below
|
||||
if (fileName[i] == '"')
|
||||
j++;
|
||||
/* Ensure there will be enough room; DO NOT PRINT ANYTHING ABOVE THIS!! */
|
||||
if (j + 2 >= bufsize) { /* Always keep room for 2 tail chars */
|
||||
// Ensure there will be enough room; DO NOT PRINT ANYTHING ABOVE THIS!!
|
||||
if (j + 2 >= bufsize) { // Always keep room for 2 tail chars
|
||||
bufsize = bufsize ? bufsize * 2 : 64;
|
||||
buf = realloc(buf, bufsize);
|
||||
if (!buf)
|
||||
fatalerror("Failed to grow buffer for file name: %s\n",
|
||||
strerror(errno));
|
||||
}
|
||||
/* Escape quotes, since we're returning a string */
|
||||
// Escape quotes, since we're returning a string
|
||||
if (fileName[i] == '"')
|
||||
buf[j - 1] = '\\';
|
||||
buf[j] = fileName[i];
|
||||
}
|
||||
/* Write everything after the loop, to ensure the buffer has been allocated */
|
||||
// Write everything after the loop, to ensure the buffer has been allocated
|
||||
buf[0] = '"';
|
||||
buf[j++] = '"';
|
||||
buf[j] = '\0';
|
||||
@@ -128,16 +124,14 @@ static int32_t CallbackPC(void)
|
||||
return section ? section->org + sect_GetSymbolOffset() : 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Get the value field of a symbol
|
||||
*/
|
||||
// Get the value field of a symbol
|
||||
int32_t sym_GetValue(struct Symbol const *sym)
|
||||
{
|
||||
if (sym_IsNumeric(sym) && sym->hasCallback)
|
||||
return sym->numCallback();
|
||||
|
||||
if (sym->type == SYM_LABEL)
|
||||
/* TODO: do not use section's org directly */
|
||||
// TODO: do not use section's org directly
|
||||
return sym->value + sym_GetSection(sym)->org;
|
||||
|
||||
return sym->value;
|
||||
@@ -153,32 +147,26 @@ static void dumpFilename(struct Symbol const *sym)
|
||||
fputs("<builtin>", stderr);
|
||||
}
|
||||
|
||||
/*
|
||||
* Set a symbol's definition filename and line
|
||||
*/
|
||||
// Set a symbol's definition filename and line
|
||||
static void setSymbolFilename(struct Symbol *sym)
|
||||
{
|
||||
sym->src = fstk_GetFileStack();
|
||||
sym->fileLine = sym->src ? lexer_GetLineNo() : 0; // This is (NULL, 1) for built-ins
|
||||
}
|
||||
|
||||
/*
|
||||
* Update a symbol's definition filename and line
|
||||
*/
|
||||
// Update a symbol's definition filename and line
|
||||
static void updateSymbolFilename(struct Symbol *sym)
|
||||
{
|
||||
struct FileStackNode *oldSrc = sym->src;
|
||||
|
||||
setSymbolFilename(sym);
|
||||
/* If the old node was referenced, ensure the new one is */
|
||||
// If the old node was referenced, ensure the new one is
|
||||
if (oldSrc && oldSrc->referenced && oldSrc->ID != (uint32_t)-1)
|
||||
out_RegisterNode(sym->src);
|
||||
/* TODO: unref the old node, and use `out_ReplaceNode` instead of deleting it */
|
||||
// TODO: unref the old node, and use `out_ReplaceNode` instead of deleting it
|
||||
}
|
||||
|
||||
/*
|
||||
* Create a new symbol by name
|
||||
*/
|
||||
// Create a new symbol by name
|
||||
static struct Symbol *createsymbol(char const *symName)
|
||||
{
|
||||
struct Symbol *sym = malloc(sizeof(*sym));
|
||||
@@ -201,10 +189,8 @@ static struct Symbol *createsymbol(char const *symName)
|
||||
return sym;
|
||||
}
|
||||
|
||||
/*
|
||||
* Creates the full name of a local symbol in a given scope, by prepending
|
||||
* the name with the parent symbol's name.
|
||||
*/
|
||||
// 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)
|
||||
{
|
||||
@@ -250,8 +236,8 @@ struct Symbol *sym_FindScopedSymbol(char const *symName)
|
||||
if (strchr(localName + 1, '.'))
|
||||
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 */
|
||||
// If auto-scoped local label, expand the name
|
||||
if (localName == symName) { // Meaning, the name begins with the dot
|
||||
char fullName[MAXSYMLEN + 1];
|
||||
|
||||
fullSymbolName(fullName, sizeof(fullName), symName, labelScope);
|
||||
@@ -271,9 +257,7 @@ static bool isReferenced(struct Symbol const *sym)
|
||||
return sym->ID != (uint32_t)-1;
|
||||
}
|
||||
|
||||
/*
|
||||
* Purge a symbol
|
||||
*/
|
||||
// Purge a symbol
|
||||
void sym_Purge(char const *symName)
|
||||
{
|
||||
struct Symbol *sym = sym_FindScopedSymbol(symName);
|
||||
@@ -285,16 +269,14 @@ void sym_Purge(char const *symName)
|
||||
} else if (isReferenced(sym)) {
|
||||
error("Symbol \"%s\" is referenced and thus cannot be purged\n", symName);
|
||||
} else {
|
||||
/* Do not keep a reference to the label's name after purging it */
|
||||
// Do not keep a reference to the label's name after purging it
|
||||
if (sym->name == labelScope)
|
||||
sym_SetCurrentSymbolScope(NULL);
|
||||
|
||||
/*
|
||||
* FIXME: this leaks sym->macro for SYM_EQUS and SYM_MACRO, but this can't
|
||||
* free(sym->macro) because the expansion may be purging itself.
|
||||
*/
|
||||
// FIXME: this leaks sym->macro for SYM_EQUS and SYM_MACRO, but this can't
|
||||
// free(sym->macro) because the expansion may be purging itself.
|
||||
hash_RemoveElement(symbols, sym->name);
|
||||
/* TODO: ideally, also unref the file stack nodes */
|
||||
// TODO: ideally, also unref the file stack nodes
|
||||
free(sym);
|
||||
}
|
||||
}
|
||||
@@ -312,9 +294,7 @@ uint32_t sym_GetPCValue(void)
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Return a constant symbol's value, assuming it's defined
|
||||
*/
|
||||
// Return a constant symbol's value, assuming it's defined
|
||||
uint32_t sym_GetConstantSymValue(struct Symbol const *sym)
|
||||
{
|
||||
if (sym == PCSymbol)
|
||||
@@ -327,9 +307,7 @@ uint32_t sym_GetConstantSymValue(struct Symbol const *sym)
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Return a constant symbol's value
|
||||
*/
|
||||
// Return a constant symbol's value
|
||||
uint32_t sym_GetConstantValue(char const *symName)
|
||||
{
|
||||
struct Symbol const *sym = sym_FindScopedSymbol(symName);
|
||||
@@ -381,9 +359,7 @@ static struct Symbol *createNonrelocSymbol(char const *symName, bool numeric)
|
||||
return sym;
|
||||
}
|
||||
|
||||
/*
|
||||
* Add an equated symbol
|
||||
*/
|
||||
// Add an equated symbol
|
||||
struct Symbol *sym_AddEqu(char const *symName, int32_t value)
|
||||
{
|
||||
struct Symbol *sym = createNonrelocSymbol(symName, true);
|
||||
@@ -465,18 +441,14 @@ struct Symbol *sym_RedefString(char const *symName, char const *value)
|
||||
}
|
||||
|
||||
updateSymbolFilename(sym);
|
||||
/*
|
||||
* FIXME: this leaks the previous sym->macro value, but this can't
|
||||
* free(sym->macro) because the expansion may be redefining itself.
|
||||
*/
|
||||
// FIXME: this leaks the previous sym->macro value, but this can't
|
||||
// free(sym->macro) because the expansion may be redefining itself.
|
||||
assignStringSymbol(sym, value);
|
||||
|
||||
return sym;
|
||||
}
|
||||
|
||||
/*
|
||||
* Alter a mutable symbol's value
|
||||
*/
|
||||
// Alter a mutable symbol's value
|
||||
struct Symbol *sym_AddVar(char const *symName, int32_t value)
|
||||
{
|
||||
struct Symbol *sym = sym_FindExactSymbol(symName);
|
||||
@@ -506,7 +478,7 @@ struct Symbol *sym_AddVar(char const *symName, int32_t value)
|
||||
*/
|
||||
static struct Symbol *addLabel(char const *symName)
|
||||
{
|
||||
assert(symName[0] != '.'); /* The symbol name must have been expanded prior */
|
||||
assert(symName[0] != '.'); // The symbol name must have been expanded prior
|
||||
struct Symbol *sym = sym_FindExactSymbol(symName);
|
||||
|
||||
if (!sym) {
|
||||
@@ -519,7 +491,7 @@ static struct Symbol *addLabel(char const *symName)
|
||||
} else {
|
||||
updateSymbolFilename(sym);
|
||||
}
|
||||
/* If the symbol already exists as a ref, just "take over" it */
|
||||
// If the symbol already exists as a ref, just "take over" it
|
||||
sym->type = SYM_LABEL;
|
||||
sym->value = sect_GetSymbolOffset();
|
||||
if (exportall)
|
||||
@@ -531,43 +503,41 @@ static struct Symbol *addLabel(char const *symName)
|
||||
return sym;
|
||||
}
|
||||
|
||||
/*
|
||||
* Add a local (`.name` or `Parent.name`) relocatable symbol
|
||||
*/
|
||||
// Add a local (`.name` or `Parent.name`) relocatable symbol
|
||||
struct Symbol *sym_AddLocalLabel(char const *symName)
|
||||
{
|
||||
if (!labelScope) {
|
||||
error("Local label '%s' in main scope\n", symName);
|
||||
return NULL;
|
||||
}
|
||||
assert(!strchr(labelScope, '.')); /* Assuming no dots in `labelScope` */
|
||||
assert(!strchr(labelScope, '.')); // Assuming no dots in `labelScope`
|
||||
|
||||
char fullName[MAXSYMLEN + 1];
|
||||
char const *localName = strchr(symName, '.');
|
||||
|
||||
assert(localName); /* There should be at least one dot in `symName` */
|
||||
/* Check for something after the dot in `localName` */
|
||||
assert(localName); // There should be at least one dot in `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);
|
||||
}
|
||||
/* Check for more than one dot in `localName` */
|
||||
// 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);
|
||||
|
||||
if (localName == symName) {
|
||||
/* Expand `symName` to the full `labelScope.symName` name */
|
||||
// Expand `symName` to the full `labelScope.symName` name
|
||||
fullSymbolName(fullName, sizeof(fullName), symName, labelScope);
|
||||
symName = fullName;
|
||||
} else {
|
||||
size_t i = 0;
|
||||
|
||||
/* Find where `labelScope` and `symName` first differ */
|
||||
// Find where `labelScope` and `symName` first differ
|
||||
while (labelScope[i] && symName[i] == labelScope[i])
|
||||
i++;
|
||||
|
||||
/* Check that `symName` starts with `labelScope` and then a '.' */
|
||||
// Check that `symName` starts with `labelScope` and then a '.'
|
||||
if (labelScope[i] != '\0' || symName[i] != '.') {
|
||||
size_t parentLen = localName - symName;
|
||||
|
||||
@@ -579,14 +549,12 @@ struct Symbol *sym_AddLocalLabel(char const *symName)
|
||||
return addLabel(symName);
|
||||
}
|
||||
|
||||
/*
|
||||
* Add a relocatable symbol
|
||||
*/
|
||||
// Add a relocatable symbol
|
||||
struct Symbol *sym_AddLabel(char const *symName)
|
||||
{
|
||||
struct Symbol *sym = addLabel(symName);
|
||||
|
||||
/* Set the symbol as the new scope */
|
||||
// Set the symbol as the new scope
|
||||
if (sym)
|
||||
sym_SetCurrentSymbolScope(sym->name);
|
||||
return sym;
|
||||
@@ -594,9 +562,7 @@ struct Symbol *sym_AddLabel(char const *symName)
|
||||
|
||||
static uint32_t anonLabelID;
|
||||
|
||||
/*
|
||||
* Add an anonymous label
|
||||
*/
|
||||
// Add an anonymous label
|
||||
struct Symbol *sym_AddAnonLabel(void)
|
||||
{
|
||||
if (anonLabelID == UINT32_MAX) {
|
||||
@@ -610,9 +576,7 @@ struct Symbol *sym_AddAnonLabel(void)
|
||||
return addLabel(name);
|
||||
}
|
||||
|
||||
/*
|
||||
* Write an anonymous label's name to a buffer
|
||||
*/
|
||||
// Write an anonymous label's name to a buffer
|
||||
void sym_WriteAnonLabelName(char buf[MIN_NB_ELMS(MAXSYMLEN + 1)], uint32_t ofs, bool neg)
|
||||
{
|
||||
uint32_t id = 0;
|
||||
@@ -636,9 +600,7 @@ void sym_WriteAnonLabelName(char buf[MIN_NB_ELMS(MAXSYMLEN + 1)], uint32_t ofs,
|
||||
sprintf(buf, "!%u", id);
|
||||
}
|
||||
|
||||
/*
|
||||
* Export a symbol
|
||||
*/
|
||||
// Export a symbol
|
||||
void sym_Export(char const *symName)
|
||||
{
|
||||
if (symName[0] == '!') {
|
||||
@@ -648,15 +610,13 @@ void sym_Export(char const *symName)
|
||||
|
||||
struct Symbol *sym = sym_FindScopedSymbol(symName);
|
||||
|
||||
/* If the symbol doesn't exist, create a ref that can be purged */
|
||||
// If the symbol doesn't exist, create a ref that can be purged
|
||||
if (!sym)
|
||||
sym = sym_Ref(symName);
|
||||
sym->isExported = true;
|
||||
}
|
||||
|
||||
/*
|
||||
* Add a macro definition
|
||||
*/
|
||||
// Add a macro definition
|
||||
struct Symbol *sym_AddMacro(char const *symName, int32_t defLineNo, char *body, size_t size)
|
||||
{
|
||||
struct Symbol *sym = createNonrelocSymbol(symName, false);
|
||||
@@ -667,20 +627,16 @@ struct Symbol *sym_AddMacro(char const *symName, int32_t defLineNo, char *body,
|
||||
sym->type = SYM_MACRO;
|
||||
sym->macroSize = size;
|
||||
sym->macro = body;
|
||||
setSymbolFilename(sym); /* TODO: is this really necessary? */
|
||||
/*
|
||||
* The symbol is created at the line after the `endm`,
|
||||
* override this with the actual definition line
|
||||
*/
|
||||
setSymbolFilename(sym); // TODO: is this really necessary?
|
||||
// The symbol is created at the line after the `endm`,
|
||||
// override this with the actual definition line
|
||||
sym->fileLine = defLineNo;
|
||||
|
||||
return sym;
|
||||
}
|
||||
|
||||
/*
|
||||
* Flag that a symbol is referenced in an RPN expression
|
||||
* and create it if it doesn't exist yet
|
||||
*/
|
||||
// Flag that a symbol is referenced in an RPN expression
|
||||
// and create it if it doesn't exist yet
|
||||
struct Symbol *sym_Ref(char const *symName)
|
||||
{
|
||||
struct Symbol *sym = sym_FindScopedSymbol(symName);
|
||||
@@ -702,9 +658,7 @@ struct Symbol *sym_Ref(char const *symName)
|
||||
return sym;
|
||||
}
|
||||
|
||||
/*
|
||||
* Set whether to export all relocatable symbols by default
|
||||
*/
|
||||
// Set whether to export all relocatable symbols by default
|
||||
void sym_SetExportAll(bool set)
|
||||
{
|
||||
exportall = set;
|
||||
@@ -721,9 +675,7 @@ static struct Symbol *createBuiltinSymbol(char const *symName)
|
||||
return sym;
|
||||
}
|
||||
|
||||
/*
|
||||
* Initialize the symboltable
|
||||
*/
|
||||
// Initialize the symboltable
|
||||
void sym_Init(time_t now)
|
||||
{
|
||||
PCSymbol = createBuiltinSymbol("@");
|
||||
@@ -761,7 +713,7 @@ void sym_Init(time_t now)
|
||||
|
||||
if (now == (time_t)-1) {
|
||||
warn("Couldn't determine current time");
|
||||
/* Fall back by pretending we are at the Epoch */
|
||||
// Fall back by pretending we are at the Epoch
|
||||
now = 0;
|
||||
}
|
||||
|
||||
|
||||
@@ -44,7 +44,7 @@ char const *printChar(int c)
|
||||
buf[2] = 't';
|
||||
break;
|
||||
|
||||
default: /* Print as hex */
|
||||
default: // Print as hex
|
||||
buf[0] = '0';
|
||||
buf[1] = 'x';
|
||||
snprintf(&buf[2], 3, "%02hhX", (uint8_t)c); // includes the '\0'
|
||||
|
||||
@@ -49,19 +49,19 @@ static const enum WarningState defaultWarnings[ARRAY_SIZE(warningStates)] = {
|
||||
|
||||
enum WarningState warningStates[ARRAY_SIZE(warningStates)];
|
||||
|
||||
bool warningsAreErrors; /* Set if `-Werror` was specified */
|
||||
bool warningsAreErrors; // Set if `-Werror` was specified
|
||||
|
||||
static enum WarningState warningState(enum WarningID id)
|
||||
{
|
||||
/* Check if warnings are globally disabled */
|
||||
// Check if warnings are globally disabled
|
||||
if (!warnings)
|
||||
return WARNING_DISABLED;
|
||||
|
||||
/* Get the actual state */
|
||||
// Get the actual state
|
||||
enum WarningState state = warningStates[id];
|
||||
|
||||
if (state == WARNING_DEFAULT)
|
||||
/* The state isn't set, grab its default state */
|
||||
// The state isn't set, grab its default state
|
||||
state = defaultWarnings[id];
|
||||
|
||||
if (warningsAreErrors && state == WARNING_ENABLED)
|
||||
@@ -95,10 +95,10 @@ static const char * const warningFlags[NB_WARNINGS] = {
|
||||
"truncation",
|
||||
"truncation",
|
||||
|
||||
/* Meta warnings */
|
||||
// Meta warnings
|
||||
"all",
|
||||
"extra",
|
||||
"everything", /* Especially useful for testing */
|
||||
"everything", // Especially useful for testing
|
||||
};
|
||||
|
||||
static const struct {
|
||||
@@ -151,7 +151,7 @@ enum MetaWarningCommand {
|
||||
META_WARNING_DONE = NB_WARNINGS
|
||||
};
|
||||
|
||||
/* Warnings that probably indicate an error */
|
||||
// Warnings that probably indicate an error
|
||||
static uint8_t const _wallCommands[] = {
|
||||
WARNING_BACKWARDS_FOR,
|
||||
WARNING_BUILTIN_ARG,
|
||||
@@ -167,7 +167,7 @@ static uint8_t const _wallCommands[] = {
|
||||
META_WARNING_DONE
|
||||
};
|
||||
|
||||
/* Warnings that are less likely to indicate an error */
|
||||
// Warnings that are less likely to indicate an error
|
||||
static uint8_t const _wextraCommands[] = {
|
||||
WARNING_EMPTY_MACRO_ARG,
|
||||
WARNING_MACRO_SHIFT,
|
||||
@@ -179,7 +179,7 @@ static uint8_t const _wextraCommands[] = {
|
||||
META_WARNING_DONE
|
||||
};
|
||||
|
||||
/* Literally everything. Notably useful for testing */
|
||||
// Literally everything. Notably useful for testing
|
||||
static uint8_t const _weverythingCommands[] = {
|
||||
WARNING_BACKWARDS_FOR,
|
||||
WARNING_BUILTIN_ARG,
|
||||
@@ -199,7 +199,7 @@ static uint8_t const _weverythingCommands[] = {
|
||||
WARNING_NUMERIC_STRING_2,
|
||||
WARNING_TRUNCATION_1,
|
||||
WARNING_TRUNCATION_2,
|
||||
/* WARNING_USER, */
|
||||
// WARNING_USER,
|
||||
META_WARNING_DONE
|
||||
};
|
||||
|
||||
@@ -213,18 +213,18 @@ void processWarningFlag(char *flag)
|
||||
{
|
||||
static bool setError = false;
|
||||
|
||||
/* First, try to match against a "meta" warning */
|
||||
// First, try to match against a "meta" warning
|
||||
for (enum WarningID id = META_WARNINGS_START; id < NB_WARNINGS; id++) {
|
||||
/* TODO: improve the matching performance? */
|
||||
// TODO: improve the matching performance?
|
||||
if (!strcmp(flag, warningFlags[id])) {
|
||||
/* We got a match! */
|
||||
// We got a match!
|
||||
if (setError)
|
||||
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++) {
|
||||
/* Warning flag, set without override */
|
||||
// Warning flag, set without override
|
||||
if (warningStates[*ptr] == WARNING_DEFAULT)
|
||||
warningStates[*ptr] = WARNING_ENABLED;
|
||||
}
|
||||
@@ -233,31 +233,31 @@ void processWarningFlag(char *flag)
|
||||
}
|
||||
}
|
||||
|
||||
/* If it's not a meta warning, specially check against `-Werror` */
|
||||
// If it's not a meta warning, specially check against `-Werror`
|
||||
if (!strncmp(flag, "error", strlen("error"))) {
|
||||
char *errorFlag = flag + strlen("error");
|
||||
|
||||
switch (*errorFlag) {
|
||||
case '\0':
|
||||
/* `-Werror` */
|
||||
// `-Werror`
|
||||
warningsAreErrors = true;
|
||||
return;
|
||||
|
||||
case '=':
|
||||
/* `-Werror=XXX` */
|
||||
// `-Werror=XXX`
|
||||
setError = true;
|
||||
processWarningFlag(errorFlag + 1); /* Skip the `=` */
|
||||
processWarningFlag(errorFlag + 1); // Skip the `=`
|
||||
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 */
|
||||
// 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 */
|
||||
// Not an error, then check if this is a negation
|
||||
strncmp(flag, "no-", strlen("no-")) ? WARNING_ENABLED
|
||||
: WARNING_DISABLED;
|
||||
char const *rootFlag = state == WARNING_DISABLED ? flag + strlen("no-") : flag;
|
||||
@@ -308,10 +308,10 @@ void processWarningFlag(char *flag)
|
||||
}
|
||||
}
|
||||
|
||||
/* Try to match the flag against a "normal" flag */
|
||||
// Try to match the flag against a "normal" flag
|
||||
for (enum WarningID id = 0; id < NB_PLAIN_WARNINGS; id++) {
|
||||
if (!strcmp(rootFlag, warningFlags[id])) {
|
||||
/* We got a match! */
|
||||
// We got a match!
|
||||
warningStates[id] = state;
|
||||
return;
|
||||
}
|
||||
@@ -374,7 +374,7 @@ void warning(enum WarningID id, char const *fmt, ...)
|
||||
|
||||
case WARNING_DEFAULT:
|
||||
unreachable_();
|
||||
/* Not reached */
|
||||
// Not reached
|
||||
|
||||
case WARNING_ENABLED:
|
||||
break;
|
||||
|
||||
@@ -29,7 +29,7 @@
|
||||
|
||||
#define BANK_SIZE 0x4000
|
||||
|
||||
/* Short options */
|
||||
// Short options
|
||||
static const char *optstring = "Ccf:i:jk:l:m:n:Op:r:st:Vv";
|
||||
|
||||
/*
|
||||
@@ -191,7 +191,7 @@ static void printAcceptedMBCNames(void)
|
||||
|
||||
static uint8_t tpp1Rev[2];
|
||||
|
||||
/**
|
||||
/*
|
||||
* @return False on failure
|
||||
*/
|
||||
static bool readMBCSlice(char const **name, char const *expected)
|
||||
@@ -837,7 +837,7 @@ static ssize_t writeBytes(int fd, void *buf, size_t len)
|
||||
return total;
|
||||
}
|
||||
|
||||
/**
|
||||
/*
|
||||
* @param rom0 A pointer to rom0
|
||||
* @param addr What address to check
|
||||
* @param fixedByte The fixed byte at the address
|
||||
@@ -853,7 +853,7 @@ static void overwriteByte(uint8_t *rom0, uint16_t addr, uint8_t fixedByte, char
|
||||
rom0[addr] = fixedByte;
|
||||
}
|
||||
|
||||
/**
|
||||
/*
|
||||
* @param rom0 A pointer to rom0
|
||||
* @param startAddr What address to begin checking from
|
||||
* @param fixed The fixed bytes at the address
|
||||
@@ -878,7 +878,7 @@ static void overwriteBytes(uint8_t *rom0, uint16_t startAddr, uint8_t const *fix
|
||||
memcpy(&rom0[startAddr], fixed, size);
|
||||
}
|
||||
|
||||
/**
|
||||
/*
|
||||
* @param input File descriptor to be used for reading
|
||||
* @param output File descriptor to be used for writing, may be equal to `input`
|
||||
* @param name The file's name, to be displayed for error output
|
||||
|
||||
@@ -153,7 +153,7 @@ static void printUsage(void) {
|
||||
exit(1);
|
||||
}
|
||||
|
||||
/**
|
||||
/*
|
||||
* Parses a number at the beginning of a string, moving the pointer to skip the parsed characters
|
||||
* Returns the provided errVal on error
|
||||
*/
|
||||
@@ -179,7 +179,7 @@ static uint16_t parseNumber(char *&string, char const *errPrefix, uint16_t errVa
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
/*
|
||||
* Turns a digit into its numeric value in the current base, if it has one.
|
||||
* Maximum is inclusive. The string_view is modified to "consume" all digits.
|
||||
* Returns 255 on parse failure (including wrong char for base), in which case
|
||||
@@ -248,7 +248,7 @@ static void registerInput(char const *arg) {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
/*
|
||||
* Turn an "at-file"'s contents into an argv that `getopt` can handle
|
||||
* @param argPool Argument characters will be appended to this vector, for storage purposes.
|
||||
*/
|
||||
@@ -317,7 +317,7 @@ static std::vector<size_t> readAtFile(std::string const &path, std::vector<char>
|
||||
} while (c != '\n' && c != EOF); // End if we reached EOL
|
||||
}
|
||||
}
|
||||
/**
|
||||
/*
|
||||
* Parses an arg vector, modifying `options` as options are read.
|
||||
* The three booleans are for the "auto path" flags, since their processing must be deferred to the
|
||||
* end of option parsing.
|
||||
@@ -785,7 +785,7 @@ void Palette::addColor(uint16_t color) {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
/*
|
||||
* Returns the ID of the color in the palette, or `size()` if the color is not in
|
||||
*/
|
||||
uint8_t Palette::indexOf(uint16_t color) const {
|
||||
|
||||
@@ -39,12 +39,12 @@ namespace packing {
|
||||
// Tile | Proto-palette
|
||||
// Page | Palette
|
||||
|
||||
/**
|
||||
/*
|
||||
* A reference to a proto-palette, and attached attributes for sorting purposes
|
||||
*/
|
||||
struct ProtoPalAttrs {
|
||||
size_t const protoPalIndex;
|
||||
/**
|
||||
/*
|
||||
* Pages from which we are banned (to prevent infinite loops)
|
||||
* This is dynamic because we wish not to hard-cap the amount of palettes
|
||||
*/
|
||||
@@ -62,7 +62,7 @@ struct ProtoPalAttrs {
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
/*
|
||||
* A collection of proto-palettes assigned to a palette
|
||||
* Does not contain the actual color indices because we need to be able to remove elements
|
||||
*/
|
||||
@@ -139,7 +139,7 @@ public:
|
||||
}
|
||||
const_iterator end() const { return const_iterator{&_assigned, _assigned.end()}; }
|
||||
|
||||
/**
|
||||
/*
|
||||
* Assigns a new ProtoPalAttrs in a free slot, assuming there is one
|
||||
* Args are passed to the `ProtoPalAttrs`'s constructor
|
||||
*/
|
||||
@@ -198,7 +198,7 @@ private:
|
||||
return colors;
|
||||
}
|
||||
public:
|
||||
/**
|
||||
/*
|
||||
* Returns the number of distinct colors
|
||||
*/
|
||||
size_t volume() const { return uniqueColors().size(); }
|
||||
@@ -208,7 +208,7 @@ public:
|
||||
return colors.size() <= options.maxOpaqueColors();
|
||||
}
|
||||
|
||||
/**
|
||||
/*
|
||||
* Computes the "relative size" of a proto-palette on this palette
|
||||
*/
|
||||
double relSizeOf(ProtoPalette const &protoPal) const {
|
||||
@@ -227,7 +227,7 @@ public:
|
||||
return relSize;
|
||||
}
|
||||
|
||||
/**
|
||||
/*
|
||||
* Computes the "relative size" of a set of proto-palettes on this palette
|
||||
*/
|
||||
template<typename Iter>
|
||||
@@ -237,7 +237,7 @@ public:
|
||||
addUniqueColors(colors, std::forward<Iter>(begin), end, protoPals);
|
||||
return colors.size();
|
||||
}
|
||||
/**
|
||||
/*
|
||||
* Computes the "relative size" of a set of colors on this palette
|
||||
*/
|
||||
template<typename Iter>
|
||||
|
||||
@@ -1,3 +1,10 @@
|
||||
/*
|
||||
* This file is part of RGBDS.
|
||||
*
|
||||
* Copyright (c) 2022, Eldred Habert and RGBDS contributors.
|
||||
*
|
||||
* SPDX-License-Identifier: MIT
|
||||
*/
|
||||
|
||||
#include "gfx/pal_sorting.hpp"
|
||||
|
||||
|
||||
@@ -165,7 +165,7 @@ void parseInlinePalSpec(char const * const rawArg) {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
/*
|
||||
* Tries to read some magic bytes from the provided `file`.
|
||||
* Returns whether the magic was correctly read.
|
||||
*/
|
||||
@@ -191,7 +191,7 @@ static T readBE(U const *bytes) {
|
||||
return val;
|
||||
}
|
||||
|
||||
/**
|
||||
/*
|
||||
* **Appends** the first line read from `file` to the end of the provided `buffer`.
|
||||
*/
|
||||
static void readLine(std::filebuf &file, std::string &buffer) {
|
||||
@@ -214,7 +214,7 @@ static void readLine(std::filebuf &file, std::string &buffer) {
|
||||
}
|
||||
|
||||
// FIXME: Normally we'd use `std::from_chars`, but that's not available with GCC 7
|
||||
/**
|
||||
/*
|
||||
* Parses the initial part of a string_view, advancing the "read index" as it does
|
||||
*/
|
||||
static uint16_t parseDec(std::string const &str, std::string::size_type &n) {
|
||||
|
||||
@@ -42,7 +42,7 @@ class ImagePalette {
|
||||
public:
|
||||
ImagePalette() = default;
|
||||
|
||||
/**
|
||||
/*
|
||||
* Registers a color in the palette.
|
||||
* If the newly inserted color "conflicts" with another one (different color, but same CGB
|
||||
* color), then the other color is returned. Otherwise, `nullptr` is returned.
|
||||
@@ -164,7 +164,7 @@ public:
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
/*
|
||||
* Reads a PNG and notes all of its colors
|
||||
*
|
||||
* This code is more complicated than strictly necessary, but that's because of the API
|
||||
@@ -466,7 +466,7 @@ public:
|
||||
};
|
||||
|
||||
class RawTiles {
|
||||
/**
|
||||
/*
|
||||
* A tile which only contains indices into the image's global palette
|
||||
*/
|
||||
class RawTile {
|
||||
@@ -481,7 +481,7 @@ private:
|
||||
std::vector<RawTile> _tiles;
|
||||
|
||||
public:
|
||||
/**
|
||||
/*
|
||||
* Creates a new raw tile, and returns a reference to it so it can be filled in
|
||||
*/
|
||||
RawTile &newTile() {
|
||||
@@ -491,7 +491,7 @@ public:
|
||||
};
|
||||
|
||||
struct AttrmapEntry {
|
||||
/**
|
||||
/*
|
||||
* This field can either be a proto-palette ID, or `transparent` to indicate that the
|
||||
* corresponding tile is fully transparent. If you are looking to get the palette ID for this
|
||||
* attrmap entry while correctly handling the above, use `getPalID`.
|
||||
@@ -831,7 +831,7 @@ struct UniqueTiles {
|
||||
UniqueTiles(UniqueTiles const &) = delete;
|
||||
UniqueTiles(UniqueTiles &&) = default;
|
||||
|
||||
/**
|
||||
/*
|
||||
* Adds a tile to the collection, and returns its ID
|
||||
*/
|
||||
std::tuple<uint16_t, TileData::MatchType> addTile(Png::TilesVisitor::Tile const &tile,
|
||||
@@ -857,7 +857,7 @@ struct UniqueTiles {
|
||||
auto end() const { return tiles.end(); }
|
||||
};
|
||||
|
||||
/**
|
||||
/*
|
||||
* Generate tile data while deduplicating unique tiles (via mirroring if enabled)
|
||||
* Additionally, while we have the info handy, convert from the 16-bit "global" tile IDs to
|
||||
* 8-bit tile IDs + the bank bit; this will save the work when we output the data later (potentially
|
||||
@@ -986,16 +986,17 @@ void process() {
|
||||
protoPalettes[n] = tileColors; // Override them
|
||||
// Remove any other proto-palettes that we encompass
|
||||
// (Example [(0, 1), (0, 2)], inserting (0, 1, 2))
|
||||
/* The following code does its job, except that references to the removed
|
||||
/*
|
||||
* The following code does its job, except that references to the removed
|
||||
* proto-palettes are not updated, causing issues.
|
||||
* TODO: overlap might not be detrimental to the packing algorithm.
|
||||
* Investigation is necessary, especially if pathological cases are found.
|
||||
|
||||
for (size_t i = protoPalettes.size(); --i != n;) {
|
||||
if (tileColors.compare(protoPalettes[i]) == ProtoPalette::WE_BIGGER) {
|
||||
protoPalettes.erase(protoPalettes.begin() + i);
|
||||
}
|
||||
}
|
||||
*
|
||||
* for (size_t i = protoPalettes.size(); --i != n;) {
|
||||
* if (tileColors.compare(protoPalettes[i]) == ProtoPalette::WE_BIGGER) {
|
||||
* protoPalettes.erase(protoPalettes.begin() + i);
|
||||
* }
|
||||
* }
|
||||
*/
|
||||
[[fallthrough]];
|
||||
|
||||
|
||||
@@ -1,3 +1,11 @@
|
||||
/*
|
||||
* This file is part of RGBDS.
|
||||
*
|
||||
* Copyright (c) 2022, Eldred Habert and RGBDS contributors.
|
||||
*
|
||||
* SPDX-License-Identifier: MIT
|
||||
*/
|
||||
|
||||
#include "gfx/rgba.hpp"
|
||||
|
||||
#include <assert.h>
|
||||
|
||||
@@ -15,10 +15,8 @@
|
||||
#include "error.h"
|
||||
#include "hashmap.h"
|
||||
|
||||
/*
|
||||
* The lower half of the hash is used to index the "master" table,
|
||||
* the upper half is used to help resolve collisions more quickly
|
||||
*/
|
||||
// The lower half of the hash is used to index the "master" table,
|
||||
// the upper half is used to help resolve collisions more quickly
|
||||
#define UINT_BITS_(NB_BITS) uint##NB_BITS##_t
|
||||
#define UINT_BITS(NB_BITS) UINT_BITS_(NB_BITS)
|
||||
typedef UINT_BITS(HASH_NB_BITS) HashType;
|
||||
@@ -34,7 +32,7 @@ struct HashMapEntry {
|
||||
#define FNV_OFFSET_BASIS 0x811c9dc5
|
||||
#define FNV_PRIME 16777619
|
||||
|
||||
/* FNV-1a hash */
|
||||
// FNV-1a hash
|
||||
static HashType hash(char const *str)
|
||||
{
|
||||
HashType hash = FNV_OFFSET_BASIS;
|
||||
|
||||
@@ -34,14 +34,12 @@ struct FreeSpace {
|
||||
struct FreeSpace *next, *prev;
|
||||
};
|
||||
|
||||
/* Table of free space for each bank */
|
||||
// Table of free space for each bank
|
||||
struct FreeSpace *memory[SECTTYPE_INVALID];
|
||||
|
||||
uint64_t nbSectionsToAssign;
|
||||
|
||||
/**
|
||||
* Init the free space-modelling structs
|
||||
*/
|
||||
// Init the free space-modelling structs
|
||||
static void initFreeSpace(void)
|
||||
{
|
||||
for (enum SectionType type = 0; type < SECTTYPE_INVALID; type++) {
|
||||
@@ -63,7 +61,7 @@ static void initFreeSpace(void)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
/*
|
||||
* Assigns a section to a given memory location
|
||||
* @param section The section to assign
|
||||
* @param location The location to assign the section to
|
||||
@@ -85,7 +83,7 @@ static void assignSection(struct Section *section, struct MemoryLocation const *
|
||||
out_AddSection(section);
|
||||
}
|
||||
|
||||
/**
|
||||
/*
|
||||
* Checks whether a given location is suitable for placing a given section
|
||||
* This checks not only that the location has enough room for the section, but
|
||||
* also that the constraints (alignment...) are respected.
|
||||
@@ -111,7 +109,7 @@ static bool isLocationSuitable(struct Section const *section,
|
||||
<= freeSpace->address + freeSpace->size;
|
||||
}
|
||||
|
||||
/**
|
||||
/*
|
||||
* Finds a suitable location to place a section at.
|
||||
* @param section The section to be placed
|
||||
* @param location A pointer to a location struct that will be filled
|
||||
@@ -146,61 +144,57 @@ static struct FreeSpace *getPlacement(struct Section const *section,
|
||||
struct FreeSpace *space;
|
||||
|
||||
for (;;) {
|
||||
/* Switch to the beginning of the next bank */
|
||||
// Switch to the beginning of the next bank
|
||||
#define BANK_INDEX (location->bank - sectionTypeInfo[section->type].firstBank)
|
||||
space = memory[section->type][BANK_INDEX].next;
|
||||
if (space)
|
||||
location->address = space->address;
|
||||
|
||||
/* Process locations in that bank */
|
||||
// Process locations in that bank
|
||||
while (space) {
|
||||
/* If that location is OK, return it */
|
||||
// If that location is OK, return it
|
||||
if (isLocationSuitable(section, space, location))
|
||||
return space;
|
||||
|
||||
/* Go to the next *possible* location */
|
||||
// Go to the next *possible* location
|
||||
if (section->isAddressFixed) {
|
||||
/*
|
||||
* If the address is fixed, there can be only
|
||||
* one candidate block per bank; if we already
|
||||
* reached it, give up.
|
||||
*/
|
||||
// If the address is fixed, there can be only
|
||||
// one candidate block per bank; if we already
|
||||
// reached it, give up.
|
||||
if (location->address < section->org)
|
||||
location->address = section->org;
|
||||
else
|
||||
/* Try again in next bank */
|
||||
// Try again in next bank
|
||||
space = NULL;
|
||||
} else if (section->isAlignFixed) {
|
||||
/* Move to next aligned location */
|
||||
/* Move back to alignment boundary */
|
||||
// Move to next aligned location
|
||||
// Move back to alignment boundary
|
||||
location->address -= section->alignOfs;
|
||||
/* Ensure we're there (e.g. on first check) */
|
||||
// Ensure we're there (e.g. on first check)
|
||||
location->address &= ~section->alignMask;
|
||||
/* Go to next align boundary and add offset */
|
||||
// Go to next align boundary and add offset
|
||||
location->address += section->alignMask + 1
|
||||
+ section->alignOfs;
|
||||
} else {
|
||||
/* Any location is fine, so, next free block */
|
||||
// Any location is fine, so, next free block
|
||||
space = space->next;
|
||||
if (space)
|
||||
location->address = space->address;
|
||||
}
|
||||
|
||||
/*
|
||||
* If that location is past the current block's end,
|
||||
* go forwards until that is no longer the case.
|
||||
*/
|
||||
// If that location is past the current block's end,
|
||||
// go forwards until that is no longer the case.
|
||||
while (space && location->address >=
|
||||
space->address + space->size)
|
||||
space = space->next;
|
||||
|
||||
/* Try again with the new location/free space combo */
|
||||
// Try again with the new location/free space combo
|
||||
}
|
||||
|
||||
if (section->isBankFixed)
|
||||
return NULL;
|
||||
|
||||
/* Try again in the next bank */
|
||||
// Try again in the next bank
|
||||
location->bank++;
|
||||
if (location->bank > sectionTypeInfo[section->type].lastBank)
|
||||
return NULL;
|
||||
@@ -208,7 +202,7 @@ static struct FreeSpace *getPlacement(struct Section const *section,
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
/*
|
||||
* Places a section in a suitable location, or error out if it fails to.
|
||||
* @warning Due to the implemented algorithm, this should be called with
|
||||
* sections of decreasing size.
|
||||
@@ -218,12 +212,10 @@ static void placeSection(struct Section *section)
|
||||
{
|
||||
struct MemoryLocation location;
|
||||
|
||||
/* Specially handle 0-byte SECTIONs, as they can't overlap anything */
|
||||
// Specially handle 0-byte SECTIONs, as they can't overlap anything
|
||||
if (section->size == 0) {
|
||||
/*
|
||||
* Unless the SECTION's address was fixed, the starting address
|
||||
* is fine for any alignment, as checked in sect_DoSanityChecks.
|
||||
*/
|
||||
// Unless the SECTION's address was fixed, the starting address
|
||||
// is fine for any alignment, as checked in sect_DoSanityChecks.
|
||||
location.address = section->isAddressFixed
|
||||
? section->org
|
||||
: sectionTypeInfo[section->type].startAddr;
|
||||
@@ -234,60 +226,56 @@ static void placeSection(struct Section *section)
|
||||
return;
|
||||
}
|
||||
|
||||
/*
|
||||
* Place section using first-fit decreasing algorithm
|
||||
* https://en.wikipedia.org/wiki/Bin_packing_problem#First-fit_algorithm
|
||||
*/
|
||||
// Place section using first-fit decreasing algorithm
|
||||
// https://en.wikipedia.org/wiki/Bin_packing_problem#First-fit_algorithm
|
||||
struct FreeSpace *freeSpace = getPlacement(section, &location);
|
||||
|
||||
if (freeSpace) {
|
||||
assignSection(section, &location);
|
||||
|
||||
/* Split the free space */
|
||||
// Split the free space
|
||||
bool noLeftSpace = freeSpace->address == section->org;
|
||||
bool noRightSpace = freeSpace->address + freeSpace->size
|
||||
== section->org + section->size;
|
||||
if (noLeftSpace && noRightSpace) {
|
||||
/* The free space is entirely deleted */
|
||||
// The free space is entirely deleted
|
||||
freeSpace->prev->next = freeSpace->next;
|
||||
if (freeSpace->next)
|
||||
freeSpace->next->prev = freeSpace->prev;
|
||||
/*
|
||||
* If the space is the last one on the list, set its
|
||||
* size to 0 so it doesn't get picked, but don't free()
|
||||
* it as it will be freed when cleaning up
|
||||
*/
|
||||
// If the space is the last one on the list, set its
|
||||
// size to 0 so it doesn't get picked, but don't free()
|
||||
// it as it will be freed when cleaning up
|
||||
free(freeSpace);
|
||||
} else if (!noLeftSpace && !noRightSpace) {
|
||||
/* The free space is split in two */
|
||||
// The free space is split in two
|
||||
struct FreeSpace *newSpace = malloc(sizeof(*newSpace));
|
||||
|
||||
if (!newSpace)
|
||||
err("Failed to split new free space");
|
||||
/* Append the new space after the chosen one */
|
||||
// Append the new space after the chosen one
|
||||
newSpace->prev = freeSpace;
|
||||
newSpace->next = freeSpace->next;
|
||||
if (freeSpace->next)
|
||||
freeSpace->next->prev = newSpace;
|
||||
freeSpace->next = newSpace;
|
||||
/* Set its parameters */
|
||||
// Set its parameters
|
||||
newSpace->address = section->org + section->size;
|
||||
newSpace->size = freeSpace->address + freeSpace->size -
|
||||
newSpace->address;
|
||||
/* Set the original space's new parameters */
|
||||
// Set the original space's new parameters
|
||||
freeSpace->size = section->org - freeSpace->address;
|
||||
/* address is unmodified */
|
||||
// address is unmodified
|
||||
} else {
|
||||
/* The amount of free spaces doesn't change: resize! */
|
||||
// The amount of free spaces doesn't change: resize!
|
||||
freeSpace->size -= section->size;
|
||||
if (noLeftSpace)
|
||||
/* The free space is moved *and* resized */
|
||||
// The free space is moved *and* resized
|
||||
freeSpace->address += section->size;
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
/* Please adjust depending on longest message below */
|
||||
// Please adjust depending on longest message below
|
||||
char where[64];
|
||||
|
||||
if (section->isBankFixed && nbbanks(section->type) != 1) {
|
||||
@@ -312,16 +300,16 @@ static void placeSection(struct Section *section)
|
||||
strcpy(where, "anywhere");
|
||||
}
|
||||
|
||||
/* If a section failed to go to several places, nothing we can report */
|
||||
// If a section failed to go to several places, nothing we can report
|
||||
if (!section->isBankFixed || !section->isAddressFixed)
|
||||
errx("Unable to place \"%s\" (%s section) %s",
|
||||
section->name, sectionTypeInfo[section->type].name, where);
|
||||
/* If the section just can't fit the bank, report that */
|
||||
// If the section just can't fit the bank, report that
|
||||
else if (section->org + section->size > endaddr(section->type) + 1)
|
||||
errx("Unable to place \"%s\" (%s section) %s: section runs past end of region ($%04x > $%04x)",
|
||||
section->name, sectionTypeInfo[section->type].name, where,
|
||||
section->org + section->size, endaddr(section->type) + 1);
|
||||
/* Otherwise there is overlap with another section */
|
||||
// Otherwise there is overlap with another section
|
||||
else
|
||||
errx("Unable to place \"%s\" (%s section) %s: section overlaps with \"%s\"",
|
||||
section->name, sectionTypeInfo[section->type].name, where,
|
||||
@@ -339,7 +327,7 @@ struct UnassignedSection {
|
||||
static struct UnassignedSection *unassignedSections[1 << 3] = {0};
|
||||
static struct UnassignedSection *sections;
|
||||
|
||||
/**
|
||||
/*
|
||||
* Categorize a section depending on how constrained it is
|
||||
* This is so the most-constrained sections are placed first
|
||||
* @param section The section to categorize
|
||||
@@ -354,13 +342,13 @@ static void categorizeSection(struct Section *section, void *arg)
|
||||
constraints |= BANK_CONSTRAINED;
|
||||
if (section->isAddressFixed)
|
||||
constraints |= ORG_CONSTRAINED;
|
||||
/* Can't have both! */
|
||||
// Can't have both!
|
||||
else if (section->isAlignFixed)
|
||||
constraints |= ALIGN_CONSTRAINED;
|
||||
|
||||
struct UnassignedSection **ptr = &unassignedSections[constraints];
|
||||
|
||||
/* Insert section while keeping the list sorted by decreasing size */
|
||||
// Insert section while keeping the list sorted by decreasing size
|
||||
while (*ptr && (*ptr)->section->size > section->size)
|
||||
ptr = &(*ptr)->next;
|
||||
|
||||
@@ -375,9 +363,9 @@ void assign_AssignSections(void)
|
||||
{
|
||||
verbosePrint("Beginning assignment...\n");
|
||||
|
||||
/** Initialize assignment **/
|
||||
// Initialize assignment
|
||||
|
||||
/* Generate linked lists of sections to assign */
|
||||
// Generate linked lists of sections to assign
|
||||
sections = malloc(sizeof(*sections) * nbSectionsToAssign + 1);
|
||||
if (!sections)
|
||||
err("Failed to allocate memory for section assignment");
|
||||
@@ -387,9 +375,9 @@ void assign_AssignSections(void)
|
||||
nbSectionsToAssign = 0;
|
||||
sect_ForEach(categorizeSection, NULL);
|
||||
|
||||
/** Place sections, starting with the most constrained **/
|
||||
// Place sections, starting with the most constrained
|
||||
|
||||
/* Specially process fully-constrained sections because of overlaying */
|
||||
// Specially process fully-constrained sections because of overlaying
|
||||
struct UnassignedSection *sectionPtr =
|
||||
unassignedSections[BANK_CONSTRAINED | ORG_CONSTRAINED];
|
||||
|
||||
@@ -399,11 +387,11 @@ void assign_AssignSections(void)
|
||||
sectionPtr = sectionPtr->next;
|
||||
}
|
||||
|
||||
/* If all sections were fully constrained, we have nothing left to do */
|
||||
// If all sections were fully constrained, we have nothing left to do
|
||||
if (!nbSectionsToAssign)
|
||||
return;
|
||||
|
||||
/* Overlaying requires only fully-constrained sections */
|
||||
// Overlaying requires only fully-constrained sections
|
||||
verbosePrint("Assigning other sections...\n");
|
||||
if (overlayFileName) {
|
||||
fprintf(stderr, "FATAL: All sections must be fixed when using an overlay file");
|
||||
@@ -427,7 +415,7 @@ max_out:
|
||||
exit(1);
|
||||
}
|
||||
|
||||
/* Assign all remaining sections by decreasing constraint order */
|
||||
// Assign all remaining sections by decreasing constraint order
|
||||
for (int8_t constraints = BANK_CONSTRAINED | ALIGN_CONSTRAINED;
|
||||
constraints >= 0; constraints--) {
|
||||
sectionPtr = unassignedSections[constraints];
|
||||
|
||||
@@ -33,34 +33,33 @@
|
||||
#include "platform.h"
|
||||
#include "version.h"
|
||||
|
||||
bool isDmgMode; /* -d */
|
||||
char *linkerScriptName; /* -l */
|
||||
char const *mapFileName; /* -m */
|
||||
bool noSymInMap; /* -M */
|
||||
char const *symFileName; /* -n */
|
||||
char const *overlayFileName; /* -O */
|
||||
char const *outputFileName; /* -o */
|
||||
uint8_t padValue; /* -p */
|
||||
bool isDmgMode; // -d
|
||||
char *linkerScriptName; // -l
|
||||
char const *mapFileName; // -m
|
||||
bool noSymInMap; // -M
|
||||
char const *symFileName; // -n
|
||||
char const *overlayFileName; // -O
|
||||
char const *outputFileName; // -o
|
||||
uint8_t padValue; // -p
|
||||
// Setting these three to 0 disables the functionality
|
||||
uint16_t scrambleROMX = 0; /* -S */
|
||||
uint16_t scrambleROMX = 0; // -S
|
||||
uint8_t scrambleWRAMX = 0;
|
||||
uint8_t scrambleSRAM = 0;
|
||||
bool is32kMode; /* -t */
|
||||
bool beVerbose; /* -v */
|
||||
bool isWRA0Mode; /* -w */
|
||||
bool disablePadding; /* -x */
|
||||
bool is32kMode; // -t
|
||||
bool beVerbose; // -v
|
||||
bool isWRA0Mode; // -w
|
||||
bool disablePadding; // -x
|
||||
|
||||
static uint32_t nbErrors = 0;
|
||||
|
||||
/***** Helper function to dump a file stack to stderr *****/
|
||||
|
||||
// Helper function to dump a file stack to stderr
|
||||
char const *dumpFileStack(struct FileStackNode const *node)
|
||||
{
|
||||
char const *lastName;
|
||||
|
||||
if (node->parent) {
|
||||
lastName = dumpFileStack(node->parent);
|
||||
/* REPT nodes use their parent's name */
|
||||
// REPT nodes use their parent's name
|
||||
if (node->type != NODE_REPT)
|
||||
lastName = node->name;
|
||||
fprintf(stderr, "(%" PRIu32 ") -> %s", node->lineNo, lastName);
|
||||
@@ -165,7 +164,7 @@ FILE *openFile(char const *fileName, char const *mode)
|
||||
return file;
|
||||
}
|
||||
|
||||
/* Short options */
|
||||
// Short options
|
||||
static const char *optstring = "dl:m:Mn:O:o:p:S:s:tVvWwx";
|
||||
|
||||
/*
|
||||
@@ -197,9 +196,7 @@ static struct option const longopts[] = {
|
||||
{ NULL, no_argument, NULL, 0 }
|
||||
};
|
||||
|
||||
/**
|
||||
* Prints the program's usage to stdout.
|
||||
*/
|
||||
// Prints the program's usage to stdout.
|
||||
static void printUsage(void)
|
||||
{
|
||||
fputs(
|
||||
@@ -219,10 +216,8 @@ static void printUsage(void)
|
||||
stderr);
|
||||
}
|
||||
|
||||
/**
|
||||
* Cleans up what has been done
|
||||
* Mostly here to please tools such as `valgrind` so actual errors can be seen
|
||||
*/
|
||||
// Cleans up what has been done
|
||||
// Mostly here to please tools such as `valgrind` so actual errors can be seen
|
||||
static void cleanup(void)
|
||||
{
|
||||
obj_Cleanup();
|
||||
@@ -362,10 +357,10 @@ _Noreturn void reportErrors(void) {
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
int optionChar;
|
||||
char *endptr; /* For error checking with `strtoul` */
|
||||
unsigned long value; /* For storing `strtoul`'s return value */
|
||||
char *endptr; // For error checking with `strtoul`
|
||||
unsigned long value; // For storing `strtoul`'s return value
|
||||
|
||||
/* Parse options */
|
||||
// Parse options
|
||||
while ((optionChar = musl_getopt_long_only(argc, argv, optstring,
|
||||
longopts, NULL)) != -1) {
|
||||
switch (optionChar) {
|
||||
@@ -407,7 +402,7 @@ int main(int argc, char *argv[])
|
||||
parseScrambleSpec(musl_optarg);
|
||||
break;
|
||||
case 's':
|
||||
/* FIXME: nobody knows what this does, figure it out */
|
||||
// FIXME: nobody knows what this does, figure it out
|
||||
(void)musl_optarg;
|
||||
warning(NULL, 0, "Nobody has any idea what `-s` does");
|
||||
break;
|
||||
@@ -425,7 +420,7 @@ int main(int argc, char *argv[])
|
||||
break;
|
||||
case 'x':
|
||||
disablePadding = true;
|
||||
/* implies tiny mode */
|
||||
// implies tiny mode
|
||||
is32kMode = true;
|
||||
break;
|
||||
default:
|
||||
@@ -436,41 +431,41 @@ int main(int argc, char *argv[])
|
||||
|
||||
int curArgIndex = musl_optind;
|
||||
|
||||
/* If no input files were specified, the user must have screwed up */
|
||||
// If no input files were specified, the user must have screwed up
|
||||
if (curArgIndex == argc) {
|
||||
fputs("FATAL: no input files\n", stderr);
|
||||
printUsage();
|
||||
exit(1);
|
||||
}
|
||||
|
||||
/* Patch the size array depending on command-line options */
|
||||
// Patch the size array depending on command-line options
|
||||
if (!is32kMode)
|
||||
sectionTypeInfo[SECTTYPE_ROM0].size = 0x4000;
|
||||
if (!isWRA0Mode)
|
||||
sectionTypeInfo[SECTTYPE_WRAM0].size = 0x1000;
|
||||
|
||||
/* Patch the bank ranges array depending on command-line options */
|
||||
// Patch the bank ranges array depending on command-line options
|
||||
if (isDmgMode)
|
||||
sectionTypeInfo[SECTTYPE_VRAM].lastBank = 0;
|
||||
|
||||
/* Read all object files first, */
|
||||
// Read all object files first,
|
||||
for (obj_Setup(argc - curArgIndex); curArgIndex < argc; curArgIndex++)
|
||||
obj_ReadFile(argv[curArgIndex], argc - curArgIndex - 1);
|
||||
|
||||
/* apply the linker script's modifications, */
|
||||
// apply the linker script's modifications,
|
||||
if (linkerScriptName) {
|
||||
verbosePrint("Reading linker script...\n");
|
||||
|
||||
linkerScript = openFile(linkerScriptName, "r");
|
||||
|
||||
/* Modify all sections according to the linker script */
|
||||
// Modify all sections according to the linker script
|
||||
struct SectionPlacement *placement;
|
||||
|
||||
while ((placement = script_NextSection())) {
|
||||
struct Section *section = placement->section;
|
||||
|
||||
assert(section->offset == 0);
|
||||
/* Check if this doesn't conflict with what the code says */
|
||||
// Check if this doesn't conflict with what the code says
|
||||
if (section->type == SECTTYPE_INVALID) {
|
||||
for (struct Section *sect = section; sect; sect = sect->nextu)
|
||||
sect->type = placement->type; // SDCC "unknown" sections
|
||||
@@ -493,7 +488,7 @@ int main(int argc, char *argv[])
|
||||
section->org = placement->org;
|
||||
section->isBankFixed = true;
|
||||
section->bank = placement->bank;
|
||||
section->isAlignFixed = false; /* The alignment is satisfied */
|
||||
section->isAlignFixed = false; // The alignment is satisfied
|
||||
}
|
||||
|
||||
fclose(linkerScript);
|
||||
@@ -506,7 +501,7 @@ int main(int argc, char *argv[])
|
||||
}
|
||||
|
||||
|
||||
/* then process them, */
|
||||
// then process them,
|
||||
obj_DoSanityChecks();
|
||||
if (nbErrors != 0)
|
||||
reportErrors();
|
||||
@@ -514,12 +509,12 @@ int main(int argc, char *argv[])
|
||||
obj_CheckAssertions();
|
||||
assign_Cleanup();
|
||||
|
||||
/* and finally output the result. */
|
||||
// and finally output the result.
|
||||
patch_ApplyPatches();
|
||||
if (nbErrors != 0)
|
||||
reportErrors();
|
||||
out_WriteFiles();
|
||||
|
||||
/* Do cleanup before quitting, though. */
|
||||
// Do cleanup before quitting, though.
|
||||
cleanup();
|
||||
}
|
||||
|
||||
@@ -39,12 +39,10 @@ static struct {
|
||||
} *nodes;
|
||||
static struct Assertion *assertions;
|
||||
|
||||
/***** Helper functions for reading object files *****/
|
||||
// Helper functions for reading object files
|
||||
|
||||
/*
|
||||
* Internal, DO NOT USE.
|
||||
* For helper wrapper macros defined below, such as `tryReadlong`
|
||||
*/
|
||||
// Internal, DO NOT USE.
|
||||
// For helper wrapper macros defined below, such as `tryReadlong`
|
||||
#define tryRead(func, type, errval, var, file, ...) \
|
||||
do { \
|
||||
FILE *tmpFile = file; \
|
||||
@@ -58,7 +56,7 @@ static struct Assertion *assertions;
|
||||
var = tmpVal; \
|
||||
} while (0)
|
||||
|
||||
/**
|
||||
/*
|
||||
* Reads an unsigned long (32-bit) value from a file.
|
||||
* @param file The file to read from. This will read 4 bytes from the file.
|
||||
* @return The value read, cast to a int64_t, or -1 on failure.
|
||||
@@ -67,25 +65,24 @@ static int64_t readlong(FILE *file)
|
||||
{
|
||||
uint32_t value = 0;
|
||||
|
||||
/* Read the little-endian value byte by byte */
|
||||
// Read the little-endian value byte by byte
|
||||
for (uint8_t shift = 0; shift < sizeof(value) * CHAR_BIT; shift += 8) {
|
||||
int byte = getc(file);
|
||||
|
||||
if (byte == EOF)
|
||||
return INT64_MAX;
|
||||
/* This must be casted to `unsigned`, not `uint8_t`. Rationale:
|
||||
* the type of the shift is the type of `byte` after undergoing
|
||||
* integer promotion, which would be `int` if this was casted to
|
||||
* `uint8_t`, because int is large enough to hold a byte. This
|
||||
* however causes values larger than 127 to be too large when
|
||||
* shifted, potentially triggering undefined behavior.
|
||||
*/
|
||||
// This must be casted to `unsigned`, not `uint8_t`. Rationale:
|
||||
// the type of the shift is the type of `byte` after undergoing
|
||||
// integer promotion, which would be `int` if this was casted to
|
||||
// `uint8_t`, because int is large enough to hold a byte. This
|
||||
// however causes values larger than 127 to be too large when
|
||||
// shifted, potentially triggering undefined behavior.
|
||||
value |= (unsigned int)byte << shift;
|
||||
}
|
||||
return value;
|
||||
}
|
||||
|
||||
/**
|
||||
/*
|
||||
* Helper macro for reading longs from a file, and errors out if it fails to.
|
||||
* Not as a function to avoid overhead in the general case.
|
||||
* @param var The variable to stash the number into
|
||||
@@ -96,9 +93,9 @@ static int64_t readlong(FILE *file)
|
||||
#define tryReadlong(var, file, ...) \
|
||||
tryRead(readlong, int64_t, INT64_MAX, var, file, __VA_ARGS__)
|
||||
|
||||
/* There is no `readbyte`, just use `fgetc` or `getc`. */
|
||||
// There is no `readbyte`, just use `fgetc` or `getc`.
|
||||
|
||||
/**
|
||||
/*
|
||||
* Helper macro for reading bytes from a file, and errors out if it fails to.
|
||||
* Differs from `tryGetc` in that the backing function is fgetc(1).
|
||||
* Not as a function to avoid overhead in the general case.
|
||||
@@ -110,7 +107,7 @@ static int64_t readlong(FILE *file)
|
||||
#define tryFgetc(var, file, ...) \
|
||||
tryRead(fgetc, int, EOF, var, file, __VA_ARGS__)
|
||||
|
||||
/**
|
||||
/*
|
||||
* Helper macro for reading bytes from a file, and errors out if it fails to.
|
||||
* Differs from `tryGetc` in that the backing function is fgetc(1).
|
||||
* Not as a function to avoid overhead in the general case.
|
||||
@@ -122,7 +119,7 @@ static int64_t readlong(FILE *file)
|
||||
#define tryGetc(var, file, ...) \
|
||||
tryRead(getc, int, EOF, var, file, __VA_ARGS__)
|
||||
|
||||
/**
|
||||
/*
|
||||
* Reads a '\0'-terminated string from a file.
|
||||
* @param file The file to read from. The file position will be advanced.
|
||||
* @return The string read, or NULL on failure.
|
||||
@@ -130,26 +127,26 @@ static int64_t readlong(FILE *file)
|
||||
*/
|
||||
static char *readstr(FILE *file)
|
||||
{
|
||||
/* Default buffer size, have it close to the average string length */
|
||||
// Default buffer size, have it close to the average string length
|
||||
size_t capacity = 32 / 2;
|
||||
size_t index = -1;
|
||||
/* Force the first iteration to allocate */
|
||||
// Force the first iteration to allocate
|
||||
char *str = NULL;
|
||||
|
||||
do {
|
||||
/* Prepare going to next char */
|
||||
// Prepare going to next char
|
||||
index++;
|
||||
|
||||
/* If the buffer isn't suitable to write the next char... */
|
||||
// If the buffer isn't suitable to write the next char...
|
||||
if (index >= capacity || !str) {
|
||||
capacity *= 2;
|
||||
str = realloc(str, capacity);
|
||||
/* End now in case of error */
|
||||
// End now in case of error
|
||||
if (!str)
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* Read char */
|
||||
// Read char
|
||||
int byte = getc(file);
|
||||
|
||||
if (byte == EOF) {
|
||||
@@ -161,7 +158,7 @@ static char *readstr(FILE *file)
|
||||
return str;
|
||||
}
|
||||
|
||||
/**
|
||||
/*
|
||||
* Helper macro for reading bytes from a file, and errors out if it fails to.
|
||||
* Not as a function to avoid overhead in the general case.
|
||||
* @param var The variable to stash the string into
|
||||
@@ -172,9 +169,9 @@ static char *readstr(FILE *file)
|
||||
#define tryReadstr(var, file, ...) \
|
||||
tryRead(readstr, char*, NULL, var, file, __VA_ARGS__)
|
||||
|
||||
/***** Functions to parse object files *****/
|
||||
// Functions to parse object files
|
||||
|
||||
/**
|
||||
/*
|
||||
* Reads a file stack node form a file.
|
||||
* @param file The file to read from
|
||||
* @param nodes The file's array of nodes
|
||||
@@ -217,7 +214,7 @@ static void readFileStackNode(FILE *file, struct FileStackNode fileNodes[], uint
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
/*
|
||||
* Reads a symbol from a file.
|
||||
* @param file The file to read from
|
||||
* @param symbol The struct to fill
|
||||
@@ -230,7 +227,7 @@ static void readSymbol(FILE *file, struct Symbol *symbol,
|
||||
fileName);
|
||||
tryGetc(symbol->type, file, "%s: Cannot read \"%s\"'s type: %s",
|
||||
fileName, symbol->name);
|
||||
/* If the symbol is defined in this file, read its definition */
|
||||
// If the symbol is defined in this file, read its definition
|
||||
if (symbol->type != SYMTYPE_IMPORT) {
|
||||
symbol->objFileName = fileName;
|
||||
uint32_t nodeID;
|
||||
@@ -253,7 +250,7 @@ static void readSymbol(FILE *file, struct Symbol *symbol,
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
/*
|
||||
* Reads a patch from a file.
|
||||
* @param file The file to read from
|
||||
* @param patch The struct to fill
|
||||
@@ -303,7 +300,7 @@ static void readPatch(FILE *file, struct Patch *patch, char const *fileName, cha
|
||||
feof(file) ? "Unexpected end of file" : strerror(errno));
|
||||
}
|
||||
|
||||
/**
|
||||
/*
|
||||
* Sets a patch's pcSection from its pcSectionID.
|
||||
* @param patch The struct to fix
|
||||
*/
|
||||
@@ -313,7 +310,7 @@ static void linkPatchToPCSect(struct Patch *patch, struct Section *fileSections[
|
||||
: fileSections[patch->pcSectionID];
|
||||
}
|
||||
|
||||
/**
|
||||
/*
|
||||
* Reads a section from a file.
|
||||
* @param file The file to read from
|
||||
* @param section The struct to fill
|
||||
@@ -372,7 +369,7 @@ static void readSection(FILE *file, struct Section *section, char const *fileNam
|
||||
section->alignOfs = tmp;
|
||||
|
||||
if (sect_HasData(section->type)) {
|
||||
/* Ensure we never allocate 0 bytes */
|
||||
// Ensure we never allocate 0 bytes
|
||||
uint8_t *data = malloc(sizeof(*data) * section->size + 1);
|
||||
|
||||
if (!data)
|
||||
@@ -404,7 +401,7 @@ static void readSection(FILE *file, struct Section *section, char const *fileNam
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
/*
|
||||
* Links a symbol to a section, keeping the section's symbol list sorted.
|
||||
* @param symbol The symbol to link
|
||||
* @param section The section to link
|
||||
@@ -433,7 +430,7 @@ static void linkSymToSect(struct Symbol *symbol, struct Section *section)
|
||||
section->nbSymbols++;
|
||||
}
|
||||
|
||||
/**
|
||||
/*
|
||||
* Reads an assertion from a file
|
||||
* @param file The file to read from
|
||||
* @param assert The struct to fill
|
||||
@@ -500,7 +497,7 @@ void obj_ReadFile(char const *fileName, unsigned int fileID)
|
||||
return;
|
||||
}
|
||||
|
||||
/* Begin by reading the magic bytes */
|
||||
// Begin by reading the magic bytes
|
||||
int matchedElems;
|
||||
|
||||
if (fscanf(file, RGBDS_OBJECT_VERSION_STRING "%n", &matchedElems) == 1
|
||||
@@ -536,7 +533,7 @@ void obj_ReadFile(char const *fileName, unsigned int fileID)
|
||||
for (uint32_t i = nodes[fileID].nbNodes; i--; )
|
||||
readFileStackNode(file, nodes[fileID].nodes, i, fileName);
|
||||
|
||||
/* This file's symbols, kept to link sections to them */
|
||||
// This file's symbols, kept to link sections to them
|
||||
struct Symbol **fileSymbols = malloc(sizeof(*fileSymbols) * nbSymbols + 1);
|
||||
|
||||
if (!fileSymbols)
|
||||
@@ -556,7 +553,7 @@ void obj_ReadFile(char const *fileName, unsigned int fileID)
|
||||
|
||||
verbosePrint("Reading %" PRIu32 " symbols...\n", nbSymbols);
|
||||
for (uint32_t i = 0; i < nbSymbols; i++) {
|
||||
/* Read symbol */
|
||||
// Read symbol
|
||||
struct Symbol *symbol = malloc(sizeof(*symbol));
|
||||
|
||||
if (!symbol)
|
||||
@@ -570,13 +567,13 @@ void obj_ReadFile(char const *fileName, unsigned int fileID)
|
||||
nbSymPerSect[symbol->sectionID]++;
|
||||
}
|
||||
|
||||
/* This file's sections, stored in a table to link symbols to them */
|
||||
// This file's sections, stored in a table to link symbols to them
|
||||
struct Section **fileSections = malloc(sizeof(*fileSections)
|
||||
* (nbSections ? nbSections : 1));
|
||||
|
||||
verbosePrint("Reading %" PRIu32 " sections...\n", nbSections);
|
||||
for (uint32_t i = 0; i < nbSections; i++) {
|
||||
/* Read section */
|
||||
// Read section
|
||||
fileSections[i] = malloc(sizeof(*fileSections[i]));
|
||||
if (!fileSections[i])
|
||||
err("%s: Couldn't create new section", fileName);
|
||||
@@ -600,7 +597,7 @@ void obj_ReadFile(char const *fileName, unsigned int fileID)
|
||||
|
||||
free(nbSymPerSect);
|
||||
|
||||
/* Give patches' PC section pointers to their sections */
|
||||
// Give patches' PC section pointers to their sections
|
||||
for (uint32_t i = 0; i < nbSections; i++) {
|
||||
if (sect_HasData(fileSections[i]->type)) {
|
||||
for (uint32_t j = 0; j < fileSections[i]->nbPatches; j++)
|
||||
@@ -608,7 +605,7 @@ void obj_ReadFile(char const *fileName, unsigned int fileID)
|
||||
}
|
||||
}
|
||||
|
||||
/* Give symbols' section pointers to their sections */
|
||||
// Give symbols' section pointers to their sections
|
||||
for (uint32_t i = 0; i < nbSymbols; i++) {
|
||||
int32_t sectionID = fileSymbols[i]->sectionID;
|
||||
|
||||
@@ -617,12 +614,12 @@ void obj_ReadFile(char const *fileName, unsigned int fileID)
|
||||
} else {
|
||||
struct Section *section = fileSections[sectionID];
|
||||
|
||||
/* Give the section a pointer to the symbol as well */
|
||||
// Give the section a pointer to the symbol as well
|
||||
linkSymToSect(fileSymbols[i], section);
|
||||
|
||||
if (section->modifier != SECTION_NORMAL) {
|
||||
if (section->modifier == SECTION_FRAGMENT)
|
||||
/* Add the fragment's offset to the symbol's */
|
||||
// Add the fragment's offset to the symbol's
|
||||
fileSymbols[i]->offset += section->offset;
|
||||
section = getMainSection(section);
|
||||
}
|
||||
|
||||
@@ -47,7 +47,7 @@ static struct {
|
||||
} *banks;
|
||||
} sections[SECTTYPE_INVALID];
|
||||
|
||||
/* Defines the order in which types are output to the sym and map files */
|
||||
// Defines the order in which types are output to the sym and map files
|
||||
static enum SectionType typeMap[SECTTYPE_INVALID] = {
|
||||
SECTTYPE_ROM0,
|
||||
SECTTYPE_ROMX,
|
||||
@@ -124,7 +124,7 @@ struct Section const *out_OverlappingSection(struct Section const *section)
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/**
|
||||
/*
|
||||
* Performs sanity checks on the overlay file.
|
||||
* @return The number of ROM banks in the overlay file
|
||||
*/
|
||||
@@ -140,7 +140,7 @@ static uint32_t checkOverlaySize(void)
|
||||
|
||||
long overlaySize = ftell(overlayFile);
|
||||
|
||||
/* Reset back to beginning */
|
||||
// Reset back to beginning
|
||||
fseek(overlayFile, 0, SEEK_SET);
|
||||
|
||||
if (overlaySize % BANK_SIZE)
|
||||
@@ -157,7 +157,7 @@ static uint32_t checkOverlaySize(void)
|
||||
return nbOverlayBanks;
|
||||
}
|
||||
|
||||
/**
|
||||
/*
|
||||
* Expand sections[SECTTYPE_ROMX].banks to cover all the overlay banks.
|
||||
* This ensures that writeROM will output each bank, even if some are not
|
||||
* covered by any sections.
|
||||
@@ -165,9 +165,9 @@ static uint32_t checkOverlaySize(void)
|
||||
*/
|
||||
static void coverOverlayBanks(uint32_t nbOverlayBanks)
|
||||
{
|
||||
/* 2 if is32kMode, 1 otherwise */
|
||||
// 2 if is32kMode, 1 otherwise
|
||||
uint32_t nbRom0Banks = sectionTypeInfo[SECTTYPE_ROM0].size / BANK_SIZE;
|
||||
/* Discount ROM0 banks to avoid outputting too much */
|
||||
// Discount ROM0 banks to avoid outputting too much
|
||||
uint32_t nbUncoveredBanks = nbOverlayBanks - nbRom0Banks > sections[SECTTYPE_ROMX].nbBanks
|
||||
? nbOverlayBanks - nbRom0Banks
|
||||
: 0;
|
||||
@@ -186,7 +186,7 @@ static void coverOverlayBanks(uint32_t nbOverlayBanks)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
/*
|
||||
* Write a ROM bank's sections to the output file.
|
||||
* @param bankSections The bank's sections, ordered by increasing address
|
||||
* @param baseOffset The address of the bank's first byte in GB address space
|
||||
@@ -201,18 +201,18 @@ static void writeBank(struct SortedSection *bankSections, uint16_t baseOffset,
|
||||
struct Section const *section = bankSections->section;
|
||||
|
||||
assert(section->offset == 0);
|
||||
/* Output padding up to the next SECTION */
|
||||
// Output padding up to the next SECTION
|
||||
while (offset + baseOffset < section->org) {
|
||||
putc(overlayFile ? getc(overlayFile) : padValue,
|
||||
outputFile);
|
||||
offset++;
|
||||
}
|
||||
|
||||
/* Output the section itself */
|
||||
// Output the section itself
|
||||
fwrite(section->data, sizeof(*section->data), section->size,
|
||||
outputFile);
|
||||
if (overlayFile) {
|
||||
/* Skip bytes even with pipes */
|
||||
// Skip bytes even with pipes
|
||||
for (uint16_t i = 0; i < section->size; i++)
|
||||
getc(overlayFile);
|
||||
}
|
||||
@@ -231,9 +231,7 @@ static void writeBank(struct SortedSection *bankSections, uint16_t baseOffset,
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Writes a ROM file to the output.
|
||||
*/
|
||||
// Writes a ROM file to the output.
|
||||
static void writeROM(void)
|
||||
{
|
||||
outputFile = openFile(outputFileName, "wb");
|
||||
@@ -258,7 +256,7 @@ static void writeROM(void)
|
||||
closeFile(overlayFile);
|
||||
}
|
||||
|
||||
/**
|
||||
/*
|
||||
* Get the lowest section by address out of the two
|
||||
* @param s1 One choice
|
||||
* @param s2 The other
|
||||
@@ -275,10 +273,8 @@ static struct SortedSection const **nextSection(struct SortedSection const **s1,
|
||||
return (*s1)->section->org < (*s2)->section->org ? s1 : s2;
|
||||
}
|
||||
|
||||
/*
|
||||
* Comparator function for `qsort` to sort symbols
|
||||
* Symbols are ordered by address, or else by original index for a stable sort
|
||||
*/
|
||||
// Comparator function for `qsort` to sort symbols
|
||||
// Symbols are ordered by address, or else by original index for a stable sort
|
||||
static int compareSymbols(void const *a, void const *b)
|
||||
{
|
||||
struct SortedSymbol const *sym1 = (struct SortedSymbol const *)a;
|
||||
@@ -290,7 +286,7 @@ static int compareSymbols(void const *a, void const *b)
|
||||
return sym1->idx < sym2->idx ? -1 : sym1->idx > sym2->idx ? 1 : 0;
|
||||
}
|
||||
|
||||
/**
|
||||
/*
|
||||
* Write a bank's contents to the sym file
|
||||
* @param bankSections The bank's sections
|
||||
*/
|
||||
@@ -357,7 +353,7 @@ static void writeSymBank(struct SortedSections const *bankSections,
|
||||
free(symList);
|
||||
}
|
||||
|
||||
/**
|
||||
/*
|
||||
* Write a bank's contents to the map file
|
||||
* @param bankSections The bank's sections
|
||||
* @return The bank's used space
|
||||
@@ -445,7 +441,7 @@ static uint16_t writeMapBank(struct SortedSections const *sectList,
|
||||
return used;
|
||||
}
|
||||
|
||||
/**
|
||||
/*
|
||||
* Write the total used space by section type to the map file
|
||||
* @param usedMap The total used space by section type
|
||||
*/
|
||||
@@ -471,9 +467,7 @@ static void writeMapUsed(uint32_t usedMap[MIN_NB_ELMS(SECTTYPE_INVALID)])
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Writes the sym and/or map files, if applicable.
|
||||
*/
|
||||
// Writes the sym and/or map files, if applicable.
|
||||
static void writeSymAndMap(void)
|
||||
{
|
||||
if (!symFileName && !mapFileName)
|
||||
|
||||
@@ -63,11 +63,9 @@ static void pushRPN(int32_t value, bool comesFromError)
|
||||
realloc(stack.values, sizeof(*stack.values) * stack.capacity);
|
||||
stack.errorFlags =
|
||||
realloc(stack.errorFlags, sizeof(*stack.errorFlags) * stack.capacity);
|
||||
/*
|
||||
* Static analysis tools complain that the capacity might become
|
||||
* zero due to overflow, but fail to realize that it's caught by
|
||||
* the overflow check above. Hence the stringent check below.
|
||||
*/
|
||||
// Static analysis tools complain that the capacity might become
|
||||
// zero due to overflow, but fail to realize that it's caught by
|
||||
// the overflow check above. Hence the stringent check below.
|
||||
if (!stack.values || !stack.errorFlags || !stack.capacity)
|
||||
err("Failed to resize RPN stack");
|
||||
}
|
||||
@@ -97,7 +95,7 @@ static void freeRPNStack(void)
|
||||
free(stack.errorFlags);
|
||||
}
|
||||
|
||||
/* RPN operators */
|
||||
// RPN operators
|
||||
|
||||
static uint32_t getRPNByte(uint8_t const **expression, int32_t *size,
|
||||
struct FileStackNode const *node, uint32_t lineNo)
|
||||
@@ -111,17 +109,17 @@ static uint32_t getRPNByte(uint8_t const **expression, int32_t *size,
|
||||
static struct Symbol const *getSymbol(struct Symbol const * const *symbolList,
|
||||
uint32_t index)
|
||||
{
|
||||
assert(index != (uint32_t)-1); /* PC needs to be handled specially, not here */
|
||||
assert(index != (uint32_t)-1); // PC needs to be handled specially, not here
|
||||
struct Symbol const *symbol = symbolList[index];
|
||||
|
||||
/* If the symbol is defined elsewhere... */
|
||||
// If the symbol is defined elsewhere...
|
||||
if (symbol->type == SYMTYPE_IMPORT)
|
||||
return sym_GetSymbol(symbol->name);
|
||||
|
||||
return symbol;
|
||||
}
|
||||
|
||||
/**
|
||||
/*
|
||||
* Compute a patch's value from its RPN string.
|
||||
* @param patch The patch to compute the value of
|
||||
* @param section The section the patch is contained in
|
||||
@@ -132,7 +130,7 @@ static struct Symbol const *getSymbol(struct Symbol const * const *symbolList,
|
||||
static int32_t computeRPNExpr(struct Patch const *patch,
|
||||
struct Symbol const * const *fileSymbols)
|
||||
{
|
||||
/* Small shortcut to avoid a lot of repetition */
|
||||
// Small shortcut to avoid a lot of repetition
|
||||
#define popRPN() popRPN(patch->src, patch->lineNo)
|
||||
|
||||
uint8_t const *expression = patch->rpnExpression;
|
||||
@@ -147,13 +145,10 @@ static int32_t computeRPNExpr(struct Patch const *patch,
|
||||
|
||||
isError = false;
|
||||
|
||||
/*
|
||||
* Friendly reminder:
|
||||
* Be VERY careful with two `popRPN` in the same expression.
|
||||
* C does not guarantee order of evaluation of operands!!
|
||||
* So, if there are two `popRPN` in the same expression, make
|
||||
* sure the operation is commutative.
|
||||
*/
|
||||
// Be VERY careful with two `popRPN` in the same expression.
|
||||
// C does not guarantee order of evaluation of operands!!
|
||||
// So, if there are two `popRPN` in the same expression, make
|
||||
// sure the operation is commutative.
|
||||
switch (command) {
|
||||
struct Symbol const *symbol;
|
||||
char const *name;
|
||||
@@ -295,11 +290,9 @@ static int32_t computeRPNExpr(struct Patch const *patch,
|
||||
break;
|
||||
|
||||
case RPN_BANK_SECT:
|
||||
/*
|
||||
* `expression` is not guaranteed to be '\0'-terminated. If it is not,
|
||||
* `getRPNByte` will have a fatal internal error.
|
||||
* In either case, `getRPNByte` will not free `expression`.
|
||||
*/
|
||||
// `expression` is not guaranteed to be '\0'-terminated. If it is not,
|
||||
// `getRPNByte` will have a fatal internal error.
|
||||
// In either case, `getRPNByte` will not free `expression`.
|
||||
name = (char const *)expression;
|
||||
while (getRPNByte(&expression, &size, patch->src, patch->lineNo))
|
||||
;
|
||||
@@ -329,7 +322,7 @@ static int32_t computeRPNExpr(struct Patch const *patch,
|
||||
break;
|
||||
|
||||
case RPN_SIZEOF_SECT:
|
||||
/* This has assumptions commented in the `RPN_BANK_SECT` case above. */
|
||||
// This has assumptions commented in the `RPN_BANK_SECT` case above.
|
||||
name = (char const *)expression;
|
||||
while (getRPNByte(&expression, &size, patch->src, patch->lineNo))
|
||||
;
|
||||
@@ -348,7 +341,7 @@ static int32_t computeRPNExpr(struct Patch const *patch,
|
||||
break;
|
||||
|
||||
case RPN_STARTOF_SECT:
|
||||
/* This has assumptions commented in the `RPN_BANK_SECT` case above. */
|
||||
// This has assumptions commented in the `RPN_BANK_SECT` case above.
|
||||
name = (char const *)expression;
|
||||
while (getRPNByte(&expression, &size, patch->src, patch->lineNo))
|
||||
;
|
||||
@@ -381,9 +374,8 @@ static int32_t computeRPNExpr(struct Patch const *patch,
|
||||
|
||||
case RPN_RST:
|
||||
value = popRPN();
|
||||
/* Acceptable values are 0x00, 0x08, 0x10, ..., 0x38
|
||||
* They can be easily checked with a bitmask
|
||||
*/
|
||||
// Acceptable values are 0x00, 0x08, 0x10, ..., 0x38
|
||||
// They can be easily checked with a bitmask
|
||||
if (value & ~0x38) {
|
||||
if (!isError)
|
||||
error(patch->src, patch->lineNo,
|
||||
@@ -406,7 +398,7 @@ static int32_t computeRPNExpr(struct Patch const *patch,
|
||||
value |= getRPNByte(&expression, &size,
|
||||
patch->src, patch->lineNo) << shift;
|
||||
|
||||
if (value == -1) { /* PC */
|
||||
if (value == -1) { // PC
|
||||
if (!patch->pcSection) {
|
||||
error(patch->src, patch->lineNo,
|
||||
"PC has no value outside a section");
|
||||
@@ -424,7 +416,7 @@ static int32_t computeRPNExpr(struct Patch const *patch,
|
||||
isError = true;
|
||||
} else {
|
||||
value = symbol->value;
|
||||
/* Symbols attached to sections have offsets */
|
||||
// Symbols attached to sections have offsets
|
||||
if (symbol->section)
|
||||
value += symbol->section->org;
|
||||
}
|
||||
@@ -461,8 +453,8 @@ void patch_CheckAssertions(struct Assertion *assert)
|
||||
fatal(assert->patch.src, assert->patch.lineNo, "%s",
|
||||
assert->message[0] ? assert->message
|
||||
: "assert failure");
|
||||
/* Not reached */
|
||||
break; /* Here so checkpatch doesn't complain */
|
||||
// Not reached
|
||||
break; // Here so checkpatch doesn't complain
|
||||
case ASSERT_ERROR:
|
||||
error(assert->patch.src, assert->patch.lineNo, "%s",
|
||||
assert->message[0] ? assert->message
|
||||
@@ -491,7 +483,7 @@ void patch_CheckAssertions(struct Assertion *assert)
|
||||
freeRPNStack();
|
||||
}
|
||||
|
||||
/**
|
||||
/*
|
||||
* Applies all of a section's patches
|
||||
* @param section The section to patch
|
||||
* @param arg Ignored callback arg
|
||||
@@ -506,7 +498,7 @@ static void applyFilePatches(struct Section *section, struct Section *dataSectio
|
||||
section->fileSymbols);
|
||||
uint16_t offset = patch->offset + section->offset;
|
||||
|
||||
/* `jr` is quite unlike the others... */
|
||||
// `jr` is quite unlike the others...
|
||||
if (patch->type == PATCHTYPE_JR) {
|
||||
// Offset is relative to the byte *after* the operand
|
||||
// PC as operand to `jr` is lower than reference PC by 2
|
||||
@@ -519,7 +511,7 @@ static void applyFilePatches(struct Section *section, struct Section *dataSectio
|
||||
jumpOffset);
|
||||
dataSection->data[offset] = jumpOffset & 0xFF;
|
||||
} else {
|
||||
/* Patch a certain number of bytes */
|
||||
// Patch a certain number of bytes
|
||||
struct {
|
||||
uint8_t size;
|
||||
int32_t min;
|
||||
@@ -544,7 +536,7 @@ static void applyFilePatches(struct Section *section, struct Section *dataSectio
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
/*
|
||||
* Applies all of a section's patches, iterating over "components" of
|
||||
* unionized sections
|
||||
* @param section The section to patch
|
||||
|
||||
@@ -41,7 +41,7 @@ static void pushFile(char *newFileName)
|
||||
linkerScriptName, lineNo);
|
||||
|
||||
if (fileStackIndex == fileStackSize) {
|
||||
if (!fileStackSize) /* Init file stack */
|
||||
if (!fileStackSize) // Init file stack
|
||||
fileStackSize = 4;
|
||||
fileStackSize *= 2;
|
||||
fileStack = realloc(fileStack, sizeof(*fileStack) * fileStackSize);
|
||||
@@ -88,7 +88,7 @@ static bool isNewline(int c)
|
||||
return c == '\r' || c == '\n';
|
||||
}
|
||||
|
||||
/**
|
||||
/*
|
||||
* Try parsing a number, in base 16 if it begins with a dollar,
|
||||
* in base 10 otherwise
|
||||
* @param str The number to parse
|
||||
@@ -108,7 +108,7 @@ static bool tryParseNumber(char const *str, uint32_t *number)
|
||||
base = 16;
|
||||
}
|
||||
|
||||
/* An empty string is not a number */
|
||||
// An empty string is not a number
|
||||
if (!*str)
|
||||
return false;
|
||||
|
||||
@@ -188,16 +188,16 @@ static struct LinkerScriptToken *nextToken(void)
|
||||
static struct LinkerScriptToken token;
|
||||
int curchar;
|
||||
|
||||
/* If the token has a string, make sure to avoid leaking it */
|
||||
// If the token has a string, make sure to avoid leaking it
|
||||
if (token.type == TOKEN_STRING)
|
||||
free(token.attr.string);
|
||||
|
||||
/* Skip initial whitespace... */
|
||||
// Skip initial whitespace...
|
||||
do
|
||||
curchar = nextChar();
|
||||
while (isWhiteSpace(curchar));
|
||||
|
||||
/* If this is a comment, skip to the end of the line */
|
||||
// If this is a comment, skip to the end of the line
|
||||
if (curchar == ';') {
|
||||
do {
|
||||
curchar = nextChar();
|
||||
@@ -207,22 +207,22 @@ static struct LinkerScriptToken *nextToken(void)
|
||||
if (curchar == EOF) {
|
||||
token.type = TOKEN_EOF;
|
||||
} else if (isNewline(curchar)) {
|
||||
/* If we have a newline char, this is a newline token */
|
||||
// If we have a newline char, this is a newline token
|
||||
token.type = TOKEN_NEWLINE;
|
||||
|
||||
if (curchar == '\r') {
|
||||
/* Handle CRLF */
|
||||
// Handle CRLF
|
||||
curchar = nextChar();
|
||||
if (curchar != '\n')
|
||||
ungetc(curchar, linkerScript);
|
||||
}
|
||||
} else if (curchar == '"') {
|
||||
/* If we have a string start, this is a string */
|
||||
// If we have a string start, this is a string
|
||||
token.type = TOKEN_STRING;
|
||||
token.attr.string = NULL; /* Force initial alloc */
|
||||
token.attr.string = NULL; // Force initial alloc
|
||||
|
||||
size_t size = 0;
|
||||
size_t capacity = 16; /* Half of the default capacity */
|
||||
size_t capacity = 16; // Half of the default capacity
|
||||
|
||||
do {
|
||||
curchar = nextChar();
|
||||
@@ -230,10 +230,10 @@ static struct LinkerScriptToken *nextToken(void)
|
||||
errx("%s(%" PRIu32 "): Unterminated string",
|
||||
linkerScriptName, lineNo);
|
||||
} else if (curchar == '"') {
|
||||
/* Quotes force a string termination */
|
||||
// Quotes force a string termination
|
||||
curchar = '\0';
|
||||
} else if (curchar == '\\') {
|
||||
/* Backslashes are escape sequences */
|
||||
// Backslashes are escape sequences
|
||||
curchar = nextChar();
|
||||
if (curchar == EOF || isNewline(curchar))
|
||||
errx("%s(%" PRIu32 "): Unterminated string",
|
||||
@@ -259,10 +259,10 @@ static struct LinkerScriptToken *nextToken(void)
|
||||
token.attr.string[size++] = curchar;
|
||||
} while (curchar);
|
||||
} else {
|
||||
/* This is either a number, command or bank, that is: a word */
|
||||
// This is either a number, command or bank, that is: a word
|
||||
char *str = NULL;
|
||||
size_t size = 0;
|
||||
size_t capacity = 8; /* Half of the default capacity */
|
||||
size_t capacity = 8; // Half of the default capacity
|
||||
|
||||
for (;;) {
|
||||
if (size >= capacity || str == NULL) {
|
||||
@@ -279,7 +279,7 @@ static struct LinkerScriptToken *nextToken(void)
|
||||
break;
|
||||
|
||||
curchar = nextChar();
|
||||
/* Whitespace, a newline or a comment end the token */
|
||||
// Whitespace, a newline or a comment end the token
|
||||
if (isWhiteSpace(curchar) || isNewline(curchar) || curchar == ';') {
|
||||
ungetc(curchar, linkerScript);
|
||||
curchar = '\0';
|
||||
@@ -288,7 +288,7 @@ static struct LinkerScriptToken *nextToken(void)
|
||||
|
||||
token.type = TOKEN_INVALID;
|
||||
|
||||
/* Try to match a command */
|
||||
// Try to match a command
|
||||
for (enum LinkerScriptCommand i = 0; i < COMMAND_INVALID; i++) {
|
||||
if (!strcmp(commands[i], str)) {
|
||||
token.type = TOKEN_COMMAND;
|
||||
@@ -298,7 +298,7 @@ static struct LinkerScriptToken *nextToken(void)
|
||||
}
|
||||
|
||||
if (token.type == TOKEN_INVALID) {
|
||||
/* Try to match a bank specifier */
|
||||
// Try to match a bank specifier
|
||||
for (enum SectionType type = 0; type < SECTTYPE_INVALID; type++) {
|
||||
if (!strcmp(sectionTypeInfo[type].name, str)) {
|
||||
token.type = TOKEN_BANK;
|
||||
@@ -309,13 +309,13 @@ static struct LinkerScriptToken *nextToken(void)
|
||||
}
|
||||
|
||||
if (token.type == TOKEN_INVALID) {
|
||||
/* Try to match an include token */
|
||||
// Try to match an include token
|
||||
if (!strcmp("INCLUDE", str))
|
||||
token.type = TOKEN_INCLUDE;
|
||||
}
|
||||
|
||||
if (token.type == TOKEN_INVALID) {
|
||||
/* None of the strings matched, do we have a number? */
|
||||
// None of the strings matched, do we have a number?
|
||||
if (tryParseNumber(str, &token.attr.number))
|
||||
token.type = TOKEN_NUMBER;
|
||||
else
|
||||
@@ -354,14 +354,14 @@ static void processCommand(enum LinkerScriptCommand command, uint16_t arg, uint1
|
||||
enum LinkerScriptParserState {
|
||||
PARSER_FIRSTTIME,
|
||||
PARSER_LINESTART,
|
||||
PARSER_INCLUDE, /* After an INCLUDE token */
|
||||
PARSER_INCLUDE, // After an INCLUDE token
|
||||
PARSER_LINEEND
|
||||
};
|
||||
|
||||
/* Part of internal state, but has data that needs to be freed */
|
||||
// Part of internal state, but has data that needs to be freed
|
||||
static uint16_t *curaddr[SECTTYPE_INVALID];
|
||||
|
||||
/* Put as global to ensure it's initialized only once */
|
||||
// Put as global to ensure it's initialized only once
|
||||
static enum LinkerScriptParserState parserState = PARSER_FIRSTTIME;
|
||||
|
||||
struct SectionPlacement *script_NextSection(void)
|
||||
@@ -373,7 +373,7 @@ struct SectionPlacement *script_NextSection(void)
|
||||
if (parserState == PARSER_FIRSTTIME) {
|
||||
lineNo = 1;
|
||||
|
||||
/* Init PC for all banks */
|
||||
// Init PC for all banks
|
||||
for (enum SectionType i = 0; i < SECTTYPE_INVALID; i++) {
|
||||
curaddr[i] = malloc(sizeof(*curaddr[i]) * nbbanks(i));
|
||||
for (uint32_t b = 0; b < nbbanks(i); b++)
|
||||
@@ -427,7 +427,7 @@ struct SectionPlacement *script_NextSection(void)
|
||||
lineNo++;
|
||||
break;
|
||||
|
||||
/* A stray string is a section name */
|
||||
// A stray string is a section name
|
||||
case TOKEN_STRING:
|
||||
parserState = PARSER_LINEEND;
|
||||
|
||||
@@ -454,15 +454,11 @@ struct SectionPlacement *script_NextSection(void)
|
||||
|
||||
token = nextToken();
|
||||
hasArg = token->type == TOKEN_NUMBER;
|
||||
/*
|
||||
* Leaving `arg` uninitialized when `!hasArg`
|
||||
* causes GCC to warn about its use as an
|
||||
* argument to `processCommand`. This cannot
|
||||
* happen because `hasArg` has to be true, but
|
||||
* silence the warning anyways.
|
||||
* I dislike doing this because it could swallow
|
||||
* actual errors, but I don't have a choice.
|
||||
*/
|
||||
// Leaving `arg` uninitialized when `!hasArg` causes GCC to warn
|
||||
// about its use as an argument to `processCommand`. This cannot
|
||||
// happen because `hasArg` has to be true, but silence the warning
|
||||
// anyways. I dislike doing this because it could swallow actual
|
||||
// errors, but I don't have a choice.
|
||||
arg = hasArg ? token->attr.number : 0;
|
||||
|
||||
if (tokType == TOKEN_COMMAND) {
|
||||
@@ -474,12 +470,10 @@ struct SectionPlacement *script_NextSection(void)
|
||||
linkerScriptName, lineNo);
|
||||
|
||||
processCommand(attr.command, arg, &curaddr[placement.type][bankID]);
|
||||
} else { /* TOKEN_BANK */
|
||||
} else { // TOKEN_BANK
|
||||
placement.type = attr.secttype;
|
||||
/*
|
||||
* If there's only one bank,
|
||||
* specifying the number is optional.
|
||||
*/
|
||||
// If there's only one bank,
|
||||
// specifying the number is optional.
|
||||
if (!hasArg && nbbanks(placement.type) != 1)
|
||||
errx("%s(%" PRIu32 "): Didn't specify a bank number",
|
||||
linkerScriptName, lineNo);
|
||||
@@ -497,7 +491,7 @@ struct SectionPlacement *script_NextSection(void)
|
||||
bankID = arg - sectionTypeInfo[placement.type].firstBank;
|
||||
}
|
||||
|
||||
/* If we read a token we shouldn't have... */
|
||||
// If we read a token we shouldn't have...
|
||||
if (token->type != TOKEN_NUMBER)
|
||||
goto lineend;
|
||||
break;
|
||||
@@ -513,9 +507,9 @@ struct SectionPlacement *script_NextSection(void)
|
||||
errx("%s(%" PRIu32 "): Expected a file name after INCLUDE",
|
||||
linkerScriptName, lineNo);
|
||||
|
||||
/* Switch to that file */
|
||||
// Switch to that file
|
||||
pushFile(token->attr.string);
|
||||
/* The file stack took ownership of the string */
|
||||
// The file stack took ownership of the string
|
||||
token->attr.string = NULL;
|
||||
|
||||
parserState = PARSER_LINESTART;
|
||||
|
||||
@@ -1,3 +1,10 @@
|
||||
/*
|
||||
* This file is part of RGBDS.
|
||||
*
|
||||
* Copyright (c) 2022, Eldred Habert and RGBDS contributors.
|
||||
*
|
||||
* SPDX-License-Identifier: MIT
|
||||
*/
|
||||
|
||||
#include <assert.h>
|
||||
#include <ctype.h>
|
||||
|
||||
@@ -166,7 +166,7 @@ static void mergeSections(struct Section *target, struct Section *other, enum Se
|
||||
// `data` pointer, or a size of 0.
|
||||
if (other->data) {
|
||||
if (target->data) {
|
||||
/* Ensure we're not allocating 0 bytes */
|
||||
// Ensure we're not allocating 0 bytes
|
||||
target->data = realloc(target->data,
|
||||
sizeof(*target->data) * target->size + 1);
|
||||
if (!target->data)
|
||||
@@ -177,7 +177,7 @@ static void mergeSections(struct Section *target, struct Section *other, enum Se
|
||||
target->data = other->data;
|
||||
other->data = NULL; // Prevent a double free()
|
||||
}
|
||||
/* Adjust patches' PC offsets */
|
||||
// Adjust patches' PC offsets
|
||||
for (uint32_t patchID = 0; patchID < other->nbPatches; patchID++)
|
||||
other->patches[patchID].pcOffset += other->offset;
|
||||
} else if (target->data) {
|
||||
@@ -195,7 +195,7 @@ static void mergeSections(struct Section *target, struct Section *other, enum Se
|
||||
|
||||
void sect_AddSection(struct Section *section)
|
||||
{
|
||||
/* Check if the section already exists */
|
||||
// Check if the section already exists
|
||||
struct Section *other = hash_GetElement(sections, section->name);
|
||||
|
||||
if (other) {
|
||||
@@ -210,7 +210,7 @@ void sect_AddSection(struct Section *section)
|
||||
errx("Section \"%s\" is of type %s, which cannot be unionized",
|
||||
section->name, sectionTypeInfo[section->type].name);
|
||||
} else {
|
||||
/* If not, add it */
|
||||
// If not, add it
|
||||
hash_AddElement(sections, section->name, section);
|
||||
}
|
||||
}
|
||||
@@ -229,7 +229,7 @@ static void doSanityChecks(struct Section *section, void *ptr)
|
||||
{
|
||||
(void)ptr;
|
||||
|
||||
/* Sanity check the section's type */
|
||||
// Sanity check the section's type
|
||||
|
||||
if (section->type < 0 || section->type >= SECTTYPE_INVALID) {
|
||||
error(NULL, 0, "Section \"%s\" has an invalid type", section->name);
|
||||
@@ -254,14 +254,12 @@ static void doSanityChecks(struct Section *section, void *ptr)
|
||||
error(NULL, 0, "%s: VRAM bank 1 can't be used with option -d",
|
||||
section->name);
|
||||
|
||||
/*
|
||||
* Check if alignment is reasonable, this is important to avoid UB
|
||||
* An alignment of zero is equivalent to no alignment, basically
|
||||
*/
|
||||
// Check if alignment is reasonable, this is important to avoid UB
|
||||
// An alignment of zero is equivalent to no alignment, basically
|
||||
if (section->isAlignFixed && section->alignMask == 0)
|
||||
section->isAlignFixed = false;
|
||||
|
||||
/* Too large an alignment may not be satisfiable */
|
||||
// Too large an alignment may not be satisfiable
|
||||
if (section->isAlignFixed && (section->alignMask & sectionTypeInfo[section->type].startAddr))
|
||||
error(NULL, 0, "%s: %s sections cannot be aligned to $%04x bytes",
|
||||
section->name, sectionTypeInfo[section->type].name, section->alignMask + 1);
|
||||
@@ -274,12 +272,12 @@ static void doSanityChecks(struct Section *section, void *ptr)
|
||||
: "Cannot place section \"%s\" in bank %" PRIu32 ", it must be between %" PRIu32 " and %" PRIu32,
|
||||
section->name, section->bank, minbank, maxbank);
|
||||
|
||||
/* Check if section has a chance to be placed */
|
||||
// Check if section has a chance to be placed
|
||||
if (section->size > sectionTypeInfo[section->type].size)
|
||||
error(NULL, 0, "Section \"%s\" is bigger than the max size for that type: %#" PRIx16 " > %#" PRIx16,
|
||||
section->name, section->size, sectionTypeInfo[section->type].size);
|
||||
|
||||
/* Translate loose constraints to strong ones when they're equivalent */
|
||||
// Translate loose constraints to strong ones when they're equivalent
|
||||
|
||||
if (minbank == maxbank) {
|
||||
section->bank = minbank;
|
||||
@@ -287,7 +285,7 @@ static void doSanityChecks(struct Section *section, void *ptr)
|
||||
}
|
||||
|
||||
if (section->isAddressFixed) {
|
||||
/* It doesn't make sense to have both org and alignment set */
|
||||
// It doesn't make sense to have both org and alignment set
|
||||
if (section->isAlignFixed) {
|
||||
if ((section->org & section->alignMask) != section->alignOfs)
|
||||
error(NULL, 0, "Section \"%s\"'s fixed address doesn't match its alignment",
|
||||
@@ -295,7 +293,7 @@ static void doSanityChecks(struct Section *section, void *ptr)
|
||||
section->isAlignFixed = false;
|
||||
}
|
||||
|
||||
/* Ensure the target address is valid */
|
||||
// Ensure the target address is valid
|
||||
if (section->org < sectionTypeInfo[section->type].startAddr
|
||||
|| section->org > endaddr(section->type))
|
||||
error(NULL, 0, "Section \"%s\"'s fixed address %#" PRIx16 " is outside of range [%#"
|
||||
|
||||
@@ -40,7 +40,7 @@ void sym_ForEach(void (*callback)(struct Symbol *, void *), void *arg)
|
||||
|
||||
void sym_AddSymbol(struct Symbol *symbol)
|
||||
{
|
||||
/* Check if the symbol already exists */
|
||||
// Check if the symbol already exists
|
||||
struct Symbol *other = hash_GetElement(symbols, symbol->name);
|
||||
|
||||
if (other) {
|
||||
@@ -53,7 +53,7 @@ void sym_AddSymbol(struct Symbol *symbol)
|
||||
exit(1);
|
||||
}
|
||||
|
||||
/* If not, add it */
|
||||
// If not, add it
|
||||
hash_AddElement(symbols, symbol->name, symbol);
|
||||
}
|
||||
|
||||
|
||||
@@ -1,3 +1,10 @@
|
||||
/*
|
||||
* This file is part of RGBDS.
|
||||
*
|
||||
* Copyright (c) 2022, RGBDS contributors.
|
||||
*
|
||||
* SPDX-License-Identifier: MIT
|
||||
*/
|
||||
|
||||
#include "linkdefs.h"
|
||||
|
||||
|
||||
@@ -6,9 +6,7 @@
|
||||
* SPDX-License-Identifier: MIT
|
||||
*/
|
||||
|
||||
/*
|
||||
* Mathematical operators that don't reuse C's behavior
|
||||
*/
|
||||
// Mathematical operators that don't reuse C's behavior
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
|
||||
Reference in New Issue
Block a user