C++实现算数表达式计算工具,支持加减乘除和自定义算符,自定义函数


/*
	Project:	算数表达式计算
	计算原理:以最内层括号为一个单元,在该括号内只有各种运算符或者函数,按照优先级计算即可
	若当前运算符的优先级小于等于前一个运算符的优先级,可以计算
	Date:		2021/06/20
	Author:		BinSong
*/

#include <stdio.h>
#include <math.h>
#include <vector>
#include <stack>
#include <string>

typedef unsigned int BOOL;
#define FALSE	0
#define TRUE	1

using namespace std;

typedef vector<double> NUMSET;

struct Operator;

//运算符处理函数,输入为一个集合,输出也为一个集合(可能会用到)
typedef BOOL(*pProcessFunc)(NUMSET&in, NUMSET&out, Operator*OperatorInfo);
//===================================================
struct Operator
{
	BOOL			IsFunc;					//是否为函数
	const char		OperatorName[16];		//运算符名称
	unsigned char	Priority;				//优先级,函数的优先级可以随意设置
	int				ReqiureArgc;			//所需参数个数,-1为可变参数
	pProcessFunc 	pProcessFunc;			//处理函数
};

//===================================================


//加法运算定义
BOOL Add(NUMSET&in, NUMSET&out, Operator*OperatorInfo)
{
	if (OperatorInfo->ReqiureArgc != -1 && in.size() != OperatorInfo->ReqiureArgc)
	{
		printf("Error:%s 's argc is invalid!\n", OperatorInfo->OperatorName);
		return FALSE;
	}
	out.push_back(in[1] + in[0]);
	return TRUE;
}

//减法运算定义
BOOL Sub(NUMSET&in, NUMSET&out, Operator*OperatorInfo)
{
	if (OperatorInfo->ReqiureArgc != -1 && in.size() != OperatorInfo->ReqiureArgc)
	{
		printf("Error:%s 's argc is invalid!\n", OperatorInfo->OperatorName);
		return FALSE;
	}
	out.push_back(in[1] - in[0]);
	return TRUE;
}

//乘法运算定义
BOOL Mul(NUMSET&in, NUMSET&out, Operator*OperatorInfo)
{
	if (OperatorInfo->ReqiureArgc != -1 && in.size() != OperatorInfo->ReqiureArgc)
	{
		printf("Error:%s 's argc is invalid!\n", OperatorInfo->OperatorName);
		return FALSE;
	}
	out.push_back(in[1] * in[0]);
	return TRUE;
}

//除法运算定义
BOOL Div(NUMSET&in, NUMSET&out, Operator*OperatorInfo)
{
	if (OperatorInfo->ReqiureArgc != -1 && in.size() != OperatorInfo->ReqiureArgc)
	{
		printf("Error:%s 's argc is invalid!\n", OperatorInfo->OperatorName);
		return FALSE;
	}
	if (in[0] == 0)							
	{
		printf("Error:The divisor is zero.\n");
		return FALSE;
	}
	out.push_back(in[1] / in[0]);
	return TRUE;
}

//pow运算定义
BOOL Pow(NUMSET&in, NUMSET&out, Operator*OperatorInfo)
{
	if (OperatorInfo->ReqiureArgc != -1 && in.size() != OperatorInfo->ReqiureArgc)
	{
		printf("Error:%s 's argc is invalid!\n", OperatorInfo->OperatorName);
		return FALSE;
	}
	if (in[0] == 0 && in[1] == 0)
	{
		printf("Error:Pow(0,0) is invalid!\n");
		return FALSE;
	}
	
	out.push_back(pow(in[0],in[1]));
	return TRUE;
}

//abs运算定义
BOOL Abs(NUMSET&in, NUMSET&out, Operator*OperatorInfo)
{
	if (OperatorInfo->ReqiureArgc != -1 && in.size() != OperatorInfo->ReqiureArgc)
	{
		printf("Error:%s 's argc is invalid!\n", OperatorInfo->OperatorName);
		return FALSE;
	}
	out.push_back(abs(in[0]));
	return TRUE;
}

