mirror of
https://github.com/gbdev/rgbds.git
synced 2025-11-20 18:22:07 +00:00
Move more RGBASM parser action code out of the Bison file
This commit is contained in:
@@ -13,30 +13,46 @@
|
|||||||
#include "asm/output.hpp" // AssertionType
|
#include "asm/output.hpp" // AssertionType
|
||||||
#include "asm/rpn.hpp" // RPNCommand
|
#include "asm/rpn.hpp" // RPNCommand
|
||||||
|
|
||||||
|
struct AlignmentSpec {
|
||||||
|
uint8_t alignment;
|
||||||
|
uint16_t alignOfs;
|
||||||
|
};
|
||||||
|
|
||||||
|
void act_If(int32_t condition);
|
||||||
|
void act_Elif(int32_t condition);
|
||||||
|
void act_Else();
|
||||||
|
void act_Endc();
|
||||||
|
|
||||||
|
AlignmentSpec act_Alignment(int32_t alignment, int32_t alignOfs);
|
||||||
|
|
||||||
|
void act_Assert(AssertionType type, Expression const &expr, std::string const &message);
|
||||||
|
void act_StaticAssert(AssertionType type, int32_t condition, std::string const &message);
|
||||||
|
|
||||||
std::optional<std::string> act_ReadFile(std::string const &name, uint32_t maxLen);
|
std::optional<std::string> act_ReadFile(std::string const &name, uint32_t maxLen);
|
||||||
|
|
||||||
|
uint32_t act_CharToNum(std::string const &str);
|
||||||
uint32_t act_StringToNum(std::vector<int32_t> const &str);
|
uint32_t act_StringToNum(std::vector<int32_t> const &str);
|
||||||
|
|
||||||
|
int32_t act_CharVal(std::string const &str, int32_t negIdx);
|
||||||
|
uint8_t act_StringByte(std::string const &str, int32_t negIdx);
|
||||||
|
|
||||||
size_t act_StringLen(std::string const &str, bool printErrors);
|
size_t act_StringLen(std::string const &str, bool printErrors);
|
||||||
std::string act_StringSlice(std::string const &str, uint32_t start, uint32_t stop);
|
std::string
|
||||||
std::string act_StringSub(std::string const &str, uint32_t pos, uint32_t len);
|
act_StringSlice(std::string const &str, int32_t negStart, std::optional<int32_t> negStop);
|
||||||
|
std::string act_StringSub(std::string const &str, int32_t negPos, std::optional<uint32_t> optLen);
|
||||||
|
|
||||||
size_t act_CharLen(std::string const &str);
|
size_t act_CharLen(std::string const &str);
|
||||||
std::string act_StringChar(std::string const &str, uint32_t idx);
|
std::string act_StringChar(std::string const &str, int32_t negIdx);
|
||||||
std::string act_CharSub(std::string const &str, uint32_t pos);
|
std::string act_CharSub(std::string const &str, int32_t negPos);
|
||||||
int32_t act_CharCmp(std::string_view str1, std::string_view str2);
|
int32_t act_CharCmp(std::string_view str1, std::string_view str2);
|
||||||
|
|
||||||
uint32_t act_AdjustNegativeIndex(int32_t idx, size_t len, char const *functionName);
|
|
||||||
uint32_t act_AdjustNegativePos(int32_t pos, size_t len, char const *functionName);
|
|
||||||
|
|
||||||
std::string act_StringReplace(std::string_view str, std::string const &old, std::string const &rep);
|
std::string act_StringReplace(std::string_view str, std::string const &old, std::string const &rep);
|
||||||
std::string act_StringFormat(
|
std::string act_StringFormat(
|
||||||
std::string const &spec, std::vector<std::variant<uint32_t, std::string>> const &args
|
std::string const &spec, std::vector<std::variant<uint32_t, std::string>> const &args
|
||||||
);
|
);
|
||||||
|
|
||||||
|
std::string act_SectionName(std::string const &symName);
|
||||||
|
|
||||||
void act_CompoundAssignment(std::string const &symName, RPNCommand op, int32_t constValue);
|
void act_CompoundAssignment(std::string const &symName, RPNCommand op, int32_t constValue);
|
||||||
|
|
||||||
void act_FailAssert(AssertionType type);
|
|
||||||
void act_FailAssertMsg(AssertionType type, std::string const &message);
|
|
||||||
|
|
||||||
#endif // RGBDS_ASM_ACTIONS_HPP
|
#endif // RGBDS_ASM_ACTIONS_HPP
|
||||||
|
|||||||
@@ -15,6 +15,107 @@
|
|||||||
#include "asm/symbol.hpp"
|
#include "asm/symbol.hpp"
|
||||||
#include "asm/warning.hpp"
|
#include "asm/warning.hpp"
|
||||||
|
|
||||||
|
void act_If(int32_t condition) {
|
||||||
|
lexer_IncIFDepth();
|
||||||
|
|
||||||
|
if (condition) {
|
||||||
|
lexer_RunIFBlock();
|
||||||
|
} else {
|
||||||
|
lexer_SetMode(LEXER_SKIP_TO_ELIF);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void act_Elif(int32_t condition) {
|
||||||
|
if (lexer_GetIFDepth() == 0) {
|
||||||
|
fatal("Found ELIF outside of an IF construct");
|
||||||
|
}
|
||||||
|
if (lexer_RanIFBlock()) {
|
||||||
|
if (lexer_ReachedELSEBlock()) {
|
||||||
|
fatal("Found ELIF after an ELSE block");
|
||||||
|
}
|
||||||
|
lexer_SetMode(LEXER_SKIP_TO_ENDC);
|
||||||
|
} else if (condition) {
|
||||||
|
lexer_RunIFBlock();
|
||||||
|
} else {
|
||||||
|
lexer_SetMode(LEXER_SKIP_TO_ELIF);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void act_Else() {
|
||||||
|
if (lexer_GetIFDepth() == 0) {
|
||||||
|
fatal("Found ELSE outside of an IF construct");
|
||||||
|
}
|
||||||
|
if (lexer_RanIFBlock()) {
|
||||||
|
if (lexer_ReachedELSEBlock()) {
|
||||||
|
fatal("Found ELSE after an ELSE block");
|
||||||
|
}
|
||||||
|
lexer_SetMode(LEXER_SKIP_TO_ENDC);
|
||||||
|
} else {
|
||||||
|
lexer_RunIFBlock();
|
||||||
|
lexer_ReachELSEBlock();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void act_Endc() {
|
||||||
|
lexer_DecIFDepth();
|
||||||
|
}
|
||||||
|
|
||||||
|
AlignmentSpec act_Alignment(int32_t alignment, int32_t alignOfs) {
|
||||||
|
AlignmentSpec spec = {0, 0};
|
||||||
|
if (alignment > 16) {
|
||||||
|
error("Alignment must be between 0 and 16, not %u", alignment);
|
||||||
|
} else if (alignOfs <= -(1 << alignment) || alignOfs >= 1 << alignment) {
|
||||||
|
error(
|
||||||
|
"The absolute alignment offset (%" PRIu32 ") must be less than alignment size (%d)",
|
||||||
|
static_cast<uint32_t>(alignOfs < 0 ? -alignOfs : alignOfs),
|
||||||
|
1 << alignment
|
||||||
|
);
|
||||||
|
} else {
|
||||||
|
spec.alignment = alignment;
|
||||||
|
spec.alignOfs = alignOfs < 0 ? (1 << alignment) + alignOfs : alignOfs;
|
||||||
|
}
|
||||||
|
return spec;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void failAssert(AssertionType type, std::string const &message) {
|
||||||
|
switch (type) {
|
||||||
|
case ASSERT_FATAL:
|
||||||
|
if (message.empty()) {
|
||||||
|
fatal("Assertion failed");
|
||||||
|
} else {
|
||||||
|
fatal("Assertion failed: %s", message.c_str());
|
||||||
|
}
|
||||||
|
case ASSERT_ERROR:
|
||||||
|
if (message.empty()) {
|
||||||
|
error("Assertion failed");
|
||||||
|
} else {
|
||||||
|
error("Assertion failed: %s", message.c_str());
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case ASSERT_WARN:
|
||||||
|
if (message.empty()) {
|
||||||
|
warning(WARNING_ASSERT, "Assertion failed");
|
||||||
|
} else {
|
||||||
|
warning(WARNING_ASSERT, "Assertion failed: %s", message.c_str());
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void act_Assert(AssertionType type, Expression const &expr, std::string const &message) {
|
||||||
|
if (!expr.isKnown()) {
|
||||||
|
out_CreateAssert(type, expr, message, sect_GetOutputOffset());
|
||||||
|
} else if (expr.value() == 0) {
|
||||||
|
failAssert(type, message);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void act_StaticAssert(AssertionType type, int32_t condition, std::string const &message) {
|
||||||
|
if (!condition) {
|
||||||
|
failAssert(type, message);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
std::optional<std::string> act_ReadFile(std::string const &name, uint32_t maxLen) {
|
std::optional<std::string> act_ReadFile(std::string const &name, uint32_t maxLen) {
|
||||||
FILE *file = nullptr;
|
FILE *file = nullptr;
|
||||||
if (std::optional<std::string> fullPath = fstk_FindFile(name); fullPath) {
|
if (std::optional<std::string> fullPath = fstk_FindFile(name); fullPath) {
|
||||||
@@ -53,6 +154,15 @@ std::optional<std::string> act_ReadFile(std::string const &name, uint32_t maxLen
|
|||||||
return contents;
|
return contents;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
uint32_t act_CharToNum(std::string const &str) {
|
||||||
|
if (std::vector<int32_t> output = charmap_Convert(str); output.size() == 1) {
|
||||||
|
return static_cast<uint32_t>(output[0]);
|
||||||
|
} else {
|
||||||
|
error("Character literals must be a single charmap unit");
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
uint32_t act_StringToNum(std::vector<int32_t> const &str) {
|
uint32_t act_StringToNum(std::vector<int32_t> const &str) {
|
||||||
uint32_t length = str.size();
|
uint32_t length = str.size();
|
||||||
|
|
||||||
@@ -80,6 +190,63 @@ uint32_t act_StringToNum(std::vector<int32_t> const &str) {
|
|||||||
return r;
|
return r;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static uint32_t adjustNegativeIndex(int32_t idx, size_t len, char const *functionName) {
|
||||||
|
// String functions adjust negative index arguments the same way,
|
||||||
|
// such that position -1 is the last character of a string.
|
||||||
|
if (idx < 0) {
|
||||||
|
idx += len;
|
||||||
|
}
|
||||||
|
if (idx < 0) {
|
||||||
|
warning(WARNING_BUILTIN_ARG, "%s: Index starts at 0", functionName);
|
||||||
|
idx = 0;
|
||||||
|
}
|
||||||
|
return static_cast<uint32_t>(idx);
|
||||||
|
}
|
||||||
|
|
||||||
|
static uint32_t adjustNegativePos(int32_t pos, size_t len, char const *functionName) {
|
||||||
|
// STRSUB and CHARSUB adjust negative position 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", functionName);
|
||||||
|
pos = 1;
|
||||||
|
}
|
||||||
|
return static_cast<uint32_t>(pos);
|
||||||
|
}
|
||||||
|
|
||||||
|
int32_t act_CharVal(std::string const &str, int32_t negIdx) {
|
||||||
|
if (size_t len = charmap_CharSize(str); len != 0) {
|
||||||
|
uint32_t idx = adjustNegativeIndex(negIdx, len, "CHARVAL");
|
||||||
|
if (std::optional<int32_t> val = charmap_CharValue(str, idx); val.has_value()) {
|
||||||
|
return *val;
|
||||||
|
} else {
|
||||||
|
warning(
|
||||||
|
WARNING_BUILTIN_ARG,
|
||||||
|
"CHARVAL: Index %" PRIu32 " is past the end of the character mapping",
|
||||||
|
idx
|
||||||
|
);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
error("CHARVAL: No character mapping for \"%s\"", str.c_str());
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
uint8_t act_StringByte(std::string const &str, int32_t negIdx) {
|
||||||
|
size_t len = str.length();
|
||||||
|
if (uint32_t idx = adjustNegativeIndex(negIdx, len, "STRBYTE"); idx < len) {
|
||||||
|
return static_cast<uint8_t>(str[idx]);
|
||||||
|
} else {
|
||||||
|
warning(
|
||||||
|
WARNING_BUILTIN_ARG, "STRBYTE: Index %" PRIu32 " is past the end of the string", idx
|
||||||
|
);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
static void errorInvalidUTF8Byte(uint8_t byte, char const *functionName) {
|
static void errorInvalidUTF8Byte(uint8_t byte, char const *functionName) {
|
||||||
error("%s: Invalid UTF-8 byte 0x%02hhX", functionName, byte);
|
error("%s: Invalid UTF-8 byte 0x%02hhX", functionName, byte);
|
||||||
}
|
}
|
||||||
@@ -116,7 +283,12 @@ size_t act_StringLen(std::string const &str, bool printErrors) {
|
|||||||
return len;
|
return len;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string act_StringSlice(std::string const &str, uint32_t start, uint32_t stop) {
|
std::string
|
||||||
|
act_StringSlice(std::string const &str, int32_t negStart, std::optional<int32_t> negStop) {
|
||||||
|
size_t adjustLen = act_StringLen(str, false);
|
||||||
|
uint32_t start = adjustNegativeIndex(negStart, adjustLen, "STRSLICE");
|
||||||
|
uint32_t stop = negStop ? adjustNegativeIndex(*negStop, adjustLen, "STRSLICE") : adjustLen;
|
||||||
|
|
||||||
size_t strLen = str.length();
|
size_t strLen = str.length();
|
||||||
size_t index = 0;
|
size_t index = 0;
|
||||||
uint32_t state = UTF8_ACCEPT;
|
uint32_t state = UTF8_ACCEPT;
|
||||||
@@ -180,7 +352,11 @@ std::string act_StringSlice(std::string const &str, uint32_t start, uint32_t sto
|
|||||||
return str.substr(startIndex, index - startIndex);
|
return str.substr(startIndex, index - startIndex);
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string act_StringSub(std::string const &str, uint32_t pos, uint32_t len) {
|
std::string act_StringSub(std::string const &str, int32_t negPos, std::optional<uint32_t> optLen) {
|
||||||
|
size_t adjustLen = act_StringLen(str, false);
|
||||||
|
uint32_t pos = adjustNegativePos(negPos, adjustLen, "STRSUB");
|
||||||
|
uint32_t len = optLen ? *optLen : pos > adjustLen ? 0 : adjustLen + 1 - pos;
|
||||||
|
|
||||||
size_t strLen = str.length();
|
size_t strLen = str.length();
|
||||||
size_t index = 0;
|
size_t index = 0;
|
||||||
uint32_t state = UTF8_ACCEPT;
|
uint32_t state = UTF8_ACCEPT;
|
||||||
@@ -248,7 +424,10 @@ size_t act_CharLen(std::string const &str) {
|
|||||||
return len;
|
return len;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string act_StringChar(std::string const &str, uint32_t idx) {
|
std::string act_StringChar(std::string const &str, int32_t negIdx) {
|
||||||
|
size_t adjustLen = act_CharLen(str);
|
||||||
|
uint32_t idx = adjustNegativeIndex(negIdx, adjustLen, "STRCHAR");
|
||||||
|
|
||||||
std::string_view view = str;
|
std::string_view view = str;
|
||||||
size_t charLen = 1;
|
size_t charLen = 1;
|
||||||
|
|
||||||
@@ -269,7 +448,10 @@ std::string act_StringChar(std::string const &str, uint32_t idx) {
|
|||||||
return std::string(start);
|
return std::string(start);
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string act_CharSub(std::string const &str, uint32_t pos) {
|
std::string act_CharSub(std::string const &str, int32_t negPos) {
|
||||||
|
size_t adjustLen = act_CharLen(str);
|
||||||
|
uint32_t pos = adjustNegativePos(negPos, adjustLen, "CHARSUB");
|
||||||
|
|
||||||
std::string_view view = str;
|
std::string_view view = str;
|
||||||
size_t charLen = 1;
|
size_t charLen = 1;
|
||||||
|
|
||||||
@@ -317,32 +499,6 @@ int32_t act_CharCmp(std::string_view str1, std::string_view str2) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
uint32_t act_AdjustNegativeIndex(int32_t idx, size_t len, char const *functionName) {
|
|
||||||
// String functions adjust negative index arguments the same way,
|
|
||||||
// such that position -1 is the last character of a string.
|
|
||||||
if (idx < 0) {
|
|
||||||
idx += len;
|
|
||||||
}
|
|
||||||
if (idx < 0) {
|
|
||||||
warning(WARNING_BUILTIN_ARG, "%s: Index starts at 0", functionName);
|
|
||||||
idx = 0;
|
|
||||||
}
|
|
||||||
return static_cast<uint32_t>(idx);
|
|
||||||
}
|
|
||||||
|
|
||||||
uint32_t act_AdjustNegativePos(int32_t pos, size_t len, char const *functionName) {
|
|
||||||
// STRSUB and CHARSUB adjust negative position 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", functionName);
|
|
||||||
pos = 1;
|
|
||||||
}
|
|
||||||
return static_cast<uint32_t>(pos);
|
|
||||||
}
|
|
||||||
|
|
||||||
std::string
|
std::string
|
||||||
act_StringReplace(std::string_view str, std::string const &old, std::string const &rep) {
|
act_StringReplace(std::string_view str, std::string const &old, std::string const &rep) {
|
||||||
if (old.empty()) {
|
if (old.empty()) {
|
||||||
@@ -431,39 +587,30 @@ std::string act_StringFormat(
|
|||||||
return str;
|
return str;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
std::string act_SectionName(std::string const &symName) {
|
||||||
|
Symbol *sym = sym_FindScopedValidSymbol(symName);
|
||||||
|
if (!sym) {
|
||||||
|
if (sym_IsPurgedScoped(symName)) {
|
||||||
|
fatal("Unknown symbol \"%s\"; it was purged", symName.c_str());
|
||||||
|
} else {
|
||||||
|
fatal("Unknown symbol \"%s\"", symName.c_str());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Section const *section = sym->getSection();
|
||||||
|
if (!section) {
|
||||||
|
fatal("\"%s\" does not belong to any section", sym->name.c_str());
|
||||||
|
}
|
||||||
|
|
||||||
|
return section->name;
|
||||||
|
}
|
||||||
|
|
||||||
void act_CompoundAssignment(std::string const &symName, RPNCommand op, int32_t constValue) {
|
void act_CompoundAssignment(std::string const &symName, RPNCommand op, int32_t constValue) {
|
||||||
Expression oldExpr, constExpr, newExpr;
|
Expression oldExpr, constExpr, newExpr;
|
||||||
int32_t newValue;
|
|
||||||
|
|
||||||
oldExpr.makeSymbol(symName);
|
oldExpr.makeSymbol(symName);
|
||||||
constExpr.makeNumber(constValue);
|
constExpr.makeNumber(constValue);
|
||||||
newExpr.makeBinaryOp(op, std::move(oldExpr), constExpr);
|
newExpr.makeBinaryOp(op, std::move(oldExpr), constExpr);
|
||||||
newValue = newExpr.getConstVal();
|
|
||||||
|
int32_t newValue = newExpr.getConstVal();
|
||||||
sym_AddVar(symName, newValue);
|
sym_AddVar(symName, newValue);
|
||||||
}
|
}
|
||||||
|
|
||||||
void act_FailAssert(AssertionType type) {
|
|
||||||
switch (type) {
|
|
||||||
case ASSERT_FATAL:
|
|
||||||
fatal("Assertion failed");
|
|
||||||
case ASSERT_ERROR:
|
|
||||||
error("Assertion failed");
|
|
||||||
break;
|
|
||||||
case ASSERT_WARN:
|
|
||||||
warning(WARNING_ASSERT, "Assertion failed");
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void act_FailAssertMsg(AssertionType type, std::string const &message) {
|
|
||||||
switch (type) {
|
|
||||||
case ASSERT_FATAL:
|
|
||||||
fatal("Assertion failed: %s", message.c_str());
|
|
||||||
case ASSERT_ERROR:
|
|
||||||
error("Assertion failed: %s", message.c_str());
|
|
||||||
break;
|
|
||||||
case ASSERT_WARN:
|
|
||||||
warning(WARNING_ASSERT, "Assertion failed: %s", message.c_str());
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|||||||
170
src/asm/parser.y
170
src/asm/parser.y
@@ -12,16 +12,12 @@
|
|||||||
|
|
||||||
#include "linkdefs.hpp"
|
#include "linkdefs.hpp"
|
||||||
|
|
||||||
|
#include "asm/actions.hpp"
|
||||||
#include "asm/lexer.hpp"
|
#include "asm/lexer.hpp"
|
||||||
#include "asm/macro.hpp"
|
#include "asm/macro.hpp"
|
||||||
#include "asm/rpn.hpp"
|
#include "asm/rpn.hpp"
|
||||||
#include "asm/section.hpp"
|
#include "asm/section.hpp"
|
||||||
|
|
||||||
struct AlignmentSpec {
|
|
||||||
uint8_t alignment;
|
|
||||||
uint16_t alignOfs;
|
|
||||||
};
|
|
||||||
|
|
||||||
struct ForArgs {
|
struct ForArgs {
|
||||||
int32_t start;
|
int32_t start;
|
||||||
int32_t stop;
|
int32_t stop;
|
||||||
@@ -47,7 +43,6 @@
|
|||||||
#include "extern/utf8decoder.hpp"
|
#include "extern/utf8decoder.hpp"
|
||||||
#include "helpers.hpp"
|
#include "helpers.hpp"
|
||||||
|
|
||||||
#include "asm/actions.hpp"
|
|
||||||
#include "asm/charmap.hpp"
|
#include "asm/charmap.hpp"
|
||||||
#include "asm/fixpoint.hpp"
|
#include "asm/fixpoint.hpp"
|
||||||
#include "asm/fstack.hpp"
|
#include "asm/fstack.hpp"
|
||||||
@@ -465,48 +460,19 @@ line_directive:
|
|||||||
|
|
||||||
if:
|
if:
|
||||||
POP_IF iconst NEWLINE {
|
POP_IF iconst NEWLINE {
|
||||||
lexer_IncIFDepth();
|
act_If($2);
|
||||||
|
|
||||||
if ($2) {
|
|
||||||
lexer_RunIFBlock();
|
|
||||||
} else {
|
|
||||||
lexer_SetMode(LEXER_SKIP_TO_ELIF);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
;
|
;
|
||||||
|
|
||||||
elif:
|
elif:
|
||||||
POP_ELIF iconst NEWLINE {
|
POP_ELIF iconst NEWLINE {
|
||||||
if (lexer_GetIFDepth() == 0) {
|
act_Elif($2);
|
||||||
fatal("Found ELIF outside of an IF construct");
|
|
||||||
}
|
|
||||||
if (lexer_RanIFBlock()) {
|
|
||||||
if (lexer_ReachedELSEBlock()) {
|
|
||||||
fatal("Found ELIF after an ELSE block");
|
|
||||||
}
|
|
||||||
lexer_SetMode(LEXER_SKIP_TO_ENDC);
|
|
||||||
} else if ($2) {
|
|
||||||
lexer_RunIFBlock();
|
|
||||||
} else {
|
|
||||||
lexer_SetMode(LEXER_SKIP_TO_ELIF);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
;
|
;
|
||||||
|
|
||||||
else:
|
else:
|
||||||
POP_ELSE NEWLINE {
|
POP_ELSE NEWLINE {
|
||||||
if (lexer_GetIFDepth() == 0) {
|
act_Else();
|
||||||
fatal("Found ELSE outside of an IF construct");
|
|
||||||
}
|
|
||||||
if (lexer_RanIFBlock()) {
|
|
||||||
if (lexer_ReachedELSEBlock()) {
|
|
||||||
fatal("Found ELSE after an ELSE block");
|
|
||||||
}
|
|
||||||
lexer_SetMode(LEXER_SKIP_TO_ENDC);
|
|
||||||
} else {
|
|
||||||
lexer_RunIFBlock();
|
|
||||||
lexer_ReachELSEBlock();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
;
|
;
|
||||||
|
|
||||||
@@ -521,7 +487,7 @@ plain_directive:
|
|||||||
|
|
||||||
endc:
|
endc:
|
||||||
POP_ENDC {
|
POP_ENDC {
|
||||||
lexer_DecIFDepth();
|
act_Endc();
|
||||||
}
|
}
|
||||||
;
|
;
|
||||||
|
|
||||||
@@ -684,29 +650,10 @@ align:
|
|||||||
|
|
||||||
align_spec:
|
align_spec:
|
||||||
uconst {
|
uconst {
|
||||||
if ($1 > 16) {
|
$$ = act_Alignment($1, 0);
|
||||||
::error("Alignment must be between 0 and 16, not %u", $1);
|
|
||||||
$$.alignment = $$.alignOfs = 0;
|
|
||||||
} else {
|
|
||||||
$$.alignment = $1;
|
|
||||||
$$.alignOfs = 0;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
| uconst COMMA iconst {
|
| uconst COMMA iconst {
|
||||||
if ($1 > 16) {
|
$$ = act_Alignment($1, $3);
|
||||||
::error("Alignment must be between 0 and 16, not %u", $1);
|
|
||||||
$$.alignment = $$.alignOfs = 0;
|
|
||||||
} else if ($3 <= -(1 << $1) || $3 >= 1 << $1) {
|
|
||||||
::error(
|
|
||||||
"The absolute alignment offset (%" PRIu32 ") must be less than alignment size (%d)",
|
|
||||||
static_cast<uint32_t>($3 < 0 ? -$3 : $3),
|
|
||||||
1 << $1
|
|
||||||
);
|
|
||||||
$$.alignment = $$.alignOfs = 0;
|
|
||||||
} else {
|
|
||||||
$$.alignment = $1;
|
|
||||||
$$.alignOfs = $3 < 0 ? (1 << $1) + $3 : $3;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
;
|
;
|
||||||
|
|
||||||
@@ -796,28 +743,16 @@ assert_type:
|
|||||||
|
|
||||||
assert:
|
assert:
|
||||||
POP_ASSERT assert_type relocexpr {
|
POP_ASSERT assert_type relocexpr {
|
||||||
if (!$3.isKnown()) {
|
act_Assert($2, $3, "");
|
||||||
out_CreateAssert($2, $3, "", sect_GetOutputOffset());
|
|
||||||
} else if ($3.value() == 0) {
|
|
||||||
act_FailAssert($2);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
| POP_ASSERT assert_type relocexpr COMMA string {
|
| POP_ASSERT assert_type relocexpr COMMA string {
|
||||||
if (!$3.isKnown()) {
|
act_Assert($2, $3, $5);
|
||||||
out_CreateAssert($2, $3, $5, sect_GetOutputOffset());
|
|
||||||
} else if ($3.value() == 0) {
|
|
||||||
act_FailAssertMsg($2, $5);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
| POP_STATIC_ASSERT assert_type iconst {
|
| POP_STATIC_ASSERT assert_type iconst {
|
||||||
if ($3 == 0) {
|
act_StaticAssert($2, $3, "");
|
||||||
act_FailAssert($2);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
| POP_STATIC_ASSERT assert_type iconst COMMA string {
|
| POP_STATIC_ASSERT assert_type iconst COMMA string {
|
||||||
if ($3 == 0) {
|
act_StaticAssert($2, $3, $5);
|
||||||
act_FailAssertMsg($2, $5);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
;
|
;
|
||||||
|
|
||||||
@@ -963,13 +898,11 @@ ds:
|
|||||||
}
|
}
|
||||||
| POP_DS POP_ALIGN LBRACK align_spec RBRACK trailing_comma {
|
| POP_DS POP_ALIGN LBRACK align_spec RBRACK trailing_comma {
|
||||||
uint32_t n = sect_GetAlignBytes($4.alignment, $4.alignOfs);
|
uint32_t n = sect_GetAlignBytes($4.alignment, $4.alignOfs);
|
||||||
|
|
||||||
sect_Skip(n, true);
|
sect_Skip(n, true);
|
||||||
sect_AlignPC($4.alignment, $4.alignOfs);
|
sect_AlignPC($4.alignment, $4.alignOfs);
|
||||||
}
|
}
|
||||||
| POP_DS POP_ALIGN LBRACK align_spec RBRACK COMMA ds_args trailing_comma {
|
| POP_DS POP_ALIGN LBRACK align_spec RBRACK COMMA ds_args trailing_comma {
|
||||||
uint32_t n = sect_GetAlignBytes($4.alignment, $4.alignOfs);
|
uint32_t n = sect_GetAlignBytes($4.alignment, $4.alignOfs);
|
||||||
|
|
||||||
sect_RelBytes(n, $7);
|
sect_RelBytes(n, $7);
|
||||||
sect_AlignPC($4.alignment, $4.alignOfs);
|
sect_AlignPC($4.alignment, $4.alignOfs);
|
||||||
}
|
}
|
||||||
@@ -1385,13 +1318,7 @@ relocexpr_no_str:
|
|||||||
$$.makeNumber($1);
|
$$.makeNumber($1);
|
||||||
}
|
}
|
||||||
| CHARACTER {
|
| CHARACTER {
|
||||||
std::vector<int32_t> output = charmap_Convert($1);
|
$$.makeNumber(act_CharToNum($1));
|
||||||
if (output.size() == 1) {
|
|
||||||
$$.makeNumber(static_cast<uint32_t>(output[0]));
|
|
||||||
} else {
|
|
||||||
::error("Character literals must be a single charmap unit");
|
|
||||||
$$.makeNumber(0);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
| OP_LOGICNOT relocexpr %prec NEG {
|
| OP_LOGICNOT relocexpr %prec NEG {
|
||||||
$$.makeUnaryOp(RPN_LOGNOT, std::move($2));
|
$$.makeUnaryOp(RPN_LOGNOT, std::move($2));
|
||||||
@@ -1598,36 +1525,10 @@ relocexpr_no_str:
|
|||||||
$$.makeNumber(charSize);
|
$$.makeNumber(charSize);
|
||||||
}
|
}
|
||||||
| OP_CHARVAL LPAREN string COMMA iconst RPAREN {
|
| OP_CHARVAL LPAREN string COMMA iconst RPAREN {
|
||||||
if (size_t len = charmap_CharSize($3); len != 0) {
|
$$.makeNumber(act_CharVal($3, $5));
|
||||||
uint32_t idx = act_AdjustNegativeIndex($5, len, "CHARVAL");
|
|
||||||
if (std::optional<int32_t> val = charmap_CharValue($3, idx); val.has_value()) {
|
|
||||||
$$.makeNumber(*val);
|
|
||||||
} else {
|
|
||||||
warning(
|
|
||||||
WARNING_BUILTIN_ARG,
|
|
||||||
"CHARVAL: Index %" PRIu32 " is past the end of the character mapping",
|
|
||||||
idx
|
|
||||||
);
|
|
||||||
$$.makeNumber(0);
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
::error("CHARVAL: No character mapping for \"%s\"", $3.c_str());
|
|
||||||
$$.makeNumber(0);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
| OP_STRBYTE LPAREN string COMMA iconst RPAREN {
|
| OP_STRBYTE LPAREN string COMMA iconst RPAREN {
|
||||||
size_t len = $3.length();
|
$$.makeNumber(act_StringByte($3, $5));
|
||||||
uint32_t idx = act_AdjustNegativeIndex($5, len, "STRBYTE");
|
|
||||||
if (idx < len) {
|
|
||||||
$$.makeNumber(static_cast<uint8_t>($3[idx]));
|
|
||||||
} else {
|
|
||||||
warning(
|
|
||||||
WARNING_BUILTIN_ARG,
|
|
||||||
"STRBYTE: Index %" PRIu32 " is past the end of the string",
|
|
||||||
idx
|
|
||||||
);
|
|
||||||
$$.makeNumber(0);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
| LPAREN relocexpr RPAREN {
|
| LPAREN relocexpr RPAREN {
|
||||||
$$ = std::move($2);
|
$$ = std::move($2);
|
||||||
@@ -1685,35 +1586,22 @@ string_literal:
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
| OP_STRSLICE LPAREN string COMMA iconst COMMA iconst RPAREN {
|
| OP_STRSLICE LPAREN string COMMA iconst COMMA iconst RPAREN {
|
||||||
size_t len = act_StringLen($3, false);
|
$$ = act_StringSlice($3, $5, $7);
|
||||||
uint32_t start = act_AdjustNegativeIndex($5, len, "STRSLICE");
|
|
||||||
uint32_t stop = act_AdjustNegativeIndex($7, len, "STRSLICE");
|
|
||||||
$$ = act_StringSlice($3, start, stop);
|
|
||||||
}
|
}
|
||||||
| OP_STRSLICE LPAREN string COMMA iconst RPAREN {
|
| OP_STRSLICE LPAREN string COMMA iconst RPAREN {
|
||||||
size_t len = act_StringLen($3, false);
|
$$ = act_StringSlice($3, $5, std::nullopt);
|
||||||
uint32_t start = act_AdjustNegativeIndex($5, len, "STRSLICE");
|
|
||||||
$$ = act_StringSlice($3, start, len);
|
|
||||||
}
|
}
|
||||||
| OP_STRSUB LPAREN string COMMA iconst COMMA uconst RPAREN {
|
| OP_STRSUB LPAREN string COMMA iconst COMMA uconst RPAREN {
|
||||||
size_t len = act_StringLen($3, false);
|
$$ = act_StringSub($3, $5, $7);
|
||||||
uint32_t pos = act_AdjustNegativePos($5, len, "STRSUB");
|
|
||||||
$$ = act_StringSub($3, pos, $7);
|
|
||||||
}
|
}
|
||||||
| OP_STRSUB LPAREN string COMMA iconst RPAREN {
|
| OP_STRSUB LPAREN string COMMA iconst RPAREN {
|
||||||
size_t len = act_StringLen($3, false);
|
$$ = act_StringSub($3, $5, std::nullopt);
|
||||||
uint32_t pos = act_AdjustNegativePos($5, len, "STRSUB");
|
|
||||||
$$ = act_StringSub($3, pos, pos > len ? 0 : len + 1 - pos);
|
|
||||||
}
|
}
|
||||||
| OP_STRCHAR LPAREN string COMMA iconst RPAREN {
|
| OP_STRCHAR LPAREN string COMMA iconst RPAREN {
|
||||||
size_t len = act_CharLen($3);
|
$$ = act_StringChar($3, $5);
|
||||||
uint32_t idx = act_AdjustNegativeIndex($5, len, "STRCHAR");
|
|
||||||
$$ = act_StringChar($3, idx);
|
|
||||||
}
|
}
|
||||||
| OP_CHARSUB LPAREN string COMMA iconst RPAREN {
|
| OP_CHARSUB LPAREN string COMMA iconst RPAREN {
|
||||||
size_t len = act_CharLen($3);
|
$$ = act_CharSub($3, $5);
|
||||||
uint32_t pos = act_AdjustNegativePos($5, len, "CHARSUB");
|
|
||||||
$$ = act_CharSub($3, pos);
|
|
||||||
}
|
}
|
||||||
| OP_REVCHAR LPAREN charmap_args RPAREN {
|
| OP_REVCHAR LPAREN charmap_args RPAREN {
|
||||||
bool unique;
|
bool unique;
|
||||||
@@ -1745,23 +1633,7 @@ string_literal:
|
|||||||
$$ = act_StringFormat($3.format, $3.args);
|
$$ = act_StringFormat($3.format, $3.args);
|
||||||
}
|
}
|
||||||
| POP_SECTION LPAREN scoped_sym RPAREN {
|
| POP_SECTION LPAREN scoped_sym RPAREN {
|
||||||
Symbol *sym = sym_FindScopedValidSymbol($3);
|
$$ = act_SectionName($3);
|
||||||
|
|
||||||
if (!sym) {
|
|
||||||
if (sym_IsPurgedScoped($3)) {
|
|
||||||
fatal("Unknown symbol \"%s\"; it was purged", $3.c_str());
|
|
||||||
} else {
|
|
||||||
fatal("Unknown symbol \"%s\"", $3.c_str());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Section const *section = sym->getSection();
|
|
||||||
|
|
||||||
if (!section) {
|
|
||||||
fatal("\"%s\" does not belong to any section", sym->name.c_str());
|
|
||||||
}
|
|
||||||
// Section names are capped by rgbasm's maximum string length,
|
|
||||||
// so this currently can't overflow.
|
|
||||||
$$ = section->name;
|
|
||||||
}
|
}
|
||||||
;
|
;
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user