词法分析状态机核心在于pos与current_char实时同步:每次next_char()须同时更新pos++和current_char;每个token从START重置状态;IN_NUMBER需用has_dot/has_e/after_e标记处理浮点数;转义序列用peek(1)预判再推进;EOF时须显式检查终态合法性。

直接用 switch 套嵌套 if 写词法分析状态机,十行内能跑通,但一加注释、一加空格、一碰浮点数就崩——真正卡住的不是逻辑,是状态退出条件和输入缓冲区游标怎么同步。
状态机里 pos 和 current_char 必须实时一致
常见错误是读完一个字符后没立刻更新 current_char,导致下一轮 switch 还在判断旧字符;或者跳转到新状态后忘了推进 pos,结果死循环匹配同一个字符。
- 每次调用
next_char()必须同时更新pos++和current_char = src[pos] - 所有
return之前(包括错误分支)都要确保pos已停在下一个待处理位置,而不是“刚读完这个字符”或“还没读” - 遇到
'\0'或pos >= src.length()时,current_char应设为'\0',且不再调用next_char()
while 循环外不维护状态变量,每个 token 从 START 状态开始
有人把 state 设成类成员变量,想靠它记住上次停在哪——这会让多 token 连续解析出错,比如 123abc 本该分出 INT 和 ID,但残留状态可能误判 b 是数字续写。
- 每个
scan_token()调用都重置局部state = START - 状态跳转只发生在当前字符处理中,不跨 token 保留
-
START状态只做分流:空格跳过、数字进IN_NUMBER、字母进IN_IDENTIFIER、'+'直接返回TOKEN_PLUS
IN_NUMBER 状态必须区分整数、小数点、科学计数法三段
只判断 isdigit(current_char) 不够,123.45e-6 里 e 后面可以跟负号,但负号不能出现在开头以外的位置;小数点只能出现一次,且不能在 e 后面再出现。
- 用布尔标记
has_dot = false、has_e = false、after_e = false,都在局部作用域里声明 - 遇到
'.'时检查!has_dot && !has_e,否则非法 - 遇到
'e'或'E'时检查!has_e && (is_digit(prev_char) || has_dot),然后设after_e = true、has_e = true - 遇到
'-'或'+'时,仅当after_e && pos == start_pos_of_e_part才合法(即紧贴e后第一个字符)
字符串字面量里的转义要提前消耗字符,不能靠回退
写 if (current_char == '\') { next_char(); handle_escape(); } 是错的——如果 handle_escape() 里又调了一次 next_char(),游标就多走了一步,后面字符全偏移。
- 统一用
peek(1)查看下一个字符是否为'n'、't'、'\'等,不推进pos - 确认是合法转义后,再一次性调用两次
next_char()(跳过\和其后字符) - 遇到未知转义如
'\x',按原样存入字符串值,不报错(兼容性考虑),但记录 warning
最易被忽略的是 EOF 处理:状态机跑到末尾时,不能假设 “反正没字符了就结束”,而要检查当前是否处于可接受终态(如 IN_NUMBER 结束在数字上,是合法 INT;但停在 '.' 上就是错误)。这类边界必须显式判断,不能依赖默认 return TOKEN_EOF。
C++免费学习笔记(深入):立即使用
在学习笔记中,你将探索 C++ 的入门与实战技巧!











