Enable simple local labels.

This commit is contained in:
Adrian Matoga 2021-02-28 11:32:32 +01:00 committed by Piotr Fusik
parent d50d484e1f
commit 8f06fec50c
2 changed files with 35 additions and 7 deletions

View File

@ -18,6 +18,7 @@
import std.algorithm; import std.algorithm;
import std.array; import std.array;
import std.ascii;
import std.conv; import std.conv;
import std.file; import std.file;
import std.math; import std.math;
@ -85,6 +86,7 @@ class Label {
Label[string] labelTable; Label[string] labelTable;
Label currentLabel; Label currentLabel;
string lastGlobalLabel;
alias int function(int a, int b) OperatorFunction; alias int function(int a, int b) OperatorFunction;
@ -261,21 +263,23 @@ void readSpaces() {
} }
string readLabel() { string readLabel() {
string label; int firstColumn = column;
while (!eol()) { while (!eol()) {
char c = line[column++]; char c = line[column++];
if (c >= '0' && c <= '9' || c == '_') { if (c >= '0' && c <= '9' || c == '_' || c == '?')
label ~= c;
continue; continue;
}
c &= 0xdf; c &= 0xdf;
if (c >= 'A' && c <= 'Z') { if (c >= 'A' && c <= 'Z')
label ~= c;
continue; continue;
}
column--; column--;
break; break;
} }
string label = line[firstColumn .. column].toUpper;
if (label.startsWith('?')) {
if (lastGlobalLabel is null)
throw new AssemblyError("Global label must be declared first");
label = lastGlobalLabel ~ label;
}
return label >= "A" ? label : null; return label >= "A" ? label : null;
} }
@ -2688,6 +2692,8 @@ void assemblyLine() {
currentLabel = null; currentLabel = null;
if (label !is null) { if (label !is null) {
if (!inFalseCondition()) { if (!inFalseCondition()) {
if (!label.canFind('?'))
lastGlobalLabel = label;
if (!pass2) { if (!pass2) {
if (label in labelTable) if (label in labelTable)
throw new AssemblyError("Label declared twice"); throw new AssemblyError("Label declared twice");

View File

@ -95,6 +95,28 @@ The label will be assigned the current value of the 'origin counter'
unless you use it with the `EQU` directive where it is assigned unless you use it with the `EQU` directive where it is assigned
the value of the `EQU` argument. the value of the `EQU` argument.
Any label name starting with `?` (question mark) refers to a 'local label'.
It is implicitly prefixed with the name of the most recently defined
'global label' (i.e. a label without any `?` in name),
and stays visible until another global label is defined.
It is still possible to access a local label from anywhere in the source
by specifying its full name.
Local labels provide a way to reuse common, short label names while keeping
them unique.
Example:
----
foo ldy #0
?loop lda data,y ; full label name is FOO?LOOP
beq ?ret
jsr sendByte
iny:bne ?loop
?ret rts
bar lda baz
beq foo?ret ; ok
bne ?loop ; ERROR: Undeclared label: BAR?LOOP
----
Instructions and directives must be preceded with some whitespace. Instructions and directives must be preceded with some whitespace.
Without leading whitespace they are treated as label names. Without leading whitespace they are treated as label names.
For example: For example: