增强版计算器(支持括号和多重运算)

#include <stdio.h>
#include <stdlib.h>
#include <ctype.h>
#include <math.h>
#include <string.h>

#define MAX_INPUT 200

// 全局变量用于跟踪解析位置
char input[MAX_INPUT];
int pos = 0;

// 错误处理函数
void error(const char *msg) {
    printf("\n错误:%s\n", msg);
    exit(1);
}

// 跳过空白字符
void skip_whitespace() {
    while (input[pos] == ' ') pos++;
}

// 获取当前字符
char peek() {
    return input[pos];
}

// 获取下一个字符
char get_char() {
    return input[pos++];
}

// 解析数字(整数和小数)
double parse_number() {
    double result = 0.0;
    double fraction = 1.0;
    int sign = 1;
    
    skip_whitespace();
    
    // 处理正负号
    if (peek() == '-') {
        sign = -1;
        get_char();
    }
    
    // 整数部分
    while (isdigit(peek())) {
        result = result * 10 + (get_char() - '0');
    }
    
    // 小数部分
    if (peek() == '.') {
        get_char();
        while (isdigit(peek())) {
            fraction *= 0.1;
            result += (get_char() - '0') * fraction;
        }
    }
    
    return sign * result;
}

// 解析表达式(加减)
double parse_expression();

// 解析因子(数字或括号表达式)
double parse_factor() {
    skip_whitespace();
    
    if (peek() == '(') {
        get_char(); // 跳过 '('
        double result = parse_expression();
        if (peek() != ')') error("括号不匹配");
        get_char(); // 跳过 ')'
        return result;
    }
    
    if (peek() == '-') {
        return -parse_factor(); // 处理负号
    }
    
    return parse_number();
}

// 解析幂运算(右结合)
double parse_power() {
    double left = parse_factor();
    
    while (1) {
        skip_whitespace();
        if (peek() == '^') {
            get_char();
            double right = parse_power(); // 右结合
            left = pow(left, right);
        } else {
            break;
        }
    }
    return left;
}

// 解析项(乘除)
double parse_term() {
    double left = parse_power();
    
    while (1) {
        skip_whitespace();
        char op = peek();
        if (op == '*' || op == '/') {
            get_char();
            double right = parse_power();
            if (op == '*') {
                left *= right;
            } else {
                if (right == 0.0) error("除数不能为零");
                left /= right;
            }
        } else {
            break;
        }
    }
    return left;
}

// 解析表达式(加减)
double parse_expression() {
    double left = parse_term();
    
    while (1) {
        skip_whitespace();
        char op = peek();
        if (op == '+' || op == '-') {
            get_char();
            double right = parse_term();
            if (op == '+') {
                left += right;
            } else {
                left -= right;
            }
        } else {
            break;
        }
    }
    return left;
}

int main() {
    printf("增强版计算器(支持括号和多重运算)\n");
    printf("支持运算符: + - * / ^ ()\n");
    printf("输入表达式(例如:2*(3+4^2))或输入q退出\n");
    
    while (1) {
        printf("\n> ");
        fgets(input, MAX_INPUT, stdin);
        
        // 移除换行符
        input[strcspn(input, "\n")] = 0;
        
        if (strcmp(input, "q") == 0) break;
        
        // 重置解析位置
        pos = 0;
        
        // 执行计算
        double result = parse_expression();
        
        // 检查是否完全解析
        skip_whitespace();
        if (peek() != '\0') {
            error("无效输入");
        }
        
        printf("结果: %.4lf\n", result);
    }
    
    printf("\n感谢使用计算器!\n");
    return 0;
}

这段程序实现了一个增强版的计算器,支持基本的数学运算符(加法、减法、乘法、除法、幂运算)以及括号运算。程序采用递归下降解析法(recursive descent parsing)来解析并计算表达式。下面是对程序各个部分的解释:

1. 头文件和全局变量

#include <stdio.h>
#include <stdlib.h>
#include <ctype.h>
#include <math.h>
#include <string.h>

#define MAX_INPUT 200

char input[MAX_INPUT];
int pos = 0;

 

  • stdio.h:用于输入输出操作。
  • stdlib.h:用于动态内存分配、程序退出等功能。
  • ctype.h:用于字符分类和操作,例如 isdigit 用来判断字符是否是数字。
  • math.h:包含数学函数(如 pow)用于计算幂运算。
  • string.h:用于字符串操作,例如 strcmp 比较两个字符串。

全局变量:

  • input:存储用户输入的表达式。
  • pos:记录当前解析位置。

2. 错误处理

void error(const char *msg) {
    printf("\n错误:%s\n", msg);
    exit(1);
}

