def read_number(self) -> str:
pos = self.pos
while self.peek_char.isdigit(): # stop when next char is not a digit
self.read_char()
if self.peek_char == ".": # float
self.read_char()
while self.peek_char.isdigit():
self.read_char()
return self.src_code[pos : self.pos + 1]词法分析:数字
约 390 字大约 1 分钟
2026-02-17
经过了上一章节,我们已经可以识别出简单的运算符了。数字比运算符稍微复杂一点,它可以是整数或者浮点数。那么如果是负数怎么办?负数的特点是以 - 开头,后面跟着一个整数或者浮点数,可以在语法分析器中处理。回到数字的识别
- 整数:以 0-9 开头,直到
peek_char()为非数字字符 - 浮点数:先识别开头的整数部分,然后
peek_char()为.,再识别小数部分,直到peek_char()为非数字字符
read_number()函数中,就实现了这个逻辑。先读到第一个非数字字符,判断是否为 .,如果是,继续读取小数部分。它返回一个字符串,这也就是为什么在 L2 需要记录pos的原因,因为每调用一次read_char(),词法分析器的pos就会增加。
我们把含有 . 的数字称为浮点数,不含有 . 的数字称为整数。将read_number()加到next_token()的最后一个分支_中,就可以识别出数字了。当然,如果我们没有识别到数字,就会抛出异常。
case _:
if self.cur_char.isdigit():
number_str = self.read_number()
if "." in number_str:
tok = Token(TokenType.FLOAT, number_str, cur_line, cur_col)
else:
tok = Token(TokenType.INT, number_str, cur_line, cur_col)
else:
tok = Token(TokenType.ILLEGAL, self.cur_char, cur_line, cur_col)
raise IllegalCharErr(self.cur_char, cur_line, cur_col)这里没有展示测试的代码。需要修改test_lexer.py的内容,把让所有的测试能够通过。当然如果成功了不要忘了提交代码。
$ git add .
$ git commit -m "lexer: number"