flex+bison实现小型编译器:词法分析、语法分析与语义检查全流程
简介这是一套面向计算机专业本科生的编译原理课程设计完整资料覆盖词法分析、LL(1)预测分析、LR(0)/SLR(1)语法分析、四元式生成与汇编代码生成并附带小型编译器实现及课程设计报告可满足从实验到报告提交的全流程需求。压缩包共14个文件以cpp、c、h源码为主辅以txt文法描述与doc实验报告整体仅557KB结构紧凑便于按模块阅读。目前已有2348人学习下载内容组织与文件划分清晰。资料中既包含可直接运行的词法分析器、语法分析程序可处理ii*i这类简单语句也有配套的LL(1)与SLR(1)文法定义方便直接测试分析流程同时提供四元式与汇编代码生成逻辑能直观展示中间代码与目标代码的衔接过程。适合正在完成编译原理大作业或希望系统梳理编译过程的学生对照学习与复用。1. 编译原理课程设计的真正难点不是算法是工具链的联动很多人第一次做编译原理课程设计把精力全扑在词法分析的正则和语法分析的文法推导上结果卡在 flex 和 bison 的联调上——每个模块单独跑都正常拼起来就崩最后靠打印 yytext 熬过验收。我把这条路的完整流程拆开来讲先用 flex 把源码切成 token 流再用 bison 按文法把 token 拼成抽象语法树接着补符号表驱动的语义检查最后走一个解释执行的小型编译器闭环。这正好覆盖标题里的「词法分析、语法分析、小型编译器」三段也会告诉你实验报告怎么写才不会被评分的人当成流水账。适合正在做课程设计的本科生也适合想快速搭起编译前端骨架的从业者。2. 整体方案选型为什么是 flex bison而不是手写递归下降动手之前先定路线。编译原理课程设计最常见的死法是拿到题目就开写代码写到语法分析阶段才发现词法接口设计错了回头改 token 定义改到崩溃。这里先讲清楚三种路线的差异再给出一个可以直接照抄的工程结构。2.1 三条实现路线的对比与适用场景常见的课程设计实现路线有三条flex bison 工具链、纯手工词法 递归下降、纯手工词法 算符优先分析法。它们的差异不只是代码量而是整个工程的复杂度和排错成本。实现路线前置学习成本代码量排错难度适用场景flex bison中两个工具都要学少中工具信息量大但规律性强大多数课程设计有实验环境支持手工词法 递归下降低最多低每行都是自己写的题目要求不得使用自动生成工具手工词法 算符优先高只适用于表达式文法中高优先级表维护麻烦目标语言只有表达式不推荐我的建议很直接如果题目没禁止生成器优先选 flex bison。理由不是它更简单而是它把「用正则切 token」和「按文法归约」这两件机械劳动交给工具把人的精力留给最值得写的部分——抽象语法树构建、符号表、语义检查。这些才是编译原理课程设计的评分重点。递归下降更适合你工作后为某个专用 DSL 写解析器时使用课程设计用它会消耗大量时间在事务性代码上。2.2 目标语言定义一个类 C 子集没有目标语言的编译器是空中楼阁。我习惯在写任何代码之前先定一个「类 C 子集」的语法规范并把示例程序贴在项目 README 开头。这样后面写 flex 规则、bison 文法、语义检查每一步都有据可依。int x; int y; bool flag; x 10; y 20; flag x y 25 x 10; if (flag) { x x 1; } else { x x - 1; } while (x 20) { x x 1; } return x;这个子集看起来小但覆盖了编译原理课程设计的核心考点变量声明、赋值语句、if/else 分支、while 循环、关系运算、逻辑运算、算术表达式、注释跳过。词法分析要处理标识符、关键字、整数、浮点数、运算符定界符五行字符语法分析要处理优先级、左结合、悬挂 else语义分析要处理未声明变量、类型不匹配、不可达 return。麻雀虽小五脏俱全。2.3 工程文件结构与一次完整构建流程明确了目标语言就可以规划文件结构。下面这个布局是我多次课程设计后固定下来的每个文件职责单一出了问题能立刻定位到是词法、语法还是语义层。project/ ├── Makefile # 构建入口控制 bison/flex/gcc 的执行顺序 ├── lexer.l # flex 词法规则生成 token 流 ├── parser.y # bison 文法规则构建 AST ├── ast.h # AST 节点类型定义与构造函数声明 ├── ast.c # AST 节点创建与销毁实现 ├── symtab.h # 符号表结构定义与接口声明 ├── symtab.c # 符号表插入、查找实现 ├── semantics.c # 语义检查变量声明、类型兼容 ├── interpreter.c # 解释执行 AST └── main.c # 入口读取源文件串联各阶段构建顺序是这条链路里最容易踩的第一个坑。bison 解析 parser.y 时会同时生成 parser.tab.c 和 parser.tab.h而 flex 的 lexer.l 里需要#include parser.tab.h来获取 token 宏定义。所以必须先跑 bison 再跑 flex最后才用 gcc 链接所有.c文件。all: compiler compiler: lex.yy.c parser.tab.c ast.c symtab.c semantics.c interpreter.c main.c gcc -o compiler lex.yy.c parser.tab.c ast.c symtab.c semantics.c interpreter.c main.c -lm lex.yy.c: lexer.l parser.tab.h flex lexer.l parser.tab.c parser.tab.h: parser.y bison -d parser.y clean: rm -f compiler lex.yy.c parser.tab.c parser.tab.h .PHONY: all clean注意 Makefile 里lex.yy.c的依赖是parser.tab.hlexer.l写错这个依赖会让你在改了 token 定义后 make 时莫名其妙地沿用旧头文件。还有一点flex 和 bison 在不同发行版里安装位置不同但编译命令基本一致flex生成lex.yy.cbison -d生成带头文件的解析器源码。整个流程清晰之后就可以开始写词法了。3. 词法分析落地Flex 规则、token 设计与行号追踪词法分析的工作量不大但细节极其容易翻车。这一章给出一个完整的 flex 词法文件并逐一解释每个规则为什么这么写。3.1 flex 文件三段式结构与 token 接口flex 文件由%{ %}定义区、%%规则区、%%用户代码区三段组成。定义区写 C 头文件包含和辅助函数声明规则区写正则与动作用户代码区放yywrap等辅助实现。%{ #include stdio.h #include stdlib.h #include string.h #include parser.tab.h int yyerror(const char *s); %} %option noyywrap %option yylineno digit [0-9] letter [A-Za-z_] identifier {letter}({letter}|{digit})*这里的核心是#include parser.tab.h。token 宏如IF、WHILE和%union类型都定义在 bison 生成的头文件里flex 通过包含它拿到类型定义。%option yylineno开启行号自动追踪后面错误报告全靠它。注意yyerror需要声明否则链接时报隐式声明警告。3.2 完整词法规则关键字、标识符、数字与注释的匹配顺序规则区的顺序是有讲究的。flex 默认「最长匹配优先长度相同时取先出现的规则」。利用这个特性我先把完整的双精度浮点数规则放在整数之前否则3.14会被切成3和.14两个 token。%% /*([^*]|\*[^*/])*\*/ { /* 跳过块注释 */ } //.* { /* 跳过行注释 */ } [ \t\r\n] { /* 跳过空白 */ } int { return INT_KW; } double { return DOUBLE_KW; } bool { return BOOL_KW; } if { return IF; } else { return ELSE; } while { return WHILE; } return { return RETURN; } true { yylval.bval 1; return BOOL_LITERAL; } false { yylval.bval 0; return BOOL_LITERAL; } {digit}.{digit} { yylval.dval atof(yytext); return DOUBLE_LITERAL; } {digit} { yylval.ival atoi(yytext); return INT_LITERAL; } {identifier} { yylval.sval strdup(yytext); return ID; } { return EQ; } ! { return NEQ; } { return GE; } { return LE; } { return AND; } || { return OR; } { return ; } - { return -; } * { return *; } / { return /; } ( { return (; } ) { return ); } { { return {; } } { return }; } { return ; } ; { return ;; } . { fprintf(stderr, line %d: 非法字符 %s\n, yylineno, yytext); return yytext[0]; }%%几个关键点要说明。关键字规则必须放在标识符规则之前因为 flex 按规则顺序匹配相同长度的输入int 如果混进 {identifier} 规则就会变成普通标识符语法层根本分不清。双精度字面量规则用 {digit}.{digit} 而不是 {digit}(.{digit})?后者会把 10 也吞成 DOUBLE_LITERAL导致类型信息丢失。最后的 . 兜底规则极其重要它确保任何未知字符都不会让 flex 死循环而是作为单字符 token 抛给语法层报错。 ### 3.3 注释匹配的玄学与规则优先级 注释正则 /*([^*]|\*[^*/])*\*/ 看起来复杂它实际上解决了两个问题注释内容里可以出现单个 *比如 a * b但不能出现 */ 结束符以外的星号组合。如果你图省事写成 /*.**/flex 的最长匹配会贪婪吞掉 */ 之后的所有内容直到最后一个 */ 才结束——整段代码被当成注释这是课程设计里最容易让调试到怀疑人生的错误之一。 行号追踪还有一个细节%option yylineno 让 flex 自动维护 yylineno但你仍然要在跨行 token 出现时手动修正。例如双引号字符串如果跨行本设计不支持yylineno 就停在起始行。这里我们的类 C 子集不支持字符串类型注释和空白由 flex 自动处理行号天然准确。词法分析到这里闭环下一步是语法分析。 ## 4. 语法分析与 AST 构建Bison 规则怎么写才能一次通过 语法分析是整个课程设计里分值最高、最容易出 conflict 警告的部分。这一章给出一个无冲突的 bison 文法以及配套的 AST 节点设计。 ### 4.1 bison 文件骨架与 %union 设计 bison 文件同样分三段。%{ %} 里 #include ast.h%union 声明所有语义值的类型——token 属性和非终结符属性共用这一个联合体。这里必须和 flex 侧的 yylval 访问方式严格对应flex 里 yylval.ival、yylval.sval、yylval.dval、yylval.bval 四种类型bison 的 %union 就要声明出这四种成员。 c %{ #include stdio.h #include stdlib.h #include ast.h int yylex(void); void yyerror(const char *s); %} %union { int ival; double dval; char bval; char *sval; struct ASTNode *node; } %token sval ID %token ival INT_LITERAL %token dval DOUBLE_LITERAL %token bval BOOL_LITERAL %token INT_KW DOUBLE_KW BOOL_KW %token IF ELSE WHILE RETURN %token EQ NEQ LE GE AND OR %type node program stmt_list stmt decl expr logic_or logic_and equality relational additive multiplicative unary primary %left OR %left AND %left EQ NEQ %left LE GE %left - %left * / % %right ! %nonassoc THEN %nonassoc ELSE %%优先级声明从低到高排列||最低其次、相等比较、关系比较、加减、乘除、一元取反。%nonassoc THEN和%nonassoc ELSE是解决悬挂 else 的关键稍后展开。%type node声明所有语法树相关的非终结符都携带 ASTNode 指针。4.2 AST 节点定义类型、结构与构造函数AST 是整个编译器的核心数据结构。我建议把所有节点类型收敛到一个结构体里用 type 字段区分比每个语法结构建一个结构体更容易写遍历代码。下面这个定义经过了多次课程设计验证覆盖声明、赋值、分支、循环、表达式五类语句。#ifndef AST_H #define AST_H typedef enum { NODE_INT_DECL, NODE_DOUBLE_DECL, NODE_BOOL_DECL, NODE_ASSIGN, NODE_IF, NODE_WHILE, NODE_RETURN, NODE_BINARY, NODE_UNARY, NODE_INT_LIT, NODE_DOUBLE_LIT, NODE_BOOL_LIT, NODE_VAR, NODE_BLOCK } NodeType; typedef struct ASTNode { NodeType type; struct ASTNode *lhs; struct ASTNode *rhs; struct ASTNode *body; /* while / if 的循环体或分支体 */ struct ASTNode *else_body; /* if 的 else 分支 */ char *name; /* 变量名 */ char *op; /* 二元/一元运算符字符串 */ int ival; double dval; int bval; struct ASTNode *next; /* 语句块中的下一条语句 */ } ASTNode; ASTNode *new_node(NodeType type); ASTNode *new_int_lit(int v); ASTNode *new_double_lit(double v); ASTNode *new_bool_lit(int v); ASTNode *new_var(char *name); ASTNode *new_binary(char *op, ASTNode *l, ASTNode *r); ASTNode *new_unary(char *op, ASTNode *operand); ASTNode *new_block(ASTNode *stmt_list); void free_ast(ASTNode *node); #endif所有节点用一个结构体的好处是遍历和销毁逻辑统一。lhs、rhs同时承担表达式左右操作数与赋值语句的目标和值两个角色body和else_body专属于 if 和 whilename只对变量节点有效。这样设计会有少量内存浪费但换取的是语义检查和解释执行阶段极低的编写复杂度。对课程设计而言这个取舍非常划算。4.3 文法规则与动作代码节点构造的完整写法文法规则的动作代码里每个归约动作都调用 AST 构造函数把子节点的指针组装进父节点。注意声明语句和赋值语句都用号但语义完全不同——声明在符号表里登记新变量赋值则要求变量已经存在。program: stmt_list { $$ $1; } ; stmt_list: stmt { $$ $1; } | stmt_list stmt { ASTNode *n $1; while (n-next) n n-next; n-next $2; $$ $1; } ; stmt: decl | { stmt_list } { $$ $2; } | IF ( expr ) stmt %prec THEN { $$ new_node(NODE_IF); $$-lhs $3; $$-body $5; } | IF ( expr ) stmt ELSE stmt %prec ELSE { $$ new_node(NODE_IF); $$-lhs $3; $$-body $5; $$-else_body $7; } | WHILE ( expr ) stmt { $$ new_node(NODE_WHILE); $$-lhs $3; $$-body $5; } | RETURN expr ; { $$ new_node(NODE_RETURN); $$-lhs $2; } | ID expr ; { $$ new_node(NODE_ASSIGN); $$-name $1; $$-lhs $3; } ; decl: INT_KW ID expr ; { $$ new_node(NODE_INT_DECL); $$-name $2; $$-lhs $4; } | DOUBLE_KW ID expr ; { $$ new_node(NODE_DOUBLE_DECL); $$-name $2; $$-lhs $4; } | BOOL_KW ID expr ; { $$ new_node(NODE_BOOL_DECL); $$-name $2; $$-lhs $4; } ; expr: logic_or { $$ $1; } ; logic_or: logic_and { $$ $1; } | logic_or OR logic_and { $$ new_binary(||, $1, $3); } ; logic_and: equality { $$ $1; } | logic_and AND equality { $$ new_binary(, $1, $3); } ;表达式层级继续往下展开equality 处理、!relational 处理 additive 处理加减multiplicative 处理乘除取模unary 处理!primary 处理括号、字面量和变量。每一层写成左递归bison 会自动转成循环而不是深度递归避免解析长表达式时栈溢出。4.4 悬挂 else 冲突%nonassoc与优先级声明初学者第一次编译 bison 文件十有八九看到conflicts: 1 shift/reduce的警告这就是经典的悬挂 else。原因if (e) stmt if (e) stmt else stmt里内层 if 归约后遇到 else 时不知道它属于外层还是内层。bison 默认 shift行为是 else 就近匹配内层 if这恰好是 C 的语义。但警告不能靠「默认行为正确」糊弄过去。正确做法是用%nonassoc THEN和%nonassoc ELSE配合%prec手动决定优先级没有 else 的 if 规则优先级是 THEN有 else 的 if 规则优先级是 ELSE。由于 ELSE 优先级更高遇到 else 时 bison 会优先归约带 else 的规则冲突从警告列表里彻底消失。照 4.1 和 4.3 的写法编译bison 应该零冲突通过。4.5 yyerror 与错误恢复不让解析器第一次报错就退出语法错误处理如果只写yyerror打印一行就退出调试体验极差——用户改一个错误后面几十行全部跟着报错。标准做法是在 stmt_list 里加错误恢复规则stmt_list: stmt { $$ $1; } | stmt_list stmt { ... } | stmt_list error ; { fprintf(stderr, line %d: 语法错误已跳过该语句\n, yylineno); yyerrok; } ;error 是 bison 内置 token遇到语法错误时它会丢弃当前 token 之前的输入一直读到分号为止然后恢复同步。yyerrok复位错误状态让解析器继续工作而不是退出。这样一条语句写错不牵连全局对实验报告的「错误处理能力」部分也是加分项。5. 词法与语法联调的五个翻车现场这个章节写的是我见过、也亲历过的坑。每一条都是「现象 → 原因 → 解决」三段式全部来自真实调试经历。5.1 先跑 bison 还是先跑 flex头文件缺失导致全线编译失败现象make报错提示parser.tab.hNo such file or directory或者 lexer.l 里所有 token 宏未定义。第一次做课程设计的同学几乎都会遇到。原因flex 的 lexer.l 通过#include parser.tab.h拿到 bison 定义的 token 宏但第一次构建时该头文件还没生成。Makefile 里如果没有把lex.yy.c的依赖声明为parser.tab.hmake 会按源码顺序尝试先编译 lexer.l 就失败。解决严格按 2.3 节的 Makefile 写法声明依赖关系。改完 token 定义后rm -f lex.yy.c parser.tab.c parser.tab.h再重新 make不要迷信增量构建。5.2 flex 的 yylval 类型和 bison 的 %union 对不上现象编译顺利通过但运行时崩溃或者yylval.sval取到乱码。调试时打印yytext正常一旦存入yylval就坏。原因flex 和 bison 对语义值的类型定义必须完全一致。flex 里写yylval.ival atoi(yytext)前提是%union里有成员ival。两者通过parser.tab.h同步理论上不会不一致——但如果你在 lexer.l 里手动#define了一个同名yylval或者用了两个不同的头文件路径类型就对不上了。解决不要在 flex 文件里手动声明extern YYSTYPE yylval;直接#include parser.tab.h。如果修改了%union务必把 flex 文件里对yylval的赋值全部检查一遍字段名要逐一对应。5.3 悬挂去掉shift/reduce冲突不能靠忽略解决现象bison 编译输出warning: 1 shift/reduce conflict程序短表达式没问题嵌套 if/else 时行为诡异或分支归属错误。原因没有用%prec明确 if-else 不同形态的优先级冲突被 bison 默认规则压制行为恰好对了但一旦文法里再混入其它规则默认行为可能变错。解决按 4.1 的方式声明%nonassoc THEN、%nonassoc ELSE并把%prec写到两条 if 规则末尾。最终期望输出0 conflicts这是语法文件「干净」的重要指标。5.4 用比较字符串 token变量名永远比不对现象解释执行x 10; y x;正常改成abc 10;后语义检查报错「未声明变量 abc」但符号表里明明有。原因词法分析里yylval.sval strdup(yytext)存的是指针。检查变量名是否匹配时如果图省事写strcmp(var-name, sym-name) 0之前的if (var-name sym-name)比较的是指针地址两个不同字符串的地址永远不会相等。解决所有字符串比较一律用strcmp。这条看起来基础但字符串字面量驻留和strdup混用时指针相等的假象很容易掩盖问题——同一个标识符在同一场景下可能两次strdup出不同地址。5.5 注释正则写错整段代码被吞现象代码里写/* a 1; */ b 2;词法分析把b 2也当成注释吞掉直到下一个*/出现才恢复程序执行结果完全错误。原因块注释正则写成/*(.|\n)**/flex 的最长匹配会让.贪婪吞掉所有字符包括中间的*/直到最后一个*/才停止。同理用.*匹配注释内容也是高危写法。解决用 3.2 节给出的严格正则/*([^*]|\*[^*/])*\*/。它保证注释内部不包含结束序列匹配到第一个合法的*/就停止。如果目标语言允许注释嵌套则这条链路的复杂度和需求复杂度都会暴涨课程设计阶段不建议开启。6. 语义检查与实验报告把闭环补齐把成果写清楚最后一步收尾把 AST 从「长得像语法」变成「真正能跑」同时把实验报告打磨成能证明你理解原理的文档。6.1 符号表驱动的语义检查语义检查的核心是一个符号表。遍历 AST 时遇到NODE_ASSIGN或任何变量读取都先查表未声明变量直接报错声明语句则把变量名和类型登记进去重复声明报错。类型检查放在二元表达式节点例如int double是否自动提升为 double取决于你在报告里声明的类型规则。6.2 解释执行而非完整代码生成小型编译器课程设计最稳妥的收官方案是解释执行自顶向下遍历 AST声明语句往符号表里写值赋值语句计算右侧再更新符号表if/while 根据条件节点求值结果决定遍历路径。这样做省去了寄存器分配和目标代码生成的庞大工作量但完整覆盖了「词法切分 → 语法解析 → 语义检查 → 执行」的编译前端闭环对本科课程设计完全够用。6.3 实验报告结构与测试用例设计实验报告的价值在于让评分者快速确认两件事你理解了原理系统能正确工作。建议结构需求描述、总体设计、详细设计词法/语法/语义分节、测试结果、反思与改进。测试用例一定要给出「预期输出」和「实际结果」的对照表。用例编号输入代码预期输出实际结果T01int a; a 1; return a;11T02int a; a 1; if (a 0) { return a; } else { return 0; }11T03未声明变量b 2;语义错误b 未声明语义错误b 未声明T04嵌套 if/else 悬挂 else 归属else 匹配最近 if匹配最近 ifT0510 / 2 - 3 * 2 100每张表后面附两段关键代码的截图配 2-3 行说明比几十页代码清单更有说服力。错误处理能力第 5.4 节的错误恢复单独列一节这是很多报告忽略但老师会看的加分项。6.4 从课程设计走向真实编译器做完这个项目如果你想继续扩展优先级我建议是数组类型、函数调用、三地址码生成。数组需要符号表支持下标访问函数需要栈帧模型三地址码是通往中间代码优化的必经之路。每一步都在现有 AST 骨架上增加节点类型不会推翻重构。我自己的血泪经验是每个阶段都保留一份能编译运行的最小版本再继续绝不在损坏的代码上叠加新功能所有调试信息用统一的-v开关控制验收时把输出调干净。这份课程设计做完你对 flex/bison 的掌握会比读十遍教材更有用。希望帮到你。本文还有配套的精品资源点击获取

