mirror of
https://github.com/gbdev/rgbds.git
synced 2025-11-20 10:12:06 +00:00
Avoid treating labels and macros differently in column 1 (#1515)
Fixes #1512
This commit is contained in:
@@ -41,7 +41,6 @@ or
|
||||
Labels tie a name to a specific location within a section (see
|
||||
.Sx Labels
|
||||
below).
|
||||
They must come first in the line.
|
||||
.Pp
|
||||
Instructions are assembled into Game Boy opcodes.
|
||||
Multiple instructions on one line can be separated by double colons
|
||||
|
||||
@@ -1849,7 +1849,19 @@ static Token yylex_NORMAL() {
|
||||
}
|
||||
}
|
||||
|
||||
if (token.type == T_(ID) && (lexerState->atLineStart || peek() == ':'))
|
||||
// This is a "lexer hack"! We need it to distinguish between label definitions
|
||||
// (which start with `LABEL`) and macro invocations (which start with `ID`).
|
||||
//
|
||||
// If we had one `IDENTIFIER` token, the parser would need to perform "lookahead"
|
||||
// to determine which rule applies. But since macros need to enter "raw" mode to
|
||||
// parse their arguments, which may not even be valid tokens in "normal" mode, we
|
||||
// cannot use lookahead to check for the presence of a `COLON`.
|
||||
//
|
||||
// Instead, we have separate `ID` and `LABEL` tokens, lexing as a `LABEL` if a ':'
|
||||
// character *immediately* follows the identifier. Thus, at the beginning of a line,
|
||||
// "Label:" and "mac:" are treated as label definitions, but "Label :" and "mac :"
|
||||
// are treated as macro invocations.
|
||||
if (token.type == T_(ID) && peek() == ':')
|
||||
token.type = T_(LABEL);
|
||||
|
||||
return token;
|
||||
|
||||
@@ -433,22 +433,6 @@ line:
|
||||
fstk_StopRept();
|
||||
yyerrok;
|
||||
}
|
||||
// Hint about unindented macros parsed as labels
|
||||
| LABEL error {
|
||||
lexer_SetMode(LEXER_NORMAL);
|
||||
lexer_ToggleStringExpansion(true);
|
||||
} endofline {
|
||||
Symbol *macro = sym_FindExactSymbol($1);
|
||||
|
||||
if (macro && macro->type == SYM_MACRO)
|
||||
fprintf(
|
||||
stderr,
|
||||
" To invoke `%s` as a macro it must be indented\n",
|
||||
$1.c_str()
|
||||
);
|
||||
fstk_StopRept();
|
||||
yyerrok;
|
||||
}
|
||||
;
|
||||
|
||||
endofline: NEWLINE | EOB;
|
||||
|
||||
28
test/asm/lexer-hack.asm
Normal file
28
test/asm/lexer-hack.asm
Normal file
@@ -0,0 +1,28 @@
|
||||
MACRO mac
|
||||
println "got {d:_NARG} args: \#"
|
||||
ENDM
|
||||
|
||||
; indented, these were always macro invocations
|
||||
mac
|
||||
mac ro
|
||||
mac : ld a, 1
|
||||
|
||||
; in column 1, we historically treated these as labels
|
||||
mac
|
||||
mac ro
|
||||
mac : ld b, 2
|
||||
|
||||
SECTION "test", ROM0
|
||||
|
||||
; a colon makes these into labels
|
||||
Label1: ld c, 3
|
||||
Label2: ld d, 4
|
||||
|
||||
; a macro invocation when already defined as a label
|
||||
Label1 args
|
||||
; and a label definition when already defined as a macro
|
||||
mac: ld e, 5
|
||||
|
||||
; the space before the colon matters!
|
||||
undef :
|
||||
undef :
|
||||
9
test/asm/lexer-hack.err
Normal file
9
test/asm/lexer-hack.err
Normal file
@@ -0,0 +1,9 @@
|
||||
error: lexer-hack.asm(22):
|
||||
"Label1" is not a macro
|
||||
error: lexer-hack.asm(24):
|
||||
'mac' already defined at lexer-hack.asm(1)
|
||||
error: lexer-hack.asm(27):
|
||||
Macro "undef" not defined
|
||||
error: lexer-hack.asm(28):
|
||||
Macro "undef" not defined
|
||||
error: Assembly aborted (4 errors)!
|
||||
6
test/asm/lexer-hack.out
Normal file
6
test/asm/lexer-hack.out
Normal file
@@ -0,0 +1,6 @@
|
||||
got 0 args:
|
||||
got 1 args: ro
|
||||
got 2 args: : ld a,1
|
||||
got 0 args:
|
||||
got 1 args: ro
|
||||
got 2 args: : ld b,2
|
||||
@@ -1,10 +1,11 @@
|
||||
MACRO mac
|
||||
println "got {d:_NARG} args"
|
||||
ENDM
|
||||
mac
|
||||
mac 42
|
||||
notmac
|
||||
mac
|
||||
mac 42
|
||||
mac::
|
||||
mac ::
|
||||
def x = 1 ; so far so good...
|
||||
def n equ 2 + * / ^ 3 ; oops
|
||||
def s equs "no closing quote, lol
|
||||
section "test", rom0 ; good again
|
||||
ld a, 42 ; keep going...
|
||||
ld xor, ret ; oh no :(
|
||||
label1: ; yes...
|
||||
label2:: ; yes...
|
||||
label3::: ; no!
|
||||
halt stop abort ; please
|
||||
println "finally!"
|
||||
|
||||
@@ -1,13 +1,11 @@
|
||||
error: syntax-error-after-syntax-error.asm(2):
|
||||
syntax error, unexpected *
|
||||
error: syntax-error-after-syntax-error.asm(3):
|
||||
Unterminated string
|
||||
error: syntax-error-after-syntax-error.asm(6):
|
||||
syntax error, unexpected newline, expecting : or ::
|
||||
error: syntax-error-after-syntax-error.asm(7):
|
||||
syntax error, unexpected newline, expecting : or ::
|
||||
To invoke `mac` as a macro it must be indented
|
||||
error: syntax-error-after-syntax-error.asm(8):
|
||||
syntax error, unexpected number, expecting : or ::
|
||||
To invoke `mac` as a macro it must be indented
|
||||
syntax error, unexpected xor
|
||||
error: syntax-error-after-syntax-error.asm(9):
|
||||
'mac' already defined at syntax-error-after-syntax-error.asm(1)
|
||||
syntax error, unexpected :
|
||||
error: syntax-error-after-syntax-error.asm(10):
|
||||
'mac' already defined at syntax-error-after-syntax-error.asm(1)
|
||||
syntax error, unexpected stop, expecting newline or end of buffer or ::
|
||||
error: Assembly aborted (5 errors)!
|
||||
|
||||
@@ -1,2 +1 @@
|
||||
got 0 args
|
||||
got 1 args
|
||||
finally!
|
||||
|
||||
Reference in New Issue
Block a user