calc19 --- 注释、表达式分隔符、long double 精度
1. 概述
本次迭代新增三项功能,并对全局数值类型进行了精度升级:
- 注释支持 ---
#开头到行尾的内容被忽略 - 表达式分隔符 ---
;分隔多个表达式,返回最后一个的值 - long double 精度 --- 全局
double→long double,提升运算精度
2. 变更清单
| 文件 | 操作 | 说明 |
|---|---|---|
parse.h |
编辑 | 新增 TOKEN_SEMICOLON;Token.value 类型 double → long double |
parse.c |
重写 | # 注释跳过;; 解析为 TOKEN_SEMICOLON;strtold/strtoul 替换 strtod |
eval.h |
编辑 | API 参数 double* → long double*;新增 eval_exprs 声明 |
eval.c |
重写 | 全部 double → long double;fmod → fmodl;新增 eval_exprs 实现 |
sym.h |
编辑 | API 参数 double → long double |
sym.c |
编辑 | SymEntry.value double → long double;%Lg |
func.h |
编辑 | API 参数 double* → long double* |
func.c |
重写 | args/val double → long double;sinl/cosl 等 l 后缀数学函数 |
main.c |
重写 | double → long double;%Lg;调用 eval_exprs 替代 eval_expr |
test.expr |
编辑 | 修复溢出测试值;新增 # 注释测试;修复 0b1010/0777 解析 |
3. 注释支持
在 parse_next 中,当遇到 # 时跳过直到行尾或字符串结束:
c
if (*input_pos == '#') {
while (*input_pos && *input_pos != '\n') { column++; input_pos++; }
if (*input_pos == '\n') { line++; column = 1; input_pos++; }
return parse_next(); /* 递归获取下一个 token */
}
示例:
calc> 3 + 5 # 这是注释
8
4. 表达式分隔符
4.1 新增 eval_exprs API
c
int eval_exprs(const char *input, long double *result);
循环解析多个以 ; 分隔的表达式,返回最后一个的值:
c
int eval_exprs(const char *input, long double *result)
{
parse_init(input); eval_error = 0;
long double val = 0.0;
while (!eval_error) {
val = parse_expr();
if (eval_error) return 1;
Token t = parse_peek();
if (t.type == TOKEN_SEMICOLON) {
parse_consume();
continue;
}
if (t.type != TOKEN_END) {
print_error_context(t.col);
fprintf(stderr, " error: unexpected token after expression\n");
return 1;
}
break;
}
*result = val; return 0;
}
4.2 使用
bash
$ ./build/calc "1; 2; 3"
3
4.3 默认切换
parse_and_eval 和 repl 均改为调用 eval_exprs,因此 ; 分隔符在所有模式下均可使用。
5. long double 精度升级
5.1 涉及范围
| 组件 | 类型变更 | 影响 |
|---|---|---|
| Token 数值 | double → long double |
解析和存储 |
| 求值器 | double → long double |
全部运算 |
| 符号表 | double → long double |
变量值 |
| 函数表 | double → long double |
参数和返回值 |
| 主程序 | double → long double |
输出格式 %Lg |
5.2 数学函数后缀
所有 <math.h> 函数调用改为 l 后缀版本:
| 函数 | 原版 | long double 版 |
|---|---|---|
| 正弦 | sin |
sinl |
| 余弦 | cos |
cosl |
| 正切 | tan |
tanl |
| 平方根 | sqrt |
sqrtl |
| 幂运算 | pow |
powl |
| 取模 | fmod |
fmodl |
| 绝对值 | fabs |
fabsl |
5.3 精度提升
| 类型 | 尾数位数 | 十进制精度 | 最大值 |
|---|---|---|---|
double |
53 bits | ~15 位 | ~1.79e308 |
long double |
64 bits | ~19 位 | ~1.19e4932 |
6. 测试验证
bash
$ make test
============================================
calc --- 测试套件
============================================
PASS [ 1] (90-18)/3+15 → 39
...
PASS [30] 1e5000*1e5000 → error
...
PASS [61] 0b1010 → 10
PASS [62] 0777 → 511
...
PASS [122] 3+5 # comment → 8
============================================
122 passed, 0 failed, 122 total
============================================