boost::bind does not compile - c++

I am new to boost spirit and I have the following problem:
#include <string>
#include <vector>
#include <boost/spirit/include/qi.hpp>
#include <boost/spirit/include/phoenix_operator.hpp>
#include <boost/spirit/include/phoenix_function.hpp>
#include <boost/spirit/include/phoenix_statement.hpp>
#include <boost/bind.hpp>
using namespace boost::spirit;
using namespace std;
struct MyGrammar
: qi::grammar<string::const_iterator, string(), ascii::space_type> {
MyGrammar();
void myFun(const string& s);
private:
qi::rule<string::const_iterator, string(), ascii::space_type> myRule;
};
using namespace boost::spirit;
using namespace std;
MyGrammar::MyGrammar() : MyGrammar::base_type(myRule) {
using qi::_1;
myRule = int_ [boost::bind(&MyGrammar::myFun, this, _1)]; // fails
myRule = int_ [_val = _1]; // fine
}
void MyGrammar::myFun(const string& s){
cout << "read: " << s << endl;
}
int
main(){
}
With the first assignment of myRule I get compile errors while the second assignment compiles fine.
In the first case the compiler outputs huge error messages that I don't understand.
At the end it says:
boost_1_49_0/include/boost/bind/bind.hpp:318:9: error: no match for call to '(const boost::_mfi::mf1<void, MyGrammar, const std::basic_string<char>&>) (MyGrammar* const&, const boost::phoenix::actor<boost::spirit::argument<0> >&)'
boost_1_49_0/include/boost/bind/mem_fn_template.hpp:163:7: note: candidates are: R boost::_mfi::mf1<R, T, A1>::operator()(T*, A1) const [with R = void, T = MyGrammar, A1 = const std::basic_string<char>&]
boost_1_49_0/include/boost/bind/mem_fn_template.hpp:184:7: note: R boost::_mfi::mf1<R, T, A1>::operator()(T&, A1) const [with R = void, T = MyGrammar, A1 = const std::basic_string<char>&]
Any ideas?
Thanks a lot for any help!

You can't use placeholders from different bind implementations. There are currently three bind functions in Boost:
boost::bind, superseded by
boost::lambda::bind, superseded by
boost::phoenix::bind, which is what you should use for Boost.Spirit
The placeholders under boost::spirit::qi (and boost::spirit::karma) are the same as the ones used by boost::phoenix::bind, so just use that.
Oh, and pro tip: Stop your using namespace std; and preferrably any other using directive in global namespace.

The first problem is that you specifiy std::string as your synthesized attribute, but then define your rule in terms of qi::int_, which has a synthesized attribute of int.
The second problem is that, as the Spirit docs state directly, non-Phoenix functors take three arguments, not one:
You can use Boost.Bind to bind member functions. For function objects, the allowed signatures are:
void operator()(Attrib const&, unused_type, unused_type) const;
void operator()(Attrib const&, Context&, unused_type) const;
void operator()(Attrib const&, Context&, bool&) const;
The third problem is that you're using Spirit's Phoenix _1 placeholder rather than boost::bind's placeholder (which is effectively in the global namespace).
In summary, this should work:
#include <string>
#include <iostream>
#include <boost/bind.hpp>
#include <boost/spirit/include/qi.hpp>
#include <boost/spirit/include/phoenix_operator.hpp>
#include <boost/spirit/include/phoenix_function.hpp>
#include <boost/spirit/include/phoenix_statement.hpp>
namespace qi = boost::spirit::qi;
namespace ascii = boost::spirit::ascii;
struct MyGrammar :
qi::grammar<std::string::const_iterator, int(), ascii::space_type>
{
MyGrammar();
void myFun(int i, qi::unused_type, qi::unused_type);
private:
qi::rule<std::string::const_iterator, int(), ascii::space_type> myRule;
};
MyGrammar::MyGrammar() : MyGrammar::base_type(myRule)
{
myRule = qi::int_[boost::bind(&MyGrammar::myFun, this, _1, _2, _3)];
}
void MyGrammar::myFun(int const i, qi::unused_type, qi::unused_type)
{
std::cout << "read: " << i << '\n';
}
int main()
{
std::string const input = "42";
std::string::const_iterator first = input.begin(), last = input.end();
qi::phrase_parse(first, last, MyGrammar(), ascii::space);
}
That being said, unless you have a very specific reason to use boost::bind here, you should be using boost::phoenix::bind instead:
#include <string>
#include <iostream>
#include <boost/spirit/include/qi.hpp>
#include <boost/spirit/include/phoenix_operator.hpp>
#include <boost/spirit/include/phoenix_function.hpp>
#include <boost/spirit/include/phoenix_statement.hpp>
#include <boost/spirit/include/phoenix_bind.hpp>
namespace qi = boost::spirit::qi;
namespace ascii = boost::spirit::ascii;
struct MyGrammar :
qi::grammar<std::string::const_iterator, int(), ascii::space_type>
{
MyGrammar();
void myFun(int i);
private:
qi::rule<std::string::const_iterator, int(), ascii::space_type> myRule;
};
MyGrammar::MyGrammar() : MyGrammar::base_type(myRule)
{
myRule = qi::int_[boost::phoenix::bind(&MyGrammar::myFun, this, qi::_1)];
}
void MyGrammar::myFun(int const i)
{
std::cout << "read: " << i << '\n';
}
int main()
{
std::string const input = "42";
std::string::const_iterator first = input.begin(), last = input.end();
qi::phrase_parse(first, last, MyGrammar(), ascii::space);
}
This allows your bound member function to take only a single argument – the synthesized attribute – as you originally wanted.

