unable to decipher compile error when using boost.spirit.parser - c++

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.

Related

use Boost.Spirit.Qi to parse into vector

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

boost::bind does not compile

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.

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)];
// *************************************************************