使用 lambda 或外部函数作为 spirit.qi 语义操作
Using lambdas or external functions as spirit.qi semantic actions
我正在尝试创建基于 Boost.Spirit.Qi 的解析。有一个像 calc_utree 这样的例子,我正在尝试扩展用作语义动作的内容。
例如,将相同的方法与单独的赋值作为语义动作重用是微不足道的
term =
factor [_val = _1]
如示例中的字面意思。但是,当我尝试将两者都传递给规则定义外部的函数(方法)时,甚至将其写为 lambda,例如
term =
factor [([&] {_val = _1; })]
它会导致那个地方的静默错误分配:_val
保持不变(编译器没有任何错误或警告)。如果我将其更改为
之类的内容,则相同
term =
factor [do_term_factor(_val, _1)]
<...>
template <typename D, typename S>
D& do_term_factor(D& d, S& s) {
d = s;
}
我似乎对 Qi
和 Phoenix
产生了主要误解。问题是(主要是同一问题的不同形式):
Phoenix
变量在 C++ lambda 中不起作用的具体情况是什么?
- 如何让它与这样的外部操作调用一起工作?
或者,没有Phoenix
如何实现_val
? Spirit
文档在这方面似乎很晦涩。
环境详细信息:Boost 1.58.0、gcc 5.4.0 或 clang 4.0(所有 Ubuntu 16.04)。
@llonesmiz 提供的链接非常好。
简而言之:您需要将功能调整为懒惰的演员。 _val = _1
也是,但是 "magically" 使用表达式模板生成。
你有 "regular" 个可调用对象
- boost::phoenix::function
- boost::phoenix::bind
- BOOST_FUNCTION_ADAPT_*
这里有一个小型游行
#include <boost/spirit/include/qi.hpp>
#include <boost/spirit/include/phoenix.hpp>
namespace qi = boost::spirit::qi;
namespace px = boost::phoenix;
//////////////////// bindables
struct GenericDoubler {
template <typename T>
auto operator()(T const& v) const { return v * 2; }
};
static const px::function<GenericDoubler> s_genericDoubler;
template <typename T>
T freeGenericDouble(T const& v) { return v * 2; }
BOOST_PHOENIX_ADAPT_FUNCTION(int, genericDouble_, freeGenericDouble, 1)
/////////////////// raw actors
int main() {
using It = std::string::const_iterator;
std::string const input = "42";
using namespace qi::labels;
for (auto rule : std::vector<qi::rule<It, int()> > {
// binds
qi::int_ [ _val = 2*_1 ],
qi::int_ [ _val = px::bind([](int i) { return 2*i; }, _1) ],
qi::int_ [ _val = px::bind(GenericDoubler(), _1) ],
qi::int_ [ _val = px::bind(&freeGenericDouble<int>, _1) ],
qi::int_ [ _val = genericDouble_(_1) ],
qi::int_ [ _val = s_genericDoubler(_1) ],
// actors
qi::int_ [ ([](int const& /*attribute*/, auto& /*context*/, bool& pass) {
// context is like boost::spirit::context<boost::fusion::cons<int&, boost::fusion::nil_>, boost::fusion::vector<> >
pass = false;
}) ],
qi::int_ [ ([](int& attribute, auto& context, bool& pass) {
int& exposed = boost::fusion::at_c<0>(context.attributes);
exposed = 2*attribute;
pass = true;
}) ],
})
{
It f = begin(input), l = end(input);
int data = 99;
if (parse(f, l, rule, data))
std::cout << "Parsed: " << data << " ";
else
std::cout << "Parse failed at '" << std::string(f,l) << "' ";
if (f != l)
std::cout << "Remaining: '" << std::string(f,l) << "'";
std::cout << '\n';
}
}
版画
Parsed: 84
Parsed: 84
Parsed: 84
Parsed: 84
Parsed: 84
Parsed: 84
Parse failed at '42' Remaining: '42'
Parsed: 84
我正在尝试创建基于 Boost.Spirit.Qi 的解析。有一个像 calc_utree 这样的例子,我正在尝试扩展用作语义动作的内容。
例如,将相同的方法与单独的赋值作为语义动作重用是微不足道的
term =
factor [_val = _1]
如示例中的字面意思。但是,当我尝试将两者都传递给规则定义外部的函数(方法)时,甚至将其写为 lambda,例如
term =
factor [([&] {_val = _1; })]
它会导致那个地方的静默错误分配:_val
保持不变(编译器没有任何错误或警告)。如果我将其更改为
term =
factor [do_term_factor(_val, _1)]
<...>
template <typename D, typename S>
D& do_term_factor(D& d, S& s) {
d = s;
}
我似乎对 Qi
和 Phoenix
产生了主要误解。问题是(主要是同一问题的不同形式):
Phoenix
变量在 C++ lambda 中不起作用的具体情况是什么?- 如何让它与这样的外部操作调用一起工作?
或者,没有Phoenix
如何实现_val
? Spirit
文档在这方面似乎很晦涩。
环境详细信息:Boost 1.58.0、gcc 5.4.0 或 clang 4.0(所有 Ubuntu 16.04)。
@llonesmiz 提供的链接非常好。
简而言之:您需要将功能调整为懒惰的演员。 _val = _1
也是,但是 "magically" 使用表达式模板生成。
你有 "regular" 个可调用对象
- boost::phoenix::function
- boost::phoenix::bind
- BOOST_FUNCTION_ADAPT_*
这里有一个小型游行
#include <boost/spirit/include/qi.hpp>
#include <boost/spirit/include/phoenix.hpp>
namespace qi = boost::spirit::qi;
namespace px = boost::phoenix;
//////////////////// bindables
struct GenericDoubler {
template <typename T>
auto operator()(T const& v) const { return v * 2; }
};
static const px::function<GenericDoubler> s_genericDoubler;
template <typename T>
T freeGenericDouble(T const& v) { return v * 2; }
BOOST_PHOENIX_ADAPT_FUNCTION(int, genericDouble_, freeGenericDouble, 1)
/////////////////// raw actors
int main() {
using It = std::string::const_iterator;
std::string const input = "42";
using namespace qi::labels;
for (auto rule : std::vector<qi::rule<It, int()> > {
// binds
qi::int_ [ _val = 2*_1 ],
qi::int_ [ _val = px::bind([](int i) { return 2*i; }, _1) ],
qi::int_ [ _val = px::bind(GenericDoubler(), _1) ],
qi::int_ [ _val = px::bind(&freeGenericDouble<int>, _1) ],
qi::int_ [ _val = genericDouble_(_1) ],
qi::int_ [ _val = s_genericDoubler(_1) ],
// actors
qi::int_ [ ([](int const& /*attribute*/, auto& /*context*/, bool& pass) {
// context is like boost::spirit::context<boost::fusion::cons<int&, boost::fusion::nil_>, boost::fusion::vector<> >
pass = false;
}) ],
qi::int_ [ ([](int& attribute, auto& context, bool& pass) {
int& exposed = boost::fusion::at_c<0>(context.attributes);
exposed = 2*attribute;
pass = true;
}) ],
})
{
It f = begin(input), l = end(input);
int data = 99;
if (parse(f, l, rule, data))
std::cout << "Parsed: " << data << " ";
else
std::cout << "Parse failed at '" << std::string(f,l) << "' ";
if (f != l)
std::cout << "Remaining: '" << std::string(f,l) << "'";
std::cout << '\n';
}
}
版画
Parsed: 84
Parsed: 84
Parsed: 84
Parsed: 84
Parsed: 84
Parsed: 84
Parse failed at '42' Remaining: '42'
Parsed: 84