4

他のスレッドでは、セマンティック アクションでシンボル テーブルにシンボルを追加する方法を読みましたが、それを削除する方法がわかりません。

私の質問の背後にある考え方は、解析されたテキストのキーワードの名前を変更できるようにしたいということです。したがって、値を持ついくつかのキーワードが指定されていますが、ユーザーはそれらを再割り当てできます。

reassign(keyword)(mykeyword)

セマンティックアクションを含むルールがあります

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 を呼び出しても機能しません。

解析中に解析されたシンボルへの参照を取得するにはどうすればよいですか?

解析中に値を保持しながらシンボルを交換する簡単な方法はありますか?

4

1 に答える 1

3

素朴な「フェニックス」の方法は、

 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)
        ];

後者は機能しません。最初のバインドがoperator,それ自体をオーバーロードするオブジェクトを返し、それがphoenix'sよりも優先されるためだと思いますoperator,

小さなヘルパーを作成して、これを回避することをお勧めします。

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) ];

ボーナス

おまけとして、ファンクター用の遅延アクターを作成することで、構文糖衣を少し追加できます。

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")));
}
于 2013-07-10T13:47:44.233 に答える