c++ - 使用 lambda 或外部函数作为 spirit.qi 语义 Action

标签 c++ parsing boost-spirit-qi boost-phoenix

我正在尝试创建基于 Boost.Spirit.Qi 的解析。有一个像 calc_utree 这样的例子,我正在尝试扩展用作语义操作的内容。

例如,将相同的方法与单独的赋值作为语义 Action 重用是微不足道的

        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;
}

我似乎对 QiPhoenix 产生了主要误解。这些问题是(主要是它们是同一问题的不同形式):

  • Phoenix 变量在 C++ lambda 中不起作用的具体情况是什么?
  • 如何让它与此类外部操作调用一起工作?

或者,如果没有Phoenix,如何实现_valSpirit 文档在这方面似乎很晦涩。

环境详细信息:Boost 1.58.0、gcc 5.4.0 或 clang 4.0(所有 Ubuntu 16.04)。

最佳答案

@llonesmiz 提供的链接非常好。

简而言之:您需要将函数调整为惰性 actor。 _val = _1 也是这样,但是使用表达式模板“神奇地”生成了。

对于您拥有的“常规”可调用对象

  • boost::phoenix::function
  • boost::phoenix::bind
  • BOOST_FUNCTION_ADAPT_*

这是一个小游行

Live On Coliru

#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 

关于c++ - 使用 lambda 或外部函数作为 spirit.qi 语义 Action ,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/49859896/

相关文章:

android - 使用 jni 包装 C++ 库

java - 用java解析JSON : dynamic keys

java - Java中SQL语句的解析和修改

c++ - 使用版本 2 语法的良好/完整 Boot Spirit 示例

c++ - 具有相同简单改编结构属性的 boost::spirit::qi 规则会产生编译错误

c++ - Xcode上找不到'opencv2/core/core.hpp'文件错误

c++ - std::mutiset 与 std::vector 读取排序字符串并将其写入文件

c++ - void 是什么意思,或者在这种情况下它如何影响 T?

python - 解析主键不唯一的 CSV 中的唯一值

c++ - boost spirit 语法错误 - "no type named ‘size’ 中的 ‘struct boost::spirit::unused_type’“