0

该函数boost::spirit::qi::parse()需要两个迭代器来定义输入范围。std::string如果我尝试从or解析,这很好用std::istream。现在我想为我的解析器实现一个更通用的接口。一种方法是用来boost::any_range定义输入。这是我编译但抛出异常的测试代码"string iterator not dereferencable"

第二个问题。我怎样才能结合boost::any_range在一起boost::spirit::classic::position_iterator来检测可能的错误位置?

#include <boost/range/any_range.hpp>
#include <boost/spirit/include/classic_position_iterator.hpp>
#include <boost/spirit/include/qi.hpp>
#include <boost/spirit/include/support_multi_pass.hpp>

namespace qi = boost::spirit::qi;

typedef boost::any_range<
    char,
    boost::forward_traversal_tag,
    char,
    std::ptrdiff_t
> input_type;

template < typename _Iterator >
    struct decode
    : qi::grammar< _Iterator >
    {
        decode( ) : decode::base_type( m_rule )
        {
            m_rule = qi::int_;

            BOOST_SPIRIT_DEBUG_NODES( ( m_rule ) )
        }

        qi::rule< _Iterator > m_rule;
    };

bool parse( const input_type& in, int& out )
{
    // We use a stream iterator to access the given stream:
    typedef boost::spirit::multi_pass<
        input_type::const_iterator
    > stream_iterator;

    // Create begin iterator for given stream:
    stream_iterator sBegin = boost::spirit::make_default_multi_pass( input_type::const_iterator( in.begin( ) ) );
    stream_iterator sEnd   = boost::spirit::make_default_multi_pass( input_type::const_iterator( ) );

    // Create an instance of the used grammar:
    decode<
        stream_iterator
    > gr;

    // Try to decode the data stored within the stream according the grammar and store the result in the out variable:
    bool r = boost::spirit::qi::parse( sBegin,
                                       sEnd,
                                       gr,
                                       out );

    return r && sBegin == sEnd;
}

void main( )
{
    std::string in = "12345"; int out;

    parse( in, out );
}

更新

1.) 我同意默认构造的sEnd迭代器存在错误。因此我简化了我的例子,我想我误解了如何使用multi_pass迭代器。在这种情况下c0false(预期的)和c1true(不是预期的)。那么使用multi_pass迭代器的正确方法是什么?

#include <boost/range/any_range.hpp>
#include <boost/spirit/include/classic_position_iterator.hpp>
#include <boost/spirit/include/qi.hpp>
#include <boost/spirit/include/support_multi_pass.hpp>

namespace qi = boost::spirit::qi;

typedef boost::any_range<
    char,
    boost::forward_traversal_tag,
    char,
    std::ptrdiff_t
> input_type;

bool parse( const input_type& in, int& out )
{
    //for( input_type::iterator i = in.begin( ); i != in.end( ); ++i )
    //{
    //    std::cout << *i;
    //}

    // We use a stream iterator to access the given stream:
    typedef boost::spirit::multi_pass<
        input_type::const_iterator,
        boost::spirit::iterator_policies::default_policy<                // Defaults:
            boost::spirit::iterator_policies::ref_counted,               // OwnershipPolicy: ref_counted
            boost::spirit::iterator_policies::buf_id_check,              // CheckingPolicy : buf_id_check
            boost::spirit::iterator_policies::buffering_input_iterator,  // InputPolicy    : buffering_input_iterator
            boost::spirit::iterator_policies::split_std_deque            // StoragePolicy  : split_std_deque
        >
    > stream_iterator;

    bool c0 = in.begin( ) == in.end( );

    // Create begin iterator for given stream:
    stream_iterator sBegin( in.begin( ) );
    stream_iterator sEnd(   in.end( )   );

    bool c1 = sBegin == sEnd;

    //for( stream_iterator i = sBegin; i != sEnd; ++i )
    //{
    //    std::cout << *i;
    //}

    return false;
}
void main( )
{
    std::string in = "12345"; int out;

    parse( in, out );
}

2.) 是的,我可以为每种类型的输入迭代器编译一个新的语法实例。我的想法是对用户隐藏实现细节(= boost::spirit)并给他一个通用接口。因此,我想避免使用模板功能。

3.) 是的,我忘了公开属性。这只是一个快速而肮脏的例子。感谢您的提示。

4

1 回答 1

1

默认构造的迭代器不等同于您的范围的结束迭代器。

该约定通常只遵循输入迭代器。

解析器继续阅读。幸运的是,您正在使用某种编译器/库实现来检测过去的访问。


实际上,您不能decode<>为输入迭代器编译一个新的语法 ( ) 实例吗?这就是 C++ 中泛型编程的重点。


更新

这就是我要做的:

  • 请注意do_parse(以及所有 Spirit,或者实际上与 Boost 相关的内容)都可以隐藏在 cpp 中

Live On Coliru

#include <boost/spirit/include/qi.hpp>

namespace mylib {
    struct public_api {
        int parse(std::string const& input);
        int parse(std::istream& stream);
    };

    template<typename It>
    static int do_parse(It f, It l) {
        namespace qi = boost::spirit::qi;

        int result;
        if (qi::parse(f, l, qi::int_, result))
            return result;

        throw std::runtime_error("parse failure");
    }

    int public_api::parse(std::string const& input) {
        return do_parse(input.begin(), input.end());
    }

    int public_api::parse(std::istream& stream) {
        boost::spirit::istream_iterator f(stream >> std::noskipws), l;
        return do_parse(f, l);
    }
}

int main()
{
    std::istringstream iss("12345");
    std::string const s("23456");

    mylib::public_api api;
    std::cout << api.parse(s)   << "\n";
    std::cout << api.parse(iss) << "\n";
}

印刷

23456
12345
于 2015-09-13T22:49:00.763 回答