I'm attempting to learn the boost spirit library. Working from the qi/karma XML example (http://www.boost.org/doc/libs/1_50_0/libs/spirit/repository/example/karma/mini_xml_karma_sr.cpp), I've attempted to change the children container in mini_xml to something other than std::vector (std::list in this example, look for the mini_xml_children typedef below). Unfortunately, doing so doesn't seem to compile.
The compile error seems to indicate that phoenix is attempting to assign std::list to std::vector, which I had a little trouble explaining because there aren't any references to std::vector in my code any longer. I did a little digging - looks like boost::spirit::karma::action::generate decides to use std::vector internally rather than detecting the container mini_xml uses.
If my assumption there is correct, I think I need a way of communicating more explicitly what the 'attribute' should be. Is there an easy way to do this? Ideally, I'd like this code to be container-agnostic.
The code:
#include <boost/config/warning_disable.hpp>
#include <boost/spirit/include/qi.hpp>
//[mini_xml_karma_sr_includes
#include <boost/spirit/include/karma.hpp>
#include <boost/spirit/repository/include/karma_subrule.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_function.hpp>
#include <boost/spirit/include/phoenix_stl.hpp>
#include <boost/fusion/include/adapt_struct.hpp>
#include <boost/variant/recursive_variant.hpp>
#include <iostream>
#include <fstream>
#include <string>
//[mini_xml_karma_sr_using
using namespace boost::spirit;
using namespace boost::spirit::ascii;
namespace repo = boost::spirit::repository;
//]
namespace fusion = boost::fusion;
namespace phoenix = boost::phoenix;
using phoenix::at_c;
using phoenix::push_back;
///////////////////////////////////////////////////////////////////////////////
// Our mini XML tree representation
///////////////////////////////////////////////////////////////////////////////
struct mini_xml;
typedef
boost::variant<
boost::recursive_wrapper<mini_xml>
, std::string
>
mini_xml_node;
//typedef std::vector<mini_xml_node> mini_xml_children; // original
typedef std::list<mini_xml_node> mini_xml_children;
struct mini_xml
{
std::string name; // tag name
mini_xml_children children; // children
};
// We need to tell fusion about our mini_xml struct
// to make it a first-class fusion citizen
BOOST_FUSION_ADAPT_STRUCT(
mini_xml,
(std::string, name)
(mini_xml_children, children)
)
///////////////////////////////////////////////////////////////////////////////
// Our mini XML grammar definition
///////////////////////////////////////////////////////////////////////////////
template <typename Iterator>
struct mini_xml_parser :
qi::grammar<Iterator, mini_xml(), space_type>
{
mini_xml_parser() : mini_xml_parser::base_type(xml)
{
text = lexeme[+(char_ - '<') [_val += _1]];
node = (xml | text) [_val = _1];
start_tag =
'<'
>> !lit('/')
>> lexeme[+(char_ - '>') [_val += _1]]
>> '>'
;
end_tag =
"</"
>> lit(_r1)
>> '>'
;
xml =
start_tag [at_c<0>(_val) = _1]
>> *node [push_back(at_c<1>(_val), _1)]
>> end_tag(at_c<0>(_val))
;
}
qi::rule<Iterator, mini_xml(), space_type> xml;
qi::rule<Iterator, mini_xml_node(), space_type> node;
qi::rule<Iterator, std::string(), space_type> text;
qi::rule<Iterator, std::string(), space_type> start_tag;
qi::rule<Iterator, void(std::string), space_type> end_tag;
};
///////////////////////////////////////////////////////////////////////////////
// A couple of phoenix functions helping to access the elements of the
// generated AST
///////////////////////////////////////////////////////////////////////////////
template <typename T>
struct get_element
{
template <typename T1>
struct result { typedef T const& type; };
T const& operator()(mini_xml_node const& node) const
{
return boost::get<T>(node);
}
};
phoenix::function<get_element<std::string> > _string;
phoenix::function<get_element<mini_xml> > _xml;
///////////////////////////////////////////////////////////////////////////////
// The output grammar defining the format of the generated data
///////////////////////////////////////////////////////////////////////////////
//[mini_xml_karma_sr_grammar
template <typename OutputIterator>
struct mini_xml_generator
: karma::grammar<OutputIterator, mini_xml()>
{
mini_xml_generator() : mini_xml_generator::base_type(xml)
{
node %= ascii::string | xml;
xml =
'<' << ascii::string[qi::_1 = phoenix::at_c<0>(qi::_val)] << '>'
<< (*node)[qi::_1 = phoenix::at_c<1>(qi::_val)]
<< "</" << ascii::string[qi::_1 = phoenix::at_c<0>(qi::_val)] << '>'
;
}
karma::rule<OutputIterator, mini_xml()> xml;
karma::rule<OutputIterator, mini_xml_node()> node;
};
//]
///////////////////////////////////////////////////////////////////////////////
// Main program
///////////////////////////////////////////////////////////////////////////////
int main(int argc, char **argv)
{
char const* filename;
if (argc > 1)
{
filename = argv[1];
}
else
{
std::cerr << "Error: No input file provided." << std::endl;
return 1;
}
std::ifstream in(filename, std::ios_base::in);
if (!in)
{
std::cerr << "Error: Could not open input file: "
<< filename << std::endl;
return 1;
}
std::string storage; // We will read the contents here.
in.unsetf(std::ios::skipws); // No white space skipping!
std::copy(
std::istream_iterator<char>(in),
std::istream_iterator<char>(),
std::back_inserter(storage));
typedef mini_xml_parser<std::string::const_iterator> mini_xml_parser;
mini_xml_parser xmlin; // Our grammar definition
mini_xml ast; // our tree
std::string::const_iterator iter = storage.begin();
std::string::const_iterator end = storage.end();
bool r = qi::phrase_parse(iter, end, xmlin, space, ast);
if (r && iter == end)
{
std::cout << "-------------------------\n";
std::cout << "Parsing succeeded\n";
std::cout << "-------------------------\n";
typedef std::back_insert_iterator<std::string> outiter_type;
typedef mini_xml_generator<outiter_type> mini_xml_generator;
mini_xml_generator xmlout; // Our grammar definition
std::string generated;
outiter_type outit(generated);
bool r = karma::generate(outit, xmlout, ast);
if (r)
std::cout << generated << std::endl;
return 0;
}
else
{
std::string::const_iterator begin = storage.begin();
std::size_t dist = std::distance(begin, iter);
std::string::const_iterator some =
iter + (std::min)(storage.size()-dist, std::size_t(30));
std::string context(iter, some);
std::cout << "-------------------------\n";
std::cout << "Parsing failed\n";
std::cout << "stopped at: \": " << context << "...\"\n";
std::cout << "-------------------------\n";
return 1;
}
}
Start of the error message:
1>------ Build started: Project: test_project, Configuration: Debug Win32 ------
1>Compiling...
1>test_project.cpp
1>c:\rtgcode\thirdparty\thirdparty\boost/spirit/home/phoenix/operator/self.hpp(27) : error C2679: binary '=' : no operator found which takes a right-hand operand of type 'const std::list<_Ty>' (or there is no acceptable conversion)
1> with
1> [
1> _Ty=mini_xml_node
1> ]
1> c:\Program Files (x86)\Microsoft Visual Studio 9.0\VC\include\vector(562): could be 'std::vector<_Ty> &std::vector<_Ty>::operator =(const std::vector<_Ty> &)'
1> with
1> [
1> _Ty=boost::variant<boost::recursive_wrapper<mini_xml>,std::string>
1> ]
1> while trying to match the argument list '(std::vector<_Ty>, const std::list<_Ty>)'
1> with
1> [
1> _Ty=boost::variant<boost::recursive_wrapper<mini_xml>,std::string>
1> ]
1> and
1> [
1> _Ty=mini_xml_node
1> ]
1> c:\rtgcode\thirdparty\thirdparty\boost/mpl/eval_if.hpp(41) : see reference to class template instantiation 'boost::phoenix::result_of_assign<X,Y>' being compiled
1> with
1> [
1> X=std::vector<boost::variant<boost::recursive_wrapper<mini_xml>,std::string>> ,
1> Y=const std::list<mini_xml_node>
1> ]
1> c:\rtgcode\thirdparty\thirdparty\boost/spirit/home/phoenix/operator/self.hpp(69) : see reference to class template instantiation 'boost::mpl::eval_if<C,F1,F2>' being compiled
1> with
1> [
1> C=boost::mpl::or_<boost::phoenix::is_actor<std::vector<boost::variant<boost::recursive_wrapper<mini_xml>,std::string>> >,boost::phoenix::is_actor<const std::list<mini_xml_node> >>,
1> F1=boost::phoenix::re_curry<boost::phoenix::assign_eval,std::vector<boost::variant<boost::recursive_wrapper<mini_xml>,std::string>> ,const std::list<mini_xml_node> >,
1> F2=boost::phoenix::result_of_assign<std::vector<boost::variant<boost::recursive_wrapper<mini_xml>,std::string>> ,const std::list<mini_xml_node> >
1> ]
1> c:\rtgcode\thirdparty\thirdparty\boost/spirit/home/phoenix/core/detail/composite_eval.hpp(88) : see reference to class template instantiation 'boost::phoenix::assign_eval::result<Env,A0,A1>' being compiled
1> with
1> [
1> Env=boost::phoenix::basic_environment<boost::fusion::vector1<std::vector<boost::variant<boost::recursive_wrapper<mini_xml>,std::string>> &>,boost::spirit::context<boost::fusion::cons<const mini_xml &,boost::fusion::nil>,boost::fusion::vector0<>>,bool>,
1> A0=boost::spirit::argument<0>,
1> A1=boost::phoenix::composite<boost::phoenix::at_eval<1>,boost::fusion::vector<boost::spirit::attribute<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_>>
1> ]
1> c:\rtgcode\thirdparty\thirdparty\boost/spirit/home/phoenix/core/composite.hpp(60) : see reference to class template instantiation 'boost::phoenix::detail::composite_eval<2>::result<Composite,Env>' being compiled
1> with
1> [
1> Composite=boost::phoenix::composite<boost::phoenix::assign_eval,boost::fusion::vector<boost::spirit::argument<0>,boost::phoenix::composite<boost::phoenix::at_eval<1>,boost::fusion::vector<boost::spirit::attribute<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_>>,boost::fusion::void_,boost::fusion::void_,boost::fusion::void_,boost::fusion::void_,boost::fusion::void_,boost::fusion::void_,boost::fusion::void_,boost::fusion::void_>>,
1> Env=boost::phoenix::basic_environment<boost::fusion::vector1<std::vector<boost::variant<boost::recursive_wrapper<mini_xml>,std::string>> &>,boost::spirit::context<boost::fusion::cons<const mini_xml &,boost::fusion::nil>,boost::fusion::vector0<>>,bool>
1> ]
1> c:\rtgcode\thirdparty\thirdparty\boost/spirit/home/phoenix/core/actor.hpp(56) : see reference to class template instantiation 'boost::phoenix::composite<EvalPolicy,EvalTuple>::result<Env>' being compiled
1> with
1> [
1> EvalPolicy=boost::phoenix::assign_eval,
1> EvalTuple=boost::fusion::vector<boost::spirit::argument<0>,boost::phoenix::composite<boost::phoenix::at_eval<1>,boost::fusion::vector<boost::spirit::attribute<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_>>,boost::fusion::void_,boost::fusion::void_,boost::fusion::void_,boost::fusion::void_,boost::fusion::void_,boost::fusion::void_,boost::fusion::void_,boost::fusion::void_>,
1> Env=boost::phoenix::basic_environment<boost::fusion::vector1<std::vector<boost::variant<boost::recursive_wrapper<mini_xml>,std::string>> &>,boost::spirit::context<boost::fusion::cons<const mini_xml &,boost::fusion::nil>,boost::fusion::vector0<>>,bool>
1> ]
1> c:\rtgcode\thirdparty\thirdparty\boost/spirit/home/phoenix/core/detail/actor.hpp(48) : see reference to class template instantiation 'boost::phoenix::eval_result<Eval,Env>' being compiled
1> with
1> [
1> Eval=boost::phoenix::composite<boost::phoenix::assign_eval,boost::fusion::vector<boost::spirit::argument<0>,boost::phoenix::composite<boost::phoenix::at_eval<1>,boost::fusion::vector<boost::spirit::attribute<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_>>,boost::fusion::void_,boost::fusion::void_,boost::fusion::void_,boost::fusion::void_,boost::fusion::void_,boost::fusion::void_,boost::fusion::void_,boost::fusion::void_>>,
1> Env=boost::phoenix::basic_environment<boost::fusion::vector1<std::vector<boost::variant<boost::recursive_wrapper<mini_xml>,std::string>> &>,boost::spirit::context<boost::fusion::cons<const mini_xml &,boost::fusion::nil>,boost::fusion::vector0<>>,bool>
1> ]
1> c:\rtgcode\thirdparty\thirdparty\boost/spirit/home/support/action_dispatch.hpp(178) : see reference to class template instantiation 'boost::phoenix::actor<Eval>::result<Sig>' being compiled
1> with
1> [
1> Eval=boost::phoenix::composite<boost::phoenix::assign_eval,boost::fusion::vector<boost::spirit::argument<0>,boost::phoenix::composite<boost::phoenix::at_eval<1>,boost::fusion::vector<boost::spirit::attribute<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_>>,boost::fusion::void_,boost::fusion::void_,boost::fusion::void_,boost::fusion::void_,boost::fusion::void_,boost::fusion::void_,boost::fusion::void_,boost::fusion::void_>>,
1> Sig=boost::phoenix::actor<boost::phoenix::composite<boost::phoenix::assign_eval,boost::fusion::vector<boost::spirit::argument<0>,boost::phoenix::composite<boost::phoenix::at_eval<1>,boost::fusion::vector<boost::spirit::attribute<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_>>,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::vector1<std::vector<boost::variant<boost::recursive_wrapper<mini_xml>,std::string>> &> &,boost::spirit::context<boost::fusion::cons<const mini_xml &,boost::fusion::nil>,boost::fusion::vector0<>> &,bool &)
1> ]
1> c:\rtgcode\thirdparty\thirdparty\boost/spirit/home/karma/action/action.hpp(69) : see reference to function template instantiation 'bool boost::spirit::traits::action_dispatch<Component>::operator ()<boost::phoenix::composite<EvalPolicy,EvalTuple>,std::vector<_Ty>,Context>(const boost::phoenix::actor<Eval> &,Attribute &,Context &)' being compiled
1> with
1> [
1> Component=boost::spirit::karma::kleene<boost::spirit::karma::reference<const boost::spirit::karma::rule<outiter_type,mini_xml_node (void)>>>,
1> EvalPolicy=boost::phoenix::assign_eval,
1> EvalTuple=boost::fusion::vector<boost::spirit::argument<0>,boost::phoenix::composite<boost::phoenix::at_eval<1>,boost::fusion::vector<boost::spirit::attribute<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_>>,boost::fusion::void_,boost::fusion::void_,boost::fusion::void_,boost::fusion::void_,boost::fusion::void_,boost::fusion::void_,boost::fusion::void_,boost::fusion::void_>,
1> _Ty=boost::variant<boost::recursive_wrapper<mini_xml>,std::string>,
1> Context=boost::spirit::context<boost::fusion::cons<const mini_xml &,boost::fusion::nil>,boost::fusion::vector0<>>,
1> Eval=boost::phoenix::composite<boost::phoenix::assign_eval,boost::fusion::vector<boost::spirit::argument<0>,boost::phoenix::composite<boost::phoenix::at_eval<1>,boost::fusion::vector<boost::spirit::attribute<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_>>,boost::fusion::void_,boost::fusion::void_,boost::fusion::void_,boost::fusion::void_,boost::fusion::void_,boost::fusion::void_,boost::fusion::void_,boost::fusion::void_>>,
1> Attribute=std::vector<boost::variant<boost::recursive_wrapper<mini_xml>,std::string>>
1> ]
*snip*
Compiled with boost v1.50.0 in Visual Studio 2008.
Side note: I couldn't get the original example to compile without first changing karma::subrule to karma::rule. Is there an issue with subrules in 1.50.0? Is there a better workaround for the issue than what I've done?
It's another case of Boost Spirit: "Semantic actions are evil"?
If you change to list, push_back
won't work, for obvious reasons. So, change
>> *node [push_back(at_c<1>(_val), _1)]
into
>> *node [phoenix::insert(at_c<1>(_val), phoenix::end(at_c<1>(_val)), _1)]
On the generator side, replace all the use of semantic actions by a simpler semantic action that allows you still rely on the attribute compatibility magic for all the rest:
karma::_a_type element_name_; // using karma::locals<std::string>
xml %=
'<' << string[element_name_ = _1] << '>'
<< *node
<< "</" << string(element_name_) << '>'
;
<rant>All in this is simply more evidence that less code is always better. Interfere less, spell out less, rely on builtin mechanisms. As soon as you interfere (by writing exact, imperative, semantic actions for attribute extraction) you lose when you want to maintain the code.</rant>
UPDATE Removed all gratuitous use of semantic actions now, so we have a Qi grammar and Karma generator that work with list
and vector
without any additional work. Also fixed some elements of style (no more using namespace
).
This means that the above phoenix::insert(at_c<1>(_val), phoenix::end(at_c<1>(_val)), _1)
is no longer needed:
qi::_a_type element_name_;
xml %=
start_tag[element_name_ = _1]
>> *node
>> end_tag(element_name_)
;
#define BOOST_SPIRIT_USE_PHOENIX_V3
#include <boost/spirit/include/qi.hpp>
#include <boost/spirit/include/karma.hpp>
#include <boost/spirit/include/phoenix.hpp>
#include <boost/spirit/include/phoenix_function.hpp>
#include <boost/fusion/include/adapt_struct.hpp>
#include <boost/variant/recursive_variant.hpp>
#include <iostream>
#include <fstream>
#include <string>
#include <list>
namespace fusion = boost::fusion;
namespace qi = boost::spirit::qi;
namespace ascii = boost::spirit::ascii;
namespace karma = boost::spirit::karma;
namespace phoenix = boost::phoenix;
///////////////////////////////////////////////////////////////////////////////
// Our mini XML tree representation
///////////////////////////////////////////////////////////////////////////////
struct mini_xml;
typedef
boost::variant<
boost::recursive_wrapper<mini_xml>
, std::string
>
mini_xml_node;
typedef std::list<mini_xml_node> mini_xml_nodes;
struct mini_xml
{
std::string name; // tag name
mini_xml_nodes children; // children
};
// We need to tell fusion about our mini_xml struct
// to make it a first-class fusion citizen
BOOST_FUSION_ADAPT_STRUCT(
mini_xml,
(std::string, name)
(mini_xml_nodes, children)
)
///////////////////////////////////////////////////////////////////////////////
// Our mini XML grammar definition
///////////////////////////////////////////////////////////////////////////////
template <typename Iterator>
struct mini_xml_parser :
qi::grammar<Iterator, mini_xml(), qi::space_type>
{
mini_xml_parser() : mini_xml_parser::base_type(start)
{
using qi::lit;
using qi::lexeme;
using ascii::char_;
using ascii::string;
using namespace qi::labels;
text %= lexeme[+(char_ - '<')];
node %= xml | text;
start_tag %=
'<'
>> !lit('/')
>> lexeme[+(char_ - '>')]
>> '>'
;
end_tag =
"</"
>> string(_r1)
>> '>'
;
qi::_a_type element_name_;
xml %=
start_tag[element_name_ = _1]
>> *node
>> end_tag(element_name_)
;
start = xml;
}
qi::rule<Iterator, mini_xml(), qi::space_type> start;
qi::rule<Iterator, mini_xml(), qi::space_type, qi::locals<std::string> > xml;
qi::rule<Iterator, mini_xml_node(), qi::space_type> node;
qi::rule<Iterator, std::string(), qi::space_type> text;
qi::rule<Iterator, std::string(), qi::space_type> start_tag;
qi::rule<Iterator, void(std::string), qi::space_type> end_tag;
};
///////////////////////////////////////////////////////////////////////////////
// A couple of phoenix functions helping to access the elements of the
// generated AST
///////////////////////////////////////////////////////////////////////////////
template <typename T>
struct get_element
{
template <typename T1>
struct result { typedef T const& type; };
T const& operator()(mini_xml_node const& node) const
{
return boost::get<T>(node);
}
};
phoenix::function<get_element<std::string> > _string;
phoenix::function<get_element<mini_xml> > _xml;
///////////////////////////////////////////////////////////////////////////////
// The output grammar defining the format of the generated data
///////////////////////////////////////////////////////////////////////////////
//[mini_xml_karma_sr_grammar
template <typename OutputIterator>
struct mini_xml_generator
: karma::grammar<OutputIterator, mini_xml()>
{
mini_xml_generator() : mini_xml_generator::base_type(entry)
{
karma::_a_type element_name_;
xml %=
'<' << karma::string[element_name_ = karma::_1] << '>'
<< *node
<< "</" << karma::string(element_name_) << '>'
;
node %= karma::string | xml;
entry %= node;
}
karma::rule<OutputIterator, mini_xml()> entry;
karma::rule<OutputIterator, mini_xml(), qi::locals<std::string> > xml;
karma::rule<OutputIterator, mini_xml_node()> node;
};
//]
///////////////////////////////////////////////////////////////////////////////
// Main program
///////////////////////////////////////////////////////////////////////////////
int main(int argc, char **argv)
{
char const* filename;
if (argc > 1)
{
filename = argv[1];
}
else
{
std::cerr << "Error: No input file provided." << std::endl;
return 1;
}
std::ifstream in(filename, std::ios_base::in);
if (!in)
{
std::cerr << "Error: Could not open input file: "
<< filename << std::endl;
return 1;
}
std::string storage; // We will read the contents here.
in.unsetf(std::ios::skipws); // No white space skipping!
std::copy(
std::istream_iterator<char>(in),
std::istream_iterator<char>(),
std::back_inserter(storage));
typedef mini_xml_parser<std::string::const_iterator> mini_xml_parser;
mini_xml_parser xmlin; // Our grammar definition
mini_xml ast; // our tree
std::string::const_iterator iter = storage.begin();
std::string::const_iterator end = storage.end();
bool r = qi::phrase_parse(iter, end, xmlin, qi::space, ast);
if (r && iter == end)
{
std::cout << "-------------------------\n";
std::cout << "Parsing succeeded\n";
std::cout << "-------------------------\n";
typedef std::back_insert_iterator<std::string> outiter_type;
typedef mini_xml_generator<outiter_type> mini_xml_generator;
mini_xml_generator xmlout; // Our grammar definition
std::string generated;
outiter_type outit(generated);
bool r = karma::generate(outit, xmlout, ast);
if (r)
std::cout << generated << std::endl;
return 0;
}
else
{
std::string::const_iterator begin = storage.begin();
std::size_t dist = std::distance(begin, iter);
std::string::const_iterator some =
iter + (std::min)(storage.size()-dist, std::size_t(30));
std::string context(iter, some);
std::cout << "-------------------------\n";
std::cout << "Parsing failed\n";
std::cout << "stopped at: \": " << context << "...\"\n";
std::cout << "-------------------------\n";
return 1;
}
}