You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在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
  • 在main函数中专门捕获division_by_zero异常,处理除零场景

这样当解析类似3/0的表达式时,就会触发异常并被捕获,你可以根据需求在catch块中添加错误处理逻辑。

内容的提问来源于stack exchange,提问作者code2learn

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.10 22:05:22