mirror of
https://github.com/gbdev/rgbds.git
synced 2025-11-20 10:12:06 +00:00
Track local label scope, string equated as .. (#1504)
This commit is contained in:
@@ -9,6 +9,7 @@
|
|||||||
#include <string>
|
#include <string>
|
||||||
#include <string_view>
|
#include <string_view>
|
||||||
#include <time.h>
|
#include <time.h>
|
||||||
|
#include <utility>
|
||||||
#include <variant>
|
#include <variant>
|
||||||
|
|
||||||
#include "asm/lexer.hpp"
|
#include "asm/lexer.hpp"
|
||||||
@@ -98,8 +99,9 @@ bool sym_IsPurgedExact(std::string const &symName);
|
|||||||
bool sym_IsPurgedScoped(std::string const &symName);
|
bool sym_IsPurgedScoped(std::string const &symName);
|
||||||
void sym_Init(time_t now);
|
void sym_Init(time_t now);
|
||||||
|
|
||||||
// Functions to save and restore the current label scope.
|
// Functions to save and restore the current label scopes.
|
||||||
Symbol const *sym_GetCurrentLabelScope();
|
std::pair<Symbol const *, Symbol const *> sym_GetCurrentLabelScopes();
|
||||||
void sym_SetCurrentLabelScope(Symbol const *newScope);
|
void sym_SetCurrentLabelScopes(std::pair<Symbol const *, Symbol const *> newScopes);
|
||||||
|
void sym_ResetCurrentLabelScopes();
|
||||||
|
|
||||||
#endif // RGBDS_ASM_SYMBOL_HPP
|
#endif // RGBDS_ASM_SYMBOL_HPP
|
||||||
|
|||||||
@@ -1527,6 +1527,7 @@ The following symbols are defined by the assembler:
|
|||||||
.It Sy Name Ta Sy Type Ta Sy Contents
|
.It Sy Name Ta Sy Type Ta Sy Contents
|
||||||
.It Dv @ Ta Ic EQU Ta PC value (essentially, the current memory address)
|
.It Dv @ Ta Ic EQU Ta PC value (essentially, the current memory address)
|
||||||
.It Dv . Ta Ic EQUS Ta The current global label scope
|
.It Dv . Ta Ic EQUS Ta The current global label scope
|
||||||
|
.It Dv .. Ta Ic EQUS Ta The current local label scope
|
||||||
.It Dv _RS Ta Ic = Ta _RS Counter
|
.It Dv _RS Ta Ic = Ta _RS Counter
|
||||||
.It Dv _NARG Ta Ic EQU Ta Number of arguments passed to macro, updated by Ic SHIFT
|
.It Dv _NARG Ta Ic EQU Ta Number of arguments passed to macro, updated by Ic SHIFT
|
||||||
.It Dv __DATE__ Ta Ic EQUS Ta Today's date
|
.It Dv __DATE__ Ta Ic EQUS Ta Today's date
|
||||||
|
|||||||
@@ -1174,7 +1174,7 @@ static Token readIdentifier(char firstChar, bool raw) {
|
|||||||
return Token(search->second);
|
return Token(search->second);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Label scope `.` is the only nonlocal identifier that starts with a dot
|
// Label scopes `.` and `..` are the only nonlocal identifiers that start with a dot
|
||||||
if (identifier.find_first_not_of('.') == identifier.npos)
|
if (identifier.find_first_not_of('.') == identifier.npos)
|
||||||
tokenType = T_(ID);
|
tokenType = T_(ID);
|
||||||
|
|
||||||
|
|||||||
@@ -10,6 +10,7 @@
|
|||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
|
#include <utility>
|
||||||
|
|
||||||
#include "helpers.hpp"
|
#include "helpers.hpp"
|
||||||
|
|
||||||
@@ -31,7 +32,7 @@ struct UnionStackEntry {
|
|||||||
struct SectionStackEntry {
|
struct SectionStackEntry {
|
||||||
Section *section;
|
Section *section;
|
||||||
Section *loadSection;
|
Section *loadSection;
|
||||||
Symbol const *scope;
|
std::pair<Symbol const *, Symbol const *> labelScopes;
|
||||||
uint32_t offset;
|
uint32_t offset;
|
||||||
int32_t loadOffset;
|
int32_t loadOffset;
|
||||||
std::stack<UnionStackEntry> unionStack;
|
std::stack<UnionStackEntry> unionStack;
|
||||||
@@ -44,7 +45,7 @@ std::unordered_map<std::string, size_t> sectionMap; // Indexes into `sectionList
|
|||||||
uint32_t curOffset; // Offset into the current section (see sect_GetSymbolOffset)
|
uint32_t curOffset; // Offset into the current section (see sect_GetSymbolOffset)
|
||||||
Section *currentSection = nullptr;
|
Section *currentSection = nullptr;
|
||||||
static Section *currentLoadSection = nullptr;
|
static Section *currentLoadSection = nullptr;
|
||||||
static Symbol const *currentLoadScope = nullptr;
|
static std::pair<Symbol const *, Symbol const *> currentLoadLabelScopes = {nullptr, nullptr};
|
||||||
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
|
||||||
@@ -395,7 +396,7 @@ static void changeSection() {
|
|||||||
if (!currentUnionStack.empty())
|
if (!currentUnionStack.empty())
|
||||||
fatalerror("Cannot change the section within a UNION\n");
|
fatalerror("Cannot change the section within a UNION\n");
|
||||||
|
|
||||||
sym_SetCurrentLabelScope(nullptr);
|
sym_ResetCurrentLabelScopes();
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Section::isSizeKnown() const {
|
bool Section::isSizeKnown() const {
|
||||||
@@ -473,7 +474,7 @@ void sect_SetLoadSection(
|
|||||||
|
|
||||||
Section *sect = getSection(name, type, org, attrs, mod);
|
Section *sect = getSection(name, type, org, attrs, mod);
|
||||||
|
|
||||||
currentLoadScope = sym_GetCurrentLabelScope();
|
currentLoadLabelScopes = sym_GetCurrentLabelScopes();
|
||||||
changeSection();
|
changeSection();
|
||||||
loadOffset = curOffset - (mod == SECTION_UNION ? 0 : sect->size);
|
loadOffset = curOffset - (mod == SECTION_UNION ? 0 : sect->size);
|
||||||
curOffset -= loadOffset;
|
curOffset -= loadOffset;
|
||||||
@@ -490,7 +491,7 @@ void sect_EndLoadSection() {
|
|||||||
curOffset += loadOffset;
|
curOffset += loadOffset;
|
||||||
loadOffset = 0;
|
loadOffset = 0;
|
||||||
currentLoadSection = nullptr;
|
currentLoadSection = nullptr;
|
||||||
sym_SetCurrentLabelScope(currentLoadScope);
|
sym_SetCurrentLabelScopes(currentLoadLabelScopes);
|
||||||
}
|
}
|
||||||
|
|
||||||
Section *sect_GetSymbolSection() {
|
Section *sect_GetSymbolSection() {
|
||||||
@@ -935,7 +936,7 @@ void sect_PushSection() {
|
|||||||
sectionStack.push_front({
|
sectionStack.push_front({
|
||||||
.section = currentSection,
|
.section = currentSection,
|
||||||
.loadSection = currentLoadSection,
|
.loadSection = currentLoadSection,
|
||||||
.scope = sym_GetCurrentLabelScope(),
|
.labelScopes = sym_GetCurrentLabelScopes(),
|
||||||
.offset = curOffset,
|
.offset = curOffset,
|
||||||
.loadOffset = loadOffset,
|
.loadOffset = loadOffset,
|
||||||
.unionStack = {},
|
.unionStack = {},
|
||||||
@@ -944,7 +945,7 @@ void sect_PushSection() {
|
|||||||
// Reset the section scope
|
// Reset the section scope
|
||||||
currentSection = nullptr;
|
currentSection = nullptr;
|
||||||
currentLoadSection = nullptr;
|
currentLoadSection = nullptr;
|
||||||
sym_SetCurrentLabelScope(nullptr);
|
sym_ResetCurrentLabelScopes();
|
||||||
std::swap(currentUnionStack, sectionStack.front().unionStack);
|
std::swap(currentUnionStack, sectionStack.front().unionStack);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -961,7 +962,7 @@ void sect_PopSection() {
|
|||||||
changeSection();
|
changeSection();
|
||||||
currentSection = entry.section;
|
currentSection = entry.section;
|
||||||
currentLoadSection = entry.loadSection;
|
currentLoadSection = entry.loadSection;
|
||||||
sym_SetCurrentLabelScope(entry.scope);
|
sym_SetCurrentLabelScopes(entry.labelScopes);
|
||||||
curOffset = entry.offset;
|
curOffset = entry.offset;
|
||||||
loadOffset = entry.loadOffset;
|
loadOffset = entry.loadOffset;
|
||||||
std::swap(currentUnionStack, entry.unionStack);
|
std::swap(currentUnionStack, entry.unionStack);
|
||||||
@@ -979,5 +980,5 @@ void sect_EndSection() {
|
|||||||
|
|
||||||
// Reset the section scope
|
// Reset the section scope
|
||||||
currentSection = nullptr;
|
currentSection = nullptr;
|
||||||
sym_SetCurrentLabelScope(nullptr);
|
sym_ResetCurrentLabelScopes();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -22,10 +22,12 @@ using namespace std::literals;
|
|||||||
std::unordered_map<std::string, Symbol> symbols;
|
std::unordered_map<std::string, Symbol> symbols;
|
||||||
std::unordered_set<std::string> purgedSymbols;
|
std::unordered_set<std::string> purgedSymbols;
|
||||||
|
|
||||||
static Symbol const *labelScope = nullptr; // Current section's label scope
|
static Symbol const *globalScope = nullptr; // Current section's global label scope
|
||||||
|
static Symbol const *localScope = nullptr; // Current section's local label scope
|
||||||
static Symbol *PCSymbol;
|
static Symbol *PCSymbol;
|
||||||
static Symbol *NARGSymbol;
|
static Symbol *NARGSymbol;
|
||||||
static Symbol *labelScopeSymbol;
|
static Symbol *globalScopeSymbol;
|
||||||
|
static Symbol *localScopeSymbol;
|
||||||
static Symbol *RSSymbol;
|
static Symbol *RSSymbol;
|
||||||
static char savedTIME[256];
|
static char savedTIME[256];
|
||||||
static char savedDATE[256];
|
static char savedDATE[256];
|
||||||
@@ -51,12 +53,20 @@ static int32_t NARGCallback() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static std::shared_ptr<std::string> labelScopeCallback() {
|
static std::shared_ptr<std::string> globalScopeCallback() {
|
||||||
if (!labelScope) {
|
if (!globalScope) {
|
||||||
error("\".\" has no value outside of a label scope\n");
|
error("\".\" has no value outside of a label scope\n");
|
||||||
return std::make_shared<std::string>("");
|
return std::make_shared<std::string>("");
|
||||||
}
|
}
|
||||||
return std::make_shared<std::string>(labelScope->name);
|
return std::make_shared<std::string>(globalScope->name);
|
||||||
|
}
|
||||||
|
|
||||||
|
static std::shared_ptr<std::string> localScopeCallback() {
|
||||||
|
if (!localScope) {
|
||||||
|
error("\"..\" has no value outside of a local label scope\n");
|
||||||
|
return std::make_shared<std::string>("");
|
||||||
|
}
|
||||||
|
return std::make_shared<std::string>(localScope->name);
|
||||||
}
|
}
|
||||||
|
|
||||||
static int32_t PCCallback() {
|
static int32_t PCCallback() {
|
||||||
@@ -141,7 +151,7 @@ static void redefinedError(Symbol const &sym) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
static void assumeAlreadyExpanded(std::string const &symName) {
|
static void assumeAlreadyExpanded(std::string const &symName) {
|
||||||
// Either the symbol name is `Global.local` or entirely '.'s (for global scope `.`),
|
// Either the symbol name is `Global.local` or entirely '.'s (for scopes `.` and `..`),
|
||||||
// but cannot be unqualified `.local`
|
// but cannot be unqualified `.local`
|
||||||
assume(!symName.starts_with('.') || symName.find_first_not_of('.') == symName.npos);
|
assume(!symName.starts_with('.') || symName.find_first_not_of('.') == symName.npos);
|
||||||
}
|
}
|
||||||
@@ -166,8 +176,10 @@ static Symbol &createSymbol(std::string const &symName) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
static bool isAutoScoped(std::string const &symName) {
|
static bool isAutoScoped(std::string const &symName) {
|
||||||
// `labelScope` should be global if it's defined
|
// `globalScope` should be global if it's defined
|
||||||
assume(!labelScope || labelScope->name.find('.') == std::string::npos);
|
assume(!globalScope || globalScope->name.find('.') == std::string::npos);
|
||||||
|
// `localScope` should be qualified local if it's defined
|
||||||
|
assume(!localScope || localScope->name.find('.') != std::string::npos);
|
||||||
|
|
||||||
size_t dotPos = symName.find('.');
|
size_t dotPos = symName.find('.');
|
||||||
|
|
||||||
@@ -175,7 +187,7 @@ static bool isAutoScoped(std::string const &symName) {
|
|||||||
if (dotPos == std::string::npos)
|
if (dotPos == std::string::npos)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
// Label scope `.` is the only nonlocal identifier that starts with a dot
|
// Label scopes `.` and `..` are the only nonlocal identifiers that start with a dot
|
||||||
if (dotPos == 0 && symName.find_first_not_of('.') == symName.npos)
|
if (dotPos == 0 && symName.find_first_not_of('.') == symName.npos)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
@@ -192,7 +204,7 @@ static bool isAutoScoped(std::string const &symName) {
|
|||||||
return false;
|
return false;
|
||||||
|
|
||||||
// Check for unqualifiable local label
|
// Check for unqualifiable local label
|
||||||
if (!labelScope)
|
if (!globalScope)
|
||||||
fatalerror("Unqualified local label '%s' in main scope\n", symName.c_str());
|
fatalerror("Unqualified local label '%s' in main scope\n", symName.c_str());
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
@@ -206,7 +218,7 @@ Symbol *sym_FindExactSymbol(std::string const &symName) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
Symbol *sym_FindScopedSymbol(std::string const &symName) {
|
Symbol *sym_FindScopedSymbol(std::string const &symName) {
|
||||||
return sym_FindExactSymbol(isAutoScoped(symName) ? labelScope->name + symName : symName);
|
return sym_FindExactSymbol(isAutoScoped(symName) ? globalScope->name + symName : symName);
|
||||||
}
|
}
|
||||||
|
|
||||||
Symbol *sym_FindScopedValidSymbol(std::string const &symName) {
|
Symbol *sym_FindScopedValidSymbol(std::string const &symName) {
|
||||||
@@ -220,8 +232,12 @@ Symbol *sym_FindScopedValidSymbol(std::string const &symName) {
|
|||||||
if (sym == NARGSymbol && !fstk_GetCurrentMacroArgs()) {
|
if (sym == NARGSymbol && !fstk_GetCurrentMacroArgs()) {
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
// `.` has no value outside of a label scope
|
// `.` has no value outside of a global label scope
|
||||||
if (sym == labelScopeSymbol && !labelScope) {
|
if (sym == globalScopeSymbol && !globalScope) {
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
// `..` has no value outside of a local label scope
|
||||||
|
if (sym == localScopeSymbol && !localScope) {
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -250,8 +266,10 @@ void sym_Purge(std::string const &symName) {
|
|||||||
else if (sym->isLabel())
|
else if (sym->isLabel())
|
||||||
warning(WARNING_PURGE_2, "Purging a label \"%s\"\n", symName.c_str());
|
warning(WARNING_PURGE_2, "Purging a label \"%s\"\n", symName.c_str());
|
||||||
// Do not keep a reference to the label after purging it
|
// Do not keep a reference to the label after purging it
|
||||||
if (labelScope == sym)
|
if (sym == globalScope)
|
||||||
labelScope = nullptr;
|
globalScope = nullptr;
|
||||||
|
if (sym == localScope)
|
||||||
|
localScope = nullptr;
|
||||||
purgedSymbols.emplace(sym->name);
|
purgedSymbols.emplace(sym->name);
|
||||||
symbols.erase(sym->name);
|
symbols.erase(sym->name);
|
||||||
}
|
}
|
||||||
@@ -264,7 +282,7 @@ bool sym_IsPurgedExact(std::string const &symName) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
bool sym_IsPurgedScoped(std::string const &symName) {
|
bool sym_IsPurgedScoped(std::string const &symName) {
|
||||||
return sym_IsPurgedExact(isAutoScoped(symName) ? labelScope->name + symName : symName);
|
return sym_IsPurgedExact(isAutoScoped(symName) ? globalScope->name + symName : symName);
|
||||||
}
|
}
|
||||||
|
|
||||||
int32_t sym_GetRSValue() {
|
int32_t sym_GetRSValue() {
|
||||||
@@ -302,12 +320,23 @@ uint32_t sym_GetConstantValue(std::string const &symName) {
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
Symbol const *sym_GetCurrentLabelScope() {
|
std::pair<Symbol const *, Symbol const *> sym_GetCurrentLabelScopes() {
|
||||||
return labelScope;
|
return {globalScope, localScope};
|
||||||
}
|
}
|
||||||
|
|
||||||
void sym_SetCurrentLabelScope(Symbol const *newScope) {
|
void sym_SetCurrentLabelScopes(std::pair<Symbol const *, Symbol const *> newScopes) {
|
||||||
labelScope = newScope;
|
globalScope = std::get<0>(newScopes);
|
||||||
|
localScope = std::get<1>(newScopes);
|
||||||
|
|
||||||
|
// `globalScope` should be global if it's defined
|
||||||
|
assume(!globalScope || globalScope->name.find('.') == std::string::npos);
|
||||||
|
// `localScope` should be qualified local if it's defined
|
||||||
|
assume(!localScope || localScope->name.find('.') != std::string::npos);
|
||||||
|
}
|
||||||
|
|
||||||
|
void sym_ResetCurrentLabelScopes() {
|
||||||
|
globalScope = nullptr;
|
||||||
|
localScope = nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
static Symbol *createNonrelocSymbol(std::string const &symName, bool numeric) {
|
static Symbol *createNonrelocSymbol(std::string const &symName, bool numeric) {
|
||||||
@@ -447,15 +476,25 @@ Symbol *sym_AddLocalLabel(std::string const &symName) {
|
|||||||
// The symbol name should be local, qualified or not
|
// The symbol name should be local, qualified or not
|
||||||
assume(symName.find('.') != std::string::npos);
|
assume(symName.find('.') != std::string::npos);
|
||||||
|
|
||||||
return addLabel(isAutoScoped(symName) ? labelScope->name + symName : symName);
|
Symbol *sym = addLabel(isAutoScoped(symName) ? globalScope->name + symName : symName);
|
||||||
|
|
||||||
|
if (sym)
|
||||||
|
localScope = sym;
|
||||||
|
|
||||||
|
return sym;
|
||||||
}
|
}
|
||||||
|
|
||||||
Symbol *sym_AddLabel(std::string const &symName) {
|
Symbol *sym_AddLabel(std::string const &symName) {
|
||||||
|
// The symbol name should be global
|
||||||
|
assume(symName.find('.') == std::string::npos);
|
||||||
|
|
||||||
Symbol *sym = addLabel(symName);
|
Symbol *sym = addLabel(symName);
|
||||||
|
|
||||||
// Set the symbol as the new scope
|
if (sym) {
|
||||||
if (sym)
|
globalScope = sym;
|
||||||
labelScope = sym;
|
// A new global scope resets the local scope
|
||||||
|
localScope = nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
return sym;
|
return sym;
|
||||||
}
|
}
|
||||||
@@ -542,7 +581,7 @@ Symbol *sym_Ref(std::string const &symName) {
|
|||||||
Symbol *sym = sym_FindScopedSymbol(symName);
|
Symbol *sym = sym_FindScopedSymbol(symName);
|
||||||
|
|
||||||
if (!sym) {
|
if (!sym) {
|
||||||
sym = &createSymbol(isAutoScoped(symName) ? labelScope->name + symName : symName);
|
sym = &createSymbol(isAutoScoped(symName) ? globalScope->name + symName : symName);
|
||||||
sym->type = SYM_REF;
|
sym->type = SYM_REF;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -566,10 +605,15 @@ void sym_Init(time_t now) {
|
|||||||
NARGSymbol->data = NARGCallback;
|
NARGSymbol->data = NARGCallback;
|
||||||
NARGSymbol->isBuiltin = true;
|
NARGSymbol->isBuiltin = true;
|
||||||
|
|
||||||
labelScopeSymbol = &createSymbol("."s);
|
globalScopeSymbol = &createSymbol("."s);
|
||||||
labelScopeSymbol->type = SYM_EQUS;
|
globalScopeSymbol->type = SYM_EQUS;
|
||||||
labelScopeSymbol->data = labelScopeCallback;
|
globalScopeSymbol->data = globalScopeCallback;
|
||||||
labelScopeSymbol->isBuiltin = true;
|
globalScopeSymbol->isBuiltin = true;
|
||||||
|
|
||||||
|
localScopeSymbol = &createSymbol(".."s);
|
||||||
|
localScopeSymbol->type = SYM_EQUS;
|
||||||
|
localScopeSymbol->data = localScopeCallback;
|
||||||
|
localScopeSymbol->isBuiltin = true;
|
||||||
|
|
||||||
RSSymbol = sym_AddVar("_RS"s, 0);
|
RSSymbol = sym_AddVar("_RS"s, 0);
|
||||||
RSSymbol->isBuiltin = true;
|
RSSymbol->isBuiltin = true;
|
||||||
|
|||||||
@@ -1,12 +1,18 @@
|
|||||||
ASSERT !DEF(@) && !DEF(.)
|
ASSERT !DEF(@) && !DEF(.) && !DEF(..)
|
||||||
|
|
||||||
PURGE @, .
|
PURGE @, ., ..
|
||||||
|
|
||||||
SECTION "test", ROM0[42]
|
SECTION "test", ROM0[42]
|
||||||
Foobar:
|
db 1
|
||||||
|
Foo:
|
||||||
|
db 2
|
||||||
|
.bar
|
||||||
|
db 3
|
||||||
|
|
||||||
PURGE @, .
|
PURGE @, ., ..
|
||||||
|
|
||||||
ASSERT DEF(@) && DEF(.) && DEF(Foobar)
|
ASSERT DEF(@) && DEF(.) && DEF(..) && DEF(Foo) && DEF(.bar)
|
||||||
|
|
||||||
PRINTLN "PC: {#05X:@}; label scope: \"{.}\"; {.}: {#05X:{.}}"
|
PRINTLN "PC: {#05X:@}"
|
||||||
|
PRINTLN "global scope: \"{.}\" ({#05X:{.}})"
|
||||||
|
PRINTLN "local scope: \"{..}\" ({#05X:{..}})"
|
||||||
|
|||||||
@@ -2,8 +2,12 @@ error: label-scope.asm(3):
|
|||||||
'@' not defined
|
'@' not defined
|
||||||
error: label-scope.asm(3):
|
error: label-scope.asm(3):
|
||||||
'.' not defined
|
'.' not defined
|
||||||
error: label-scope.asm(8):
|
error: label-scope.asm(3):
|
||||||
|
'..' not defined
|
||||||
|
error: label-scope.asm(12):
|
||||||
Built-in symbol '@' cannot be purged
|
Built-in symbol '@' cannot be purged
|
||||||
error: label-scope.asm(8):
|
error: label-scope.asm(12):
|
||||||
Built-in symbol '.' cannot be purged
|
Built-in symbol '.' cannot be purged
|
||||||
error: Assembly aborted (4 errors)!
|
error: label-scope.asm(12):
|
||||||
|
Built-in symbol '..' cannot be purged
|
||||||
|
error: Assembly aborted (6 errors)!
|
||||||
|
|||||||
@@ -1 +1,3 @@
|
|||||||
PC: $002A; label scope: "Foobar"; Foobar: $002A
|
PC: $002D
|
||||||
|
global scope: "Foo" ($002B)
|
||||||
|
local scope: "Foo.bar" ($002C)
|
||||||
|
|||||||
@@ -1,6 +1,33 @@
|
|||||||
section "period", rom0
|
SECTION "period", ROM0
|
||||||
|
|
||||||
global1: db 1
|
assert !def(.) && !def(..)
|
||||||
.local db 2
|
|
||||||
. db 3 ; this...
|
global1:
|
||||||
global1 db 4 ; ...expands to this
|
assert !strcmp("{.}", "global1") && !def(..)
|
||||||
|
|
||||||
|
.local1:
|
||||||
|
assert !strcmp("{.}", "global1") && !strcmp("{..}", "global1.local1")
|
||||||
|
|
||||||
|
global1.local2:
|
||||||
|
assert !strcmp("{.}", "global1") && !strcmp("{..}", "global1.local2")
|
||||||
|
|
||||||
|
global2:
|
||||||
|
assert !strcmp("{.}", "global2") && !def(..)
|
||||||
|
|
||||||
|
.local1:
|
||||||
|
assert !strcmp("{.}", "global2") && !strcmp("{..}", "global2.local1")
|
||||||
|
|
||||||
|
LOAD "load", WRAM0
|
||||||
|
assert !def(.) && !def(..)
|
||||||
|
|
||||||
|
wGlobal1:
|
||||||
|
assert !strcmp("{.}", "wGlobal1") && !def(..)
|
||||||
|
|
||||||
|
.wLocal1:
|
||||||
|
assert !strcmp("{.}", "wGlobal1") && !strcmp("{..}", "wGlobal1.wLocal1")
|
||||||
|
|
||||||
|
wGlobal2:
|
||||||
|
assert !strcmp("{.}", "wGlobal2") && !def(..)
|
||||||
|
|
||||||
|
ENDL
|
||||||
|
assert !strcmp("{.}", "global2") && !strcmp("{..}", "global2.local1")
|
||||||
|
|||||||
@@ -1,5 +0,0 @@
|
|||||||
error: period.asm(5):
|
|
||||||
syntax error, unexpected DB, expecting : or ::
|
|
||||||
error: period.asm(6):
|
|
||||||
syntax error, unexpected DB, expecting : or ::
|
|
||||||
error: Assembly aborted (2 errors)!
|
|
||||||
@@ -3,11 +3,16 @@ assert !DEF(@)
|
|||||||
println @
|
println @
|
||||||
println "{@}?"
|
println "{@}?"
|
||||||
|
|
||||||
; not inside a label scope
|
; not inside a global scope
|
||||||
assert !DEF(.)
|
assert !DEF(.)
|
||||||
println .
|
println .
|
||||||
println "{.}?"
|
println "{.}?"
|
||||||
|
|
||||||
|
; not inside a local scope
|
||||||
|
assert !DEF(..)
|
||||||
|
println ..
|
||||||
|
println "{..}?"
|
||||||
|
|
||||||
; not inside a macro
|
; not inside a macro
|
||||||
assert !DEF(_NARG)
|
assert !DEF(_NARG)
|
||||||
println _NARG
|
println _NARG
|
||||||
@@ -18,11 +23,16 @@ assert DEF(@)
|
|||||||
println @
|
println @
|
||||||
println "{@}!"
|
println "{@}!"
|
||||||
|
|
||||||
LabelScope:
|
GlobalScope:
|
||||||
assert DEF(.)
|
assert DEF(.)
|
||||||
println .
|
println .
|
||||||
println "{.}!"
|
println "{.}!"
|
||||||
|
|
||||||
|
.localScope:
|
||||||
|
assert DEF(..)
|
||||||
|
println ..
|
||||||
|
println "{..}!"
|
||||||
|
|
||||||
MACRO m
|
MACRO m
|
||||||
assert DEF(_NARG)
|
assert DEF(_NARG)
|
||||||
println _NARG
|
println _NARG
|
||||||
|
|||||||
@@ -7,7 +7,11 @@ error: undefined-builtins.asm(8):
|
|||||||
error: undefined-builtins.asm(9):
|
error: undefined-builtins.asm(9):
|
||||||
Interpolated symbol "." does not exist
|
Interpolated symbol "." does not exist
|
||||||
error: undefined-builtins.asm(13):
|
error: undefined-builtins.asm(13):
|
||||||
_NARG has no value outside of a macro
|
".." has no value outside of a local label scope
|
||||||
error: undefined-builtins.asm(14):
|
error: undefined-builtins.asm(14):
|
||||||
|
Interpolated symbol ".." does not exist
|
||||||
|
error: undefined-builtins.asm(18):
|
||||||
|
_NARG has no value outside of a macro
|
||||||
|
error: undefined-builtins.asm(19):
|
||||||
Interpolated symbol "_NARG" does not exist
|
Interpolated symbol "_NARG" does not exist
|
||||||
error: Assembly aborted (6 errors)!
|
error: Assembly aborted (8 errors)!
|
||||||
|
|||||||
@@ -1,12 +1,16 @@
|
|||||||
$0
|
$0
|
||||||
?
|
?
|
||||||
|
|
||||||
|
?
|
||||||
|
|
||||||
?
|
?
|
||||||
$0
|
$0
|
||||||
?
|
?
|
||||||
$42
|
$42
|
||||||
$42!
|
$42!
|
||||||
$42
|
$42
|
||||||
LabelScope!
|
GlobalScope!
|
||||||
|
$42
|
||||||
|
GlobalScope.localScope!
|
||||||
$3
|
$3
|
||||||
$3!
|
$3!
|
||||||
|
|||||||
Reference in New Issue
Block a user