//max运算定义
BOOL Max(NUMSET&in, NUMSET&out, Operator*OperatorInfo)
{
	if (OperatorInfo->ReqiureArgc!=-1&&in.size() != OperatorInfo->ReqiureArgc)
	{
		printf("Error:%s 's argc is invalid!\n", OperatorInfo->OperatorName);
		return FALSE;
	}
	double maxvalue = 0;

	for (auto it = in.begin(); it != in.end(); it++)
	{
		if (it == in.begin())
		{
			maxvalue = *it;
		}
		else
		{
			if (*it>maxvalue)
				maxvalue = *it;
		}
	}
	out.push_back(maxvalue);
	return TRUE;
}

//Min运算定义
BOOL Min(NUMSET&in, NUMSET&out, Operator*OperatorInfo)
{
	if (OperatorInfo->ReqiureArgc != -1 && in.size() != OperatorInfo->ReqiureArgc)
	{
		printf("Error:%s 's argc is invalid!\n", OperatorInfo->OperatorName);
		return FALSE;
	}
	double minvalue = 0;

	for (auto it = in.begin(); it != in.end(); it++)
	{
		if (it == in.begin())
		{
			minvalue = *it;
		}
		else
		{
			if (*it<minvalue)
				minvalue = *it;
		}
	}
	out.push_back(minvalue);
	return TRUE;
}

Operator operators[] =
{
	{ 0, "+", 0, 2, Add },
	{ 0, "-", 0, 2, Sub },
	{ 0, "*", 1, 2, Mul },
	{ 0, "/", 1, 2, Div },
	{ 1, "pow", 0, 2, Pow },
	{ 1, "abs", 0, 1, Abs },
	{ 1, "max", 0, -1, Max },			//max参数数量不确定
	{ 1, "min", 0, -1, Min },			//min参数数量不确定

	{ 0, "NULL", 0, 0, 0 }
};

Operator* GetOperatorInfo(const char*Name,BOOL IsFunc)	//获取运算符信息
{
	for (int i = 0; strcmp(operators[i].OperatorName, "NULL"); i++)
	{
		if (!strcmp(operators[i].OperatorName, Name) && operators[i].IsFunc == IsFunc)
			return &operators[i];
	}
	return NULL;
}




//从字符串起始处读取一个数字
BOOL ReadNum(const char*pExpression,double&num,int&NumStrLen)
{
	const char*pSign = pExpression;
	BOOL HasSign = FALSE;
	NumStrLen = 0;
	//从第一个字符判断不是数字
	if ((*pExpression < '0' || *pExpression > '9') && (*pExpression != '-') && (*pExpression != '+'))
		return FALSE;

	if ((*pExpression == '-') || (*pExpression == '+'))
	{
		HasSign = TRUE;
		++NumStrLen;
		++pSign;
	}
	int PointCount = 0;
	while ((*pSign >= '0' && *pSign <= '9') || (*pSign=='.'))
	{
		if (*pSign == '.')
			++PointCount;
		if (PointCount > 1)
			return FALSE;
		++pSign;
		++NumStrLen;
	}

	sscanf(pExpression, "%lf", &num);

	return NumStrLen - HasSign;
}

//读取函数名
BOOL ReadFunc(const char*pExpression, Operator* &pOperator,int&FuncNameLen)
{
	const char*pSign = pExpression;
	while (*pSign != '0')
	{
		if (*pSign == '(')
		{
			FuncNameLen = pSign - pExpression;
			char*temp = (char*)malloc(FuncNameLen + 1);
			temp[FuncNameLen] = 0;

			memcpy(temp, pExpression, FuncNameLen);

			pOperator = GetOperatorInfo(temp,TRUE);
			
			free(temp);
			return (BOOL)pOperator;
		}
		pSign++;
	}
	return FALSE;
}



//读取运算符名称
BOOL ReadOperator(const char*pExpression, Operator* &pOperator, int&OperatorNameLen)
{
	const char*pSign = pExpression;
	for (int i = 0; strcmp(operators[i].OperatorName, "NULL"); i++)
	{
		if (!memcmp(operators[i].OperatorName, pSign, strlen(operators[i].OperatorName)) && operators[i].IsFunc == FALSE)
		{
			pOperator = &operators[i];
			OperatorNameLen = strlen(operators[i].OperatorName);
			return TRUE;
		}
	}
	return FALSE;
}

//计算只剩下四则运算的括号内表达式的值,计算顺序为从右往左(原因看开头的计算原理),只要计算栈顶部的两个数即可
BOOL Calculate(stack<double>&Nums, stack<string>&Operators)
{
	NUMSET in,out;

	in.push_back(Nums.top());
	Nums.pop();

	in.push_back(Nums.top());
	Nums.pop();


	Operator*pOperator = GetOperatorInfo(Operators.top().c_str(), 0);
	Operators.pop();

	if (!pOperator)
		return FALSE;
	
	pOperator->pProcessFunc(in, out, pOperator);

	Nums.push(out.back());
	return TRUE;
}
//(数字/函数/括号,这三者等价,都可以看作是一个值)和 运算符轮流读取
const char*CalculateExpression(const char*pExpression,BOOL IsFunc,NUMSET&ret)
{

	stack<double>Nums;					//数字栈
	stack<string>Operators;				//运算符栈

	const char*pSign = pExpression + 1;	//pExpession指向的是'('

	
	int NumStrLen, FuncNameLen,OperatorNameLen;
	double TempNum;
	Operator* pOperator;
	
	int n = 1;
	while (TRUE)
	{
		if (*pSign == ')' || *pSign == ',')			//栈中的数字按照从右向左的顺序计算即可
		{
			NUMSET _ret;
			//出栈运算
			while (Operators.size())
			{
				Calculate(Nums, Operators);
			}	
			ret.push_back(Nums.top());				//保存括号中每一部分的结果

			if (*pSign == ')')						//括号结束,返回
				return pSign + 1;
			if (*pSign == ',')						//部分结束,继续下一部分
			{
				++pSign;
				n = 1;
			}
		}
		else
		{
			if (n & 1)								//括号内读取的第一个一定是数字(数字前面可以有+,-)
			{
				//函数,括号和数字,最终都是一个数
				//读数字或者函数或括号
				if (ReadNum(pSign, TempNum, NumStrLen))
				{
					pSign += NumStrLen;
					Nums.push(TempNum);
				}
				else if (ReadFunc(pSign, pOperator, FuncNameLen))
				{
					
					NUMSET func_arg_ret, _ret;
					pSign += FuncNameLen;

					//计算每一个参数
					if (FALSE == (pSign = CalculateExpression(pSign, TRUE, func_arg_ret)))
					{
						printf("Error:function %s 's argvs exist fault!\n", pOperator->OperatorName);
						return NULL;
					}
					
					pOperator->pProcessFunc(func_arg_ret, _ret, pOperator);
					//数字入栈
					Nums.push(_ret.front());			//_ret.front()为函数计算的结果

				}
				else if (*pSign == '(')
				{
					NUMSET _ret;
					pSign = CalculateExpression(pSign, FALSE, _ret);
					if (pSign == FALSE)
					{
						return NULL;
					}
					//数字入栈
					Nums.push(_ret.front());
				}
				else
				{
					printf("Error:Invalid expression!\n");
					return NULL;
				}
			}
			else
			{
				if (ReadOperator(pSign, pOperator, OperatorNameLen))
				{
					while ((Operators.size() > 0) &&
						(GetOperatorInfo(Operators.top().c_str(), FALSE)->Priority >= pOperator->Priority))
					{
						//如果当前的运算符优先级小于等于上一个,那么上一个就可以计算
						Calculate(Nums, Operators);
					}
					Operators.push(pOperator->OperatorName);
					pSign += OperatorNameLen;
				}
				else
				{
					printf("Error:Invalid expression!\n");
					return NULL;
				}
			}
			n++;
		}
	}
}

int main()
{
	printf("Please input expression:");
	NUMSET ret;
	char Expression[256] = { '(' };
	gets(Expression+1);

	strcat(Expression, ")");

	if (CalculateExpression(Expression, FALSE, ret))
	{
		printf("result:%lf\n", ret.front());
	}
	return 0;
}

演示 :
在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Suspend.

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值