この関数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
したがって、例を単純化しましたが、イテレータの使用方法を誤解していると思います。この場合c0
はfalse
(予期される) であり、(予期さc1
れtrue
ない) です。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.) はい、属性を公開するのを忘れていました。これは簡単で汚い例にすぎません。ヒントをありがとう。