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:
Rangi
2022-08-29 18:01:34 -04:00
committed by Eldred Habert
parent dca24a6d50
commit fa13611bbf
76 changed files with 1077 additions and 1335 deletions

View File

@@ -20,4 +20,4 @@ void charmap_Add(char *mapping, uint8_t value);
size_t charmap_Convert(char const *input, uint8_t *output); size_t charmap_Convert(char const *input, uint8_t *output);
size_t charmap_ConvertNext(char const **input, uint8_t **output); size_t charmap_ConvertNext(char const **input, uint8_t **output);
#endif /* RGBDS_ASM_CHARMAP_H */ #endif // RGBDS_ASM_CHARMAP_H

View File

@@ -28,4 +28,4 @@ int32_t fix_Round(int32_t i);
int32_t fix_Ceil(int32_t i); int32_t fix_Ceil(int32_t i);
int32_t fix_Floor(int32_t i); int32_t fix_Floor(int32_t i);
#endif /* RGBDS_ASM_FIXPOINT_H */ #endif // RGBDS_ASM_FIXPOINT_H

View File

@@ -60,4 +60,4 @@ void fmt_FinishCharacters(struct FormatSpec *fmt);
void fmt_PrintString(char *buf, size_t bufLen, struct FormatSpec const *fmt, char const *value); void fmt_PrintString(char *buf, size_t bufLen, struct FormatSpec const *fmt, char const *value);
void fmt_PrintNumber(char *buf, size_t bufLen, struct FormatSpec const *fmt, uint32_t value); void fmt_PrintNumber(char *buf, size_t bufLen, struct FormatSpec const *fmt, uint32_t value);
#endif /* RGBDS_FORMAT_SPEC_H */ #endif // RGBDS_FORMAT_SPEC_H

View File

@@ -6,9 +6,7 @@
* SPDX-License-Identifier: MIT * SPDX-License-Identifier: MIT
*/ */
/* // Contains some assembler-wide defines and externs
* Contains some assembler-wide defines and externs
*/
#ifndef RGBDS_ASM_FSTACK_H #ifndef RGBDS_ASM_FSTACK_H
#define RGBDS_ASM_FSTACK_H #define RGBDS_ASM_FSTACK_H
@@ -21,13 +19,13 @@
struct FileStackNode { struct FileStackNode {
struct FileStackNode *parent; /* Pointer to parent node, for error reporting */ struct FileStackNode *parent; // Pointer to parent node, for error reporting
/* Line at which the parent context was exited; meaningless for the root level */ // Line at which the parent context was exited; meaningless for the root level
uint32_t lineNo; uint32_t lineNo;
struct FileStackNode *next; /* Next node in the output linked list */ struct FileStackNode *next; // Next node in the output linked list
bool referenced; /* If referenced, don't free! */ bool referenced; // If referenced, don't free!
uint32_t ID; /* Set only if referenced: ID within the object file, -1 if not output yet */ uint32_t ID; // Set only if referenced: ID within the object file, -1 if not output yet
enum { enum {
NODE_REPT, NODE_REPT,
@@ -36,16 +34,16 @@ struct FileStackNode {
} type; } type;
}; };
struct FileStackReptNode { /* NODE_REPT */ struct FileStackReptNode { // NODE_REPT
struct FileStackNode node; struct FileStackNode node;
uint32_t reptDepth; uint32_t reptDepth;
/* WARNING: if changing this type, change overflow check in `fstk_Init` */ // WARNING: if changing this type, change overflow check in `fstk_Init`
uint32_t iters[]; /* REPT iteration counts since last named node, in reverse depth order */ uint32_t iters[]; // REPT iteration counts since last named node, in reverse depth order
}; };
struct FileStackNamedNode { /* NODE_FILE, NODE_MACRO */ struct FileStackNamedNode { // NODE_FILE, NODE_MACRO
struct FileStackNode node; struct FileStackNode node;
char name[]; /* File name for files, file::macro name for macros */ char name[]; // File name for files, file::macro name for macros
}; };
#define DEFAULT_MAX_DEPTH 64 #define DEFAULT_MAX_DEPTH 64
@@ -56,11 +54,11 @@ struct MacroArgs;
void fstk_Dump(struct FileStackNode const *node, uint32_t lineNo); void fstk_Dump(struct FileStackNode const *node, uint32_t lineNo);
void fstk_DumpCurrent(void); void fstk_DumpCurrent(void);
struct FileStackNode *fstk_GetFileStack(void); struct FileStackNode *fstk_GetFileStack(void);
/* The lifetime of the returned chars is until reaching the end of that file */ // The lifetime of the returned chars is until reaching the end of that file
char const *fstk_GetFileName(void); char const *fstk_GetFileName(void);
void fstk_AddIncludePath(char const *s); void fstk_AddIncludePath(char const *s);
/** /*
* @param path The user-provided file name * @param path The user-provided file name
* @param fullPath The address of a pointer, which will be made to point at the full path * @param fullPath The address of a pointer, which will be made to point at the full path
* The pointer's value must be a valid argument to `realloc`, including NULL * The pointer's value must be a valid argument to `realloc`, including NULL
@@ -81,4 +79,4 @@ bool fstk_Break(void);
void fstk_NewRecursionDepth(size_t newDepth); void fstk_NewRecursionDepth(size_t newDepth);
void fstk_Init(char const *mainPath, size_t maxDepth); void fstk_Init(char const *mainPath, size_t maxDepth);
#endif /* RGBDS_ASM_FSTACK_H */ #endif // RGBDS_ASM_FSTACK_H

View File

@@ -11,7 +11,7 @@
#include <stdbool.h> #include <stdbool.h>
#define MAXSTRLEN 255 #define MAXSTRLEN 255
struct LexerState; struct LexerState;
extern struct LexerState *lexerState; extern struct LexerState *lexerState;
@@ -49,9 +49,7 @@ static inline void lexer_SetGfxDigits(char const digits[4])
gfxDigits[3] = digits[3]; gfxDigits[3] = digits[3];
} }
/* // `path` is referenced, but not held onto..!
* `path` is referenced, but not held onto..!
*/
struct LexerState *lexer_OpenFile(char const *path); struct LexerState *lexer_OpenFile(char const *path);
struct LexerState *lexer_OpenFileView(char const *path, char *buf, size_t size, uint32_t lineNo); struct LexerState *lexer_OpenFileView(char const *path, char *buf, size_t size, uint32_t lineNo);
void lexer_RestartRept(uint32_t lineNo); void lexer_RestartRept(uint32_t lineNo);
@@ -99,4 +97,4 @@ struct DsArgList {
struct Expression *args; struct Expression *args;
}; };
#endif /* RGBDS_ASM_LEXER_H */ #endif // RGBDS_ASM_LEXER_H

View File

@@ -34,4 +34,4 @@ uint32_t macro_UseNewUniqueID(void);
void macro_ShiftCurrentArgs(int32_t count); void macro_ShiftCurrentArgs(int32_t count);
uint32_t macro_NbArgs(void); uint32_t macro_NbArgs(void);
#endif #endif // RGBDS_MACRO_H

View File

@@ -20,7 +20,7 @@ extern bool warnOnHaltNop;
extern bool optimizeLoads; extern bool optimizeLoads;
extern bool warnOnLdOpt; extern bool warnOnLdOpt;
extern bool verbose; extern bool verbose;
extern bool warnings; /* True to enable warnings, false to disable them. */ extern bool warnings; // True to enable warnings, false to disable them.
extern FILE *dependfile; extern FILE *dependfile;
extern char *targetFileName; extern char *targetFileName;
@@ -28,4 +28,4 @@ extern bool generatedMissingIncludes;
extern bool failedOnMissingInclude; extern bool failedOnMissingInclude;
extern bool generatePhonyDeps; extern bool generatePhonyDeps;
#endif /* RGBDS_MAIN_H */ #endif // RGBDS_MAIN_H

View File

@@ -22,4 +22,4 @@ void opt_Parse(char const *option);
void opt_Push(void); void opt_Push(void);
void opt_Pop(void); void opt_Pop(void);
#endif #endif // RGBDS_OPT_H

View File

@@ -27,4 +27,4 @@ bool out_CreateAssert(enum AssertionType type, struct Expression const *expr,
char const *message, uint32_t ofs); char const *message, uint32_t ofs);
void out_WriteObject(void); void out_WriteObject(void);
#endif /* RGBDS_ASM_OUTPUT_H */ #endif // RGBDS_ASM_OUTPUT_H

View File

@@ -27,17 +27,13 @@ struct Expression {
uint32_t rpnPatchSize; // Size the expression will take in the object file uint32_t rpnPatchSize; // Size the expression will take in the object file
}; };
/* // Determines if an expression is known at assembly time
* Determines if an expression is known at assembly time
*/
static inline bool rpn_isKnown(struct Expression const *expr) static inline bool rpn_isKnown(struct Expression const *expr)
{ {
return expr->isKnown; return expr->isKnown;
} }
/* // Determines if an expression is a symbol suitable for const diffing
* Determines if an expression is a symbol suitable for const diffing
*/
static inline bool rpn_isSymbol(const struct Expression *expr) static inline bool rpn_isSymbol(const struct Expression *expr)
{ {
return expr->isSymbol; return expr->isSymbol;
@@ -67,4 +63,4 @@ void rpn_CheckRST(struct Expression *expr, const struct Expression *src);
void rpn_CheckNBit(struct Expression const *expr, uint8_t n); void rpn_CheckNBit(struct Expression const *expr, uint8_t n);
int32_t rpn_GetConstVal(struct Expression const *expr); int32_t rpn_GetConstVal(struct Expression const *expr);
#endif /* RGBDS_ASM_RPN_H */ #endif // RGBDS_ASM_RPN_H

View File

@@ -23,8 +23,8 @@ struct Section {
char *name; char *name;
enum SectionType type; enum SectionType type;
enum SectionModifier modifier; enum SectionModifier modifier;
struct FileStackNode *src; /* Where the section was defined */ struct FileStackNode *src; // Where the section was defined
uint32_t fileLine; /* Line where the section was defined */ uint32_t fileLine; // Line where the section was defined
uint32_t size; uint32_t size;
uint32_t org; uint32_t org;
uint32_t bank; uint32_t bank;
@@ -79,4 +79,4 @@ void sect_PopSection(void);
bool sect_IsSizeKnown(struct Section const NONNULL(name)); bool sect_IsSizeKnown(struct Section const NONNULL(name));
#endif #endif // RGBDS_SECTION_H

View File

@@ -32,28 +32,28 @@ enum SymbolType {
struct Symbol { struct Symbol {
char name[MAXSYMLEN + 1]; char name[MAXSYMLEN + 1];
enum SymbolType type; enum SymbolType type;
bool isExported; /* Whether the symbol is to be exported */ bool isExported; // Whether the symbol is to be exported
bool isBuiltin; /* Whether the symbol is a built-in */ bool isBuiltin; // Whether the symbol is a built-in
struct Section *section; struct Section *section;
struct FileStackNode *src; /* Where the symbol was defined */ struct FileStackNode *src; // Where the symbol was defined
uint32_t fileLine; /* Line where the symbol was defined */ uint32_t fileLine; // Line where the symbol was defined
bool hasCallback; bool hasCallback;
union { union {
/* If sym_IsNumeric */ // If sym_IsNumeric
int32_t value; int32_t value;
int32_t (*numCallback)(void); int32_t (*numCallback)(void);
/* For SYM_MACRO and SYM_EQUS; TODO: have separate fields */ // For SYM_MACRO and SYM_EQUS; TODO: have separate fields
struct { struct {
size_t macroSize; size_t macroSize;
char *macro; char *macro;
}; };
/* For SYM_EQUS */ // For SYM_EQUS
char const *(*strCallback)(void); char const *(*strCallback)(void);
}; };
uint32_t ID; /* ID of the symbol in the object file (-1 if none) */ uint32_t ID; // ID of the symbol in the object file (-1 if none)
struct Symbol *next; /* Next object to output in the object file */ struct Symbol *next; // Next object to output in the object file
}; };
bool sym_IsPC(struct Symbol const *sym); bool sym_IsPC(struct Symbol const *sym);
@@ -98,9 +98,7 @@ static inline bool sym_IsExported(struct Symbol const *sym)
return sym->isExported; return sym->isExported;
} }
/* // Get a string equate's value
* Get a string equate's value
*/
static inline char const *sym_GetStringValue(struct Symbol const *sym) static inline char const *sym_GetStringValue(struct Symbol const *sym)
{ {
if (sym->hasCallback) if (sym->hasCallback)
@@ -123,17 +121,11 @@ struct Symbol *sym_AddVar(char const *symName, int32_t value);
uint32_t sym_GetPCValue(void); uint32_t sym_GetPCValue(void);
uint32_t sym_GetConstantSymValue(struct Symbol const *sym); uint32_t sym_GetConstantSymValue(struct Symbol const *sym);
uint32_t sym_GetConstantValue(char const *symName); uint32_t sym_GetConstantValue(char const *symName);
/* // Find a symbol by exact name, bypassing expansion checks
* Find a symbol by exact name, bypassing expansion checks
*/
struct Symbol *sym_FindExactSymbol(char const *symName); struct Symbol *sym_FindExactSymbol(char const *symName);
/* // Find a symbol by exact name; may not be scoped, produces an error if it is
* Find a symbol by exact name; may not be scoped, produces an error if it is
*/
struct Symbol *sym_FindUnscopedSymbol(char const *symName); struct Symbol *sym_FindUnscopedSymbol(char const *symName);
/* // Find a symbol, possibly scoped, by name
* Find a symbol, possibly scoped, by name
*/
struct Symbol *sym_FindScopedSymbol(char const *symName); struct Symbol *sym_FindScopedSymbol(char const *symName);
struct Symbol const *sym_GetPC(void); struct Symbol const *sym_GetPC(void);
struct Symbol *sym_AddMacro(char const *symName, int32_t defLineNo, char *body, size_t size); struct Symbol *sym_AddMacro(char const *symName, int32_t defLineNo, char *body, size_t size);
@@ -143,8 +135,8 @@ struct Symbol *sym_RedefString(char const *symName, char const *value);
void sym_Purge(char const *symName); void sym_Purge(char const *symName);
void sym_Init(time_t now); void sym_Init(time_t now);
/* Functions to save and restore the current symbol scope. */ // Functions to save and restore the current symbol scope.
char const *sym_GetCurrentSymbolScope(void); char const *sym_GetCurrentSymbolScope(void);
void sym_SetCurrentSymbolScope(char const *newScope); void sym_SetCurrentSymbolScope(char const *newScope);
#endif /* RGBDS_SYMBOL_H */ #endif // RGBDS_SYMBOL_H

View File

@@ -18,4 +18,4 @@ char const *printChar(int c);
*/ */
size_t readUTF8Char(uint8_t *dest, char const *src); size_t readUTF8Char(uint8_t *dest, char const *src);
#endif /* RGBDS_UTIL_H */ #endif // RGBDS_UTIL_H

View File

@@ -91,4 +91,4 @@ _Noreturn void fatalerror(char const *fmt, ...) format_(printf, 1, 2);
*/ */
void error(char const *fmt, ...) format_(printf, 1, 2); void error(char const *fmt, ...) format_(printf, 1, 2);
#endif #endif // WARNING_H

View File

@@ -1,4 +1,4 @@
/** /*
* Allocator adaptor that interposes construct() calls to convert value-initialization * Allocator adaptor that interposes construct() calls to convert value-initialization
* (which is what you get with e.g. `vector::resize`) into default-initialization (which does not * (which is what you get with e.g. `vector::resize`) into default-initialization (which does not
* zero out non-class types). * zero out non-class types).
@@ -36,4 +36,4 @@ public:
template<typename T> template<typename T>
using DefaultInitVec = std::vector<T, default_init_allocator<T>>; using DefaultInitVec = std::vector<T, default_init_allocator<T>>;
#endif #endif // DEFAULT_INIT_ALLOC_H

View File

@@ -26,4 +26,4 @@ _Noreturn void errx(char const NONNULL(fmt), ...) format_(printf, 1, 2);
} }
#endif #endif
#endif /* RGBDS_ERROR_H */ #endif // RGBDS_ERROR_H

View File

@@ -11,4 +11,4 @@
uint32_t decode(uint32_t *state, uint32_t *codep, uint8_t byte); uint32_t decode(uint32_t *state, uint32_t *codep, uint8_t byte);
#endif /* EXTERN_UTF8DECODER_H */ #endif // EXTERN_UTF8DECODER_H

View File

@@ -71,19 +71,19 @@ struct Options {
extern Options options; extern Options options;
/** /*
* Prints the error count, and exits with failure * Prints the error count, and exits with failure
*/ */
[[noreturn]] void giveUp(); [[noreturn]] void giveUp();
/** /*
* Prints a warning, and does not change the error count * Prints a warning, and does not change the error count
*/ */
void warning(char const *fmt, ...); void warning(char const *fmt, ...);
/** /*
* Prints an error, and increments the error count * Prints an error, and increments the error count
*/ */
void error(char const *fmt, ...); void error(char const *fmt, ...);
/** /*
* Prints a fatal error, increments the error count, and gives up * Prints a fatal error, increments the error count, and gives up
*/ */
[[noreturn]] void fatal(char const *fmt, ...); [[noreturn]] void fatal(char const *fmt, ...);
@@ -120,4 +120,4 @@ static constexpr auto flipTable(std::integer_sequence<T, i...>) {
// Flipping tends to happen fairly often, so take a bite out of dcache to speed it up // Flipping tends to happen fairly often, so take a bite out of dcache to speed it up
static constexpr auto flipTable = detail::flipTable(std::make_integer_sequence<uint16_t, 256>()); static constexpr auto flipTable = detail::flipTable(std::make_integer_sequence<uint16_t, 256>());
#endif /* RGBDS_GFX_MAIN_HPP */ #endif // RGBDS_GFX_MAIN_HPP

View File

@@ -21,7 +21,7 @@ class ProtoPalette;
namespace packing { namespace packing {
/** /*
* Returns which palette each proto-palette maps to, and how many palettes are necessary * Returns which palette each proto-palette maps to, and how many palettes are necessary
*/ */
std::tuple<DefaultInitVec<size_t>, size_t> std::tuple<DefaultInitVec<size_t>, size_t>
@@ -29,4 +29,4 @@ std::tuple<DefaultInitVec<size_t>, size_t>
} }
#endif /* RGBDS_GFX_PAL_PACKING_HPP */ #endif // RGBDS_GFX_PAL_PACKING_HPP

View File

@@ -29,4 +29,4 @@ void rgb(std::vector<Palette> &palettes);
} }
#endif /* RGBDS_GFX_PAL_SORTING_HPP */ #endif // RGBDS_GFX_PAL_SORTING_HPP

View File

@@ -12,4 +12,4 @@
void parseInlinePalSpec(char const * const arg); void parseInlinePalSpec(char const * const arg);
void parseExternalPalSpec(char const *arg); void parseExternalPalSpec(char const *arg);
#endif /* RGBDS_GFX_PAL_SPEC_HPP */ #endif // RGBDS_GFX_PAL_SPEC_HPP

View File

@@ -11,4 +11,4 @@
void process(); void process();
#endif /* RGBDS_GFX_CONVERT_HPP */ #endif // RGBDS_GFX_CONVERT_HPP

View File

@@ -21,7 +21,7 @@ class ProtoPalette {
std::array<uint16_t, 4> _colorIndices{UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX}; std::array<uint16_t, 4> _colorIndices{UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX};
public: public:
/** /*
* Adds the specified color to the set * Adds the specified color to the set
* Returns false if the set is full * Returns false if the set is full
*/ */
@@ -41,4 +41,4 @@ public:
decltype(_colorIndices)::const_iterator end() const; decltype(_colorIndices)::const_iterator end() const;
}; };
#endif /* RGBDS_GFX_PROTO_PALETTE_HPP */ #endif // RGBDS_GFX_PROTO_PALETTE_HPP

View File

@@ -11,4 +11,4 @@
void reverse(); void reverse();
#endif /* RGBDS_GFX_REVERSE_HPP */ #endif // RGBDS_GFX_REVERSE_HPP

View File

@@ -20,7 +20,7 @@ struct Rgba {
constexpr Rgba(uint8_t r, uint8_t g, uint8_t b, uint8_t a) constexpr Rgba(uint8_t r, uint8_t g, uint8_t b, uint8_t a)
: red(r), green(g), blue(b), alpha(a) {} : red(r), green(g), blue(b), alpha(a) {}
/** /*
* Constructs the color from a "packed" RGBA representation (0xRRGGBBAA) * Constructs the color from a "packed" RGBA representation (0xRRGGBBAA)
*/ */
explicit constexpr Rgba(uint32_t rgba = 0) explicit constexpr Rgba(uint32_t rgba = 0)
@@ -35,7 +35,7 @@ struct Rgba {
(uint8_t)(cgbColor & 0x8000 ? 0x00 : 0xFF)}; (uint8_t)(cgbColor & 0x8000 ? 0x00 : 0xFF)};
} }
/** /*
* Returns this RGBA as a 32-bit number that can be printed in hex (`%08x`) to yield its CSS * Returns this RGBA as a 32-bit number that can be printed in hex (`%08x`) to yield its CSS
* representation * representation
*/ */
@@ -45,7 +45,7 @@ struct Rgba {
} }
friend bool operator!=(Rgba const &lhs, Rgba const &rhs) { return lhs.toCSS() != rhs.toCSS(); } friend bool operator!=(Rgba const &lhs, Rgba const &rhs) { return lhs.toCSS() != rhs.toCSS(); }
/** /*
* CGB colors are RGB555, so we use bit 15 to signify that the color is transparent instead * CGB colors are RGB555, so we use bit 15 to signify that the color is transparent instead
* Since the rest of the bits don't matter then, we return 0x8000 exactly. * Since the rest of the bits don't matter then, we return 0x8000 exactly.
*/ */
@@ -55,7 +55,7 @@ struct Rgba {
bool isTransparent() const { return alpha < transparency_threshold; } bool isTransparent() const { return alpha < transparency_threshold; }
static constexpr uint8_t opacity_threshold = 0xF0; static constexpr uint8_t opacity_threshold = 0xF0;
bool isOpaque() const { return alpha >= opacity_threshold; } bool isOpaque() const { return alpha >= opacity_threshold; }
/** /*
* Computes the equivalent CGB color, respects the color curve depending on options * Computes the equivalent CGB color, respects the color curve depending on options
*/ */
uint16_t cgbColor() const; uint16_t cgbColor() const;
@@ -64,4 +64,4 @@ struct Rgba {
uint8_t grayIndex() const; uint8_t grayIndex() const;
}; };
#endif /* RGBDS_GFX_RGBA_HPP */ #endif // RGBDS_GFX_RGBA_HPP

View File

@@ -6,7 +6,7 @@
* SPDX-License-Identifier: MIT * SPDX-License-Identifier: MIT
*/ */
/* Generic hashmap implementation (C++ templates are calling...) */ // Generic hashmap implementation (C++ templates are calling...)
#ifndef RGBDS_LINK_HASHMAP_H #ifndef RGBDS_LINK_HASHMAP_H
#define RGBDS_LINK_HASHMAP_H #define RGBDS_LINK_HASHMAP_H
@@ -18,10 +18,10 @@
static_assert(HALF_HASH_NB_BITS * 2 == HASH_NB_BITS, ""); static_assert(HALF_HASH_NB_BITS * 2 == HASH_NB_BITS, "");
#define HASHMAP_NB_BUCKETS (1 << HALF_HASH_NB_BITS) #define HASHMAP_NB_BUCKETS (1 << HALF_HASH_NB_BITS)
/* HashMapEntry is internal, please do not attempt to use it */ // HashMapEntry is internal, please do not attempt to use it
typedef struct HashMapEntry *HashMap[HASHMAP_NB_BUCKETS]; typedef struct HashMapEntry *HashMap[HASHMAP_NB_BUCKETS];
/** /*
* Adds an element to a hashmap. * Adds an element to a hashmap.
* @warning Adding a new element with an already-present key will not cause an * @warning Adding a new element with an already-present key will not cause an
* error, this must be handled externally. * error, this must be handled externally.
@@ -33,7 +33,7 @@ typedef struct HashMapEntry *HashMap[HASHMAP_NB_BUCKETS];
*/ */
void **hash_AddElement(HashMap map, char const *key, void *element); void **hash_AddElement(HashMap map, char const *key, void *element);
/** /*
* Removes an element from a hashmap. * Removes an element from a hashmap.
* @param map The HashMap to remove the element from * @param map The HashMap to remove the element from
* @param key The key to search the element with * @param key The key to search the element with
@@ -41,7 +41,7 @@ void **hash_AddElement(HashMap map, char const *key, void *element);
*/ */
bool hash_RemoveElement(HashMap map, char const *key); bool hash_RemoveElement(HashMap map, char const *key);
/** /*
* Finds an element in a hashmap, and returns a pointer to its value field. * Finds an element in a hashmap, and returns a pointer to its value field.
* @param map The map to consider the elements of * @param map The map to consider the elements of
* @param key The key to search an element for * @param key The key to search an element for
@@ -49,7 +49,7 @@ bool hash_RemoveElement(HashMap map, char const *key);
*/ */
void **hash_GetNode(HashMap const map, char const *key); void **hash_GetNode(HashMap const map, char const *key);
/** /*
* Finds an element in a hashmap. * Finds an element in a hashmap.
* @param map The map to consider the elements of * @param map The map to consider the elements of
* @param key The key to search an element for * @param key The key to search an element for
@@ -58,7 +58,7 @@ void **hash_GetNode(HashMap const map, char const *key);
*/ */
void *hash_GetElement(HashMap const map, char const *key); void *hash_GetElement(HashMap const map, char const *key);
/** /*
* Executes a function on each element in a hashmap. * Executes a function on each element in a hashmap.
* @param map The map to consider the elements of * @param map The map to consider the elements of
* @param func The function to run. The first argument will be the element, * @param func The function to run. The first argument will be the element,
@@ -67,11 +67,11 @@ void *hash_GetElement(HashMap const map, char const *key);
*/ */
void hash_ForEach(HashMap const map, void (*func)(void *, void *), void *arg); void hash_ForEach(HashMap const map, void (*func)(void *, void *), void *arg);
/** /*
* Cleanly empties a hashmap from its contents. * Cleanly empties a hashmap from its contents.
* This does not `free` the data structure itself! * This does not `free` the data structure itself!
* @param map The map to empty * @param map The map to empty
*/ */
void hash_EmptyMap(HashMap map); void hash_EmptyMap(HashMap map);
#endif /* RGBDS_LINK_HASHMAP_H */ #endif // RGBDS_LINK_HASHMAP_H

