mirror of
https://github.com/gbdev/rgbds.git
synced 2025-12-05 17:27:48 +00:00
Symbol names with more than two '.'s could be defined as constants
Dot-only names could also trip an assertion in `make develop` when used as labels
This commit is contained in:
@@ -68,6 +68,8 @@ struct Symbol {
|
|||||||
uint32_t getConstantValue() const;
|
uint32_t getConstantValue() const;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
bool sym_IsDotScope(std::string const &symName);
|
||||||
|
|
||||||
void sym_ForEach(void (*callback)(Symbol &));
|
void sym_ForEach(void (*callback)(Symbol &));
|
||||||
|
|
||||||
Symbol *sym_AddLocalLabel(std::string const &symName);
|
Symbol *sym_AddLocalLabel(std::string const &symName);
|
||||||
|
|||||||
@@ -1295,7 +1295,7 @@ static Token readIdentifier(char firstChar, bool raw) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Label scopes `.` and `..` are the only nonlocal identifiers that start 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 (sym_IsDotScope(identifier)) {
|
||||||
tokenType = T_(SYMBOL);
|
tokenType = T_(SYMBOL);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1939,11 +1939,12 @@ static Token yylex_NORMAL() {
|
|||||||
|
|
||||||
// `token` is either a `SYMBOL` or a `LOCAL`, and both have a `std::string` value.
|
// `token` is either a `SYMBOL` or a `LOCAL`, and both have a `std::string` value.
|
||||||
assume(std::holds_alternative<std::string>(token.value));
|
assume(std::holds_alternative<std::string>(token.value));
|
||||||
|
std::string const &identifier = std::get<std::string>(token.value);
|
||||||
|
|
||||||
// Raw symbols and local symbols cannot be string expansions
|
// Raw symbols and local symbols cannot be string expansions
|
||||||
if (!raw && token.type == T_(SYMBOL) && lexerState->expandStrings) {
|
if (!raw && token.type == T_(SYMBOL) && lexerState->expandStrings) {
|
||||||
// Attempt string expansion
|
// Attempt string expansion
|
||||||
if (Symbol const *sym = sym_FindExactSymbol(std::get<std::string>(token.value));
|
if (Symbol const *sym = sym_FindExactSymbol(identifier);
|
||||||
sym && sym->type == SYM_EQUS) {
|
sym && sym->type == SYM_EQUS) {
|
||||||
beginExpansion(sym->getEqus(), sym->name);
|
beginExpansion(sym->getEqus(), sym->name);
|
||||||
continue; // Restart, reading from the new buffer
|
continue; // Restart, reading from the new buffer
|
||||||
@@ -1954,6 +1955,7 @@ static Token yylex_NORMAL() {
|
|||||||
// - label definitions (which are followed by a ':' and use the token `LABEL`)
|
// - label definitions (which are followed by a ':' and use the token `LABEL`)
|
||||||
// - quiet macro invocations (which are followed by a '?' and use the token `QMACRO`)
|
// - quiet macro invocations (which are followed by a '?' and use the token `QMACRO`)
|
||||||
// - regular macro invocations (which use the token `SYMBOL`)
|
// - regular macro invocations (which use the token `SYMBOL`)
|
||||||
|
// - label scopes "." and ".." (which use the token `SYMBOL` no matter what)
|
||||||
//
|
//
|
||||||
// If we had one `IDENTIFIER` token, the parser would need to perform "lookahead" to
|
// If we had one `IDENTIFIER` token, the parser would need to perform "lookahead" to
|
||||||
// determine which rule applies. But since macros need to enter "raw" mode to parse
|
// determine which rule applies. But since macros need to enter "raw" mode to parse
|
||||||
@@ -1964,7 +1966,7 @@ static Token yylex_NORMAL() {
|
|||||||
// one to lex depending on the character *immediately* following the identifier.
|
// one to lex depending on the character *immediately* following the identifier.
|
||||||
// Thus "name:" is a label definition, and "name?" is a quiet macro invocation, but
|
// Thus "name:" is a label definition, and "name?" is a quiet macro invocation, but
|
||||||
// "name :" and "name ?" and just "name" are all regular macro invocations.
|
// "name :" and "name ?" and just "name" are all regular macro invocations.
|
||||||
if (token.type == T_(SYMBOL)) {
|
if (token.type == T_(SYMBOL) && !sym_IsDotScope(identifier)) {
|
||||||
c = peek();
|
c = peek();
|
||||||
token.type = c == ':' ? T_(LABEL) : c == '?' ? T_(QMACRO) : T_(SYMBOL);
|
token.type = c == ':' ? T_(LABEL) : c == '?' ? T_(QMACRO) : T_(SYMBOL);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -53,6 +53,12 @@ bool sym_IsPC(Symbol const *sym) {
|
|||||||
return sym == PCSymbol;
|
return sym == PCSymbol;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool sym_IsDotScope(std::string const &symName) {
|
||||||
|
// Label scopes `.` and `..` are the only nonlocal identifiers that start with a dot.
|
||||||
|
// Three or more dots are considered a nonsensical local label.
|
||||||
|
return symName == "." || symName == "..";
|
||||||
|
}
|
||||||
|
|
||||||
void sym_ForEach(void (*callback)(Symbol &)) {
|
void sym_ForEach(void (*callback)(Symbol &)) {
|
||||||
for (auto &it : symbols) {
|
for (auto &it : symbols) {
|
||||||
callback(it.second);
|
callback(it.second);
|
||||||
@@ -215,8 +221,8 @@ 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 scopes `.` and `..`),
|
// Either the symbol name is `Global.local` or entirely '.'s (for scopes `.` and `..`),
|
||||||
// but cannot be unqualified `.local`
|
// but cannot be unqualified `.local` or more than two '.'s
|
||||||
assume(!symName.starts_with('.') || symName.find_first_not_of('.') == symName.npos);
|
assume(!symName.starts_with('.') || sym_IsDotScope(symName));
|
||||||
}
|
}
|
||||||
|
|
||||||
static Symbol &createSymbol(std::string const &symName) {
|
static Symbol &createSymbol(std::string const &symName) {
|
||||||
@@ -253,7 +259,7 @@ static bool isAutoScoped(std::string const &symName) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Label scopes `.` and `..` are the only nonlocal identifiers that start 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 (sym_IsDotScope(symName)) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
2
test/asm/dots-constant.asm
Normal file
2
test/asm/dots-constant.asm
Normal file
@@ -0,0 +1,2 @@
|
|||||||
|
section "test", rom0
|
||||||
|
def #... equs "sublocal"
|
||||||
3
test/asm/dots-constant.err
Normal file
3
test/asm/dots-constant.err
Normal file
@@ -0,0 +1,3 @@
|
|||||||
|
error: syntax error, unexpected local label, expecting symbol
|
||||||
|
at dots-constant.asm(2)
|
||||||
|
Assembly aborted with 1 error!
|
||||||
2
test/asm/dots-interpolate.asm
Normal file
2
test/asm/dots-interpolate.asm
Normal file
@@ -0,0 +1,2 @@
|
|||||||
|
section "test", rom0
|
||||||
|
println "{...}"
|
||||||
2
test/asm/dots-interpolate.err
Normal file
2
test/asm/dots-interpolate.err
Normal file
@@ -0,0 +1,2 @@
|
|||||||
|
FATAL: `...` is a nonsensical reference to a nested local label
|
||||||
|
at dots-interpolate.asm(2)
|
||||||
2
test/asm/dots-label.asm
Normal file
2
test/asm/dots-label.asm
Normal file
@@ -0,0 +1,2 @@
|
|||||||
|
section "test", rom0
|
||||||
|
#...:
|
||||||
2
test/asm/dots-label.err
Normal file
2
test/asm/dots-label.err
Normal file
@@ -0,0 +1,2 @@
|
|||||||
|
FATAL: `...` is a nonsensical reference to a nested local label
|
||||||
|
at dots-label.asm(2)
|
||||||
4
test/asm/dots-macro-arg.asm
Normal file
4
test/asm/dots-macro-arg.asm
Normal file
@@ -0,0 +1,4 @@
|
|||||||
|
MACRO test
|
||||||
|
println "\<...>"
|
||||||
|
ENDM
|
||||||
|
test 1, 2, 3, 4
|
||||||
2
test/asm/dots-macro-arg.err
Normal file
2
test/asm/dots-macro-arg.err
Normal file
@@ -0,0 +1,2 @@
|
|||||||
|
FATAL: `...` is a nonsensical reference to a nested local label
|
||||||
|
at dots-macro-arg.asm::test(2) <- dots-macro-arg.asm(4)
|
||||||
@@ -16,3 +16,17 @@ ASSERT DEF(@) && DEF(.) && DEF(..) && DEF(Foo) && DEF(.bar)
|
|||||||
PRINTLN "PC: {#05X:@}"
|
PRINTLN "PC: {#05X:@}"
|
||||||
PRINTLN "global scope: \"{.}\" ({#05X:{.}})"
|
PRINTLN "global scope: \"{.}\" ({#05X:{.}})"
|
||||||
PRINTLN "local scope: \"{..}\" ({#05X:{..}})"
|
PRINTLN "local scope: \"{..}\" ({#05X:{..}})"
|
||||||
|
|
||||||
|
SECTION "can't redefine", ROM0
|
||||||
|
|
||||||
|
#.
|
||||||
|
#.:
|
||||||
|
#.?
|
||||||
|
DEF #. EQUS "global"
|
||||||
|
jp #.
|
||||||
|
|
||||||
|
#..
|
||||||
|
#..:
|
||||||
|
#..?
|
||||||
|
DEF #.. EQUS "local"
|
||||||
|
jp #..
|
||||||
|
|||||||
@@ -10,4 +10,32 @@ error: Built-in symbol `.` cannot be purged
|
|||||||
at label-scope.asm(12)
|
at label-scope.asm(12)
|
||||||
error: Built-in symbol `..` cannot be purged
|
error: Built-in symbol `..` cannot be purged
|
||||||
at label-scope.asm(12)
|
at label-scope.asm(12)
|
||||||
Assembly aborted with 6 errors!
|
error: `.` is not a macro
|
||||||
|
at label-scope.asm(22)
|
||||||
|
error: `.` is not a macro
|
||||||
|
at label-scope.asm(23)
|
||||||
|
error: `.` is not a macro
|
||||||
|
at label-scope.asm(24)
|
||||||
|
error: `.` is reserved for a built-in symbol
|
||||||
|
at label-scope.asm(25)
|
||||||
|
error: `.` has no value outside of a label scope
|
||||||
|
at label-scope.asm(26)
|
||||||
|
warning: Treating strings as numbers is deprecated; use character literals or `CHARVAL` instead [-Wobsolete]
|
||||||
|
at label-scope.asm(26)
|
||||||
|
error: Strings as numbers must be a single charmap unit
|
||||||
|
at label-scope.asm(26)
|
||||||
|
error: `..` is not a macro
|
||||||
|
at label-scope.asm(28)
|
||||||
|
error: `..` is not a macro
|
||||||
|
at label-scope.asm(29)
|
||||||
|
error: `..` is not a macro
|
||||||
|
at label-scope.asm(30)
|
||||||
|
error: `..` is reserved for a built-in symbol
|
||||||
|
at label-scope.asm(31)
|
||||||
|
error: `..` has no value outside of a local label scope
|
||||||
|
at label-scope.asm(32)
|
||||||
|
warning: Treating strings as numbers is deprecated; use character literals or `CHARVAL` instead [-Wobsolete]
|
||||||
|
at label-scope.asm(32)
|
||||||
|
error: Strings as numbers must be a single charmap unit
|
||||||
|
at label-scope.asm(32)
|
||||||
|
Assembly aborted with 18 errors!
|
||||||
|
|||||||
Reference in New Issue
Block a user