3. 识别整数与浮点字面量

识别整数与浮点字面量 学习卡片

任务目标

实现一个词法分析器,能够从输入字符串中识别三类字面量:十进制整数(如 123)、十六进制整数(如 0x1F)以及浮点数(如 3.14、2.0e-3)。输出每个字面量的类型、原始文本和数值。

实现方案

采用手工状态机方式,逐字符扫描输入。核心逻辑分为三个入口:scan_number 负责统一调度,根据前缀和字符特征分派到 scan_decimal_or_float 或 scan_hex。浮点数支持小数点与科学计数法指数部分。识别完成后返回 列表,每个 包含类型、文本和解析后的数值(浮点数统一转为 double)。

完整代码

import re
from enum import Enum

class TokenType(Enum):
    DEC_INT = "十进制整数"
    HEX_INT = "十六进制整数"
    FLOAT   = "浮点数"

class :
    def __init__(self, type_, text, value):
        self.type = type_
        self.text = text
        self.value = value
    def __repr__(self):
        return f"({self.type.value}, '{self.text}', {self.value})"

def scan_number(src):
    tokens = []
    i = 0
    n = len(src)
    while i < n:
        ch = src[i]
        if ch.isdigit() or (ch == '.' and i+1 < n and src[i+1].isdigit()):
            tok, i = _scan_numeric(src, i)
            tokens.append(tok)
        else:
            i += 1
    return tokens

def _scan_numeric(src, start):
    i = start
    n = len(src)
    # 十六进制:0x 或 0X 开头
    if src[i] == '0' and i+1 < n and src[i+1] in ('x', 'X'):
        j = i + 2
        while j < n and (src[j].isdigit() or src[j].lower() in 'abcdef'):
            j += 1
        text = src[i:j]
        return (TokenType.HEX_INT, text, int(text, 16)), j

    # 十进制或浮点
    j = i
    is_float = False
    # 整数部分
    while j < n and src[j].isdigit():
        j += 1
    # 小数部分
    if j < n and src[j] == '.':
        # 防止 "1..2" 或 "1." 后无数字但后面是字母的情况
        if j+1 < n and src[j+1].isdigit():
            is_float = True
            j += 1
            while j < n and src[j].isdigit():
                j += 1
    # 指数部分
    if j < n and src[j] in ('e', 'E'):
        k = j + 1
        if k < n and src[k] in ('+', '-'):
            k += 1
        if k < n and src[k].isdigit():
            is_float = True
            j = k
            while j < n and src[j].isdigit():
                j += 1

    text = src[i:j]
    if is_float:
        return (TokenType.FLOAT, text, float(text)), j
    else:
        return (TokenType.DEC_INT, text, int(text)), j

# 最小调用入口
if __name__ == "__main__":
    test = "123 0x1F 3.14 2.0e-3 0xABC 42 1.5E+2"
    for tok in scan_number(test):
        print(tok)

运行与验证

直接运行脚本:

python3 lexer.py

预期输出(与代码逻辑严格一致):

(十进制整数, '123', 123)
(十六进制整数, '0x1F', 31)
(浮点数, '3.14', 3.14)
(浮点数, '2.0e-3', 0.002)
(十六进制整数, '0xABC', 2748)
(十进制整数, '42', 42)
(浮点数, '1.5E+2', 150.0)

判定通过条件:输出与上述完全一致,且 0x1F 的值为 31、2.0e-3 的值为 0.002,说明十六进制与科学计数法解析正确。

边界行为说明

  • 输入 1. 后无数字时,不识别为浮点,只识别整数 1,后续 . 被跳过。
  • 输入 0x 后无十六进制数字时,只识别 0 为十进制整数,x 被跳过。
  • 形如 1e3 会被识别为浮点数 1000.0;1e 后无数字则只识别整数 1。
  • 非数字字符(如空格、运算符)直接跳过,不产生错误。