合并 boost::spirit 和 boost::any_range?
Combine boost::spirit and boost::any_range?
函数boost::spirit::qi::parse()
需要两个迭代器来定义输入范围。如果我尝试从 std::string
或 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
迭代器。在这种情况下,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.) 是的我忘了公开属性。这只是一个快速而肮脏的例子。谢谢提示。
默认构造的迭代器不等同于您的范围的结束迭代器。
输入迭代器通常只遵循该约定。
解析器继续读取。幸运的是,您正在使用某种 compiler/library 实现来检测结束后访问。
实际上,您不能为输入迭代器编译一个新语法 (decode<>
) 实例吗?这就是 C++ 泛型编程的全部要点。
更新
这就是我要做的:
- 请注意
do_parse
(以及与 Spirit 或 Boost 相关的所有内容)可以隐藏在 cpp
#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
函数boost::spirit::qi::parse()
需要两个迭代器来定义输入范围。如果我尝试从 std::string
或 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
迭代器。在这种情况下,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.) 是的我忘了公开属性。这只是一个快速而肮脏的例子。谢谢提示。
默认构造的迭代器不等同于您的范围的结束迭代器。
输入迭代器通常只遵循该约定。
解析器继续读取。幸运的是,您正在使用某种 compiler/library 实现来检测结束后访问。
实际上,您不能为输入迭代器编译一个新语法 (decode<>
) 实例吗?这就是 C++ 泛型编程的全部要点。
更新
这就是我要做的:
- 请注意
do_parse
(以及与 Spirit 或 Boost 相关的所有内容)可以隐藏在 cpp
#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