Related

unable to decipher compile error when using boost.spirit.parser

I am trying to learn to parse using boost.spirit parser. I am using Windows 8.1 with VisualStudio 2015. I have installed and successfuly compiled the test program from the boost.spirit installation document so my installation of boost seems fine.
I have been following the tutorial on the boost.org on using the paser. I created the following code to parse a double:
#include <boost/config/warning_disable.hpp>
#include <boost/spirit/include/qi.hpp>
#include <boost/spirit/include/phoenix_core.hpp>
#include <boost/spirit/include/phoenix_operator.hpp>
#include <boost/spirit/include/phoenix_object.hpp>
namespace qi = boost::spirit::qi;
namespace ascii = boost::spirit::ascii;
template <typename Iterator>
bool myParser(Iterator first, Iterator last) {
using qi::double_;
qi::rule<Iterator, double(), ascii::space_type> myrule;
myrule %= double_;
bool r = parse(first, last, myrule, ascii::space);
return r;
}
int main() {
std::string dstr = std::string("2.1");
bool r = myParser(dstr.begin(), dstr.end());
return 0;
}
When I compile I get the following error message from rule.hpp line 304:
'bool boost::function4<R,T0,T1,T2,T3>::operator ()(T0,T1,T2,T3) const': cannot convert argument 4 from 'const boost::spirit::unused_type' to 'const boost::spirit::qi::char_class<boost::spirit::tag::char_code<boost::spirit::tag::space,boost::spirit::char_encoding::ascii>> '
Any help will be greatly appreciated. Thanks
As is mentioned by jv_ in the link, you are using a skipper, but not calling the phrase_parse API which would accept a skipper. So, the parse call tries to bind the ascii::space parser to the first exposed attribute (which is a double).
That assignment fails.
In all likelihood you don't want a skipper for this simple grammar, and I'd write:
#include <boost/spirit/include/qi.hpp>
template <typename Iterator> bool myParser(Iterator first, Iterator last) {
namespace qi = boost::spirit::qi;
return qi::parse(first, last, qi::double_ >> qi::eoi);
}
int main() {
std::string const dstr("2.1");
bool r = myParser(dstr.begin(), dstr.end());
return r?0:1;
}
Note the qi::eol which checks that all of the input was consumed.

Filter the synthesized attribute through a std::map in a boost spirit semantic action

