Skip to content

Commit

Permalink
Merge pull request cc65#2132 from vrubleg/ulabel
Browse files Browse the repository at this point in the history
Add support of unnamed labels with @ (.localchar) prefix
  • Loading branch information
mrdudz authored May 14, 2024
2 parents b1e1c13 + f789316 commit 90723d7
Show file tree
Hide file tree
Showing 6 changed files with 108 additions and 44 deletions.
55 changes: 24 additions & 31 deletions doc/ca65.sgml
Original file line number Diff line number Diff line change
Expand Up @@ -829,49 +829,42 @@ names like "Loop". Here is an example:
bne @Loop ; ERROR: Unknown identifier!
</verb></tscreen>


<sect1>Unnamed labels<p>

If you really want to write messy code, there are also unnamed labels. These
labels do not have a name (you guessed that already, didn't you?). A colon is
used to mark the absence of the name.
If you really want to write messy code, there are also unnamed labels. To define
an unnamed label, use either <tt>@:</tt> (<tt>.LOCALCHAR</tt> is respected if it
is set) or sole <tt>:</tt>.

Unnamed labels may be accessed by using the colon plus several minus or plus
characters as a label designator. Using the '-' characters will create a back
reference (use the n'th label backwards), using '+' will create a forward
reference (use the n'th label in forward direction). An example will help to
understand this:
To reference an unnamed label, use <tt>@</tt> (<tt>.LOCALCHAR</tt> is respected
if it is set) or <tt>:</tt> with several <tt>-</tt> or <tt>+</tt> characters.
The <tt>-</tt> characters will create a back reference (n'th label backwards),
the <tt>+</tt> will create a forward reference (n'th label in forward direction).
As an alternative, angle brackets <tt>&lt;</tt> and <tt>&gt;</tt> may be used
instead of <tt>-</tt> and <tt>+</tt> with the same meaning.

<tscreen><verb>
: lda (ptr1),y ; #1
cmp (ptr2),y
bne :+ ; -> #2
tax
beq :+++ ; -> #4
iny
bne :- ; -> #1
inc ptr1+1
inc ptr2+1
bne :- ; -> #1

: bcs :+ ; #2 -> #3
ldx #$FF
rts
Example:

: ldx #$01 ; #3
: rts ; #4
<tscreen><verb>
cpy #0
beq @++
@:
sta $2007
dey
bne @-
@:
rts
</verb></tscreen>

As you can see from the example, unnamed labels will make even short
sections of code hard to understand, because you have to count labels
to find branch targets (this is the reason why I for my part do
prefer the "cheap" local labels). Nevertheless, unnamed labels are
convenient in some situations, so it's your decision.
Unnamed labels may make even short sections of code hard to understand, because
you have to count labels to find branch targets. It's better to prefer the
"cheap" local labels. Nevertheless, unnamed labels are convenient in some
situations, so it's up to your discretion.

<em/Note:/ <ref id="scopes" name="Scopes"> organize named symbols, not
unnamed ones, so scopes don't have an effect on unnamed labels.



<sect1>Using macros to define labels and constants<p>

While there are drawbacks with this approach, it may be handy in a few rare
Expand Down
18 changes: 18 additions & 0 deletions src/ca65/main.c
Original file line number Diff line number Diff line change
Expand Up @@ -707,6 +707,24 @@ static void OneLine (void)
NextTok ();
}

/* Handle @-style unnamed labels */
if (CurTok.Tok == TOK_ULABEL) {
if (CurTok.IVal != 0) {
Error ("Invalid unnamed label definition");
}
ULabDef ();
NextTok ();

/* Skip the colon. If NoColonLabels is enabled, allow labels without
** a colon if there is no whitespace before the identifier.
*/
if (CurTok.Tok == TOK_COLON) {
NextTok ();
} else if (CurTok.WS || !NoColonLabels) {
Error ("':' expected");
}
}

/* If the first token on the line is an identifier, check for a macro or
** an instruction.
*/
Expand Down
44 changes: 34 additions & 10 deletions src/ca65/scanner.c
Original file line number Diff line number Diff line change
Expand Up @@ -1124,17 +1124,33 @@ void NextRawTok (void)
/* Local symbol? */
if (C == LocalStart) {

/* Read the identifier. */
ReadIdent ();
NextChar ();

if (IsIdChar (C)) {
/* Read a local identifier */
CurTok.Tok = TOK_LOCAL_IDENT;
SB_AppendChar (&CurTok.SVal, LocalStart);
ReadIdent ();
} else {
/* Read an unnamed label */
CurTok.IVal = 0;
CurTok.Tok = TOK_ULABEL;

/* Start character alone is not enough */
if (SB_GetLen (&CurTok.SVal) == 1) {
Error ("Invalid cheap local symbol");
goto Again;
if (C == '-' || C == '<') {
int PrevC = C;
do {
--CurTok.IVal;
NextChar ();
} while (C == PrevC);
} else if (C == '+' || C == '>') {
int PrevC = C;
do {
++CurTok.IVal;
NextChar ();
} while (C == PrevC);
}
}

/* A local identifier */
CurTok.Tok = TOK_LOCAL_IDENT;
return;
}

Expand Down Expand Up @@ -1314,22 +1330,30 @@ void NextRawTok (void)
break;

case '-':
case '<':
{
int PrevC = C;
CurTok.IVal = 0;
do {
--CurTok.IVal;
NextChar ();
} while (C == '-');
} while (C == PrevC);
CurTok.Tok = TOK_ULABEL;
break;
}

case '+':
case '>':
{
int PrevC = C;
CurTok.IVal = 0;
do {
++CurTok.IVal;
NextChar ();
} while (C == '+');
} while (C == PrevC);
CurTok.Tok = TOK_ULABEL;
break;
}

case '=':
NextChar ();
Expand Down
2 changes: 1 addition & 1 deletion src/ca65/token.h
Original file line number Diff line number Diff line change
Expand Up @@ -71,7 +71,7 @@ typedef enum token_t {
TOK_REG, /* Sweet16 R.. register (in sweet16 mode) */

TOK_ASSIGN, /* := */
TOK_ULABEL, /* :++ or :-- */
TOK_ULABEL, /* An unnamed label */

TOK_EQ, /* = */
TOK_NE, /* <> */
Expand Down
8 changes: 6 additions & 2 deletions src/ca65/ulabel.c
Original file line number Diff line number Diff line change
Expand Up @@ -107,8 +107,12 @@ ExprNode* ULabRef (int Which)
int Index;
ULabel* L;

/* Which can never be 0 */
PRECONDITION (Which != 0);
/* Which should not be 0 */
if (Which == 0) {
Error ("Invalid unnamed label reference");
/* We must return something valid */
return GenCurrentPC();
}

/* Get the index of the referenced label */
if (Which > 0) {
Expand Down
25 changes: 25 additions & 0 deletions test/asm/listing/060-ulabel.s
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
; Test new-style (@:) and legacy-style (:) unnamed labels.
; Make sure that they have identical behavior.

.ORG $0000

@: nop
: nop
.ASSERT @<< = $0000, error
.ASSERT @-- = $0000, error
.ASSERT :<< = $0000, error
.ASSERT :-- = $0000, error
.ASSERT @< = $0001, error
.ASSERT @- = $0001, error
.ASSERT :< = $0001, error
.ASSERT :- = $0001, error
.ASSERT @> = $0002, error
.ASSERT @+ = $0002, error
.ASSERT :> = $0002, error
.ASSERT :+ = $0002, error
.ASSERT @>> = $0003, error
.ASSERT @++ = $0003, error
.ASSERT :>> = $0003, error
.ASSERT :++ = $0003, error
@: nop
: nop

0 comments on commit 90723d7

Please sign in to comment.