Implement . string constant for the current label scope (#1499)

This commit is contained in:
Sylvie
2024-09-13 15:20:01 -04:00
committed by GitHub
parent bfb96b038d
commit 122ef95d9c
15 changed files with 133 additions and 23 deletions

View File

@@ -36,10 +36,11 @@ struct Symbol {
uint32_t fileLine; // Line where the symbol was defined uint32_t fileLine; // Line where the symbol was defined
std::variant< std::variant<
int32_t, // If isNumeric() int32_t, // If isNumeric()
int32_t (*)(), // If isNumeric() and has a callback int32_t (*)(), // If isNumeric() via a callback
ContentSpan, // For SYM_MACRO ContentSpan, // For SYM_MACRO
std::shared_ptr<std::string> // For SYM_EQUS std::shared_ptr<std::string>, // For SYM_EQUS
std::shared_ptr<std::string> (*)() // For SYM_EQUS via a callback
> >
data; data;

View File

@@ -1526,6 +1526,7 @@ The following symbols are defined by the assembler:
.Bl -column -offset indent "__ISO_8601_LOCAL__" "EQUS" .Bl -column -offset indent "__ISO_8601_LOCAL__" "EQUS"
.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 _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

View File

@@ -327,8 +327,6 @@ static std::unordered_map<std::string, int, CaseInsensitive, CaseInsensitive> ke
{"POPO", T_(POP_POPO) }, {"POPO", T_(POP_POPO) },
{"OPT", T_(POP_OPT) }, {"OPT", T_(POP_OPT) },
{".", T_(PERIOD) },
}; };
static bool isWhitespace(int c) { static bool isWhitespace(int c) {
@@ -1173,6 +1171,10 @@ 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
if (identifier.find_first_not_of('.') == identifier.npos)
tokenType = T_(ID);
return Token(tokenType, identifier); return Token(tokenType, identifier);
} }

View File

@@ -107,7 +107,6 @@
%token EOB "end of buffer" %token EOB "end of buffer"
// General punctuation // General punctuation
%token PERIOD "."
%token COMMA "," %token COMMA ","
%token COLON ":" DOUBLE_COLON "::" %token COLON ":" DOUBLE_COLON "::"
%token LBRACK "[" RBRACK "]" %token LBRACK "[" RBRACK "]"

View File