I have a case where I'd like to filter the value that comes up as a synthesized attribute inside of a rule through a std::map.
The map is pre-generated and will not change during the parsing.
The nature of the map and the real parser means that the lookup should never fail (although the actual number of elements may be quite large)
The usual approach perfectly suited to this problem (use a symbol table) isn't appropriate for the real case. In the real problem, the lookup is conditional based on an attribute that won't be apparent until much later in the parse (in a somewhat removed rule).
My attempt:
#define BOOST_SPIRIT_USE_PHOENIX_V3
#include <boost/spirit/include/qi.hpp>
#include <boost/spirit/include/phoenix.hpp>
#include <boost/foreach.hpp>
#include <string>
#include <iostream>
#include <vector>
#include <map>
namespace qi = boost::spirit::qi;
namespace phx = boost::phoenix;
int main() {
std::map<unsigned int, unsigned int> myMap;
myMap[1] = 100; myMap[2] = 200; myMap[3] = 300;
std::string test = "1 2 3";
std::vector<unsigned int> results;
qi::rule<std::string::iterator, unsigned int()> r
= qi::uint_ [qi::_val = phx::at(myMap, qi::_1)];
qi::parse(test.begin(), test.end(), ( r % " " ), results);
BOOST_FOREACH(unsigned int &x, results) {
std::cout << x << "\n";
}
}
I guess I was under the impression, due to the phoenix support for stl containers, that this should work. But I get a compile error on the rule line. This error goes away if I replace the semantic action with the classic pointless [qi::_val = qi::_1] (not surprisingly).
The compiler error under MSVS10 is shockingly long, as usual, but here's the first mention of my code file: (at C:\code\Compiler2\spirit_test.cpp(25)... line 25 is the rule r)
C:\boost_1_50_0\boost/spirit/home/qi/nonterminal/rule.hpp(191) : see reference to function template instantiatio
n 'void boost::spirit::qi::rule<Iterator,T1>::define<boost::mpl::false_,Expr>(boost::spirit::qi::rule<Iterator,T1> &,con
st Expr &,boost::mpl::true_)' being compiled
with
[
Iterator=std::_String_iterator<char,std::char_traits<char>,std::allocator<char>>,
T1=unsigned int (void),
Expr=boost::proto::exprns_::expr<boost::proto::tagns_::tag::subscript,boost::proto::argsns_::list2<const boo
st::spirit::terminal<boost::spirit::tag::uint_> &,const boost::phoenix::actor<boost::proto::exprns_::basic_expr<boost::p
roto::tagns_::tag::assign,boost::proto::argsns_::list2<boost::proto::exprns_::expr<boost::proto::tagns_::tag::terminal,b
oost::proto::argsns_::term<boost::spirit::attribute<0>>,0>,boost::phoenix::actor<boost::proto::exprns_::basic_expr<boost
::phoenix::detail::tag::function_eval,boost::proto::argsns_::list3<boost::proto::exprns_::basic_expr<boost::proto::tagns
_::tag::terminal,boost::proto::argsns_::term<boost::phoenix::stl::at_impl>,0>,boost::phoenix::actor<boost::proto::exprns
_::basic_expr<boost::proto::tagns_::tag::terminal,boost::proto::argsns_::term<boost::reference_wrapper<std::map<unsigned
int,unsigned int>>>,0>>,boost::phoenix::actor<boost::spirit::argument<0>>>,3>>>,2>> &>,2>
]
C:\code\Compiler2\spirit_test.cpp(25) : see reference to function template instantiation 'boost::spirit::qi
::rule<Iterator,T1>::rule<boost::proto::exprns_::expr<Tag,Args,Arity>>(const Expr &,const std::string &)' being compiled
with
[
Iterator=std::_String_iterator<char,std::char_traits<char>,std::allocator<char>>,
T1=unsigned int (void),
Tag=boost::proto::tagns_::tag::subscript,
Args=boost::proto::argsns_::list2<const boost::spirit::terminal<boost::spirit::tag::uint_> &,const boost::ph
oenix::actor<boost::proto::exprns_::basic_expr<boost::proto::tagns_::tag::assign,boost::proto::argsns_::list2<boost::pro
to::exprns_::expr<boost::proto::tagns_::tag::terminal,boost::proto::argsns_::term<boost::spirit::attribute<0>>,0>,boost:
:phoenix::actor<boost::proto::exprns_::basic_expr<boost::phoenix::detail::tag::function_eval,boost::proto::argsns_::list
3<boost::proto::exprns_::basic_expr<boost::proto::tagns_::tag::terminal,boost::proto::argsns_::term<boost::phoenix::stl:
:at_impl>,0>,boost::phoenix::actor<boost::proto::exprns_::basic_expr<boost::proto::tagns_::tag::terminal,boost::proto::a
rgsns_::term<boost::reference_wrapper<std::map<unsigned int,unsigned int>>>,0>>,boost::phoenix::actor<boost::spirit::arg
ument<0>>>,3>>>,2>> &>,
Arity=2,
Expr=boost::proto::exprns_::expr<boost::proto::tagns_::tag::subscript,boost::proto::argsns_::list2<const boo
st::spirit::terminal<boost::spirit::tag::uint_> &,const boost::phoenix::actor<boost::proto::exprns_::basic_expr<boost::p
roto::tagns_::tag::assign,boost::proto::argsns_::list2<boost::proto::exprns_::expr<boost::proto::tagns_::tag::terminal,b
oost::proto::argsns_::term<boost::spirit::attribute<0>>,0>,boost::phoenix::actor<boost::proto::exprns_::basic_expr<boost
::phoenix::detail::tag::function_eval,boost::proto::argsns_::list3<boost::proto::exprns_::basic_expr<boost::proto::tagns
_::tag::terminal,boost::proto::argsns_::term<boost::phoenix::stl::at_impl>,0>,boost::phoenix::actor<boost::proto::exprns
_::basic_expr<boost::proto::tagns_::tag::terminal,boost::proto::argsns_::term<boost::reference_wrapper<std::map<unsigned
int,unsigned int>>>,0>>,boost::phoenix::actor<boost::spirit::argument<0>>>,3>>>,2>> &>,2>
]
C:\boost_1_50_0\boost/proto/transform/default.hpp(154) : error C2440: '=' : cannot convert from 'std::pair<_Ty1,_Ty2>' t
o 'unsigned int'
with
[
_Ty1=const unsigned int,
_Ty2=unsigned int
]
No user-defined-conversion operator available that can perform this conversion, or the operator cannot be called
Reposting from comment
Try qi::_val = phx::ref(myMap)[qi::_1] rather than qi::_val = phx::at(myMap, qi::_1).
The problem is that the return type of phoenix::at is defined in this header as container::value_type. This is a pair in the case of a map. Simply specializing the result for map makes it work (using ref as noted by ildjarn).
#define BOOST_SPIRIT_USE_PHOENIX_V3
#include <boost/spirit/include/qi.hpp>
#include <boost/spirit/include/phoenix.hpp>
#include <boost/foreach.hpp>
#include <string>
#include <iostream>
#include <vector>
#include <map>
namespace qi = boost::spirit::qi;
namespace phx = boost::phoenix;
namespace boost { namespace phoenix { namespace stl {
template <typename This, typename Key, typename Value, typename Compare, typename Allocator, typename Index>
struct at_impl::result<This(std::map<Key,Value,Compare,Allocator>&, Index)>
{
typedef Value & type;
};
template <typename This, typename Key, typename Value, typename Compare, typename Allocator, typename Index>
struct at_impl::result<This(std::map<Key,Value,Compare,Allocator> const&, Index)>
{
typedef Value const& type;
};
}}}
int main() {
std::map<unsigned int, unsigned int> myMap;
myMap[1] = 100; myMap[2] = 200; myMap[3] = 300;
std::string test = "1 2 3";
std::vector<unsigned int> results;
qi::rule<std::string::iterator, unsigned int()> r
= qi::uint_ [qi::_val = phx::at(phx::cref(myMap), qi::_1)];
qi::parse(test.begin(), test.end(), ( r % " " ), results);
BOOST_FOREACH(unsigned int &x, results) {
std::cout << x << "\n";
}
}

Boost.Spirit with Boost.Variant and C++11: Expecting a zero-argument constructor

I'm trying to compile a simple grammar using Boost.Spirit. I'm using g++ 4.7.0 and boost 1.49.0-1.1 on Arch Linux x86_64.
The eventual goal here is an assembler. There will be multiple operands with one class each. All the operand types together are stored in a boost::variant type.
I've had success compiling this sample up to the direct rule when it is also the base_type of the grammar, but introducing the operand rule (and making it the base type) causes g++ 4.7.0 to complain that:
example.cpp:61:7: required from ‘Grammar<Iterator>::Grammar() [with Iterator = __gnu_cxx::__normal_iterator<char*, std::basic_string<char> >]’
example.cpp:76:21: required from here
/usr/include/boost/spirit/home/qi/detail/attributes.hpp:23:63: error: no matching function for call to ‘DirectOperand::DirectOperand()’
/usr/include/boost/spirit/home/qi/detail/attributes.hpp:23:63: note: candidates are:
example.cpp:20:12: note: DirectOperand::DirectOperand(const DirectValue&)
example.cpp:20:12: note: candidate expects 1 argument, 0 provided
example.cpp:16:7: note: DirectOperand::DirectOperand(const DirectOperand&)
example.cpp:16:7: note: candidate expects 1 argument, 0 provided
I don't understand why it should be looking for a default constructor for DirectOperand, since the semantic action should call it with the constructor.
I've tried lots of variations, including
operand = directOp[_val = _1];
and even writing a helper function to "force" the type, like:
static Operand makeDirectOperand( const DirectOperand& op ) { return op; }
// ...
operand = directOp[&makeDirectOp];
but no matter what I do, it complains about the missing default constructor.
When I actually defined a zero-argument constructor, I found that it compiled, but that that DirectOperand::value_ never changed from the default value I assigned.
Here's the code. It's as short as I could make it.
#include <cstdint>
#include <iostream>
#include <string>
#include <boost/spirit/include/qi.hpp>
#include <boost/spirit/include/qi_uint.hpp>
#include <boost/spirit/include/phoenix_core.hpp>
#include <boost/spirit/include/phoenix_operator.hpp>
#include <boost/spirit/include/phoenix_fusion.hpp>
#include <boost/spirit/include/phoenix_stl.hpp>
#include <boost/variant.hpp>
typedef std::uint16_t DataWord;
typedef boost::variant<std::string, DataWord> DirectValue;
class DirectOperand {
private:
DirectValue value_;
public:
explicit DirectOperand( const DirectValue& value ) :
value_( value ) {}
const DirectValue& value() const { return value_; }
};
// For example purposes, but there will be multiple operand types
// here.
typedef boost::variant<DirectOperand> Operand;
namespace qi = boost::spirit::qi;
namespace ascii = boost::spirit::ascii;
template <typename Iterator>
struct Grammar : qi::grammar<Iterator, Operand(), ascii::space_type> {
Grammar() : Grammar::base_type( operand ) {
using qi::lexeme;
using ascii::char_;
using qi::uint_parser;
using namespace qi::labels;
uint_parser<DataWord, 16, 1, 4> uhex_p;
uint_parser<DataWord, 10, 1, 5> uint_p;
word =
char_( "a-zA-Z._" ) [_val += _1]
>> *char_( "a-zA-Z0-9._" ) [_val += _1]
;
number = (
"0x" >> uhex_p
| uint_p
)
[_val = _1]
;
direct %= ( word | number );
directOp %= direct;
// This would be ( directOp | indirectOp | etc)
operand %= directOp;
}
qi::rule<Iterator, DataWord(), ascii::space_type> number;
qi::rule<Iterator, std::string()> word;
qi::rule<Iterator, DirectValue(), ascii::space_type> direct;
qi::rule<Iterator, DirectOperand(), ascii::space_type> directOp;
qi::rule<Iterator, Operand(), ascii::space_type> operand;
};
int main() {
std::string line;
typedef std::string::iterator iterator_type;
typedef Grammar<iterator_type> Grammar;
Grammar grammar {};
}
I believe that the instantiation of the attribute qi::rule (directOp here) requires a default constructor.
If you are loathe to include a default constructor in DirectOperand, you could try wrapping it up in a boost::optional for the purpose of deferring initialization.

