我想在语义操作中更改局部变量值,如下所示:
#define BOOST_SPIRIT_USE_PHOENIX_V3
#include <boost/spirit/include/qi.hpp>
#include <boost/spirit/include/phoenix.hpp>
#include <string>
namespace qi = boost::spirit::qi;
namespace spirit = boost::spirit;
namespace ascii = boost::spirit::ascii;
using boost::phoenix::ref;
using boost::phoenix::bind;
void dummy(const std::vector<char>& v, int& var)
{
var = 7;
}
template <typename Iterator>
struct x_grammar : public qi::grammar<Iterator, std::string(), ascii::space_type>
{
public:
x_grammar() : x_grammar::base_type(start_rule, "x_grammar")
{
using namespace qi;
int local_var = 0;
start_rule = (+(char_ - ";"))[bind(dummy, _1, ref(local_var))];
//repeat(ref(local_var))[some_rule];
}
private:
qi::rule<Iterator, std::string(), ascii::space_type> start_rule;
};
int main()
{
typedef std::string::const_iterator iter;
std::string storage("string;aaa");
iter it_begin(storage.begin());
iter it_end(storage.end());
std::string read_data;
using boost::spirit::ascii::space;
x_grammar<iter> g;
try {
bool r = qi::phrase_parse(it_begin, it_end, g, space, read_data);
std::cout << "Pass!\n";
} catch (const qi::expectation_failure<iter>& x) {
std::cout << "Error!\n";
}
}
我使用GCC 4.6.1和boost 1.55获得了一些恼人的编译错误。
答案 0 :(得分:6)
我不禁要注意,如果编译器错误让你烦恼,那么也许你应该编写有效的代码:/
虽然这当然是一个轻率的评论,但它也有点启发。
我已经告诉你两次现在在你的语法中使用构造函数局部变量的整个想法是从根本上被打破:
你想要的是
这里真正重要的是
Boost Spirit从表达式模板生成解析器。表达式模板是90%的静态信息(仅限类型),并将“编译”(
.compile()
)转换为“可调用”(.parse()
)形式。最重要的是,当你可以在你的语义动作中编写控制流时,这些都不会在定义网站上实际执行。它被“编译”成一个懒惰的演员,以后可以调用它。
当相应的解析表达式匹配
时,生成的解析将有条件地调用惰性actor
看起来您只想使用函数转换属性。
以下是您可以做的事情:
转换为语义动作的一部分,将结果放入常规属性(维护解析器组合的“功能”语义):
qi::rule<Iterator, exposed(), Skipper> myrule;
myrule = int_ [ _val = phx::bind(custom_xform, _1) ];
custom_xform
是任何旧学校的可校友(包括多态学校):
exposed custom_xform(int i) { return make_new_exposed(i); }
// or
struct custom_xfrom_t {
template <typename> struct result { typedef exposed type; };
template <typename Int>
exposed operator()(Int i) const {
return make_new_exposed(i);
}
};
static const custom_xform_t custom_xform;
你可以添加一些语法糖 [1]
qi::rule<Iterator, exposed(), Skipper> myrule;
myrule = int_ [ _val = custom_xform(_1) ];
这要求custom_xform
被定义为懒惰的演员:
phx::function<custom_xform_t> custom_xform; // `custom_xform_t` again the (polymorphic) functor
您可能会注意到这对常规功能不起作用。您可以将其包装在可调用对象中,或使用
BOOST_PHOENIX_ADAPT_FUNCTION
宏为您执行此操作
如果您想要更频繁地应用更多涉及的转换,请考虑使用Spirit定制点:
如果您为属性选择特定类型(例如Ast::Multiplicity
或Ast::VelocityRanking
,而不是int
或double
[1] 使用BOOST_SPIRIT_USE_PHOENIX_V3
答案 1 :(得分:2)
使用C ++ 03的代码compiles。但是,当使用GCC 4.6的C ++ 11支持时,代码fails to compile。以下是错误的相关摘录:
/usr/local/include/boost/spirit/home/support/action_dispatch.hpp: In static member function 'static void boost::spirit::traits::action_dispatch< Component>::caller(F&&, A&& ...) [with F = const std::_Bind<with Boost.Phoenix actors>]' ... main.cpp:25:9: instantiated from 'x_grammar<Iterator>::x_grammar() [...] /usr/local/include/boost/spirit/home/support/action_dispatch.hpp:142:13: error: no matching function for call to 'boost::spirit::traits:: action_dispatch<...>::do_call(const std::_Bind<with Boost.Phoenix actors>)'
尽管using boost::phoenix::bind
指令,对bind()
的无限制调用正在解析为std::bind()
而不是boost::phoenix::bind()
,但参数正在解析为Boost.Phoenix actor。 Boost.Spirit documentation特别警告不要混合来自不同图书馆的占位符:
您必须确保不要将占位符与不属于的库混合,并且在编写语义操作时不要使用不同的库。
因此,编译问题可以通过在定义语义动作时显式来解决。使用:
std::bind(dummy, std::placeholders::_1, std::ref(local_var))
或:
boost::phoenix::bind(dummy, _1, ref(local_var))
虽然这解决了编译器错误,但值得注意的是ref(local_var)
对象将保持悬空引用,因为它的生命周期超出local_var
的范围。这是一个有效的example,其中local_var
的生命周期通过使其成为静态而延伸到构造函数的范围之外。