How can I extract std::string object via boost spirit - c++

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)

Related

What's the appropriate way to indicate a Qi transform attribute fail?

What's the proper way to indicate a parse fail in a boost::spirit::traits::transform_attribute? Can I throw any old exception, or is there a specific thing it wants me to do?
namespace boost
{
namespace spirit
{
namespace traits
{
template <>
struct transform_attribute<TwoNums, std::vector<char>, qi::domain>
{
typedef std::vector<char> type;
static type pre(TwoWords&) { return{}; }
static void post(TwoWords& val, type const& attr) {
std::string stringed(attr.begin(), attr.end());
//https://stackoverflow.com/questions/236129/the-most-elegant-way-to-iterate-the-words-of-a-string
std::vector<std::string> strs;
boost::split(strs, stringed, ",");
if(strs.size()!=2)
{
//What do I do here?
}
val = TwoWords(strs[0],strs[1]);
}
static void fail(FDate&) { }
};
}
}
}
Yes, raising an exception seems the only out-of-band way.
You could use qi::on_error to trap and respond to it.
However, it's a bit unclear what you need this for. It seems a bit upside down to use split inside a parser. Splitting is basically a poor version of parsing.
Why not have a rule for the sub-parsing?
1. Simple Throw...
Live On Coliru
#include <boost/algorithm/string.hpp>
#include <boost/spirit/include/qi.hpp>
#include <iomanip>
namespace qi = boost::spirit::qi;
struct Invalid {};
struct TwoWords {
std::string one, two;
};
namespace boost { namespace spirit { namespace traits {
template <> struct transform_attribute<TwoWords, std::vector<char>, qi::domain> {
typedef std::vector<char> type;
static type pre(TwoWords &) { return {}; }
static void post(TwoWords &val, type const &attr) {
std::string stringed(attr.begin(), attr.end());
std::vector<std::string> strs;
boost::split(strs, stringed, boost::is_any_of(","));
if (strs.size() != 2) {
throw Invalid{};
}
val = TwoWords{ strs.at(0), strs.at(1) };
}
static void fail(TwoWords &) {}
};
} } }
template <typename It>
struct Demo1 : qi::grammar<It, TwoWords()> {
Demo1() : Demo1::base_type(start) {
start = qi::attr_cast<TwoWords>(+qi::char_);
}
private:
qi::rule<It, TwoWords()> start;
};
int main() {
Demo1<std::string::const_iterator> parser;
for (std::string const input : { ",", "a,b", "a,b,c" }) {
std::cout << "Parsing " << std::quoted(input) << " -> ";
TwoWords tw;
try {
if (parse(input.begin(), input.end(), parser, tw)) {
std::cout << std::quoted(tw.one) << ", " << std::quoted(tw.two) << "\n";
} else {
std::cout << "Failed\n";
}
} catch(Invalid) {
std::cout << "Input invalid\n";
}
}
}
Prints
Parsing "," -> "", ""
Parsing "a,b" -> "a", "b"
Parsing "a,b,c" -> Input invalid
2. Handling Errors Inside The Parser
This feels a bit hacky because it will require you to throw a expectation_failure.
This is not optimal since it assumes you know the iterator the parser is going to be instantiated with.
on_error was designed for use with expectation points
*Live On Coliru
#include <boost/algorithm/string.hpp>
#include <boost/spirit/include/qi.hpp>
#include <iomanip>
namespace qi = boost::spirit::qi;
struct Invalid {};
struct TwoWords {
std::string one, two;
};
namespace boost { namespace spirit { namespace traits {
template <> struct transform_attribute<TwoWords, std::vector<char>, qi::domain> {
typedef std::vector<char> type;
static type pre(TwoWords &) { return {}; }
static void post(TwoWords &val, type const &attr) {
std::string stringed(attr.begin(), attr.end());
std::vector<std::string> strs;
boost::split(strs, stringed, boost::is_any_of(","));
if (strs.size() != 2) {
throw qi::expectation_failure<std::string::const_iterator>({}, {}, info("test"));
}
val = TwoWords{ strs.at(0), strs.at(1) };
}
static void fail(TwoWords &) {}
};
} } }
template <typename It>
struct Demo2 : qi::grammar<It, TwoWords()> {
Demo2() : Demo2::base_type(start) {
start = qi::attr_cast<TwoWords>(+qi::char_);
qi::on_error(start, [](auto&&...){});
// more verbose spelling:
// qi::on_error<qi::error_handler_result::fail> (start, [](auto&&...){[>no-op<]});
}
private:
qi::rule<It, TwoWords()> start;
};
int main() {
Demo2<std::string::const_iterator> parser;
for (std::string const input : { ",", "a,b", "a,b,c" }) {
std::cout << "Parsing " << std::quoted(input) << " -> ";
TwoWords tw;
try {
if (parse(input.begin(), input.end(), parser, tw)) {
std::cout << std::quoted(tw.one) << ", " << std::quoted(tw.two) << "\n";
} else {
std::cout << "Failed\n";
}
} catch(Invalid) {
std::cout << "Input invalid\n";
}
}
}
Prints
Parsing "," -> "", ""
Parsing "a,b" -> "a", "b"
Parsing "a,b,c" -> Failed
3. Finally: Sub-rules Rule!
Let's assume a slightly more interesting grammar in which you have a ; separated list of TwoWords:
"foo,bar;a,b"
We parse into a vector of TwoWords:
using Word = std::string;
struct TwoWords { std::string one, two; };
using TwoWordses = std::vector<TwoWords>;
Instead of using traits to "coerce" attributes, we just adapt the struct and rely on automatic attribute propagation:
BOOST_FUSION_ADAPT_STRUCT(TwoWords, one, two)
The parser mimics the data-types:
template <typename It>
struct Demo3 : qi::grammar<It, TwoWordses()> {
Demo3() : Demo3::base_type(start) {
using namespace qi;
word = *(graph - ',' - ';');
twowords = word >> ',' >> word;
start = twowords % ';';
}
private:
qi::rule<It, Word()> word;
qi::rule<It, TwoWords()> twowords;
qi::rule<It, TwoWordses()> start;
};
And the full test is Live On Coliru
#include <boost/fusion/adapted/struct.hpp>
#include <boost/spirit/include/qi.hpp>
#include <iomanip>
namespace qi = boost::spirit::qi;
using Word = std::string;
struct TwoWords { std::string one, two; };
using TwoWordses = std::vector<TwoWords>;
BOOST_FUSION_ADAPT_STRUCT(TwoWords, one, two);
template <typename It>
struct Demo3 : qi::grammar<It, TwoWordses()> {
Demo3() : Demo3::base_type(start) {
using namespace qi;
word = *(graph - ',' - ';');
twowords = word >> ',' >> word;
start = twowords % ';';
}
private:
qi::rule<It, Word()> word;
qi::rule<It, TwoWords()> twowords;
qi::rule<It, TwoWordses()> start;
};
int main() {
using It = std::string::const_iterator;
Demo3<It> parser;
for (std::string const input : {
",",
"foo,bar",
"foo,bar;qux,bax",
"foo,bar;qux,bax;err,;,ful",
// failing cases or cases with trailing input:
"",
"foo,bar;",
"foo,bar,qux",
})
{
std::cout << "Parsing " << std::quoted(input) << " ->\n";
TwoWordses tws;
It f = input.begin(), l = input.end();
if (parse(f, l, parser, tws)) {
for(auto& tw : tws) {
std::cout << " - " << std::quoted(tw.one) << ", " << std::quoted(tw.two) << "\n";
}
} else {
std::cout << "Failed\n";
}
if (f != l) {
std::cout << "Remaining unparsed input: " << std::quoted(std::string(f,l)) << "\n";
}
}
}
Prints
Parsing "," ->
- "", ""
Parsing "foo,bar" ->
- "foo", "bar"
Parsing "foo,bar;qux,bax" ->
- "foo", "bar"
- "qux", "bax"
Parsing "foo,bar;qux,bax;err,;,ful" ->
- "foo", "bar"
- "qux", "bax"
- "err", ""
- "", "ful"
Parsing "" ->
Failed
Parsing "foo,bar;" ->
- "foo", "bar"
Remaining unparsed input: ";"
Parsing "foo,bar,qux" ->
- "foo", "bar"
Remaining unparsed input: ",qux"

