如何在Boost::Spirit中处理算术表达式的浮点异常(如除零)?
解决Boost.Spirit整数算术表达式除零异常捕获问题
整数除法遇到除零属于C++未定义行为,默认不会抛出异常,所以你原代码中的try-catch块无法捕获这类错误。而使用double类型时,除零是标准定义的行为(返回inf),因此不会触发异常。要实现整数除零的异常捕获,需要在解析过程中手动检查除数并抛出异常。
修改思路
在除法运算的语义动作中,添加除数检查逻辑:当除数为0时抛出自定义异常,之后在调用phrase_parse的地方捕获该异常即可。借助Boost.Phoenix可以方便地将检查逻辑嵌入到Spirit的规则中。
修改后的完整代码
#include <iostream> #include <sstream> #include <stdexcept> #include <boost/config/warning_disable.hpp> #include <boost/spirit/include/qi.hpp> #include <boost/spirit/include/phoenix.hpp> namespace math_calculator { namespace qi = boost::spirit::qi; namespace ascii = boost::spirit::ascii; namespace phoenix = boost::phoenix; // 自定义除零异常 struct division_by_zero : std::runtime_error { division_by_zero() : std::runtime_error("division by zero") {} }; /////////////////////////////////////////////////////////////////////////// // Our calculator grammar /////////////////////////////////////////////////////////////////////////// template <typename Iterator> struct calculator : qi::grammar<Iterator, int(), ascii::space_type> { calculator() : calculator::base_type(expression) { using qi::_val; using qi::_1; using qi::uint_; using phoenix::throw_; expression = term [_val = _1] >> *( ('+' >> term [_val += _1]) | ('-' >> term [_val -= _1]) ) ; term = factor [_val = _1] >> *( ('*' >> factor [_val *= _1]) | ('/' >> factor [_val = phoenix::if_(_1 == 0)[throw_(division_by_zero())].else_(_val / _1)]) ) ; factor = uint_ [_val = _1] | '(' >> expression [_val = _1] >> ')' | ('-' >> factor [_val = -_1]) | ('+' >> factor [_val = _1]) ; } qi::rule<Iterator, int(), ascii::space_type> expression, term, factor; }; } typedef math_calculator::calculator<std::string::const_iterator> calculator; int main() { std::cout << "start" << std::endl; calculator calc; std::string expression = "3/0"; int result = 0; std::string::const_iterator iter = expression.begin(); std::string::const_iterator end = expression.end(); std::stringstream resultstream; try{ bool r = boost::spirit::qi::phrase_parse(iter, end, calc, boost::spirit::ascii::space, result); if (! (r && iter == end)) { result = 0; } } catch(const math_calculator::division_by_zero& e) { std::cout << "Caught exception: " << e.what() << std::endl; result = 0; // 异常时设置默认值 } catch(...) { std::cout << "Caught an unknown exception." << std::endl; result = 0; } resultstream.clear(); resultstream << result; std::cout << "end: " << resultstream.str() << std::endl; }
关键修改点
- 定义了自定义异常
division_by_zero,用于明确标识除零错误 - 在除法的语义动作中,使用
phoenix::if_检查除数_1是否为0:- 如果为0,调用
phoenix::throw_抛出自定义异常 - 否则执行正常的整数除法
_val / _1
- 如果为0,调用
- 在
main函数中专门捕获division_by_zero异常,处理除零场景
这样当解析类似3/0的表达式时,就会触发异常并被捕获,你可以根据需求在catch块中添加错误处理逻辑。
内容的提问来源于stack exchange,提问作者code2learn
相关产品推荐
相关产品推荐

