Reorganize the asm parser to be more like the linker script parser

Split the declarations into those required for the `%union` and
those only required for the `code`.
Only declare functions on top; define them at the bottom.
This commit is contained in:
Rangi42
2024-02-29 16:17:55 -05:00
parent 043db49676
commit 91d22f180e
3 changed files with 481 additions and 455 deletions

View File

@@ -4,8 +4,6 @@
#define RGBDS_FORMAT_SPEC_H #define RGBDS_FORMAT_SPEC_H
#include <stdint.h> #include <stdint.h>
#include <variant>
#include <vector>
enum FormatState { enum FormatState {
FORMAT_SIGN, // expects '+' or ' ' (optional) FORMAT_SIGN, // expects '+' or ' ' (optional)
@@ -30,11 +28,6 @@ struct FormatSpec {
bool valid; bool valid;
}; };
struct StrFmtArgList {
char *format;
std::vector<std::variant<uint32_t, char *>> *args;
};
FormatSpec fmt_NewSpec(void); FormatSpec fmt_NewSpec(void);
bool fmt_IsEmpty(FormatSpec const *fmt); bool fmt_IsEmpty(FormatSpec const *fmt);
bool fmt_IsValid(FormatSpec const *fmt); bool fmt_IsValid(FormatSpec const *fmt);

View File

@@ -149,9 +149,4 @@ int yylex(void);
bool lexer_CaptureRept(CaptureBody *capture); bool lexer_CaptureRept(CaptureBody *capture);
bool lexer_CaptureMacroBody(CaptureBody *capture); bool lexer_CaptureMacroBody(CaptureBody *capture);
struct AlignmentSpec {
uint8_t alignment;
uint16_t alignOfs;
};
#endif // RGBDS_ASM_LEXER_H #endif // RGBDS_ASM_LEXER_H

View File

@@ -1,412 +1,88 @@
/* SPDX-License-Identifier: MIT */ /* SPDX-License-Identifier: MIT */
%{ %code requires {
#include <ctype.h> #include <stdint.h>
#include <errno.h> #include <inttypes.h>
#include <inttypes.h> #include <string>
#include <new> #include <variant>
#include <stdint.h> #include <vector>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "asm/charmap.hpp" #include "asm/format.hpp"
#include "asm/fixpoint.hpp" #include "asm/lexer.hpp"
#include "asm/format.hpp" #include "asm/macro.hpp"
#include "asm/fstack.hpp" #include "asm/rpn.hpp"
#include "asm/lexer.hpp" #include "asm/symbol.hpp"
#include "asm/macro.hpp"
#include "asm/main.hpp"
#include "asm/opt.hpp"
#include "asm/output.hpp"
#include "asm/rpn.hpp"
#include "asm/section.hpp"
#include "asm/symbol.hpp"
#include "util.hpp"
#include "asm/warning.hpp"
#include "extern/utf8decoder.hpp" #include "linkdefs.hpp"
#include "helpers.hpp" struct AlignmentSpec {
#include "linkdefs.hpp" uint8_t alignment;
#include "platform.hpp" // strncasecmp, strdup uint16_t alignOfs;
};
static CaptureBody captureBody; // Captures a REPT/FOR or MACRO struct ForArgs {
int32_t start;
int32_t stop;
int32_t step;
};
static void upperstring(char *dest, char const *src) struct StrFmtArgList {
{ char *format;
while (*src) std::vector<std::variant<uint32_t, char *>> *args;
*dest++ = toupper(*src++); };
*dest = '\0';
} }
%code {
static void lowerstring(char *dest, char const *src) #include <ctype.h>
{ #include <errno.h>
while (*src) #include <new>
*dest++ = tolower(*src++); #include <stdio.h>
*dest = '\0'; #include <stdlib.h>
} #include <string.h>
static uint32_t str2int2(std::vector<uint8_t> const &s) #include "asm/charmap.hpp"
{ #include "asm/fixpoint.hpp"
uint32_t length = s.size(); #include "asm/fstack.hpp"
#include "asm/main.hpp"
if (length > 4) #include "asm/opt.hpp"
warning(WARNING_NUMERIC_STRING_1, #include "asm/output.hpp"
"Treating string as a number ignores first %" PRIu32 " character%s\n", #include "asm/section.hpp"
length - 4, length == 5 ? "" : "s"); #include "util.hpp"
else if (length > 1) #include "asm/warning.hpp"
warning(WARNING_NUMERIC_STRING_2,
"Treating %" PRIu32 "-character string as a number\n", length); #include "extern/utf8decoder.hpp"
uint32_t r = 0; #include "helpers.hpp"
#include "platform.hpp" // strncasecmp, strdup
for (uint32_t i = length < 4 ? 0 : length - 4; i < length; i++) {
r <<= 8; static CaptureBody captureBody; // Captures a REPT/FOR or MACRO
r |= s[i];
} static void upperstring(char *dest, char const *src);
static void lowerstring(char *dest, char const *src);
return r; static uint32_t str2int2(std::vector<uint8_t> const &s);
} static const char *strrstr(char const *s1, char const *s2);
static void errorInvalidUTF8Byte(uint8_t byte, char const *functionName);
static const char *strrstr(char const *s1, char const *s2) static size_t strlenUTF8(char const *s);
{ static void strsubUTF8(char *dest, size_t destLen, char const *src, uint32_t pos,
size_t len1 = strlen(s1); uint32_t len);
size_t len2 = strlen(s2); static size_t charlenUTF8(char const *s);
static void charsubUTF8(char *dest, char const *src, uint32_t pos);
if (len2 > len1) static uint32_t adjustNegativePos(int32_t pos, size_t len, char const *functionName);
return nullptr; static void strrpl(char *dest, size_t destLen, char const *src, char const *old,
char const *rep);
for (char const *p = s1 + len1 - len2; p >= s1; p--) static void initStrFmtArgList(StrFmtArgList *args);
if (!strncmp(p, s2, len2)) static void freeStrFmtArgList(StrFmtArgList *args);
return p; static void strfmt(char *dest, size_t destLen, char const *fmt,
std::vector<std::variant<uint32_t, char *>> &args);
return nullptr; static void compoundAssignment(const char *symName, enum RPNCommand op, int32_t constValue);
} static void initDsArgList(std::vector<Expression> *&args);
static void initPurgeArgList(std::vector<std::string> *&args);
static void errorInvalidUTF8Byte(uint8_t byte, char const *functionName) static void failAssert(enum AssertionType type);
{ static void failAssertMsg(enum AssertionType type, char const *msg);
error("%s: Invalid UTF-8 byte 0x%02hhX\n", functionName, byte); void yyerror(char const *str);
}
// The CPU encodes instructions in a logical way, so most instructions actually follow patterns.
static size_t strlenUTF8(char const *s) // These enums thus help with bit twiddling to compute opcodes
{ enum {
size_t len = 0;
uint32_t state = 0;
for (uint32_t codep = 0; *s; s++) {
uint8_t byte = *s;
switch (decode(&state, &codep, byte)) {
case 1:
errorInvalidUTF8Byte(byte, "STRLEN");
state = 0;
// fallthrough
case 0:
len++;
break;
}
}
// Check for partial code point.
if (state != 0)
error("STRLEN: Incomplete UTF-8 character\n");
return len;
}
static void strsubUTF8(char *dest, size_t destLen, char const *src, uint32_t pos, uint32_t len)
{
size_t srcIndex = 0;
size_t destIndex = 0;
uint32_t state = 0;
uint32_t codep = 0;
uint32_t curLen = 0;
uint32_t curPos = 1;
// Advance to starting position in source string.
while (src[srcIndex] && curPos < pos) {
switch (decode(&state, &codep, src[srcIndex])) {
case 1:
errorInvalidUTF8Byte(src[srcIndex], "STRSUB");
state = 0;
// fallthrough
case 0:
curPos++;
break;
}
srcIndex++;
}
// A position 1 past the end of the string is allowed, but will trigger the
// "Length too big" warning below if the length is nonzero.
if (!src[srcIndex] && pos > curPos)
warning(WARNING_BUILTIN_ARG,
"STRSUB: Position %" PRIu32 " is past the end of the string\n", pos);
// Copy from source to destination.
while (src[srcIndex] && destIndex < destLen - 1 && curLen < len) {
switch (decode(&state, &codep, src[srcIndex])) {
case 1:
errorInvalidUTF8Byte(src[srcIndex], "STRSUB");
state = 0;
// fallthrough
case 0:
curLen++;
break;
}
dest[destIndex++] = src[srcIndex++];
}
if (curLen < len)
warning(WARNING_BUILTIN_ARG, "STRSUB: Length too big: %" PRIu32 "\n", len);
// Check for partial code point.
if (state != 0)
error("STRSUB: Incomplete UTF-8 character\n");
dest[destIndex] = '\0';
}
static size_t charlenUTF8(char const *s)
{
size_t len;
for (len = 0; charmap_ConvertNext(&s, nullptr); len++)
;
return len;
}
static void charsubUTF8(char *dest, char const *src, uint32_t pos)
{
size_t charLen = 1;
// Advance to starting position in source string.
for (uint32_t curPos = 1; charLen && curPos < pos; curPos++)
charLen = charmap_ConvertNext(&src, nullptr);
char const *start = src;
if (!charmap_ConvertNext(&src, nullptr))
warning(WARNING_BUILTIN_ARG,
"CHARSUB: Position %" PRIu32 " is past the end of the string\n", pos);
// Copy from source to destination.
memcpy(dest, start, src - start);
dest[src - start] = '\0';
}
static uint32_t adjustNegativePos(int32_t pos, size_t len, char const *functionName)
{
// STRSUB and CHARSUB adjust negative `pos` arguments the same way,
// such that position -1 is the last character of a string.
if (pos < 0)
pos += len + 1;
if (pos < 1) {
warning(WARNING_BUILTIN_ARG, "%s: Position starts at 1\n", functionName);
pos = 1;
}
return (uint32_t)pos;
}
static void strrpl(char *dest, size_t destLen, char const *src, char const *old, char const *rep)
{
size_t oldLen = strlen(old);
size_t repLen = strlen(rep);
size_t i = 0;
if (!oldLen) {
warning(WARNING_EMPTY_STRRPL, "STRRPL: Cannot replace an empty string\n");
strcpy(dest, src);
return;
}
for (char const *next = strstr(src, old); next && *next; next = strstr(src, old)) {
// Copy anything before the substring to replace
unsigned int lenBefore = next - src;
memcpy(dest + i, src, lenBefore < destLen - i ? lenBefore : destLen - i);
i += next - src;
if (i >= destLen)
break;
// Copy the replacement substring
memcpy(dest + i, rep, repLen < destLen - i ? repLen : destLen - i);
i += repLen;
if (i >= destLen)
break;
src = next + oldLen;
}
if (i < destLen) {
size_t srcLen = strlen(src);
// Copy anything after the last replaced substring
memcpy(dest + i, src, srcLen < destLen - i ? srcLen : destLen - i);
i += srcLen;
}
if (i >= destLen) {
warning(WARNING_LONG_STR, "STRRPL: String too long, got truncated\n");
i = destLen - 1;
}
dest[i] = '\0';
}
static void initStrFmtArgList(StrFmtArgList *args)
{
args->args = new(std::nothrow) std::vector<std::variant<uint32_t, char *>>();
if (!args->args)
fatalerror("Failed to allocate memory for STRFMT arg list: %s\n",
strerror(errno));
}
static void freeStrFmtArgList(StrFmtArgList *args)
{
free(args->format);
for (std::variant<uint32_t, char *> &arg : *args->args) {
if (char **str = std::get_if<char *>(&arg); str)
free(*str);
}
delete args->args;
}
static void strfmt(char *dest, size_t destLen, char const *fmt,
std::vector<std::variant<uint32_t, char *>> &args)
{
size_t a = 0;
size_t i = 0;
while (i < destLen) {
int c = *fmt++;
if (c == '\0') {
break;
} else if (c != '%') {
dest[i++] = c;
continue;
}
c = *fmt++;
if (c == '%') {
dest[i++] = c;
continue;
}
FormatSpec spec = fmt_NewSpec();
while (c != '\0') {
fmt_UseCharacter(&spec, c);
if (fmt_IsFinished(&spec))
break;
c = *fmt++;
}
if (fmt_IsEmpty(&spec)) {
error("STRFMT: Illegal '%%' at end of format string\n");
dest[i++] = '%';
break;
} else if (!fmt_IsValid(&spec)) {
error("STRFMT: Invalid format spec for argument %zu\n", a + 1);
dest[i++] = '%';
a++;
continue;
} else if (a >= args.size()) {
// Will warn after formatting is done.
dest[i++] = '%';
a++;
continue;
}
std::variant<uint32_t, char *> &arg = args[a++];
static char buf[MAXSTRLEN + 1];
std::visit(Visitor{
[&](uint32_t num) { fmt_PrintNumber(buf, sizeof(buf), &spec, num); },
[&](char *str) { fmt_PrintString(buf, sizeof(buf), &spec, str); },
}, arg);
i += snprintf(&dest[i], destLen - i, "%s", buf);
}
if (a < args.size())
error("STRFMT: %zu unformatted argument(s)\n", args.size() - a);
else if (a > args.size())
error("STRFMT: Not enough arguments for format spec, got: %zu, need: %zu\n",
args.size(), a);
if (i > destLen - 1) {
warning(WARNING_LONG_STR, "STRFMT: String too long, got truncated\n");
i = destLen - 1;
}
dest[i] = '\0';
}
static void compoundAssignment(const char *symName, enum RPNCommand op, int32_t constValue) {
Expression oldExpr, constExpr, newExpr;
int32_t newValue;
rpn_Symbol(&oldExpr, symName);
rpn_Number(&constExpr, constValue);
rpn_BinaryOp(op, &newExpr, &oldExpr, &constExpr);
newValue = rpn_GetConstVal(&newExpr);
sym_AddVar(symName, newValue);
}
static void initDsArgList(std::vector<Expression> *&args)
{
args = new(std::nothrow) std::vector<Expression>();
if (!args)
fatalerror("Failed to allocate memory for ds arg list: %s\n", strerror(errno));
}
static void initPurgeArgList(std::vector<std::string> *&args)
{
args = new(std::nothrow) std::vector<std::string>();
if (!args)
fatalerror("Failed to allocate memory for purge arg list: %s\n", strerror(errno));
}
static void failAssert(enum AssertionType type)
{
switch (type) {
case ASSERT_FATAL:
fatalerror("Assertion failed\n");
case ASSERT_ERROR:
error("Assertion failed\n");
break;
case ASSERT_WARN:
warning(WARNING_ASSERT, "Assertion failed\n");
break;
}
}
static void failAssertMsg(enum AssertionType type, char const *msg)
{
switch (type) {
case ASSERT_FATAL:
fatalerror("Assertion failed: %s\n", msg);
case ASSERT_ERROR:
error("Assertion failed: %s\n", msg);
break;
case ASSERT_WARN:
warning(WARNING_ASSERT, "Assertion failed: %s\n", msg);
break;
}
}
void yyerror(char const *str)
{
error("%s\n", str);
}
// The CPU encodes instructions in a logical way, so most instructions actually follow patterns.
// These enums thus help with bit twiddling to compute opcodes
enum {
REG_B = 0, REG_B = 0,
REG_C, REG_C,
REG_D, REG_D,
@@ -415,39 +91,29 @@ enum {
REG_L, REG_L,
REG_HL_IND, REG_HL_IND,
REG_A REG_A
}; };
enum { enum {
REG_BC_IND = 0, REG_BC_IND = 0,
REG_DE_IND, REG_DE_IND,
REG_HL_INDINC, REG_HL_INDINC,
REG_HL_INDDEC, REG_HL_INDDEC,
}; };
enum { enum {
REG_BC = 0, REG_BC = 0,
REG_DE = 1, REG_DE = 1,
REG_HL = 2, REG_HL = 2,
// LD/INC/ADD/DEC allow SP, PUSH/POP allow AF // LD/INC/ADD/DEC allow SP, PUSH/POP allow AF
REG_SP = 3, REG_SP = 3,
REG_AF = 3 REG_AF = 3
}; };
enum { enum {
CC_NZ = 0, CC_NZ = 0,
CC_Z, CC_Z,
CC_NC, CC_NC,
CC_C CC_C
};
%}
%code requires {
// Only used in the %union
struct ForArgs {
int32_t start;
int32_t stop;
int32_t step;
}; };
} }
@@ -2289,3 +1955,375 @@ hl_ind_dec : T_LBRACK T_MODE_HL_DEC T_RBRACK
; ;
%% %%
static void upperstring(char *dest, char const *src)
{
while (*src)
*dest++ = toupper(*src++);
*dest = '\0';
}
static void lowerstring(char *dest, char const *src)
{
while (*src)
*dest++ = tolower(*src++);
*dest = '\0';
}
static uint32_t str2int2(std::vector<uint8_t> const &s)
{
uint32_t length = s.size();
if (length > 4)
warning(WARNING_NUMERIC_STRING_1,
"Treating string as a number ignores first %" PRIu32 " character%s\n",
length - 4, length == 5 ? "" : "s");
else if (length > 1)
warning(WARNING_NUMERIC_STRING_2,
"Treating %" PRIu32 "-character string as a number\n", length);
uint32_t r = 0;
for (uint32_t i = length < 4 ? 0 : length - 4; i < length; i++) {
r <<= 8;
r |= s[i];
}
return r;
}
static const char *strrstr(char const *s1, char const *s2)
{
size_t len1 = strlen(s1);
size_t len2 = strlen(s2);
if (len2 > len1)
return nullptr;
for (char const *p = s1 + len1 - len2; p >= s1; p--)
if (!strncmp(p, s2, len2))
return p;
return nullptr;
}
static void errorInvalidUTF8Byte(uint8_t byte, char const *functionName)
{
error("%s: Invalid UTF-8 byte 0x%02hhX\n", functionName, byte);
}
static size_t strlenUTF8(char const *s)
{
size_t len = 0;
uint32_t state = 0;
for (uint32_t codep = 0; *s; s++) {
uint8_t byte = *s;
switch (decode(&state, &codep, byte)) {
case 1:
errorInvalidUTF8Byte(byte, "STRLEN");
state = 0;
// fallthrough
case 0:
len++;
break;
}
}
// Check for partial code point.
if (state != 0)
error("STRLEN: Incomplete UTF-8 character\n");
return len;
}
static void strsubUTF8(char *dest, size_t destLen, char const *src, uint32_t pos, uint32_t len)
{
size_t srcIndex = 0;
size_t destIndex = 0;
uint32_t state = 0;
uint32_t codep = 0;
uint32_t curLen = 0;
uint32_t curPos = 1;
// Advance to starting position in source string.
while (src[srcIndex] && curPos < pos) {
switch (decode(&state, &codep, src[srcIndex])) {
case 1:
errorInvalidUTF8Byte(src[srcIndex], "STRSUB");
state = 0;
// fallthrough
case 0:
curPos++;
break;
}
srcIndex++;
}
// A position 1 past the end of the string is allowed, but will trigger the
// "Length too big" warning below if the length is nonzero.
if (!src[srcIndex] && pos > curPos)
warning(WARNING_BUILTIN_ARG,
"STRSUB: Position %" PRIu32 " is past the end of the string\n", pos);
// Copy from source to destination.
while (src[srcIndex] && destIndex < destLen - 1 && curLen < len) {
switch (decode(&state, &codep, src[srcIndex])) {
case 1:
errorInvalidUTF8Byte(src[srcIndex], "STRSUB");
state = 0;
// fallthrough
case 0:
curLen++;
break;
}
dest[destIndex++] = src[srcIndex++];
}
if (curLen < len)
warning(WARNING_BUILTIN_ARG, "STRSUB: Length too big: %" PRIu32 "\n", len);
// Check for partial code point.
if (state != 0)
error("STRSUB: Incomplete UTF-8 character\n");
dest[destIndex] = '\0';
}
static size_t charlenUTF8(char const *s)
{
size_t len;
for (len = 0; charmap_ConvertNext(&s, nullptr); len++)
;
return len;
}
static void charsubUTF8(char *dest, char const *src, uint32_t pos)
{
size_t charLen = 1;
// Advance to starting position in source string.
for (uint32_t curPos = 1; charLen && curPos < pos; curPos++)
charLen = charmap_ConvertNext(&src, nullptr);
char const *start = src;
if (!charmap_ConvertNext(&src, nullptr))
warning(WARNING_BUILTIN_ARG,
"CHARSUB: Position %" PRIu32 " is past the end of the string\n", pos);
// Copy from source to destination.
memcpy(dest, start, src - start);
dest[src - start] = '\0';
}
static uint32_t adjustNegativePos(int32_t pos, size_t len, char const *functionName)
{
// STRSUB and CHARSUB adjust negative `pos` arguments the same way,
// such that position -1 is the last character of a string.
if (pos < 0)
pos += len + 1;
if (pos < 1) {
warning(WARNING_BUILTIN_ARG, "%s: Position starts at 1\n", functionName);
pos = 1;
}
return (uint32_t)pos;
}
static void strrpl(char *dest, size_t destLen, char const *src, char const *old, char const *rep)
{
size_t oldLen = strlen(old);
size_t repLen = strlen(rep);
size_t i = 0;
if (!oldLen) {
warning(WARNING_EMPTY_STRRPL, "STRRPL: Cannot replace an empty string\n");
strcpy(dest, src);
return;
}
for (char const *next = strstr(src, old); next && *next; next = strstr(src, old)) {
// Copy anything before the substring to replace
unsigned int lenBefore = next - src;
memcpy(dest + i, src, lenBefore < destLen - i ? lenBefore : destLen - i);
i += next - src;
if (i >= destLen)
break;
// Copy the replacement substring
memcpy(dest + i, rep, repLen < destLen - i ? repLen : destLen - i);
i += repLen;
if (i >= destLen)
break;
src = next + oldLen;
}
if (i < destLen) {
size_t srcLen = strlen(src);
// Copy anything after the last replaced substring
memcpy(dest + i, src, srcLen < destLen - i ? srcLen : destLen - i);
i += srcLen;
}
if (i >= destLen) {
warning(WARNING_LONG_STR, "STRRPL: String too long, got truncated\n");
i = destLen - 1;
}
dest[i] = '\0';
}
static void initStrFmtArgList(StrFmtArgList *args)
{
args->args = new(std::nothrow) std::vector<std::variant<uint32_t, char *>>();
if (!args->args)
fatalerror("Failed to allocate memory for STRFMT arg list: %s\n",
strerror(errno));
}
static void freeStrFmtArgList(StrFmtArgList *args)
{
free(args->format);
for (std::variant<uint32_t, char *> &arg : *args->args) {
if (char **str = std::get_if<char *>(&arg); str)
free(*str);
}
delete args->args;
}
static void strfmt(char *dest, size_t destLen, char const *fmt,
std::vector<std::variant<uint32_t, char *>> &args)
{
size_t a = 0;
size_t i = 0;
while (i < destLen) {
int c = *fmt++;
if (c == '\0') {
break;
} else if (c != '%') {
dest[i++] = c;
continue;
}
c = *fmt++;
if (c == '%') {
dest[i++] = c;
continue;
}
FormatSpec spec = fmt_NewSpec();
while (c != '\0') {
fmt_UseCharacter(&spec, c);
if (fmt_IsFinished(&spec))
break;
c = *fmt++;
}
if (fmt_IsEmpty(&spec)) {
error("STRFMT: Illegal '%%' at end of format string\n");
dest[i++] = '%';
break;
} else if (!fmt_IsValid(&spec)) {
error("STRFMT: Invalid format spec for argument %zu\n", a + 1);
dest[i++] = '%';
a++;
continue;
} else if (a >= args.size()) {
// Will warn after formatting is done.
dest[i++] = '%';
a++;
continue;
}
std::variant<uint32_t, char *> &arg = args[a++];
static char buf[MAXSTRLEN + 1];
std::visit(Visitor{
[&](uint32_t num) { fmt_PrintNumber(buf, sizeof(buf), &spec, num); },
[&](char *str) { fmt_PrintString(buf, sizeof(buf), &spec, str); },
}, arg);
i += snprintf(&dest[i], destLen - i, "%s", buf);
}
if (a < args.size())
error("STRFMT: %zu unformatted argument(s)\n", args.size() - a);
else if (a > args.size())
error("STRFMT: Not enough arguments for format spec, got: %zu, need: %zu\n",
args.size(), a);
if (i > destLen - 1) {
warning(WARNING_LONG_STR, "STRFMT: String too long, got truncated\n");
i = destLen - 1;
}
dest[i] = '\0';
}
static void compoundAssignment(const char *symName, enum RPNCommand op, int32_t constValue)
{
Expression oldExpr, constExpr, newExpr;
int32_t newValue;
rpn_Symbol(&oldExpr, symName);
rpn_Number(&constExpr, constValue);
rpn_BinaryOp(op, &newExpr, &oldExpr, &constExpr);
newValue = rpn_GetConstVal(&newExpr);
sym_AddVar(symName, newValue);
}
static void initDsArgList(std::vector<Expression> *&args)
{
args = new(std::nothrow) std::vector<Expression>();
if (!args)
fatalerror("Failed to allocate memory for ds arg list: %s\n", strerror(errno));
}
static void initPurgeArgList(std::vector<std::string> *&args)
{
args = new(std::nothrow) std::vector<std::string>();
if (!args)
fatalerror("Failed to allocate memory for purge arg list: %s\n", strerror(errno));
}
static void failAssert(enum AssertionType type)
{
switch (type) {
case ASSERT_FATAL:
fatalerror("Assertion failed\n");
case ASSERT_ERROR:
error("Assertion failed\n");
break;
case ASSERT_WARN:
warning(WARNING_ASSERT, "Assertion failed\n");
break;
}
}
static void failAssertMsg(enum AssertionType type, char const *msg)
{
switch (type) {
case ASSERT_FATAL:
fatalerror("Assertion failed: %s\n", msg);
case ASSERT_ERROR:
error("Assertion failed: %s\n", msg);
break;
case ASSERT_WARN:
warning(WARNING_ASSERT, "Assertion failed: %s\n", msg);
break;
}
}
void yyerror(char const *str)
{
error("%s\n", str);
}