Parsing into structs with containers

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.

Learning Boost.Spirit: parsing INI

I started to learn Boost.Spirit and finish reading Qi - Writing Parsers section. When reading, everything is easy and understandable. But when I try to do something, there are a lot of errors, because there are too many includes and namespaces and I need to know when to include/use them. As the practice, I want to write simple INI parser.
Here is the code (includes are from one of examples inside Spirit lib as almost everything else):
#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_stl.hpp>
#include <boost/fusion/adapted/std_pair.hpp>
#include <boost/fusion/include/adapt_struct.hpp>
#include <boost/spirit/include/phoenix_object.hpp>
#include <iostream>
#include <string>
#include <vector>
#include <map>
namespace client
{
typedef std::map<std::string, std::string> key_value_map_t;
struct mini_ini
{
std::string name;
key_value_map_t key_values_map;
};
} // client
BOOST_FUSION_ADAPT_STRUCT(
client::mini_ini,
(std::string, name)
(client::key_value_map_t, key_values_map)
)
namespace client
{
namespace qi = boost::spirit::qi;
namespace ascii = boost::spirit::ascii;
namespace phoenix = boost::phoenix;
template <typename Iterator>
struct ini_grammar : qi::grammar<Iterator, mini_ini(), ascii::space_type>
{
ini_grammar() : ini_grammar::base_type(section_, "section")
{
using qi::char_;
using qi::on_error;
using qi::fail;
using namespace qi::labels;
using phoenix::construct;
using phoenix::val;
key_ = +char_("a-zA-Z_0-9");
pair_ = key_ >> '=' >> *char_;
section_ = '[' >> key_ >> ']' >> '\n' >> *(pair_ >> '\n');
key_.name("key");
pair_.name("pair");
section_.name("section");
on_error<fail>
(
section_
, std::cout
<< val("Error! Expecting ")
<< _4 // what failed?
<< val(" here: \"")
<< construct<std::string>(_3, _2) // iterators to error-pos, end
<< val("\"")
<< std::endl
);
}
qi::rule<Iterator, std::string(), ascii::space_type> key_;
qi::rule<Iterator, mini_ini(), ascii::space_type> section_;
qi::rule<Iterator, std::pair<std::string, std::string>(), ascii::space_type> pair_;
};
} // client
int
main()
{
std::string storage =
"[section]\n"
"key1=val1\n"
"key2=val2\n";
client::mini_ini ini;
typedef client::ini_grammar<std::string::const_iterator> ini_grammar;
ini_grammar grammar;
using boost::spirit::ascii::space;
std::string::const_iterator iter = storage.begin();
std::string::const_iterator end = storage.end();
bool r = phrase_parse(iter, end, grammar, space, ini);
if (r && iter == end)
{
std::cout << "-------------------------\n";
std::cout << "Parsing succeeded\n";
std::cout << "-------------------------\n";
return 0;
}
else
{
std::cout << "-------------------------\n";
std::cout << "Parsing failed\n";
std::cout << "-------------------------\n";
std::cout << std::string(iter, end) << "\n";
return 1;
}
return 0;
}
As u can see I want to parse next text into mini_ini struct:
"[section]"
"key1=val1"
"key2=val2";
I have the fail and std::string(iter, end) is full input string.
My questions:
Why I see fail but don't see on_error<fail> handler ?
Have you any recommendations how to learn Boost.Spirit (I have good understanding of documentation in theory, but in practice I have a lot of WHY ???) ?
Thanks
Q. Why I see fail but don't see on_error handler
The on_error handler is only fired for the registered rule (section_) and if an expectation point is failed.
Your grammar doesn't contain expectation points (only >> are used, not >).
Q. Have you any recommendations how to learn Boost.Spirit (I have good understanding of documentation in theory, but in practice I have a lot of WHY ???) ?
Just build the parsers you need. Copy good conventions from the docs and SO answers. There are a lot of them. As you have seen, quite a number contain full examples of Ini parsers with varying levels of error reporting too.
Bonus hints:
Do more detailed status reporting:
bool ok = phrase_parse(iter, end, grammar, space, ini);
if (ok) {
std::cout << "Parse success\n";
} else {
std::cout << "Parse failure\n";
}
if (iter != end) {
std::cout << "Remaining unparsed: '" << std::string(iter, end) << "'\n";
}
return ok && (iter==end)? 0 : 1;
Use BOOST_SPIRIT_DEBUG:
#define BOOST_SPIRIT_DEBUG
// and later
BOOST_SPIRIT_DEBUG_NODES((key_)(pair_)(section_))
Prints:
<section_>
<try>[section]\nkey1=val1\n</try>
<key_>
<try>section]\nkey1=val1\nk</try>
<success>]\nkey1=val1\nkey2=val</success>
<attributes>[[s, e, c, t, i, o, n]]</attributes>
</key_>
<fail/>
</section_>
Parse failure
Remaining unparsed: '[section]
key1=val1
key2=val2
'
You'll notice that the section header isn't parsed because the newline is not matched. Your skipper (space_type) skips the newline, hence it will never match: Boost spirit skipper issues
Fix skipper
When using blank_type as the skipper you'll get a successful parse:
<section_>
<try>[section]\nkey1=val1\n</try>
<key_>
<try>section]\nkey1=val1\nk</try>
<success>]\nkey1=val1\nkey2=val</success>
<attributes>[[s, e, c, t, i, o, n]]</attributes>
</key_>
<pair_>
<try>key1=val1\nkey2=val2\n</try>
<key_>
<try>key1=val1\nkey2=val2\n</try>
<success>=val1\nkey2=val2\n</success>
<attributes>[[k, e, y, 1]]</attributes>
</key_>
<success></success>
<attributes>[[[k, e, y, 1], [v, a, l, 1,
, k, e, y, 2, =, v, a, l, 2,
]]]</attributes>
</pair_>
<success>key1=val1\nkey2=val2\n</success>
<attributes>[[[s, e, c, t, i, o, n], []]]</attributes>
</section_>
Parse success
Remaining unparsed: 'key1=val1
key2=val2
NOTE: The parse succeeds but doesn't do what you want. This is because *char_ includes newlines. So make that
pair_ = key_ >> '=' >> *(char_ - qi::eol); // or
pair_ = key_ >> '=' >> *~char_("\r\n"); // etc
Full code
Live On Coliru
#define BOOST_SPIRIT_DEBUG
#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_stl.hpp>
#include <boost/fusion/adapted/std_pair.hpp>
#include <boost/fusion/include/adapt_struct.hpp>
#include <boost/spirit/include/phoenix_object.hpp>
#include <iostream>
#include <string>
#include <vector>
#include <map>
namespace client
{
typedef std::map<std::string, std::string> key_value_map_t;
struct mini_ini
{
std::string name;
key_value_map_t key_values_map;
};
} // client
BOOST_FUSION_ADAPT_STRUCT(
client::mini_ini,
(std::string, name)
(client::key_value_map_t, key_values_map)
)
namespace client
{
namespace qi = boost::spirit::qi;
namespace ascii = boost::spirit::ascii;
namespace phoenix = boost::phoenix;
template <typename Iterator>
struct ini_grammar : qi::grammar<Iterator, mini_ini(), ascii::blank_type>
{
ini_grammar() : ini_grammar::base_type(section_, "section")
{
using qi::char_;
using qi::on_error;
using qi::fail;
using namespace qi::labels;
using phoenix::construct;
using phoenix::val;
key_ = +char_("a-zA-Z_0-9");
pair_ = key_ >> '=' >> *char_;
section_ = '[' >> key_ >> ']' >> '\n' >> *(pair_ >> '\n');
BOOST_SPIRIT_DEBUG_NODES((key_)(pair_)(section_))
on_error<fail>
(
section_
, std::cout
<< val("Error! Expecting ")
<< _4 // what failed?
<< val(" here: \"")
<< construct<std::string>(_3, _2) // iterators to error-pos, end
<< val("\"")
<< std::endl
);
}
qi::rule<Iterator, std::string(), ascii::blank_type> key_;
qi::rule<Iterator, mini_ini(), ascii::blank_type> section_;
qi::rule<Iterator, std::pair<std::string, std::string>(), ascii::blank_type> pair_;
};
} // client
int
main()
{
std::string storage =
"[section]\n"
"key1=val1\n"
"key2=val2\n";
client::mini_ini ini;
typedef client::ini_grammar<std::string::const_iterator> ini_grammar;
ini_grammar grammar;
using boost::spirit::ascii::blank;
std::string::const_iterator iter = storage.begin();
std::string::const_iterator end = storage.end();
bool ok = phrase_parse(iter, end, grammar, blank, ini);
if (ok) {
std::cout << "Parse success\n";
} else {
std::cout << "Parse failure\n";
}
if (iter != end) {
std::cout << "Remaining unparsed: '" << std::string(iter, end) << "'\n";
}
return ok && (iter==end)? 0 : 1;
}

