#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
,退出程序。 - 每次计算后输出结果。
总结
程序使用递归下降解析法解析数学表达式,支持加减、乘除、幂运算、括号运算,能够处理负数、浮点数,并且具有简单的错误处理机制。