1
votes

I'm writing a little compiler just for fun and I'm using Boost Spirit Qi to describe my grammar. Now I want to make a minor change in the grammar to prepare some further additions. Unfortunately these changes won't compile and I would like to understand why this is the case.

Here is a snippet from the code I want to change. I hope the provided information is enough to understand the idea. The complete code is a bit large, but if you want to look at it or even test it (Makefile and Travis CI is provided), see https://github.com/Kruecke/BFGenerator/blob/8f66aa5/bf/compiler.cpp#L433.

typedef boost::variant<
    function_call_t,
    variable_declaration_t,
    variable_assignment_t,
    // ...
> instruction_t;

struct grammar : qi::grammar<iterator, program_t(), ascii::space_type> {
    grammar() : grammar::base_type(program) {
        instruction = function_call
                    | variable_declaration
                    | variable_assignment
                 // | ...
                    ;

        function_call = function_name >> '(' > -(variable_name % ',') > ')' > ';';
        // ...
    }

    qi::rule<iterator, instruction::instruction_t(),   ascii::space_type> instruction;
    qi::rule<iterator, instruction::function_call_t(), ascii::space_type> function_call;
    // ...
};

So far, everything is just working fine. Now I want to move the parsing of the trailing semicolon (> ';') from the function_call rule to the instruction rule. My code now looks like this:

struct grammar : qi::grammar<iterator, program_t(), ascii::space_type> {
    grammar() : grammar::base_type(program) {
        instruction = (function_call > ';') // Added trailing semicolon
                    | variable_declaration
                    | variable_assignment
                 // | ...
                    ;

        // Removed trailing semicolon here:
        function_call = function_name >> '(' > -(variable_name % ',') > ')';
        // ...
    }

From my understanding the rules haven't really changed because the character parser ';' doesn't yield any attribute and so it shouldn't matter where this parser is positioned. However, this change won't compile:

/usr/include/boost/spirit/home/support/container.hpp:278:13: error: no matching function for call to ‘std::basic_string<char>::insert(std::basic_string<char>::iterator, const bf::instruction::function_call_t&)’
             c.insert(c.end(), val);
             ^

(This error comes from the instruction = ... line.)

Why is this change not compiling? I'm rather looking for an explanation to understand what's going on than a workaround.

1

1 Answers

2
votes

Ok, so after looking at this closely, you are trying to insert multiple strings into your function_call_t type, which is a fusion sequence that can be converted to from a single std::string. However, you are probably going to run into issues with your function_call rule because it's attribute is actually tuple <std::string, optional <vector <std::string>>>. I'd imagine that spirit is having issues flattening that structure out and that is causing your issue, however, I don't have a compiler to test it out at the moment.