C++ 提高精神难度,从XML示例开始
我正在尝试学习boost spirit库。从qi/karma XML示例()开始,我尝试将mini_XML中的子容器更改为std::vector以外的内容(本例中的std::list,请在下面查找mini_XML_children typedef)。不幸的是,这样做似乎无法编译 编译错误似乎表明phoenix正试图将std::list分配给std::vector,对此我解释起来有点困难,因为我的代码中不再有任何对std::vector的引用。我做了一些挖掘-看起来像boost::spirit::karma::action::generate决定在内部使用std::vector,而不是检测mini_xml使用的容器 如果我的假设是正确的,我想我需要一种更明确地传达“属性”应该是什么的方式。有没有一个简单的方法可以做到这一点?理想情况下,我希望这段代码与容器无关 守则:C++ 提高精神难度,从XML示例开始,c++,xml,boost,boost-spirit,C++,Xml,Boost,Boost Spirit,我正在尝试学习boost spirit库。从qi/karma XML示例()开始,我尝试将mini_XML中的子容器更改为std::vector以外的内容(本例中的std::list,请在下面查找mini_XML_children typedef)。不幸的是,这样做似乎无法编译 编译错误似乎表明phoenix正试图将std::list分配给std::vector,对此我解释起来有点困难,因为我的代码中不再有任何对std::vector的引用。我做了一些挖掘-看起来像boost::spirit::
#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;
}
}
#包括
#包括
//[mini_xml_karma_sr_包括
#包括
#包括
#包括
#包括
#包括
//]
#包括
#包括
#包括
#包括
#包括
#包括
#包括
//[mini_xml_karma_sr_使用
使用名称空间boost::spirit;
使用名称空间boost::spirit::ascii;
名称空间repo=boost::spirit::repository;
//]
名称空间融合=boost::fusion;
名称空间phoenix=boost::phoenix;
使用phoenix::at_c;
使用phoenix::推回;
///////////////////////////////////////////////////////////////////////////////
//我们的迷你XML树表示
///////////////////////////////////////////////////////////////////////////////
结构迷你xml;
类型定义
boost::variant<
递归包装器
,std::string
>
迷你xml节点;
//typedef std::vector mini_xml_children;//起初的
typedef std::列出mini_xml_子项;
结构迷你xml
{
std::string name;//标记名
mini_xml_children children;//children
};
//我们需要告诉fusion我们的mini_xml结构
//让它成为一流的融合公民
增强融合适应结构(
迷你xml,
(std::字符串,名称)
(迷你xml儿童,儿童)
)
///////////////////////////////////////////////////////////////////////////////
//我们的迷你XML语法定义
///////////////////////////////////////////////////////////////////////////////
模板
结构迷你xml解析器:
语法
{
迷你xml解析器():迷你xml解析器::基本类型(xml)
{
text=词素[+(char.-'')[\u val+=\u 1]]
>> '>'
;
尾端标签=
“这是
#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;
}
}
如果您更改为列表,push_back
将不起作用,原因很明显。因此,请更改
>> *node [push_back(at_c<1>(_val), _1)]
#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;
}
}
#定义提升(精神)使用(凤凰)
#包括
#包括
#包括
#包括
#包括
#包括
#包括
#包括
#包括
#包括
名称空间融合=boost::fusion;
名称空间qi=boost::spirit::qi;
名称空间ascii=boost::spirit::ascii;
名称空间业力=提升::精神::业力;
名称空间phoenix=boost::phoenix;
///////////////////////////////////////////////////////////////////////////////
//我们的迷你XML树表示
///////////////////////////////////////////////////////////////////////////////
结构迷你xml;
类型定义
boost::variant<
递归包装器
,std::string
>
迷你xml节点;
typedef std::列出小型xml节点;
结构迷你xml
{
std::string name;//标记名
mini_xml_节点子节点;//子节点
};
//我们需要告诉fusion我们的mini_xml结构
//让它成为一流的融合公民
增强融合适应结构(
迷你xml,
(std::字符串,名称)
(小型xml节点、子节点)
)
///////////////////////////////////////////////////////////////////////////////
//我们的迷你XML语法定义
///////////////////////////////////////////////////////////////////////////////
模板
结构迷你xml解析器:
语法
{
迷你xml解析器():迷你xml解析器::基本类型(开始)
{
使用qi::lit;
使用气:词素;
使用ascii::char;
使用ascii::字符串;
使用名称空间qi::标签;
text%=词素[+(char_-“”)]
>> '>'
;
尾端标签=
“有趣的是,这个示例使用的是破损的子规则(既然您现在没有使用存储库示例,那么您为什么要获取存储库示例?看起来很好?哦,我找错地方了?该死。我没有意识到存储库/示例和示例位置之间的区别……以后不会再犯这个错误了!”)看这里:这就像精神的“贡献”
karma::_a_type element_name_; // using karma::locals<std::string>
xml %=
'<' << string[element_name_ = _1] << '>'
<< *node
<< "</" << string(element_name_) << '>'
;
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;
}
}