calc4 — 交互式 REPL 模式1. 概述本次迭代在 calc3 求值器基础上增加交互式 REPL 模式Read-Eval-Print Loop提供实时运算体验并显示运算步骤。运行模式对比模式启动方式输出用途批处理./calc 表达式仅结果数字脚本调用、自动化测试交互式./calc无参数运算步骤 结果手动输入探索交互示例$ ./build/calc calc (90-18)/315 90 - 18 72 72 / 3 24 24 15 39 result: 39 calc 35*2 5 * 2 10 3 10 13 result: 13 calc exit2. 变更清单文件操作说明eval.h编辑新增eval_set_print_steps(int enable)声明eval.c编辑新增print_steps标志parse_expr和parse_term中每步运算插入步骤打印新增eval_set_print_steps实现main.c编辑新增repl()函数main()按参数有无分流批处理/交互模式其余文件无需改动parse.h/parse.c/Makefile/test.expr不变3. 交互模式设计3.1 main.c — REPL 循环staticintrepl(void){charbuf[MAX_INPUT];eval_set_print_steps(1);while(1){printf(calc );fflush(stdout);if(!fgets(buf,sizeof(buf),stdin))break;/* 去掉末尾换行符 */size_tlenstrlen(buf);if(len0buf[len-1]\n)buf[len-1]\0;if(strcmp(buf,exit)0)break;if(*buf\0)continue;intresult;if(eval_expr(buf,result)!0)continue;printf( result: %d\n,result);}return0;}核心逻辑打印calc提示符fflush确保立即显示fgets读取一行用户输入去掉末尾换行符判断exit→ 退出循环判断空行 → 跳过调用eval_expr求值 → 输出结果循环往复直到 EOF 或exit3.2 main() 分流intmain(intargc,char*argv[]){if(argc1){/* 批处理模式从命令行参数读取 */returnparse_and_eval(argv[1]);}/* 交互模式 */returnrepl();}有参数 → 批处理eval_set_print_steps(0)不输出步骤无参数 → 交互式 REPLeval_set_print_steps(1)输出步骤4. 运算步骤打印4.1 eval_set_print_steps APIvoideval_set_print_steps(intenable);在eval.c中通过print_steps静态变量控制eval_expr每次调用时会重置eval_error但保留print_steps标志。4.2 步骤打印位置在parse_expr和parse_term的每个二元运算完成后插入打印// parse_expr 中 —— 处理 -intresultleftright;if(print_steps)printf( %d %d %d\n,left,right,result);leftresult;// parse_term 中 —— 处理 * / %intresultleft*right;if(print_steps)printf( %d * %d %d\n,left,right,result);leftresult;4.3 优先级自动体现利用递归下降的天然求值顺序——内层语法层先求值外层后求值——步骤打印顺序自动反映运算符优先级输入步骤输出顺序说明35*25 * 2 10→3 10 13*行先于行(90-18)/31590 - 18 72→72 / 3 24→24 15 39括号内先求值无需额外排序逻辑打印顺序等于求值顺序。5. 目录结构更新后calc/ ├── Makefile # 构建脚本 ├── parse.h # tokenizer 头文件 ├── parse.c # tokenizer 实现 ├── eval.h # 求值器头文件含 eval_set_print_steps ├── eval.c # 递归下降求值器实现含步骤打印 ├── main.c # 入口程序批处理 REPL 双模式 ├── test.expr # 测试用例文件 ├── doc/ │ ├── calc1.md # 第一次构建tokenizer 基础 │ ├── calc2.md # 第二次构建取模、负号区分、测试套件 │ ├── calc3.md # 第三次构建表达式求值器 │ └── calc4.md # 本次构建交互式 REPL └── build/ └── calc6. 测试验证6.1 回归测试批处理模式不受影响make test9/9 全部 PASS$maketestcalc — 测试套件PASS[1](90-18)/315 →39PASS[2]10%3 →1PASS[3]-53 →-2PASS[4]3-5 →-2PASS[5](-3)→-3PASS[6](-820)%-3 →0PASS[7]35→8PASS[8]35 → error PASS[9]empty→ error9passed,0failed,9total6.2 交互模式验证$ ./build/calc calc (90-18)/315 90 - 18 72 72 / 3 24 24 15 39 result: 39 calc 35*2 5 * 2 10 3 10 13 result: 13 calc 10%3 10 % 3 1 result: 1 calc --5 result: 5 calc exit6.3 管道输入验证$echo(90-18)/315|./build/calc calc90-187272/324241539result:397. 设计要点双模式共存main()通过argc简单分流两种模式互不干扰步骤打印嵌入求值过程在递归下降的每个二元运算点插入printf无需额外遍历打印顺序自动反映优先级内层term先于外层expr求值*/%的步骤行自然出现在-之前静默求值不受影响eval_set_print_steps(0)时print_steps为假不产生任何额外输出批处理和测试路径完全透明