C++ Blog

Boost.Spirit: Semantic Actions

Posted in boost, Uncategorized by Umesh Sirsiwal on January 1, 2010

Note that this post applies to Spirit.Classic or 2.0.

In the first two posts we introduced basic parsing techniques defined by Spirit. The parsing is only useful, if we can do something with parsing results. In Spirit you achieve this with semantic actions.

Semantic actions are expected to use functional programming paradigms. The most basic semantic action has the following prototype:

 void f(IteratorT first, IteratorT last);

or as functor

  struct my_functor
        void operator()(IteratorT first, IteratorT last) const;

Here is an example of simple action from Spirit user guide:

    my_action(char const* first, char const* last)
        std::string str(first, last);
        std::cout << str << std::endl;

Applying the action is rather simple. You specify them in [] after the rule. From previous e-mail address parser, you can write:

    r = *(mailTo | anychar_p);
    mailTo = "mailTo:" >> emailAddress[&my_action];
    emailAddress = lexeme_d[ +alnum_p >> '@' >> +alnum_p >> *('.' >> +alnum_p)];

my_action will be called with iterator pointing to start and end of the parsed e-mail address. The above action will result in printing all the e-mail addresses in the input.

In a lot of cases, it is wasteful to call actions with the Iterators pointing to first and last. After all, Spirit has just parsed the contents. For this purpose the boost defines specialized actions. For example

  void func(NumT val);

or equivalent functor

struct fctr
        void operator()(NumT val) const;

can be applied to any numeric parsers (real_p, ureal_p, int_p, uint_p). Similar actions exist for other other types of parsers. Please check Spirit guide for details.

The complete program looks like:

#include <boost/spirit/core.hpp>
#include <iostream>
using namespace boost::spirit;

my_action(const char* first, const char* last)
std::string str(first, last);
std::cout << str << std::endl;

struct my_grammar : public grammar<my_grammar>
template <typename ScannerT>
struct definition
rule<ScannerT>  r, mailTo, emailAddress;
definition(my_grammar const& self)  {
r = *(mailTo | anychar_p);
mailTo = “mailTo:” >> emailAddress[&my_action];
emailAddress = lexeme_d[ +alnum_p >> ‘@’ >> +alnum_p >> *(‘.’ >> +alnum_p)];
rule<ScannerT> const& start() const { return r; }

int main(){
const char* str = “mailTo:a@b.com  test mailTo:d@f.com”;
my_grammar g;
if (parse(str, str + strlen(str), g, space_p).full)
std::cout << “parsing succeeded\n”;
std:: cout << “parsing failed\n”;
return 0;
In addition, there is a large selection of pre-defined actions. You an find them here.

One Response

Subscribe to comments with RSS.

  1. sehe said, on January 15, 2015 at 11:16 pm

    Note that Spirit Classic refers to Spirit V1.x, not V2. Indded this article is about Spirit V1.x

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Google photo

You are commenting using your Google account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s

%d bloggers like this: