C++带语法检查的数学算式计算器
立即下载
资源介绍:
适合初学C++的同学看一看,具体可参见博客https://blog.csdn.net/qq_42593411/article/details/136180857?spm=1001.2014.3001.5502
#include"BaseOperatorPro.h"
#include"brackCheck.h"
//去除字符串末端多余的空格符和制表符并对括号合法性进行判断
bool Readformulaline(std::string& line)
{
if (!line.empty())
{
//去除末尾多余的空格或制表符
int _index = line.size() - 1;
while (_index >= 0 && (line[_index] == ' ' || line[_index] == '\t'))
--_index;
line.erase(line.begin() + (_index + 1), line.end());
//对括号合法性进行判断
return brace_brack_paren_legitmate(line);
}
else
return false;
return true;
}
//根据s返回相应的计算方式标记
int mathfunc(std::string s)
{
if (s.compare("sin") == 0)
return SIN;
else if (s.compare("cos") == 0)
return COS;
else if (s.compare("exp") == 0)
return EXP;
else if (s.compare("tan") == 0)
return TAN;
else if (s.compare("pow") == 0)
return POW;
else if (s.compare("sqrt") == 0)
return SQRT;
else if (s.compare("arcsin") == 0)
return ARCSIN;
else if (s.compare("arccos") == 0)
return ARCCOS;
else if (s.compare("arctan") == 0)
return ARCTAN;
else if (s.compare("ln") == 0)
return LN;
else if (s.compare("lg") == 0)
return LG;
else if (s.compare("abs") == 0)
return ABS;
else
return NOTFUNC;
}
/** @brief 对运算符容器进行位置检查,如果出现位置相邻的运算符则报错
@param loperators: 解析计算式获得的std::vector&.
@note 只对双元运算符进行位置限制
*/
bool check_Oper_position(std::vector& loperators)
{
//如果运算符容器中出现连续位置的运算符,返回错误
for (int i = 1; i < loperators.size(); ++i)
{
if (loperators[i].PriorityLevel != 3 && loperators[i - 1].PriorityLevel != 3) //只对双元运算符进行位置限制
{
if (loperators[i].pos_InString - loperators[i - 1].pos_InString <= 1)
return false;
}
}
return true;
}
/** @brief 传入将计算式解析后的数值容器和运算符容器,根据运算规则计算出结果,如果正确则返回true,错误返回false
@param lvalues: 解析计算式获得的std::vector&.
@param loperators: 解析计算式获得的std::vector&.
@param result: inputOutput the calculate result.
@note 主要的报错类型有两种: 1.如果运算符找不到相应的计算数值,计算失败返回错误. 2.运算符遍历完毕,数值容器中只能
有一个未处理数据,如果多余或者少于则计算失败返回错误
*/
bool calculateBaseline(std::vector& lvalues, std::vector& loperators, double& result)
{
//先对传入容器的位置情况进行检查
if (check_Oper_position(loperators) == false)
{
std::cerr << "error: two operators found adjacent in position!" << std::endl;
result = ERROR;
return false;
}
//根据运算符优先级对loperators进行排序
std::sort(loperators.begin(), loperators.end(), cmp_operatorPriority);
for (auto operIt = loperators.begin(); operIt != loperators.end(); ++operIt)
{
//priority level = 3 代表只需要向上寻找一个操作数即可
if ((*operIt).PriorityLevel == 3)
{
//从当前操作符开始向上找第一个为处理的数字
int operPos = (*operIt).pos_InString;
auto Upper_valuePos_it = std::find_if(lvalues.begin(), lvalues.end(),
[operPos](const ValueMap& vp) { return (vp.pos_InString > operPos && vp.IsProcess == false); });
//错误检查:如果未找到或者,数字位置和运算符位置差大于1,则报错
if (Upper_valuePos_it == lvalues.end() || (*Upper_valuePos_it).pos_InString - (*operIt).pos_InString > 1)
{
std::cerr << "error: not exist number to cooperate with current operator: " <<
(*operIt).getStringFuncName() << std::endl;
result = ERROR;
return false;
}
//没有发生错误进行数值运算
double temp = (*Upper_valuePos_it).value;
(*Upper_valuePos_it).value = (*operIt).singleCalculate(temp);
}
else
{
//priority level = 4,2,1 代表只需要向上向下寻找两个操作数
//从当前操作数位置向上向下找未处理的数字
int operPos = (*operIt).pos_InString;
auto Upper_valuePos_it = std::find_if(lvalues.begin(), lvalues.end(),
[operPos](const ValueMap& vp) { return (vp.pos_InString > operPos && vp.IsProcess == false); });
//找到了上未处理数字,从上未处理寻找下未处理数字
auto lower_valuePos_it = Upper_valuePos_it;
//错误检查,并开启向下寻找数字的通道: 如果二元运算符却只有一个数字报错
if (Upper_valuePos_it == lvalues.end() || Upper_valuePos_it == lvalues.begin())
{
std::cerr << "error: not exist number to cooperate with current operator: " <<
(*operIt).getStringFuncName() << std::endl;
result = ERROR;
return false;
}
else
{
int i = lower_valuePos_it - lvalues.begin(); //为了防止迭代器越界,利用一个变量定义循环范围
while (i > 0)
{
--lower_valuePos_it;
if ((*lower_valuePos_it).IsProcess == false) //向下找到了未处理数
break;
--i;
}
//当i == 0时代表向下未找到
if (i == 0)
{
std::cerr << "error: not exist number to cooperate with current operator: " <<
(*operIt).getStringFuncName() << std::endl;
result = ERROR;
return false;
}
}
//已经找到了运算符左右未处理数
double temp = (*Upper_valuePos_it).value;
(*lower_valuePos_it).IsProcess = true; //将左边的数字置为已处理
(*Upper_valuePos_it).value = (*operIt).dualCalculate((*lower_valuePos_it).value, temp);
}
}
//遍历整个数组,如果存在2个以上未处理元素则报错,则当_Not_Process_Count = 1时,程序正确
int _Not_Process_Count = 0;
for (auto vit = lvalues.begin(); vit != lvalues.end(); ++vit)
{
if ((*vit).IsProcess == false)
{
_Not_Process_Count++;
if (_Not_Process_Count < 2)
result = (*vit).value;
}
}
if (_Not_Process_Count > 1)
{
std::cerr << "error: the valueContainer include too many value!" << std::endl;
result = ERROR;
return false;
}
else if (_Not_Process_Count == 0)
{
std::cerr << "error: not include enough operators!" << std::endl;
result = ERROR;
return false;
}
return true;
}
int getop(const std::string& Subline, int& index, char s[], int& pos)
{
int c, i;
if (index >= Subline.size()) //字符串已经遍历完毕 return EOF
return EOF;
// remove black space
while ((s[0] = c = Subline[index++]) == ' ' || c == '\t')
;
s[1] = '\0';
i = 0;
if (islower(c)) //command or NAME
{
while (islower(s[++i] = c = Subline[index++]))
;
pos++;
index--;
s[i] = '\0';
if (strlen(s) > 1)
return NAME;
else
return c; //unknown name
}
if (!isdigit(c) && c != '.' && c != '-') //判断排除空格后获取的第一个字符是否是运算符
{
pos++;
return c;
}
if (c == '-') //处理负数情况
{
if (isdigit(c = Subline[index++]) || c == '.')
s[++i] = c;
else
{
index--;
pos++;
return '-';
}
}
if (isdigit(c))
while (isdigit(s[++i] = c = Subline[index++]))
;
if (c == '.')
while (isdigit(s[++i] = c = Subline[index++]))
;
s[i] = '\0';
pos++;
index--; //必须自减一次,因为超前赋值了
return NUMBER;
}
bool SubStringProcess(std::string& Subline, double& result)
{
//如果子串(括号中内容)是空的,则返回错误
if (Readformulaline(Subline) == false || Subline.empty())
{
std::cerr << "error: the subline is empty!" << std::endl;
result = ERROR;
return false;
}
//定义一行数据中的数值、操作符容器 !!!!!
std::vector lineOperators;
std::vector lineValues;
//初始化
int type;
char s[MAXOP];
int pos = 0;
int index = 0;
//计算过程是否出错标志位
bool isgood = true;
while ((type = getop(Subline, index, s, pos)) != EOF)
{
if (type == '{' || type == '[' || type == '(')
{
if (type == '{')
{
int index1 = Subline.find('}', (size_t)index); //从subline中index处开始查找第一次出现的下标
std::string Subsubstring = Subline.substr(index, (index1 - index)); //index自动指向括号下一个字符
index = index1 + 1; //将index更新指向反括号下一个位置
double value = 0.0;
if (SubStringProcess(Subsubstring, value) == true)
lineValues