相关新闻

知识蒸馏+增量学习:目标检测模型如何越训越强不忘旧类

知识蒸馏+增量学习:目标检测模型如何越训越强不忘旧类

简介:本资源为基于知识蒸馏的目标检测模型增量深度学习方法的Python源码,面向人工智能、计算机视觉方向的高校学生、教师及企业研发人员,尤其适合正在做毕设、课程设计或算法进阶的学习者,用于解决目标检测模型在增量学习中易遗忘…

2026/10/12 10:03:54 阅读更多 →
AI Agent记忆管理实战:四层架构与可验证落地指南

AI Agent记忆管理实战:四层架构与可验证落地指南

1. 为什么“记忆”是AI Agent最常被忽略的致命短板 我第一次在某跨平台系统里跑通一个带多轮对话的Agent时,兴奋地给团队演示“它能记住用户刚说过的偏好”。结果第三轮对话刚过,它就把用户明确说过的“不要推荐咖啡因饮料”忘得一干二净,转头…

2026/10/12 10:03:54 阅读更多 →
AI Agent工程实践指南:从决策判断到故障防御

AI Agent工程实践指南:从决策判断到故障防御

1. 这不是又一本“AI科普书”,而是一份给动手者的Agent开发手记你点开这个标题,大概率不是想听“AI Agent是什么”这种教科书定义——毕竟搜索引擎里铺天盖地的“概念图解”“三层架构图”“RAGLLMAgent”已经够多。真正卡住你的,是那几个深夜…

