Search code examples
c++boostboost-spiritboost-spirit-x3

x3::symbols moves result and therefore removes it from the symbol_parser itself


So, I ran into strange behaviour with boost::spirit::x3 as supplied in boost 1.59:

I defined a 'dynamic' symbol table via:

struct instructions : x3::symbols<OpCode> {
    instructions()
    {
        name("instructions");
    }

    void set_instruction_set(const std::unordered_map<std::string, OpCode>& instruction_set) {
        for (const auto& var : instruction_set) {
            add(var.first, var.second);
        }
    }
} instructions_parser;

OpCodeis defined as

struct OpCode
{
    std::string mnemonic;
    std::vector<...> variants;// actual type in vector<> not important.
};

now, with the symbol table embedded in the neccessary rules, when parsing an input string like

mov r2  r1
mov r1  @80

the resulting ast only contains the first mov with its operands. The second mov is missing but the operands are correctly parsed. This may look as followed, when printing the resulting AST:

mov r2 r1 
    r1 @80

With the debugger I located the source of the error in symbols.hpp in symbol_parser::parse():

template <typename Iterator, typename Context, typename Attribute>
    bool parse(Iterator& first, Iterator const& last
      , Context const& context, unused_type, Attribute& attr) const
    {
        x3::skip_over(first, last, context);

        if (value_type* val_ptr
            = lookup->find(first, last, get_case_compare<Encoding>(context)))
        {
            x3::traits::move_to(*val_ptr, attr); //<- the error originates from here
            return true;
        }
        return false;
    }

with move_to beeing:

template <typename T>
inline void move_to(T& src, T& dest)
{
    if (boost::addressof(src) != boost::addressof(dest))
        dest = std::move(src);
}

As you can see, the src which is my OpCode instance added in the symbol_parser is moved. This means after the first call its empty again and that's why only the first instructions appears. It's, simply put, moved out of the symbol table.

Now finally my question: Is this a bug or am I making a mistake?


Solution

  • As suggested by sehe my workaround as an answer:

    I found a temporary workaround: By declaring the template parameter as const one can suppress move semantics. The copy-ctor is then called.

    I.E.: x3::symbols<const std::string>