Feb 26

Frank Dellaert was asking a valid question on the Spirit mailing list where he pointed out some things he was not able to understand. His question clearly uncovered an inconsistency in Spirit’s API. This lead us to implement some minor additional feature, which in the end turned out to make more uniform the way semantic actions are handled.

Given the following definitions:

#include <boost/spirit/include/qi.hpp>
#include <boost/spirit/include/phoenix.hpp>

namespace qi = boost::spirit::qi;
namespace phoenix = boost::phoenix;

class Point3
{
    double x_, y_, z_;
public:
    Point3() : x_(0), y_(0), z_(0) {}
    Point3(double x, double y, double z) : x_(x), y_(y), z_(z) {}
};

Point3 pt3;
std::string input("1.0,2.0,3.0");

He showed that this piece of code works fine:

qi::rule<std::string::iterator, Point3()> r =
    (qi::double_ >> ',' >> qi::double_ >> ',' >> qi::double_)
    [
        qi::_val = phoenix::construct<Point3>(qi::_1, qi::_2, qi::_3)
    ];
qi::parse(input.begin(), input.end(), r, pt3);

At the same time, this code does not compile:

qi::parse(
   input.begin(), input.end(),
   (qi::double_ >> ',' >> qi::double_ >> ',' >> qi::double_)
   [
       qi::_val = phoenix::construct<Point3>(qi::_1, qi::_2, qi::_3)
   ],
   pt3);

The only difference between the two is that in the first case the parser is wrapped into a rule, while in the second example the parser is directly placed inline into the parse() API call. After some investigation I understood, that the placeholder qi::_val was only usable in semantic actions attached to some right hand side of a rule. In this context, it referred to the rule’s attribute.

After some discussions on IRC we decided that this limitation in the behavior of qi::_val is unneeded and confusing. It turned out that the fix is simple and does not break any existing code. The change, which will be available starting with the next release of Boost (V1.47), has been committed to SVN already. With this change in place it is possible to use the placeholder qi::_val in top level semantic actions as well, where it will refer to the whole attribute passed in by the user. This now allows to compile the second code example from above.

Please feel free to try it in your code! Note that the fix has been applied not only to Qi’s set of parse() API functions, but also to Karma’s set of generate() functions.

Thanks again to Frank for bringing up this detail, which in the end stirred some interesting discussions and which made Spirit a bit easier to use.

One Response to “Using _val in Top Level Semantic Actions”

  1. Frank Dellaert says:

    You’re welcome 🙂

Leave a Reply

preload preload preload