Predefined Actors

Actors

The framework has a number of predefined semantic action functors. Experience shows that these functors are so often used that they were included as part of the core framework to spare the user from having to reinvent the same functionality over and over again.

Quick example: assign_a actor

    int i, j;
    std::string s;
    r = int_p[assign_a(i)] >> (+alpha_p)[assign_a(s)] >> int_p[assign_a(j,i)];

Given an input 123456 Hello 789,

  1. assign_a(i) will extract the number 123456 and assign it to i,
  2. assign_a(s) will extract the string "Hello" and assign it to s,
  3. assign_a(j,i) will assign i to j, j=i, without using the parse result.

Technically, the expression assign_a(v) is a template function that generates a semantic action. In fact, actor instances are not created directly since they usually involve a number of template parameters. Instead generator functions ("helper functions") are provided to generate actors from their arguments. All helper functions have the "_a" suffix. For example, append_actor is created using the append_a function.

The semantic action generated is polymorphic and should work with any type as long as it is compatible with the arguments received from the parser. It might not be obvious, but a string can accept the iterator first and last arguments that are passed into a generic semantic action (see above). In fact, any STL container that has an assign(first, last) member function can be used.

Actors summary

Below are tables summarizing the "built-in" actors with the conventions given below.

Note that examples are provided after the tables.

Unary operator actors
++ref increment_a(ref)
--ref decrement_a(ref)
Assign actors
ref = value assign_a(ref)
ref = value_ref assign_a(ref, value_ref)
Container actors
ref.push_back(value) push_back_a(ref)
ref.push_back(value_ref) push_back_a(ref, value_ref)
ref.push_front(value) push_front_a(ref)
ref.push_front(value_ref) push_front_a(ref, value_ref)
ref.clear() clear_a(ref)
Associative container actors
ref.insert(vt(value, value_ref)) insert_key_a(ref, value_ref)
ref.insert(vt(key_ref,value_ref)) insert_at_a(ref, key_ref_, value_ref)
ref.insert(vt(key_ref,value)) insert_at_a(ref, key_ref)
ref[value] = value_ref assign_key_a(ref, value_ref)
ref.erase(ref,value) erase_a(ref)
ref.erase(ref,key_ref) erase_a(ref, key_ref)
Miscellanous actors
swaps aref and bref swap_a(aref, bref)

Include Files

The header files for the predefined actors are located in boost/spirit/actor. The file actors.hpp contains all the includes for all the actors. You may include just the specific header files that you need. The list below enumerates the header files.

    #include <boost/spirit/actor/assign_actor.hpp>
#include <boost/spirit/actor/assign_key.hpp> #include <boost/spirit/actor/clear_actor.hpp> #include <boost/spirit/actor/decrement_actor.hpp> #include <boost/spirit/actor/erase_actor.hpp>
#include <boost/spirit/actor/increment_actor.hpp>
#include <boost/spirit/actor/insert_key_actor.hpp> #include <boost/spirit/actor/insert_at_actor.hpp> #include <boost/spirit/actor/push_back_actor.hpp> #include <boost/spirit/actor/push_front_actor.hpp> #include <boost/spirit/actor/swap_actor.hpp>

Examples

Increment a value

Suppose that your input string is

    1,2,-3,4,...

and we want to count the number of ints. The actor increment_a applies ++ to its reference:

    int count = 0;    
    rule<> r = list_p.direct(int_p[increment_a(count)], ch_p(','));

Append values to a vector (or other container)

Here, you want to fill a vector<int> with the numbers. The actor push_back_a can be used to insert the integers at the back of the vector:

    vector<int> v;
    rule<> r = list_p.direct(int_p[push_back_a(v)], ch_p(','));

insert key-value pairs into a map

Suppose that your input string is

    (1,2) (3,4) ... 

and you want to parse the pair into a map<int,int>. assign_a can be used to store key and values in a temporary key variable, while insert_a is used to insert it into the map:

    map<int, int>::value_type k;
    map<int, int> m;
    
    rule<> pair = 
        confix_p(
            '('
          , int_p[assign_a(k.first)] >> ',' >> int_p[assign_a(k.second)]
          , ')'
        )
[
insert_at_a(m, k)] ;

Policy holder actors and policy actions

The action takes place through a call to the () operator: single argument () operator call for character parsers and two argument (first, last) call for phrase parsers. Actors should implement at least one of the two () operator.

A lot of actors need to store reference to one or more objects. For example, actions on container need to store a reference to the container.

Therefore, this kind of actor have been broken down into a) an action policy that does the action (act member function), b) policy holder actor that stores the references and feeds the act member function.

Policy holder actors

The available policy holders are enumerated below.

Policy holders
Name Stored variables Act signature
ref_actor 1 reference act(ref)
ref_value_actor 1 ref act(ref, value) or act(ref, first, last)
ref_const_ref_actor 1 ref and 1 const ref act(ref, const_ref)
ref_const_ref_value_actor 1 ref act(ref, value) or act(ref, first, last)
ref_const_ref_const_ref_actor 1 ref, 2 const ref act(ref, const_ref1, const_ref2)

Include Files

The predefined policy header files are located in boost/spirit/actor:

    #include <boost/spirit/actor/ref_actor.hpp>
#include <boost/spirit/actor/ref_value_actor.hpp> #include <boost/spirit/actor/ref_const_ref.hpp> #include <boost/spirit/actor/ref_const_ref_value.hpp> #include <boost/spirit/actor/ref_const_ref_value.hpp> #include <boost/spirit/actor/ref_const_ref_const_ref.hpp>

Holder naming convention

Policy holder have the following naming convention:

    <member>_ >> *<member> >> !value >> actor

where member is the action policy member which can be of type:

and value states if the policy uses the parse result or not.

Holder example: ref_actor class

    // this is the building block for action that  
    // take a reference and the parse result

    template<
        typename T, // reference type
        typename ActionT // action policy
    >
    class ref_value_actor : public ActionT
    {
    public:

        explicit ref_value_actor(T& ref_)
        : ref(ref_){}

        template<typename T2>
        void operator()(T2 const& val) const
        {
            act(ref, val); // defined in ActionT
        }

        template<typename IteratorT>
        void operator()(
            IteratorT const& first,
            IteratorT const& last) const
        {
            act(ref,first,last); // defined in ActionT
        }

    private: 

       T& ref;
    };

Actor example: assign_actor

    // assign_action assigns the parse result to the reference

    struct assign_action
    {
        template<
            typename T,
            typename ValueT
        >
        void act(T& ref, ValueT const& value) const
        {
            ref = value;
        }
        
        template<
            typename T,
            typename IteratorT
        >
        void act(
            T& ref, 
            IteratorT const& first, 
            IteratorT const& last) const
        {
            typedef typename T::value_type value_type;
            value_type vt(first, last);
            ref = vt;
        }
    };

Helper function example: assign_a function

    // assign_a is a polymorphic helper function that generators an
    // assign_actor based on ref_value_actor, assign_action and the 
    // type of its argument.

    template<typename T>
    inline ref_value_actor<T, assign_action>
    assign_a(T& ref)
    {
        return ref_value_actor<T, assign_action>(ref);
    }