状态机需确保每个状态明确回答“吃不吃当前字符、推不推pos、去哪个状态”,空格换行必须显式消费并advance(),数字/标识符在非法字符处截断不推进pos,字符串转义用子状态处理,token值优先用string_view避免拷贝。

直接用状态机实现 C++ 脚本词法分析,核心不是写多少状态,而是让每个状态跳转有明确输入条件、不漏字符、不回溯、不依赖后续字符预读——否则 while 循环里容易卡死或分错 token。
状态机怎么定义转移函数才不会漏掉空格和换行?
常见错误是把 whitespace 当作“跳过”,实际它必须被显式消费并推进位置。否则遇到连续空格或注释前的缩进时,pos 停在第一个空格就不再动了。
- 每个状态处理完当前字符后,必须调用
advance()(即++pos),哪怕只是跳过 - 空白符(
' ',' ',' ',' ')应统一进入STATE_SKIP,该状态只做advance()并回到STATE_START - 不要在
STATE_START里用if (c == ' ') continue;——这会跳过advance(),导致下轮还读同一个空格
get_next_token() 怎么避免数字和标识符混淆?
比如输入 "123abc",应该分出 TOKEN_NUMBER 还是报错?取决于你的语法设计;但更常见的是 "123" 是数,"123abc" 是非法 token。关键在状态退出时机。
- 进入
STATE_IN_NUMBER后,只要下一个字符是数字或小数点(且没出现过小数点),就继续;一旦遇到非数字字符,立即退出并返回已读部分 - 退出时不要吃掉那个“破坏数字”的字符(如
'a'),要保留给下一轮get_next_token()处理——即pos不再自增 - 标识符状态(
STATE_IN_IDENTIFIER)同理:允许字母/下划线/数字(但首字符不能是数字),遇到非法字符就截断,不推进pos
字符串字面量中反斜杠转义怎么不崩状态?
输入 "hello"world" 或 "C:pathile" 容易让状态机误判结束引号或崩溃。根本问题是:转义只影响语义,不影响状态流转节奏。
立即学习“C++免费学习笔记(深入)”;
- 进入
STATE_IN_STRING后,每读一个字符都检查是否为'\';若是,则进入临时子状态STATE_ESCAPE,读下一个字符后直接合并到字符串值中,并回到STATE_IN_STRING - 不要在
STATE_ESCAPE中做任何 token 类型判断(比如认为'"'是结束),它只负责吞掉两个字符、拼接内容 - 如果
'\'后跟的是非法转义(如'x'),可选择报错并停在'\'位置,或忽略反斜杠、把'x'当普通字符——后者更鲁棒,但需文档说明
为什么 std::string_view 比 std::string 更适合 token 值存储?
因为词法分析阶段不需要修改 token 内容,只关心起始和长度。用 std::string 每次都拷贝,性能差,且容易在长文件中引发大量内存分配。
- token 结构体里存
std::string_view,构造时传入源字符串引用 +start_pos+length - 确保源字符串(如
const std::string& src)生命周期长于所有 token 对象;若解析后立刻使用 token,没问题;若缓存 token 到 vector 里再处理,就得用std::string拷贝 - 注意:
std::string_view无法表示空字符串以外的“未初始化”状态,建议加一个bool valid字段或用std::optional<:string_view></:string_view>
真正难的不是画状态图,而是每个状态出口都要回答三个问题:这个字符我吃不吃?pos 推不推?下一个状态是什么?少想一个,get_next_token() 就可能无限循环或漏 token。


















