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.array;
import std.ascii;
import std.conv;
import std.file;
import std.math;
@ -85,6 +86,7 @@ class Label {
Label[string] labelTable;
Label currentLabel;
string lastGlobalLabel;
alias int function(int a, int b) OperatorFunction;
@ -261,21 +263,23 @@ void readSpaces() {
}
string readLabel() {
string label;
int firstColumn = column;
while (!eol()) {
char c = line[column++];
if (c >= '0' && c <= '9' || c == '_') {
label ~= c;
if (c >= '0' && c <= '9' || c == '_' || c == '?')
continue;
}
c &= 0xdf;
if (c >= 'A' && c <= 'Z') {
label ~= c;
if (c >= 'A' && c <= 'Z')
continue;
}
column--;
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;
}
@ -2688,6 +2692,8 @@ void assemblyLine() {
currentLabel = null;
if (label !is null) {
if (!inFalseCondition()) {
if (!label.canFind('?'))
lastGlobalLabel = label;
if (!pass2) {
if (label in labelTable)
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
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.
Without leading whitespace they are treated as label names.
For example: