Predefined 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.
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,
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.
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) |
Miscellaneous actors | |||||||
swaps aref and bref | swap_a(aref, bref) |
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_actor.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>
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(','));
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(','));
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)]
;
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.
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) |
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>
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.
// 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;
};
// 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;
}
};
// 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);
}
Copyright © 2003 Jonathan de Halleux
Copyright © 2003 Joel de Guzman
Use, modification and distribution is subject to the Boost Software License, Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)