Boost自定义解析器无法与qi :: parse一起使用

时间:2019-01-11 17:03:22

标签: boost-spirit

我只是在Spirit Code Base中改编了一个示例解析器,并测试了它的工作原理。代码如下,

#include <boost/spirit/include/classic_core.hpp>
#include <boost/spirit/include/classic_assign_actor.hpp>
#include <boost/spirit/home/classic/core/parser.hpp>
//#include <boost/spirit/include/qi.hpp>  //UNCOMMENT THIS!
#include <iostream>
#include <string>
#include <cstdint>

///////////////////////////////////////////////////////////////////////////////
using namespace std;
using namespace BOOST_SPIRIT_CLASSIC_NS;

//namespace qi = boost::spirit::qi; //UNCOMMENT THIS!


template <typename T, int DecimalPlaces=4>
struct fixed_point_parser : boost::spirit::classic::parser<fixed_point_parser<T>>
{
    static constexpr int pow10[10] = {
        1, 10, 100, 1000, 10000,
        100000, 1000000, 10000000, 100000000, 1000000000
    };

    typedef fixed_point_parser<T> self_t;

    template <typename ScannerT>
    struct result
    {
        typedef typename match_result<ScannerT, uint64_t>::type type;
    };

    fixed_point_parser() {}  //ctor

    template <typename ScannerT>
    typename parser_result<self_t, ScannerT>::type
        parse(ScannerT const& scan) const
    {
        typedef typename parser_result<fixed_point_parser, ScannerT>::type RT;

        if (!scan.at_end())
        {
            uint_parser<int, 10, 1, 6> int_part;
            typename ScannerT::iterator_t save = scan.first;

            RT n_match = int_part.parse(scan);
            T  n = n_match.has_valid_attribute() ?
                n_match.value() : T(0);
            bool got_a_number = n_match;

            if (got_a_number)
            {
                n *= pow10[DecimalPlaces];
                if (ch_p(".").parse(scan))
                {
                    RT frac = int_part.parse(scan);
                    if (frac)
                    {
                        n += frac.value() * pow10[DecimalPlaces - frac.length()];
                        return scan.create_match(n_match.length() + frac.length() + 1, n, save, scan.first);
                    }
                    else
                        return scan.no_match();
                }
                return scan.create_match(n_match.length(), n, save, scan.first);
            }

        }
        return scan.no_match();
    }
};


int main()
{

    string str = "1234.5";

    fixed_point_parser<uint64_t> f{};

//  if (qi::parse(str.begin(), str.end(), f)) //UNCOMMENT THIS!
    if (parse(str.begin(), str.end(), f).full) //COMMENT THIS OUT!
    {
        cout << "Parsing succeeded\n";
    }
    else
    {
        cout << "Parsing failed\n";
    }


    return 0;
}

代码将正确编译和解析。

但是一旦您取消注释“取消注释!”并尝试使其与qi配合使用,然后编译将失败。

有人可以帮忙解释原因吗?

1 个答案:

答案 0 :(得分:1)

好吧,我真的想出了办法。

template <typename T, int DecimalPlaces=4 >
struct fixed_point_parser
    : primitive_parser<fixed_point_parser<T> >
{
    static constexpr int pow10[10] = {
        1, 10, 100, 1000, 10000,
        100000, 1000000, 10000000, 100000000, 1000000000
    };


    template <typename Context, typename Iterator>
    struct attribute
    {
        typedef T type;
    };

    template <typename Iterator, typename Context, typename Skipper>
    bool parse(Iterator& first, Iterator const& last
        , Context& /*context*/, Skipper const& skipper
        , T& attr_) const
    {
        bool got_a_number = extract_uint<T, 10, 1, -1>::call(first, last, attr_);

        if (got_a_number)
        {
            attr_ *= pow10[DecimalPlaces];
            if (ureal_policies<T>::parse_dot(first, last))
            {
                T frac_part;
                Iterator save = first;
                bool got_frac_part = extract_uint<T, 10, 1, -1>::call(first, last, frac_part);
                if (got_frac_part)
                {
                    auto dist = first - save;
                    attr_ += frac_part * pow10[DecimalPlaces - dist];
                }
            }
            return true;
        }
        return false;
    }

    template <typename Iterator, typename Context
        , typename Skipper, typename Attribute>
        bool parse(Iterator& first, Iterator const& last
            , Context& context, Skipper const& skipper
            , Attribute& attr_param) const
    {
        // this case is called when Attribute is not T
        T attr_;
        if (parse(first, last, context, skipper, attr_))
        {

            boost::spirit::traits::assign_to(attr_, attr_param);
            return true;
        }
        return false;
    }

    template <typename Context>
    info what(Context& /*context*/) const
    {
        return info("fixed_point");
    }
};