计算器(表达式)

//weizengke 2011-7-8
/*
计算器(表达式)
栈操作;
运算符栈顶的优先级较高
可以处理确保正确的表达式的求值,可以使浮点型的小数运算

  输入一下各种表达式:
    8*.2
 	-2
	5.6*(-2*(1+(-3)))
	2*((4+2)*5)-7/11
	((((2+3)*2+4.0*2)*4)+2)*4
	1+2+3
	2*(6+((2+3)*2+2)/2+3)
	2*(2+(3+(4+2*(5+6))))
*/
#include <stack>
#include<iostream>
#include <cmath>
#include <ctype.h> 
#include <cstdlib>
using namespace std;
const int NUM_MAX = 10;
const int MAX = 1000;
stack<char> sOper;
stack<double> sNum;
char expr[1000]="\0";
bool isNum(char c)
{
	if(c=='.'||isdigit(c)) return 1;
	else return 0;
}
bool isCalaOper(char c)
{
	if(c=='+'||c=='-'||c=='*'||c=='/') return true;
	else return false;
}
bool isOper(char c)
{
	if(c=='+'||c=='-'||c=='*'||c=='/'||c=='('||c==')'||c=='=') return true;
	else return false;
}
double calc(double a, char oper, double b)
{
	switch (oper)
	{
	case '+': return a+b;
		break;
	case '-': return a-b;
		break;
	case '*': return a*b;
		break;
	case '/': return a/b;
		break;
	}
}
int YXJ(char op)
{

	if(op=='=') return -1;

	if(sOper.empty()) return 0;

	char preOper=sOper.top();

	if(preOper=='(') return 2; 

	if(op=='*'||op=='/')  {
		if(preOper=='+'||preOper=='-') return 1;
		else return -1;
	}
	if(op=='+'||op=='-')  {
		if(preOper=='*'||preOper=='/') return -1;
		else return -1;
	}
	
}

void getValue(int preI,int n) //应该限制n的长度。
{
	char cnum[NUM_MAX];
	memset(cnum,'\0',sizeof(cnum));
	double num;
	strncpy(cnum,&expr[preI],n);   	//	cout<<preI<<"--"<<i<<"=";
	num=atof(cnum);
	sNum.push(num);
}

double caculate()
{
	double res;
	char op=sOper.top();
	if(op!=')'&&op!='(')
	{
		sOper.pop();
		double a,b;
		b=sNum.top();
		sNum.pop();
		a=sNum.top();
		sNum.pop();
	//	cout<<"calc:"<<a<<op<<b<<"=";
		res = calc(a,op,b);
	//	cout<<res<<endl;
		sNum.push(res);
	}
	return res;
}
int init()
{
	int i=0,j;
	int len=strlen(expr);
	while(expr[i]!='\0')
	{
		if(!(isNum(expr[i])||isOper(expr[i])||expr[i]==' ')) return 0;

		if(expr[i]==' ')
		{
			for (j=i;j<len;j++)
			{
				expr[j]=expr[j+1];
			}
			expr[j]='\0';
			len--;
		}
		i++;
	}
	expr[i]='=';
	expr[i+1]='\0';
	return 1;
}
int Check(char *str)   //检查括号匹配性
{
	stack <char> s;
	int i=0;
	while (str[i]!='\0')
	{
		if(str[i]=='(') s.push(str[i]);
		if(str[i]==')'){
			if(s.empty()) return 0;
			else s.pop();
		}
		i++;
	}
	if(s.empty()) return 1;
	else return 0;
}
int main()
{

   freopen("in.txt","r",stdin);
   while(gets(expr))
   {
	 if(strcmp(expr,"0")==0) break;

	 if(!Check(expr)){
		 cout<<expr<<" is Not Format (括号不匹配)..."<<endl;
		 continue;
	 }
	 if(!init()) {//初始化去掉空格并加上=号......可增加检查语法错误方法
		 cout<<expr<<" is Not Format (存在非法字符)..."<<endl;
		 continue;
	 } 

	int i=0;
	int preI=0;
 	for (i=0;expr[i]!='\0';i++)
 	{
	
		if(isNum(expr[i])){
			preI=i;
			while(isNum(expr[i])) {
				i++;
			}
			getValue(preI,i-preI);
		}
		
		if(isOper(expr[i])) {
			if(expr[i]=='(') {//是'(',不必处理
				sOper.push(expr[i]);
				continue;
			}
		if(expr[i]==')') { //处理最近一对括号
			while(sOper.top()!='(')  //持续计算到弹出左括号
			{
				caculate();
			}
			sOper.pop();//弹出左括号
			continue;
		}
		if(isCalaOper(expr[i-1])) {
			//cout<<expr<<" Is Not Format..."<<endl;
			break;
				//表达是错误
		}
      //暂时无法处理 *2+1之类的非-+得变号问题
		if(/*(expr[i]=='-'||expr[i]=='+')&&*/(expr[i-1]=='('||i==0)) 
			sNum.push(0);  //处理变号  2*(-5+6) to 2*(0-5+6)
		else {
				//cout<<expr<<" Is Not Format..."<<endl;
				//break;
				//表达是错误
			}

			//循环判断是否需要持续进行计算,并执行相应动作
		while(!sOper.empty()){
			int Yxj=YXJ(expr[i]);
			if(Yxj==-1)	caculate();
			if(Yxj==0)	caculate();
			if(Yxj==1)	break;
			if(Yxj==2)	break;
		}
			//本次运算符入栈
			sOper.push(expr[i]);
			continue;
		}
		//表达是错误(出现其他字符)
 	}

	//处理最后一步(此时必然只剩下最后一次运算)
	sOper.pop();//剔除等号
	if(!sOper.empty()){
		caculate();
	}
	double ans=sNum.top();
	sNum.pop();

	if(!sNum.empty()||!sOper.empty()) cout<<expr<<" Is Not Format (运算符使用错误)..."<<endl;
 	else cout<<expr<<ans<<endl;

	while(!sNum.empty()) sNum.pop();
	while(!sOper.empty()) sOper.pop();

   }
	return 0;
}


 

