有多种方法。
我通常建议使用经过深思熟虑的
repeat(n)
表达式,直接暴露
容器属性(例如
vector<vector<double>>
)。
你似乎在寻找具有状态的语义动作。 (这是从lex / yacc常见的做法)。
我在下面的三个完整演示中详细介绍了这些方法(1、2和3)。
一种高级技术是使用
自定义点来允许Spirit将您的
Matrix
类型直接处理为容器属性,并使用
spirit :: traits
覆盖其插入逻辑。 对于这种方法,我参考了此答案:
pass attribute to child rule in boost spirit。
这里有一个相对简单的方法:
parsing directly into a vector<vector<double> >
(full code live online)
qi::rule<It, Matrix::value_type(size_t cols), qi::blank_type> row;
qi::rule<It, Matrix(size_t rows,size_t cols), qi::blank_type> matrix;
row %= skip(char_(" \t,")) [ repeat(_r1) [ double_ ] ];
matrix %= eps // [ std::cout << phx::val("debug: ") << _r1 << ", " << _r2 << "\n" ]
>> repeat(_r1) [ row(_r2) >> (eol|eoi) ];
Usage:
if (qi::phrase_parse(f,l,parser(10, 4),qi::blank, m))
std::cout << "Wokay\n";
else
std::cerr << "Uhoh\n";
Similarly, but adapting a Matrix
struct (full code live here)
struct Matrix
{
Matrix(size_t rows, size_t cols) : _cells(), _rows(rows), _cols(cols) { }
double & data(size_t col, size_t row) { return _cells.at(row).at(col); }
const double & data(size_t col, size_t row) const { return _cells.at(row).at(col); }
size_t columns() const { return _cols; }
size_t rows() const { return _rows; }
std::vector<std::vector<double> > _cells;
size_t _rows, _cols;
};
BOOST_FUSION_ADAPT_STRUCT(Matrix, (std::vector<std::vector<double> >,_cells))
Usage
Matrix m(10, 4);
if (qi::phrase_parse(f,l,parser(m.rows(),m.columns()),qi::blank, m))
std::cout << "Wokay\n";
else
std::cerr << "Uhoh\n";
使用语义动作和qi::locals
3. 这种方法需要更多的工作,但可能更加灵活。你需要定义一个多态可调用类型,以在给定的单元格中插入一个值:
struct MatrixInsert
{
template <typename, typename, typename, typename> struct result { typedef bool type; };
template <typename Matrix, typename Row, typename Col, typename Value>
bool operator()(Matrix &m, Row& r, Col& c, Value v) const
{
if (r < m.rows() && c < m.columns())
{
m.data(r, c++) = v;
return true;
}
return false;
}
};
BOOST_PHOENIX_ADAPT_CALLABLE(matrix_insert, MatrixInsert, 4)
最后一行将其变成了一个
phoenix
的惰性函数,因此您可以在语义动作中使用它而无需使用奇怪的绑定语法:
qi::rule<It, Matrix(), qi::blank_type, qi::locals<size_t , size_t> > matrix;
matrix = eps [ _a = 0 ]
>> (
eps [ _b = 0 ]
>> double_ [ _pass = matrix_insert(_val, _a, _b, _1) ]
)
;
完整的代码在这里,再次提醒您可以在
liveworkspace.org上实时运行。