View File

@@ -93,4 +93,4 @@
// (Having two instances of `arr` is OK because the contents of `sizeof` are not evaluated.) // (Having two instances of `arr` is OK because the contents of `sizeof` are not evaluated.)
#define ARRAY_SIZE(arr) (sizeof(arr) / sizeof *(arr)) #define ARRAY_SIZE(arr) (sizeof(arr) / sizeof *(arr))
#endif /* HELPERS_H */ #endif // HELPERS_H

View File

@@ -79,12 +79,10 @@ using Holder = std::conditional_t<std::is_lvalue_reference_v<T>, T,
std::remove_cv_t<std::remove_reference_t<T>>>; std::remove_cv_t<std::remove_reference_t<T>>>;
} }
/** // Does the same number of iterations as the first container's iterator!
* Does the same number of iterations as the first container's iterator!
*/
template<typename... Containers> template<typename... Containers>
static constexpr auto zip(Containers &&...cs) { static constexpr auto zip(Containers &&...cs) {
return detail::ZipContainer<detail::Holder<Containers>...>(std::forward<Containers>(cs)...); return detail::ZipContainer<detail::Holder<Containers>...>(std::forward<Containers>(cs)...);
} }
#endif /* RGBDS_ITERTOOLS_HPP */ #endif // RGBDS_ITERTOOLS_HPP

View File

@@ -6,7 +6,7 @@
* SPDX-License-Identifier: MIT * SPDX-License-Identifier: MIT
*/ */
/* Assigning all sections a place */ // Assigning all sections a place
#ifndef RGBDS_LINK_ASSIGN_H #ifndef RGBDS_LINK_ASSIGN_H
#define RGBDS_LINK_ASSIGN_H #define RGBDS_LINK_ASSIGN_H
@@ -14,14 +14,10 @@
extern uint64_t nbSectionsToAssign; extern uint64_t nbSectionsToAssign;
/** // Assigns all sections a slice of the address space
* Assigns all sections a slice of the address space
*/
void assign_AssignSections(void); void assign_AssignSections(void);
/** // `free`s all assignment memory that was allocated
* `free`s all assignment memory that was allocated.
*/
void assign_Cleanup(void); void assign_Cleanup(void);
#endif /* RGBDS_LINK_ASSIGN_H */ #endif // RGBDS_LINK_ASSIGN_H

View File

@@ -6,7 +6,7 @@
* SPDX-License-Identifier: MIT * SPDX-License-Identifier: MIT
*/ */
/* Declarations that all modules use, as well as `main` and related */ // Declarations that all modules use, as well as `main` and related
#ifndef RGBDS_LINK_MAIN_H #ifndef RGBDS_LINK_MAIN_H
#define RGBDS_LINK_MAIN_H #define RGBDS_LINK_MAIN_H
@@ -16,7 +16,7 @@
#include "helpers.h" #include "helpers.h"
/* Variables related to CLI options */ // Variables related to CLI options
extern bool isDmgMode; extern bool isDmgMode;
extern char *linkerScriptName; extern char *linkerScriptName;
extern char const *mapFileName; extern char const *mapFileName;
@@ -35,7 +35,7 @@ extern bool disablePadding;
struct FileStackNode { struct FileStackNode {
struct FileStackNode *parent; struct FileStackNode *parent;
/* Line at which the parent context was exited; meaningless for the root level */ // Line at which the parent context was exited; meaningless for the root level
uint32_t lineNo; uint32_t lineNo;
enum { enum {
@@ -44,21 +44,21 @@ struct FileStackNode {
NODE_MACRO, NODE_MACRO,
} type; } type;
union { union {
char *name; /* NODE_FILE, NODE_MACRO */ char *name; // NODE_FILE, NODE_MACRO
struct { /* NODE_REPT */ struct { // NODE_REPT
uint32_t reptDepth; uint32_t reptDepth;
uint32_t *iters; uint32_t *iters;
}; };
}; };
}; };
/* Helper macro for printing verbose-mode messages */ // Helper macro for printing verbose-mode messages
#define verbosePrint(...) do { \ #define verbosePrint(...) do { \
if (beVerbose) \ if (beVerbose) \
fprintf(stderr, __VA_ARGS__); \ fprintf(stderr, __VA_ARGS__); \
} while (0) } while (0)
/** /*
* Dump a file stack to stderr * Dump a file stack to stderr
* @param node The leaf node to dump the context of * @param node The leaf node to dump the context of
*/ */
@@ -73,7 +73,7 @@ void error(struct FileStackNode const *where, uint32_t lineNo,
_Noreturn void fatal(struct FileStackNode const *where, uint32_t lineNo, _Noreturn void fatal(struct FileStackNode const *where, uint32_t lineNo,
char const *fmt, ...) format_(printf, 3, 4); char const *fmt, ...) format_(printf, 3, 4);
/** /*
* Opens a file if specified, and aborts on error. * Opens a file if specified, and aborts on error.
* @param fileName The name of the file to open; if NULL, no file will be opened * @param fileName The name of the file to open; if NULL, no file will be opened
* @param mode The mode to open the file with * @param mode The mode to open the file with
@@ -87,4 +87,4 @@ FILE *openFile(char const *fileName, char const *mode);
fclose(tmp); \ fclose(tmp); \
} while (0) } while (0)
#endif /* RGBDS_LINK_MAIN_H */ #endif // RGBDS_LINK_MAIN_H

View File

@@ -6,37 +6,37 @@
* SPDX-License-Identifier: MIT * SPDX-License-Identifier: MIT
*/ */
/* Declarations related to processing of object (.o) files */ // Declarations related to processing of object (.o) files
#ifndef RGBDS_LINK_OBJECT_H #ifndef RGBDS_LINK_OBJECT_H
#define RGBDS_LINK_OBJECT_H #define RGBDS_LINK_OBJECT_H
/** /*
* Read an object (.o) file, and add its info to the data structures. * Read an object (.o) file, and add its info to the data structures.
* @param fileName A path to the object file to be read * @param fileName A path to the object file to be read
* @param i The ID of the file * @param i The ID of the file
*/ */
void obj_ReadFile(char const *fileName, unsigned int i); void obj_ReadFile(char const *fileName, unsigned int i);
/** /*
* Perform validation on the object files' contents * Perform validation on the object files' contents
*/ */
void obj_DoSanityChecks(void); void obj_DoSanityChecks(void);
/** /*
* Evaluate all assertions * Evaluate all assertions
*/ */
void obj_CheckAssertions(void); void obj_CheckAssertions(void);
/** /*
* Sets up object file reading * Sets up object file reading
* @param nbFiles The number of object files that will be read * @param nbFiles The number of object files that will be read
*/ */
void obj_Setup(unsigned int nbFiles); void obj_Setup(unsigned int nbFiles);
/** /*
* `free`s all object memory that was allocated. * `free`s all object memory that was allocated.
*/ */
void obj_Cleanup(void); void obj_Cleanup(void);
#endif /* RGBDS_LINK_OBJECT_H */ #endif // RGBDS_LINK_OBJECT_H

View File

@@ -6,7 +6,7 @@
* SPDX-License-Identifier: MIT * SPDX-License-Identifier: MIT
*/ */
/* Outputting the result of linking */ // Outputting the result of linking
#ifndef RGBDS_LINK_OUTPUT_H #ifndef RGBDS_LINK_OUTPUT_H
#define RGBDS_LINK_OUTPUT_H #define RGBDS_LINK_OUTPUT_H
@@ -14,22 +14,22 @@
#include "link/section.h" #include "link/section.h"
/** /*
* Registers a section for output. * Registers a section for output.
* @param section The section to add * @param section The section to add
*/ */
void out_AddSection(struct Section const *section); void out_AddSection(struct Section const *section);
/** /*
* Finds an assigned section overlapping another one. * Finds an assigned section overlapping another one.
* @param section The section that is being overlapped * @param section The section that is being overlapped
* @return A section overlapping it * @return A section overlapping it
*/ */
struct Section const *out_OverlappingSection(struct Section const *section); struct Section const *out_OverlappingSection(struct Section const *section);
/** /*
* Writes all output (bin, sym, map) files. * Writes all output (bin, sym, map) files.
*/ */
void out_WriteFiles(void); void out_WriteFiles(void);
#endif /* RGBDS_LINK_OUTPUT_H */ #endif // RGBDS_LINK_OUTPUT_H

View File

@@ -6,7 +6,7 @@
* SPDX-License-Identifier: MIT * SPDX-License-Identifier: MIT
*/ */
/* Applying patches to SECTIONs */ // Applying patches to SECTIONs
#ifndef RGBDS_LINK_PATCH_H #ifndef RGBDS_LINK_PATCH_H
#define RGBDS_LINK_PATCH_H #define RGBDS_LINK_PATCH_H
@@ -27,15 +27,15 @@ struct Assertion {
struct Assertion *next; struct Assertion *next;
}; };
/** /*
* Checks all assertions * Checks all assertions
* @return true if assertion failed * @return true if assertion failed
*/ */
void patch_CheckAssertions(struct Assertion *assertion); void patch_CheckAssertions(struct Assertion *assertion);
/** /*
* Applies all SECTIONs' patches to them * Applies all SECTIONs' patches to them
*/ */
void patch_ApplyPatches(void); void patch_ApplyPatches(void);
#endif /* RGBDS_LINK_PATCH_H */ #endif // RGBDS_LINK_PATCH_H

View File

@@ -6,7 +6,7 @@
* SPDX-License-Identifier: MIT * SPDX-License-Identifier: MIT
*/ */
/* Parsing a linker script */ // Parsing a linker script
#ifndef RGBDS_LINK_SCRIPT_H #ifndef RGBDS_LINK_SCRIPT_H
#define RGBDS_LINK_SCRIPT_H #define RGBDS_LINK_SCRIPT_H
@@ -24,15 +24,15 @@ struct SectionPlacement {
extern uint64_t script_lineNo; extern uint64_t script_lineNo;
/** /*
* Parses the linker script to return the next section constraint * Parses the linker script to return the next section constraint
* @return A pointer to a struct, or NULL on EOF. The pointer shouldn't be freed * @return A pointer to a struct, or NULL on EOF. The pointer shouldn't be freed
*/ */
struct SectionPlacement *script_NextSection(void); struct SectionPlacement *script_NextSection(void);
/** /*
* `free`s all assignment memory that was allocated. * `free`s all assignment memory that was allocated.
*/ */
void script_Cleanup(void); void script_Cleanup(void);
#endif /* RGBDS_LINK_SCRIPT_H */ #endif // RGBDS_LINK_SCRIPT_H

View File

@@ -6,7 +6,7 @@
* SPDX-License-Identifier: MIT * SPDX-License-Identifier: MIT
*/ */
/* Assigning all sections a place */ // Assigning all sections a place
#ifndef RGBDS_LINK_SDAS_OBJ_H #ifndef RGBDS_LINK_SDAS_OBJ_H
#define RGBDS_LINK_SDAS_OBJ_H #define RGBDS_LINK_SDAS_OBJ_H
@@ -16,4 +16,4 @@ struct FileStackNode;
void sdobj_ReadFile(struct FileStackNode const *fileName, FILE *file); void sdobj_ReadFile(struct FileStackNode const *fileName, FILE *file);
#endif /* RGBDS_LINK_SDAS_OBJ_H */ #endif // RGBDS_LINK_SDAS_OBJ_H

View File

@@ -6,11 +6,11 @@
* SPDX-License-Identifier: MIT * SPDX-License-Identifier: MIT
*/ */
/* Declarations manipulating symbols */ // Declarations manipulating symbols
#ifndef RGBDS_LINK_SECTION_H #ifndef RGBDS_LINK_SECTION_H
#define RGBDS_LINK_SECTION_H #define RGBDS_LINK_SECTION_H
/* GUIDELINE: external code MUST NOT BE AWARE of the data structure used!! */ // GUIDELINE: external code MUST NOT BE AWARE of the data structure used!!
#include <stdint.h> #include <stdint.h>
#include <stdbool.h> #include <stdbool.h>
@@ -41,7 +41,7 @@ struct Patch {
}; };
struct Section { struct Section {
/* Info contained in the object files */ // Info contained in the object files
char *name; char *name;
uint16_t size; uint16_t size;
uint16_t offset; uint16_t offset;
@@ -56,14 +56,14 @@ struct Section {
bool isAlignFixed; bool isAlignFixed;
uint16_t alignMask; uint16_t alignMask;
uint16_t alignOfs; uint16_t alignOfs;
uint8_t *data; /* Array of size `size`*/ uint8_t *data; // Array of size `size`
uint32_t nbPatches; uint32_t nbPatches;
struct Patch *patches; struct Patch *patches;
/* Extra info computed during linking */ // Extra info computed during linking
struct Symbol **fileSymbols; struct Symbol **fileSymbols;
uint32_t nbSymbols; uint32_t nbSymbols;
struct Symbol **symbols; struct Symbol **symbols;
struct Section *nextu; /* The next "component" of this unionized sect */ struct Section *nextu; // The next "component" of this unionized sect
}; };
/* /*
@@ -76,27 +76,27 @@ struct Section {
*/ */
void sect_ForEach(void (*callback)(struct Section *, void *), void *arg); void sect_ForEach(void (*callback)(struct Section *, void *), void *arg);
/** /*
* Registers a section to be processed. * Registers a section to be processed.
* @param section The section to register. * @param section The section to register.
*/ */
void sect_AddSection(struct Section *section); void sect_AddSection(struct Section *section);
/** /*
* Finds a section by its name. * Finds a section by its name.
* @param name The name of the section to look for * @param name The name of the section to look for
* @return A pointer to the section, or NULL if it wasn't found * @return A pointer to the section, or NULL if it wasn't found
*/ */
struct Section *sect_GetSection(char const *name); struct Section *sect_GetSection(char const *name);
/** /*
* `free`s all section memory that was allocated. * `free`s all section memory that was allocated.
*/ */
void sect_CleanupSections(void); void sect_CleanupSections(void);
/** /*
* Checks if all sections meet reasonable criteria, such as max size * Checks if all sections meet reasonable criteria, such as max size
*/ */
void sect_DoSanityChecks(void); void sect_DoSanityChecks(void);
#endif /* RGBDS_LINK_SECTION_H */ #endif // RGBDS_LINK_SECTION_H

View File

@@ -6,11 +6,11 @@
* SPDX-License-Identifier: MIT * SPDX-License-Identifier: MIT
*/ */
/* Declarations manipulating symbols */ // Declarations manipulating symbols
#ifndef RGBDS_LINK_SYMBOL_H #ifndef RGBDS_LINK_SYMBOL_H
#define RGBDS_LINK_SYMBOL_H #define RGBDS_LINK_SYMBOL_H
/* GUIDELINE: external code MUST NOT BE AWARE of the data structure used!! */ // GUIDELINE: external code MUST NOT BE AWARE of the data structure used!!
#include <stdint.h> #include <stdint.h>
@@ -19,7 +19,7 @@
struct FileStackNode; struct FileStackNode;
struct Symbol { struct Symbol {
/* Info contained in the object files */ // Info contained in the object files
char *name; char *name;
enum ExportLevel type; enum ExportLevel type;
char const *objFileName; char const *objFileName;
@@ -31,7 +31,7 @@ struct Symbol {
int32_t offset; int32_t offset;
int32_t value; int32_t value;
}; };
/* Extra info computed during linking */ // Extra info computed during linking
struct Section *section; struct Section *section;
}; };
@@ -47,16 +47,16 @@ void sym_ForEach(void (*callback)(struct Symbol *, void *), void *arg);
void sym_AddSymbol(struct Symbol *symbol); void sym_AddSymbol(struct Symbol *symbol);
/** /*
* Finds a symbol in all the defined symbols. * Finds a symbol in all the defined symbols.
* @param name The name of the symbol to look for * @param name The name of the symbol to look for
* @return A pointer to the symbol, or NULL if not found. * @return A pointer to the symbol, or NULL if not found.
*/ */
struct Symbol *sym_GetSymbol(char const *name); struct Symbol *sym_GetSymbol(char const *name);
/** /*
* `free`s all symbol memory that was allocated. * `free`s all symbol memory that was allocated.
*/ */
void sym_CleanupSymbols(void); void sym_CleanupSymbols(void);
#endif /* RGBDS_LINK_SYMBOL_H */ #endif // RGBDS_LINK_SYMBOL_H

View File

@@ -88,7 +88,7 @@ extern struct SectionTypeInfo {
uint32_t lastBank; uint32_t lastBank;
} sectionTypeInfo[SECTTYPE_INVALID]; } sectionTypeInfo[SECTTYPE_INVALID];
/** /*
* Tells whether a section has data in its object file definition, * Tells whether a section has data in its object file definition,
* depending on type. * depending on type.
* @param type The section's type * @param type The section's type
@@ -100,7 +100,7 @@ static inline bool sect_HasData(enum SectionType type)
return type == SECTTYPE_ROM0 || type == SECTTYPE_ROMX; return type == SECTTYPE_ROM0 || type == SECTTYPE_ROMX;
} }
/** /*
* Computes a memory region's end address (last byte), eg. 0x7FFF * Computes a memory region's end address (last byte), eg. 0x7FFF
* @return The address of the last byte in that memory region * @return The address of the last byte in that memory region
*/ */
@@ -109,7 +109,7 @@ static inline uint16_t endaddr(enum SectionType type)
return sectionTypeInfo[type].startAddr + sectionTypeInfo[type].size - 1; return sectionTypeInfo[type].startAddr + sectionTypeInfo[type].size - 1;
} }
/** /*
* Computes a memory region's number of banks * Computes a memory region's number of banks
* @return The number of banks, 1 for regions without banking * @return The number of banks, 1 for regions without banking
*/ */
@@ -141,4 +141,4 @@ enum PatchType {
PATCHTYPE_INVALID PATCHTYPE_INVALID
}; };
#endif /* RGBDS_LINKDEFS_H */ #endif // RGBDS_LINKDEFS_H

View File

@@ -18,4 +18,4 @@ int32_t op_shift_left(int32_t value, int32_t amount);
int32_t op_shift_right(int32_t value, int32_t amount); int32_t op_shift_right(int32_t value, int32_t amount);
int32_t op_shift_right_unsigned(int32_t value, int32_t amount); int32_t op_shift_right_unsigned(int32_t value, int32_t amount);
#endif /* RGBDS_OP_MATH_H */ #endif // RGBDS_OP_MATH_H

View File

@@ -6,7 +6,7 @@
* SPDX-License-Identifier: MIT * SPDX-License-Identifier: MIT
*/ */
/* platform-specific hacks */ // platform-specific hacks
#ifndef RGBDS_PLATFORM_H #ifndef RGBDS_PLATFORM_H
#define RGBDS_PLATFORM_H #define RGBDS_PLATFORM_H
@@ -20,20 +20,20 @@
# include <strings.h> # include <strings.h>
#endif #endif
/* MSVC has deprecated strdup in favor of _strdup */ // MSVC has deprecated strdup in favor of _strdup
#ifdef _MSC_VER #ifdef _MSC_VER
# define strdup _strdup # define strdup _strdup
#endif #endif
/* MSVC prefixes the names of S_* macros with underscores, // MSVC prefixes the names of S_* macros with underscores,
and doesn't define any S_IS* macros. Define them ourselves */ // and doesn't define any S_IS* macros; define them ourselves
#ifdef _MSC_VER #ifdef _MSC_VER
# define S_IFMT _S_IFMT # define S_IFMT _S_IFMT
# define S_IFDIR _S_IFDIR # define S_IFDIR _S_IFDIR
# define S_ISDIR(mode) (((mode) & S_IFMT) == S_IFDIR) # define S_ISDIR(mode) (((mode) & S_IFMT) == S_IFDIR)
#endif #endif
/* MSVC doesn't use POSIX types or defines for `read` */ // MSVC doesn't use POSIX types or defines for `read`
#ifdef _MSC_VER #ifdef _MSC_VER
# include <io.h> # include <io.h>
# define STDIN_FILENO 0 # define STDIN_FILENO 0
@@ -46,7 +46,7 @@
# include <unistd.h> # include <unistd.h>
#endif #endif
/* MSVC doesn't support `[static N]` for array arguments from C99 or C11 */ // MSVC doesn't support `[static N]` for array arguments from C99 or C11
#ifdef _MSC_VER #ifdef _MSC_VER
# define MIN_NB_ELMS(N) # define MIN_NB_ELMS(N)
# define ARR_QUALS(...) # define ARR_QUALS(...)
@@ -75,4 +75,4 @@
# define setmode(fd, mode) ((void)0) # define setmode(fd, mode) ((void)0)
#endif #endif
#endif /* RGBDS_PLATFORM_H */ #endif // RGBDS_PLATFORM_H

View File

@@ -24,4 +24,4 @@ char const *get_package_version_string(void);
} }
#endif #endif
#endif /* EXTERN_VERSION_H */ #endif // EXTERN_VERSION_H

View File

