三次迭代踩坑实录:表达式解析从0到完整实现
一、写在前面:这三周我到底做了个啥
这三周的面向对象作业,我一步步把一个只能算加减乘幂的简单表达式解析器,迭代成了能支持x/y双变量、指数函数、自定义函数、递推函数、求导/梯度的完整表达式引擎。
从最开始只会拆括号,到最后能处理 dx、dy、grad、f{n-1}(x) 这种复杂语法,整个过程一边踩坑一边重构,也算真正体会到了面向对象迭代开发的感觉。
二、三次迭代:需求一点点堆上来,我也一点点往上补
第一次作业:最基础的表达式展开
第一次要求很单纯:输入带+、-、*、^、小括号的单变量表达式,把所有括号展开、合并同类项,输出最简形式。
当时我主要做了这几件事:
- 搭了最基础的递归下降 Parser,能把字符串拆成语法树
- 写了 Expr 表达式类和 Monomial 单项式类,用来存项、做运算
- 实现括号展开、幂运算、同类项合并
- 第一次真正理解:表达式要先解析,再运算,最后输出
难度不算大,但第一次写递归下降,还是卡了挺久。
第二次作业:加了指数、选择因子、自定义函数
第二次在第一次的基础上突然加了不少东西:
- exp() 指数函数
- 三目选择式因子
[(a==b)?x:y] - 自定义普通函数调用 f(x)
我当时的做法是:
- 给 Node 接口加了 ExpNode、SelectionNode、FunctionCallNode 这些新节点
- 扩展 Expr,让它能识别和存储指数项
- 加了 FunctionRegistry 来存函数定义
- 尽量不推翻第一次的结构,在原有框架上扩展
这次最大的感受:第一次的架构好不好,直接决定第二次改起来痛不痛苦。
第三次作业:双变量 + 求导 + 递推函数,直接拉满难度
第三次是最终版,也是最难的一次:
- 新增变量 y,变成双变量表达式
- 支持 dx( )、dy( ) 求导、grad( ) 梯度
- 支持递推函数 f{0}, f{1}, f{n-1}, f{n-2}
我主要做了这些调整:
- 重构 Monomial,同时存 x 次数、y 次数、指数参数
- 写 DerivativeNode 处理求导语法,在 Monomial 里实现求导逻辑
- 加 EvalContext 上下文,用来传函数、变量、递推下标
- 给递推函数加缓存,避免重复计算爆炸
这次重构最多,但也最有成就感——整个结构终于稳定下来了。
三、我的代码结构:高内聚、低耦合,我是这么理解的
我这套代码整体分成三层:Parser 解析层、Node 语法树层、Expr 表达式运算层。
内聚性:每个类只干一件事
- Monomial:只管单项式本身——存 x、y、指数项,做乘法、求导、格式化,不掺和解析和整体运算,非常专一。
- Expr:只管表达式整体运算——加减乘幂、合并同类项、求导、输出,不关心字符串怎么解析。
- Parser:只管把字符串变成语法树,完全不参与计算。
- 各种 Node:比如求导节点、指数节点、函数调用节点,每种只处理一种语法,职责很清晰。
简单说:一个类只负责一块功能,不会乱七八糟堆代码。
耦合度:依赖关系很干净,不乱串
- 整体是单向依赖:Parser → Node → Expr → Monomial,没有循环依赖。
- 都面向接口编程,Node 只暴露 expand 一个方法,互相之间不直接调用细节。
- 用 EvalContext 把运行时信息包起来,函数、表达式、上下文之间不硬耦合。
所以后面迭代加功能时,基本不用大改老代码,加新类、新节点就行,扩展性还不错。
四、Codex 帮我干活:真实体验比传统 AI 好用太多
这次作业我大概有 20% 左右的代码是用 Codex 生成的,剩下都是自己写逻辑、调结构,但 Codex 全程都在帮我提速。
它主要帮我干了这些事:
- 快速生成重复代码:比如各种 Node 的模板、getter、构造方法
- Debug 神器:报一个错,把代码贴过去,它能直接指出空指针、边界条件错在哪
- 帮我造 hack 数据点、测试用例,覆盖各种边界情况
- CheckStyle 一键修正:格式不对直接帮我改好,省了大量时间
真实感受:Codex 这种代码智能体,比豆包这种好用多了,它能跟着你一起写、一起调、一起测。
同样的工作量,以前要写半天,现在有它辅助快很多,尤其是机械性工作直接解放双手。
五、对这门课第一单元的一点小建议
从一个初体验复杂项目构建的学生的角度,我对我们的课程有两个小建议:
第一次作业最好给一个参考代码框架
第一次接触递归下降、表达式结构,很多人完全不知道从哪下手。如果能给一个基础的类结构、Parser 骨架、Expr 的核心方法,大家能少走非常多弯路,也能更早进入正确的面向对象设计思路。
提前说清楚三次迭代的兼容方向
三次需求是一步步加的,如果第一次就能大概知道后面要加变量、求导、递推,我们在设计架构时会更有远见,少一些后期推翻重构的痛苦。
六、做完这三次作业,我真正学到了什么
- 终于搞懂递归下降解析器到底怎么写,不再害怕表达式解析。
- 深刻理解什么叫高内聚、低耦合,不是背概念,是真的在代码里用到。
- 学会用面向对象的思路做迭代开发,而不是一把梭写完。
- 体验了 AI 辅助开发的完整流程:生成→Debug→测试→规范,效率提升非常明显。
这三周虽然经常debug到深夜,但确实是我收获最大、成长最扎实的一次作业。从一个只会写简单逻辑的人,到能独立完成一整个解析引擎,进步肉眼可见