Speeding up the spread of Qi Spirit attributes
I have a problem with the Boost Spirit Qi grammar that emits an unwanted type, resulting in this compilation error:
error C2664: 'std::basic_string<_Elem,_Traits,_Ax> &std::basic_string<_Elem,_Traits,_Ax>::insert(unsigned int,const std::basic_string<_Elem,_Traits,_Ax> &)' : cannot convert parameter 1 from 'std::_String_iterator<_Elem,_Traits,_Alloc>' to 'unsigned int'
Here is the grammar that is causing the problem:
qi::rule<Iterator, qi::unused_type()> gr_newline;
// asmast::label() just contains an identifier struct that is properly emitted from gr_identifier
qi::rule<Iterator, asmast::label(), skipper<Iterator> > gr_label;
gr_newline = +( char_('\r')
|char_('\n')
);
This fails:
gr_label = gr_identifier
>> ':'
> gr_newline;
But the following all works:
// This parses OK
gr_label = gr_identifier
> gr_newline;
// This also parses OK
gr_label = gr_identifier
> ':'
> gr_newline;
// This also parses OK
// **Why does this work when parenthesized?**
gr_label = gr_identifier
>> (':'
> skip_grammar.gr_newline
);
// This also parses OK
gr_label = gr_identifier
>> omit[':'
> gr_newline];
I don't understand why remove the literal character or omit the [] that it "fixes" the problem, but I don't want the grammar to be cluttered with that.
As per the compound attribute rules for โ and> found here , and character parser attributes here , gr_label should only emit asmast :: label
a: A, b: B --> (a >> b): tuple<A, B>
a: A, b: Unused --> (a >> b): A <---- This one here is the one that should match so far as I understand
a: Unused, b: B --> (a >> b): B
a: Unused, b: Unused --> (a >> b): Unused
Expression Attribute
c unused or if c is a Lazy Argument, the character type returned by invoking it.
However, somehow something pollutes the assigned attribute and results in a compiler error.
So my questions are where is this grammar emitting the unwanted attribute and how to get rid of it.
source to share
The problem is that you have to mix and match >
and >>
here.
Even though you are following the rules for generating documented attributes correctly, it looks like the side is Unused
more like fusion::vector1<qi::unused_type>
(instead of qi::unused_type
).
Side note:
This also explains " Why does this work when parenthesized? " -
you change the order in which the expression is evaluated (operator precedence overflow)
and get a different type.
You can find out if my guess is correct using methods like eg. Detection of parameter types in the semantic action Spirit .
So the short answer is this is how it works. Whether this is a bug, an oversight in the documentation, or just the function is not constructive for discussion on SO. I am linking to the [spirit-general] mailing list (note that they also have an active #IRC channel).
The answer is slightly longer : I think there is something else that you are not showing .
Two things:
-
The error message states quite clearly that it is trying
insert
a string iterator where the character is expected (or convertible). I don't see any link to any of the code you posted, although I can guess- using qi :: raw [] somewhere (likely)
- using iterator_pair in one of your ast structures (rather unlikely)
-
I can compile your "problematic" rule sample, fully nested within my "mock" grammar. I created a guess from the little bits you set in the previous question.
- see the complete program I used below or see it running in Live on Coliru mode (I also compiled this locally using GCC 4.7.3 and boost 1.53)
I think maybe you should try posting another question showing a Short Self Contained Correct Example which has a problem that you are actually facing.
Be sure to include the compiler version and boost version.
Fully working SSCCE example
#define BOOST_SPIRIT_DEBUG
#include <boost/spirit/include/qi.hpp>
namespace qi = boost::spirit::qi;
namespace asmast
{
typedef std::string label;
}
template <typename It, typename Skipper = qi::blank_type>
struct parser : qi::grammar<It, Skipper>
{
parser() : parser::base_type(start)
{
using namespace qi;
start = lexeme["Func" >> !(alnum | '_')] > function;
function = gr_identifier
>> "{"
>> -(
gr_instruction
| gr_label
//| gr_vardecl
//| gr_paramdecl
) % eol
> "}";
gr_instruction_names.add("Mov", unused);
gr_instruction_names.add("Push", unused);
gr_instruction_names.add("Exit", unused);
gr_instruction = lexeme [ gr_instruction_names >> !(alnum|"_") ] > gr_operands;
gr_operands = -(gr_operand % ',');
gr_identifier = lexeme [ alpha >> *(alnum | '_') ];
gr_operand = gr_identifier | gr_string;
gr_string = lexeme [ '"' >> *("\"\"" | ~char_("\"")) >> '"' ];
gr_newline = +( char_('\r')
|char_('\n')
);
gr_label = gr_identifier >> ':' > gr_newline;
BOOST_SPIRIT_DEBUG_NODES((start)(function)(gr_instruction)(gr_operands)(gr_identifier)(gr_operand)(gr_string));
}
private:
qi::symbols<char, qi::unused_type> gr_instruction_names;
qi::rule<It, Skipper> start, function, gr_instruction, gr_operands, gr_operand, gr_string;
qi::rule<It, qi::unused_type()> gr_newline;
qi::rule<It, asmast::label(), Skipper> gr_label, gr_identifier;
};
int main()
{
typedef boost::spirit::istream_iterator It;
std::cin.unsetf(std::ios::skipws);
It f(std::cin), l;
parser<It, qi::blank_type> p;
try
{
bool ok = qi::phrase_parse(f,l,p,qi::blank);
if (ok) std::cout << "parse success\n";
else std::cerr << "parse failed: '" << std::string(f,l) << "'\n";
if (f!=l) std::cerr << "trailing unparsed: '" << std::string(f,l) << "'\n";
return ok;
} catch(const qi::expectation_failure<It>& e)
{
std::string frag(e.first, e.last);
std::cerr << e.what() << "'" << frag << "'\n";
}
return false;
}
source to share