AI开发C语言应用按步走,表达式计算器calc的第四步,交互式 REPL 模式

calc4 --- 交互式 REPL 模式

1. 概述

本次迭代在 calc3 求值器基础上增加交互式 REPL 模式(Read-Eval-Print Loop),提供实时运算体验,并显示运算步骤。

运行模式对比

模式 启动方式 输出 用途
批处理 ./calc "表达式" 仅结果数字 脚本调用、自动化测试
交互式 ./calc(无参数) 运算步骤 + 结果 手动输入探索

交互示例

复制代码
$ ./build/calc
calc> (90-18)/3+15
  90 - 18 = 72
  72 / 3 = 24
  24 + 15 = 39
  result: 39
calc> 3+5*2
  5 * 2 = 10
  3 + 10 = 13
  result: 13
calc> exit

2. 变更清单

文件 操作 说明
eval.h 编辑 新增 eval_set_print_steps(int enable) 声明
eval.c 编辑 新增 print_steps 标志;parse_exprparse_term 中每步运算插入步骤打印;新增 eval_set_print_steps 实现
main.c 编辑 新增 repl() 函数;main() 按参数有无分流批处理/交互模式
其余文件 无需改动 parse.h/parse.c/Makefile/test.expr 不变

3. 交互模式设计

3.1 main.c --- REPL 循环

c 复制代码
static int repl(void)
{
    char buf[MAX_INPUT];
    eval_set_print_steps(1);

    while (1) {
        printf("calc> ");
        fflush(stdout);

        if (!fgets(buf, sizeof(buf), stdin))
            break;

        /* 去掉末尾换行符 */
        size_t len = strlen(buf);
        if (len > 0 && buf[len - 1] == '\n')
            buf[len - 1] = '\0';

        if (strcmp(buf, "exit") == 0)
            break;
        if (*buf == '\0')
            continue;

        int result;
        if (eval_expr(buf, &result) != 0)
            continue;

        printf("  result: %d\n", result);
    }
    return 0;
}

核心逻辑

  1. 打印 calc> 提示符(fflush 确保立即显示)
  2. fgets 读取一行用户输入
  3. 去掉末尾换行符
  4. 判断 exit → 退出循环
  5. 判断空行 → 跳过
  6. 调用 eval_expr 求值 → 输出结果
  7. 循环往复,直到 EOF 或 exit

3.2 main() 分流

c 复制代码
int main(int argc, char *argv[])
{
    if (argc > 1) {
        /* 批处理模式:从命令行参数读取 */
        return parse_and_eval(argv[1]);
    }
    /* 交互模式 */
    return repl();
}
  • 有参数 → 批处理(eval_set_print_steps(0),不输出步骤)
  • 无参数 → 交互式 REPL(eval_set_print_steps(1),输出步骤)

4. 运算步骤打印

4.1 eval_set_print_steps API

c 复制代码
void eval_set_print_steps(int enable);

eval.c 中通过 print_steps 静态变量控制,eval_expr 每次调用时会重置 eval_error保留 print_steps 标志。

4.2 步骤打印位置

parse_exprparse_term 的每个二元运算完成后插入打印:

c 复制代码
// parse_expr 中 ------ 处理 + -
int result = left + right;
if (print_steps)
    printf("  %d + %d = %d\n", left, right, result);
left = result;

// parse_term 中 ------ 处理 * / %
int result = left * right;
if (print_steps)
    printf("  %d * %d = %d\n", left, right, result);
left = result;

4.3 优先级自动体现

利用递归下降的天然求值顺序------内层语法层先求值,外层后求值------步骤打印顺序自动反映运算符优先级:

输入 步骤输出顺序 说明
3+5*2 5 * 2 = 103 + 10 = 13 * 行先于 +
(90-18)/3+15 90 - 18 = 7272 / 3 = 2424 + 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/
    └── calc

6. 测试验证

6.1 回归测试

批处理模式不受影响,make test 9/9 全部 PASS:

bash 复制代码
$ make test
============================================
  calc --- 测试套件
============================================
  PASS  [ 1] (90-18)/3+15           → 39
  PASS  [ 2] 10%3                   → 1
  PASS  [ 3] -5+3                   → -2
  PASS  [ 4] 3+-5                   → -2
  PASS  [ 5] (-3)                   → -3
  PASS  [ 6] (-8+20)%-3             → 0
  PASS  [ 7] 3 + 5                  → 8
  PASS  [ 8] 3+@5                   → error
  PASS  [ 9] <empty>                → error
============================================
  9 passed, 0 failed, 9 total
============================================

6.2 交互模式验证

复制代码
$ ./build/calc
calc> (90-18)/3+15
  90 - 18 = 72
  72 / 3 = 24
  24 + 15 = 39
  result: 39
calc> 3+5*2
  5 * 2 = 10
  3 + 10 = 13
  result: 13
calc> 10%3
  10 % 3 = 1
  result: 1
calc> --5
  result: 5
calc> exit

6.3 管道输入验证

bash 复制代码
$ echo "(90-18)/3+15" | ./build/calc
calc>   90 - 18 = 72
  72 / 3 = 24
  24 + 15 = 39
  result: 39

7. 设计要点

  1. 双模式共存main() 通过 argc 简单分流,两种模式互不干扰
  2. 步骤打印嵌入求值过程 :在递归下降的每个二元运算点插入 printf,无需额外遍历
  3. 打印顺序自动反映优先级 :内层 term 先于外层 expr 求值,* / % 的步骤行自然出现在 + - 之前
  4. 静默求值不受影响eval_set_print_steps(0)print_steps 为假,不产生任何额外输出,批处理和测试路径完全透明
相关推荐
吃好睡好便好7 分钟前
MATLAB仿真框图2
开发语言·matlab·仿真·simulink
小当家.1051 小时前
MCP 协议深度解析:AI 领域的 USB-C 接口
开发语言·人工智能·agent·tool·mcp
accept 99%1 小时前
python版提取 PDF 的常用第三方库与工具
开发语言·python·pdf
lzhdim1 小时前
C# 通过 Windows API 实现进程内存读写操作
开发语言·windows·c#
-银雾鸢尾-1 小时前
C#中的预处理指令
开发语言·c#
Livia要学习2 小时前
Python面向对象三大特性:封装、继承、多态
开发语言·python
dalong102 小时前
Savitzky-Golay 的C# 实现
开发语言·kotlin·c#
十月的皮皮2 小时前
STM32从零到量产开发:四路继电器工业控制模块开发 -上位机 Program.cs 应用程序入口设计说明
c语言·stm32·单片机·stm32cubemx·hal库
坚持编程的菜鸟2 小时前
模拟实现memcpy
c语言·算法·模拟实现my_memcpy
show4332 小时前
多格式导出怎么做?2026免费小程序TXT/SRT实践
开发语言·小程序·c#