更新
回答您编辑的问题:是的,您可以在没有语义操作的情况下执行此操作,只需:
template<typename It>
struct Parser : qi::grammar<It, Matrix(), qi::space_type>
{
Parser() : Parser::base_type(matrix_)
{
matrixBlock_ = qi::lit(";") >> *qi::int_;
matrix_ = qi::repeat(3)[ matrixBlock_ ];
}
qi::rule<It, Matrix(), qi::space_type> matrixBlock_, matrix_;
};
请注意,您可能想要验证行数/列数。请参阅我的扩展示例,它使用额外的语义操作来检查(注意从*int_
to的细微变化+int_
以避免空行):
#include <boost/spirit/include/qi.hpp>
#include <boost/spirit/include/karma.hpp>
#include <boost/spirit/include/phoenix.hpp>
namespace qi = boost::spirit::qi;
namespace karma = boost::spirit::karma;
namespace phx = boost::phoenix;
typedef std::vector<int> Matrix;
template<typename It>
struct Parser : qi::grammar<It, Matrix(), qi::space_type>
{
Parser() : Parser::base_type(matrix_)
{
using namespace qi;
matrixBlock_ = lit(";") >> +int_ >> eps( 0 == (phx::size(_val) % 3));
matrix_ = repeat(3)[ matrixBlock_ ];
}
qi::rule<It, Matrix(), qi::space_type> matrixBlock_, matrix_;
};
int main()
{
std::string test = ";42 45 -9; 3 2 1; 12 34 56";
std::string::const_iterator f(test.begin()), l(test.end());
Parser<std::string::const_iterator> parser;
Matrix m;
if (qi::phrase_parse(f,l,parser,qi::space, m))
std::cout << "Wokay\n";
else
std::cerr << "Uhoh\n";
std::cout << karma::format(karma::auto_ % ", ", m) << "\n";
}
旧答案:
是的,您可以使用 Spirit 的自定义点将您的用户定义类型视为容器。我建议的文档条目在这里:
这是一个简单的例子,展示了如何使用它,现场:
关于“幻像条目”的旁注,一般来说:
请注意,有一些与回溯语法和容器属性相关的常见问题解答。问题是,出于性能原因,解析器在回溯时不会撤消(“回滚”)对其底层容器的更改。您可以使用强制此行为,qi::hold
但可能值得努力将语法重新设计为
完整代码示例:
#include <boost/spirit/include/qi.hpp>
#include <boost/spirit/include/karma.hpp>
namespace qi = boost::spirit::qi;
namespace karma = boost::spirit::karma;
struct Matrix
{
std::vector<int> data;
};
namespace boost { namespace spirit { namespace traits {
template <>
struct is_container<Matrix>
{
};
template <typename Attrib>
struct push_back_container<Matrix, Attrib>
{
static bool call(Matrix& c, Attrib const& val)
{
c.data.push_back(val);
return true;
}
};
template <>
struct container_value<Matrix>
{
typedef int type;
};
} } }
template<typename It>
struct Parser : qi::grammar<It, Matrix(), qi::space_type>
{
Parser() : Parser::base_type(start)
{
start = *qi::int_;
}
qi::rule<It, Matrix(), qi::space_type> start;
};
int main()
{
std::string test = "42 45 -9";
std::string::const_iterator f(test.begin()),
l(test.end());
Parser<std::string::const_iterator> parser;
Matrix m;
if (qi::phrase_parse(f,l,parser,qi::space, m))
std::cout << "Wokay\n";
else
std::cerr << "Uhoh\n";
std::cout << karma::format(karma::auto_ % ", ", m.data) << "\n";
}
输出:
Wokay
42, 45, -9
更新
多一点背景:
当然,对于这样一个简单的例子,它只是包装了一个标准支持的容器类型,使用融合适配会相当容易:(http://liveworkspace.org/code/56aea8619867451a21cd49fddb1e93bd)
#include <boost/spirit/include/qi.hpp>
#include <boost/spirit/include/karma.hpp>
#include <boost/fusion/adapted/struct.hpp>
namespace qi = boost::spirit::qi;
namespace karma = boost::spirit::karma;
struct Matrix { std::vector<int> data; };
BOOST_FUSION_ADAPT_STRUCT(Matrix, (std::vector<int>, data));
int main()
{
std::string test = "42 45 -9";
std::string::const_iterator f(test.begin()), l(test.end());
Matrix m;
if (qi::phrase_parse(f,l, qi::eps >> *qi::int_, qi::space, m))
std::cout << karma::format(karma::auto_ % ", ", m.data) << "\n";
}
请注意,qi::eps
由于结构中仅包含一个数据元素的错误(AFAICT),这是必要的。请参阅此处的讨论(以及其他一些提及)