mirror of
https://github.com/cc65/cc65.git
synced 2025-02-28 20:29:46 +00:00
Merge pull request #2132 from vrubleg/ulabel
Add support of unnamed labels with @ (.localchar) prefix
This commit is contained in:
commit
90723d7dd1
@ -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><</tt> and <tt>></tt> may be used
|
||||
instead of <tt>-</tt> and <tt>+</tt> with the same meaning.
|
||||
|
||||
Example:
|
||||
|
||||
<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
|
||||
|
||||
: ldx #$01 ; #3
|
||||
: rts ; #4
|
||||
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
|
||||
|
@ -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.
|
||||
*/
|
||||
|
@ -1124,17 +1124,33 @@ Again:
|
||||
/* Local symbol? */
|
||||
if (C == LocalStart) {
|
||||
|
||||
/* Read the identifier. */
|
||||
ReadIdent ();
|
||||
NextChar ();
|
||||
|
||||
/* Start character alone is not enough */
|
||||
if (SB_GetLen (&CurTok.SVal) == 1) {
|
||||
Error ("Invalid cheap local symbol");
|
||||
goto Again;
|
||||
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;
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
@ -1314,22 +1330,30 @@ CharAgain:
|
||||
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 ();
|
||||
|
@ -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, /* <> */
|
||||
|
@ -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) {
|
||||
|
25
test/asm/listing/060-ulabel.s
Normal file
25
test/asm/listing/060-ulabel.s
Normal file
@ -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
|
Loading…
x
Reference in New Issue
Block a user