@@ -25,6 +25,7 @@ std::unordered_set<std::string> purgedSymbols;
static Symbol const *labelScope = nullptr; // Current section's label scope static Symbol const *labelScope = nullptr; // Current section's label scope
static Symbol *PCSymbol; static Symbol *PCSymbol;
static Symbol *NARGSymbol; static Symbol *NARGSymbol;
static Symbol *labelScopeSymbol;
static Symbol *RSSymbol; static Symbol *RSSymbol;
static char savedTIME[256]; static char savedTIME[256];
static char savedDATE[256]; static char savedDATE[256];
@@ -50,6 +51,14 @@ static int32_t NARGCallback() {
} }
} }
static std::shared_ptr<std::string> labelScopeCallback() {
if (!labelScope) {
error("\".\" has no value outside of a label scope\n");
return std::make_shared<std::string>("");
}
return std::make_shared<std::string>(labelScope->name);
}
static int32_t PCCallback() { static int32_t PCCallback() {
return sect_GetSymbolSection()->org + sect_GetSymbolOffset(); return sect_GetSymbolSection()->org + sect_GetSymbolOffset();
} }
@@ -78,7 +87,12 @@ ContentSpan const &Symbol::getMacro() const {
} }
std::shared_ptr<std::string> Symbol::getEqus() const { std::shared_ptr<std::string> Symbol::getEqus() const {
assume(std::holds_alternative<std::shared_ptr<std::string>>(data)); assume(
std::holds_alternative<std::shared_ptr<std::string>>(data)
|| std::holds_alternative<std::shared_ptr<std::string> (*)()>(data)
);
if (auto *callback = std::get_if<std::shared_ptr<std::string> (*)()>(&data); callback)
return (*callback)();
return std::get<std::shared_ptr<std::string>>(data); return std::get<std::shared_ptr<std::string>>(data);
} }
@@ -126,9 +140,14 @@ static void redefinedError(Symbol const &sym) {
} }
} }
static void assumeAlreadyExpanded(std::string const &symName) {
// Either the symbol name is `Global.local` or entirely '.'s (for global scope `.`),
// but cannot be unqualified `.local`
assume(!symName.starts_with('.') || symName.find_first_not_of('.') == symName.npos);
}
static Symbol &createSymbol(std::string const &symName) { static Symbol &createSymbol(std::string const &symName) {
// The symbol name should have been expanded already assumeAlreadyExpanded(symName);
assume(!symName.starts_with('.'));
static uint32_t nextDefIndex = 0; static uint32_t nextDefIndex = 0;
@@ -156,6 +175,10 @@ 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
if (dotPos == 0 && symName.find_first_not_of('.') == symName.npos)
return false;
// Check for nothing after the dot // Check for nothing after the dot
if (dotPos == symName.length() - 1) if (dotPos == symName.length() - 1)
fatalerror("'%s' is a nonsensical reference to an empty local label\n", symName.c_str()); fatalerror("'%s' is a nonsensical reference to an empty local label\n", symName.c_str());
@@ -176,8 +199,7 @@ static bool isAutoScoped(std::string const &symName) {
} }
Symbol *sym_FindExactSymbol(std::string const &symName) { Symbol *sym_FindExactSymbol(std::string const &symName) {
// The symbol name should have been expanded already assumeAlreadyExpanded(symName);
assume(!symName.starts_with('.'));
auto search = symbols.find(symName); auto search = symbols.find(symName);
return search != symbols.end() ? &search->second : nullptr; return search != symbols.end() ? &search->second : nullptr;
@@ -198,6 +220,11 @@ 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
if (sym == labelScopeSymbol && !labelScope) {
return nullptr;
}
return sym; return sym;
} }
@@ -231,8 +258,7 @@ void sym_Purge(std::string const &symName) {
} }
bool sym_IsPurgedExact(std::string const &symName) { bool sym_IsPurgedExact(std::string const &symName) {
// The symbol name should have been expanded already assumeAlreadyExpanded(symName);
assume(!symName.starts_with('.'));
return purgedSymbols.find(symName) != purgedSymbols.end(); return purgedSymbols.find(symName) != purgedSymbols.end();
} }
@@ -391,8 +417,7 @@ Symbol *sym_AddVar(std::string const &symName, int32_t value) {
} }
static Symbol *addLabel(std::string const &symName) { static Symbol *addLabel(std::string const &symName) {
// The symbol name should have been expanded already assumeAlreadyExpanded(symName);
assume(!symName.starts_with('.'));
Symbol *sym = sym_FindExactSymbol(symName); Symbol *sym = sym_FindExactSymbol(symName);
@@ -541,6 +566,11 @@ void sym_Init(time_t now) {
NARGSymbol->data = NARGCallback; NARGSymbol->data = NARGCallback;
NARGSymbol->isBuiltin = true; NARGSymbol->isBuiltin = true;
labelScopeSymbol = &createSymbol("."s);
labelScopeSymbol->type = SYM_EQUS;
labelScopeSymbol->data = labelScopeCallback;
labelScopeSymbol->isBuiltin = true;
RSSymbol = sym_AddVar("_RS"s, 0); RSSymbol = sym_AddVar("_RS"s, 0);
RSSymbol->isBuiltin = true; RSSymbol->isBuiltin = true;

View File

@@ -11,5 +11,23 @@ REDEF _NARG = 78
DEF _NARG EQUS "hello" DEF _NARG EQUS "hello"
REDEF _NARG EQUS "world" REDEF _NARG EQUS "world"
SECTION "test", ROM0 SECTION "_NARG", ROM0
_NARG: _NARG:
ENDSECTION
ASSERT !DEF(.)
PURGE .
DEF . EQU 12
REDEF . EQU 34
DEF . = 56
REDEF . = 78
DEF . EQUS "hello"
REDEF . EQUS "world"
SECTION ".", ROM0
.:
ENDSECTION

View File

@@ -14,4 +14,20 @@ error: builtin-reserved.asm(12):
'_NARG' is reserved for a built-in symbol '_NARG' is reserved for a built-in symbol
error: builtin-reserved.asm(15): error: builtin-reserved.asm(15):
'_NARG' is reserved for a built-in symbol '_NARG' is reserved for a built-in symbol
error: Assembly aborted (8 errors)! error: builtin-reserved.asm(20):
'.' not defined
error: builtin-reserved.asm(22):
'.' is reserved for a built-in symbol
error: builtin-reserved.asm(23):
'.' is reserved for a built-in symbol
error: builtin-reserved.asm(25):
'.' is reserved for a built-in symbol
error: builtin-reserved.asm(26):
'.' is reserved for a built-in symbol
error: builtin-reserved.asm(28):
'.' is reserved for a built-in symbol
error: builtin-reserved.asm(29):
'.' is reserved for a built-in symbol
error: builtin-reserved.asm(32):
"." has no value outside of a label scope
error: Assembly aborted (16 errors)!

12
test/asm/label-scope.asm Normal file
View File

@@ -0,0 +1,12 @@
ASSERT !DEF(@) && !DEF(.)
PURGE @, .
SECTION "test", ROM0[42]
Foobar:
PURGE @, .
ASSERT DEF(@) && DEF(.) && DEF(Foobar)
PRINTLN "PC: {#05X:@}; label scope: \"{.}\"; {.}: {#05X:{.}}"

9
test/asm/label-scope.err Normal file
View File

@@ -0,0 +1,9 @@
error: label-scope.asm(3):
'@' not defined
error: label-scope.asm(3):
'.' not defined
error: label-scope.asm(8):
Built-in symbol '@' cannot be purged
error: label-scope.asm(8):
Built-in symbol '.' cannot be purged
error: Assembly aborted (4 errors)!

1
test/asm/label-scope.out Normal file
View File

@@ -0,0 +1 @@
PC: $002A; label scope: "Foobar"; Foobar: $002A

View File

@@ -2,4 +2,5 @@ section "period", rom0
global1: db 1 global1: db 1
.local db 2 .local db 2
. db 3 . db 3 ; this...
global1 db 4 ; ...expands to this

View File

@@ -1,3 +1,5 @@
error: period.asm(5): error: period.asm(5):
syntax error, unexpected . syntax error, unexpected DB, expecting : or ::
error: Assembly aborted (1 error)! error: period.asm(6):
syntax error, unexpected DB, expecting : or ::
error: Assembly aborted (2 errors)!

View File

@@ -3,6 +3,11 @@ assert !DEF(@)
println @ println @
println "{@}?" println "{@}?"
; not inside a label scope
assert !DEF(.)
println .
println "{.}?"
; not inside a macro ; not inside a macro
assert !DEF(_NARG) assert !DEF(_NARG)
println _NARG println _NARG
@@ -13,6 +18,11 @@ assert DEF(@)
println @ println @
println "{@}!" println "{@}!"
LabelScope:
assert DEF(.)
println .
println "{.}!"
MACRO m MACRO m
assert DEF(_NARG) assert DEF(_NARG)
println _NARG println _NARG

View File

@@ -3,7 +3,11 @@ error: undefined-builtins.asm(3):
error: undefined-builtins.asm(4): error: undefined-builtins.asm(4):
Interpolated symbol "@" does not exist Interpolated symbol "@" does not exist
error: undefined-builtins.asm(8): error: undefined-builtins.asm(8):
_NARG has no value outside of a macro "." has no value outside of a label scope
error: undefined-builtins.asm(9): error: undefined-builtins.asm(9):
Interpolated symbol "." does not exist
error: undefined-builtins.asm(13):
_NARG has no value outside of a macro
error: undefined-builtins.asm(14):
Interpolated symbol "_NARG" does not exist Interpolated symbol "_NARG" does not exist
error: Assembly aborted (4 errors)! error: Assembly aborted (6 errors)!

View File

@@ -1,8 +1,12 @@
$0 $0
?
? ?
$0 $0
? ?
$42 $42
$42! $42!
$42
LabelScope!
$3 $3
$3! $3!