Using the + operator in boost::spirit: char cast error?

In boost::spirit, I am trying to use the +(...) syntax to match one or more strings, like here:
#include <boost/config/warning_disable.hpp>
#include <boost/spirit/include/qi.hpp>
#include <iostream>
#include <string>
namespace client
{
namespace qi = boost::spirit::qi;
namespace ascii = boost::spirit::ascii;
template <typename Iterator>
bool parse(Iterator first, Iterator last)
{
using qi::char_;
qi::rule< Iterator, std::string(), ascii::space_type > text;
qi::rule< Iterator, std::string() > myword;
text = '"' >> +( myword ) >> '"'; // ERROR!
myword = +char_;
bool r = qi::phrase_parse(first, last, text, ascii::space);
if (first != last)
return false;
return r;
}
}
But I'm getting the following error:
foo.cpp:20: instantiated from 'bool client::parse
boost/spirit/home/qi/detail/assign_to.hpp:109: error: \
invalid static_cast from type \
'const std::basic_string<char, std::char_traits<char>, std::allocator<char> >' \
to type 'char'
Does anyone know what I'm doing wrong?
Your code compiles just fine with Boost V1.47 (Spirit V2.5). In this version of Spirit the attribute handling has been completely rewritten which fixes this issue (and a lot of other issues).

