0

この関数boost::spirit::qi::parse()は、入力範囲を定義するために 2 つの反復子を想定しています。std::stringまたはから解析しようとすると、これはうまく機能しますstd::istream。ここで、パーサー用により汎用的なインターフェイスを実装したいと考えています。1 つのアプローチは、 を使用boost::any_rangeして入力を定義することでした。これがコンパイルされたが例外をスローする私のテストコードです: "string iterator not dereferencable".

2 番目の質問です。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