调试计算器表达式中的错误通常涉及多个方面,包括语法分析、语义检查以及运行时行为的跟踪。以下是一些关键步骤和方法,可以帮助识别并修复表达式中的问题: ### 语法检查 在表达式计算器中,首先需要确保输入的表达式符合定义的文法规则。例如,一个典型的表达式可能由数字、运算符和括号组成,并遵循特定的结构[^1]。可以通过构建解析器来验证输入是否符合预期格式。 ```python def parse_expression(expr): try: # 尝试解析表达式 result = eval(expr) return result except SyntaxError as e: print(f"Syntax error in expression: {e}") ``` ### 单元测试 编写针对同情况的单元测试可以有效地发现潜在的问题。这些测试应该覆盖各种合法和非法的输入组合。 ```python import unittest class TestExpressionCalculator(unittest.TestCase): def test_valid_expressions(self): self.assertEqual(parse_expression("2 + 3"), 5) self.assertEqual(parse_expression("(2 + 3) * 4"), 20) def test_invalid_expressions(self): with self.assertRaises(SyntaxError): parse_expression("2 ++ 3") if __name__ == '__main__': unittest.main() ``` ### 日志记录 在解析和执行过程中添加详细的日志记录可以帮助定位具体出错的位置。这可以通过标准库如 `logging` 来实现。 ```python import logging logging.basicConfig(level=logging.DEBUG) def evaluate_expression(expr): logging.debug(f"Evaluating expression: {expr}") try: result = eval(expr) logging.debug(f"Result: {result}") return result except Exception as e: logging.error(f"Evaluation failed: {e}") raise ``` ### 调试工具 使用集成开发环境(IDE)提供的调试功能,比如断点设置、变量监视等,能够逐步执行代码并观察中间状态。对于Visual Studio 2015遇到的特定问题,如内部错误或无法编辑的情况,可以尝试更新相关组件或重新安装软件以解决dll版本匹配等问题[^2]。 ### 异常处理 良好的异常处理机制仅能捕获错误,还能提供有用的错误信息给用户或开发者。 ```python def safe_evaluate(expr): try: return eval(expr) except NameError as ne: print(f"Undefined variable used: {ne}") except ZeroDivisionError: print("Cannot divide by zero.") except Exception as ex: print(f"An unexpected error occurred: {ex}") ``` 通过以上方法结合实际应用场景进行调整和完善,可以有效提升对计算器表达式错误的诊断能力。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值