boost spirit v2 compile error - trying to use symbols for something slightly harder and missing an important point somewhere

I have tried various approaches to fixing this issue with maps and casts, splitting the parse into different sub-pieces, using std::vector directly and trying _r1 etc. but I seem to have failed to grasp something fundamental about the use of attributes.
I want to parse a line such as:
DEFMACRO macroname param1 param2 param3 ... paramN
and add macroname into a qi::symbols parser along with its list of params.
Matching on
lit("DEFMACRO") >> (+char_) >> predicate_
and putting into a defmacro struct works fine, but when I try to use the result or store it whole as the data element of a symbols parser I get errors of the form
cannot convert from 'const boost::phoenix::actor' to 'const client::defmacro'
but whatever I try I always fail to "convert from 'const boost::phoenix::actor' to" whatever data type I am trying to use (eg straight to std::vector or other variations in structs. Also tried variations on syntax but so far drawn a blank.
Code fragment is below, followed by compiler output for this variation on my problem.
Any explanation of my failure to grasp some important concept very welcome.
Using VC++ 2008 with Spirit 1.42.
Thanks
Rick
#include <boost/spirit/include/qi.hpp>
#include <boost/spirit/include/qi_int.hpp>
#include <boost/spirit/include/phoenix_core.hpp>
#include <boost/spirit/include/phoenix_operator.hpp>
#include <boost/spirit/include/phoenix_fusion.hpp>
#include <boost/spirit/include/phoenix_stl.hpp>
#include <boost/spirit/include/phoenix_object.hpp>
#include <boost/fusion/include/adapt_struct.hpp>
#include <string>
#include <vector>
namespace client
{
namespace fusion = boost::fusion;
namespace phoenix = boost::phoenix;
namespace qi = boost::spirit::qi;
namespace ascii = boost::spirit::ascii;
typedef std::vector<std::string> predicate;
struct defmacro
{
std::string name; // identifier for macro
predicate params; // parameters for macro
};
}
BOOST_FUSION_ADAPT_STRUCT(
client::defmacro,
(std::string, name)
(client::predicate, params)
)
namespace client
{
template <typename Iterator>
struct awe_grammar
: qi::grammar<Iterator, awe(), qi::locals<std::string>, ascii::space_type>
{
awe_grammar()
: awe_grammar::base_type(x, "x")
{
using qi::lit;
using qi::eol;
using qi::int_;
using ascii::char_;
using namespace qi::labels;
using phoenix::at_c;
long line_no=1;
qi::symbols<std::string, defmacro> macros;
eol_ = eol[ref(line_no)++];
predicate_ %= *(+char_);
defmacro_line_ %= (lit("DEFMACRO") >> (+char_) >> predicate_ >> eol_);
// ******** This line will not compile *************************
defmacro_ = defmacro_line_[macros.add(at_c<0>(_1),_1)];
// *************************************************************
}
qi::rule<Iterator, defmacro(), ascii::space_type> defmacro_line_;
qi::rule<Iterator, void(), ascii::space_type> defmacro_;
qi::rule<Iterator, predicate(), ascii::space_type> predicate_;
};
}
2>v:\awe\parser\parser\spirit\spirit_eg.cpp(XXX) : error C2664: 'const boost::spirit::qi::symbols<Char,T>::adder &boost::spirit::qi::symbols<Char,T>::adder::operator ()<boost::phoenix::actor<Eval>>(const Str &,const T &) const' : cannot convert parameter 2 from 'const boost::phoenix::actor<Eval>' to 'const client::defmacro &'
2> with
2> [
2> Char=std::string,
2> T=client::defmacro,
2> Eval=boost::phoenix::composite<boost::phoenix::at_eval<0>,boost::fusion::vector<boost::spirit::argument<0>,boost::fusion::void_,boost::fusion::void_,boost::fusion::void_,boost::fusion::void_,boost::fusion::void_,boost::fusion::void_,boost::fusion::void_,boost::fusion::void_,boost::fusion::void_>>,
2> Str=boost::phoenix::actor<boost::phoenix::composite<boost::phoenix::at_eval<0>,boost::fusion::vector<boost::spirit::argument<0>,boost::fusion::void_,boost::fusion::void_,boost::fusion::void_,boost::fusion::void_,boost::fusion::void_,boost::fusion::void_,boost::fusion::void_,boost::fusion::void_,boost::fusion::void_>>>
2> ]
2> and
2> [
2> Eval=boost::spirit::argument<0>
2> ]
2> Reason: cannot convert from 'const boost::phoenix::actor<Eval>' to 'const client::defmacro'
2> with
2> [
2> Eval=boost::spirit::argument<0>
2> ]
2> No user-defined-conversion operator available that can perform this conversion, or the operator cannot be called
2> v:\awe\parser\parser\spirit\spirit_eg.cpp(351) : while compiling class template member function 'client::awe_grammar<Iterator>::awe_grammar(void)'
2> with
2> [
2> Iterator=std::_String_const_iterator<char,std::char_traits<char>,std::allocator<char>>
2> ]
2> v:\awe\parser\parser\spirit\spirit_eg.cpp(622) : see reference to class template instantiation 'client::awe_grammar<Iterator>' being compiled
2> with
2> [
2> Iterator=std::_String_const_iterator<char,std::char_traits<char>,std::allocator<char>>
2> ]
You can add values to symbols outside of your grammar like this:
#include <boost/spirit/include/qi.hpp>
#include <boost/spirit/include/qi_int.hpp>
#include <boost/spirit/include/phoenix_core.hpp>
#include <boost/spirit/include/phoenix_operator.hpp>
#include <boost/spirit/include/phoenix_fusion.hpp>
#include <boost/spirit/include/phoenix_stl.hpp>
#include <boost/spirit/include/phoenix_object.hpp>
#include <boost/fusion/include/adapt_struct.hpp>
#include <string>
#include <vector>
namespace client
{
namespace fusion = boost::fusion;
namespace phoenix = boost::phoenix;
namespace qi = boost::spirit::qi;
namespace ascii = boost::spirit::ascii;
typedef std::vector<std::string> predicate;
struct defmacro
{
std::string name; // identifier for macro
predicate params; // parameters for macro
};
typedef std::vector<defmacro> awe;
}
BOOST_FUSION_ADAPT_STRUCT(
client::defmacro,
(std::string, name)
(client::predicate, params)
)
namespace client
{
template <typename Iterator>
struct awe_grammar
: qi::grammar<Iterator, awe()>
{
awe_grammar()
: awe_grammar::base_type(start_)
{
using qi::lit;
using qi::eol;
using ascii::char_;
using ascii::blank;
using ascii::space;
using namespace qi::labels;
using phoenix::ref;
using phoenix::at_c;
line_no = 0;
eol_ = eol[++ref(line_no)];
identifier_ %= qi::lexeme[+(char_ - space)];
predicate_ %= (identifier_ % blank) >> eol_;
defmacro_line_ %=
lit("DEFMACRO ")
>> identifier_ >> ' '
>> predicate_
;
start_ %= +defmacro_line_;
}
long line_no;
qi::rule<Iterator, void() > eol_;
qi::rule<Iterator, defmacro() > defmacro_line_;
qi::rule<Iterator, awe() > start_;
qi::rule<Iterator, std::string()> identifier_;
qi::rule<Iterator, predicate() > predicate_;
};
}
and
#include <cstdlib>
#include <iostream>
#include "awe_grammar.h"
template <typename P, typename T>
void test_parser_attr(
char const* input, P const& p, T& attr, bool full_match = true)
{
using boost::spirit::qi::parse;
char const* f(input);
char const* l(f + strlen(f));
if (parse(f, l, p, attr) && (!full_match || (f == l)))
std::cout << "ok" << std::endl;
else
std::cout << "fail" << std::endl;
}
int main( /*int _argc, char * _argv[]*/ )
{
typedef client::awe_grammar<char const *> my_grammar;
my_grammar g;
client::awe result;
test_parser_attr(
"DEFMACRO macroname param1 param2 param3\n"
"DEFMACRO macro2 param1 param2\n",
g,
result,
true
);
////////////////////
// adding
////////////////////
boost::spirit::qi::symbols<char, client::defmacro> macros;
for (size_t i = 0; i < result.size(); i++)
{
macros.add(result[i].name, result[i]);
}
return EXIT_SUCCESS;
}
After that you can do with your macros what you want (for example, pass it to another grammar).
Try this:
// ******** This line will not compile *************************
using qi::_val;
defmacro_ = defmacro_line_[macros.add(at_c<0>(_val),_1)];
// *************************************************************