Skip to content

Commit 90723d7

Browse files
authored
Merge pull request cc65#2132 from vrubleg/ulabel
Add support of unnamed labels with @ (.localchar) prefix
2 parents b1e1c13 + f789316 commit 90723d7

File tree

6 files changed

+108
-44
lines changed

6 files changed

+108
-44
lines changed

doc/ca65.sgml

Lines changed: 24 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -829,49 +829,42 @@ names like "Loop". Here is an example:
829829
bne @Loop ; ERROR: Unknown identifier!
830830
</verb></tscreen>
831831

832+
832833
<sect1>Unnamed labels<p>
833834

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

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

844-
<tscreen><verb>
845-
: lda (ptr1),y ; #1
846-
cmp (ptr2),y
847-
bne :+ ; -> #2
848-
tax
849-
beq :+++ ; -> #4
850-
iny
851-
bne :- ; -> #1
852-
inc ptr1+1
853-
inc ptr2+1
854-
bne :- ; -> #1
855-
856-
: bcs :+ ; #2 -> #3
857-
ldx #$FF
858-
rts
846+
Example:
859847

860-
: ldx #$01 ; #3
861-
: rts ; #4
848+
<tscreen><verb>
849+
cpy #0
850+
beq @++
851+
@:
852+
sta $2007
853+
dey
854+
bne @-
855+
@:
856+
rts
862857
</verb></tscreen>
863858

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

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

873867

874-
875868
<sect1>Using macros to define labels and constants<p>
876869

877870
While there are drawbacks with this approach, it may be handy in a few rare

src/ca65/main.c

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -707,6 +707,24 @@ static void OneLine (void)
707707
NextTok ();
708708
}
709709

710+
/* Handle @-style unnamed labels */
711+
if (CurTok.Tok == TOK_ULABEL) {
712+
if (CurTok.IVal != 0) {
713+
Error ("Invalid unnamed label definition");
714+
}
715+
ULabDef ();
716+
NextTok ();
717+
718+
/* Skip the colon. If NoColonLabels is enabled, allow labels without
719+
** a colon if there is no whitespace before the identifier.
720+
*/
721+
if (CurTok.Tok == TOK_COLON) {
722+
NextTok ();
723+
} else if (CurTok.WS || !NoColonLabels) {
724+
Error ("':' expected");
725+
}
726+
}
727+
710728
/* If the first token on the line is an identifier, check for a macro or
711729
** an instruction.
712730
*/

src/ca65/scanner.c

Lines changed: 34 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1124,17 +1124,33 @@ void NextRawTok (void)
11241124
/* Local symbol? */
11251125
if (C == LocalStart) {
11261126

1127-
/* Read the identifier. */
1128-
ReadIdent ();
1127+
NextChar ();
1128+
1129+
if (IsIdChar (C)) {
1130+
/* Read a local identifier */
1131+
CurTok.Tok = TOK_LOCAL_IDENT;
1132+
SB_AppendChar (&CurTok.SVal, LocalStart);
1133+
ReadIdent ();
1134+
} else {
1135+
/* Read an unnamed label */
1136+
CurTok.IVal = 0;
1137+
CurTok.Tok = TOK_ULABEL;
11291138

1130-
/* Start character alone is not enough */
1131-
if (SB_GetLen (&CurTok.SVal) == 1) {
1132-
Error ("Invalid cheap local symbol");
1133-
goto Again;
1139+
if (C == '-' || C == '<') {
1140+
int PrevC = C;
1141+
do {
1142+
--CurTok.IVal;
1143+
NextChar ();
1144+
} while (C == PrevC);
1145+
} else if (C == '+' || C == '>') {
1146+
int PrevC = C;
1147+
do {
1148+
++CurTok.IVal;
1149+
NextChar ();
1150+
} while (C == PrevC);
1151+
}
11341152
}
11351153

1136-
/* A local identifier */
1137-
CurTok.Tok = TOK_LOCAL_IDENT;
11381154
return;
11391155
}
11401156

@@ -1314,22 +1330,30 @@ void NextRawTok (void)
13141330
break;
13151331

13161332
case '-':
1333+
case '<':
1334+
{
1335+
int PrevC = C;
13171336
CurTok.IVal = 0;
13181337
do {
13191338
--CurTok.IVal;
13201339
NextChar ();
1321-
} while (C == '-');
1340+
} while (C == PrevC);
13221341
CurTok.Tok = TOK_ULABEL;
13231342
break;
1343+
}
13241344

13251345
case '+':
1346+
case '>':
1347+
{
1348+
int PrevC = C;
13261349
CurTok.IVal = 0;
13271350
do {
13281351
++CurTok.IVal;
13291352
NextChar ();
1330-
} while (C == '+');
1353+
} while (C == PrevC);
13311354
CurTok.Tok = TOK_ULABEL;
13321355
break;
1356+
}
13331357

13341358
case '=':
13351359
NextChar ();

src/ca65/token.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -71,7 +71,7 @@ typedef enum token_t {
7171
TOK_REG, /* Sweet16 R.. register (in sweet16 mode) */
7272

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

7676
TOK_EQ, /* = */
7777
TOK_NE, /* <> */

src/ca65/ulabel.c

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -107,8 +107,12 @@ ExprNode* ULabRef (int Which)
107107
int Index;
108108
ULabel* L;
109109

110-
/* Which can never be 0 */
111-
PRECONDITION (Which != 0);
110+
/* Which should not be 0 */
111+
if (Which == 0) {
112+
Error ("Invalid unnamed label reference");
113+
/* We must return something valid */
114+
return GenCurrentPC();
115+
}
112116

113117
/* Get the index of the referenced label */
114118
if (Which > 0) {

test/asm/listing/060-ulabel.s

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
; Test new-style (@:) and legacy-style (:) unnamed labels.
2+
; Make sure that they have identical behavior.
3+
4+
.ORG $0000
5+
6+
@: nop
7+
: nop
8+
.ASSERT @<< = $0000, error
9+
.ASSERT @-- = $0000, error
10+
.ASSERT :<< = $0000, error
11+
.ASSERT :-- = $0000, error
12+
.ASSERT @< = $0001, error
13+
.ASSERT @- = $0001, error
14+
.ASSERT :< = $0001, error
15+
.ASSERT :- = $0001, error
16+
.ASSERT @> = $0002, error
17+
.ASSERT @+ = $0002, error
18+
.ASSERT :> = $0002, error
19+
.ASSERT :+ = $0002, error
20+
.ASSERT @>> = $0003, error
21+
.ASSERT @++ = $0003, error
22+
.ASSERT :>> = $0003, error
23+
.ASSERT :++ = $0003, error
24+
@: nop
25+
: nop

0 commit comments

Comments
 (0)