需从零实现基于DFA的轻量级C++词法分析器,支持标识符、数字、字符串(含转义)、单行/块注释、运算符及关键字识别;Token结构含kind、string_view lexeme、行列号;用array查表驱动状态转移,终态标记明确,拒绝非法字符。

你需要在C++中从零构建一个轻量级脚本语言的词法分析器,它能识别标识符、数字字面量、运算符、括号、注释等基本Token,并用确定性有限状态机(DFA)驱动分词过程,最终输出结构化的Token序列供后续语法分析使用。
定义Token枚举与数据结构
创建TokenKind枚举,按实际需识别的词素类型逐项列出:空格不生成Token,单行注释以//开头但不包含换行符,字符串字面量支持双引号包裹及转义反斜杠,关键字如ifwhilereturn需区分于普通标识符。
声明struct Token,包含kind(枚举值)、lexeme(std::string_view,指向源码原始字符区间)、line(行号,从1开始)、column(列号,从1开始)。【lexeme必须是string_view而非string,否则每次切片都触发内存分配】
定义std::vector<token></token>作为最终输出容器。
立即学习“C++免费学习笔记(深入)”;
设计状态机状态与转移表
枚举所有DFA状态:Start、InNumber、InIdentifier、InString、InComment、AfterSlash、AfterStar、AfterEqual、AfterExclam等;其中AfterSlash用于区分/除法与//注释,AfterStar用于检测/*块注释起始。
用std::array<:array>, NUM_STATES></:array>实现转移表,对ASCII字符做查表跳转;非ASCII字符(如UTF-8中文)统一归为Invalid状态并报错。这一步操作起来很简单,直接初始化二维数组即可。
终态(accepting state)单独用std::array<bool num_states></bool>标记,例如InNumber、InIdentifier、InString结束位置均为终态,而AfterSlash不是终态——它必须后接/才构成有效注释。
实现核心扫描循环
第一步:初始化state = Start,start_pos = current_pos,line = 1,column = 1。
第二步:进入while (current_pos 主循环,每次读取<code>char c = source[current_pos],查转移表得next_state。若next_state == Invalid,立即报错并终止;若c是换行符
,则++line,column = 1;否则++column。
第三步:若当前state是终态,且next_state != state(即状态即将离开终态),说明当前字符不属于该Token,应在此截断并生成Token。例如处于InNumber终态,下一个字符是字母,则立即提取source.substr(start_pos, current_pos - start_pos)生成NUMBER Token,然后重置start_pos = current_pos,state = Start。
第四步:更新state = next_state,++current_pos。注意:只有在状态迁移发生时才推进指针;若遇到空白字符(空格、制表符、换行符),在Start状态下直接跳过,不生成Token也不推进start_pos。
处理关键字与标识符的语义分离
方法一:在生成IDENTIFIER Token后,对lexeme内容做哈希比对。维护一个static const std::unordered_map<:string_view tokenkind></:string_view>映射表,键为"if""else""while"等,值为对应关键字枚举。匹配成功则将Token的kind覆盖为关键字类型。
方法二:在DFA中为每个关键字单独建一条路径,例如从Start→MatchI→MatchIf→AcceptIf,但会显著膨胀状态数。不推荐,仅当关键字极少且追求纯DFA无后处理时选用。
提示:关键字匹配必须在Token生成后立即进行,不能延迟到语法分析阶段——词法分析器职责就是输出明确分类的Token,不应把歧义留给上层。
字符串字面量与转义处理
进入InString状态后,持续读取字符直至遇到未转义的"。检测转义逻辑:若当前字符是,则下一个字符无论是什么(包括换行符)都视为字面量的一部分,并跳过下个字符。这要求扫描循环中对做特殊预判:读到时,先检查current_pos + 1是否越界,再读取c_next,然后current_pos += 2。
若在字符串中遇到换行符且未被转义,属于词法错误,立即报错并终止。这一步不能忽略,否则会导致解析器误吞整段代码。
字符串内容提取时,去掉首尾双引号,内部转义序列按规则还原:\→,"→",
→换行符。使用std::string临时构造解码后内容,赋给Token的lexeme字段(此时已非原始视图,但符合语义需求)。


















