表达式中可以有四则运算符、括号、整数/实数值、已经赋值的符号名和预定义的符号常量( pi 和 e ),也可以只有单个的整数/实数值。 发现输入内容与文法不符或将导致非法计算时,则从标准输出设备输出出错提示,并计算出错次数。写出此c++程序并给出注释
时间: 2024-02-29 13:52:27 浏览: 63
以下是一个实现上述功能的C++程序,其中使用了map来存储符号名和符号常量:
```cpp
#include <iostream>
#include <string>
#include <stack>
#include <map>
#include <cmath>
using namespace std;
// 定义常量 pi 和 e
const double PI = 3.141592653589793;
const double E = 2.718281828459045;
// 获取符号的优先级
int priority(char op) {
if (op == '+' || op == '-') return 1;
if (op == '*' || op == '/') return 2;
return 0;
}
// 计算两个数的结果
double calculate(double a, double b, char op) {
if (op == '+') return a + b;
if (op == '-') return a - b;
if (op == '*') return a * b;
if (op == '/') return a / b;
return 0;
}
// 判断一个字符串是否为数字
bool is_number(const string& s) {
for (int i = 0; i < s.length(); i++) {
if (!isdigit(s[i]) && s[i] != '.') return false;
}
return true;
}
// 处理符号名或符号常量
double process_symbol(const string& symbol, const map<string, double>& symbols) {
if (symbols.find(symbol) != symbols.end()) {
return symbols.at(symbol);
}
if (symbol == "pi") {
return PI;
}
if (symbol == "e") {
return E;
}
return 0;
}
// 计算表达式的值
double evaluate(const string& expression, map<string, double>& symbols) {
stack<double> operands;
stack<char> operators;
for (int i = 0; i < expression.length(); i++) {
if (isdigit(expression[i]) || expression[i] == '.') {
// 处理数字
double operand = 0;
while (i < expression.length() && (isdigit(expression[i]) || expression[i] == '.')) {
operand = operand * 10 + (expression[i] - '0');
i++;
}
i--;
operands.push(operand);
}
else if (isalpha(expression[i])) {
// 处理符号名
string symbol;
while (i < expression.length() && (isalnum(expression[i]) || expression[i] == '_')) {
symbol += expression[i];
i++;
}
i--;
double value = process_symbol(symbol, symbols);
if (value == 0) {
cout << "Error: undefined symbol \"" << symbol << "\"" << endl;
return -1;
}
operands.push(value);
}
else if (expression[i] == '(') {
// 处理左括号
operators.push(expression[i]);
}
else if (expression[i] == ')') {
// 处理右括号
while (operators.top() != '(') {
double b = operands.top();
operands.pop();
double a = operands.top();
operands.pop();
char op = operators.top();
operators.pop();
operands.push(calculate(a, b, op));
}
operators.pop(); // 弹出左括号
}
else if (expression[i] == '+' || expression[i] == '-' || expression[i] == '*' || expression[i] == '/') {
// 处理运算符
while (!operators.empty() && priority(operators.top()) >= priority(expression[i])) {
double b = operands.top();
operands.pop();
double a = operands.top();
operands.pop();
char op = operators.top();
operators.pop();
operands.push(calculate(a, b, op));
}
operators.push(expression[i]);
}
else {
// 非法字符
cout << "Error: invalid character '" << expression[i] << "'" << endl;
return -1;
}
}
while (!operators.empty()) {
// 处理剩余的运算符
double b = operands.top();
operands.pop();
double a = operands.top();
operands.pop();
char op = operators.top();
operators.pop();
operands.push(calculate(a, b, op));
}
return operands.top();
}
int main() {
map<string, double> symbols;
int error_count = 0;
while (true) {
string input;
getline(cin, input);
if (input == "quit") {
break;
}
double result = evaluate(input, symbols);
if (result == -1) {
error_count++;
}
else {
cout << result << endl;
}
}
cout << "Number of errors: " << error_count << endl;
return 0;
}
```
在这个实现中,我们使用了map来存储符号名和符号常量的值。在计算表达式时,我们首先扫描表达式并处理以下情况:
1. 如果当前字符是数字或小数点,则将其作为操作数压入操作数栈中。
2. 如果当前字符是字母,则将其作为符号名处理,并在符号表中查找其对应的值。如果找到了对应的值,则将其作为操作数压入操作数栈中;否则输出错误信息。
3. 如果当前字符是左括号,则将其压入操作符栈中。
4. 如果当前字符是右括号,则从操作符栈中弹出操作符和操作数栈中的两个操作数,计算它们的值,并将结果压入操作数栈中,直到遇到左括号。
5. 如果当前字符是操作符,则从操作符栈中弹出操作符和操作数栈中的两个操作数,计算它们的值,并将结果压入操作数栈中,直到操作符栈为空或者栈顶操作符的优先级小于当前操作符的优先级。然后将当前操作符压入操作符栈中。
6. 如果当前字符是其他非法字符,则输出错误信息。
最后,当我们处理完整个表达式后,我们从操作符栈中弹出操作符和操作数栈中的两个操作数,计算它们的值,并将结果压入操作数栈中,直到操作数栈中只剩下一个元素为止。这个元素就是表达式的值。
阅读全文