@@ -21,33 +21,29 @@
#include "hashmap.h" #include "hashmap.h"
/* // Charmaps are stored using a structure known as "trie".
* Charmaps are stored using a structure known as "trie". // Essentially a tree, where each nodes stores a single character's worth of info:
* 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,
* whether there exists a mapping that ends at the current character,
*/
struct Charnode { struct Charnode {
bool isTerminal; /* Whether there exists a mapping that ends here */ bool isTerminal; // Whether there exists a mapping that ends here
uint8_t value; /* If the above is true, its corresponding value */ uint8_t value; // If the above is true, its corresponding value
/* This MUST be indexes and not pointers, because pointers get invalidated by `realloc`!! */ // 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 */ size_t next[255]; // Indexes of where to go next, 0 = nowhere
}; };
#define INITIAL_CAPACITY 32 #define INITIAL_CAPACITY 32
struct Charmap { struct Charmap {
char *name; char *name;
size_t usedNodes; /* How many nodes are being used */ size_t usedNodes; // How many nodes are being used
size_t capacity; /* How many nodes have been allocated */ size_t capacity; // How many nodes have been allocated
struct Charnode nodes[]; /* first node is reserved for the root node */ struct Charnode nodes[]; // first node is reserved for the root node
}; };
static HashMap charmaps; static HashMap charmaps;
/* // Store pointers to hashmap nodes, so that there is only one pointer to the memory block
* Store pointers to hashmap nodes, so that there is only one pointer to the memory block // that gets reallocated.
* that gets reallocated.
*/
static struct Charmap **currentCharmap; static struct Charmap **currentCharmap;
struct CharmapStackEntry { struct CharmapStackEntry {
@@ -96,7 +92,7 @@ struct Charmap *charmap_New(char const *name, char const *baseName)
return charmap; return charmap;
} }
/* Init the new charmap's fields */ // Init the new charmap's fields
if (base) { if (base) {
resizeCharmap(&charmap, base->capacity); resizeCharmap(&charmap, base->capacity);
charmap->usedNodes = base->usedNodes; charmap->usedNodes = base->usedNodes;
@@ -105,7 +101,7 @@ struct Charmap *charmap_New(char const *name, char const *baseName)
} else { } else {
resizeCharmap(&charmap, INITIAL_CAPACITY); resizeCharmap(&charmap, INITIAL_CAPACITY);
charmap->usedNodes = 1; charmap->usedNodes = 1;
initNode(&charmap->nodes[0]); /* Init the root node */ initNode(&charmap->nodes[0]); // Init the root node
} }
charmap->name = strdup(name); charmap->name = strdup(name);
@@ -169,16 +165,16 @@ void charmap_Add(char *mapping, uint8_t value)
if (node->next[c]) { if (node->next[c]) {
node = &charmap->nodes[node->next[c]]; node = &charmap->nodes[node->next[c]];
} else { } else {
/* Register next available node */ // Register next available node
node->next[c] = charmap->usedNodes; 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) { if (charmap->usedNodes == charmap->capacity) {
charmap->capacity *= 2; charmap->capacity *= 2;
resizeCharmap(currentCharmap, charmap->capacity); resizeCharmap(currentCharmap, charmap->capacity);
charmap = *currentCharmap; charmap = *currentCharmap;
} }
/* Switch to and init new node */ // Switch to and init new node
node = &charmap->nodes[charmap->usedNodes++]; node = &charmap->nodes[charmap->usedNodes++];
initNode(node); 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) size_t charmap_ConvertNext(char const **input, uint8_t **output)
{ {
/* // The goal is to match the longest mapping possible.
* The goal is to match the longest mapping possible. // For that, advance through the trie with each character read.
* 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 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.
* If no match, read a UTF-8 codepoint and output that.
*/
struct Charmap const *charmap = *currentCharmap; struct Charmap const *charmap = *currentCharmap;
struct Charnode const *node = &charmap->nodes[0]; struct Charnode const *node = &charmap->nodes[0];
struct Charnode const *match = NULL; struct Charnode const *match = NULL;

View File

@@ -6,9 +6,7 @@
* SPDX-License-Identifier: MIT * SPDX-License-Identifier: MIT
*/ */
/* // Fixed-point math routines
* Fixed-point math routines
*/
#include <inttypes.h> #include <inttypes.h>
#include <math.h> #include <math.h>
@@ -30,9 +28,6 @@
#define M_PI 3.14159265358979323846 #define M_PI 3.14159265358979323846
#endif #endif
/*
* Print a fixed point value
*/
void fix_Print(int32_t i) void fix_Print(int32_t i)
{ {
uint32_t u = i; uint32_t u = i;
@@ -47,121 +42,76 @@ void fix_Print(int32_t i)
((uint32_t)(fix2double(u) * 100000 + 0.5)) % 100000); ((uint32_t)(fix2double(u) * 100000 + 0.5)) % 100000);
} }
/*
* Calculate sine
*/
int32_t fix_Sin(int32_t i) int32_t fix_Sin(int32_t i)
{ {
return double2fix(sin(fdeg2rad(fix2double(i)))); return double2fix(sin(fdeg2rad(fix2double(i))));
} }
/*
* Calculate cosine
*/
int32_t fix_Cos(int32_t i) int32_t fix_Cos(int32_t i)
{ {
return double2fix(cos(fdeg2rad(fix2double(i)))); return double2fix(cos(fdeg2rad(fix2double(i))));
} }
/*
* Calculate tangent
*/
int32_t fix_Tan(int32_t i) int32_t fix_Tan(int32_t i)
{ {
return double2fix(tan(fdeg2rad(fix2double(i)))); return double2fix(tan(fdeg2rad(fix2double(i))));
} }
/*
* Calculate arcsine
*/
int32_t fix_ASin(int32_t i) int32_t fix_ASin(int32_t i)
{ {
return double2fix(rad2fdeg(asin(fix2double(i)))); return double2fix(rad2fdeg(asin(fix2double(i))));
} }
/*
* Calculate arccosine
*/
int32_t fix_ACos(int32_t i) int32_t fix_ACos(int32_t i)
{ {
return double2fix(rad2fdeg(acos(fix2double(i)))); return double2fix(rad2fdeg(acos(fix2double(i))));
} }
/*
* Calculate arctangent
*/
int32_t fix_ATan(int32_t i) int32_t fix_ATan(int32_t i)
{ {
return double2fix(rad2fdeg(atan(fix2double(i)))); return double2fix(rad2fdeg(atan(fix2double(i))));
} }
/*
* Calculate atan2
*/
int32_t fix_ATan2(int32_t i, int32_t j) int32_t fix_ATan2(int32_t i, int32_t j)
{ {
return double2fix(rad2fdeg(atan2(fix2double(i), fix2double(j)))); return double2fix(rad2fdeg(atan2(fix2double(i), fix2double(j))));
} }
/*
* Multiplication
*/
int32_t fix_Mul(int32_t i, int32_t j) int32_t fix_Mul(int32_t i, int32_t j)
{ {
return double2fix(fix2double(i) * fix2double(j)); return double2fix(fix2double(i) * fix2double(j));
} }
/*
* Division
*/
int32_t fix_Div(int32_t i, int32_t j) int32_t fix_Div(int32_t i, int32_t j)
{ {
return double2fix(fix2double(i) / fix2double(j)); return double2fix(fix2double(i) / fix2double(j));
} }
/*
* Modulo
*/
int32_t fix_Mod(int32_t i, int32_t j) int32_t fix_Mod(int32_t i, int32_t j)
{ {
return double2fix(fmod(fix2double(i), fix2double(j))); return double2fix(fmod(fix2double(i), fix2double(j)));
} }
/*
* Power
*/
int32_t fix_Pow(int32_t i, int32_t j) int32_t fix_Pow(int32_t i, int32_t j)
{ {
return double2fix(pow(fix2double(i), fix2double(j))); return double2fix(pow(fix2double(i), fix2double(j)));
} }
/*
* Logarithm
*/
int32_t fix_Log(int32_t i, int32_t j) int32_t fix_Log(int32_t i, int32_t j)
{ {
return double2fix(log(fix2double(i)) / log(fix2double(j))); return double2fix(log(fix2double(i)) / log(fix2double(j)));
} }
/*
* Round
*/
int32_t fix_Round(int32_t i) int32_t fix_Round(int32_t i)
{ {
return double2fix(round(fix2double(i))); return double2fix(round(fix2double(i)));
} }
/*
* Ceil
*/
int32_t fix_Ceil(int32_t i) int32_t fix_Ceil(int32_t i)
{ {
return double2fix(ceil(fix2double(i))); return double2fix(ceil(fix2double(i)));
} }
/*
* Floor
*/
int32_t fix_Floor(int32_t i) int32_t fix_Floor(int32_t i)
{ {
return double2fix(floor(fix2double(i))); return double2fix(floor(fix2double(i)));

View File

@@ -46,7 +46,7 @@ void fmt_UseCharacter(struct FormatSpec *fmt, int c)
return; return;
switch (c) { switch (c) {
/* sign */ // sign
case ' ': case ' ':
case '+': case '+':
if (fmt->state > FORMAT_SIGN) if (fmt->state > FORMAT_SIGN)
@@ -55,7 +55,7 @@ void fmt_UseCharacter(struct FormatSpec *fmt, int c)
fmt->sign = c; fmt->sign = c;
break; break;
/* prefix */ // prefix
case '#': case '#':
if (fmt->state > FORMAT_PREFIX) if (fmt->state > FORMAT_PREFIX)
goto invalid; goto invalid;
@@ -63,7 +63,7 @@ void fmt_UseCharacter(struct FormatSpec *fmt, int c)
fmt->prefix = true; fmt->prefix = true;
break; break;
/* align */ // align
case '-': case '-':
if (fmt->state > FORMAT_ALIGN) if (fmt->state > FORMAT_ALIGN)
goto invalid; goto invalid;
@@ -71,11 +71,11 @@ void fmt_UseCharacter(struct FormatSpec *fmt, int c)
fmt->alignLeft = true; fmt->alignLeft = true;
break; break;
/* pad and width */ // pad and width
case '0': case '0':
if (fmt->state < FORMAT_WIDTH) if (fmt->state < FORMAT_WIDTH)
fmt->padZero = true; fmt->padZero = true;
/* fallthrough */ // fallthrough
case '1': case '1':
case '2': case '2':
case '3': case '3':
@@ -104,7 +104,7 @@ void fmt_UseCharacter(struct FormatSpec *fmt, int c)
fmt->hasFrac = true; fmt->hasFrac = true;
break; break;
/* type */ // type
case 'd': case 'd':
case 'u': case 'u':
case 'X': 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 len = strlen(value);
size_t totalLen = fmt->width > len ? fmt->width : len; 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"); error("Formatted string value too long\n");
totalLen = bufLen - 1; totalLen = bufLen - 1;
if (len > totalLen) if (len > totalLen)
@@ -182,7 +182,7 @@ void fmt_PrintNumber(char *buf, size_t bufLen, struct FormatSpec const *fmt, uin
if (fmt->type == 's') if (fmt->type == 's')
error("Formatting number as type 's'\n"); 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') { if (fmt->type == 'd' || fmt->type == 'f') {
int32_t v = value; int32_t v = value;
@@ -200,10 +200,10 @@ void fmt_PrintNumber(char *buf, size_t bufLen, struct FormatSpec const *fmt, uin
: fmt->type == 'o' ? '&' : fmt->type == 'o' ? '&'
: 0; : 0;
char valueBuf[262]; /* Max 5 digits + decimal + 255 fraction digits + terminator */ char valueBuf[262]; // Max 5 digits + decimal + 255 fraction digits + terminator
if (fmt->type == 'b') { if (fmt->type == 'b') {
/* Special case for binary */ // Special case for binary
char *ptr = valueBuf; char *ptr = valueBuf;
do { do {
@@ -213,7 +213,7 @@ void fmt_PrintNumber(char *buf, size_t bufLen, struct FormatSpec const *fmt, uin
*ptr = '\0'; *ptr = '\0';
/* Reverse the digits */ // Reverse the digits
size_t valueLen = ptr - valueBuf; size_t valueLen = ptr - valueBuf;
for (size_t i = 0, j = valueLen - 1; i < j; i++, j--) { 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; valueBuf[j] = c;
} }
} else if (fmt->type == 'f') { } 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; size_t fracWidth = fmt->hasFrac ? fmt->fracWidth : 5;
if (fracWidth > 255) { 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 numLen = !!sign + !!prefix + len;
size_t totalLen = fmt->width > numLen ? fmt->width : numLen; 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"); error("Formatted numeric value too long\n");
totalLen = bufLen - 1; totalLen = bufLen - 1;
if (numLen > totalLen) { if (numLen > totalLen) {
@@ -273,7 +273,7 @@ void fmt_PrintNumber(char *buf, size_t bufLen, struct FormatSpec const *fmt, uin
buf[i] = ' '; buf[i] = ' ';
} else { } else {
if (fmt->padZero) { if (fmt->padZero) {
/* sign, then prefix, then zero padding */ // sign, then prefix, then zero padding
if (sign) if (sign)
buf[pos++] = sign; buf[pos++] = sign;
if (prefix) 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++) for (size_t i = 0; i < padLen; i++)
buf[pos++] = '0'; buf[pos++] = '0';
} else { } else {
/* space padding, then sign, then prefix */ // space padding, then sign, then prefix
for (size_t i = 0; i < padLen; i++) for (size_t i = 0; i < padLen; i++)
buf[pos++] = ' '; buf[pos++] = ' ';
if (sign) if (sign)

View File

@@ -19,7 +19,7 @@
#include "asm/main.h" #include "asm/main.h"
#include "asm/symbol.h" #include "asm/symbol.h"
#include "asm/warning.h" #include "asm/warning.h"
#include "platform.h" /* S_ISDIR (stat macro) */ #include "platform.h" // S_ISDIR (stat macro)
#define MAXINCPATHS 128 #define MAXINCPATHS 128
@@ -28,7 +28,7 @@ struct Context {
struct FileStackNode *fileInfo; struct FileStackNode *fileInfo;
struct LexerState *lexerState; struct LexerState *lexerState;
uint32_t uniqueID; uint32_t uniqueID;
struct MacroArgs *macroArgs; /* Macro args are *saved* here */ struct MacroArgs *macroArgs; // Macro args are *saved* here
uint32_t nbReptIters; uint32_t nbReptIters;
int32_t forValue; int32_t forValue;
int32_t forStep; int32_t forStep;
@@ -47,7 +47,7 @@ static const char *dumpNodeAndParents(struct FileStackNode const *node)
char const *name; char const *name;
if (node->type == NODE_REPT) { 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; struct FileStackReptNode const *reptInfo = (struct FileStackReptNode const *)node;
name = dumpNodeAndParents(node->parent); name = dumpNodeAndParents(node->parent);
@@ -88,7 +88,7 @@ struct FileStackNode *fstk_GetFileStack(void)
struct FileStackNode *node = contextStack->fileInfo; 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) { while (node && !node->referenced) {
node->ID = -1; node->ID = -1;
node->referenced = true; node->referenced = true;
@@ -99,7 +99,7 @@ struct FileStackNode *fstk_GetFileStack(void)
char const *fstk_GetFileName(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; struct FileStackNode const *node = contextStack->fileInfo;
while (node->type != NODE_FILE) while (node->type != NODE_FILE)
@@ -120,7 +120,7 @@ void fstk_AddIncludePath(char const *path)
char *str = malloc(allocSize); char *str = malloc(allocSize);
if (!str) { 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)); error("Failed to allocate new include path: %s\n", strerror(errno));
return; return;
} }
@@ -149,14 +149,14 @@ static bool isPathValid(char const *path)
if (stat(path, &statbuf) != 0) if (stat(path, &statbuf) != 0)
return false; return false;
/* Reject directories */ // Reject directories
return !S_ISDIR(statbuf.st_mode); return !S_ISDIR(statbuf.st_mode);
} }
bool fstk_FindFile(char const *path, char **fullPath, size_t *size) bool fstk_FindFile(char const *path, char **fullPath, size_t *size)
{ {
if (!*size) { if (!*size) {
*size = 64; /* This is arbitrary, really */ *size = 64; // This is arbitrary, really
*fullPath = realloc(*fullPath, *size); *fullPath = realloc(*fullPath, *size);
if (!*fullPath) if (!*fullPath)
error("realloc error during include path search: %s\n", 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; break;
} }
/* Oh how I wish `asnprintf` was standard... */ // Oh how I wish `asnprintf` was standard...
if ((size_t)len >= *size) { /* `len` doesn't include the terminator, `size` does */ if ((size_t)len >= *size) { // `size` includes the terminator, `len` doesn't
*size = len + 1; *size = len + 1;
*fullPath = realloc(*fullPath, *size); *fullPath = realloc(*fullPath, *size);
if (!*fullPath) { if (!*fullPath) {
@@ -212,17 +212,18 @@ bool yywrap(void)
fatalerror("Ended block with %" PRIu32 " unterminated IF construct%s\n", fatalerror("Ended block with %" PRIu32 " unterminated IF construct%s\n",
ifDepth, ifDepth == 1 ? "" : "s"); 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; 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) { if (contextStack->fileInfo->referenced) {
size_t size = sizeof(*fileInfo) + sizeof(fileInfo->iters[0]) * fileInfo->reptDepth; size_t size = sizeof(*fileInfo) + sizeof(fileInfo->iters[0]) * fileInfo->reptDepth;
struct FileStackReptNode *copy = malloc(size); struct FileStackReptNode *copy = malloc(size);
if (!copy) if (!copy)
fatalerror("Failed to duplicate REPT file node: %s\n", strerror(errno)); 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); memcpy(copy, fileInfo, size);
copy->node.next = NULL; copy->node.next = NULL;
copy->node.referenced = false; copy->node.referenced = false;
@@ -231,19 +232,19 @@ bool yywrap(void)
contextStack->fileInfo = (struct FileStackNode *)fileInfo; 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) { if (contextStack->forName && fileInfo->iters[0] <= contextStack->nbReptIters) {
contextStack->forValue += contextStack->forStep; contextStack->forValue += contextStack->forStep;
struct Symbol *sym = sym_AddVar(contextStack->forName, struct Symbol *sym = sym_AddVar(contextStack->forName,
contextStack->forValue); 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) if (sym->type != SYM_VAR)
fatalerror("Failed to update FOR symbol value\n"); fatalerror("Failed to update FOR symbol value\n");
} }
/* Advance to the next iteration */ // Advance to the next iteration
fileInfo->iters[0]++; 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) { if (fileInfo->iters[0] <= contextStack->nbReptIters) {
lexer_RestartRept(contextStack->fileInfo->lineNo); lexer_RestartRept(contextStack->fileInfo->lineNo);
contextStack->uniqueID = macro_UseNewUniqueID(); contextStack->uniqueID = macro_UseNewUniqueID();
@@ -260,15 +261,15 @@ bool yywrap(void)
contextDepth--; contextDepth--;
lexer_DeleteState(context->lexerState); 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) if (context->fileInfo->type == NODE_MACRO)
macro_UseNewArgs(contextStack->macroArgs); macro_UseNewArgs(contextStack->macroArgs);
/* Free the file stack node */ // Free the file stack node
if (!context->fileInfo->referenced) if (!context->fileInfo->referenced)
free(context->fileInfo); free(context->fileInfo);
/* Free the FOR symbol name */ // Free the FOR symbol name
free(context->forName); 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); free(context);
lexer_SetState(contextStack->lexerState); lexer_SetState(contextStack->lexerState);
@@ -276,11 +277,9 @@ bool yywrap(void)
return false; return false;
} }
/* // Make sure not to switch the lexer state before calling this, so the saved line no is correct.
* 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.
* 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.
* Callers should set contextStack->lexerState after this so it is not NULL
*/
static void newContext(struct FileStackNode *fileInfo) static void newContext(struct FileStackNode *fileInfo)
{ {
++contextDepth; ++contextDepth;
@@ -291,15 +290,14 @@ static void newContext(struct FileStackNode *fileInfo)
if (!context) if (!context)
fatalerror("Failed to allocate memory for new context: %s\n", strerror(errno)); fatalerror("Failed to allocate memory for new context: %s\n", strerror(errno));
fileInfo->parent = contextStack->fileInfo; 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->referenced = false;
fileInfo->lineNo = lexer_GetLineNo(); fileInfo->lineNo = lexer_GetLineNo();
context->fileInfo = fileInfo; context->fileInfo = fileInfo;
context->forName = NULL; context->forName = NULL;
/*
* Link new entry to its parent so it's reachable later // Link new entry to its parent so it's reachable later
* ERRORS SHOULD NOT OCCUR AFTER THIS!! // ERRORS SHOULD NOT OCCUR AFTER THIS!!
*/
context->parent = contextStack; context->parent = contextStack;
contextStack = context; contextStack = context;
} }
@@ -337,7 +335,7 @@ void fstk_RunInclude(char const *path)
if (!contextStack->lexerState) if (!contextStack->lexerState)
fatalerror("Failed to set up lexer for file include\n"); fatalerror("Failed to set up lexer for file include\n");
lexer_SetStateAtEOL(contextStack->lexerState); 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; contextStack->uniqueID = 0;
macro_SetUniqueID(0); macro_SetUniqueID(0);
} }
@@ -356,16 +354,16 @@ void fstk_RunMacro(char const *macroName, struct MacroArgs *args)
} }
contextStack->macroArgs = macro_GetCurrentArgs(); 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; size_t reptNameLen = 0;
struct FileStackNode const *node = macro->src; struct FileStackNode const *node = macro->src;
if (node->type == NODE_REPT) { if (node->type == NODE_REPT) {
struct FileStackReptNode const *reptNode = (struct FileStackReptNode const *)node; 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"); reptNameLen += reptNode->reptDepth * strlen("::REPT~4294967295");
/* Look for next named node */ // Look for next named node
do { do {
node = node->parent; node = node->parent;
} while (node->type == NODE_REPT); } while (node->type == NODE_REPT);
@@ -381,7 +379,7 @@ void fstk_RunMacro(char const *macroName, struct MacroArgs *args)
return; return;
} }
fileInfo->node.type = NODE_MACRO; fileInfo->node.type = NODE_MACRO;
/* Print the name... */ // Print the name...
char *dest = fileInfo->name; char *dest = fileInfo->name;
memcpy(dest, baseNode->name, baseLen); 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->reptDepth = reptDepth + 1;
fileInfo->iters[0] = 1; fileInfo->iters[0] = 1;
if (reptDepth) if (reptDepth)
/* Copy all parent iter counts */ // Copy all parent iter counts
memcpy(&fileInfo->iters[1], memcpy(&fileInfo->iters[1],
((struct FileStackReptNode *)contextStack->fileInfo)->iters, ((struct FileStackReptNode *)contextStack->fileInfo)->iters,
reptDepth * sizeof(fileInfo->iters[0])); reptDepth * sizeof(fileInfo->iters[0]));
newContext((struct FileStackNode *)fileInfo); 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->fileInfo->lineNo = reptLineNo;
contextStack->lexerState = lexer_OpenFileView("REPT", body, size, 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) void fstk_StopRept(void)
{ {
/* Prevent more iterations */ // Prevent more iterations
contextStack->nbReptIters = 0; 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)); fatalerror("Failed to allocate memory for main file info: %s\n", strerror(errno));
context->fileInfo = (struct FileStackNode *)fileInfo; 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->parent = NULL;
context->fileInfo->lineNo = 0; // This still gets written to the object file, so init it context->fileInfo->lineNo = 0; // This still gets written to the object file, so init it
context->fileInfo->referenced = false; context->fileInfo->referenced = false;
@@ -548,13 +546,11 @@ void fstk_Init(char const *mainPath, size_t maxDepth)
context->forStep = 0; context->forStep = 0;
context->forName = NULL; 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; contextStack = context;
/* // Check that max recursion depth won't allow overflowing node `malloc`s
* Check that max recursion depth won't allow overflowing node `malloc`s // This assumes that the rept node is larger
* This assumes that the rept node is larger
*/
#define DEPTH_LIMIT ((SIZE_MAX - sizeof(struct FileStackReptNode)) / sizeof(uint32_t)) #define DEPTH_LIMIT ((SIZE_MAX - sizeof(struct FileStackReptNode)) / sizeof(uint32_t))
if (maxDepth > DEPTH_LIMIT) { if (maxDepth > DEPTH_LIMIT) {
error("Recursion depth may not be higher than %zu, defaulting to " 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 { } else {
maxRecursionDepth = maxDepth; 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); assert(DEPTH_LIMIT >= DEFAULT_MAX_DEPTH);
#undef DEPTH_LIMIT #undef DEPTH_LIMIT
} }

File diff suppressed because it is too large Load Diff

View File

@@ -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 <assert.h>
#include <errno.h> #include <errno.h>
@@ -12,13 +19,11 @@
#define MAXMACROARGS 99999 #define MAXMACROARGS 99999
/* // Your average macro invocation does not go past the tens, but some go further
* 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,
* This ensures that sane and slightly insane invocations suffer no penalties, // and the rest is insane and thus will assume responsibility.
* and the rest is insane and thus will assume responsibility. // Additionally, ~300 bytes (on x64) of memory per level of nesting has been
* Additionally, ~300 bytes (on x64) of memory per level of nesting has been // deemed reasonable. (Halve that on x86.)
* deemed reasonable. (Halve that on x86.)
*/
#define INITIAL_ARG_SIZE 32 #define INITIAL_ARG_SIZE 32
struct MacroArgs { struct MacroArgs {
unsigned int nbArgs; unsigned int nbArgs;
@@ -33,11 +38,9 @@ struct MacroArgs {
static struct MacroArgs *macroArgs = NULL; static struct MacroArgs *macroArgs = NULL;
static uint32_t uniqueID = 0; static uint32_t uniqueID = 0;
static uint32_t maxUniqueID = 0; static uint32_t maxUniqueID = 0;
/* // The initialization is somewhat harmful, since it is never used, but it
* 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
* 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!
* better solution, but if you have one, please feel free!
*/
static char uniqueIDBuf[] = "_u4294967295"; // UINT32_MAX static char uniqueIDBuf[] = "_u4294967295"; // UINT32_MAX
static char *uniqueIDPtr = NULL; 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"); error("A maximum of " EXPAND_AND_STR(MAXMACROARGS) " arguments is allowed\n");
if (macArgs->nbArgs >= macArgs->capacity) { if (macArgs->nbArgs >= macArgs->capacity) {
macArgs->capacity *= 2; macArgs->capacity *= 2;
/* Check that overflow didn't roll us back */ // Check that overflow didn't roll us back
if (macArgs->capacity <= macArgs->nbArgs) if (macArgs->capacity <= macArgs->nbArgs)
fatalerror("Failed to add new macro argument: capacity overflow\n"); fatalerror("Failed to add new macro argument: capacity overflow\n");
macArgs = realloc(macArgs, SIZEOF_ARGS(macArgs->capacity)); macArgs = realloc(macArgs, SIZEOF_ARGS(macArgs->capacity));
@@ -112,9 +115,9 @@ char const *macro_GetAllArgs(void)
size_t len = 0; size_t len = 0;
for (uint32_t i = macroArgs->shift; i < macroArgs->nbArgs; i++) 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; char *ptr = str;
if (!str) if (!str)
@@ -126,9 +129,9 @@ char const *macro_GetAllArgs(void)
memcpy(ptr, macroArgs->args[i], n); memcpy(ptr, macroArgs->args[i], n);
ptr += 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) if (i < macroArgs->nbArgs - 1 || n == 0)
*ptr++ = ','; /* no space after comma */ *ptr++ = ','; // no space after comma
} }
*ptr = '\0'; *ptr = '\0';
@@ -153,8 +156,8 @@ void macro_SetUniqueID(uint32_t id)
} else { } else {
if (uniqueID > maxUniqueID) if (uniqueID > maxUniqueID)
maxUniqueID = uniqueID; maxUniqueID = uniqueID;
/* The buffer is guaranteed to be the correct size */ // The buffer is guaranteed to be the correct size
/* This is a valid label fragment, but not a valid numeric */ // This is a valid label fragment, but not a valid numeric
sprintf(uniqueIDBuf, "_u%" PRIu32, id); sprintf(uniqueIDBuf, "_u%" PRIu32, id);
uniqueIDPtr = uniqueIDBuf; uniqueIDPtr = uniqueIDBuf;
} }

View File

@@ -39,8 +39,8 @@
#ifdef __clang__ #ifdef __clang__
#if __has_feature(address_sanitizer) && !defined(__SANITIZE_ADDRESS__) #if __has_feature(address_sanitizer) && !defined(__SANITIZE_ADDRESS__)
#define __SANITIZE_ADDRESS__ #define __SANITIZE_ADDRESS__
#endif /* __has_feature(address_sanitizer) && !defined(__SANITIZE_ADDRESS__) */ #endif // __has_feature(address_sanitizer) && !defined(__SANITIZE_ADDRESS__)
#endif /* __clang__ */ #endif // __clang__
#ifdef __SANITIZE_ADDRESS__ #ifdef __SANITIZE_ADDRESS__
// There are known, non-trivial to fix leaks. We would still like to have `make develop' // 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 optimizeLoads;
bool warnOnLdOpt; bool warnOnLdOpt;
bool verbose; 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) static char *make_escape(char const *str)
{ {
char * const escaped_str = malloc(strlen(str) * 2 + 1); 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__); err("%s: Failed to allocate memory", __func__);
while (*str) { while (*str) {
/* All dollars needs to be doubled */ // All dollars needs to be doubled
if (*str == '$') if (*str == '$')
*dest++ = '$'; *dest++ = '$';
*dest++ = *str++; *dest++ = *str++;
@@ -85,22 +85,20 @@ static char *make_escape(char const *str)
return escaped_str; return escaped_str;
} }
/* Short options */ // Short options
static const char *optstring = "b:D:Eg:Hhi:LlM:o:p:r:VvW:w"; static const char *optstring = "b:D:Eg:Hhi:LlM:o:p:r:VvW:w";
/* Variables for the long-only options */ // Variables for the long-only options
static int depType; /* Variants of `-M` */ static int depType; // Variants of `-M`
/* // Equivalent long options
* Equivalent long options // Please keep in the same order as short opts
* Please keep in the same order as short opts //
* // Also, make sure long opts don't create ambiguity:
* Also, make sure long opts don't create ambiguity: // A long opt's name should start with the same letter as its short opt,
* 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`).
* except if it doesn't create any ambiguity (`verbose` versus `version`). // This is because long opt matching, even to a single char, is prioritized
* This is because long opt matching, even to a single char, is prioritized // over short opt matching
* over short opt matching
*/
static struct option const longopts[] = { static struct option const longopts[] = {
{ "binary-digits", required_argument, NULL, 'b' }, { "binary-digits", required_argument, NULL, 'b' },
{ "define", required_argument, NULL, 'D' }, { "define", required_argument, NULL, 'D' },
@@ -152,10 +150,8 @@ int main(int argc, char *argv[])
time_t now = time(NULL); time_t now = time(NULL);
char const *sourceDateEpoch = getenv("SOURCE_DATE_EPOCH"); char const *sourceDateEpoch = getenv("SOURCE_DATE_EPOCH");
/* // Support SOURCE_DATE_EPOCH for reproducible builds
* Support SOURCE_DATE_EPOCH for reproducible builds // https://reproducible-builds.org/docs/source-date-epoch/
* https://reproducible-builds.org/docs/source-date-epoch/
*/
if (sourceDateEpoch) if (sourceDateEpoch)
now = (time_t)strtoul(sourceDateEpoch, NULL, 0); now = (time_t)strtoul(sourceDateEpoch, NULL, 0);
@@ -289,7 +285,7 @@ int main(int argc, char *argv[])
warnings = false; warnings = false;
break; break;
/* Long-only options */ // Long-only options
case 0: case 0:
switch (depType) { switch (depType) {
case 'G': case 'G':
@@ -321,10 +317,10 @@ int main(int argc, char *argv[])
} }
break; break;
/* Unrecognized options */ // Unrecognized options
default: default:
print_usage(); print_usage();
/* NOTREACHED */ // NOTREACHED
} }
} }
@@ -376,7 +372,7 @@ int main(int argc, char *argv[])
if (failedOnMissingInclude) if (failedOnMissingInclude)
return 0; return 0;
/* If no path specified, don't write file */ // If no path specified, don't write file
if (objectName != NULL) if (objectName != NULL)
out_WriteObject(); out_WriteObject();
return 0; return 0;

View File

@@ -1,3 +1,11 @@
/*
* This file is part of RGBDS.
*
* Copyright (c) 2022, RGBDS contributors.
*
* SPDX-License-Identifier: MIT
*/
#include <ctype.h> #include <ctype.h>
#include <errno.h> #include <errno.h>
#include <stdbool.h> #include <stdbool.h>

View File

@@ -6,9 +6,7 @@
* SPDX-License-Identifier: MIT * SPDX-License-Identifier: MIT
*/ */
/* // Outputs an objectfile
* Outputs an objectfile
*/
#include <assert.h> #include <assert.h>
#include <errno.h> #include <errno.h>
@@ -54,18 +52,16 @@ char *objectName;
struct Section *sectionList; 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 *objectSymbols = NULL;
static struct Symbol **objectSymbolsTail = &objectSymbols; 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 Assertion *assertions = NULL;
static struct FileStackNode *fileStackNodes = 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) static uint32_t countSections(void)
{ {
uint32_t count = 0; uint32_t count = 0;
@@ -76,9 +72,7 @@ static uint32_t countSections(void)
return count; 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) static uint32_t countPatches(struct Section const *sect)
{ {
uint32_t r = 0; uint32_t r = 0;
@@ -90,9 +84,7 @@ static uint32_t countPatches(struct Section const *sect)
return r; 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) static uint32_t countAsserts(void)
{ {
struct Assertion *assert = assertions; struct Assertion *assert = assertions;
@@ -105,9 +97,7 @@ static uint32_t countAsserts(void)
return count; 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) static void putlong(uint32_t i, FILE *f)
{ {
putc(i, f); putc(i, f);
@@ -116,9 +106,7 @@ static void putlong(uint32_t i, FILE *f)
putc(i >> 24, 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) static void putstring(char const *s, FILE *f)
{ {
while (*s) while (*s)
@@ -133,7 +121,7 @@ static uint32_t getNbFileStackNodes(void)
void out_RegisterNode(struct FileStackNode *node) 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) { while (node->ID == (uint32_t)-1) {
node->ID = getNbFileStackNodes(); node->ID = getNbFileStackNodes();
if (node->ID == (uint32_t)-1) if (node->ID == (uint32_t)-1)
@@ -141,7 +129,7 @@ void out_RegisterNode(struct FileStackNode *node)
node->next = fileStackNodes; node->next = fileStackNodes;
fileStackNodes = node; fileStackNodes = node;
/* Also register the node's parents */ // Also register the node's parents
node = node->parent; node = node->parent;
if (!node) if (!node)
break; break;
@@ -156,25 +144,21 @@ This is code intended to replace a node, which is pretty useless until ref count
struct FileStackNode **ptr = &fileStackNodes; struct FileStackNode **ptr = &fileStackNodes;
/* // The linked list is supposed to have decrementing IDs, so iterate with less memory reads,
* 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
* to hopefully hit the cache less. A debug check is added after, in case a change is made // that breaks this assumption.
* that breaks this assumption.
*/
for (uint32_t i = fileStackNodes->ID; i != node->ID; i--) for (uint32_t i = fileStackNodes->ID; i != node->ID; i--)
ptr = &(*ptr)->next; ptr = &(*ptr)->next;
assert((*ptr)->ID == node->ID); assert((*ptr)->ID == node->ID);
node->next = (*ptr)->next; node->next = (*ptr)->next;
assert(!node->next || node->next->ID == node->ID - 1); /* Catch inconsistencies early */ assert(!node->next || node->next->ID == node->ID - 1); // Catch inconsistencies early
/* TODO: unreference the node */ // TODO: unreference the node
*ptr = node; *ptr = node;
#endif #endif
} }
/* // Return a section's ID
* Return a section's ID
*/
static uint32_t getsectid(struct Section const *sect) static uint32_t getsectid(struct Section const *sect)
{ {
struct Section const *sec = sectionList; struct Section const *sec = sectionList;
@@ -195,9 +179,7 @@ static uint32_t getSectIDIfAny(struct Section const *sect)
return sect ? getsectid(sect) : (uint32_t)-1; 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) static void writepatch(struct Patch const *patch, FILE *f)
{ {
assert(patch->src->ID != (uint32_t)-1); 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); 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) static void writesection(struct Section const *sect, FILE *f)
{ {
putstring(sect->name, 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) static void writesymbol(struct Symbol const *sym, FILE *f)
{ {
putstring(sym->name, f); putstring(sym->name, f);
@@ -285,10 +263,8 @@ static void registerSymbol(struct Symbol *sym)
sym->ID = nbSymbols++; sym->ID = nbSymbols++;
} }
/* // Returns a symbol's ID within the object file
* Returns a symbol's ID within the object file // If the symbol does not have one, one is assigned by registering the symbol
* If the symbol does not have one, one is assigned by registering the symbol
*/
static uint32_t getSymbolID(struct Symbol *sym) static uint32_t getSymbolID(struct Symbol *sym)
{ {
if (sym->ID == (uint32_t)-1 && !sym_IsPC(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
* 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
* 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) static struct Patch *allocpatch(uint32_t type, struct Expression const *expr, uint32_t ofs)
{ {
struct Patch *patch = malloc(sizeof(struct Patch)); 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->pcSection = sect_GetSymbolSection();
patch->pcOffset = sect_GetSymbolOffset(); 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) { if (expr->isKnown) {
patch->rpnSize = rpnSize; 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[0] = RPN_CONST;
patch->rpn[1] = (uint32_t)(expr->val) & 0xFF; patch->rpn[1] = (uint32_t)(expr->val) & 0xFF;
patch->rpn[2] = (uint32_t)(expr->val) >> 8; 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; 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) void out_CreatePatch(uint32_t type, struct Expression const *expr, uint32_t ofs, uint32_t pcShift)
{ {
struct Patch *patch = allocpatch(type, expr, ofs); 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; 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, bool out_CreateAssert(enum AssertionType type, struct Expression const *expr,
char const *message, uint32_t ofs) 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; struct FileStackReptNode const *reptNode = (struct FileStackReptNode const *)node;
putlong(reptNode->reptDepth, f); 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--; ) for (uint32_t i = reptNode->reptDepth; i--; )
putlong(reptNode->iters[i], f); 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) void out_WriteObject(void)
{ {
FILE *f; FILE *f;
@@ -529,7 +497,7 @@ void out_WriteObject(void)
if (!f) if (!f)
err("Couldn't write file '%s'", objectName); 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); sym_ForEach(registerUnregisteredSymbol, NULL);
fprintf(f, RGBDS_OBJECT_VERSION_STRING); fprintf(f, RGBDS_OBJECT_VERSION_STRING);
@@ -569,9 +537,7 @@ void out_WriteObject(void)
fclose(f); fclose(f);
} }
/* // Set the objectfilename
* Set the objectfilename
*/
void out_SetFileName(char *s) void out_SetFileName(char *s)
{ {
objectName = s; objectName = s;

View File

@@ -36,7 +36,7 @@
#include "linkdefs.h" #include "linkdefs.h"
#include "platform.h" // strncasecmp, strdup #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) static void upperstring(char *dest, char const *src)
{ {
@@ -104,14 +104,14 @@ static size_t strlenUTF8(char const *s)
case 1: case 1:
errorInvalidUTF8Byte(byte, "STRLEN"); errorInvalidUTF8Byte(byte, "STRLEN");
state = 0; state = 0;
/* fallthrough */ // fallthrough
case 0: case 0:
len++; len++;
break; break;
} }
} }
/* Check for partial code point. */ // Check for partial code point.
if (state != 0) if (state != 0)
error("STRLEN: Incomplete UTF-8 character\n"); 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 curLen = 0;
uint32_t curPos = 1; uint32_t curPos = 1;
/* Advance to starting position in source string. */ // Advance to starting position in source string.
while (src[srcIndex] && curPos < pos) { while (src[srcIndex] && curPos < pos) {
switch (decode(&state, &codep, src[srcIndex])) { switch (decode(&state, &codep, src[srcIndex])) {
case 1: case 1:
errorInvalidUTF8Byte(src[srcIndex], "STRSUB"); errorInvalidUTF8Byte(src[srcIndex], "STRSUB");
state = 0; state = 0;
/* fallthrough */ // fallthrough
case 0: case 0:
curPos++; curPos++;
break; break;
@@ -141,21 +141,19 @@ static void strsubUTF8(char *dest, size_t destLen, char const *src, uint32_t pos
srcIndex++; srcIndex++;
} }
/* // A position 1 past the end of the string is allowed, but will trigger the
* 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.
* "Length too big" warning below if the length is nonzero.
*/
if (!src[srcIndex] && pos > curPos) if (!src[srcIndex] && pos > curPos)
warning(WARNING_BUILTIN_ARG, warning(WARNING_BUILTIN_ARG,
"STRSUB: Position %" PRIu32 " is past the end of the string\n", pos); "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) { while (src[srcIndex] && destIndex < destLen - 1 && curLen < len) {
switch (decode(&state, &codep, src[srcIndex])) { switch (decode(&state, &codep, src[srcIndex])) {
case 1: case 1:
errorInvalidUTF8Byte(src[srcIndex], "STRSUB"); errorInvalidUTF8Byte(src[srcIndex], "STRSUB");
state = 0; state = 0;
/* fallthrough */ // fallthrough
case 0: case 0:
curLen++; curLen++;
break; break;
@@ -166,7 +164,7 @@ static void strsubUTF8(char *dest, size_t destLen, char const *src, uint32_t pos
if (curLen < len) if (curLen < len)
warning(WARNING_BUILTIN_ARG, "STRSUB: Length too big: %" PRIu32 "\n", 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) if (state != 0)
error("STRSUB: Incomplete UTF-8 character\n"); 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; 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++) for (uint32_t curPos = 1; charLen && curPos < pos; curPos++)
charLen = charmap_ConvertNext(&src, NULL); charLen = charmap_ConvertNext(&src, NULL);
@@ -197,7 +195,7 @@ static void charsubUTF8(char *dest, char const *src, uint32_t pos)
warning(WARNING_BUILTIN_ARG, warning(WARNING_BUILTIN_ARG,
"CHARSUB: Position %" PRIu32 " is past the end of the string\n", pos); "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); memcpy(dest, start, src - start);
dest[src - start] = '\0'; 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) static uint32_t adjustNegativePos(int32_t pos, size_t len, char const *functionName)
{ {
/* // STRSUB and CHARSUB adjust negative `pos` arguments the same way,
* STRSUB and CHARSUB adjust negative `pos` arguments the same way, // such that position -1 is the last character of a string.
* such that position -1 is the last character of a string.
*/
if (pos < 0) if (pos < 0)
pos += len + 1; pos += len + 1;
if (pos < 1) { if (pos < 1) {
@@ -545,7 +541,7 @@ enum {
%left T_OP_SHL T_OP_SHR T_OP_USHR %left T_OP_SHL T_OP_SHR T_OP_USHR
%left T_OP_MUL T_OP_DIV T_OP_MOD %left T_OP_MUL T_OP_DIV T_OP_MOD
%precedence NEG /* negation -- unary minus */ %precedence NEG // negation -- unary minus
%token T_OP_EXP "**" %token T_OP_EXP "**"
%left T_OP_EXP %left T_OP_EXP
@@ -588,7 +584,6 @@ enum {
%type <symName> scoped_id %type <symName> scoped_id
%type <symName> scoped_anon_id %type <symName> scoped_anon_id
%token T_POP_EQU "EQU" %token T_POP_EQU "EQU"
%token T_POP_SET "SET"
%token T_POP_EQUAL "=" %token T_POP_EQUAL "="
%token T_POP_EQUS "EQUS" %token T_POP_EQUS "EQUS"
@@ -642,7 +637,7 @@ enum {
%type <forArgs> for_args %type <forArgs> for_args
%token T_Z80_ADC "adc" T_Z80_ADD "add" T_Z80_AND "and" %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_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_DAA "daa" T_Z80_DEC "dec" T_Z80_DI "di"
%token T_Z80_EI "ei" %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_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_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_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_SLA "sla" T_Z80_SRA "sra" T_Z80_SRL "srl" T_Z80_SUB "sub"
%token T_Z80_SWAP "swap" %token T_Z80_SWAP "swap"
%token T_Z80_XOR "xor" %token T_Z80_XOR "xor"
@@ -707,8 +702,8 @@ plain_directive : label
; ;
line : plain_directive endofline line : plain_directive endofline
| line_directive /* Directives that manage newlines themselves */ | line_directive // Directives that manage newlines themselves
/* Continue parsing the next line on a syntax error */ // Continue parsing the next line on a syntax error
| error { | error {
lexer_SetMode(LEXER_NORMAL); lexer_SetMode(LEXER_NORMAL);
lexer_ToggleStringExpansion(true); lexer_ToggleStringExpansion(true);
@@ -716,7 +711,7 @@ line : plain_directive endofline
fstk_StopRept(); fstk_StopRept();
yyerrok; yyerrok;
} }
/* Hint about unindented macros parsed as labels */ // Hint about unindented macros parsed as labels
| T_LABEL error { | T_LABEL error {
lexer_SetMode(LEXER_NORMAL); lexer_SetMode(LEXER_NORMAL);
lexer_ToggleStringExpansion(true); lexer_ToggleStringExpansion(true);
@@ -731,19 +726,17 @@ line : plain_directive endofline
} }
; ;
/* // For "logistical" reasons, these directives must manage newlines themselves.
* 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,
* 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).
* 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.
* This is DEFINITELY one of the more FRAGILE parts of the codebase, handle with care.
*/
line_directive : macrodef line_directive : macrodef
| rept | rept
| for | for
| break | break
| include | include
| if | 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 | elif
| else | 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_directive : equ
| assignment | assignment
| rb | rb
@@ -1300,7 +1293,7 @@ constlist_8bit_entry : reloc_8bit_no_str {
sect_RelByte(&$1, 0); sect_RelByte(&$1, 0);
} }
| string { | 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); size_t length = charmap_Convert($1, output);
sect_AbsByteGroup(output, length); sect_AbsByteGroup(output, length);
@@ -1316,7 +1309,7 @@ constlist_16bit_entry : reloc_16bit_no_str {
sect_RelWord(&$1, 0); sect_RelWord(&$1, 0);
} }
| string { | 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); size_t length = charmap_Convert($1, output);
sect_AbsWordGroup(output, length); sect_AbsWordGroup(output, length);
@@ -1681,7 +1674,7 @@ sectattrs : %empty {
$$.alignOfs = $7; $$.alignOfs = $7;
} }
| sectattrs T_COMMA T_OP_BANK T_LBRACK uconst T_RBRACK { | 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; $$.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_AbsByte(0x01 | (REG_DE << 4));
sect_RelWord(&$4, 1); sect_RelWord(&$4, 1);
} }
/* // HL is taken care of in z80_ld_hl
* HL is taken care of in z80_ld_hl // SP is taken care of in z80_ld_sp
* SP is taken care of in z80_ld_sp
*/
; ;
z80_nop : T_Z80_NOP { sect_AbsByte(0x00); } 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_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(0xCB);
sect_AbsByte(0xC0 | ($2 << 3) | $4); sect_AbsByte(0xC0 | ($2 << 3) | $4);
} }

View File

@@ -6,9 +6,7 @@
* SPDX-License-Identifier: MIT * SPDX-License-Identifier: MIT
*/ */
/* // Controls RPN expressions for objectfiles
* Controls RPN expressions for objectfiles
*/
#include <assert.h> #include <assert.h>
#include <errno.h> #include <errno.h>
@@ -28,7 +26,7 @@
#include "opmath.h" #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 { \ #define makeUnknown(expr_, ...) do { \
struct Expression *_expr = expr_; \ struct Expression *_expr = expr_; \
_expr->isKnown = false; \ _expr->isKnown = false; \
@@ -47,17 +45,15 @@
static uint8_t *reserveSpace(struct Expression *expr, uint32_t size) 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 (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) if (!expr->rpn)
expr->rpnCapacity = 256; /* Initial size */ expr->rpnCapacity = 256; // Initial size
while (expr->rpnCapacity - expr->rpnLength < size) { while (expr->rpnCapacity - expr->rpnLength < size) {
if (expr->rpnCapacity >= MAXRPNLEN) if (expr->rpnCapacity >= MAXRPNLEN)
/* // To avoid generating humongous object files, cap the
* To avoid generating humongous object files, cap the // size of RPN expressions
* size of RPN expressions
*/
fatalerror("RPN expression cannot grow larger than " fatalerror("RPN expression cannot grow larger than "
EXPAND_AND_STR(MAXRPNLEN) " bytes\n"); EXPAND_AND_STR(MAXRPNLEN) " bytes\n");
else if (expr->rpnCapacity > MAXRPNLEN / 2) else if (expr->rpnCapacity > MAXRPNLEN / 2)
@@ -77,9 +73,7 @@ static uint8_t *reserveSpace(struct Expression *expr, uint32_t size)
return ptr; return ptr;
} }
/* // Init a RPN expression
* Init a RPN expression
*/
static void rpn_Init(struct Expression *expr) static void rpn_Init(struct Expression *expr)
{ {
expr->reason = NULL; expr->reason = NULL;
@@ -91,9 +85,7 @@ static void rpn_Init(struct Expression *expr)
expr->rpnPatchSize = 0; expr->rpnPatchSize = 0;
} }
/* // Free the RPN expression
* Free the RPN expression
*/
void rpn_Free(struct Expression *expr) void rpn_Free(struct Expression *expr)
{ {
free(expr->rpn); free(expr->rpn);
@@ -101,9 +93,7 @@ void rpn_Free(struct Expression *expr)
rpn_Init(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) void rpn_Number(struct Expression *expr, uint32_t i)
{ {
rpn_Init(expr); 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" makeUnknown(expr, sym_IsPC(sym) ? "PC is not constant at assembly time"
: "'%s' is not constant at assembly time", symName); : "'%s' is not constant at assembly time", symName);
sym = sym_Ref(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); uint8_t *ptr = reserveSpace(expr, nameLen + 1);
*ptr++ = RPN_SYM; *ptr++ = RPN_SYM;
memcpy(ptr, sym->name, nameLen); 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); struct Symbol const *sym = sym_FindScopedSymbol(symName);
/* The @ symbol is treated differently. */ // The @ symbol is treated differently.
if (sym_IsPC(sym)) { if (sym_IsPC(sym)) {
rpn_BankSelf(expr); rpn_BankSelf(expr);
return; 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 assert(sym); // If the symbol didn't exist, it should have been created
if (sym_GetSection(sym) && sym_GetSection(sym)->bank != (uint32_t)-1) { if (sym_GetSection(sym) && 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; expr->val = sym_GetSection(sym)->bank;
} else { } else {
makeUnknown(expr, "\"%s\"'s bank is not known", symName); 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); uint8_t *ptr = reserveSpace(expr, nameLen + 1);
*ptr++ = RPN_BANK_SYM; *ptr++ = RPN_BANK_SYM;
memcpy(ptr, sym->name, nameLen); memcpy(ptr, sym->name, nameLen);
@@ -194,7 +184,7 @@ void rpn_BankSection(struct Expression *expr, char const *sectionName)
} else { } else {
makeUnknown(expr, "Section \"%s\"'s bank is not known", sectionName); 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); uint8_t *ptr = reserveSpace(expr, nameLen + 1);
expr->rpnPatchSize += nameLen + 1; expr->rpnPatchSize += nameLen + 1;
@@ -214,7 +204,7 @@ void rpn_SizeOfSection(struct Expression *expr, char const *sectionName)
} else { } else {
makeUnknown(expr, "Section \"%s\"'s size is not known", sectionName); 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); uint8_t *ptr = reserveSpace(expr, nameLen + 1);
expr->rpnPatchSize += nameLen + 1; expr->rpnPatchSize += nameLen + 1;
@@ -234,7 +224,7 @@ void rpn_StartOfSection(struct Expression *expr, char const *sectionName)
} else { } else {
makeUnknown(expr, "Section \"%s\"'s start is not known", sectionName); 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); uint8_t *ptr = reserveSpace(expr, nameLen + 1);
expr->rpnPatchSize += nameLen + 1; expr->rpnPatchSize += nameLen + 1;
@@ -252,7 +242,7 @@ void rpn_CheckHRAM(struct Expression *expr, const struct Expression *src)
expr->rpnPatchSize++; expr->rpnPatchSize++;
*reserveSpace(expr, 1) = RPN_HRAM; *reserveSpace(expr, 1) = RPN_HRAM;
} else if (expr->val >= 0xFF00 && expr->val <= 0xFFFF) { } else if (expr->val >= 0xFF00 && expr->val <= 0xFFFF) {
/* That range is valid, but only keep the lower byte */ // That range is valid, but only keep the lower byte
expr->val &= 0xFF; expr->val &= 0xFF;
} else if (expr->val < 0 || expr->val > 0xFF) { } else if (expr->val < 0 || expr->val > 0xFF) {
error("Source address $%" PRIx32 " not between $FF00 to $FFFF\n", expr->val); 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; *expr = *src;
if (rpn_isKnown(expr)) { 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) if (expr->val & ~0x38)
error("Invalid address $%" PRIx32 " for RST\n", expr->val); 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; expr->val |= 0xC7;
} else { } else {
expr->rpnPatchSize++; 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) void rpn_CheckNBit(struct Expression const *expr, uint8_t n)
{ {
assert(n != 0); // That doesn't make sense 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) 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); struct Symbol const *sym1 = rpn_SymbolOf(src);
if (!sym1 || !sym || sym1->type != SYM_LABEL || sym->type != SYM_LABEL) 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)); return rpn_IsDiffConstant(src1, rpn_SymbolOf(src2));
} }
/** /*
* Attempts to compute a constant binary AND from non-constant operands * Attempts to compute a constant binary AND from non-constant operands
* This is possible if one operand is a symbol belonging to an `ALIGN[N]` section, and the other is * This is possible if one operand is a symbol belonging to an `ALIGN[N]` section, and the other is
* a constant that only keeps (some of) the lower N bits. * 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; expr->isSymbol = false;
int32_t constMaskVal; int32_t constMaskVal;
/* First, check if the expression is known */ // First, check if the expression is known
expr->isKnown = src1->isKnown && src2->isKnown; expr->isKnown = src1->isKnown && src2->isKnown;
if (expr->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; uint32_t uleft = src1->val, uright = src2->val;
switch (op) { switch (op) {
@@ -537,9 +525,9 @@ void rpn_BinaryOp(enum RPNCommand op, struct Expression *expr,
expr->val = constMaskVal; expr->val = constMaskVal;
expr->isKnown = true; expr->isKnown = true;
} else { } 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) { if (src1->isKnown) {
uint32_t lval = src1->val; uint32_t lval = src1->val;
uint8_t bytes[] = {RPN_CONST, lval, lval >> 8, 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, memcpy(reserveSpace(expr, sizeof(bytes)), bytes,
sizeof(bytes)); sizeof(bytes));
/* Use the other expression's un-const reason */ // Use the other expression's un-const reason
expr->reason = src2->reason; expr->reason = src2->reason;
free(src1->reason); free(src1->reason);
} else { } else {
/* Otherwise just reuse its RPN buffer */ // Otherwise just reuse its RPN buffer
expr->rpnPatchSize = src1->rpnPatchSize; expr->rpnPatchSize = src1->rpnPatchSize;
expr->rpn = src1->rpn; expr->rpn = src1->rpn;
expr->rpnCapacity = src1->rpnCapacity; expr->rpnCapacity = src1->rpnCapacity;
@@ -564,12 +552,12 @@ void rpn_BinaryOp(enum RPNCommand op, struct Expression *expr,
free(src2->reason); free(src2->reason);
} }
/* Now, merge the right expression into the left one */ // Now, merge the right expression into the left one
uint8_t *ptr = src2->rpn; /* Pointer to the right RPN */ uint8_t *ptr = src2->rpn; // Pointer to the right RPN
uint32_t len = src2->rpnLength; /* Size of the right RPN */ uint32_t len = src2->rpnLength; // Size of the right RPN
uint32_t patchSize = src2->rpnPatchSize; 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; uint32_t rval = src2->val;
uint8_t bytes[] = {RPN_CONST, rval, rval >> 8, rval >> 16, uint8_t bytes[] = {RPN_CONST, rval, rval >> 8, rval >> 16,
rval >> 24}; rval >> 24};
@@ -578,13 +566,13 @@ void rpn_BinaryOp(enum RPNCommand op, struct Expression *expr,
len = sizeof(bytes); len = sizeof(bytes);
patchSize = 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); uint8_t *buf = reserveSpace(expr, len + 1);
memcpy(buf, ptr, len); memcpy(buf, ptr, len);
buf[len] = op; 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; expr->rpnPatchSize += patchSize + 1;
} }
} }

View File

@@ -1,3 +1,10 @@
/*
* This file is part of RGBDS.
*
* Copyright (c) 2022, RGBDS contributors.
*
* SPDX-License-Identifier: MIT
*/
#include <assert.h> #include <assert.h>
#include <errno.h> #include <errno.h>
@@ -30,7 +37,7 @@ struct UnionStackEntry {
struct SectionStackEntry { struct SectionStackEntry {
struct Section *section; struct Section *section;
struct Section *loadSection; struct Section *loadSection;
char const *scope; /* Section's symbol scope */ char const *scope; // Section's symbol scope
uint32_t offset; uint32_t offset;
int32_t loadOffset; int32_t loadOffset;
struct UnionStackEntry *unionStack; struct UnionStackEntry *unionStack;
@@ -38,14 +45,12 @@ struct SectionStackEntry {
}; };
struct SectionStackEntry *sectionStack; 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; struct Section *currentSection = NULL;
static struct Section *currentLoadSection = 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) attr_(warn_unused_result) static bool checksection(void)
{ {
if (currentSection) if (currentSection)
@@ -55,10 +60,8 @@ attr_(warn_unused_result) static bool checksection(void)
return false; return false;
} }
/* // A quick check to see if we have an initialized section that can contain
* A quick check to see if we have an initialized section that can contain // this much initialized data
* this much initialized data
*/
attr_(warn_unused_result) static bool checkcodesection(void) attr_(warn_unused_result) static bool checkcodesection(void)
{ {
if (!checksection()) if (!checksection())
@@ -85,17 +88,13 @@ attr_(warn_unused_result) static bool checkSectionSize(struct Section const *sec
return false; 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) 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
* 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
* prevent the assembler from generating huge object files or trying to allocate too much // memory.
* memory. // A check at the linking stage is still necessary.
* 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 the section has already overflowed, skip the check to avoid erroring out ad nauseam
if (currentSection->size != UINT32_MAX 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 assert(alignment < 16); // Should be ensured by the caller
unsigned int nbSectErrors = 0; unsigned int nbSectErrors = 0;
/* // Unionized sections only need "compatible" constraints, and they end up with the strictest
* Unionized sections only need "compatible" constraints, and they end up with the strictest // combination of both.
* combination of both.
*/
if (sect_HasData(type)) if (sect_HasData(type))
fail("Cannot declare ROM sections as UNION\n"); fail("Cannot declare ROM sections as UNION\n");
if (org != (uint32_t)-1) { 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) if (sect->org != (uint32_t)-1 && sect->org != org)
fail("Section already declared as fixed at different address $%04" fail("Section already declared as fixed at different address $%04"
PRIx32 "\n", sect->org); 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 %" fail("Section already declared as aligned to %u bytes (offset %"
PRIu16 ")\n", 1U << sect->align, sect->alignOfs); PRIu16 ")\n", 1U << sect->align, sect->alignOfs);
else else
/* Otherwise, just override */ // Otherwise, just override
sect->org = org; sect->org = org;
} else if (alignment != 0) { } 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 != (uint32_t)-1) {
if ((sect->org - alignOffset) & mask(alignment)) if ((sect->org - alignOffset) & mask(alignment))
fail("Section already declared as fixed at incompatible address $%04" fail("Section already declared as fixed at incompatible address $%04"
PRIx32 "\n", sect->org); PRIx32 "\n", sect->org);
/* Check if alignment offsets are compatible */ // Check if alignment offsets are compatible
} else if ((alignOffset & mask(sect->align)) } else if ((alignOffset & mask(sect->align))
!= (sect->alignOfs & mask(alignment))) { != (sect->alignOfs & mask(alignment))) {
fail("Section already declared with incompatible %u" 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 assert(alignment < 16); // Should be ensured by the caller
unsigned int nbSectErrors = 0; unsigned int nbSectErrors = 0;
/* // Fragments only need "compatible" constraints, and they end up with the strictest
* Fragments only need "compatible" constraints, and they end up with the strictest // combination of both.
* combination of both. // The merging is however performed at the *end* of the original section!
* The merging is however performed at the *end* of the original section!
*/
if (org != (uint32_t)-1) { if (org != (uint32_t)-1) {
uint16_t curOrg = org - sect->size; 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) if (sect->org != (uint32_t)-1 && sect->org != curOrg)
fail("Section already declared as fixed at incompatible address $%04" fail("Section already declared as fixed at incompatible address $%04"
PRIx32 " (cur addr = %04" PRIx32 ")\n", 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 %" fail("Section already declared as aligned to %u bytes (offset %"
PRIu16 ")\n", 1U << sect->align, sect->alignOfs); PRIu16 ")\n", 1U << sect->align, sect->alignOfs);
else else
/* Otherwise, just override */ // Otherwise, just override
sect->org = curOrg; sect->org = curOrg;
} else if (alignment != 0) { } else if (alignment != 0) {
@@ -207,12 +202,12 @@ static unsigned int mergeFragments(struct Section *sect, enum SectionType type,
if (curOfs < 0) if (curOfs < 0)
curOfs += 1U << alignment; 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 != (uint32_t)-1) {
if ((sect->org - curOfs) & mask(alignment)) if ((sect->org - curOfs) & mask(alignment))
fail("Section already declared as fixed at incompatible address $%04" fail("Section already declared as fixed at incompatible address $%04"
PRIx32 "\n", sect->org); 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))) { } else if ((curOfs & mask(sect->align)) != (sect->alignOfs & mask(alignment))) {
fail("Section already declared with incompatible %u" fail("Section already declared with incompatible %u"
"-byte alignment (offset %" PRIu16 ")\n", "-byte alignment (offset %" PRIu16 ")\n",
@@ -246,10 +241,10 @@ static void mergeSections(struct Section *sect, enum SectionType type, uint32_t
// Common checks // 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) if (sect->bank == (uint32_t)-1)
sect->bank = bank; 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) else if (bank != (uint32_t)-1 && sect->bank != bank)
fail("Section already declared with different bank %" PRIu32 "\n", fail("Section already declared with different bank %" PRIu32 "\n",
sect->bank); sect->bank);
@@ -270,9 +265,7 @@ static void mergeSections(struct Section *sect, enum SectionType type, uint32_t
#undef fail #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, static struct Section *createSection(char const *name, enum SectionType type,
uint32_t org, uint32_t bank, uint8_t alignment, uint32_t org, uint32_t bank, uint8_t alignment,
uint16_t alignOffset, enum SectionModifier mod) uint16_t alignOffset, enum SectionModifier mod)
@@ -298,7 +291,7 @@ static struct Section *createSection(char const *name, enum SectionType type,
sect->next = NULL; sect->next = NULL;
sect->patches = 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)) { if (sect_HasData(type)) {
sect->data = malloc(sectionTypeInfo[type].size); sect->data = malloc(sectionTypeInfo[type].size);
if (sect->data == NULL) if (sect->data == NULL)
@@ -310,9 +303,7 @@ static struct Section *createSection(char const *name, enum SectionType type,
return sect; 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, static struct Section *getSection(char const *name, enum SectionType type, uint32_t org,
struct SectionSpec const *attrs, enum SectionModifier mod) 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); error("Alignment must be between 0 and 16, not %u\n", alignment);
alignment = 16; 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); uint32_t mask = mask(alignment);
if (org != (uint32_t)-1) { if (org != (uint32_t)-1) {
if ((org - alignOffset) & mask) if ((org - alignOffset) & mask)
error("Section \"%s\"'s fixed address doesn't match its alignment\n", error("Section \"%s\"'s fixed address doesn't match its alignment\n",
name); name);
alignment = 0; /* Ignore it if it's satisfied */ alignment = 0; // Ignore it if it's satisfied
} else if (sectionTypeInfo[type].startAddr & mask) { } else if (sectionTypeInfo[type].startAddr & mask) {
error("Section \"%s\"'s alignment cannot be attained in %s\n", error("Section \"%s\"'s alignment cannot be attained in %s\n",
name, sectionTypeInfo[type].name); name, sectionTypeInfo[type].name);
alignment = 0; /* Ignore it if it's unattainable */ alignment = 0; // Ignore it if it's unattainable
org = 0; org = 0;
} else if (alignment == 16) { } else if (alignment == 16) {
// Treat an alignment of 16 as being fixed at address 0 // 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; return sect;
} }
/* // Set the current section
* Set the current section
*/
static void changeSection(void) static void changeSection(void)
{ {
if (unionStack) if (unionStack)
@@ -401,9 +390,7 @@ static void changeSection(void)
sym_SetCurrentSymbolScope(NULL); 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, void sect_NewSection(char const *name, uint32_t type, uint32_t org,
struct SectionSpec const *attribs, enum SectionModifier mod) 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; 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, void sect_SetLoadSection(char const *name, uint32_t type, uint32_t org,
struct SectionSpec const *attribs, enum SectionModifier mod) struct SectionSpec const *attribs, enum SectionModifier mod)
{ {
@@ -478,9 +463,7 @@ struct Section *sect_GetSymbolSection(void)
return currentLoadSection ? currentLoadSection : currentSection; return currentLoadSection ? currentLoadSection : currentSection;
} }
/* // The offset into the section above
* The offset into the section above
*/
uint32_t sect_GetSymbolOffset(void) uint32_t sect_GetSymbolOffset(void)
{ {
return curOffset; return curOffset;
@@ -615,9 +598,7 @@ void sect_CheckUnionClosed(void)
error("Unterminated UNION construct!\n"); error("Unterminated UNION construct!\n");
} }
/* // Output an absolute byte
* Output an absolute byte
*/
void sect_AbsByte(uint8_t b) void sect_AbsByte(uint8_t b)
{ {
if (!checkcodesection()) if (!checkcodesection())
@@ -661,9 +642,7 @@ void sect_AbsLongGroup(uint8_t const *s, size_t length)
writelong(*s++); writelong(*s++);
} }
/* // Skip this many bytes
* Skip this many bytes
*/
void sect_Skip(uint32_t skip, bool ds) void sect_Skip(uint32_t skip, bool ds)
{ {
if (!checksection()) 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) void sect_String(char const *s)
{ {
if (!checkcodesection()) if (!checkcodesection())
@@ -697,10 +674,8 @@ void sect_String(char const *s)
writebyte(*s++); writebyte(*s++);
} }
/* // Output a relocatable byte. Checking will be done to see if it
* Output a relocatable byte. Checking will be done to see if it // is an absolute value in disguise.
* is an absolute value in disguise.
*/
void sect_RelByte(struct Expression *expr, uint32_t pcShift) void sect_RelByte(struct Expression *expr, uint32_t pcShift)
{ {
if (!checkcodesection()) if (!checkcodesection())
@@ -717,10 +692,8 @@ void sect_RelByte(struct Expression *expr, uint32_t pcShift)
rpn_Free(expr); rpn_Free(expr);
} }
/* // Output several copies of a relocatable byte. Checking will be done to see if
* Output several copies of a relocatable byte. Checking will be done to see if // it is an absolute value in disguise.
* it is an absolute value in disguise.
*/
void sect_RelBytes(uint32_t n, struct Expression *exprs, size_t size) void sect_RelBytes(uint32_t n, struct Expression *exprs, size_t size)
{ {
if (!checkcodesection()) if (!checkcodesection())
@@ -743,10 +716,8 @@ void sect_RelBytes(uint32_t n, struct Expression *exprs, size_t size)
rpn_Free(&exprs[i]); rpn_Free(&exprs[i]);
} }
/* // Output a relocatable word. Checking will be done to see if
* Output a relocatable word. Checking will be done to see if // it's an absolute value in disguise.
* it's an absolute value in disguise.
*/
void sect_RelWord(struct Expression *expr, uint32_t pcShift) void sect_RelWord(struct Expression *expr, uint32_t pcShift)
{ {
if (!checkcodesection()) if (!checkcodesection())
@@ -763,10 +734,8 @@ void sect_RelWord(struct Expression *expr, uint32_t pcShift)
rpn_Free(expr); rpn_Free(expr);
} }
/* // Output a relocatable longword. Checking will be done to see if
* Output a relocatable longword. Checking will be done to see if // is an absolute value in disguise.
* is an absolute value in disguise.
*/
void sect_RelLong(struct Expression *expr, uint32_t pcShift) void sect_RelLong(struct Expression *expr, uint32_t pcShift)
{ {
if (!checkcodesection()) if (!checkcodesection())
@@ -783,10 +752,8 @@ void sect_RelLong(struct Expression *expr, uint32_t pcShift)
rpn_Free(expr); rpn_Free(expr);
} }
/* // Output a PC-relative relocatable byte. Checking will be done to see if it
* Output a PC-relative relocatable byte. Checking will be done to see if it // is an absolute value in disguise.
* is an absolute value in disguise.
*/
void sect_PCRelByte(struct Expression *expr, uint32_t pcShift) void sect_PCRelByte(struct Expression *expr, uint32_t pcShift)
{ {
if (!checkcodesection()) if (!checkcodesection())
@@ -800,12 +767,12 @@ void sect_PCRelByte(struct Expression *expr, uint32_t pcShift)
writebyte(0); writebyte(0);
} else { } else {
struct Symbol const *sym = rpn_SymbolOf(expr); 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; int16_t offset;
/* Offset is relative to the byte *after* the operand */ // Offset is relative to the byte *after* the operand
if (sym == pc) if (sym == pc)
offset = -2; /* PC as operand to `jr` is lower than reference PC by 2 */ offset = -2; // PC as operand to `jr` is lower than reference PC by 2
else else
offset = sym_GetValue(sym) - (sym_GetValue(pc) + 1); offset = sym_GetValue(sym) - (sym_GetValue(pc) + 1);
@@ -820,9 +787,7 @@ void sect_PCRelByte(struct Expression *expr, uint32_t pcShift)
rpn_Free(expr); rpn_Free(expr);
} }
/* // Output a binary file
* Output a binary file
*/
void sect_BinaryFile(char const *s, int32_t startPos) void sect_BinaryFile(char const *s, int32_t startPos)
{ {
if (startPos < 0) { if (startPos < 0) {
@@ -869,7 +834,7 @@ void sect_BinaryFile(char const *s, int32_t startPos)
if (errno != ESPIPE) if (errno != ESPIPE)
error("Error determining size of INCBIN file '%s': %s\n", error("Error determining size of INCBIN file '%s': %s\n",
s, strerror(errno)); 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--) while (startPos--)
(void)fgetc(f); (void)fgetc(f);
} }
@@ -901,7 +866,7 @@ void sect_BinaryFileSlice(char const *s, int32_t start_pos, int32_t length)
if (!checkcodesection()) if (!checkcodesection())
return; return;
if (length == 0) /* Don't even bother with 0-byte slices */ if (length == 0) // Don't even bother with 0-byte slices
return; return;
if (!reserveSpace(length)) if (!reserveSpace(length))
return; return;
@@ -946,7 +911,7 @@ void sect_BinaryFileSlice(char const *s, int32_t start_pos, int32_t length)
if (errno != ESPIPE) if (errno != ESPIPE)
error("Error determining size of INCBIN file '%s': %s\n", error("Error determining size of INCBIN file '%s': %s\n",
s, strerror(errno)); 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--) while (start_pos--)
(void)fgetc(f); (void)fgetc(f);
} }
@@ -968,9 +933,7 @@ cleanup:
fclose(f); fclose(f);
} }
/* // Section stack routines
* Section stack routines
*/
void sect_PushSection(void) void sect_PushSection(void)
{ {
struct SectionStackEntry *entry = malloc(sizeof(*entry)); struct SectionStackEntry *entry = malloc(sizeof(*entry));

View File

@@ -6,9 +6,7 @@
* SPDX-License-Identifier: MIT * SPDX-License-Identifier: MIT
*/ */
/* // Symboltable and macroargs stuff
* Symboltable and macroargs stuff
*/
#include <assert.h> #include <assert.h>
#include <errno.h> #include <errno.h>
@@ -36,7 +34,7 @@
HashMap symbols; 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 struct Symbol *PCSymbol;
static char savedTIME[256]; static char savedTIME[256];
static char savedDATE[256]; static char savedDATE[256];
@@ -85,36 +83,34 @@ static int32_t Callback__LINE__(void)
static char const *Callback__FILE__(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.
* 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
* 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.
* EQUS expansions, which cannot straddle file boundaries. So this should be fine.
*/
static char *buf = NULL; static char *buf = NULL;
static size_t bufsize = 0; static size_t bufsize = 0;
char const *fileName = fstk_GetFileName(); char const *fileName = fstk_GetFileName();
size_t j = 1; size_t j = 1;
assert(fileName[0]); 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++) { 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] == '"') if (fileName[i] == '"')
j++; j++;
/* Ensure there will be enough room; DO NOT PRINT ANYTHING ABOVE THIS!! */ // Ensure there will be enough room; DO NOT PRINT ANYTHING ABOVE THIS!!
if (j + 2 >= bufsize) { /* Always keep room for 2 tail chars */ if (j + 2 >= bufsize) { // Always keep room for 2 tail chars
bufsize = bufsize ? bufsize * 2 : 64; bufsize = bufsize ? bufsize * 2 : 64;
buf = realloc(buf, bufsize); buf = realloc(buf, bufsize);
if (!buf) if (!buf)
fatalerror("Failed to grow buffer for file name: %s\n", fatalerror("Failed to grow buffer for file name: %s\n",
strerror(errno)); strerror(errno));
} }
/* Escape quotes, since we're returning a string */ // Escape quotes, since we're returning a string
if (fileName[i] == '"') if (fileName[i] == '"')
buf[j - 1] = '\\'; buf[j - 1] = '\\';
buf[j] = fileName[i]; 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[0] = '"';
buf[j++] = '"'; buf[j++] = '"';
buf[j] = '\0'; buf[j] = '\0';
@@ -128,16 +124,14 @@ static int32_t CallbackPC(void)
return section ? section->org + sect_GetSymbolOffset() : 0; 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) int32_t sym_GetValue(struct Symbol const *sym)
{ {
if (sym_IsNumeric(sym) && sym->hasCallback) if (sym_IsNumeric(sym) && sym->hasCallback)
return sym->numCallback(); return sym->numCallback();
if (sym->type == SYM_LABEL) 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 + sym_GetSection(sym)->org;
return sym->value; return sym->value;
@@ -153,32 +147,26 @@ static void dumpFilename(struct Symbol const *sym)
fputs("<builtin>", stderr); 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) static void setSymbolFilename(struct Symbol *sym)
{ {
sym->src = fstk_GetFileStack(); sym->src = fstk_GetFileStack();
sym->fileLine = sym->src ? lexer_GetLineNo() : 0; // This is (NULL, 1) for built-ins 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) static void updateSymbolFilename(struct Symbol *sym)
{ {
struct FileStackNode *oldSrc = sym->src; struct FileStackNode *oldSrc = sym->src;
setSymbolFilename(sym); 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) if (oldSrc && oldSrc->referenced && oldSrc->ID != (uint32_t)-1)
out_RegisterNode(sym->src); 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) static struct Symbol *createsymbol(char const *symName)
{ {
struct Symbol *sym = malloc(sizeof(*sym)); struct Symbol *sym = malloc(sizeof(*sym));
@@ -201,10 +189,8 @@ static struct Symbol *createsymbol(char const *symName)
return sym; return sym;
} }
/* // Creates the full name of a local symbol in a given scope, by prepending
* Creates the full name of a local symbol in a given scope, by prepending // the name with the parent symbol's name.
* the name with the parent symbol's name.
*/
static void fullSymbolName(char *output, size_t outputSize, static void fullSymbolName(char *output, size_t outputSize,
char const *localName, char const *scopeName) char const *localName, char const *scopeName)
{ {
@@ -250,8 +236,8 @@ struct Symbol *sym_FindScopedSymbol(char const *symName)
if (strchr(localName + 1, '.')) if (strchr(localName + 1, '.'))
fatalerror("'%s' is a nonsensical reference to a nested local symbol\n", fatalerror("'%s' is a nonsensical reference to a nested local symbol\n",
symName); symName);
/* If auto-scoped local label, expand the name */ // If auto-scoped local label, expand the name
if (localName == symName) { /* Meaning, the name begins with the dot */ if (localName == symName) { // Meaning, the name begins with the dot
char fullName[MAXSYMLEN + 1]; char fullName[MAXSYMLEN + 1];
fullSymbolName(fullName, sizeof(fullName), symName, labelScope); fullSymbolName(fullName, sizeof(fullName), symName, labelScope);
@@ -271,9 +257,7 @@ static bool isReferenced(struct Symbol const *sym)
return sym->ID != (uint32_t)-1; return sym->ID != (uint32_t)-1;
} }
/* // Purge a symbol
* Purge a symbol
*/
void sym_Purge(char const *symName) void sym_Purge(char const *symName)
{ {
struct Symbol *sym = sym_FindScopedSymbol(symName); struct Symbol *sym = sym_FindScopedSymbol(symName);
@@ -285,16 +269,14 @@ void sym_Purge(char const *symName)
} else if (isReferenced(sym)) { } else if (isReferenced(sym)) {
error("Symbol \"%s\" is referenced and thus cannot be purged\n", symName); error("Symbol \"%s\" is referenced and thus cannot be purged\n", symName);
} else { } 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) if (sym->name == labelScope)
sym_SetCurrentSymbolScope(NULL); sym_SetCurrentSymbolScope(NULL);
/* // FIXME: this leaks sym->macro for SYM_EQUS and SYM_MACRO, but this can't
* 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.
* free(sym->macro) because the expansion may be purging itself.
*/
hash_RemoveElement(symbols, sym->name); hash_RemoveElement(symbols, sym->name);
/* TODO: ideally, also unref the file stack nodes */ // TODO: ideally, also unref the file stack nodes
free(sym); free(sym);
} }
} }
@@ -312,9 +294,7 @@ uint32_t sym_GetPCValue(void)
return 0; 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) uint32_t sym_GetConstantSymValue(struct Symbol const *sym)
{ {
if (sym == PCSymbol) if (sym == PCSymbol)
@@ -327,9 +307,7 @@ uint32_t sym_GetConstantSymValue(struct Symbol const *sym)
return 0; return 0;
} }
/* // Return a constant symbol's value
* Return a constant symbol's value
*/
uint32_t sym_GetConstantValue(char const *symName) uint32_t sym_GetConstantValue(char const *symName)
{ {
struct Symbol const *sym = sym_FindScopedSymbol(symName); struct Symbol const *sym = sym_FindScopedSymbol(symName);
@@ -381,9 +359,7 @@ static struct Symbol *createNonrelocSymbol(char const *symName, bool numeric)
return sym; return sym;
} }
/* // Add an equated symbol
* Add an equated symbol
*/
struct Symbol *sym_AddEqu(char const *symName, int32_t value) struct Symbol *sym_AddEqu(char const *symName, int32_t value)
{ {
struct Symbol *sym = createNonrelocSymbol(symName, true); struct Symbol *sym = createNonrelocSymbol(symName, true);
@@ -465,18 +441,14 @@ struct Symbol *sym_RedefString(char const *symName, char const *value)
} }
updateSymbolFilename(sym); updateSymbolFilename(sym);
/* // FIXME: this leaks the previous sym->macro value, but this can't
* FIXME: this leaks the previous sym->macro value, but this can't // free(sym->macro) because the expansion may be redefining itself.
* free(sym->macro) because the expansion may be redefining itself.
*/
assignStringSymbol(sym, value); assignStringSymbol(sym, value);
return sym; 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_AddVar(char const *symName, int32_t value)
{ {
struct Symbol *sym = sym_FindExactSymbol(symName); 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) 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); struct Symbol *sym = sym_FindExactSymbol(symName);
if (!sym) { if (!sym) {
@@ -519,7 +491,7 @@ static struct Symbol *addLabel(char const *symName)
} else { } else {
updateSymbolFilename(sym); 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->type = SYM_LABEL;
sym->value = sect_GetSymbolOffset(); sym->value = sect_GetSymbolOffset();
if (exportall) if (exportall)
@@ -531,43 +503,41 @@ static struct Symbol *addLabel(char const *symName)
return sym; 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) struct Symbol *sym_AddLocalLabel(char const *symName)
{ {
if (!labelScope) { if (!labelScope) {
error("Local label '%s' in main scope\n", symName); error("Local label '%s' in main scope\n", symName);
return NULL; return NULL;
} }
assert(!strchr(labelScope, '.')); /* Assuming no dots in `labelScope` */ assert(!strchr(labelScope, '.')); // Assuming no dots in `labelScope`
char fullName[MAXSYMLEN + 1]; char fullName[MAXSYMLEN + 1];
char const *localName = strchr(symName, '.'); char const *localName = strchr(symName, '.');
assert(localName); /* There should be at least one dot in `symName` */ assert(localName); // There should be at least one dot in `symName`
/* Check for something after the dot in `localName` */ // Check for something after the dot in `localName`
if (localName[1] == '\0') { if (localName[1] == '\0') {
fatalerror("'%s' is a nonsensical reference to an empty local label\n", fatalerror("'%s' is a nonsensical reference to an empty local label\n",
symName); symName);
} }
/* Check for more than one dot in `localName` */ // Check for more than one dot in `localName`
if (strchr(localName + 1, '.')) if (strchr(localName + 1, '.'))
fatalerror("'%s' is a nonsensical reference to a nested local label\n", fatalerror("'%s' is a nonsensical reference to a nested local label\n",
symName); symName);
if (localName == 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); fullSymbolName(fullName, sizeof(fullName), symName, labelScope);
symName = fullName; symName = fullName;
} else { } else {
size_t i = 0; 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]) while (labelScope[i] && symName[i] == labelScope[i])
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] != '.') { if (labelScope[i] != '\0' || symName[i] != '.') {
size_t parentLen = localName - symName; size_t parentLen = localName - symName;
@@ -579,14 +549,12 @@ struct Symbol *sym_AddLocalLabel(char const *symName)
return addLabel(symName); return addLabel(symName);
} }
/* // Add a relocatable symbol
* Add a relocatable symbol
*/
struct Symbol *sym_AddLabel(char const *symName) struct Symbol *sym_AddLabel(char const *symName)
{ {
struct Symbol *sym = addLabel(symName); struct Symbol *sym = addLabel(symName);
/* Set the symbol as the new scope */ // Set the symbol as the new scope
if (sym) if (sym)
sym_SetCurrentSymbolScope(sym->name); sym_SetCurrentSymbolScope(sym->name);
return sym; return sym;
@@ -594,9 +562,7 @@ struct Symbol *sym_AddLabel(char const *symName)
static uint32_t anonLabelID; static uint32_t anonLabelID;
/* // Add an anonymous label
* Add an anonymous label
*/
struct Symbol *sym_AddAnonLabel(void) struct Symbol *sym_AddAnonLabel(void)
{ {
if (anonLabelID == UINT32_MAX) { if (anonLabelID == UINT32_MAX) {
@@ -610,9 +576,7 @@ struct Symbol *sym_AddAnonLabel(void)
return addLabel(name); 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) void sym_WriteAnonLabelName(char buf[MIN_NB_ELMS(MAXSYMLEN + 1)], uint32_t ofs, bool neg)
{ {
uint32_t id = 0; 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); sprintf(buf, "!%u", id);
} }
/* // Export a symbol
* Export a symbol
*/
void sym_Export(char const *symName) void sym_Export(char const *symName)
{ {
if (symName[0] == '!') { if (symName[0] == '!') {
@@ -648,15 +610,13 @@ void sym_Export(char const *symName)
struct Symbol *sym = sym_FindScopedSymbol(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) if (!sym)
sym = sym_Ref(symName); sym = sym_Ref(symName);
sym->isExported = true; 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_AddMacro(char const *symName, int32_t defLineNo, char *body, size_t size)
{ {
struct Symbol *sym = createNonrelocSymbol(symName, false); 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->type = SYM_MACRO;
sym->macroSize = size; sym->macroSize = size;
sym->macro = body; sym->macro = body;
setSymbolFilename(sym); /* TODO: is this really necessary? */ setSymbolFilename(sym); // TODO: is this really necessary?
/* // The symbol is created at the line after the `endm`,
* The symbol is created at the line after the `endm`, // override this with the actual definition line
* override this with the actual definition line
*/
sym->fileLine = defLineNo; sym->fileLine = defLineNo;
return sym; return sym;
} }
/* // Flag that a symbol is referenced in an RPN expression
* Flag that a symbol is referenced in an RPN expression // and create it if it doesn't exist yet
* and create it if it doesn't exist yet
*/
struct Symbol *sym_Ref(char const *symName) struct Symbol *sym_Ref(char const *symName)
{ {
struct Symbol *sym = sym_FindScopedSymbol(symName); struct Symbol *sym = sym_FindScopedSymbol(symName);
@@ -702,9 +658,7 @@ struct Symbol *sym_Ref(char const *symName)
return sym; 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) void sym_SetExportAll(bool set)
{ {
exportall = set; exportall = set;
@@ -721,9 +675,7 @@ static struct Symbol *createBuiltinSymbol(char const *symName)
return sym; return sym;
} }
/* // Initialize the symboltable
* Initialize the symboltable
*/
void sym_Init(time_t now) void sym_Init(time_t now)
{ {
PCSymbol = createBuiltinSymbol("@"); PCSymbol = createBuiltinSymbol("@");
@@ -761,7 +713,7 @@ void sym_Init(time_t now)
if (now == (time_t)-1) { if (now == (time_t)-1) {
warn("Couldn't determine current time"); 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; now = 0;
} }

View File

@@ -44,7 +44,7 @@ char const *printChar(int c)
buf[2] = 't'; buf[2] = 't';
break; break;
default: /* Print as hex */ default: // Print as hex
buf[0] = '0'; buf[0] = '0';
buf[1] = 'x'; buf[1] = 'x';
snprintf(&buf[2], 3, "%02hhX", (uint8_t)c); // includes the '\0' snprintf(&buf[2], 3, "%02hhX", (uint8_t)c); // includes the '\0'

View File

@@ -49,19 +49,19 @@ static const enum WarningState defaultWarnings[ARRAY_SIZE(warningStates)] = {
enum WarningState warningStates[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) static enum WarningState warningState(enum WarningID id)
{ {
/* Check if warnings are globally disabled */ // Check if warnings are globally disabled
if (!warnings) if (!warnings)
return WARNING_DISABLED; return WARNING_DISABLED;
/* Get the actual state */ // Get the actual state
enum WarningState state = warningStates[id]; enum WarningState state = warningStates[id];
if (state == WARNING_DEFAULT) 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]; state = defaultWarnings[id];
if (warningsAreErrors && state == WARNING_ENABLED) if (warningsAreErrors && state == WARNING_ENABLED)
@@ -95,10 +95,10 @@ static const char * const warningFlags[NB_WARNINGS] = {
"truncation", "truncation",
"truncation", "truncation",
/* Meta warnings */ // Meta warnings
"all", "all",
"extra", "extra",
"everything", /* Especially useful for testing */ "everything", // Especially useful for testing
}; };
static const struct { static const struct {
@@ -151,7 +151,7 @@ enum MetaWarningCommand {
META_WARNING_DONE = NB_WARNINGS META_WARNING_DONE = NB_WARNINGS
}; };
/* Warnings that probably indicate an error */ // Warnings that probably indicate an error
static uint8_t const _wallCommands[] = { static uint8_t const _wallCommands[] = {
WARNING_BACKWARDS_FOR, WARNING_BACKWARDS_FOR,
WARNING_BUILTIN_ARG, WARNING_BUILTIN_ARG,
@@ -167,7 +167,7 @@ static uint8_t const _wallCommands[] = {
META_WARNING_DONE 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[] = { static uint8_t const _wextraCommands[] = {
WARNING_EMPTY_MACRO_ARG, WARNING_EMPTY_MACRO_ARG,
WARNING_MACRO_SHIFT, WARNING_MACRO_SHIFT,
@@ -179,7 +179,7 @@ static uint8_t const _wextraCommands[] = {
META_WARNING_DONE META_WARNING_DONE
}; };
/* Literally everything. Notably useful for testing */ // Literally everything. Notably useful for testing
static uint8_t const _weverythingCommands[] = { static uint8_t const _weverythingCommands[] = {
WARNING_BACKWARDS_FOR, WARNING_BACKWARDS_FOR,
WARNING_BUILTIN_ARG, WARNING_BUILTIN_ARG,
@@ -199,7 +199,7 @@ static uint8_t const _weverythingCommands[] = {
WARNING_NUMERIC_STRING_2, WARNING_NUMERIC_STRING_2,
WARNING_TRUNCATION_1, WARNING_TRUNCATION_1,
WARNING_TRUNCATION_2, WARNING_TRUNCATION_2,
/* WARNING_USER, */ // WARNING_USER,
META_WARNING_DONE META_WARNING_DONE
}; };
@@ -213,18 +213,18 @@ void processWarningFlag(char *flag)
{ {
static bool setError = false; 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++) { 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])) { if (!strcmp(flag, warningFlags[id])) {
/* We got a match! */ // We got a match!
if (setError) if (setError)
errx("Cannot make meta warning \"%s\" into an error", errx("Cannot make meta warning \"%s\" into an error",
flag); flag);
for (uint8_t const *ptr = metaWarningCommands[id - META_WARNINGS_START]; for (uint8_t const *ptr = metaWarningCommands[id - META_WARNINGS_START];
*ptr != META_WARNING_DONE; ptr++) { *ptr != META_WARNING_DONE; ptr++) {
/* Warning flag, set without override */ // Warning flag, set without override
if (warningStates[*ptr] == WARNING_DEFAULT) if (warningStates[*ptr] == WARNING_DEFAULT)
warningStates[*ptr] = WARNING_ENABLED; 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"))) { if (!strncmp(flag, "error", strlen("error"))) {
char *errorFlag = flag + strlen("error"); char *errorFlag = flag + strlen("error");
switch (*errorFlag) { switch (*errorFlag) {
case '\0': case '\0':
/* `-Werror` */ // `-Werror`
warningsAreErrors = true; warningsAreErrors = true;
return; return;
case '=': case '=':
/* `-Werror=XXX` */ // `-Werror=XXX`
setError = true; setError = true;
processWarningFlag(errorFlag + 1); /* Skip the `=` */ processWarningFlag(errorFlag + 1); // Skip the `=`
setError = false; setError = false;
return; 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 : 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 strncmp(flag, "no-", strlen("no-")) ? WARNING_ENABLED
: WARNING_DISABLED; : WARNING_DISABLED;
char const *rootFlag = state == WARNING_DISABLED ? flag + strlen("no-") : flag; 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++) { for (enum WarningID id = 0; id < NB_PLAIN_WARNINGS; id++) {
if (!strcmp(rootFlag, warningFlags[id])) { if (!strcmp(rootFlag, warningFlags[id])) {
/* We got a match! */ // We got a match!
warningStates[id] = state; warningStates[id] = state;
return; return;
} }
@@ -374,7 +374,7 @@ void warning(enum WarningID id, char const *fmt, ...)
case WARNING_DEFAULT: case WARNING_DEFAULT:
unreachable_(); unreachable_();
/* Not reached */ // Not reached
case WARNING_ENABLED: case WARNING_ENABLED:
break; break;

View File

@@ -29,7 +29,7 @@
#define BANK_SIZE 0x4000 #define BANK_SIZE 0x4000
/* Short options */ // Short options
static const char *optstring = "Ccf:i:jk:l:m:n:Op:r:st:Vv"; 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]; static uint8_t tpp1Rev[2];
/** /*
* @return False on failure * @return False on failure
*/ */
static bool readMBCSlice(char const **name, char const *expected) 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; return total;
} }
/** /*
* @param rom0 A pointer to rom0 * @param rom0 A pointer to rom0
* @param addr What address to check * @param addr What address to check
* @param fixedByte The fixed byte at the address * @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; rom0[addr] = fixedByte;
} }
/** /*
* @param rom0 A pointer to rom0 * @param rom0 A pointer to rom0
* @param startAddr What address to begin checking from * @param startAddr What address to begin checking from
* @param fixed The fixed bytes at the address * @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); memcpy(&rom0[startAddr], fixed, size);
} }
/** /*
* @param input File descriptor to be used for reading * @param input File descriptor to be used for reading
* @param output File descriptor to be used for writing, may be equal to `input` * @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 * @param name The file's name, to be displayed for error output

View File

@@ -153,7 +153,7 @@ static void printUsage(void) {
exit(1); exit(1);
} }
/** /*
* Parses a number at the beginning of a string, moving the pointer to skip the parsed characters * Parses a number at the beginning of a string, moving the pointer to skip the parsed characters
* Returns the provided errVal on error * 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. * 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. * 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 * 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 * 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. * @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 } while (c != '\n' && c != EOF); // End if we reached EOL
} }
} }
/** /*
* Parses an arg vector, modifying `options` as options are read. * 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 * The three booleans are for the "auto path" flags, since their processing must be deferred to the
* end of option parsing. * 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 * 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 { uint8_t Palette::indexOf(uint16_t color) const {

View File

@@ -39,12 +39,12 @@ namespace packing {
// Tile | Proto-palette // Tile | Proto-palette
// Page | Palette // Page | Palette
/** /*
* A reference to a proto-palette, and attached attributes for sorting purposes * A reference to a proto-palette, and attached attributes for sorting purposes
*/ */
struct ProtoPalAttrs { struct ProtoPalAttrs {
size_t const protoPalIndex; size_t const protoPalIndex;
/** /*
* Pages from which we are banned (to prevent infinite loops) * Pages from which we are banned (to prevent infinite loops)
* This is dynamic because we wish not to hard-cap the amount of palettes * 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 * 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 * 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()}; } const_iterator end() const { return const_iterator{&_assigned, _assigned.end()}; }
/** /*
* Assigns a new ProtoPalAttrs in a free slot, assuming there is one * Assigns a new ProtoPalAttrs in a free slot, assuming there is one
* Args are passed to the `ProtoPalAttrs`'s constructor * Args are passed to the `ProtoPalAttrs`'s constructor
*/ */
@@ -198,7 +198,7 @@ private:
return colors; return colors;
} }
public: public:
/** /*
* Returns the number of distinct colors * Returns the number of distinct colors
*/ */
size_t volume() const { return uniqueColors().size(); } size_t volume() const { return uniqueColors().size(); }
@@ -208,7 +208,7 @@ public:
return colors.size() <= options.maxOpaqueColors(); return colors.size() <= options.maxOpaqueColors();
} }
/** /*
* Computes the "relative size" of a proto-palette on this palette * Computes the "relative size" of a proto-palette on this palette
*/ */
double relSizeOf(ProtoPalette const &protoPal) const { double relSizeOf(ProtoPalette const &protoPal) const {
@@ -227,7 +227,7 @@ public:
return relSize; return relSize;
} }
/** /*
* Computes the "relative size" of a set of proto-palettes on this palette * Computes the "relative size" of a set of proto-palettes on this palette
*/ */
template<typename Iter> template<typename Iter>
@@ -237,7 +237,7 @@ public:
addUniqueColors(colors, std::forward<Iter>(begin), end, protoPals); addUniqueColors(colors, std::forward<Iter>(begin), end, protoPals);
return colors.size(); return colors.size();
} }
/** /*
* Computes the "relative size" of a set of colors on this palette * Computes the "relative size" of a set of colors on this palette
*/ */
template<typename Iter> template<typename Iter>

View File

@@ -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" #include "gfx/pal_sorting.hpp"

View File

@@ -165,7 +165,7 @@ void parseInlinePalSpec(char const * const rawArg) {
} }
} }
/** /*
* Tries to read some magic bytes from the provided `file`. * Tries to read some magic bytes from the provided `file`.
* Returns whether the magic was correctly read. * Returns whether the magic was correctly read.
*/ */
@@ -191,7 +191,7 @@ static T readBE(U const *bytes) {
return val; return val;
} }
/** /*
* **Appends** the first line read from `file` to the end of the provided `buffer`. * **Appends** the first line read from `file` to the end of the provided `buffer`.
*/ */
static void readLine(std::filebuf &file, std::string &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 // 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 * 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) { static uint16_t parseDec(std::string const &str, std::string::size_type &n) {

View File

@@ -42,7 +42,7 @@ class ImagePalette {
public: public:
ImagePalette() = default; ImagePalette() = default;
/** /*
* Registers a color in the palette. * Registers a color in the palette.
* If the newly inserted color "conflicts" with another one (different color, but same CGB * 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. * color), then the other color is returned. Otherwise, `nullptr` is returned.
@@ -164,7 +164,7 @@ public:
return true; return true;
} }
/** /*
* Reads a PNG and notes all of its colors * Reads a PNG and notes all of its colors
* *
* This code is more complicated than strictly necessary, but that's because of the API * This code is more complicated than strictly necessary, but that's because of the API
@@ -466,7 +466,7 @@ public:
}; };
class RawTiles { class RawTiles {
/** /*
* A tile which only contains indices into the image's global palette * A tile which only contains indices into the image's global palette
*/ */
class RawTile { class RawTile {
@@ -481,7 +481,7 @@ private:
std::vector<RawTile> _tiles; std::vector<RawTile> _tiles;
public: public:
/** /*
* Creates a new raw tile, and returns a reference to it so it can be filled in * Creates a new raw tile, and returns a reference to it so it can be filled in
*/ */
RawTile &newTile() { RawTile &newTile() {
@@ -491,7 +491,7 @@ public:
}; };
struct AttrmapEntry { struct AttrmapEntry {
/** /*
* This field can either be a proto-palette ID, or `transparent` to indicate that the * 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 * 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`. * attrmap entry while correctly handling the above, use `getPalID`.
@@ -831,7 +831,7 @@ struct UniqueTiles {
UniqueTiles(UniqueTiles const &) = delete; UniqueTiles(UniqueTiles const &) = delete;
UniqueTiles(UniqueTiles &&) = default; UniqueTiles(UniqueTiles &&) = default;
/** /*
* Adds a tile to the collection, and returns its ID * Adds a tile to the collection, and returns its ID
*/ */
std::tuple<uint16_t, TileData::MatchType> addTile(Png::TilesVisitor::Tile const &tile, std::tuple<uint16_t, TileData::MatchType> addTile(Png::TilesVisitor::Tile const &tile,
@@ -857,7 +857,7 @@ struct UniqueTiles {
auto end() const { return tiles.end(); } auto end() const { return tiles.end(); }
}; };
/** /*
* Generate tile data while deduplicating unique tiles (via mirroring if enabled) * 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 * 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 * 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 protoPalettes[n] = tileColors; // Override them
// Remove any other proto-palettes that we encompass // Remove any other proto-palettes that we encompass
// (Example [(0, 1), (0, 2)], inserting (0, 1, 2)) // (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. * proto-palettes are not updated, causing issues.
* TODO: overlap might not be detrimental to the packing algorithm. * TODO: overlap might not be detrimental to the packing algorithm.
* Investigation is necessary, especially if pathological cases are found. * Investigation is necessary, especially if pathological cases are found.
*
for (size_t i = protoPalettes.size(); --i != n;) { * for (size_t i = protoPalettes.size(); --i != n;) {
if (tileColors.compare(protoPalettes[i]) == ProtoPalette::WE_BIGGER) { * if (tileColors.compare(protoPalettes[i]) == ProtoPalette::WE_BIGGER) {
protoPalettes.erase(protoPalettes.begin() + i); * protoPalettes.erase(protoPalettes.begin() + i);
} * }
} * }
*/ */
[[fallthrough]]; [[fallthrough]];

View File

@@ -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 "gfx/rgba.hpp"
#include <assert.h> #include <assert.h>

View File

@@ -15,10 +15,8 @@
#include "error.h" #include "error.h"
#include "hashmap.h" #include "hashmap.h"
/* // The lower half of the hash is used to index the "master" table,
* 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 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##NB_BITS##_t
#define UINT_BITS(NB_BITS) UINT_BITS_(NB_BITS) #define UINT_BITS(NB_BITS) UINT_BITS_(NB_BITS)
typedef UINT_BITS(HASH_NB_BITS) HashType; typedef UINT_BITS(HASH_NB_BITS) HashType;
@@ -34,7 +32,7 @@ struct HashMapEntry {
#define FNV_OFFSET_BASIS 0x811c9dc5 #define FNV_OFFSET_BASIS 0x811c9dc5
#define FNV_PRIME 16777619 #define FNV_PRIME 16777619
/* FNV-1a hash */ // FNV-1a hash
static HashType hash(char const *str) static HashType hash(char const *str)
{ {
HashType hash = FNV_OFFSET_BASIS; HashType hash = FNV_OFFSET_BASIS;

View File

@@ -34,14 +34,12 @@ struct FreeSpace {
struct FreeSpace *next, *prev; struct FreeSpace *next, *prev;
}; };
/* Table of free space for each bank */ // Table of free space for each bank
struct FreeSpace *memory[SECTTYPE_INVALID]; struct FreeSpace *memory[SECTTYPE_INVALID];
uint64_t nbSectionsToAssign; uint64_t nbSectionsToAssign;
/** // Init the free space-modelling structs
* Init the free space-modelling structs
*/
static void initFreeSpace(void) static void initFreeSpace(void)
{ {
for (enum SectionType type = 0; type < SECTTYPE_INVALID; type++) { 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 * Assigns a section to a given memory location
* @param section The section to assign * @param section The section to assign
* @param location The location to assign the section to * @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); out_AddSection(section);
} }
/** /*
* Checks whether a given location is suitable for placing a given 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 * This checks not only that the location has enough room for the section, but
* also that the constraints (alignment...) are respected. * also that the constraints (alignment...) are respected.
@@ -111,7 +109,7 @@ static bool isLocationSuitable(struct Section const *section,
<= freeSpace->address + freeSpace->size; <= freeSpace->address + freeSpace->size;
} }
/** /*
* Finds a suitable location to place a section at. * Finds a suitable location to place a section at.
* @param section The section to be placed * @param section The section to be placed
* @param location A pointer to a location struct that will be filled * @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; struct FreeSpace *space;
for (;;) { 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) #define BANK_INDEX (location->bank - sectionTypeInfo[section->type].firstBank)
space = memory[section->type][BANK_INDEX].next; space = memory[section->type][BANK_INDEX].next;
if (space) if (space)
location->address = space->address; location->address = space->address;
/* Process locations in that bank */ // Process locations in that bank
while (space) { while (space) {
/* If that location is OK, return it */ // If that location is OK, return it
if (isLocationSuitable(section, space, location)) if (isLocationSuitable(section, space, location))
return space; return space;
/* Go to the next *possible* location */ // Go to the next *possible* location
if (section->isAddressFixed) { if (section->isAddressFixed) {
/* // If the address is fixed, there can be only
* If the address is fixed, there can be only // one candidate block per bank; if we already
* one candidate block per bank; if we already // reached it, give up.
* reached it, give up.
*/
if (location->address < section->org) if (location->address < section->org)
location->address = section->org; location->address = section->org;
else else
/* Try again in next bank */ // Try again in next bank
space = NULL; space = NULL;
} else if (section->isAlignFixed) { } else if (section->isAlignFixed) {
/* Move to next aligned location */ // Move to next aligned location
/* Move back to alignment boundary */ // Move back to alignment boundary
location->address -= section->alignOfs; 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; 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 location->address += section->alignMask + 1
+ section->alignOfs; + section->alignOfs;
} else { } else {
/* Any location is fine, so, next free block */ // Any location is fine, so, next free block
space = space->next; space = space->next;
if (space) if (space)
location->address = space->address; location->address = space->address;
} }
/* // If that location is past the current block's end,
* If that location is past the current block's end, // go forwards until that is no longer the case.
* go forwards until that is no longer the case.
*/
while (space && location->address >= while (space && location->address >=
space->address + space->size) space->address + space->size)
space = space->next; space = space->next;
/* Try again with the new location/free space combo */ // Try again with the new location/free space combo
} }
if (section->isBankFixed) if (section->isBankFixed)
return NULL; return NULL;
/* Try again in the next bank */ // Try again in the next bank
location->bank++; location->bank++;
if (location->bank > sectionTypeInfo[section->type].lastBank) if (location->bank > sectionTypeInfo[section->type].lastBank)
return NULL; 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. * 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 * @warning Due to the implemented algorithm, this should be called with
* sections of decreasing size. * sections of decreasing size.
@@ -218,12 +212,10 @@ static void placeSection(struct Section *section)
{ {
struct MemoryLocation location; 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) { if (section->size == 0) {
/* // Unless the SECTION's address was fixed, the starting address
* Unless the SECTION's address was fixed, the starting address // is fine for any alignment, as checked in sect_DoSanityChecks.
* is fine for any alignment, as checked in sect_DoSanityChecks.
*/
location.address = section->isAddressFixed location.address = section->isAddressFixed
? section->org ? section->org
: sectionTypeInfo[section->type].startAddr; : sectionTypeInfo[section->type].startAddr;
@@ -234,60 +226,56 @@ static void placeSection(struct Section *section)
return; return;
} }
/* // Place section using first-fit decreasing algorithm
* Place section using first-fit decreasing algorithm // https://en.wikipedia.org/wiki/Bin_packing_problem#First-fit_algorithm
* https://en.wikipedia.org/wiki/Bin_packing_problem#First-fit_algorithm
*/
struct FreeSpace *freeSpace = getPlacement(section, &location); struct FreeSpace *freeSpace = getPlacement(section, &location);
if (freeSpace) { if (freeSpace) {
assignSection(section, &location); assignSection(section, &location);
/* Split the free space */ // Split the free space
bool noLeftSpace = freeSpace->address == section->org; bool noLeftSpace = freeSpace->address == section->org;
bool noRightSpace = freeSpace->address + freeSpace->size bool noRightSpace = freeSpace->address + freeSpace->size
== section->org + section->size; == section->org + section->size;
if (noLeftSpace && noRightSpace) { if (noLeftSpace && noRightSpace) {
/* The free space is entirely deleted */ // The free space is entirely deleted
freeSpace->prev->next = freeSpace->next; freeSpace->prev->next = freeSpace->next;
if (freeSpace->next) if (freeSpace->next)
freeSpace->next->prev = freeSpace->prev; freeSpace->next->prev = freeSpace->prev;
/* // If the space is the last one on the list, set its
* 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()
* size to 0 so it doesn't get picked, but don't free() // it as it will be freed when cleaning up
* it as it will be freed when cleaning up
*/
free(freeSpace); free(freeSpace);
} else if (!noLeftSpace && !noRightSpace) { } else if (!noLeftSpace && !noRightSpace) {
/* The free space is split in two */ // The free space is split in two
struct FreeSpace *newSpace = malloc(sizeof(*newSpace)); struct FreeSpace *newSpace = malloc(sizeof(*newSpace));
if (!newSpace) if (!newSpace)
err("Failed to split new free space"); 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->prev = freeSpace;
newSpace->next = freeSpace->next; newSpace->next = freeSpace->next;
if (freeSpace->next) if (freeSpace->next)
freeSpace->next->prev = newSpace; freeSpace->next->prev = newSpace;
freeSpace->next = newSpace; freeSpace->next = newSpace;
/* Set its parameters */ // Set its parameters
newSpace->address = section->org + section->size; newSpace->address = section->org + section->size;
newSpace->size = freeSpace->address + freeSpace->size - newSpace->size = freeSpace->address + freeSpace->size -
newSpace->address; newSpace->address;
/* Set the original space's new parameters */ // Set the original space's new parameters
freeSpace->size = section->org - freeSpace->address; freeSpace->size = section->org - freeSpace->address;
/* address is unmodified */ // address is unmodified
} else { } else {
/* The amount of free spaces doesn't change: resize! */ // The amount of free spaces doesn't change: resize!
freeSpace->size -= section->size; freeSpace->size -= section->size;
if (noLeftSpace) if (noLeftSpace)
/* The free space is moved *and* resized */ // The free space is moved *and* resized
freeSpace->address += section->size; freeSpace->address += section->size;
} }
return; return;
} }
/* Please adjust depending on longest message below */ // Please adjust depending on longest message below
char where[64]; char where[64];
if (section->isBankFixed && nbbanks(section->type) != 1) { if (section->isBankFixed && nbbanks(section->type) != 1) {
@@ -312,16 +300,16 @@ static void placeSection(struct Section *section)
strcpy(where, "anywhere"); 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) if (!section->isBankFixed || !section->isAddressFixed)
errx("Unable to place \"%s\" (%s section) %s", errx("Unable to place \"%s\" (%s section) %s",
section->name, sectionTypeInfo[section->type].name, where); 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) 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)", errx("Unable to place \"%s\" (%s section) %s: section runs past end of region ($%04x > $%04x)",
section->name, sectionTypeInfo[section->type].name, where, section->name, sectionTypeInfo[section->type].name, where,
section->org + section->size, endaddr(section->type) + 1); section->org + section->size, endaddr(section->type) + 1);
/* Otherwise there is overlap with another section */ // Otherwise there is overlap with another section
else else
errx("Unable to place \"%s\" (%s section) %s: section overlaps with \"%s\"", errx("Unable to place \"%s\" (%s section) %s: section overlaps with \"%s\"",
section->name, sectionTypeInfo[section->type].name, where, section->name, sectionTypeInfo[section->type].name, where,
@@ -339,7 +327,7 @@ struct UnassignedSection {
static struct UnassignedSection *unassignedSections[1 << 3] = {0}; static struct UnassignedSection *unassignedSections[1 << 3] = {0};
static struct UnassignedSection *sections; static struct UnassignedSection *sections;
/** /*
* Categorize a section depending on how constrained it is * Categorize a section depending on how constrained it is
* This is so the most-constrained sections are placed first * This is so the most-constrained sections are placed first
* @param section The section to categorize * @param section The section to categorize
@@ -354,13 +342,13 @@ static void categorizeSection(struct Section *section, void *arg)
constraints |= BANK_CONSTRAINED; constraints |= BANK_CONSTRAINED;
if (section->isAddressFixed) if (section->isAddressFixed)
constraints |= ORG_CONSTRAINED; constraints |= ORG_CONSTRAINED;
/* Can't have both! */ // Can't have both!
else if (section->isAlignFixed) else if (section->isAlignFixed)
constraints |= ALIGN_CONSTRAINED; constraints |= ALIGN_CONSTRAINED;
struct UnassignedSection **ptr = &unassignedSections[constraints]; 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) while (*ptr && (*ptr)->section->size > section->size)
ptr = &(*ptr)->next; ptr = &(*ptr)->next;
@@ -375,9 +363,9 @@ void assign_AssignSections(void)
{ {
verbosePrint("Beginning assignment...\n"); 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); sections = malloc(sizeof(*sections) * nbSectionsToAssign + 1);
if (!sections) if (!sections)
err("Failed to allocate memory for section assignment"); err("Failed to allocate memory for section assignment");
@@ -387,9 +375,9 @@ void assign_AssignSections(void)
nbSectionsToAssign = 0; nbSectionsToAssign = 0;
sect_ForEach(categorizeSection, NULL); 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 = struct UnassignedSection *sectionPtr =
unassignedSections[BANK_CONSTRAINED | ORG_CONSTRAINED]; unassignedSections[BANK_CONSTRAINED | ORG_CONSTRAINED];
@@ -399,11 +387,11 @@ void assign_AssignSections(void)
sectionPtr = sectionPtr->next; 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) if (!nbSectionsToAssign)
return; return;
/* Overlaying requires only fully-constrained sections */ // Overlaying requires only fully-constrained sections
verbosePrint("Assigning other sections...\n"); verbosePrint("Assigning other sections...\n");
if (overlayFileName) { if (overlayFileName) {
fprintf(stderr, "FATAL: All sections must be fixed when using an overlay file"); fprintf(stderr, "FATAL: All sections must be fixed when using an overlay file");
@@ -427,7 +415,7 @@ max_out:
exit(1); 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; for (int8_t constraints = BANK_CONSTRAINED | ALIGN_CONSTRAINED;
constraints >= 0; constraints--) { constraints >= 0; constraints--) {
sectionPtr = unassignedSections[constraints]; sectionPtr = unassignedSections[constraints];

View File

@@ -33,34 +33,33 @@
#include "platform.h" #include "platform.h"
#include "version.h" #include "version.h"
bool isDmgMode; /* -d */ bool isDmgMode; // -d
char *linkerScriptName; /* -l */ char *linkerScriptName; // -l
char const *mapFileName; /* -m */ char const *mapFileName; // -m
bool noSymInMap; /* -M */ bool noSymInMap; // -M
char const *symFileName; /* -n */ char const *symFileName; // -n
char const *overlayFileName; /* -O */ char const *overlayFileName; // -O
char const *outputFileName; /* -o */ char const *outputFileName; // -o
uint8_t padValue; /* -p */ uint8_t padValue; // -p
// Setting these three to 0 disables the functionality // Setting these three to 0 disables the functionality
uint16_t scrambleROMX = 0; /* -S */ uint16_t scrambleROMX = 0; // -S
uint8_t scrambleWRAMX = 0; uint8_t scrambleWRAMX = 0;
uint8_t scrambleSRAM = 0; uint8_t scrambleSRAM = 0;
bool is32kMode; /* -t */ bool is32kMode; // -t
bool beVerbose; /* -v */ bool beVerbose; // -v
bool isWRA0Mode; /* -w */ bool isWRA0Mode; // -w
bool disablePadding; /* -x */ bool disablePadding; // -x
static uint32_t nbErrors = 0; 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 *dumpFileStack(struct FileStackNode const *node)
{ {
char const *lastName; char const *lastName;
if (node->parent) { if (node->parent) {
lastName = dumpFileStack(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) if (node->type != NODE_REPT)
lastName = node->name; lastName = node->name;
fprintf(stderr, "(%" PRIu32 ") -> %s", node->lineNo, lastName); fprintf(stderr, "(%" PRIu32 ") -> %s", node->lineNo, lastName);
@@ -165,7 +164,7 @@ FILE *openFile(char const *fileName, char const *mode)
return file; return file;
} }
/* Short options */ // Short options
static const char *optstring = "dl:m:Mn:O:o:p:S:s:tVvWwx"; 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 } { NULL, no_argument, NULL, 0 }
}; };
/** // Prints the program's usage to stdout.
* Prints the program's usage to stdout.
*/
static void printUsage(void) static void printUsage(void)
{ {
fputs( fputs(
@@ -219,10 +216,8 @@ static void printUsage(void)
stderr); stderr);
} }
/** // Cleans up what has been done
* Cleans up what has been done // Mostly here to please tools such as `valgrind` so actual errors can be seen
* Mostly here to please tools such as `valgrind` so actual errors can be seen
*/
static void cleanup(void) static void cleanup(void)
{ {
obj_Cleanup(); obj_Cleanup();
@@ -362,10 +357,10 @@ _Noreturn void reportErrors(void) {
int main(int argc, char *argv[]) int main(int argc, char *argv[])
{ {
int optionChar; int optionChar;
char *endptr; /* For error checking with `strtoul` */ char *endptr; // For error checking with `strtoul`
unsigned long value; /* For storing `strtoul`'s return value */ unsigned long value; // For storing `strtoul`'s return value
/* Parse options */ // Parse options
while ((optionChar = musl_getopt_long_only(argc, argv, optstring, while ((optionChar = musl_getopt_long_only(argc, argv, optstring,
longopts, NULL)) != -1) { longopts, NULL)) != -1) {
switch (optionChar) { switch (optionChar) {
@@ -407,7 +402,7 @@ int main(int argc, char *argv[])
parseScrambleSpec(musl_optarg); parseScrambleSpec(musl_optarg);
break; break;
case 's': case 's':
/* FIXME: nobody knows what this does, figure it out */ // FIXME: nobody knows what this does, figure it out
(void)musl_optarg; (void)musl_optarg;
warning(NULL, 0, "Nobody has any idea what `-s` does"); warning(NULL, 0, "Nobody has any idea what `-s` does");
break; break;
@@ -425,7 +420,7 @@ int main(int argc, char *argv[])
break; break;
case 'x': case 'x':
disablePadding = true; disablePadding = true;
/* implies tiny mode */ // implies tiny mode
is32kMode = true; is32kMode = true;
break; break;
default: default:
@@ -436,41 +431,41 @@ int main(int argc, char *argv[])
int curArgIndex = musl_optind; 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) { if (curArgIndex == argc) {
fputs("FATAL: no input files\n", stderr); fputs("FATAL: no input files\n", stderr);
printUsage(); printUsage();
exit(1); exit(1);
} }
/* Patch the size array depending on command-line options */ // Patch the size array depending on command-line options
if (!is32kMode) if (!is32kMode)
sectionTypeInfo[SECTTYPE_ROM0].size = 0x4000; sectionTypeInfo[SECTTYPE_ROM0].size = 0x4000;
if (!isWRA0Mode) if (!isWRA0Mode)
sectionTypeInfo[SECTTYPE_WRAM0].size = 0x1000; 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) if (isDmgMode)
sectionTypeInfo[SECTTYPE_VRAM].lastBank = 0; sectionTypeInfo[SECTTYPE_VRAM].lastBank = 0;
/* Read all object files first, */ // Read all object files first,
for (obj_Setup(argc - curArgIndex); curArgIndex < argc; curArgIndex++) for (obj_Setup(argc - curArgIndex); curArgIndex < argc; curArgIndex++)
obj_ReadFile(argv[curArgIndex], argc - curArgIndex - 1); obj_ReadFile(argv[curArgIndex], argc - curArgIndex - 1);
/* apply the linker script's modifications, */ // apply the linker script's modifications,
if (linkerScriptName) { if (linkerScriptName) {
verbosePrint("Reading linker script...\n"); verbosePrint("Reading linker script...\n");
linkerScript = openFile(linkerScriptName, "r"); linkerScript = openFile(linkerScriptName, "r");
/* Modify all sections according to the linker script */ // Modify all sections according to the linker script
struct SectionPlacement *placement; struct SectionPlacement *placement;
while ((placement = script_NextSection())) { while ((placement = script_NextSection())) {
struct Section *section = placement->section; struct Section *section = placement->section;
assert(section->offset == 0); 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) { if (section->type == SECTTYPE_INVALID) {
for (struct Section *sect = section; sect; sect = sect->nextu) for (struct Section *sect = section; sect; sect = sect->nextu)
sect->type = placement->type; // SDCC "unknown" sections sect->type = placement->type; // SDCC "unknown" sections
@@ -493,7 +488,7 @@ int main(int argc, char *argv[])
section->org = placement->org; section->org = placement->org;
section->isBankFixed = true; section->isBankFixed = true;
section->bank = placement->bank; section->bank = placement->bank;
section->isAlignFixed = false; /* The alignment is satisfied */ section->isAlignFixed = false; // The alignment is satisfied
} }
fclose(linkerScript); fclose(linkerScript);
@@ -506,7 +501,7 @@ int main(int argc, char *argv[])
} }
/* then process them, */ // then process them,
obj_DoSanityChecks(); obj_DoSanityChecks();
if (nbErrors != 0) if (nbErrors != 0)
reportErrors(); reportErrors();
@@ -514,12 +509,12 @@ int main(int argc, char *argv[])
obj_CheckAssertions(); obj_CheckAssertions();
assign_Cleanup(); assign_Cleanup();
/* and finally output the result. */ // and finally output the result.
patch_ApplyPatches(); patch_ApplyPatches();
if (nbErrors != 0) if (nbErrors != 0)
reportErrors(); reportErrors();
out_WriteFiles(); out_WriteFiles();
/* Do cleanup before quitting, though. */ // Do cleanup before quitting, though.
cleanup(); cleanup();
} }

View File

@@ -39,12 +39,10 @@ static struct {
} *nodes; } *nodes;
static struct Assertion *assertions; static struct Assertion *assertions;
/***** Helper functions for reading object files *****/ // Helper functions for reading object files
/* // Internal, DO NOT USE.
* Internal, DO NOT USE. // For helper wrapper macros defined below, such as `tryReadlong`
* For helper wrapper macros defined below, such as `tryReadlong`
*/
#define tryRead(func, type, errval, var, file, ...) \ #define tryRead(func, type, errval, var, file, ...) \
do { \ do { \
FILE *tmpFile = file; \ FILE *tmpFile = file; \
@@ -58,7 +56,7 @@ static struct Assertion *assertions;
var = tmpVal; \ var = tmpVal; \
} while (0) } while (0)
/** /*
* Reads an unsigned long (32-bit) value from a file. * 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. * @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. * @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; 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) { for (uint8_t shift = 0; shift < sizeof(value) * CHAR_BIT; shift += 8) {
int byte = getc(file); int byte = getc(file);
if (byte == EOF) if (byte == EOF)
return INT64_MAX; return INT64_MAX;
/* This must be casted to `unsigned`, not `uint8_t`. Rationale: // This must be casted to `unsigned`, not `uint8_t`. Rationale:
* the type of the shift is the type of `byte` after undergoing // the type of the shift is the type of `byte` after undergoing
* integer promotion, which would be `int` if this was casted to // integer promotion, which would be `int` if this was casted to
* `uint8_t`, because int is large enough to hold a byte. This // `uint8_t`, because int is large enough to hold a byte. This
* however causes values larger than 127 to be too large when // however causes values larger than 127 to be too large when
* shifted, potentially triggering undefined behavior. // shifted, potentially triggering undefined behavior.
*/
value |= (unsigned int)byte << shift; value |= (unsigned int)byte << shift;
} }
return value; return value;
} }
/** /*
* Helper macro for reading longs from a file, and errors out if it fails to. * 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. * Not as a function to avoid overhead in the general case.
* @param var The variable to stash the number into * @param var The variable to stash the number into
@@ -96,9 +93,9 @@ static int64_t readlong(FILE *file)
#define tryReadlong(var, file, ...) \ #define tryReadlong(var, file, ...) \
tryRead(readlong, int64_t, INT64_MAX, var, file, __VA_ARGS__) 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. * 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). * Differs from `tryGetc` in that the backing function is fgetc(1).
* Not as a function to avoid overhead in the general case. * 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, ...) \ #define tryFgetc(var, file, ...) \
tryRead(fgetc, int, EOF, var, file, __VA_ARGS__) tryRead(fgetc, int, EOF, var, file, __VA_ARGS__)
/** /*
* Helper macro for reading bytes from a file, and errors out if it fails to. * 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). * Differs from `tryGetc` in that the backing function is fgetc(1).
* Not as a function to avoid overhead in the general case. * 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, ...) \ #define tryGetc(var, file, ...) \
tryRead(getc, int, EOF, var, file, __VA_ARGS__) tryRead(getc, int, EOF, var, file, __VA_ARGS__)
/** /*
* Reads a '\0'-terminated string from a file. * Reads a '\0'-terminated string from a file.
* @param file The file to read from. The file position will be advanced. * @param file The file to read from. The file position will be advanced.
* @return The string read, or NULL on failure. * @return The string read, or NULL on failure.
@@ -130,26 +127,26 @@ static int64_t readlong(FILE *file)
*/ */
static char *readstr(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 capacity = 32 / 2;
size_t index = -1; size_t index = -1;
/* Force the first iteration to allocate */ // Force the first iteration to allocate
char *str = NULL; char *str = NULL;
do { do {
/* Prepare going to next char */ // Prepare going to next char
index++; 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) { if (index >= capacity || !str) {
capacity *= 2; capacity *= 2;
str = realloc(str, capacity); str = realloc(str, capacity);
/* End now in case of error */ // End now in case of error
if (!str) if (!str)
return NULL; return NULL;
} }
/* Read char */ // Read char
int byte = getc(file); int byte = getc(file);
if (byte == EOF) { if (byte == EOF) {
@@ -161,7 +158,7 @@ static char *readstr(FILE *file)
return str; return str;
} }
/** /*
* Helper macro for reading bytes from a file, and errors out if it fails to. * 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. * Not as a function to avoid overhead in the general case.
* @param var The variable to stash the string into * @param var The variable to stash the string into
@@ -172,9 +169,9 @@ static char *readstr(FILE *file)
#define tryReadstr(var, file, ...) \ #define tryReadstr(var, file, ...) \
tryRead(readstr, char*, NULL, var, file, __VA_ARGS__) 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. * Reads a file stack node form a file.
* @param file The file to read from * @param file The file to read from
* @param nodes The file's array of nodes * @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. * Reads a symbol from a file.
* @param file The file to read from * @param file The file to read from
* @param symbol The struct to fill * @param symbol The struct to fill
@@ -230,7 +227,7 @@ static void readSymbol(FILE *file, struct Symbol *symbol,
fileName); fileName);
tryGetc(symbol->type, file, "%s: Cannot read \"%s\"'s type: %s", tryGetc(symbol->type, file, "%s: Cannot read \"%s\"'s type: %s",
fileName, symbol->name); 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) { if (symbol->type != SYMTYPE_IMPORT) {
symbol->objFileName = fileName; symbol->objFileName = fileName;
uint32_t nodeID; uint32_t nodeID;
@@ -253,7 +250,7 @@ static void readSymbol(FILE *file, struct Symbol *symbol,
} }
} }
/** /*
* Reads a patch from a file. * Reads a patch from a file.
* @param file The file to read from * @param file The file to read from
* @param patch The struct to fill * @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)); feof(file) ? "Unexpected end of file" : strerror(errno));
} }
/** /*
* Sets a patch's pcSection from its pcSectionID. * Sets a patch's pcSection from its pcSectionID.
* @param patch The struct to fix * @param patch The struct to fix
*/ */
@@ -313,7 +310,7 @@ static void linkPatchToPCSect(struct Patch *patch, struct Section *fileSections[
: fileSections[patch->pcSectionID]; : fileSections[patch->pcSectionID];
} }
/** /*
* Reads a section from a file. * Reads a section from a file.
* @param file The file to read from * @param file The file to read from
* @param section The struct to fill * @param section The struct to fill
@@ -372,7 +369,7 @@ static void readSection(FILE *file, struct Section *section, char const *fileNam
section->alignOfs = tmp; section->alignOfs = tmp;
if (sect_HasData(section->type)) { 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); uint8_t *data = malloc(sizeof(*data) * section->size + 1);
if (!data) 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. * Links a symbol to a section, keeping the section's symbol list sorted.
* @param symbol The symbol to link * @param symbol The symbol to link
* @param section The section to link * @param section The section to link
@@ -433,7 +430,7 @@ static void linkSymToSect(struct Symbol *symbol, struct Section *section)
section->nbSymbols++; section->nbSymbols++;
} }
/** /*
* Reads an assertion from a file * Reads an assertion from a file
* @param file The file to read from * @param file The file to read from
* @param assert The struct to fill * @param assert The struct to fill
@@ -500,7 +497,7 @@ void obj_ReadFile(char const *fileName, unsigned int fileID)
return; return;
} }
/* Begin by reading the magic bytes */ // Begin by reading the magic bytes
int matchedElems; int matchedElems;
if (fscanf(file, RGBDS_OBJECT_VERSION_STRING "%n", &matchedElems) == 1 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--; ) for (uint32_t i = nodes[fileID].nbNodes; i--; )
readFileStackNode(file, nodes[fileID].nodes, i, fileName); 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); struct Symbol **fileSymbols = malloc(sizeof(*fileSymbols) * nbSymbols + 1);
if (!fileSymbols) if (!fileSymbols)
@@ -556,7 +553,7 @@ void obj_ReadFile(char const *fileName, unsigned int fileID)
verbosePrint("Reading %" PRIu32 " symbols...\n", nbSymbols); verbosePrint("Reading %" PRIu32 " symbols...\n", nbSymbols);
for (uint32_t i = 0; i < nbSymbols; i++) { for (uint32_t i = 0; i < nbSymbols; i++) {
/* Read symbol */ // Read symbol
struct Symbol *symbol = malloc(sizeof(*symbol)); struct Symbol *symbol = malloc(sizeof(*symbol));
if (!symbol) if (!symbol)
@@ -570,13 +567,13 @@ void obj_ReadFile(char const *fileName, unsigned int fileID)
nbSymPerSect[symbol->sectionID]++; 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) struct Section **fileSections = malloc(sizeof(*fileSections)
* (nbSections ? nbSections : 1)); * (nbSections ? nbSections : 1));
verbosePrint("Reading %" PRIu32 " sections...\n", nbSections); verbosePrint("Reading %" PRIu32 " sections...\n", nbSections);
for (uint32_t i = 0; i < nbSections; i++) { for (uint32_t i = 0; i < nbSections; i++) {
/* Read section */ // Read section
fileSections[i] = malloc(sizeof(*fileSections[i])); fileSections[i] = malloc(sizeof(*fileSections[i]));
if (!fileSections[i]) if (!fileSections[i])
err("%s: Couldn't create new section", fileName); err("%s: Couldn't create new section", fileName);
@@ -600,7 +597,7 @@ void obj_ReadFile(char const *fileName, unsigned int fileID)
free(nbSymPerSect); 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++) { for (uint32_t i = 0; i < nbSections; i++) {
if (sect_HasData(fileSections[i]->type)) { if (sect_HasData(fileSections[i]->type)) {
for (uint32_t j = 0; j < fileSections[i]->nbPatches; j++) 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++) { for (uint32_t i = 0; i < nbSymbols; i++) {
int32_t sectionID = fileSymbols[i]->sectionID; int32_t sectionID = fileSymbols[i]->sectionID;
@@ -617,12 +614,12 @@ void obj_ReadFile(char const *fileName, unsigned int fileID)
} else { } else {
struct Section *section = fileSections[sectionID]; 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); linkSymToSect(fileSymbols[i], section);
if (section->modifier != SECTION_NORMAL) { if (section->modifier != SECTION_NORMAL) {
if (section->modifier == SECTION_FRAGMENT) 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; fileSymbols[i]->offset += section->offset;
section = getMainSection(section); section = getMainSection(section);
} }

View File

@@ -47,7 +47,7 @@ static struct {
} *banks; } *banks;
} sections[SECTTYPE_INVALID]; } 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] = { static enum SectionType typeMap[SECTTYPE_INVALID] = {
SECTTYPE_ROM0, SECTTYPE_ROM0,
SECTTYPE_ROMX, SECTTYPE_ROMX,
@@ -124,7 +124,7 @@ struct Section const *out_OverlappingSection(struct Section const *section)
return NULL; return NULL;
} }
/** /*
* Performs sanity checks on the overlay file. * Performs sanity checks on the overlay file.
* @return The number of ROM banks in 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); long overlaySize = ftell(overlayFile);
/* Reset back to beginning */ // Reset back to beginning
fseek(overlayFile, 0, SEEK_SET); fseek(overlayFile, 0, SEEK_SET);
if (overlaySize % BANK_SIZE) if (overlaySize % BANK_SIZE)
@@ -157,7 +157,7 @@ static uint32_t checkOverlaySize(void)
return nbOverlayBanks; return nbOverlayBanks;
} }
/** /*
* Expand sections[SECTTYPE_ROMX].banks to cover all the overlay banks. * Expand sections[SECTTYPE_ROMX].banks to cover all the overlay banks.
* This ensures that writeROM will output each bank, even if some are not * This ensures that writeROM will output each bank, even if some are not
* covered by any sections. * covered by any sections.
@@ -165,9 +165,9 @@ static uint32_t checkOverlaySize(void)
*/ */
static void coverOverlayBanks(uint32_t nbOverlayBanks) 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; 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 uint32_t nbUncoveredBanks = nbOverlayBanks - nbRom0Banks > sections[SECTTYPE_ROMX].nbBanks
? nbOverlayBanks - nbRom0Banks ? nbOverlayBanks - nbRom0Banks
: 0; : 0;
@@ -186,7 +186,7 @@ static void coverOverlayBanks(uint32_t nbOverlayBanks)
} }
} }
/** /*
* Write a ROM bank's sections to the output file. * Write a ROM bank's sections to the output file.
* @param bankSections The bank's sections, ordered by increasing address * @param bankSections The bank's sections, ordered by increasing address
* @param baseOffset The address of the bank's first byte in GB address space * @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; struct Section const *section = bankSections->section;
assert(section->offset == 0); assert(section->offset == 0);
/* Output padding up to the next SECTION */ // Output padding up to the next SECTION
while (offset + baseOffset < section->org) { while (offset + baseOffset < section->org) {
putc(overlayFile ? getc(overlayFile) : padValue, putc(overlayFile ? getc(overlayFile) : padValue,
outputFile); outputFile);
offset++; offset++;
} }
/* Output the section itself */ // Output the section itself
fwrite(section->data, sizeof(*section->data), section->size, fwrite(section->data, sizeof(*section->data), section->size,
outputFile); outputFile);
if (overlayFile) { if (overlayFile) {
/* Skip bytes even with pipes */ // Skip bytes even with pipes
for (uint16_t i = 0; i < section->size; i++) for (uint16_t i = 0; i < section->size; i++)
getc(overlayFile); 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) static void writeROM(void)
{ {
outputFile = openFile(outputFileName, "wb"); outputFile = openFile(outputFileName, "wb");
@@ -258,7 +256,7 @@ static void writeROM(void)
closeFile(overlayFile); closeFile(overlayFile);
} }
/** /*
* Get the lowest section by address out of the two * Get the lowest section by address out of the two
* @param s1 One choice * @param s1 One choice
* @param s2 The other * @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; return (*s1)->section->org < (*s2)->section->org ? s1 : s2;
} }
/* // Comparator function for `qsort` to sort symbols
* Comparator function for `qsort` to sort symbols // Symbols are ordered by address, or else by original index for a stable sort
* Symbols are ordered by address, or else by original index for a stable sort
*/
static int compareSymbols(void const *a, void const *b) static int compareSymbols(void const *a, void const *b)
{ {
struct SortedSymbol const *sym1 = (struct SortedSymbol const *)a; 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; return sym1->idx < sym2->idx ? -1 : sym1->idx > sym2->idx ? 1 : 0;
} }
/** /*
* Write a bank's contents to the sym file * Write a bank's contents to the sym file
* @param bankSections The bank's sections * @param bankSections The bank's sections
*/ */
@@ -357,7 +353,7 @@ static void writeSymBank(struct SortedSections const *bankSections,
free(symList); free(symList);
} }
/** /*
* Write a bank's contents to the map file * Write a bank's contents to the map file
* @param bankSections The bank's sections * @param bankSections The bank's sections
* @return The bank's used space * @return The bank's used space
@@ -445,7 +441,7 @@ static uint16_t writeMapBank(struct SortedSections const *sectList,
return used; return used;
} }
/** /*
* Write the total used space by section type to the map file * Write the total used space by section type to the map file
* @param usedMap The total used space by section type * @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) static void writeSymAndMap(void)
{ {
if (!symFileName && !mapFileName) if (!symFileName && !mapFileName)

View File

@@ -63,11 +63,9 @@ static void pushRPN(int32_t value, bool comesFromError)
realloc(stack.values, sizeof(*stack.values) * stack.capacity); realloc(stack.values, sizeof(*stack.values) * stack.capacity);
stack.errorFlags = stack.errorFlags =
realloc(stack.errorFlags, sizeof(*stack.errorFlags) * stack.capacity); realloc(stack.errorFlags, sizeof(*stack.errorFlags) * stack.capacity);
/* // Static analysis tools complain that the capacity might become
* Static analysis tools complain that the capacity might become // zero due to overflow, but fail to realize that it's caught by
* zero due to overflow, but fail to realize that it's caught by // the overflow check above. Hence the stringent check below.
* the overflow check above. Hence the stringent check below.
*/
if (!stack.values || !stack.errorFlags || !stack.capacity) if (!stack.values || !stack.errorFlags || !stack.capacity)
err("Failed to resize RPN stack"); err("Failed to resize RPN stack");
} }
@@ -97,7 +95,7 @@ static void freeRPNStack(void)
free(stack.errorFlags); free(stack.errorFlags);
} }
/* RPN operators */ // RPN operators
static uint32_t getRPNByte(uint8_t const **expression, int32_t *size, static uint32_t getRPNByte(uint8_t const **expression, int32_t *size,
struct FileStackNode const *node, uint32_t lineNo) 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, static struct Symbol const *getSymbol(struct Symbol const * const *symbolList,
uint32_t index) 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]; struct Symbol const *symbol = symbolList[index];
/* If the symbol is defined elsewhere... */ // If the symbol is defined elsewhere...
if (symbol->type == SYMTYPE_IMPORT) if (symbol->type == SYMTYPE_IMPORT)
return sym_GetSymbol(symbol->name); return sym_GetSymbol(symbol->name);
return symbol; return symbol;
} }
/** /*
* Compute a patch's value from its RPN string. * Compute a patch's value from its RPN string.
* @param patch The patch to compute the value of * @param patch The patch to compute the value of
* @param section The section the patch is contained in * @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, static int32_t computeRPNExpr(struct Patch const *patch,
struct Symbol const * const *fileSymbols) 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) #define popRPN() popRPN(patch->src, patch->lineNo)
uint8_t const *expression = patch->rpnExpression; uint8_t const *expression = patch->rpnExpression;
@@ -147,13 +145,10 @@ static int32_t computeRPNExpr(struct Patch const *patch,
isError = false; isError = false;
/* // Be VERY careful with two `popRPN` in the same expression.
* Friendly reminder: // C does not guarantee order of evaluation of operands!!
* Be VERY careful with two `popRPN` in the same expression. // So, if there are two `popRPN` in the same expression, make
* C does not guarantee order of evaluation of operands!! // sure the operation is commutative.
* So, if there are two `popRPN` in the same expression, make
* sure the operation is commutative.
*/
switch (command) { switch (command) {
struct Symbol const *symbol; struct Symbol const *symbol;
char const *name; char const *name;
@@ -295,11 +290,9 @@ static int32_t computeRPNExpr(struct Patch const *patch,
break; break;
case RPN_BANK_SECT: case RPN_BANK_SECT:
/* // `expression` is not guaranteed to be '\0'-terminated. If it is not,
* `expression` is not guaranteed to be '\0'-terminated. If it is not, // `getRPNByte` will have a fatal internal error.
* `getRPNByte` will have a fatal internal error. // In either case, `getRPNByte` will not free `expression`.
* In either case, `getRPNByte` will not free `expression`.
*/
name = (char const *)expression; name = (char const *)expression;
while (getRPNByte(&expression, &size, patch->src, patch->lineNo)) while (getRPNByte(&expression, &size, patch->src, patch->lineNo))
; ;
@@ -329,7 +322,7 @@ static int32_t computeRPNExpr(struct Patch const *patch,
break; break;
case RPN_SIZEOF_SECT: 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; name = (char const *)expression;
while (getRPNByte(&expression, &size, patch->src, patch->lineNo)) while (getRPNByte(&expression, &size, patch->src, patch->lineNo))
; ;
@@ -348,7 +341,7 @@ static int32_t computeRPNExpr(struct Patch const *patch,
break; break;
case RPN_STARTOF_SECT: 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; name = (char const *)expression;
while (getRPNByte(&expression, &size, patch->src, patch->lineNo)) while (getRPNByte(&expression, &size, patch->src, patch->lineNo))
; ;
@@ -381,9 +374,8 @@ static int32_t computeRPNExpr(struct Patch const *patch,
case RPN_RST: case RPN_RST:
value = popRPN(); value = popRPN();
/* Acceptable values are 0x00, 0x08, 0x10, ..., 0x38 // Acceptable values are 0x00, 0x08, 0x10, ..., 0x38
* They can be easily checked with a bitmask // They can be easily checked with a bitmask
*/
if (value & ~0x38) { if (value & ~0x38) {
if (!isError) if (!isError)
error(patch->src, patch->lineNo, error(patch->src, patch->lineNo,
@@ -406,7 +398,7 @@ static int32_t computeRPNExpr(struct Patch const *patch,
value |= getRPNByte(&expression, &size, value |= getRPNByte(&expression, &size,
patch->src, patch->lineNo) << shift; patch->src, patch->lineNo) << shift;
if (value == -1) { /* PC */ if (value == -1) { // PC
if (!patch->pcSection) { if (!patch->pcSection) {
error(patch->src, patch->lineNo, error(patch->src, patch->lineNo,
"PC has no value outside a section"); "PC has no value outside a section");
@@ -424,7 +416,7 @@ static int32_t computeRPNExpr(struct Patch const *patch,
isError = true; isError = true;
} else { } else {
value = symbol->value; value = symbol->value;
/* Symbols attached to sections have offsets */ // Symbols attached to sections have offsets
if (symbol->section) if (symbol->section)
value += symbol->section->org; value += symbol->section->org;
} }
@@ -461,8 +453,8 @@ void patch_CheckAssertions(struct Assertion *assert)
fatal(assert->patch.src, assert->patch.lineNo, "%s", fatal(assert->patch.src, assert->patch.lineNo, "%s",
assert->message[0] ? assert->message assert->message[0] ? assert->message
: "assert failure"); : "assert failure");
/* Not reached */ // Not reached
break; /* Here so checkpatch doesn't complain */ break; // Here so checkpatch doesn't complain
case ASSERT_ERROR: case ASSERT_ERROR:
error(assert->patch.src, assert->patch.lineNo, "%s", error(assert->patch.src, assert->patch.lineNo, "%s",
assert->message[0] ? assert->message assert->message[0] ? assert->message
@@ -491,7 +483,7 @@ void patch_CheckAssertions(struct Assertion *assert)
freeRPNStack(); freeRPNStack();
} }
/** /*
* Applies all of a section's patches * Applies all of a section's patches
* @param section The section to patch * @param section The section to patch
* @param arg Ignored callback arg * @param arg Ignored callback arg
@@ -506,7 +498,7 @@ static void applyFilePatches(struct Section *section, struct Section *dataSectio
section->fileSymbols); section->fileSymbols);
uint16_t offset = patch->offset + section->offset; uint16_t offset = patch->offset + section->offset;
/* `jr` is quite unlike the others... */ // `jr` is quite unlike the others...
if (patch->type == PATCHTYPE_JR) { if (patch->type == PATCHTYPE_JR) {
// Offset is relative to the byte *after* the operand // Offset is relative to the byte *after* the operand
// PC as operand to `jr` is lower than reference PC by 2 // 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); jumpOffset);
dataSection->data[offset] = jumpOffset & 0xFF; dataSection->data[offset] = jumpOffset & 0xFF;
} else { } else {
/* Patch a certain number of bytes */ // Patch a certain number of bytes
struct { struct {
uint8_t size; uint8_t size;
int32_t min; 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 * Applies all of a section's patches, iterating over "components" of
* unionized sections * unionized sections
* @param section The section to patch * @param section The section to patch

View File

@@ -41,7 +41,7 @@ static void pushFile(char *newFileName)
linkerScriptName, lineNo); linkerScriptName, lineNo);
if (fileStackIndex == fileStackSize) { if (fileStackIndex == fileStackSize) {
if (!fileStackSize) /* Init file stack */ if (!fileStackSize) // Init file stack
fileStackSize = 4; fileStackSize = 4;
fileStackSize *= 2; fileStackSize *= 2;
fileStack = realloc(fileStack, sizeof(*fileStack) * fileStackSize); fileStack = realloc(fileStack, sizeof(*fileStack) * fileStackSize);
@@ -88,7 +88,7 @@ static bool isNewline(int c)
return c == '\r' || c == '\n'; return c == '\r' || c == '\n';
} }
/** /*
* Try parsing a number, in base 16 if it begins with a dollar, * Try parsing a number, in base 16 if it begins with a dollar,
* in base 10 otherwise * in base 10 otherwise
* @param str The number to parse * @param str The number to parse
@@ -108,7 +108,7 @@ static bool tryParseNumber(char const *str, uint32_t *number)
base = 16; base = 16;
} }
/* An empty string is not a number */ // An empty string is not a number
if (!*str) if (!*str)
return false; return false;
@@ -188,16 +188,16 @@ static struct LinkerScriptToken *nextToken(void)
static struct LinkerScriptToken token; static struct LinkerScriptToken token;
int curchar; 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) if (token.type == TOKEN_STRING)
free(token.attr.string); free(token.attr.string);
/* Skip initial whitespace... */ // Skip initial whitespace...
do do
curchar = nextChar(); curchar = nextChar();
while (isWhiteSpace(curchar)); 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 == ';') { if (curchar == ';') {
do { do {
curchar = nextChar(); curchar = nextChar();
@@ -207,22 +207,22 @@ static struct LinkerScriptToken *nextToken(void)
if (curchar == EOF) { if (curchar == EOF) {
token.type = TOKEN_EOF; token.type = TOKEN_EOF;
} else if (isNewline(curchar)) { } 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; token.type = TOKEN_NEWLINE;
if (curchar == '\r') { if (curchar == '\r') {
/* Handle CRLF */ // Handle CRLF
curchar = nextChar(); curchar = nextChar();
if (curchar != '\n') if (curchar != '\n')
ungetc(curchar, linkerScript); ungetc(curchar, linkerScript);
} }
} else if (curchar == '"') { } 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.type = TOKEN_STRING;
token.attr.string = NULL; /* Force initial alloc */ token.attr.string = NULL; // Force initial alloc
size_t size = 0; size_t size = 0;
size_t capacity = 16; /* Half of the default capacity */ size_t capacity = 16; // Half of the default capacity
do { do {
curchar = nextChar(); curchar = nextChar();
@@ -230,10 +230,10 @@ static struct LinkerScriptToken *nextToken(void)
errx("%s(%" PRIu32 "): Unterminated string", errx("%s(%" PRIu32 "): Unterminated string",
linkerScriptName, lineNo); linkerScriptName, lineNo);
} else if (curchar == '"') { } else if (curchar == '"') {
/* Quotes force a string termination */ // Quotes force a string termination
curchar = '\0'; curchar = '\0';
} else if (curchar == '\\') { } else if (curchar == '\\') {
/* Backslashes are escape sequences */ // Backslashes are escape sequences
curchar = nextChar(); curchar = nextChar();
if (curchar == EOF || isNewline(curchar)) if (curchar == EOF || isNewline(curchar))
errx("%s(%" PRIu32 "): Unterminated string", errx("%s(%" PRIu32 "): Unterminated string",
@@ -259,10 +259,10 @@ static struct LinkerScriptToken *nextToken(void)
token.attr.string[size++] = curchar; token.attr.string[size++] = curchar;
} while (curchar); } while (curchar);
} else { } 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; char *str = NULL;
size_t size = 0; size_t size = 0;
size_t capacity = 8; /* Half of the default capacity */ size_t capacity = 8; // Half of the default capacity
for (;;) { for (;;) {
if (size >= capacity || str == NULL) { if (size >= capacity || str == NULL) {
@@ -279,7 +279,7 @@ static struct LinkerScriptToken *nextToken(void)
break; break;
curchar = nextChar(); 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 == ';') { if (isWhiteSpace(curchar) || isNewline(curchar) || curchar == ';') {
ungetc(curchar, linkerScript); ungetc(curchar, linkerScript);
curchar = '\0'; curchar = '\0';
@@ -288,7 +288,7 @@ static struct LinkerScriptToken *nextToken(void)
token.type = TOKEN_INVALID; token.type = TOKEN_INVALID;
/* Try to match a command */ // Try to match a command
for (enum LinkerScriptCommand i = 0; i < COMMAND_INVALID; i++) { for (enum LinkerScriptCommand i = 0; i < COMMAND_INVALID; i++) {
if (!strcmp(commands[i], str)) { if (!strcmp(commands[i], str)) {
token.type = TOKEN_COMMAND; token.type = TOKEN_COMMAND;
@@ -298,7 +298,7 @@ static struct LinkerScriptToken *nextToken(void)
} }
if (token.type == TOKEN_INVALID) { 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++) { for (enum SectionType type = 0; type < SECTTYPE_INVALID; type++) {
if (!strcmp(sectionTypeInfo[type].name, str)) { if (!strcmp(sectionTypeInfo[type].name, str)) {
token.type = TOKEN_BANK; token.type = TOKEN_BANK;
@@ -309,13 +309,13 @@ static struct LinkerScriptToken *nextToken(void)
} }
if (token.type == TOKEN_INVALID) { if (token.type == TOKEN_INVALID) {
/* Try to match an include token */ // Try to match an include token
if (!strcmp("INCLUDE", str)) if (!strcmp("INCLUDE", str))
token.type = TOKEN_INCLUDE; token.type = TOKEN_INCLUDE;
} }
if (token.type == TOKEN_INVALID) { 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)) if (tryParseNumber(str, &token.attr.number))
token.type = TOKEN_NUMBER; token.type = TOKEN_NUMBER;
else else
@@ -354,14 +354,14 @@ static void processCommand(enum LinkerScriptCommand command, uint16_t arg, uint1
enum LinkerScriptParserState { enum LinkerScriptParserState {
PARSER_FIRSTTIME, PARSER_FIRSTTIME,
PARSER_LINESTART, PARSER_LINESTART,
PARSER_INCLUDE, /* After an INCLUDE token */ PARSER_INCLUDE, // After an INCLUDE token
PARSER_LINEEND 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]; 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; static enum LinkerScriptParserState parserState = PARSER_FIRSTTIME;
struct SectionPlacement *script_NextSection(void) struct SectionPlacement *script_NextSection(void)
@@ -373,7 +373,7 @@ struct SectionPlacement *script_NextSection(void)
if (parserState == PARSER_FIRSTTIME) { if (parserState == PARSER_FIRSTTIME) {
lineNo = 1; lineNo = 1;
/* Init PC for all banks */ // Init PC for all banks
for (enum SectionType i = 0; i < SECTTYPE_INVALID; i++) { for (enum SectionType i = 0; i < SECTTYPE_INVALID; i++) {
curaddr[i] = malloc(sizeof(*curaddr[i]) * nbbanks(i)); curaddr[i] = malloc(sizeof(*curaddr[i]) * nbbanks(i));
for (uint32_t b = 0; b < nbbanks(i); b++) for (uint32_t b = 0; b < nbbanks(i); b++)
@@ -427,7 +427,7 @@ struct SectionPlacement *script_NextSection(void)
lineNo++; lineNo++;
break; break;
/* A stray string is a section name */ // A stray string is a section name
case TOKEN_STRING: case TOKEN_STRING:
parserState = PARSER_LINEEND; parserState = PARSER_LINEEND;
@@ -454,15 +454,11 @@ struct SectionPlacement *script_NextSection(void)
token = nextToken(); token = nextToken();
hasArg = token->type == TOKEN_NUMBER; hasArg = token->type == TOKEN_NUMBER;
/* // Leaving `arg` uninitialized when `!hasArg` causes GCC to warn
* Leaving `arg` uninitialized when `!hasArg` // about its use as an argument to `processCommand`. This cannot
* causes GCC to warn about its use as an // happen because `hasArg` has to be true, but silence the warning
* argument to `processCommand`. This cannot // anyways. I dislike doing this because it could swallow actual
* happen because `hasArg` has to be true, but // errors, but I don't have a choice.
* 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; arg = hasArg ? token->attr.number : 0;
if (tokType == TOKEN_COMMAND) { if (tokType == TOKEN_COMMAND) {
@@ -474,12 +470,10 @@ struct SectionPlacement *script_NextSection(void)
linkerScriptName, lineNo); linkerScriptName, lineNo);
processCommand(attr.command, arg, &curaddr[placement.type][bankID]); processCommand(attr.command, arg, &curaddr[placement.type][bankID]);
} else { /* TOKEN_BANK */ } else { // TOKEN_BANK
placement.type = attr.secttype; placement.type = attr.secttype;
/* // If there's only one bank,
* If there's only one bank, // specifying the number is optional.
* specifying the number is optional.
*/
if (!hasArg && nbbanks(placement.type) != 1) if (!hasArg && nbbanks(placement.type) != 1)
errx("%s(%" PRIu32 "): Didn't specify a bank number", errx("%s(%" PRIu32 "): Didn't specify a bank number",
linkerScriptName, lineNo); linkerScriptName, lineNo);
@@ -497,7 +491,7 @@ struct SectionPlacement *script_NextSection(void)
bankID = arg - sectionTypeInfo[placement.type].firstBank; 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) if (token->type != TOKEN_NUMBER)
goto lineend; goto lineend;
break; break;
@@ -513,9 +507,9 @@ struct SectionPlacement *script_NextSection(void)
errx("%s(%" PRIu32 "): Expected a file name after INCLUDE", errx("%s(%" PRIu32 "): Expected a file name after INCLUDE",
linkerScriptName, lineNo); linkerScriptName, lineNo);
/* Switch to that file */ // Switch to that file
pushFile(token->attr.string); pushFile(token->attr.string);
/* The file stack took ownership of the string */ // The file stack took ownership of the string
token->attr.string = NULL; token->attr.string = NULL;
parserState = PARSER_LINESTART; parserState = PARSER_LINESTART;

View File

@@ -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 <assert.h>
#include <ctype.h> #include <ctype.h>

View File

@@ -166,7 +166,7 @@ static void mergeSections(struct Section *target, struct Section *other, enum Se
// `data` pointer, or a size of 0. // `data` pointer, or a size of 0.
if (other->data) { if (other->data) {
if (target->data) { if (target->data) {
/* Ensure we're not allocating 0 bytes */ // Ensure we're not allocating 0 bytes
target->data = realloc(target->data, target->data = realloc(target->data,
sizeof(*target->data) * target->size + 1); sizeof(*target->data) * target->size + 1);
if (!target->data) if (!target->data)
@@ -177,7 +177,7 @@ static void mergeSections(struct Section *target, struct Section *other, enum Se
target->data = other->data; target->data = other->data;
other->data = NULL; // Prevent a double free() other->data = NULL; // Prevent a double free()
} }
/* Adjust patches' PC offsets */ // Adjust patches' PC offsets
for (uint32_t patchID = 0; patchID < other->nbPatches; patchID++) for (uint32_t patchID = 0; patchID < other->nbPatches; patchID++)
other->patches[patchID].pcOffset += other->offset; other->patches[patchID].pcOffset += other->offset;
} else if (target->data) { } 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) 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); struct Section *other = hash_GetElement(sections, section->name);
if (other) { if (other) {
@@ -210,7 +210,7 @@ void sect_AddSection(struct Section *section)
errx("Section \"%s\" is of type %s, which cannot be unionized", errx("Section \"%s\" is of type %s, which cannot be unionized",
section->name, sectionTypeInfo[section->type].name); section->name, sectionTypeInfo[section->type].name);
} else { } else {
/* If not, add it */ // If not, add it
hash_AddElement(sections, section->name, section); hash_AddElement(sections, section->name, section);
} }
} }
@@ -229,7 +229,7 @@ static void doSanityChecks(struct Section *section, void *ptr)
{ {
(void)ptr; (void)ptr;
/* Sanity check the section's type */ // Sanity check the section's type
if (section->type < 0 || section->type >= SECTTYPE_INVALID) { if (section->type < 0 || section->type >= SECTTYPE_INVALID) {
error(NULL, 0, "Section \"%s\" has an invalid type", section->name); 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", error(NULL, 0, "%s: VRAM bank 1 can't be used with option -d",
section->name); section->name);
/* // Check if alignment is reasonable, this is important to avoid UB
* Check if alignment is reasonable, this is important to avoid UB // An alignment of zero is equivalent to no alignment, basically
* An alignment of zero is equivalent to no alignment, basically
*/
if (section->isAlignFixed && section->alignMask == 0) if (section->isAlignFixed && section->alignMask == 0)
section->isAlignFixed = false; 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)) if (section->isAlignFixed && (section->alignMask & sectionTypeInfo[section->type].startAddr))
error(NULL, 0, "%s: %s sections cannot be aligned to $%04x bytes", error(NULL, 0, "%s: %s sections cannot be aligned to $%04x bytes",
section->name, sectionTypeInfo[section->type].name, section->alignMask + 1); 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, : "Cannot place section \"%s\" in bank %" PRIu32 ", it must be between %" PRIu32 " and %" PRIu32,
section->name, section->bank, minbank, maxbank); 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) if (section->size > sectionTypeInfo[section->type].size)
error(NULL, 0, "Section \"%s\" is bigger than the max size for that type: %#" PRIx16 " > %#" PRIx16, error(NULL, 0, "Section \"%s\" is bigger than the max size for that type: %#" PRIx16 " > %#" PRIx16,
section->name, section->size, sectionTypeInfo[section->type].size); 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) { if (minbank == maxbank) {
section->bank = minbank; section->bank = minbank;
@@ -287,7 +285,7 @@ static void doSanityChecks(struct Section *section, void *ptr)
} }
if (section->isAddressFixed) { 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->isAlignFixed) {
if ((section->org & section->alignMask) != section->alignOfs) if ((section->org & section->alignMask) != section->alignOfs)
error(NULL, 0, "Section \"%s\"'s fixed address doesn't match its alignment", 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; section->isAlignFixed = false;
} }
/* Ensure the target address is valid */ // Ensure the target address is valid
if (section->org < sectionTypeInfo[section->type].startAddr if (section->org < sectionTypeInfo[section->type].startAddr
|| section->org > endaddr(section->type)) || section->org > endaddr(section->type))
error(NULL, 0, "Section \"%s\"'s fixed address %#" PRIx16 " is outside of range [%#" error(NULL, 0, "Section \"%s\"'s fixed address %#" PRIx16 " is outside of range [%#"

View File

@@ -40,7 +40,7 @@ void sym_ForEach(void (*callback)(struct Symbol *, void *), void *arg)
void sym_AddSymbol(struct Symbol *symbol) 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); struct Symbol *other = hash_GetElement(symbols, symbol->name);
if (other) { if (other) {
@@ -53,7 +53,7 @@ void sym_AddSymbol(struct Symbol *symbol)
exit(1); exit(1);
} }
/* If not, add it */ // If not, add it
hash_AddElement(symbols, symbol->name, symbol); hash_AddElement(symbols, symbol->name, symbol);
} }

View File

@@ -1,3 +1,10 @@
/*
* This file is part of RGBDS.
*
* Copyright (c) 2022, RGBDS contributors.
*
* SPDX-License-Identifier: MIT
*/
#include "linkdefs.h" #include "linkdefs.h"

View File

@@ -6,9 +6,7 @@
* SPDX-License-Identifier: MIT * 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> #include <stdint.h>

View File

@@ -1,3 +1,10 @@
/*
* This file is part of RGBDS.
*
* Copyright (c) 2022, Eldred Habert and RGBDS contributors.
*
* SPDX-License-Identifier: MIT
*/
// For `execProg` (Windows is its special little snowflake again) // For `execProg` (Windows is its special little snowflake again)
#if !defined(_MSC_VER) && !defined(__MINGW32__) #if !defined(_MSC_VER) && !defined(__MINGW32__)
@@ -125,7 +132,7 @@ public:
Rgba const &pixel(uint32_t x, uint32_t y) const { return pixels[y * width + x]; } Rgba const &pixel(uint32_t x, uint32_t y) const { return pixels[y * width + x]; }
/** /*
* Reads a PNG and notes all of its colors * Reads a PNG and notes all of its colors
* *
* This code is more complicated than strictly necessary, but that's because of the API * This code is more complicated than strictly necessary, but that's because of the API
@@ -298,7 +305,7 @@ static char *execProg(char const *name, char * const *argv) {
fatal("%s returned with status %d", name, info.si_status); fatal("%s returned with status %d", name, info.si_status);
} }
#else /* defined(_MSC_VER) || defined(__MINGW32__) */ #else // defined(_MSC_VER) || defined(__MINGW32__)
auto winStrerror = [](DWORD errnum) { auto winStrerror = [](DWORD errnum) {
LPTSTR buf; LPTSTR buf;