diff --git a/include/platform.hpp b/include/platform.hpp index dd383b03..381234a6 100644 --- a/include/platform.hpp +++ b/include/platform.hpp @@ -19,7 +19,7 @@ #ifdef _MSC_VER #define S_IFMT _S_IFMT #define S_IFDIR _S_IFDIR - #define S_ISDIR(mode) (((mode)&S_IFMT) == S_IFDIR) + #define S_ISDIR(mode) (((mode) & S_IFMT) == S_IFDIR) #endif // gcc has __PRETTY_FUNCTION__, MSVC has __FUNCSIG__, __func__ is standard @@ -49,7 +49,7 @@ #ifdef _MSC_VER #include #define O_RDWR _O_RDWR - #define S_ISREG(field) ((field)&_S_IFREG) + #define S_ISREG(field) ((field) & _S_IFREG) #define O_BINARY _O_BINARY #define O_TEXT _O_TEXT #elif !defined(O_BINARY) // Cross-compilers define O_BINARY diff --git a/src/asm/fixpoint.cpp b/src/asm/fixpoint.cpp index 2ff336d8..98962b64 100644 --- a/src/asm/fixpoint.cpp +++ b/src/asm/fixpoint.cpp @@ -15,13 +15,6 @@ #define M_PI 3.14159265358979323846 #endif -#define fix2double(i, q) ((double)((i) / pow(2.0, q))) -#define double2fix(d, q) ((int32_t)round((d)*pow(2.0, q))) - -// 2*pi radians == 1 turn -#define turn2rad(f) ((f) * (M_PI * 2)) -#define rad2turn(r) ((r) / (M_PI * 2)) - uint8_t fixPrecision; uint8_t fix_Precision() { @@ -32,6 +25,22 @@ double fix_PrecisionFactor() { return pow(2.0, fixPrecision); } +static double fix2double(int32_t i, int32_t q) { + return i / pow(2.0, q); +} + +static int32_t double2fix(double d, int32_t q) { + return (int32_t)round(d * pow(2.0, q)); +} + +static double turn2rad(double t) { + return t * (M_PI * 2); +} + +static double rad2turn(double r) { + return r / (M_PI * 2); +} + int32_t fix_Sin(int32_t i, int32_t q) { return double2fix(sin(turn2rad(fix2double(i, q))), q); } diff --git a/src/asm/lexer.cpp b/src/asm/lexer.cpp index 67501c55..820f453b 100644 --- a/src/asm/lexer.cpp +++ b/src/asm/lexer.cpp @@ -50,48 +50,49 @@ #include // MapViewOfFile #include // CloseHandle // clang-format on + #define MAP_FAILED nullptr - #define mapFile(ptr, fd, path, size) \ - do { \ - (ptr) = MAP_FAILED; \ - HANDLE file = CreateFileA( \ - path, \ - GENERIC_READ, \ - FILE_SHARE_READ, \ - nullptr, \ - OPEN_EXISTING, \ - FILE_FLAG_POSIX_SEMANTICS | FILE_FLAG_RANDOM_ACCESS, \ - nullptr \ - ); \ - HANDLE mappingObj; \ - if (file == INVALID_HANDLE_VALUE) \ - break; \ - mappingObj = CreateFileMappingA(file, nullptr, PAGE_READONLY, 0, 0, nullptr); \ - if (mappingObj != INVALID_HANDLE_VALUE) \ - (ptr) = MapViewOfFile(mappingObj, FILE_MAP_READ, 0, 0, 0); \ - CloseHandle(mappingObj); \ - CloseHandle(file); \ - } while (0) - #define munmap(ptr, size) UnmapViewOfFile((ptr)) + +static void mapFile(void *&mappingAddr, int fd, char const *path, size_t) { + mappingAddr = MAP_FAILED; + HANDLE file = CreateFileA( + path, + GENERIC_READ, + FILE_SHARE_READ, + nullptr, + OPEN_EXISTING, + FILE_FLAG_POSIX_SEMANTICS | FILE_FLAG_RANDOM_ACCESS, + nullptr + ); + HANDLE mappingObj; + if (file == INVALID_HANDLE_VALUE) + return; + mappingObj = CreateFileMappingA(file, nullptr, PAGE_READONLY, 0, 0, nullptr); + if (mappingObj != INVALID_HANDLE_VALUE) + mappingAddr = MapViewOfFile(mappingObj, FILE_MAP_READ, 0, 0, 0); + CloseHandle(mappingObj); + CloseHandle(file); +} + +static int munmap(void *mappingAddr, size_t) { + return UnmapViewOfFile(mappingAddr) == 0 ? -1 : 0; +} #else // defined(_MSC_VER) || defined(__MINGW32__) - #include - #define mapFile(ptr, fd, path, size) \ - do { \ - (ptr) = mmap(nullptr, (size), PROT_READ, MAP_PRIVATE, (fd), 0); \ - if ((ptr) == MAP_FAILED && errno == ENOTSUP) { \ - /* \ - * The implementation may not support MAP_PRIVATE; try again with MAP_SHARED \ - * instead, offering, I believe, weaker guarantees about external modifications to \ - * the file while reading it. That's still better than not opening it at all, \ - * though \ - */ \ - if (verbose) \ - printf("mmap(%s, MAP_PRIVATE) failed, retrying with MAP_SHARED\n", path); \ - (ptr) = mmap(nullptr, (size), PROT_READ, MAP_SHARED, (fd), 0); \ - } \ - } while (0) + +static void mapFile(void *&mappingAddr, int fd, char const *path, size_t size) { + mappingAddr = mmap(nullptr, size, PROT_READ, MAP_PRIVATE, fd, 0); + if (mappingAddr == MAP_FAILED && errno == ENOTSUP) { + // The implementation may not support MAP_PRIVATE; try again with MAP_SHARED + // instead, offering, I believe, weaker guarantees about external modifications to + // the file while reading it. That's still better than not opening it at all, though. + if (verbose) + printf("mmap(%s, MAP_PRIVATE) failed, retrying with MAP_SHARED\n", path); + mappingAddr = mmap(nullptr, size, PROT_READ, MAP_SHARED, fd, 0); + } +} + #endif // !( defined(_MSC_VER) || defined(__MINGW32__) ) // Bison 3.6 changed token "types" to "kinds"; cast to int for simple compatibility diff --git a/src/asm/symbol.cpp b/src/asm/symbol.cpp index fe9d7f11..e2d4812c 100644 --- a/src/asm/symbol.cpp +++ b/src/asm/symbol.cpp @@ -583,21 +583,12 @@ void sym_Init(time_t now) { sym_AddVar("_RS", 0)->isBuiltin = true; -#define addSym(fn, name, val) \ - do { \ - Symbol *sym = fn(name, val); \ - assert(sym); \ - sym->isBuiltin = true; \ - } while (0) -#define addNumber(name, val) addSym(sym_AddEqu, name, val) -#define addString(name, val) addSym(sym_AddString, name, val) - - addString("__RGBDS_VERSION__", get_package_version_string()); - addNumber("__RGBDS_MAJOR__", PACKAGE_VERSION_MAJOR); - addNumber("__RGBDS_MINOR__", PACKAGE_VERSION_MINOR); - addNumber("__RGBDS_PATCH__", PACKAGE_VERSION_PATCH); + sym_AddString("__RGBDS_VERSION__", get_package_version_string())->isBuiltin = true; + sym_AddEqu("__RGBDS_MAJOR__", PACKAGE_VERSION_MAJOR)->isBuiltin = true; + sym_AddEqu("__RGBDS_MINOR__", PACKAGE_VERSION_MINOR)->isBuiltin = true; + sym_AddEqu("__RGBDS_PATCH__", PACKAGE_VERSION_PATCH)->isBuiltin = true; #ifdef PACKAGE_VERSION_RC - addNumber("__RGBDS_RC__", PACKAGE_VERSION_RC); + sym_AddEqu("__RGBDS_RC__", PACKAGE_VERSION_RC)->isBuiltin = true; #endif if (now == (time_t)-1) { @@ -626,21 +617,17 @@ void sym_Init(time_t now) { time_utc ); - addString("__TIME__", savedTIME); - addString("__DATE__", savedDATE); - addString("__ISO_8601_LOCAL__", savedTIMESTAMP_ISO8601_LOCAL); - addString("__ISO_8601_UTC__", savedTIMESTAMP_ISO8601_UTC); + sym_AddString("__TIME__", savedTIME)->isBuiltin = true; + sym_AddString("__DATE__", savedDATE)->isBuiltin = true; + sym_AddString("__ISO_8601_LOCAL__", savedTIMESTAMP_ISO8601_LOCAL)->isBuiltin = true; + sym_AddString("__ISO_8601_UTC__", savedTIMESTAMP_ISO8601_UTC)->isBuiltin = true; - addNumber("__UTC_YEAR__", time_utc->tm_year + 1900); - addNumber("__UTC_MONTH__", time_utc->tm_mon + 1); - addNumber("__UTC_DAY__", time_utc->tm_mday); - addNumber("__UTC_HOUR__", time_utc->tm_hour); - addNumber("__UTC_MINUTE__", time_utc->tm_min); - addNumber("__UTC_SECOND__", time_utc->tm_sec); - -#undef addNumber -#undef addString -#undef addSym + sym_AddEqu("__UTC_YEAR__", time_utc->tm_year + 1900)->isBuiltin = true; + sym_AddEqu("__UTC_MONTH__", time_utc->tm_mon + 1)->isBuiltin = true; + sym_AddEqu("__UTC_DAY__", time_utc->tm_mday)->isBuiltin = true; + sym_AddEqu("__UTC_HOUR__", time_utc->tm_hour)->isBuiltin = true; + sym_AddEqu("__UTC_MINUTE__", time_utc->tm_min)->isBuiltin = true; + sym_AddEqu("__UTC_SECOND__", time_utc->tm_sec)->isBuiltin = true; labelScope = std::nullopt; anonLabelID = 0; diff --git a/src/fix/main.cpp b/src/fix/main.cpp index 6fd4ad31..f1ea4073 100644 --- a/src/fix/main.cpp +++ b/src/fix/main.cpp @@ -1218,36 +1218,38 @@ finish: return nbErrors; } +static void parseByte(uint16_t &output, char name) { + if (musl_optarg[0] == 0) { + report("error: Argument to option '%c' may not be empty\n", name); + } else { + char *endptr; + unsigned long value; + + if (musl_optarg[0] == '$') { + value = strtoul(&musl_optarg[1], &endptr, 16); + } else { + value = strtoul(musl_optarg, &endptr, 0); + } + if (*endptr) { + report( + "error: Expected number as argument to option '%c', got %s\n", + name, + musl_optarg + ); + } else if (value > 0xFF) { + report("error: Argument to option '%c' is larger than 255: %lu\n", name, value); + } else { + output = value; + } + } +} + int main(int argc, char *argv[]) { nbErrors = 0; for (int ch; (ch = musl_getopt_long_only(argc, argv, optstring, longopts, nullptr)) != -1;) { switch (ch) { size_t len; -#define parseByte(output, name) \ - do { \ - char *endptr; \ - unsigned long tmp; \ -\ - if (musl_optarg[0] == 0) { \ - report("error: Argument to option '" name "' may not be empty\n"); \ - } else { \ - if (musl_optarg[0] == '$') { \ - tmp = strtoul(&musl_optarg[1], &endptr, 16); \ - } else { \ - tmp = strtoul(musl_optarg, &endptr, 0); \ - } \ - if (*endptr) \ - report( \ - "error: Expected number as argument to option '" name "', got %s\n", \ - musl_optarg \ - ); \ - else if (tmp > 0xFF) \ - report("error: Argument to option '" name "' is larger than 255: %lu\n", tmp); \ - else \ - output = tmp; \ - } \ - } while (0) case 'C': case 'c': @@ -1334,7 +1336,7 @@ int main(int argc, char *argv[]) { break; case 'l': - parseByte(oldLicensee, "l"); + parseByte(oldLicensee, 'l'); break; case 'm': @@ -1360,7 +1362,7 @@ int main(int argc, char *argv[]) { break; case 'n': - parseByte(romVersion, "n"); + parseByte(romVersion, 'n'); break; case 'O': @@ -1368,11 +1370,11 @@ int main(int argc, char *argv[]) { break; case 'p': - parseByte(padValue, "p"); + parseByte(padValue, 'p'); break; case 'r': - parseByte(ramSize, "r"); + parseByte(ramSize, 'r'); break; case 's': @@ -1405,7 +1407,6 @@ int main(int argc, char *argv[]) { printUsage(); exit(1); } -#undef parseByte } if ((cartridgeType & 0xFF00) == TPP1 && !japanese) diff --git a/src/link/patch.cpp b/src/link/patch.cpp index 289a52bf..452b753a 100644 --- a/src/link/patch.cpp +++ b/src/link/patch.cpp @@ -35,9 +35,9 @@ static void pushRPN(int32_t value, bool comesFromError) { // has popped any values with the error flag set. static bool isError = false; -static int32_t popRPN(FileStackNode const *node, uint32_t lineNo) { +static int32_t popRPN(Patch const &patch) { if (rpnStack.empty()) - fatal(node, lineNo, "Internal error, RPN stack empty"); + fatal(patch.src, patch.lineNo, "Internal error, RPN stack empty"); RPNStackEntry entry = rpnStack.front(); @@ -48,11 +48,9 @@ static int32_t popRPN(FileStackNode const *node, uint32_t lineNo) { // RPN operators -static uint32_t getRPNByte( - uint8_t const *&expression, int32_t &size, FileStackNode const *node, uint32_t lineNo -) { +static uint32_t getRPNByte(uint8_t const *&expression, int32_t &size, Patch const &patch) { if (!size--) - fatal(node, lineNo, "Internal error, RPN expression overread"); + fatal(patch.src, patch.lineNo, "Internal error, RPN expression overread"); return *expression++; } @@ -77,8 +75,6 @@ static Symbol const *getSymbol(std::vector const &symbolList, uint32_t i * errors caused by the value should be suppressed. */ static int32_t computeRPNExpr(Patch const &patch, std::vector const &fileSymbols) { -// Small shortcut to avoid a lot of repetition -#define popRPN() popRPN(patch.src, patch.lineNo) uint8_t const *expression = patch.rpnExpression.data(); int32_t size = (int32_t)patch.rpnExpression.size(); @@ -87,7 +83,7 @@ static int32_t computeRPNExpr(Patch const &patch, std::vector const &fil while (size > 0) { enum RPNCommand command = - (enum RPNCommand)getRPNByte(expression, size, patch.src, patch.lineNo); + (enum RPNCommand)getRPNByte(expression, size, patch); int32_t value; isError = false; @@ -102,120 +98,120 @@ static int32_t computeRPNExpr(Patch const &patch, std::vector const &fil Section const *sect; case RPN_ADD: - value = popRPN() + popRPN(); + value = popRPN(patch) + popRPN(patch); break; case RPN_SUB: - value = popRPN(); - value = popRPN() - value; + value = popRPN(patch); + value = popRPN(patch) - value; break; case RPN_MUL: - value = popRPN() * popRPN(); + value = popRPN(patch) * popRPN(patch); break; case RPN_DIV: - value = popRPN(); + value = popRPN(patch); if (value == 0) { if (!isError) error(patch.src, patch.lineNo, "Division by 0"); isError = true; - popRPN(); + popRPN(patch); value = INT32_MAX; } else { - value = op_divide(popRPN(), value); + value = op_divide(popRPN(patch), value); } break; case RPN_MOD: - value = popRPN(); + value = popRPN(patch); if (value == 0) { if (!isError) error(patch.src, patch.lineNo, "Modulo by 0"); isError = true; - popRPN(); + popRPN(patch); value = 0; } else { - value = op_modulo(popRPN(), value); + value = op_modulo(popRPN(patch), value); } break; case RPN_NEG: - value = -popRPN(); + value = -popRPN(patch); break; case RPN_EXP: - value = popRPN(); + value = popRPN(patch); if (value < 0) { if (!isError) error(patch.src, patch.lineNo, "Exponent by negative"); isError = true; - popRPN(); + popRPN(patch); value = 0; } else { - value = op_exponent(popRPN(), value); + value = op_exponent(popRPN(patch), value); } break; case RPN_OR: - value = popRPN() | popRPN(); + value = popRPN(patch) | popRPN(patch); break; case RPN_AND: - value = popRPN() & popRPN(); + value = popRPN(patch) & popRPN(patch); break; case RPN_XOR: - value = popRPN() ^ popRPN(); + value = popRPN(patch) ^ popRPN(patch); break; case RPN_NOT: - value = ~popRPN(); + value = ~popRPN(patch); break; case RPN_LOGAND: - value = popRPN(); - value = popRPN() && value; + value = popRPN(patch); + value = popRPN(patch) && value; break; case RPN_LOGOR: - value = popRPN(); - value = popRPN() || value; + value = popRPN(patch); + value = popRPN(patch) || value; break; case RPN_LOGNOT: - value = !popRPN(); + value = !popRPN(patch); break; case RPN_LOGEQ: - value = popRPN() == popRPN(); + value = popRPN(patch) == popRPN(patch); break; case RPN_LOGNE: - value = popRPN() != popRPN(); + value = popRPN(patch) != popRPN(patch); break; case RPN_LOGGT: - value = popRPN(); - value = popRPN() > value; + value = popRPN(patch); + value = popRPN(patch) > value; break; case RPN_LOGLT: - value = popRPN(); - value = popRPN() < value; + value = popRPN(patch); + value = popRPN(patch) < value; break; case RPN_LOGGE: - value = popRPN(); - value = popRPN() >= value; + value = popRPN(patch); + value = popRPN(patch) >= value; break; case RPN_LOGLE: - value = popRPN(); - value = popRPN() <= value; + value = popRPN(patch); + value = popRPN(patch) <= value; break; case RPN_SHL: - value = popRPN(); - value = op_shift_left(popRPN(), value); + value = popRPN(patch); + value = op_shift_left(popRPN(patch), value); break; case RPN_SHR: - value = popRPN(); - value = op_shift_right(popRPN(), value); + value = popRPN(patch); + value = op_shift_right(popRPN(patch), value); break; case RPN_USHR: - value = popRPN(); - value = op_shift_right_unsigned(popRPN(), value); + value = popRPN(patch); + value = op_shift_right_unsigned(popRPN(patch), value); break; case RPN_BANK_SYM: value = 0; for (uint8_t shift = 0; shift < 32; shift += 8) - value |= getRPNByte(expression, size, patch.src, patch.lineNo) << shift; + value |= getRPNByte(expression, size, patch) << shift; symbol = getSymbol(fileSymbols, value); if (!symbol) { @@ -245,7 +241,7 @@ static int32_t computeRPNExpr(Patch const &patch, std::vector const &fil // `expression` is not guaranteed to be '\0'-terminated. If it is not, // `getRPNByte` will have a fatal internal error. name = (char const *)expression; - while (getRPNByte(expression, size, patch.src, patch.lineNo)) + while (getRPNByte(expression, size, patch)) ; sect = sect_GetSection(name); @@ -277,7 +273,7 @@ static int32_t computeRPNExpr(Patch const &patch, std::vector const &fil case RPN_SIZEOF_SECT: // This has assumptions commented in the `RPN_BANK_SECT` case above. name = (char const *)expression; - while (getRPNByte(expression, size, patch.src, patch.lineNo)) + while (getRPNByte(expression, size, patch)) ; sect = sect_GetSection(name); @@ -299,7 +295,7 @@ static int32_t computeRPNExpr(Patch const &patch, std::vector const &fil case RPN_STARTOF_SECT: // This has assumptions commented in the `RPN_BANK_SECT` case above. name = (char const *)expression; - while (getRPNByte(expression, size, patch.src, patch.lineNo)) + while (getRPNByte(expression, size, patch)) ; sect = sect_GetSection(name); @@ -320,7 +316,7 @@ static int32_t computeRPNExpr(Patch const &patch, std::vector const &fil break; case RPN_SIZEOF_SECTTYPE: - value = getRPNByte(expression, size, patch.src, patch.lineNo); + value = getRPNByte(expression, size, patch); if (value < 0 || value >= SECTTYPE_INVALID) { error(patch.src, patch.lineNo, "Requested SIZEOF() an invalid section type"); isError = true; @@ -331,7 +327,7 @@ static int32_t computeRPNExpr(Patch const &patch, std::vector const &fil break; case RPN_STARTOF_SECTTYPE: - value = getRPNByte(expression, size, patch.src, patch.lineNo); + value = getRPNByte(expression, size, patch); if (value < 0 || value >= SECTTYPE_INVALID) { error(patch.src, patch.lineNo, "Requested STARTOF() an invalid section type"); isError = true; @@ -342,7 +338,7 @@ static int32_t computeRPNExpr(Patch const &patch, std::vector const &fil break; case RPN_HRAM: - value = popRPN(); + value = popRPN(patch); if (!isError && (value < 0 || (value > 0xFF && value < 0xFF00) || value > 0xFFFF)) { error(patch.src, patch.lineNo, "Value %" PRId32 " is not in HRAM range", value); isError = true; @@ -351,7 +347,7 @@ static int32_t computeRPNExpr(Patch const &patch, std::vector const &fil break; case RPN_RST: - value = popRPN(); + value = popRPN(patch); // Acceptable values are 0x00, 0x08, 0x10, ..., 0x38 // They can be easily checked with a bitmask if (value & ~0x38) { @@ -365,13 +361,13 @@ static int32_t computeRPNExpr(Patch const &patch, std::vector const &fil case RPN_CONST: value = 0; for (uint8_t shift = 0; shift < 32; shift += 8) - value |= getRPNByte(expression, size, patch.src, patch.lineNo) << shift; + value |= getRPNByte(expression, size, patch) << shift; break; case RPN_SYM: value = 0; for (uint8_t shift = 0; shift < 32; shift += 8) - value |= getRPNByte(expression, size, patch.src, patch.lineNo) << shift; + value |= getRPNByte(expression, size, patch) << shift; if (value == -1) { // PC if (!patch.pcSection) { @@ -414,9 +410,7 @@ static int32_t computeRPNExpr(Patch const &patch, std::vector const &fil error(patch.src, patch.lineNo, "RPN stack has %zu entries on exit, not 1", rpnStack.size()); isError = false; - return popRPN(); - -#undef popRPN + return popRPN(patch); } void patch_CheckAssertions(std::deque &assertions) {