boost spirit and boost any - unexpected result

I have the following code:
#include <boost/any.hpp>
#include <boost/spirit/include/qi.hpp>
#include <iostream>
#include <string>
template <typename Iterator>
struct parser : boost::spirit::qi::grammar<Iterator, boost::any, boost::spirit::qi::ascii::space_type>
{
parser() : parser::base_type(start)
{
start %= boost::spirit::qi::int_;
}
boost::spirit::qi::rule<Iterator, boost::any, boost::spirit::qi::ascii::space_type> start;
};
int main()
{
const std::string input_data("1");
boost::any var;
auto itr = input_data.begin();
auto end = input_data.end();
parser<decltype(itr)> g;
bool res = boost::spirit::qi::phrase_parse(itr, end, g, boost::spirit::ascii::space, var);
if (res && itr == end)
{
std::cout << "Parsing succeeded \n";
try
{
std::cout << boost::any_cast<int>(var) << '\n';
}
catch (const boost::bad_any_cast& ex)
{
std::cerr << ex.what() << '\n';
}
}
else
{
std::cout << "Parsing failed \n";
}
}
Output
Parsing succeeded
boost::bad_any_cast: failed conversion using boost::any_cast
I think that cast should work fine in such case. Am i wrong? How can I fix it?
Initialize your any!
boost::any var = 0;
Spirit binds the attribute value by reference, so it will cast to int& before invoking the qi::int_ parser.
On a side note, using boost::any with Spirit seems like misguided plan. I can't see why you'd diverge from statically known types and e.g. Variant. But I'll leave that up to you :)
P.S. Oh, and you forgot some more parentheses like here :). See it Live On Coliru now

