在其他线程中,我已经阅读了如何在语义操作中将符号添加到符号表,但我不知道如何删除它。
我的问题背后的想法是,我想允许重命名已解析文本中的关键字。因此,给出了几个具有值的关键字,但用户可以重新分配它们:
reassign(keyword)(mykeyword)
我有一个语义 Action 规则
using namespace boost::spirit::qi;
...
qi::symbols<char, TYPE> keywords;
...
key_replace = ( lit("reassign") >> lit("(") >> keywords >> lit(")") >>
lit("(") >> lexeme [ raw [ ( alpha >> *( alnum | '_' ) ) ] ] >> lit (")") )
[ boost::phoenix::bind(keywords.remove, _1) ]; // TODO: replace not remove
问题是,我没有得到对符号本身的引用,而是对存储值的引用。所以调用 remove 不起作用。
如何在解析过程中获取对已解析符号的引用?
有没有更简单的方法来交换符号,同时在解析期间保留值?
最佳答案
天真的“凤凰”方式是
rule_assign = key >> value
[ phx::bind(keywords.add, _1, _2) ];
rule_remove = key
[ phx::bind(keywords.remove, _1) ];
// and voila: (BROKEN)
rule_replace = key >> value
[ phx::bind(keywords.remove, _1),
phx::bind(keywords.add, _1, _2)
];
后者不起作用,我相信是因为第一个绑定(bind)返回一个重载 operator,
本身的对象,并且它比 phoenix
更受青睐' s 运算符,
。
我建议您通过编写一个小助手来解决这个问题:
struct assign_symbol_f
{
assign_symbol_f(Symbols& sym) : sym(sym) {}
typedef bool result_type;
template<typename Key, typename Value>
bool operator()(Key const& key, Value const& value) const
{
bool replaced = (nullptr != sym.find(key));
sym.remove(key);
sym.add(key, value);
return replaced;
}
private:
Symbols& sym;
};
这会透明地分配或重新分配 symbols
树中的项目。按如下方式使用它:
rule_replace_or_add = key >> value
[ phx::bind(assign_symbol_f(keywords), qi::_1, qi::_2) ];
现在,您可以拆分内容并更加具体:
assign_symbol_f assign_sym(keywords);
rule_assign = key >> value
[ qi::_pass = !phx::bind(assign_sym, _1, _2) ];
rule_replace = key >> value
[ qi::_pass = phx::bind(assign_sym, _1, _2) ];
奖金
作为奖励,您可以通过为仿函数创建一个惰性 actor 来获得一点语法糖:
phx::function<assign_symbol_f> assign_sym;
// use it like
rule_assign = key >> value
[ qi::_pass = assign_sym(_1, _2) ];
rule_replace = key >> value
[ qi::_pass = assign_sym(_1, _2) ];
看妈妈!不再有 phx::bind
。
完整演示
完成一个基本的测试套件:)
#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 phx = boost::phoenix;
typedef qi::symbols<char, int> Symbols;
struct assign_symbol_f
{
assign_symbol_f(Symbols& sym) : sym(sym) {}
typedef bool result_type;
template<typename Key, typename Value>
bool operator()(Key const& key, Value const& value) const
{
bool replaced = (nullptr != sym.find(key));
sym.remove(key);
sym.add(key, value);
return replaced;
}
private:
Symbols& sym;
};
template <typename Iter> struct parser : qi::grammar<Iter, qi::space_type>
{
parser(Symbols &dict)
: parser::base_type(start),
assign_sym(dict)
{
using namespace qi;
identifier = +graph;
add_rule = lit("+") >> (identifier >> int_)
[ assign_sym(_1, _2) ]
;
del_rule = lit("-") >> identifier
[ phx::bind(dict.remove, _1) ]
;
start = (del_rule | add_rule) % ";";
}
private:
phx::function<assign_symbol_f> assign_sym;
qi::rule<Iter, qi::space_type> start, del_rule, add_rule;
qi::rule<Iter, std::string()> identifier; // no skipper
};
bool execute(std::string const& test, Symbols& dict)
{
auto f = test.begin(), l = test.end();
parser<std::string::const_iterator> prsr(dict);
return
qi::phrase_parse(f, l, prsr, qi::space)
&& (f == l);
}
int main() {
Symbols dict;
assert(execute("+foo 3; +bar 4; -foo", dict));
assert(!dict.find("foo"));
assert( dict.find("bar") && (4 == dict.at("bar")));
assert(!dict.find("zap"));
assert(execute("+zap -42; +bar 5; +foo 33", dict));
assert( dict.find("zap") && (-42 == dict.at("zap")));
assert( dict.find("bar") && (5 == dict.at("bar"))); // replaced
assert( dict.find("foo") && (33 == dict.at("foo")));
}
关于c++ - 在语义 Action 中去掉一个灵气符号,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/17570396/