Skip to content

Commit 6b89938

Browse files
authored
Avoid treating labels and macros differently in column 1 (#1515)
Fixes #1512
1 parent 15919e5 commit 6b89938

9 files changed

+75
-39
lines changed

man/rgbasm.5

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -41,7 +41,6 @@ or
4141
Labels tie a name to a specific location within a section (see
4242
.Sx Labels
4343
below).
44-
They must come first in the line.
4544
.Pp
4645
Instructions are assembled into Game Boy opcodes.
4746
Multiple instructions on one line can be separated by double colons

src/asm/lexer.cpp

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1849,7 +1849,19 @@ static Token yylex_NORMAL() {
18491849
}
18501850
}
18511851

1852-
if (token.type == T_(ID) && (lexerState->atLineStart || peek() == ':'))
1852+
// This is a "lexer hack"! We need it to distinguish between label definitions
1853+
// (which start with `LABEL`) and macro invocations (which start with `ID`).
1854+
//
1855+
// If we had one `IDENTIFIER` token, the parser would need to perform "lookahead"
1856+
// to determine which rule applies. But since macros need to enter "raw" mode to
1857+
// parse their arguments, which may not even be valid tokens in "normal" mode, we
1858+
// cannot use lookahead to check for the presence of a `COLON`.
1859+
//
1860+
// Instead, we have separate `ID` and `LABEL` tokens, lexing as a `LABEL` if a ':'
1861+
// character *immediately* follows the identifier. Thus, at the beginning of a line,
1862+
// "Label:" and "mac:" are treated as label definitions, but "Label :" and "mac :"
1863+
// are treated as macro invocations.
1864+
if (token.type == T_(ID) && peek() == ':')
18531865
token.type = T_(LABEL);
18541866

18551867
return token;

src/asm/parser.y

Lines changed: 0 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -433,22 +433,6 @@ line:
433433
fstk_StopRept();
434434
yyerrok;
435435
}
436-
// Hint about unindented macros parsed as labels
437-
| LABEL error {
438-
lexer_SetMode(LEXER_NORMAL);
439-
lexer_ToggleStringExpansion(true);
440-
} endofline {
441-
Symbol *macro = sym_FindExactSymbol($1);
442-
443-
if (macro && macro->type == SYM_MACRO)
444-
fprintf(
445-
stderr,
446-
" To invoke `%s` as a macro it must be indented\n",
447-
$1.c_str()
448-
);
449-
fstk_StopRept();
450-
yyerrok;
451-
}
452436
;
453437

454438
endofline: NEWLINE | EOB;

test/asm/lexer-hack.asm

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
MACRO mac
2+
println "got {d:_NARG} args: \#"
3+
ENDM
4+
5+
; indented, these were always macro invocations
6+
mac
7+
mac ro
8+
mac : ld a, 1
9+
10+
; in column 1, we historically treated these as labels
11+
mac
12+
mac ro
13+
mac : ld b, 2
14+
15+
SECTION "test", ROM0
16+
17+
; a colon makes these into labels
18+
Label1: ld c, 3
19+
Label2: ld d, 4
20+
21+
; a macro invocation when already defined as a label
22+
Label1 args
23+
; and a label definition when already defined as a macro
24+
mac: ld e, 5
25+
26+
; the space before the colon matters!
27+
undef :
28+
undef :

test/asm/lexer-hack.err

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
error: lexer-hack.asm(22):
2+
"Label1" is not a macro
3+
error: lexer-hack.asm(24):
4+
'mac' already defined at lexer-hack.asm(1)
5+
error: lexer-hack.asm(27):
6+
Macro "undef" not defined
7+
error: lexer-hack.asm(28):
8+
Macro "undef" not defined
9+
error: Assembly aborted (4 errors)!

test/asm/lexer-hack.out

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
got 0 args:
2+
got 1 args: ro
3+
got 2 args: : ld a,1
4+
got 0 args:
5+
got 1 args: ro
6+
got 2 args: : ld b,2
Lines changed: 11 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,11 @@
1-
MACRO mac
2-
println "got {d:_NARG} args"
3-
ENDM
4-
mac
5-
mac 42
6-
notmac
7-
mac
8-
mac 42
9-
mac::
10-
mac ::
1+
def x = 1 ; so far so good...
2+
def n equ 2 + * / ^ 3 ; oops
3+
def s equs "no closing quote, lol
4+
section "test", rom0 ; good again
5+
ld a, 42 ; keep going...
6+
ld xor, ret ; oh no :(
7+
label1: ; yes...
8+
label2:: ; yes...
9+
label3::: ; no!
10+
halt stop abort ; please
11+
println "finally!"
Lines changed: 7 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,11 @@
1+
error: syntax-error-after-syntax-error.asm(2):
2+
syntax error, unexpected *
3+
error: syntax-error-after-syntax-error.asm(3):
4+
Unterminated string
15
error: syntax-error-after-syntax-error.asm(6):
2-
syntax error, unexpected newline, expecting : or ::
3-
error: syntax-error-after-syntax-error.asm(7):
4-
syntax error, unexpected newline, expecting : or ::
5-
To invoke `mac` as a macro it must be indented
6-
error: syntax-error-after-syntax-error.asm(8):
7-
syntax error, unexpected number, expecting : or ::
8-
To invoke `mac` as a macro it must be indented
6+
syntax error, unexpected xor
97
error: syntax-error-after-syntax-error.asm(9):
10-
'mac' already defined at syntax-error-after-syntax-error.asm(1)
8+
syntax error, unexpected :
119
error: syntax-error-after-syntax-error.asm(10):
12-
'mac' already defined at syntax-error-after-syntax-error.asm(1)
10+
syntax error, unexpected stop, expecting newline or end of buffer or ::
1311
error: Assembly aborted (5 errors)!
Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,2 +1 @@
1-
got 0 args
2-
got 1 args
1+
finally!

0 commit comments

Comments
 (0)