How do you use a variable stored in a boost spirit closure as input to a boost spirit loop parser?

I would like to use a parsed value as the input to a loop parser.
The grammar defines a header that specifies the (variable) size of the following string. For example, say the following string is the input to some parser.
12\r\nTest Payload
The parser should extract the 12, convert it to an unsigned int and then read twelve characters. I can define a boost spirit grammar that compiles, but an assertion in the boost spirit code fails at runtime.
#include <iostream>
#include <boost/spirit.hpp>
using namespace boost::spirit;
struct my_closure : public closure<my_closure, std::size_t> {
member1 size;
};
struct my_grammar : public grammar<my_grammar> {
template <typename ScannerT>
struct definition {
typedef rule<ScannerT> rule_type;
typedef rule<ScannerT, my_closure::context_t> closure_rule_type;
closure_rule_type header;
rule_type payload;
rule_type top;
definition(const my_grammar &self)
{
using namespace phoenix;
header = uint_p[header.size = arg1];
payload = repeat_p(header.size())[anychar_p][assign_a(self.result)];
top = header >> str_p("\r\n") >> payload;
}
const rule_type &start() const { return top; }
};
my_grammar(std::string &p_) : result(p_) {}
std::string &result;
};
int
main(int argc, char **argv)
{
const std::string content = "12\r\nTest Payload";
std::string payload;
my_grammar g(payload);
if (!parse(content.begin(), content.end(), g).full) {
std::cerr << "there was a parsing error!\n";
return -1;
}
std::cout << "Payload: " << payload << std::endl;
return 0;
}
Is it possible to tell spirit that the closure variable should be evaluated lazily? Is this behaviour supported by boost spirit?
This is much easier with the new qi parser available in Spirit 2. The following code snippet provides a full example that mostly works. An unexpected character is being inserted into the final result.
#include <iostream>
#include <string>
#include <boost/version.hpp>
#include <boost/spirit/include/qi.hpp>
#include <boost/spirit/include/qi_repeat.hpp>
#include <boost/spirit/include/qi_grammar.hpp>
#include <boost/spirit/include/phoenix_core.hpp>
#include <boost/spirit/include/phoenix_operator.hpp>
using boost::spirit::qi::repeat;
using boost::spirit::qi::uint_;
using boost::spirit::ascii::char_;
using boost::spirit::ascii::alpha;
using boost::spirit::qi::_1;
namespace phx = boost::phoenix;
namespace qi = boost::spirit::qi;
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;
}
static void
straight_forward()
{
std::string str;
int n;
test_parser_attr("12\r\nTest Payload",
uint_[phx::ref(n) = _1] >> "\r\n" >> repeat(phx::ref(n))[char_],
str);
std::cout << "str.length() == " << str.length() << std::endl;
std::cout << n << "," << str << std::endl; // will print "12,Test Payload"
}
template <typename P, typename T>
void
test_phrase_parser(char const* input, P const& p,
T& attr, bool full_match = true)
{
using boost::spirit::qi::phrase_parse;
using boost::spirit::qi::ascii::space;
char const* f(input);
char const* l(f + strlen(f));
if (phrase_parse(f, l, p, space, attr) && (!full_match || (f == l)))
std::cout << "ok" << std::endl;
else
std::cout << "fail" << std::endl;
}
template <typename Iterator>
struct test_grammar
: qi::grammar<Iterator, std::string(), qi::locals<unsigned> > {
test_grammar()
: test_grammar::base_type(my_rule)
{
using boost::spirit::qi::_a;
my_rule %= uint_[_a = _1] >> "\r\n" >> repeat(_a)[char_];
}
qi::rule<Iterator, std::string(), qi::locals<unsigned> > my_rule;
};
static void
with_grammar_local_variable()
{
std::string str;
test_phrase_parser("12\r\nTest Payload", test_grammar<const char*>(), str);
std::cout << str << std::endl; // will print "Test Payload"
}
int
main(int argc, char **argv)
{
std::cout << "boost version: " << BOOST_LIB_VERSION << std::endl;
straight_forward();
with_grammar_local_variable();
return 0;
}
What you are looking for is lazy_p, check the example here: http://www.boost.org/doc/libs/1_35_0/libs/spirit/doc/the_lazy_parser.html