I have written a working token parser based on the code shown at spirit lex example 4
One of my rules looks like this
set_name
= ( tok.set_ >> tok.name_ >> tok.identifier )
[
std::cout << val("set name statement to: ") << _3 << "\n"
]
;
This works well. When presented with
SET NAME xyz
it outputs as I expect
set name statement to: xyz
Now I want to do something useful, store the name found into a class. Working from parser semantic examples I write this code
class writer
{
public:
void print(string const& s) const
{
std::cout << s << std::endl;
}
};
writer w;
...
set_name
= ( tok.set_ >> tok.name_ >> tok.identifier )
[
boost::bind( &writer::print, &w, ::_3 )
]
;
This does not compile
1>C:\Program Files\boost\boost_1_44\boost/bind/bind.hpp(318) : error C2664: 'R boost::_mfi::cmf1::operator ()(const U &,A1) const' : cannot convert parameter 2 from 'bool' to 'const std::basic_string ' 1> with 1> [ 1> R=void, 1> T=eCrew::rule::writer, 1> A1=const std::string &, 1> U=eCrew::rule::writer * 1> ] 1> and 1> [ 1> _Elem=char, 1> _Traits=std::char_traits, 1> _Ax=std::allocator 1> ] 1> Reason: cannot convert from 'bool' to 'const std::string' 1> No constructor could take the source type, or constructor overload resolution was ambiguous
Why is the compiler complaining about a trying to convert from bool to string? There is no bool that I can see.
The placeholder in
std::cout << val("set name statement to: ") << _3 << "\n"
refers to boost::spirit::_3
, which is a boost.phoenix v2 placeholder. The placeholder in
boost::bind(&writer::print, &w, ::_3)
is a boost.bind placeholder (naturally).
These placeholders do not share the same behavior, or even refer to the same data. Phoenix placeholders of the form _N refer to the Nth subattribute of your parser, while bind placeholders have a different meaning:
bool&
'hit' parameterThe easiest solution in your case is to use boost::phoenix::bind
instead of boost::bind
, so that you can continue using _3
to refer to the third subattribute of your parser instead of having to pick it out manually inside of writer::print
.
Alternatively, only attach the semantic action to tok.identifier
so that boost.bind's ::_1
works as you expect:
set_name
= tok.set_
>> tok.name_
>> tok.identifier[boost::bind(&writer::print, &w, ::_1)]
;