C语言词法分析器完整实现:从预处理到符号表的编译原理参考
简介编译原理课程设计中词法分析器是编译器前端的关键模块负责将源代码字符流转换为有意义的单词序列。该文档以docx格式封装内含完整的C语言词法分析器代码与实现说明面向计算机专业学生、编译原理学习者及需快速完成课程设计或实验报告的开发者。资源包共1个docx文件压缩后仅18KB轻量便于下载。文档围绕预处理、错误处理、单词识别三大环节展开具体涉及注释与空白过滤、GetChar字符读取与分类、关键字表/标识符表/常量表/错误码表的数据组织以及Dualistic结构体保存单词种类与值等细节。文档通过宏定义控制关键字长度、标识符上限和缓冲区大小并清晰展示错误定位函数ProcError的调用方式。目前已吸引143人学习或浏览适合用作课设参考也可直接对照源码理解词法分析流程为后续语法分析及编译器实现打下扎实基础。1. 词法分析器代码一份能直接跑完实验的 C 语言参考实现编译原理课的词法分析实验卡住大多数人的不是“知道要识别关键字、标识符、运算符”而是代码写到一半忽然发现注释怎么去、和怎么区分、符号表和常量表怎么组织、错误行号怎么定位。这份代码把这些问题一次性解决了。它用纯 C 语言实现了一个完整的词法分析器包含预处理去注释、32 个 C 关键字识别、标识符/常量双表管理、错误代码表、二元组输出主函数直接读Test.txt输出Result.txt。适合正在做编译原理课程设计、需要一份可复现参考代码的从业者也适合想搞懂“词法分析器到底怎么组织状态判断”的人直接读代码、改代码。2. 预处理与字符管理先把注释和空白清掉再谈识别2.1 预处理函数的设计思路为什么不能边读边分析词法分析器最容易被忽略的环节是注释处理。如果主流程里遇到/就直接判断运算符那么//和/* */会污染整个 token 流。这份代码的做法是先跑一遍pretreatment()把注释剥掉把结果写到临时缓冲区再拷贝回全局缓冲区proBuffer。常见的做法是先处理注释再做词法分析因为注释里的内容对后续识别没有任何意义而且//注释可能包含不配对的引号、括号直接进分析流程会让状态机乱掉。void pretreatment() { int lines 0; char tmp[PRO_MAX_LEN]; // 处理结果先存临时空间 int tmpp 0; bool flg; char tmpc; point 0; do { flg GetChar(); if (ch /) { flg GetChar(); switch (ch) { case /: do { flg GetChar(); } while (!(ch \n || flg false)); if (ch \n) Retract(); // 归还换行 break; case *: do { flg GetChar(); tmpc ch; if (tmpc \n) tmp[tmpp] tmpc; flg GetChar(); Retract(); } while (flg !(flg tmpc * ch /)); flg GetChar(); if (!flg) ProcError(5); break; default: Retract(); Retract(); GetChar(); tmp[tmpp] ch; flg GetChar(); tmp[tmpp] ch; } } else { tmp[tmpp] ch; } } while (flg); tmp[tmpp] \0; strcpy(proBuffer, tmp); }这段代码的核心逻辑是把//注释一直读到行尾或文件结束把/* */注释一直读到匹配的*/。注释里如果有换行会把换行保存到临时缓冲区这是为了后面errorLine行号定位不出错。default分支处理的是“斜杠后跟的不是注释符号”的情况比如a / b或者/这里连续两次Retract()再重新GetChar()目的是把/和下一个字符都原样保留。注意Retract()只回退一个字符所以这里回退两次再读一次等价于把当前位置恢复到/前再重新读入/和后续字符。2.2 GetChar 与 Retract 的配对规则行号维护的玄机GetChar()每次从proBuffer里取一个字符并且如果取到\n就让errorLine加一。Retract()则反向操作但如果当前proBuffer[point]是\n它会先让errorLine减一再回退指针这是行号维护的关键。bool GetChar() { if (point PRO_MAX_LEN proBuffer[point] ! \0) { ch proBuffer[point]; if (ch \n) errorLine; return true; } ch \0; return false; } void Retract() { if (proBuffer[point] \n errorLine 0) errorLine--; point--; }这里有个很容易踩的坑Retract()判断的是proBuffer[point]也就是当前指针指向的字符。如果之前GetChar()刚读到\n并且指针已经越过了它回退时proBuffer[point]指向的是代码里的\n这时errorLine减一逻辑是对的。但如果连续回退两次第二次回退时proBuffer[point]已经不是\n就不会再减这也是为什么代码里default分支要回退两次然后重新读入保证行号不重复加减。另外GetBC()用来跳过空白字符它内部先GetChar()再循环判断isspace(ch)如果文件读完就返回false并把ch置为\0。2.3 预处理阶段的边界情况注释符号出现在字符串里这份代码的预处理逻辑有一个明确的边界它没有处理“注释符号出现在字符串或字符常量里”的情况。比如char *s /* not comment */;预处理会认为/*是注释开始然后把字符串内容当注释吃掉直到找到*/。如果*/没找到就报ProcError(5)提示“注释丧失 */”。这是实验级代码的正常取舍——真正的编译器预处理需要区分 token 上下文但课程设计里通常不会把这种用例作为硬性要求。我一般会在实验报告里主动写清楚这个限制反而显得对词法分析的状态感知有理解。3. 关键字表与符号表用查表法代替逐字比较3.1 32 个关键字的存储方式与 Reserve 函数C 语言的关键字有 32 个这份代码用二维字符数组kwTab存下来KEYWORD_LEN宏定义为 32。Reserve()函数逐个比较如果匹配返回i1否则返回 0。注意 1 的原因是 0 被用作“非关键字”的标记这样关键字编号从 1 开始不会和错误码 0 冲突。int Reserve(char *str) { int i; for (i 0; i KEYWORD_LEN; i) { if (0 strcmp(kwTab[i], str)) return i 1; } return 0; }查表法的核心好处是简单直接32 个关键字线性扫描的开销对实验来说完全可以接受。如果觉得顺序查找不够“高级”可以改成二分查找前提是kwTab按字母序排列但这会让代码维护成本变高。实验报告里如果你写“本设计采用查表法时间复杂度 O(n)在关键字数量固定为 32 时开销可忽略”评审老师挑不出毛病。关键字编号用i1还有个隐藏好处后续 wordAnalyse 里的pDu-value -1表示“该 token 没有表下标”而关键字 token 的 value 永远为 -1因为它不需要进符号表。3.2 符号表与常量表的插入策略去重是关键InsertId()和InsertConst()做的事情本质上一样先遍历表找到同名就返回已有下标找不到就追加新条目。表的容量是STB_MAX_LEN 1000常量表也是 1000。int InsertId(char *str) { int i; for (i 0; i pointSTB; i) if (0 strcmp(signTab[i], str)) return i; strcpy(signTab[pointSTB], str); return (pointSTB - 1); }这段代码里pointSTB既是已用条目的数量也是下一个空位的下标。strcpy之后pointSTB返回值是pointSTB - 1也就是新插入条目的下标。这个设计的好处是同一个标识符在源代码里出现 10 次符号表里只有 1 条记录后续语法分析阶段查符号表属性时直接复用下标即可。坏处是如果源代码里标识符超过 999 个会越界写坏内存因为这里没有检查pointSTB是否达到上限。实际使用时建议在InsertId开头加一个容量判断返回-1表示表满。不信的话拿一段自动生成的超长代码跑一次大概率会看到玄学崩溃。3.3 标识符识别的状态循环字母开头、后面跟字母数字下划线wordAnalyse()里对标识符的处理用的是judge变量技巧先GetBC()拿到非空白字符然后根据字符类型设置judge的值再进入 switch 分支。GetBC(); judge ch; if (isalpha(ch) || ch _) judge L; if (isdigit(ch)) judge D; switch (judge) { case L: while (isalnum(ch) || ch _) { wordget[i] ch; GetChar(); } wordget[i] \0; Retract(); code Reserve(wordget); if (code 0) { value InsertId(wordget); pDu-kind ID; pDu-value value; } else { pDu-kind code; pDu-value -1; } return true;这段代码的核心思想是只要当前字符是字母、数字或下划线就一直读下去直到遇到非这些字符然后Retract()回退多余读入的字符。这里有个细节容易被忽略循环条件是isalnum(ch) || ch _也就是说数字开头进不了这个分支因为在前面judge判断时isdigit(ch)会把数字字符导向D分支。标识符开头不能是数字的规则在这里是靠分支入口保证的不是靠循环条件。Retract()之后调Reserve判断是不是关键字是关键字就给 kind 赋关键字编号不是关键字就插入符号表。注意循环里最后一次GetChar()读到的字符是要被回退的这就是“超前读一个字符”的标准做法。4. 运算符与界符识别judge 变量 多字符运算符消解4.1 judge 变量与 switch 分支的整体结构这个分析器的运算符识别部分用了judge变量做入口分发judge初始值就是当前字符本身但字母被改成L数字被改成D这样 switch 的 case 就可以同时处理单字符运算符和字母/数字分支。单字符界符如(,),[,],;,{,}直接构造 token 返回。多字符运算符则需要向前多看一个字符来判断到底是还是是还是。case : wordget[i] ch; GetChar(); if (ch || ch ) wordget[i] ch; else Retract(); wordget[i] \0; break;这段代码的逻辑先收下再读下一个字符。如果下一个字符是或,说明是或一起收进 wordget否则说明只有一个需要Retract()把多读的字符还回去。回退之后wordget[i] \0截断字符串然后跳出 switch统一走到底部pDu-kind OPERAT; return true;。这个模式在-、*、/、%、、、、|、^、等分支里反复出现区别只在于第二个字符的候选项不同。-分支多了一个的判断所以-指针访问符也能被识别出来。4.2 字符常量与字符串常量的处理转义字符的关键路径字符常量分支用单引号开头逻辑是先收下再读一个字符。如果这个字符是\说明是转义序列比如\n需要再读一个字符把n收进来然后再读右引号。case \: wordget[i] ch; GetChar(); wordget[i] ch; if (ch \\) { GetChar(); wordget[i] ch; } GetChar(); wordget[i] ch; wordget[i] \0; if (ch ! \) { printf(%s, wordget); ProcError(2); pDu-kind ERROR; pDu-value 0; } else { value InsertConst(wordget); pDu-kind CONST; pDu-value value; } return true;这里有个值得注意的顺序问题如果读到的不是\\那说明只有一个普通字符此时第二次GetChar()直接读右引号。所以整个逻辑覆盖了a和\n两种形态。如果最后读到的不是比如ab这种多字符常量就会报ProcError(2)提示“不正确的字符常量表达”。字符串常量分支case 的处理类似不同的是循环直到读到双引号或文件结束如果ch \0说明字符串没闭合报错误码 3。4.3 运算符识别的遗漏项检查对照 C 语言运算符表我把 C 语言运算符过了一遍这份代码覆盖了 - * / % | ^ !的单字符形式以及 -- - * / % ! || | ^ -的多字符形式。缺失的是? :已经在界符里处理了sizeof走关键字表。三个点...可变参数、#预处理器、.结构体访问都归到界符分支。所以只要不是反复嵌套的复杂表达式这份分析器的运算符识别是够用的。不过要注意*分支判断的是**和***其实不是 C 标准运算符但这不影响分析器正常工作最多是多识别一个不存在的运算符 token。运行时如果遇到a ** b这种代码它会被识别成两个*运算符语法分析阶段会报错这是合理的。5. 避坑与常见问题排查行号错乱、表溢出、getch 依赖5.1 错误行号不准预处理改变了行数但分析阶段的行号是对的现象预处理完成后打印的源代码行数和词法分析报错时的行数对不上。原因pretreatment()会删除//注释原来注释里的换行会被丢掉只有/* */注释里的换行被保留。词法分析时errorLine从 0 重新计数读入的是预处理后的缓冲区所以行号对应的是预处理后的代码行不是原始文件行。解决如果你想对原始文件行号需要在pretreatment()里把删除的换行数量统计出来或者保留原始文件副本。一般实验不要求精确到原始行号预处理后行号够用。5.2 表溢出导致内存写坏插入函数没有容量检查现象源代码里标识符超过 1000 个程序不报错但结果随机出错严重时崩溃。原因InsertId()和InsertConst()只判断同名存在不判断pointSTB是否达到STB_MAX_LEN。解决在插入前加判断表满时返回 0 或 -1主循环收到异常值就停止分析并提示“符号表溢出”。int InsertId(char *str) { if (pointSTB STB_MAX_LEN) return -1; int i; for (i 0; i pointSTB; i) if (0 strcmp(signTab[i], str)) return i; strcpy(signTab[pointSTB], str); return (pointSTB - 1); }对课程设计来说加上这段判断不需要额外引入复杂逻辑但能避免最让人头疼的越界崩溃。要注意-1会和合法的表下标 0 冲突所以主循环里对value -1有特殊判断时要区分“表满”和“关键字 token”两种情况。5.3 getch() 在非 Windows 平台失效移植到 Linux 会报错现象用 GCC 在 Linux 下编译链接阶段报getchundefined reference。原因getch()是 Windows 下conio.h提供的函数Linux 的gcc默认不链接对应库。解决有两个方向一是用getchar()替代但会残留换行符需要额外处理二是用curses库或直接删掉这两个暂停点。从实验结果可读性角度我建议保留 Windows 版本的getch()在报告里注明“本实验在 Windows Visual Studio/Dev-C 环境运行”然后在代码注释里给一个 Linux 替代版本。#ifdef _WIN32 #include conio.h #else #include termios.h #include unistd.h static int getch() { struct termios oldt, newt; tcgetattr(STDIN_FILENO, oldt); newt oldt; newt.c_lflag ~(ICANON | ECHO); tcsetattr(STDIN_FILENO, TCSANOW, newt); int c getchar(); tcsetattr(STDIN_FILENO, TCSANOW, oldt); return c; } #endif5.4 数字识别的边界小数点没进数字逻辑现象输入3.14分析结果是一个整数常量3、一个界符.、一个整数常量14。原因case D分支只循环吸收数字字符遇到.就停止。解决如果你要识别浮点数需要在case D分支里加一个ch .的判断同时判断小数点后是否跟数字。注意a[3].x这种结构体取成员的场景如果盲目把.并入数字反而会出错。一般实验只要求整数常量这个行为可以保留并在报告里说明。5.5 注释未闭合时报错但错误码显示位置不准现象/* comment没有闭合预处理阶段报Error:第 n 行,注释丧失 */但行号是文件末尾行不是注释开始行。原因ProcError(5)调用时errorLine已经累加到文件末尾而代码没有记录注释开始行号。解决在进入/*分支前保存当前errorLine到一个局部变量报错时用这个局部变量输出。这个细节在验收演示时容易被问到改一下也就几行代码。6. 从 Test.txt 到 Result.txt主流程跑通与验证技巧主函数做的事很直接读Test.txt到proBuffer显示源程序调用pretreatment()去注释然后循环调用wordAnalyse()生成二元组写入Result.txt。建议在调试时先准备一段覆盖各种情况的测试代码包含关键字、标识符、整数常量、字符常量、字符串常量、各类运算符、//注释、/* */注释一次性验证所有分支。int main() { Dualistic tmp; pDualistic ptmp tmp; FILE *fin, *fout; int i; char c; char filename[20]; printf(源代码读入\n); if ((fin fopen(Test.txt, r)) NULL) { printf(Cannot open infile\n); return 0; } i 0; while ((c fgetc(fin)) ! EOF) { if (i PRO_MAX_LEN - 1) { printf(\n 程序代码太长无法处理\a); return 0; } proBuffer[i] c; } fclose(fin); proBuffer[i] \0; printf(\n***************************\n 源 代 码 读 入 成 功 源 代 码 如 下 :\n%s, proBuffer); printf(\n 按任意键继续\n); getch(); printf(\n 预处理\n); pretreatment(); printf(\n***************************\n 预处理成功去掉注释后的源代码为:\n%s*, proBuffer); printf(\n 按任意键继续\n); getch(); printf(\n 词法分析\n); point 0; if ((fout fopen(Result.txt, wb)) NULL) { printf(建立文件 Result.txt 失败。\n); return 0; } i 0; errorLine 0; do { if (i PRO_MAX_LEN) break; if (!wordAnalyse(ptmp)) break; if (ptmp-value -1) fprintf(fout, %d, -1\n, ptmp-kind); else fprintf(fout, %d, %d\n, ptmp-kind, ptmp-value); } while (1); fclose(fout); return 0; }主循环里i PRO_MAX_LEN是一个保险丝防止wordAnalyse内部出 bug 死循环无限写文件。ptmp-value -1对应的 token 是关键字、界符和运算符它们不进符号表所以二元组第二个分量固定是 -1。标识符和常量的 value 是符号表/常量表下标。验证方法很简单打开Result.txt对照源程序逐个 token 检查。比如int a 3;应该输出int的关键字编码、a的符号表下标、的运算符编码、3的常量表下标、;的界符编码。实际跑的时候我习惯先跑一个 5 行左右的最小用例确认每个 kind 值都在预期范围再跑完整的测试文件。复杂运算符的验证重点看和、和、-和-这三组最容易翻车的情况是否输出了不同的 kind。从那以后我每次拿到新的词法分析器代码都会先用一份刻意包含所有运算符的样例去测一遍边界组合再谈后续的语法分析对接。这招虽然不是万能但确实能提前拦下大半的识别 bug希望帮到你。本文还有配套的精品资源点击获取

