The Boost C++ Libraries

Actions

So far, the examples in this chapter only detect two things: whether the parser was successful and where the parse ended. However, parsers normally process data in some way, as you will see in the next examples.

Example 11.9. Linking actions with parsers
#include <boost/spirit/include/qi.hpp>
#include <string>
#include <iostream>

using namespace boost::spirit;

int main()
{
  std::string s;
  std::getline(std::cin, s);
  auto it = s.begin();
  bool match = qi::phrase_parse(it, s.end(),
    qi::int_[([](int i){ std::cout << i << '\n'; })], ascii::space);
  std::cout << std::boolalpha << match << '\n';
  if (it != s.end())
    std::cout << std::string{it, s.end()} << '\n';
}

Example 11.9 uses boost::spirit::qi::int_ to parse an integer, then writes that integer to standard output. That’s why an action has been linked with boost::spirit::qi::int_. Actions are functions or function objects that are called when a parser is applied. Linking is done with the operator operator[], which is overloaded by boost::spirit::qi::int_ and other parsers. Example 11.9 uses a lambda function as an action that expects a sole parameter of type int and writes it to standard output.

If you start Example 11.9 and enter a number, the number is displayed.

The type of the parameter passed to an action depends on the parser. For example, boost::spirit::qi::int_ forwards an int value, while boost::spirit::qi::float_ passes a float value.

Example 11.10. Boost.Spirit with Boost.Phoenix
#define BOOST_SPIRIT_USE_PHOENIX_V3
#include <boost/spirit/include/qi.hpp>
#include <boost/phoenix/phoenix.hpp>
#include <string>
#include <iostream>

using namespace boost::spirit;
using boost::phoenix::ref;

int main()
{
  std::string s;
  std::getline(std::cin, s);
  auto it = s.begin();
  int i;
  bool match = qi::phrase_parse(it, s.end(), qi::int_[ref(i) = qi::_1],
    ascii::space);
  std::cout << std::boolalpha << match << '\n';
  if (match)
    std::cout << i << '\n';
  if (it != s.end())
    std::cout << std::string{it, s.end()} << '\n';
}

Example 11.10 uses Boost.Phoenix to store the int value parsed with boost::spirit::qi::int_ in i. If boost::spirit::qi::phrase_parse() returns true, i is written to standard output.

This example defines the macro BOOST_SPIRIT_USE_PHOENIX_V3 before including the header files from Boost.Spirit. This macro selects the third and current version of Boost.Phoenix. This is important because Boost.Phoenix was forked from Boost.Spirit, and Boost.Spirit contains the second version of Boost.Phoenix. If BOOST_SPIRIT_USE_PHOENIX_V3 isn’t defined, the second version of Boost.Phoenix will be included through the Boost.Spirit header files and the third version through boost/phoenix/phoenix.hpp. The different versions will lead to a compiler error.

Please note how the lambda function is defined in detail. boost::phoenix::ref() creates a reference to the variable i. However, the placeholder _1 isn’t from Boost.Phoenix, it’s from Boost.Spirit. This is important because boost::spirit::qi::_1 provides access to the parsed value with the normally expected type – int in Example 11.10. If the lambda function used boost::phoenix::placeholders::arg1, the compiler would report an error because boost::phoenix::placeholders::arg1 wouldn’t represent an int; it would be based on another type from Boost.Spirit, and the int value would need to be extracted.

The Boost.Spirit documentation contains an overview on tools that support a Boost.Phoenix integration.