AI开发C语言应用按步走,表达式计算器calc的第十四步,内置数学函数调用 calc14 — 内置数学函数调用1. 概述本次迭代新增了内置数学函数调用功能允许在表达式中直接调用math.h中的标准数学函数如sin(65),sqrt(16),pow(2,10)等。新增模块func.h/func.c— 函数注册表模块2. 变更清单文件操作说明func.h新建函数表 APIfunc_call(name, argc, args, result)func.c新建16 个数学函数注册使用 union 存储函数指针parse.h编辑新增TOKEN_COMMA枚举parse.c编辑新增,字符解析和TOKEN_COMMA支持修复 union 覆盖 bug删除冗余tok.data.value 0eval.c编辑parse_factor中 IDENTIFIER 分支增加函数调用检测#include func.hMakefile编辑SRC/HDR/OBJ加入func.c/func.h/func.oeval.o依赖增加func.htest.expr编辑新增 10 个函数调用测试用例总数 48→583. 函数表模块3.1 func.hintfunc_call(constchar*name,intargc,constdouble*args,double*val);name函数名argc参数个数1 或 2args参数数组val输出计算结果返回值0 成功1 未找到该函数3.2 func.c — 函数注册表使用函数指针联合体避免-pedantic警告typedefdouble(*func1_t)(double);typedefdouble(*func2_t)(double,double);typedefstruct{constchar*name;intargc;union{func1_tf1;func2_tf2;}func;}FuncEntry;staticFuncEntry func_table[]{{sin,1,{.f1sin}},{cos,1,{.f1cos}},{tan,1,{.f1tan}},{asin,1,{.f1asin}},{acos,1,{.f1acos}},{atan,1,{.f1atan}},{atan2,2,{.f2atan2}},{sqrt,1,{.f1sqrt}},{pow,2,{.f2pow}},{exp,1,{.f1exp}},{log,1,{.f1log}},{log10,1,{.f1log10}},{floor,1,{.f1floor}},{ceil,1,{.f1ceil}},{abs,1,{.f1fabs}},{fabs,1,{.f1fabs}},};共16 个函数其中 14 个单参数2 个双参数pow,atan2。4. 求值器扩展4.1 函数调用检测逻辑在parse_factor的TOKEN_IDENTIFIER分支中通过parse_peek()检查下一个 token 是否为(来区分函数调用和变量引用if(t.typeTOKEN_IDENTIFIER){parse_consume();Token nextparse_peek();if(next.typeTOKEN_LPAREN){parse_consume();/* 消费 ( */doubleargs[2];intargc0;args[0]parse_expr();/* 第一个参数 */argc1;if(parse_peek().typeTOKEN_COMMA){parse_consume();args[1]parse_expr();/* 第二个参数 */argc2;}if(!expect(TOKEN_RPAREN))return0.0;doubleresult;if(func_call(t.data.name,argc,args,result)!0){fprintf(stderr, error: unknown function %s\n,t.data.name);set_error();return0.0;}if(print_steps){if(argc1)printf( %s(%g) %g\n,t.data.name,args[0],result);elseprintf( %s(%g, %g) %g\n,t.data.name,args[0],args[1],result);}returnresult;}/* 变量引用原有逻辑 */...}4.2 修复的 union 覆盖 bug在parse.c的标识符识别代码中原有的tok.data.value 0语句会覆盖tok.data.name的前 8 个字节因为data是联合体导致变量名和函数名变为空字符串。修复方式删除这三行冗余赋值因为tok.data.value已在函数开头初始化为 0。5. 测试验证$maketestcalc — 测试套件PASS[1](90-18)/315 →39... PASS[49]sin(0)→0PASS[50]cos(0)→1PASS[51]sqrt(16)→4PASS[52]pow(2,10)→1024PASS[53]abs(-5)→5PASS[54]floor(3.7)→3PASS[55]ceil(3.2)→4PASS[56]sqrt(4)1 →3PASS[57]sin(3.14159/2)→1PASS[58]unknown()→ error58passed,0failed,58total手动验证$ ./build/calcsin(3.14159/2)1$ ./build/calcpow(2,10)1024$ ./build/calcsqrt(16)15