相关新闻

Kepware OPC DA Client连接失败的三大DCOM配置要点

Kepware OPC DA Client连接失败的三大DCOM配置要点

简介:本资源是一份面向工业物联网(IIoT)开发者与自动化工程师的Kepware OPC DA Client实战入门教程,聚焦于使用KEPServerEX实现设备数据采集与监控的核心配置流程。内容覆盖从新建Project、配置Channel(含Optimization…

2026/10/13 21:59:44 阅读更多 →
React脚手架原理与选型指南:从Vite到工程化落地

React脚手架原理与选型指南:从Vite到工程化落地

聊到React项目的起步阶段,脚手架这几个字几乎每次都会被摆上台面。它不是一个简单的配置文件,而是把一整套前端工程化底座直接端到你面前:开发服务器、热更新、构建打包、代码规范、环境变量管理,这些原本要折腾一周的事情&#x…

2026/10/13 21:58:43 阅读更多 →
Agent Skill实战指南:从零构建可复用的AI助手能力模块

Agent Skill实战指南:从零构建可复用的AI助手能力模块

1. 从"每次都要重新教"说起:Agent Skill到底在解决什么如果你用过任何一款AI助手,大概率经历过这样的场景:你花十分钟跟它解释"帮我整理会议纪要时,要按项目分组,每个项目下列出待办事项、负责人和截止…

2026/10/13 21:58:43 阅读更多 →

最新新闻

GRP-U8行政事业版数据库部署与运维:从选型到备份恢复的实战指南

GRP-U8行政事业版数据库部署与运维:从选型到备份恢复的实战指南

简介:无论是日常余额核对、凭证追溯,还是年末结转时清理数据,面对GRP-U8行政事业版庞大的数据库常常让人无从下手。这份资料面向用友GRP-U8财务软件的运维实施与行政事业单位信息化人员,集中梳理出真正核心的四张业务表——GL_Yeb…

2026/10/13 22:59:15 阅读更多 →
Servlet从原理到实战:吃透Java Web底层核心机制

Servlet从原理到实战:吃透Java Web底层核心机制

Servlet 这门技术,放在十年前是 Java Web 开发者的必修课,放在今天看,很多刚接触 Spring Boot 的同学可能只在依赖清单里见过它,甚至有人觉得它已经过时了。但实际上去掉 Spring 的外壳,真正在底层处理 HTTP 请求、管理…

2026/10/13 22:59:15 阅读更多 →
ThinkPHP新闻发布系统开发实战:从路由到后台管理全流程

ThinkPHP新闻发布系统开发实战:从路由到后台管理全流程

简介:ThinkPHP新闻发布系统是一份面向PHP初学者和Web开发入门者的完整前后台项目源码,覆盖前台文章展示、后台分类与文章管理,并集成百度UEditor富文本编辑器,旨在通过一个真实项目帮助理解MVC分层、ActiveRecord数据库操作、路由…

2026/10/13 22:59:15 阅读更多 →
Servlet核心机制与生命周期详解:从HTTP请求到Java方法的完整链路

Servlet核心机制与生命周期详解:从HTTP请求到Java方法的完整链路

Servlet这东西,说起来有点“老”,但如果你想搞明白Java Web到底是怎么跑起来的,它还真躲不开。我带团队和面试新人的时候发现一个现象:不少人上来就学Spring Boot,写接口已经非常熟练,但你把问题往回问一层…

2026/10/13 22:59:15 阅读更多 →
Java NIO Channel深度解析:从BIO痛点、Buffer机制到非阻塞实战

Java NIO Channel深度解析:从BIO痛点、Buffer机制到非阻塞实战

1. 从BIO的痛点到Channel的设计动机很多同学学NIO的时候,一上来就啃Selector、ByteBuffer、Channel这三大件,结果学完一圈还是不知道Channel到底解决了什么问题。我刚开始接触NIO那会儿也是这样,API背得滚瓜烂熟,真到写网络服务的…

2026/10/13 22:59:15 阅读更多 →
ACM竞赛中STL sort的cmp函数设计原理与避坑指南

ACM竞赛中STL sort的cmp函数设计原理与避坑指南

1. 为什么排序不是“写个for循环就完事”的事?刚接触ACM竞赛的新人,十有八九都经历过这个阶段:看到一道题说“把数组从小到大排好”,立刻撸起袖子写个冒泡——三重嵌套,i、j、k变量齐飞,跑样例能过&#xf…

2026/10/13 22:58:14 阅读更多 →

日新闻

物联网系统集成避坑指南:从选型到验收的关键要点

物联网系统集成避坑指南:从选型到验收的关键要点

做了这么多年物联网系统集成的项目,我最大的感受是,大部分坑不是出在技术前沿,而是出在一些看起来很平常的地方。设备选了便宜的、协议没问清楚、现场没摸透、验收标准写得含糊——这些细枝末节,最后都会变成延期、超支和扯皮的大…

2026/10/13 0:00:57 阅读更多 →
ESP32舵机控制全攻略:从PWM原理到高级玩法与常见故障排查

ESP32舵机控制全攻略:从PWM原理到高级玩法与常见故障排查

如果你玩ESP32有一阵子了,很难不碰到舵机控制这道坎。做智能小车要转方向,做机械臂要抬关节,做云台要偏航俯仰,背后都是同一个东西在干活:舵机。而我见过太多人卡在“代码能编译、舵机就是不听话”这个阶段&#xff0c…

2026/10/13 0:00:57 阅读更多 →
CAN总线原理与STM32实战:抗干扰、仲裁、错误处理全解析

CAN总线原理与STM32实战:抗干扰、仲裁、错误处理全解析

1. 为什么CAN总线至今仍是工业现场的“硬通货”?——从汽车底盘到智能温室的真实需求你有没有拆过一辆老款燃油车的中控台?或者调试过某高校实验室里那台跑着Modbus协议却频频丢帧的PLC控制柜?又或者,在某个农业物联网项目里&…

2026/10/13 0:00:57 阅读更多 →

周新闻

流感时间序列预测实战:ARIMA/LSTM全流程拆解与避坑指南

流感时间序列预测实战:ARIMA/LSTM全流程拆解与避坑指南

简介:基于 ARIMA、LSTM、Transformer 等模型的流感时间序列预测 Python 源码,面向计算机相关专业课程设计与期末大作业学生,以及项目实战学习者。内容覆盖预处理、平稳性检验、定阶、残差分析、多模型对比预测的完整时序建模流程,…

2026/10/13 2:54:56 阅读更多 →
影刀RPA新手教程:键盘模拟输入实战——输入文本与模拟按键的区别

影刀RPA新手教程:键盘模拟输入实战——输入文本与模拟按键的区别

影刀RPA新手教程:键盘模拟输入实战——输入文本与模拟按键的区别 做影刀RPA自动化,十个新手有八个栽在"往输入框里填东西"这件事上:要么填不进去,要么填了一半,要么直接把原来内容追加在后面。这背后的根因&…

2026/10/13 16:22:04 阅读更多 →
影刀RPA新手教程:阅文起点小说数据采集实战——书籍信息与章节内容

影刀RPA新手教程:阅文起点小说数据采集实战——书籍信息与章节内容

影刀RPA新手教程:阅文起点小说数据采集实战——书籍信息与章节内容 1. 认识影刀:什么场景该用RPA采小说数据 起点中文网的页面结构相对稳定——分类榜单、书籍详情、章节内容三块独立页面,跳转链路清晰。这种场景非常适合影刀自动化&#x…

2026/10/13 1:58:08 阅读更多 →

月新闻

我发现了一个新思路:用 Remotion + Claude Code 像写代码一样自动化生成短视频

我发现了一个新思路:用 Remotion + Claude Code 像写代码一样自动化生成短视频

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/13 22:01:27 阅读更多 →
Windows下 Codex 中 Chrome 和 Computer Use 插件不可用问题排查及解决参考方式:TaoToken 统一 Key 配置与验证

Windows下 Codex 中 Chrome 和 Computer Use 插件不可用问题排查及解决参考方式:TaoToken 统一 Key 配置与验证

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/13 14:57:39 阅读更多 →
黑夜航拍船只数据集训练YOLOV5模型全流程解析

黑夜航拍船只数据集训练YOLOV5模型全流程解析

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/12 18:11:17 阅读更多 →