I have been learning boost::spirit and have come across confusion that a semantic action is evaluated during grammar construction. The following code produces the output:
string=
My assumption is that this output as part of the semantic action attached to the orule
.
Is there a way to avoid this behaviour? or is it something that I will need to live with if I'm using std::cout
in a semantic action?
#include <boost/spirit/include/qi.hpp>
#include <boost/spirit/include/phoenix.hpp>
#include <iostream>
#include <string>
namespace phx = boost::phoenix;
namespace qi = boost::spirit::qi;
template <typename Iterator>
struct my_grammar : qi::grammar<Iterator, std::string( ) >
{
my_grammar() : my_grammar::base_type(orule)
{
using qi::_1;
using qi::_2;
using qi::attr;
using qi::string;
using phx::val;
orule = string("abc") [ std::cout << "string=" << _1 << std::endl ];
}
qi::rule< Iterator, std::string() > orule;
};
int main()
{
typedef std::string::const_iterator iterator_type;
typedef my_grammar<iterator_type> parser;
parser my_parser; // Our grammar
return 0;
}
Short answer: No, semantic actions are not evaluated during rule initialization.
However, your problem is that you didn't (just) write a semantic action.
Yes, in your case the first part of that expression
has a side-effect:
(std::cout << "string=")
inserts the literal into the standard ostream object and then returnsstd::cout
by reference.This is because you use the
std::operator<<
defined in the standard library, notboost::phoenix::....::operator<<
¹.You can fix this by forcing the type of the second argument to something that will select the right overload:
Of course, you can always make doubly sure by doing e.g.
But you'll notice that people tend to skip this whenever it's possible. The second operand being
boost::spirit::_1
already induces expression-template context (i.e. selects the non-standard operator overloads that construct lazy actors instead of the side-effect).¹ which likely ends up just being
boost::proto::....::operator<<
anyhow, but that's all delicious implementation details :)