发布于2026-07-10 阅读(0)
扫一扫,手机访问
词法分析状态机实现时,最容易被忽略的一个问题就是:状态变量和输入游标之间必须保持实时一致。每次调用next_char(),都要让pos自增的同时,把current_char更新为src[pos]。如果忘了这一步,下一轮switch判断的就会是旧字符,逻辑自然会乱套。更常见的陷阱是,跳转到新状态后忘了推进pos,结果同一个字符被反复处理,陷入死循环。所以,所有return分支(包括错误处理),都必须保证pos已经准确指向下一个待处理的位置——既不是“刚读完的那个字符”,也不是“还没读到的位置”。遇到'\0'或pos >= src.length()时,current_char应该直接设为'\0',并且不再调用next_char()。
关于状态变量的生命周期,有个原则需要明确:while循环之外不要维护任何跨token的状态。有人喜欢把state设成类成员变量,指望靠它记住上次处理停在了哪——这其实是多token连续解析时最大的隐患。比如123abc这个输入,本应分出INT和ID两个token,但如果残留状态让后续字符被误判为数字的延续,结果就会出错。正确的做法是:每次调用scan_token(),都在局部作用域重置state = START。状态跳转只发生在当前字符的处理过程中,绝不跨token保留。START状态只做最基础的分流:遇到空格直接跳过,看到数字进入IN_NUMBER,碰到字母进入IN_IDENTIFIER,遇见'+'就立即返回TOKEN_PLUS。
IN_NUMBER状态的处理相对复杂一些。只用isdigit(current_char)来判断远远不够,因为像123.45e-6这样的浮点数,e后面是可以跟负号的,但这个负号不能出现在数字开头以外的位置;小数点只能出现一次,而且一旦遇到e,后面就不能再有小数点了。解决方法是引入三个布尔标记:has_dot、has_e和after_e,都在局部作用域里声明。遇到'.'时,检查!has_dot && !has_e,否则报非法。遇到'e'或'E'时,检查!has_e && (isdigit(prev_char) || has_dot),然后设置after_e = true、has_e = true。而'-'或'+'的出现,仅当after_e为true,且当前pos恰好是e后面的第一个字符时才合法——这需要额外记录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来收尾。
售后无忧
立即购买>office旗舰店
售后无忧
立即购买>office旗舰店
售后无忧
立即购买>office旗舰店
售后无忧
立即购买>office旗舰店
正版软件
正版软件
正版软件
正版软件
正版软件
1
2
3
7
8