【中缀表达式求值】(异常处理 | Stack | 支持单目运算 | 支持位运算)

 保证程序健壮性和可读性以及执行效率,在任何输入下都能得到合适处理,现代cpp编写

支持二元操作

& and

| or

^ xor

+ plus

- minis

* multiply

/ divide

% module

一元运算

- opposite 相反数

~ not 按位取反

可以报出的异常包括:

括号不匹配

出现无效字符

操作数和运算符的相对位置有误

除零错误

等等

测试样例

完整代码

#include <string>
#include <string_view>
#include <sstream>
#include <iostream>
#include <stack>
#include <cctype>
#include <concepts>
#include <functional>
#include <unordered_map>
#include <ranges>
#include <optional>
#include <cstdlib>
#include <iomanip>

constexpr std::string_view PAREN { "()[]{}<>" };
constexpr std::string_view BINARY  { "&|^+-*/%" };

std::unordered_map<char, std::function<long(long, long)>> f {
	{'&', std::bit_and<long>()},
	{'|', std::bit_or<long>()},
	{'^', std::bit_xor<long>()},
    {'+', std::plus<long>()},
    {'-', std::minus<long>()},
    {'*', std::multiplies<long>()},
    {'/', std::function<long(long, long)>([](long v1, long v2){
		if(!v2){
			std::cerr << "divides by 0\n";
			std::exit(0);
		}
		return std::divides<long>()(v1, v2);
    })},
    {'%', std::modulus<long>()},
};

template <typename Tp>
Tp get(std::stack<Tp>& Stk, std::istringstream& Vs) try{
	if(Stk.empty()) throw Vs.tellg();
	Tp t = Stk.top(); Stk.pop();
	return t;
}catch(std::istringstream::pos_type indicator){
	std::cerr << "stack top-get failed at position indicator:\t"
			  << indicator - 2 << '\n';
	std::exit(0);

}

bool alpha_validate(std::string_view expr){
	for(auto alpha : expr)
		if(!(alpha == ' ')
		&& !std::isdigit(alpha)
		&& BINARY.find(alpha) == std::string_view::npos
		&& PAREN.find(alpha) == std::string_view::npos ){
			std::cerr << "invalid alpha:\t" << alpha << '\n';
			return false;
		}
	return true;
}
bool parenthesis_validate(std::string_view expr){
	std::stack<std::string_view::size_type> parenStk;
	for(auto index : expr
		| std::views::filter([](char alpha)
		{ return !(PAREN.find(alpha) == std::string_view::npos); })
		| std::views::transform([](char alpha)
		{ return PAREN.find(alpha); } )
	){
		if(!(index & 1U)){
			parenStk.push(index);
			continue;
		}
		if(!(index == parenStk.top() + 1)){
			std::cerr << "incompatible parenthesis:"
					  << PAREN[parenStk.top()]
					  << "  &  "
					  << PAREN[index]
					  <<"\n";
			return false;
		}
		parenStk.pop();
	}
	return parenStk.empty();
}

inline long extract(std::istringstream& Vs) try{
	long opd {}; char alpha {};
	if(!(Vs && std::isdigit(Vs.peek()))) throw Vs.tellg();
	do{
		Vs.get(alpha);
		opd = opd * 10 + (alpha - '0');
	}while(Vs && std::isdigit(Vs.peek()));
	return opd;
}catch(std::istringstream::pos_type indicator){
	std::cerr << "extract failed at position indicator:\t"
			    << indicator - 2<< '\n';
	std::exit(0);
}

long calculate(std::istringstream& Vs){
	std::stack<long> opdStk;
	std::stack<char> oprStk;
	char alpha {};
	while(Vs >> alpha){
		if(alpha == ' ') continue;
		if(std::isdigit(alpha) && Vs.unget()){
			opdStk.push(extract(Vs));
			continue;
		}
		auto oindex { BINARY.find(alpha) };
		auto pindex { PAREN.find(alpha) };
		if(!(oindex == std::string_view::npos)){
			if(alpha == '-' && opdStk.empty()){
				Vs.get(alpha);
				if(alpha == '>'){
					std::cerr << "unary operator '-' meets no operand\n";
					std::exit(0); 
				}
				opdStk.push(std::negate<long>()(
					std::isdigit(alpha) && Vs.unget() ?
						extract(Vs) :
						calculate(Vs) ) );
			}
			else{
				while(!oprStk.empty() && oindex < BINARY.find(oprStk.top()))
					opdStk.push(f[get(oprStk, Vs)]
						  (get(opdStk, Vs), get(opdStk, Vs)));
				oprStk.push(alpha);
			}
			continue;
		}
		if(!(pindex & 1U)){
			opdStk.push(calculate(Vs));
			continue;
		}
		while(!oprStk.empty())
			opdStk.push(f[get(oprStk, Vs)]
				  (get(opdStk, Vs), get(opdStk, Vs)));
		return opdStk.top();
	}
	return opdStk.top();
}

[[discard]] std::optional<long>
calculate(std::string_view expr) noexcept{
	if(!alpha_validate(expr)
	|| !parenthesis_validate(expr))
		return std::nullopt;
	std::string __expr__(expr);
	__expr__ = '<' + __expr__ + '>';
	std::istringstream Vs(__expr__);
	return calculate(Vs);
}

void test(std::string_view expr, bool binary = false){
	auto result { calculate(expr) };
	if(result){
		std::cout << expr << " = ";
		if(binary) std::cout << "0x" << std::setfill('0') << std::setw(5) << std::hex;
		std::cout << *result
				  << "\n";
	}
	endl(std::cout);
}
int main(void){
/*
	std::string expr;
	std::getline(std::cin, expr);
*/
    test("{1+2*3-4/2}");
    test("[-3+8*(4-2)/4]+{-5%3}");
    test("{-(4+3)*6+8-2}/[2+(-5)]");
    test("{4+2[3-2*5}");
    test("(5^3 + 98|56^(43-2))", true);
    test("{(3-8)*(2+[4-2]/3+1}");
    test("1/0");
	return 0;
}

  • 33
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

XNB's Not a Beginner

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

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

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

打赏作者

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

抵扣说明:

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

余额充值