我有两个具有相同属性的规则。
是否可以将matrix_规则的属性传递给matrixBlock_子规则? 我想保持repeat指令不要创建表单向量<的属性。取代。相反,它应该继续写入matrix_(numBlocks的次数)的属性。 我试图将该属性作为继承属性传递给子规则并进行编译(见下文)。但我在我的矢量中得到了几个“鬼”条目,这些条目不是来自phoenix :: push_back。 这对我来说似乎不是最佳方式。我们可以在matrixBlock_中使用自动属性传播而不是语义动作吗?
typedef vector<columnT> Matrix;
matrix_ = repeat(numBlocks)[ matrixBlock_(_val) ];
matrixBlock_ = *column[phoenix::push_back(_r1, _1)];
qi::rule<Iterator, Matrix(), ascii::space_type> matrix_;
qi::rule<Iterator, void(Matrix&), ascii::space_type> matrixBlock_;
澄清问题:
如果我编写没有语义动作的规则,则matrix_的合成属性将是
vector< vector< columnT > >
-
typedef vector<columnT> Matrix;
matrix_ = repeat(numBlocks)[ matrixBlock_ ];
matrixBlock_ = *column;
qi::rule<Iterator, Matrix(), ascii::space_type> matrix_;
qi::rule<Iterator, Matrix(), ascii::space_type> matrixBlock_;
我希望它具有与matrixBlock_相同的属性类型,即1维数组。
我的实际解决方案是只使用一个规则。 (看起来很简单:-))
typedef vector<columnT> Matrix;
matrix_ = repeat(numBlocks)[ *column_[ phoenix::push_back(_val, _1) ] ];
//matrixBlock_ = *column;
qi::rule<Iterator, Matrix(), ascii::space_type> matrix_;
//qi::rule<Iterator, Matrix(), ascii::space_type> matrixBlock_;
我能够在vs2010中使用此代码重现幻像条目并提升1.46.1
http://liveworkspace.org/code/505091dc4631a379763567168a728e0c
输出为:42,45,-9,3,2,1,12,34,56,0,0,0
我的错误是使用旧的Boost版本。没有1.5的牙龈。
现在我的语法有两个工作版本。是否可以在不使用push_back语义操作的情况下重新设计语法?
答案 0 :(得分:4)
回答您编辑过的问题:是的,您可以在没有语义操作的情况下执行此操作,只需执行以下操作:
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_;
};
请注意,可能要验证行数/列数。 See my extended sample ,它使用额外的语义操作来检查(注意从*int_
到+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的自定义点将用户定义的类型视为容器。我建议的文档条目在这里:
这是一个简单的例子,展示了如何使用它:live:
关于'幻影条目'的旁注,一般来说:
请注意,有一些与回溯语法和容器属性相关的常见问题解答。问题是,出于性能原因,解析器不会在回溯时撤消(“回滚”)对其底层容器的更改。您可以使用
可能是值得的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
更多背景知识:
当然,对于这样一个简单的例子,它只包含一个标准的受支持容器类型,使用fusion adaptation 相当容易:(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";
}
请注意,由于包含仅包含一个数据元素的结构的错误(AFAICT),qi::eps
是必需的。参见例如discussion here(以及其他一些提及)