c++ - 在语义 Action 中去掉一个灵气符号

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

在其他线程中,我已经阅读了如何在语义操作中将符号添加到符号表,但我不知道如何删除它。

我的问题背后的想法是,我想允许重命名已解析文本中的关键字。因此,给出了几个具有值的关键字,但用户可以重新分配它们:

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/

相关文章:

c++ - 非模板类型参数

c++ - 如何在C++中实现一个简单的多线程FileLogger?

c++ - 使用 Boost Spirit 匹配字符串

c++ - 为什么我无法访问语义操作中的值?

c++ - boost spirit qi - 将字符串解析为 bool 值

c++ - 递归 lambda 和捕获(段错误)

c++ - 在对其进行线程操作后保存 GDI+ 位图

c++ - 理解 Boost.Spirit 中的列表运算符(%)

c++ - Boost Spirit 和抽象语法树设计

c++ - 不允许类型名称