How can use boost.spirit x3 to parse into structs like:
struct person{
std::string name;
std::vector<std::string> friends;
}
Coming from boost.spirit v2 I would use a grammar but since X3 doesnt support grammars I have no idea how to do this clean.
EDIT: It would be nice if someone could help me writing a parser parsing a list of strings and returns a person with the first string is the name and the res of the strings are in the friends vector.
Parsing with x3 is much simpler than it was with v2, so you shouldn't have too much trouble moving over. Grammars being gone is a good thing!
Here's how you can parse into a vector of strings:
//#define BOOST_SPIRIT_X3_DEBUG
#include <fstream>
#include <iostream>
#include <string>
#include <type_traits>
#include <vector>
#include <boost/fusion/include/adapt_struct.hpp>
#include <boost/fusion/include/io.hpp>
#include <boost/spirit/home/x3.hpp>
#include <boost/spirit/home/x3/support/ast/variant.hpp>
namespace x3 = boost::spirit::x3;
struct person
{
std::string name;
std::vector<std::string> friends;
};
BOOST_FUSION_ADAPT_STRUCT(
person,
(std::string, name)
(std::vector<std::string>, friends)
);
auto const name = x3::rule<struct name_class, std::string> { "name" }
= x3::raw[x3::lexeme[x3::alpha >> *x3::alnum]];
auto const root = x3::rule<struct person_class, person> { "person" }
= name >> *name;
int main(int, char**)
{
std::string const input = "bob john ellie";
auto it = input.begin();
auto end = input.end();
person p;
if (phrase_parse(it, end, root >> x3::eoi, x3::space, p))
{
std::cout << "parse succeeded" << std::endl;
std::cout << p.name << " has " << p.friends.size() << " friends." << std::endl;
}
else
{
std::cout << "parse failed" << std::endl;
if (it != end)
std::cout << "remaining: " << std::string(it, end) << std::endl;
}
return 0;
}
As you can see on Coliru, the output is :
parse succeeded
bob has 2 friends.
Related
I am still trying to wrap my head around Boost::Spirit.
I want to parse two words into a variable. When I can do that, into a struct.
The single word compiles, the Variable doesn't. Why?
#include <boost/spirit/include/qi.hpp>
#include <boost/tuple/tuple.hpp>
#include <string>
#include <iostream>
using namespace boost::spirit;
/*
class Syntax : public qi::parser{
};
*/
int main()
{
//get user input
std::string input;
std::getline(std::cin, input);
auto it = input.begin();
bool result;
//define grammar for a single word
auto word_grammar = +qi::alnum - qi::space;
std::string singleWord;
result = qi::parse(
it, input.end(),
word_grammar,
singleWord
);
if(!result){
std::cout << "Failed to parse a word" << '\n';
return -1;
}
std::cout << "\"" << singleWord << "\"" << '\n';
//Now parse two words into a variable
std::cout << "Variable:\n";
typedef boost::tuple<std::string, std::string> Variable;
Variable variable;
auto variable_grammar = word_grammar >> word_grammar;
result = qi::parse(
it, input.end(),
variable_grammar,
variable
);
if(!result){
std::cout << "Failed to parse a variable" << '\n';
return -1;
}
std::cout << "\"" << variable.get<0>() << "\" \"" << variable.get<1>() << "\"" << '\n';
//now parse a list of variables
std::cout << "List of Variables:\n";
std::list<Variable> variables;
result = qi::parse(
it, input.end(),
variable_grammar % +qi::space,
variable
);
if(!result){
std::cout << "Failed to parse a list of variables" << '\n';
return -1;
}
for(auto var : variables)
std::cout << "DataType: " << var.get<0>() << ", VariableName: " << var.get<1>() << '\n';
}
In the end I want to parse something like this:
int a
float b
string name
Templates are nice, but when problems occur the error messages are just not human readable (thus no point in posting them here).
I am using the gcc
Sorry to take so long. I've been building a new web server in a hurry and had much to learn.
Here is what it looks like in X3. I think it is easier to deal with than qi. And then, I've used it a lot more. But then qi is much more mature, richer. That said, x3 is meant to be adaptable, hackable. So you can make it do just about anything you want.
So, live on coliru
#include <string>
#include <iostream>
#include <vector>
#include <boost/spirit/home/x3.hpp>
#include <boost/tuple/tuple.hpp>
//as pointed out, for the error 'The parser expects tuple-like attribute type'
#include <boost/fusion/adapted/boost_tuple.hpp>
//our declarations
using Variable = boost::tuple<std::string, std::string>;
using Vector = std::vector<Variable>;
namespace parsers {
using namespace boost::spirit::x3;
auto const word = lexeme[+char_("a-zA-Z")];
//note, using 'space' as the stock skipper
auto const tuple = word >> word;
}
std::ostream& operator << (std::ostream& os, /*const*/ Variable& obj) {
return os << obj.get<0>() << ' ' << obj.get<1>();
}
std::ostream& operator << (std::ostream& os, /*const*/ Vector& obj) {
for (auto& item : obj)
os << item << " : ";
return os;
}
template<typename P, typename A>
bool test_parse(std::string in, P parser, A& attr) {
auto begin(in.begin());
bool r = phrase_parse(begin, in.end(), parser, boost::spirit::x3::space, attr);
std::cout << "result:\n " << attr << std::endl;
return r;
}
int main()
{
//not recomended but this is testing stuff
using namespace boost::spirit::x3;
using namespace parsers;
std::string input("first second third forth");
//parse one word
std::string singleWord;
test_parse(input, word, singleWord);
//parse two words into a variable
Variable variable;
test_parse(input, tuple, variable);
//parse two sets of two words
Vector vector;
test_parse(input, *tuple, vector);
}
You may like this form of testing. You can concentrate on testing parsers without a lot of extra code. It makes it easier down the road to keep your basic parsers in their own namespace. Oh yea, x3 compiles much faster than qi!
The single word compiles, the Variable doesn't. Why?
There are missing two #includes:
#include <boost/fusion/adapted/boost_tuple.hpp>
#include <boost/spirit/include/qi_list.hpp>
I'm trying to parse input which has either a plus or minus character, followed by an X or Y character, followed by an unsigned integer.
(char_('+') | char_('-')) >> char_("xyXY") >> uint_
According to my reading of the docs, the synthesised attribute for this would be tuple<vector<char>,unsigned int> because the alternative parser (char | char) would be of type char, the char >> char("xyXY") would be vector<char>, and the vector<char> >> uint_ would be a tuple of the types, so tuple<vector<char>,unsigned int>. This fails to compile
qi\detail\assign_to.hpp(152) : error C2440: 'static_cast' : cannot convert from 'const char' to 'boost::tuples::tuple<T0,T1>'
Code:
#include <iostream>
#include <string>
#include <vector>
#include <boost/fusion/include/tuple.hpp>
#include <boost/spirit/include/qi.hpp>
#include <boost/tuple/tuple.hpp>
using namespace boost::spirit::qi;
int main()
{
std::string input("-Y 512");
typedef std::string::const_iterator Iterator;
Iterator first = input.begin();
Iterator last = input.end();
boost::tuple<std::vector<char>,unsigned int> output;
bool result = phrase_parse(first,last,(char_('+') | char_('-')) >> char_("xyXY") >> uint_,ascii::space,output);
if(result && first == last)
std::cout << "sign=" << boost::get<0>(output)[0] << ", xy=" << boost::get<0>(output)[1] << ", size=" << boost::get<1>(output) << '\n';
else
std::cerr << "Parse error\n";
}
I then tried tuple<char,char,unsigned int> as the attribute type:
#include <iostream>
#include <string>
#include <vector>
#include <boost/fusion/include/tuple.hpp>
#include <boost/spirit/include/qi.hpp>
#include <boost/tuple/tuple.hpp>
using namespace boost::spirit::qi;
int main()
{
std::string input("-Y 512");
typedef std::string::const_iterator Iterator;
Iterator first = input.begin();
Iterator last = input.end();
boost::tuple<char,char,unsigned int> output;
bool result = phrase_parse(first,last,(char_('+') | char_('-')) >> char_("xyXY") >> uint_,ascii::space,output);
if(result && first == last)
std::cout << "sign=" << boost::get<0>(output) << ", xy=" << boost::get<1>(output) << ", size=" << boost::get<2>(output) << '\n';
else
std::cerr << "Parse error\n";
}
This compiles but the output is incorrect. The first token of the input is parsed correctly, but the subsequent tokens aren't:
sign=-, xy= , size=0
I also tried as_string[]:
#include <iostream>
#include <string>
#include <vector>
#include <boost/fusion/include/tuple.hpp>
#include <boost/spirit/include/qi.hpp>
#include <boost/tuple/tuple.hpp>
using namespace boost::spirit::qi;
int main()
{
std::string input("-Y 512");
typedef std::string::const_iterator Iterator;
Iterator first = input.begin();
Iterator last = input.end();
boost::tuple<std::string,unsigned int> output;
bool result = phrase_parse(first,last,as_string[(char_('+') | char_('-')) >> char_("xyXY")] >> uint_,ascii::space,output);
if(result && first == last)
std::cout << "sign=" << boost::get<0>(output)[0] << ", xy=" << boost::get<0>(output)[1] << ", size=" << boost::get<1>(output) << '\n';
else
std::cerr << "Parse error\n";
}
This improved things as the x/y token got parsed, but not the third integer token:
sign=-, xy=Y, size=0
Please show me where I'm going wrong.
I'm using Spirit version 2.5.2 (from Boost 1.58.0) and Microsoft Visual Studio 2008.
Spirit library docs recommend to use Fusion tuple. I think I saw somewhere (can't find it now) that Boost tuple may not be fully compatible with Spirit library.
Here is your fixed example:
#include <iostream>
#include <string>
#include <vector>
#include <boost/fusion/include/tuple.hpp>
#include <boost/spirit/include/qi.hpp>
#include <boost/fusion/sequence.hpp>
namespace qi = boost::spirit::qi;
int main()
{
std::string input("-Y 512");
typedef std::string::const_iterator Iterator;
Iterator first = input.begin();
Iterator last = input.end();
boost::fusion::tuple<char, char, unsigned int> output;
bool result = qi::phrase_parse(first, last, (qi::char_('+') | qi::char_('-')) >> qi::char_("xyXY") >> qi::uint_, qi::ascii::space, output);
if (result && first == last)
std::cout << "sign=" << boost::fusion::get<0>(output) << ", xy=" << boost::fusion::get<1>(output) << ", size=" << boost::fusion::get<2>(output) << '\n';
else
std::cerr << "Parse error\n";
return 0;
}
Output:
sign=-, xy=Y, size=512
Update: Actually I found here that it's possible to use boost::tuple but different header needs to be included: #include <boost/fusion/include/boost_tuple.hpp>.
I am trying to learn Boost.Spirit, but I have found a difficulty.
I am trying to parse a string into the following structure:
struct employee {
std::string name;
std::string location;
};
And it seems that when two attributes with the same type are back to back, they collapse (logically) into a std::vector of that type. Because of that rule, the following parser
+x3::ascii::alnum >>
+x3::space >>
+x3::ascii::alnum
would have the attribute of std::vector<std::string>.
But I am trying to parse this into that struct, which means that the ideal attribute for me would be a boost::fusion::tuple<std::string, std::string>, so I can adapt my struct to it.
The complete version of the not working code (referenced above):
// Example program
#include <iostream>
#include <string>
#include <boost/spirit/home/x3.hpp>
#include <boost/fusion/include/adapt_struct.hpp>
struct employee {
std::string name;
std::string location;
};
BOOST_FUSION_ADAPT_STRUCT(employee,
(std::string, name),
(std::string, location)
)
namespace x3 = boost::spirit::x3;
x3::rule<struct parse_emp_id, employee> const parse_emp = "Employee Parser";
auto parse_emp_def =
+x3::ascii::alnum >>
+x3::space >>
+x3::ascii::alnum
;
BOOST_SPIRIT_DEFINE(parse_emp);
int main()
{
std::string input = "Joe Fairbanks";
employee ret;
x3::parse(input.begin(), input.end(), parse_emp, ret);
std::cout << "Name: " << ret.name << "\tLocation: " << ret.location << std::endl;
}
See it live
This code triggers a static_assert telling me that my attribute isn't correct:
error: static_assert failed "Attribute does not have the expected size."
With the command of
clang++ -std=c++14 test.cpp
(it also fails under GCC).
What I have tried
I have found a workaround to this problem, but it is messy, and I can't believe that this is the cleanest way:
// Example program
#include <iostream>
#include <string>
#include <boost/spirit/home/x3.hpp>
#include <boost/fusion/include/adapt_struct.hpp>
struct employee {
std::string name;
std::string location;
};
namespace x3 = boost::spirit::x3;
x3::rule<struct parse_emp_id, employee> const parse_emp = "Employee Parser";
auto parse_emp_def =
x3::eps [
([](auto& ctx) {
x3::_val(ctx) = employee{};
})
]>>
(+x3::ascii::alnum)[
([](auto& ctx) {
x3::_val(ctx).name = x3::_attr(ctx);
})
]>>
+x3::space >>
(+x3::ascii::alnum)[
([](auto& ctx) {
x3::_val(ctx).location = x3::_attr(ctx);
})
]
;
BOOST_SPIRIT_DEFINE(parse_emp);
int main()
{
std::string input = "Joe Fairbanks";
employee ret;
x3::parse(input.begin(), input.end(), parse_emp, ret);
std::cout << "Name: " << ret.name << "\tLocation: " << ret.location << std::endl;
}
See it live
I really don't like that solution: it kinda ruins the amazing expressiveness of spirit and makes it super ugly, also if I want to add new fields into the employee struct, then I have to add an extra lambda, instead of just updating my BOOST_FUSION_ADAPT_STRUCT, which is much easier.
So the question is: Is there some way to (hopefully) cleanly split two consecutive attributes of the same type from the std::vector and into a boost::fusion::vector?
Thank you in advance for getting this far ;).
The problem is that unlike character literals, x3::space has an attribute. So you don't have an attribute of two separate character sequences separated by whitespace, but rather an attribute of one big character sequence which includes the whitespace.
The omit directive is what you're after, and with that single addition your 'not working code' works. :-]
// Example program
#include <string>
#include <iostream>
#include <boost/fusion/include/adapt_struct.hpp>
#include <boost/spirit/home/x3.hpp>
namespace x3 = boost::spirit::x3;
struct employee {
std::string name;
std::string location;
};
BOOST_FUSION_ADAPT_STRUCT(employee, name, location)
x3::rule<struct parse_emp_id, employee> const parse_emp = "Employee Parser";
auto parse_emp_def
= +x3::ascii::alnum
>> x3::omit[+x3::space]
>> +x3::ascii::alnum
;
BOOST_SPIRIT_DEFINE(parse_emp)
int main()
{
std::string const input = "Joe Fairbanks";
employee ret;
x3::parse(input.begin(), input.end(), parse_emp, ret);
std::cout << "Name: " << ret.name << "\tLocation: " << ret.location << '\n';
}
Online Demo
I am trying to use Boost Spirit X3 with semantic actions while parsing the structure to an AST. If I use a rule without separate definition and instantiation it works just fine, for example:
#include <vector>
#include <string>
#include <iostream>
#include <boost/fusion/include/adapt_struct.hpp>
#include <boost/spirit/home/x3.hpp>
namespace ast
{
struct ast_struct
{
int number;
std::vector<int> numbers;
};
}
BOOST_FUSION_ADAPT_STRUCT(
ast::ast_struct,
(int, number)
(std::vector<int>, numbers)
)
namespace x3 = boost::spirit::x3;
using namespace std;
void parse( const std::string &data )
{
string::const_iterator begin = data.begin();
string::const_iterator end = data.end();
unsigned n(0);
auto f = [&n]( auto &ctx )
{
n = x3::_attr(ctx);
};
ast::ast_struct ast;
bool r = x3::parse( begin, end,
x3::int_[f] >> +( x3::omit[+x3::blank] >> x3::int_ ), ast );
if ( r && begin == end )
{
cout << "n: " << n << ", ";
std::copy(ast.numbers.begin(), ast.numbers.end(),
std::ostream_iterator<int>(std::cout << ast.numbers.size() << " elements: ", " "));
cout << endl;
}
else
cout << "Parse failed" << endl;
}
int main()
{
parse( "3 1 2 3" );
parse( "4 1 2 3 4" );
return 0;
}
Running the code above (compiled with flags -std=c++14) outputs the expected result:
n: 3, 3 elements: 1 2 3
n: 4, 4 elements: 1 2 3 4
Now I am trying to have my Spirit X3 parser organized more or less the same way as the calc 9 example from Boost Spirit X3, but it does not work:
ast.hxx: defines the abstract syntax tree.
grammar.hxx: user interface exposing the parser methods.
grammar.cxx: instantiates the rules.
grammar_def.hxx: parser grammar definition.
config.hxx: parser configuration.
main.cxx: parser usage example.
ast.hxx:
#ifndef AST_HXX
#define AST_HXX
#include <vector>
#include <boost/fusion/include/adapt_struct.hpp>
namespace ast
{
struct ast_struct
{
int number;
std::vector<int> numbers;
};
}
BOOST_FUSION_ADAPT_STRUCT(
ast::ast_struct,
(int, number)
(std::vector<int>, numbers)
)
#endif
grammar.hxx:
#ifndef GRAMMAR_HXX
#define GRAMMAR_HXX
#include "ast.hxx"
#include <boost/spirit/home/x3.hpp>
namespace parser
{
namespace x3 = boost::spirit::x3;
using my_rule_type = x3::rule<class my_rule_class, ast::ast_struct>;
BOOST_SPIRIT_DECLARE( my_rule_type );
const my_rule_type &get_my_rule();
}
#endif
grammar.cxx:
#include "grammar_def.hxx"
#include "config.hxx"
namespace parser
{
BOOST_SPIRIT_INSTANTIATE( my_rule_type, iterator_type, context_type )
}
grammar_def.hxx:
#ifndef GRAMMAR_DEF_HXX
#define GRAMMAR_DEF_HXX
#include <iostream>
#include <boost/spirit/home/x3.hpp>
#include "grammar.hxx"
#include "ast.hxx"
namespace parser
{
namespace x3 = boost::spirit::x3;
const my_rule_type my_rule( "my_rule" );
unsigned n;
auto f = []( auto &ctx )
{
n = x3::_attr(ctx);
};
auto my_rule_def = x3::int_[f] >> +( x3::omit[+x3::blank] >> x3::int_ );
BOOST_SPIRIT_DEFINE( my_rule )
const my_rule_type &get_my_rule()
{
return my_rule;
}
}
#endif
config.hxx:
#ifndef CONFIG_HXX
#define CONFIG_HXX
#include <string>
#include <boost/spirit/home/x3.hpp>
namespace parser
{
namespace x3 = boost::spirit::x3;
using iterator_type = std::string::const_iterator;
using context_type = x3::unused_type;
}
#endif
main.cxx:
#include "ast.hxx"
#include "grammar.hxx"
#include "config.hxx"
#include <iostream>
#include <boost/spirit/home/x3.hpp>
#include <string>
namespace x3 = boost::spirit::x3;
using namespace std;
void parse( const std::string &data )
{
parser::iterator_type begin = data.begin();
parser::iterator_type end = data.end();
ast::ast_struct ast;
cout << "Parsing [" << string(begin,end) << "]" << endl;
bool r = x3::parse( begin, end, parser::get_my_rule(), ast );
if ( r && begin == end )
{
std::copy(ast.numbers.begin(), ast.numbers.end(),
std::ostream_iterator<int>(std::cout << ast.numbers.size() << " elements: ", " "));
cout << endl;
}
else
cout << "Parse failed" << endl;
}
int main()
{
parse( "3 1 2 3" );
parse( "4 1 2 3 4" );
return 0;
}
Compiling main.cxx and grammar.cxx (flags: -std=c++14) and running the code above prints:
Parsing [3 1 2 3]
0 elements:
Parsing [4 1 2 3 4]
0 elements:
I apologize for the long source code, I tried to make it as small as possible.
Please notice I have some usage for the unsigned n global variable, it will be used with a custom repeat directive (see question here and one of the solutions here). In order to keep the question focused I removed the repeat part from this question, so even though I could remove the semantic action in this example, it is not a possible solution.
I would appreciate some help to get this issue uncovered, it is not clear to me why the code above does not work. Thank you in advance.
I must admit actually reconstructing your sample was a bit too much work for me (call me lazy...).
However, I know the answer and a trick to make your life simpler.
The Answer
Semantic actions on a rule definition inhibit automatic attribute propagation. From the Qi docs (the same goes for X3, but I always lose the link to the docs):
r = p; Rule definition
This is equivalent to r %= p (see below) if there are no semantic actions attached anywhere in p.
r %= p; Auto-rule definition
The attribute of p should be compatible with the synthesized attribute of r. When p is successful, its attribute is automatically propagated to r's synthesized attribute.
The Trick
You can inject state (your n reference, in this case) using the x3::with<> directive. That way you don't have the namespace global (n) and can make the parser reentrant, threadsafe etc.
Here's my "simplist" take on things, in a single file:
namespace parsing {
x3::rule<struct parser, ast::ast_struct> parser {"parser"};
struct state_tag { };
auto record_number = [](auto &ctx) {
unsigned& n = x3::get<state_tag>(ctx);
n = x3::_attr(ctx);
};
auto parser_def = x3::rule<struct parser_def, ast::ast_struct> {}
%= x3::int_[record_number] >> +(x3::omit[+x3::blank] >> x3::int_);
BOOST_SPIRIT_DEFINE(parser)
}
Tip: run the demo with = instead of the %= to see the difference in behaviour!
Note that get<state_tag>(ctx) returns a reference_wrapper<unsigned> just because we use the parser as follows:
void parse(const std::string &data) {
using namespace std;
ast::ast_struct ast;
unsigned n;
auto parser = x3::with<parsing::state_tag>(ref(n)) [parsing::parser] >> x3::eoi;
if (x3::parse(data.begin(), data.end(), parser, ast)) {
cout << "n: " << n << ", ";
copy(ast.numbers.begin(), ast.numbers.end(), ostream_iterator<int>(cout << ast.numbers.size() << " elements: ", " "));
cout << "\n";
} else
cout << "Parse failed\n";
}
Live Demo
Live On Coliru
#include <boost/fusion/include/adapt_struct.hpp>
#include <boost/spirit/home/x3.hpp>
#include <iostream>
namespace ast {
struct ast_struct {
int number;
std::vector<int> numbers;
};
}
BOOST_FUSION_ADAPT_STRUCT(ast::ast_struct, number, numbers)
namespace x3 = boost::spirit::x3;
namespace parsing {
x3::rule<struct parser, ast::ast_struct> parser {"parser"};
struct state_tag { };
auto record_number = [](auto &ctx) {
unsigned& n = x3::get<state_tag>(ctx); // note: returns reference_wrapper<T>
n = x3::_attr(ctx);
};
auto parser_def = x3::rule<struct parser_def, ast::ast_struct> {}
%= x3::int_[record_number] >> +(x3::omit[+x3::blank] >> x3::int_);
BOOST_SPIRIT_DEFINE(parser)
}
void parse(const std::string &data) {
using namespace std;
ast::ast_struct ast;
unsigned n = 0;
auto parser = x3::with<parsing::state_tag>(ref(n)) [parsing::parser] >> x3::eoi;
if (x3::parse(data.begin(), data.end(), parser, ast)) {
cout << "n: " << n << ", ";
copy(ast.numbers.begin(), ast.numbers.end(), ostream_iterator<int>(cout << ast.numbers.size() << " elements: ", " "));
cout << "\n";
} else
cout << "Parse failed\n";
}
int main() {
parse("3 1 2 3");
parse("4 1 2 3 4");
}
Prints
n: 3, 3 elements: 1 2 3
n: 4, 4 elements: 1 2 3 4
I have the following code:
#include <boost/fusion/include/adapt_struct.hpp>
#include <boost/fusion/include/io.hpp>
#include <boost/spirit/include/qi.hpp>
#include <iostream>
#include <string>
struct function
{
std::string ret_type;
std::string name;
};
BOOST_FUSION_ADAPT_STRUCT(
::function,
(std::string, ret_type)
(std::string, name)
)
template <typename Iterator>
struct function_parser : boost::spirit::qi::grammar<Iterator, function(), boost::spirit::qi::ascii::space_type>
{
function_parser() : function_parser::base_type(start)
{
using boost::spirit::qi::ascii::char_;
using boost::spirit::qi::int_;
start %= +char_ >> +char_;
}
boost::spirit::qi::rule<Iterator, function(), boost::spirit::qi::ascii::space_type> start;
};
int main()
{
std::string input_data("void foo");
function fn;
auto itr = input_data.begin();
auto end = input_data.end();
function_parser<decltype(itr)> g;
bool res = boost::spirit::qi::phrase_parse(itr, end, g, boost::spirit::ascii::space, fn);
if (res && itr == end)
{
std::cout << boost::fusion::tuple_open('[');
std::cout << boost::fusion::tuple_close(']');
std::cout << boost::fusion::tuple_delimiter(", ");
std::cout << "Parsing succeeded\n";
std::cout << "got: " << boost::fusion::as_vector(fn) << std::endl;
}
else
{
std::cout << "Parsing failed \n";
}
}
Output
Parsing failed
What am I doing wrong? How can I fix it?
+char_
eats all input! Now, the next
+char_
requires at least a single character, which isn't there (the first kleen plus ate it) so the parse fails.
I suggest instead:
using namespace boost::spirit::qi;
start = lexeme[+graph] >> lexeme[+graph];
The documentation should be able to tell you what that does (I hope. No time to elaborate)