2026/10/12 10:03:54 阅读更多 →

最新新闻

从 Ubuntu 25.10 到 26.04 LTS:一次跨版本升级的完整技术路线图与 TaoToken 配置实践

从 Ubuntu 25.10 到 26.04 LTS:一次跨版本升级的完整技术路线图与 TaoToken 配置实践

/* 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 10:42:36 阅读更多 →
FFmpeg Windows编译整合包:x264/x265/AAC静态库配置与调试指南

FFmpeg Windows编译整合包:x264/x265/AAC静态库配置与调试指南

简介:本资源面向需要在Windows平台完成FFmpeg音视频开发环境搭建的开发者,尤其适合希望直接获取可编译、可调试源码包的初中级工程师。压缩包约291.35MB,整合了x264、x265、AAC与FFmpeg的源码及配套编译工具,并按用途划分为多个目…

2026/10/12 10:42:36 阅读更多 →
九月开源项目盘点:20个AI工作流与终端工具,小而精趋势明显

九月开源项目盘点:20个AI工作流与终端工具,小而精趋势明显

1. 为什么九月的开源圈值得单独拎出来聊九月份在开源社区里一直是个特殊的月份。北半球的开发者结束了暑假,南半球的同行们还在冬末的节奏里憋着劲,各大项目维护者像是约好了一样集中发版,新项目也扎堆冒头。我翻了一圈这个月冒出来的仓库&am…

2026/10/12 10:42:36 阅读更多 →
Allure 自动化测试报告实战:接入、定制与排错全链路

Allure 自动化测试报告实战:接入、定制与排错全链路

测试报告这件事,我做自动化这些年踩过的坑比写过的用例还多。前几年接手一个老项目,前任留下的"测试报告"是一个四百多行的 txt,PASS和FAIL交替刷屏,失败原因清一色写着AssertionError,既没有截图也没有请求…

2026/10/12 10:42:36 阅读更多 →
三维重建与点云处理入门:从配准、分割到表面重建的完整指南

三维重建与点云处理入门:从配准、分割到表面重建的完整指南

1. 三维重建与点云技术入门指南1.1 从零开始理解三维重建与点云三维重建这个词听起来很唬人,但说白了就是让计算机通过一张或多张二维照片,反推出物体或场景在真实世界中的三维形状。你可以把它想象成:你站在一个雕塑前面拍了几十张照片&…

2026/10/12 10:42:36 阅读更多 →
MATLAB入门实操:从矩阵运算到脚本绘图调试

MATLAB入门实操:从矩阵运算到脚本绘图调试

刚接触MATLAB的时候,很多人会把它当成一个"计算器加强版"来用,输几个命令也算出了结果,但真到了要独立完成一个入门级演示项目时才发现,自己连"怎么把代码组织得像样"都还没想清楚。这篇文章就是写给那些已经…

2026/10/12 10:41:35 阅读更多 →

日新闻

复古胶片颗粒感噪点合成器:Canvas ImageData 像素高斯杂色注入算法

复古胶片颗粒感噪点合成器:Canvas ImageData 像素高斯杂色注入算法

在数码相机、高清显示屏与现代矢量图形技术高度发达的今天,画面可以做到绝对的锐利、平滑与无瑕。然而,当一张秋日手账插画或拍立得照片过于“平整无瑕”时,往往会散发出一种冰冷生硬的“数码塑料感(Digital Plasticity&#xff0…

2026/10/12 0:00:59 阅读更多 →
活字印刷古籍线装排版:Canvas 竖排文字与栏线自适应算法

活字印刷古籍线装排版:Canvas 竖排文字与栏线自适应算法

在现代网页与移动端设计中,横排(Horizontal Layout)早已经成为了绝对的主流。然而,当我们翻开泛黄的线装古籍、宋版木刻诗集,或是欣赏一张茶道雅集的手写便签时,那种**自上而下纵向书写、自右向左逐列铺展&…

2026/10/12 0:00:59 阅读更多 →
周日晚间的“精神松绑减震器”:无压力情绪倾倒箱与温和轻声陪伴

周日晚间的“精神松绑减震器”:无压力情绪倾倒箱与温和轻声陪伴

每到周日的晚上八点到十点,很多人心里都会悄悄亮起一盏警示灯。 在心理学上,这种现象有一个专门的称谓——“周日夜晚焦虑症(Sunday Scaries)”。明天又是周一,闹钟又要重新在七点响彻卧房;脑海里仿佛有一个…

2026/10/12 0:00:59 阅读更多 →

周新闻

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

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

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

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

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

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

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

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

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

2026/10/12 0:16:43 阅读更多 →

月新闻

我发现了一个新思路:用 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/11 10:45:37 阅读更多 →
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/11 14:36:53 阅读更多 →
黑夜航拍船只数据集训练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/11 14:36:54 阅读更多 →