I am quite new to Spirit.
I am trying to use Qi to parse the argument for a CMD command in my embedded Tcl interpreter.
As some arguments may used multiple times, I will need a vector to store all arguments of the same sort.
This is a simplified example of my problem, where I try to store integers into a vector.
#include <boost/spirit/include/qi.hpp>
#include <boost/spirit/include/phoenix.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/support.hpp>
#include <boost/fusion/include/adapt_struct.hpp>
#include <boost/variant/recursive_variant.hpp>
using std::string;
using std::vector;
namespace {
namespace qi = boost::spirit::qi;
namespace phoenix = boost::phoenix;
namespace ascii = boost::spirit::ascii;
struct Argument {
vector<int> svDefine; // macro definitions
};
}
BOOST_FUSION_ADAPT_STRUCT
(
Argument,
(vector<int>, svDefine)
)
namespace {
typedef string::const_iterator SIter;
struct ArgParser : qi::grammar<SIter, Argument(), ascii::space_type> {
qi::rule<SIter, Argument(), ascii::space_type> start;
ArgParser() : ArgParser::base_type(start) {
using phoenix::at_c;
using qi::int_;
using phoenix::push_back;
using namespace qi::labels;
start = +("define" >> int_ [push_back(at_c<0>(_val), _1)]);
}
};
}
Compiling it with g++ 4.5.1 boost 1.51 generates lost of errors
In file included from /usr/include/boost/spirit/home/phoenix/container.hpp:10:0,
from /usr/include/boost/spirit/home/phoenix.hpp:12,
from /usr/include/boost/spirit/include/phoenix.hpp:13,
from qi_test.cpp:2:
.....
qi_test.cpp:43:64: instantiated from here
/usr/include/boost/spirit/home/phoenix/stl/container/container.hpp:492:40: error: ‘struct boost::fusion::vector<int>’ has no member named ‘push_back’
/usr/include/boost/spirit/home/phoenix/stl/container/container.hpp:492:40: error: return-statement with a value, in function returning 'void'
qi_test.cpp: In static member function ‘static
.....
qi_test.cpp:43:64: instantiated from here
qi_test.cpp:28:509: error: invalid initialization of reference of type boost::fusion::vector<int>&’ from expression of type ‘std::vector<int>’
Basically I am confused. No idea what is wrong.
You are mixing up two types of vector template classes here:
std::vector
and
boost::fusion::vector
if you just omit (comment out)
using std::vector;
things will probably become quite clear
Related
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.
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.
I'd like to process some template arguments by using boost::mpl::fold. At the moment, I'm still stuck to the sample provided by Boost as even that does not work for me. I get the following error:
..\src\main.cpp:18:32: error: template argument 2 is invalid
..\src\main.cpp:18:37: error: wrong number of template arguments (4, should be 3)
The following code is taken from http://www.boost.org/doc/libs/1_48_0/libs/mpl/doc/refmanual/fold.html
#include <string>
#include <iostream>
#include <boost/mpl/fold.hpp>
#include <boost/mpl/plus.hpp>
#include <boost/mpl/vector.hpp>
#include <boost/type_traits.hpp>
using namespace std;
using namespace boost;
using namespace boost::mpl;
using namespace boost::type_traits;
typedef vector<long,float,short,double,float,long,long double> types;
typedef fold<
types
, int_<0>
, if_< is_float<_2>,next<_1>,_1 >
>::type number_of_floats;
BOOST_MPL_ASSERT_RELATION( number_of_floats::value, ==, 4 );
int main(){
}
I'm running mingw 4.7.0 using the flag "-std=c++11". I found some other examples on the net but have not yet been successful in compiling anything useful. Any suggestions?
You are messing up the namespaces. Making a lot of symbols ambiguous.
Remove the using and the example works fine for me.
...
using namespace boost;
typedef mpl::vector<long,float,short,double,float,long,long double> types;
typedef mpl::fold<
types
, mpl::int_<0>
, mpl::if_< is_float<boost::mpl::_2>,boost::mpl::next<boost::mpl::_1>,boost::mpl::_1 >
>::type number_of_floats;
...
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)];
// *************************************************************
I'm trying to apply a transformation to an mpl::string, but can't get it to compile. I'm using MS VC++2010 and Boost 1.43.0. The code:
#include <boost/mpl/string.hpp>
#include <boost/mpl/vector_c.hpp>
#include <boost/mpl/transform.hpp>
#include <boost/mpl/plus.hpp>
#include <boost/mpl/arithmetic.hpp>
using namespace boost;
int main() {
// this compiles OK
typedef mpl::vector_c<int, 'abcd', 'efgh'> numbers;
typedef mpl::transform<numbers, mpl::plus<mpl::_1, mpl::int_<1> > >::type result_numbers;
// this doesn't (error C2039: 'value' : is not a member of 'boost::mpl::has_push_back_arg')
typedef mpl::string<'abcd', 'efgh'> chars;
typedef mpl::transform<chars, mpl::plus<mpl::_1, mpl::int_<1> > >::type result_chars;
}
I've posted the full error message at http://paste.ubuntu.com/447759/.
The MPL docs say that mpl::transform needs a Forward Sequence, and mpl::string is a Bidirectional Sequence, which I gather is a type of Forward Sequence, so I thought it'd work.
Am I doing something wrong, or is this outright impossible? If so, why?
Thanks!
Turns out that it works if I use transform_view.