1. Token 与源码位置
Lexer 负责把字符流拆成 Token,并给每个 Token 标注源码位置。关键字不是普通标识符,注释跳过、字符串扫描和 Position 记录会直接影响后续诊断质量。这里的 关键字 表会把 let、fn、if、while 映射为专门的 TokenType。
enum TokenType {
Identifier,
Number,
String,
Let,
Fn,
If,
While,
Equal,
EOF,
}
type Position = { line: number; column: number; offset: number };
const keywords = new Map<string, TokenType>([
["let", TokenType.Let],
["fn", TokenType.Fn],
["if", TokenType.If],
["while", TokenType.While],
]);
2. 扫描 MiniLang
扫描器要处理空白、comment skipping、字符串扫描和源码位置推进。MiniLang 示例 let name: string = "compiler"; 会被拆成 let 关键字、name 标识符、string 类型名、等号和字符串字面量。
class Lexer {
constructor(private source: string, private current = 0) {}
scanTokens(): Token[] {
const tokens: Token[] = [];
while (!this.isAtEnd()) tokens.push(this.scanToken());
tokens.push({ type: TokenType.EOF, lexeme: "", position: this.position() });
return tokens;
}
private scanString(): Token {
// let name: string = "compiler";
return { type: TokenType.String, lexeme: this.readUntilQuote(), position: this.position() };
}
}