error 函数用来处理错误信息,打印错误并退出程序。

3. 跳过空白字符

void skip_whitespace() {
    while (input[pos] == ' ') pos++;
}

skip_whitespace 函数用于跳过输入中的空格字符。在解析过程中,遇到空格会自动跳过。

4. 获取当前字符和下一个字符

char peek() {
    return input[pos];
}

char get_char() {
    return input[pos++];
}
  • peek 返回当前字符,但不移动解析位置。
  • get_char 返回当前字符,并将解析位置向后推进一位。

5. 解析数字

double parse_number() {
    double result = 0.0;
    double fraction = 1.0;
    int sign = 1;
    
    skip_whitespace();
    
    if (peek() == '-') {
        sign = -1;
        get_char();
    }
    
    while (isdigit(peek())) {
        result = result * 10 + (get_char() - '0');
    }
    
    if (peek() == '.') {
        get_char();
        while (isdigit(peek())) {
            fraction *= 0.1;
            result += (get_char() - '0') * fraction;
        }
    }
    
    return sign * result;
}

parse_number 函数用于解析数字(整数或浮点数):

  • 先跳过空白字符。
  • 处理负号(如果有的话)。
  • 解析整数部分。
  • 如果遇到小数点,继续解析小数部分。
  • 返回解析结果。

6. 解析因子(数字或括号表达式)

double parse_factor() {
    skip_whitespace();
    
    if (peek() == '(') {
        get_char();
        double result = parse_expression();
        if (peek() != ')') error("括号不匹配");
        get_char();
        return result;
    }
    
    if (peek() == '-') {
        return -parse_factor();
    }
    
    return parse_number();
}

parse_factor 解析一个因子,它可以是一个数字或一个括号内的表达式:

  • 如果遇到左括号 (,递归解析括号中的表达式。
  • 如果遇到负号 -,递归解析负数。
  • 否则,解析数字。

7. 解析幂运算(右结合)

double parse_power() {
    double left = parse_factor();
    
    while (1) {
        skip_whitespace();
        if (peek() == '^') {
            get_char();
            double right = parse_power();
            left = pow(left, right);
        } else {
            break;
        }
    }
    return left;
}

parse_power 解析幂运算(^):

  • 先解析因子。
  • 如果当前是 ^,则进行幂运算,右结合(即 a^b^c 等价于 a^(b^c))。
  • 使用 pow 函数进行幂运算。

8. 解析项(乘除)

double parse_term() {
    double left = parse_power();
    
    while (1) {
        skip_whitespace();
        char op = peek();
        if (op == '*' || op == '/') {
            get_char();
            double right = parse_power();
            if (op == '*') {
                left *= right;
            } else {
                if (right == 0.0) error("除数不能为零");
                left /= right;
            }
        } else {
            break;
        }
    }
    return left;
}

parse_term 解析乘法和除法:

  • 先解析幂运算。
  • 如果遇到乘号 * 或除号 /,继续解析右边的因子并进行相应运算。
  • 如果除数为零,输出错误信息。

9. 解析加减

double parse_expression() {
    double left = parse_term();
    
    while (1) {
        skip_whitespace();
        char op = peek();
        if (op == '+' || op == '-') {
            get_char();
            double right = parse_term();
            if (op == '+') {
                left += right;
            } else {
                left -= right;
            }
        } else {
            break;
        }
    }
    return left;
}

parse_expression 解析加法和减法:

  • 先解析项(乘除)。
  • 如果遇到加号 + 或减号 -,继续解析右边的项并进行加法或减法运算。

10. 主函数

int main() {
    printf("增强版计算器(支持括号和多重运算)\n");
    printf("支持运算符: + - * / ^ ()\n");
    printf("输入表达式(例如:2*(3+4^2))或输入q退出\n");
    
    while (1) {
        printf("\n> ");
        fgets(input, MAX_INPUT, stdin);
        
        input[strcspn(input, "\n")] = 0;
        
        if (strcmp(input, "q") == 0) break;
        
        pos = 0;
        
        double result = parse_expression();
        
        skip_whitespace();
        if (peek() != '\0') {
            error("无效输入");
        }
        
        printf("结果: %.4lf\n", result);
    }
    
    printf("\n感谢使用计算器!\n");
    return 0;
}
  • 主函数循环提示用户输入表达式,调用 parse_expression 解析并计算结果。
  • 如果输入是 q,退出程序。
  • 每次计算后输出结果。

总结

程序使用递归下降解析法解析数学表达式,支持加减、乘除、幂运算、括号运算,能够处理负数、浮点数,并且具有简单的错误处理机制。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值