feat(parser): macro expansion, conditionals and include splicing with -I
Assisted-by: GLM 5.3 Flash
This commit is contained in:
+44
-1
@@ -119,7 +119,9 @@ func (l *Lexer) Next() token.Token {
|
||||
// is a C-preprocessor line continuation (used by #define macros in the
|
||||
// runtime .s files): splice the lines together by consuming both, so
|
||||
// the whole macro becomes one logical line that the parser treats as an
|
||||
// opaque preprocessor directive.
|
||||
// opaque preprocessor directive. The backslash may also reach its
|
||||
// newline across whitespace and a trailing comment ("…; \ // note\n"),
|
||||
// which the toolchain's scanner skips the same way.
|
||||
for {
|
||||
c := l.cur()
|
||||
if c == ' ' || c == '\t' || c == '\r' {
|
||||
@@ -136,6 +138,16 @@ func (l *Lexer) Next() token.Token {
|
||||
}
|
||||
continue
|
||||
}
|
||||
if c == '\\' && l.continuationAhead() {
|
||||
l.advance() // backslash, then the runes the scan saw
|
||||
for !l.atEnd() && l.cur() != '\n' {
|
||||
l.advance()
|
||||
}
|
||||
if !l.atEnd() {
|
||||
l.advance() // the newline that closes the continuation
|
||||
}
|
||||
continue
|
||||
}
|
||||
break
|
||||
}
|
||||
|
||||
@@ -185,6 +197,28 @@ func (l *Lexer) Next() token.Token {
|
||||
}
|
||||
}
|
||||
|
||||
// continuationAhead reports, without consuming anything, whether the
|
||||
// backslash at the current position closes onto a newline through nothing
|
||||
// but horizontal whitespace and one line comment. Positions after the
|
||||
// backslash are inspected directly on the rune slice so a non-match leaves
|
||||
// the scanner state untouched.
|
||||
func (l *Lexer) continuationAhead() bool {
|
||||
i := l.i + 1
|
||||
for i < len(l.src) {
|
||||
switch r := l.src[i]; {
|
||||
case r == ' ' || r == '\t' || r == '\r':
|
||||
i++
|
||||
case r == '/' && i+1 < len(l.src) && l.src[i+1] == '/':
|
||||
for i < len(l.src) && l.src[i] != '\n' {
|
||||
i++
|
||||
}
|
||||
default:
|
||||
return r == '\n'
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
// lineComment consumes a // comment up to, but not including, the newline. A
|
||||
// trailing run of \r, spaces and tabs is line-ending whitespace rather than
|
||||
// comment content, so it never enters the token text. Trimming only a \r
|
||||
@@ -403,6 +437,15 @@ func (l *Lexer) punct(start token.Position) token.Token {
|
||||
case '|':
|
||||
l.advance()
|
||||
return l.make(token.Pipe, start, "|")
|
||||
case ';':
|
||||
l.advance()
|
||||
return l.make(token.Semicolon, start, ";")
|
||||
case '&':
|
||||
l.advance()
|
||||
return l.make(token.Ampersand, start, "&")
|
||||
case '~':
|
||||
l.advance()
|
||||
return l.make(token.Tilde, start, "~")
|
||||
default:
|
||||
// Unknown rune: emit it as Illegal and move on.
|
||||
l.advance()
|
||||
|
||||
Reference in New Issue
Block a user