前段时间我在windows中编写了解析代码的精神,它运行良好。现在我正在尝试在Ubuntu上构建它,但是c ++(gcc版本4.6.3(Ubuntu / Linaro 4.6.3-1ubuntu5))失败了一些错误消息,我没有丝毫的胶水怎么办(第161行由注释“// LINE 161 !!!!”标记):
#include <string>
#include <map>
#include <boost/config/warning_disable.hpp>
#include <boost/spirit/include/qi.hpp>
#include <boost/spirit/include/qi_hold.hpp>
#include <boost/spirit/include/qi_omit.hpp>
#include <boost/spirit/include/phoenix_core.hpp>
#include <boost/spirit/include/phoenix_operator.hpp>
#include <boost/spirit/include/phoenix_stl.hpp>
#include <boost/spirit/include/phoenix_fusion.hpp>
#include <boost/fusion/include/adapt_struct.hpp>
#include <boost/fusion/include/io.hpp>
#include <boost/variant/recursive_variant.hpp>
#include <boost/foreach.hpp>
#include <exception>
#include <vector>
using namespace std;
using namespace boost;
using boost::spirit::qi::phrase_parse;
using boost::spirit::qi::char_;
using boost::spirit::qi::double_;
using boost::spirit::qi::eps;
using boost::spirit::qi::lit;
using boost::spirit::qi::_1;
using boost::spirit::qi::grammar;
using boost::spirit::qi::lexeme;
using boost::spirit::qi::symbols;
using boost::spirit::qi::rule;
using boost::spirit::qi::hold;
using boost::spirit::qi::omit;
using boost::spirit::_val;
using boost::spirit::ascii::space;
using boost::spirit::ascii::space_type;
using boost::phoenix::ref;
using boost::phoenix::push_back;
using boost::phoenix::at_c;
namespace sx {
namespace parserInternal {
/**
* types of _XNODE_
*/
enum _XTYPE_ {
_XTEXT_ ,
_XTAG_ ,
_S_ATTRIB_,
_R_ATTRIB_
};
/**
* structure for boost spirit
* parsetree datastructure
*/
struct _XNODE_ {
/**
* type of node
*/
int type;
/**
* data of XText
*/
string text;
/**
* data of XTag
*/
string name;
vector<_XNODE_> nodes;
/**
* data of string attribute
*/
string strID;
string strAttrib;
/**
* data of real attribute
*/
string rID;
double rAttrib;
/**
* bug fix - stop parser from
* taking characters it shouldn't
* by assigning eat with the useless
* string sequences
*/
string eat;
};
}
}
BOOST_FUSION_ADAPT_STRUCT (
sx::parserInternal::_XNODE_ ,
(int ,type) // 0
(std::string ,text) // 1 - XText
(std::string ,name) // 2 - XTag
(std::vector<sx::parserInternal::_XNODE_> ,nodes) // 3 - XTag
(std::string ,strID) // 4 - str. attrib
(std::string ,strAttrib) // 5 - str. attrib
(std::string ,rID) // 6 - r. attrib
(double ,rAttrib) // 7 - r. attrib
(std::string ,eat) // 8 - bug fix
)
namespace sx {
namespace parserInternal {
/**
* filters comments out of the text
*/
struct SXFilter: public grammar<string::iterator,string()> {
/**
* start rule
*/
rule<string::iterator,string()> start;
/**
* recognizes a sequence starting with //, and anything
* ending with newline
*/
rule<string::iterator,string()> skipSmallComment;
/**
* recognizes a sequence starting with /* and anything
* ending with the two characters '*' and '/' in sequence
*/
rule<string::iterator,string()> skipLargeComment;
/**
* recognizes newline
*/
rule<string::iterator,string()> separator;
/**
* recognizes any text not containing the char sequences
* /* amd //
*/
rule<string::iterator,string()> acceptable;
SXFilter(): SXFilter::base_type(start) {
separator %= lexeme[(char_('\n') | char_('\r\n'))];
acceptable %= *lexeme[char_ - lit("/*") - lit("//")];
skipLargeComment %= lit("/*") >> *lexeme[char_ - lit("*/")] >> lit("*/");
skipSmallComment %= lit ("//") >> *lexeme[char_ - separator];
start %= eps >> acceptable >>
*(
(
omit[skipSmallComment]
| omit[skipLargeComment]
) >> acceptable
)
//LINE 161!!!!
;
}
};
/**
* grammar for the parser
*/
struct XGrammar: public grammar<string::iterator,_XNODE_(),space_type> {
/**
* a tag
*/
rule<string::iterator,_XNODE_(),space_type> tag;
/**
* child nodes of a tag
*/
rule<string::iterator,vector<_XNODE_>(),space_type> nodelist;
/**
* identifyer - starts with a letter in a-zA-Z_:. , and can be
* continued by a-zA-Z_0-9:. , must have at least one letter
*/
rule<string::iterator,string()> identifyer;
/**
* any char sequence without the letter " of any length
* bordered by the letter "
*/
rule<string::iterator,string()> textdata;
/**
* attribute assigned with string value
*/
rule<string::iterator,_XNODE_(),space_type> strAttrib;
/**
* attribute assigned with double value
*/
rule<string::iterator,_XNODE_(),space_type> realAttrib;
/**
* simply textdata returning _XNODE_
*/
rule<string::iterator,_XNODE_(),space_type> textNode;
/**
* constructor, makes tag to the node's root
*/
XGrammar(): XGrammar::base_type(tag) {
identifyer %= lexeme[char_("a-zA-Z_:.") >> *( char_("0-9a-zA-Z_:.") )];
textdata %= lexeme['"' >> *(char_ - '"') >> '"'];
strAttrib %=
identifyer[at_c<4>(_val) = _1] >> char_('=') >>
textdata[at_c<5>(_val) = _1] >> char_(';')[at_c<0>(_val) = _S_ATTRIB_];
realAttrib %=
identifyer[at_c<6>(_val) = _1] >> char_('=') >>
double_[at_c<7>(_val) = _1] >> char_(';')[at_c<0>(_val) = _R_ATTRIB_];
textNode %= textdata[at_c<1>(_val) = _1][at_c<0>(_val) = _XTEXT_];
nodelist %= eps >>
*(
tag
| strAttrib
| realAttrib
| textNode
)
;
tag %= eps >>
char_('(') >> identifyer[at_c<2>(_val) = _1] >> char_(')')[at_c<8>(_val) = _1] >>
(
char_('{') >>
nodelist[at_c<3>(_val) = _1] >>
char_('}')
| eps
)[at_c<0>(_val) = _XTAG_]
;
}
};
void parseSXdata1(const string &data, string &output) {
string filterable = data;
string::iterator iter1 = filterable.begin();
string::iterator iter2 = filterable.end();
SXFilter filter;
bool parsed = phrase_parse(
iter1,
iter2,
filter,
space,
output
);
if(!parsed || iter1 != iter2) {
throw std::exception();
}
}
void parseSXdata2(string &data, parserInternal::_XNODE_ &output) {
string::iterator iter1 = data.begin();
string::iterator iter2 = data.end();
XGrammar grammar;
bool parsed = phrase_parse(
iter1,
iter2,
grammar,
space,
output
);
if(!parsed || iter1 != iter2) {
throw std::exception();
}
}
}
}
int main(int argc, char **argv) {
string data =
"(testsx) {\n"
" (test) {\"hello world\"}\n"
" (test2) {\n"
" attrib1 = 123;\n"
" attrib2 = \"hey\";\n"
" }\n"
"}"
;
string iterable;
sx::parserInternal::_XNODE_ output; //root of parsetree
sx::parserInternal::parseSXdata1(data,iterable);
sx::parserInternal::parseSXdata2(iterable,output);
return 0;
}
我使用boost库1.47在MSVC 2008中成功编译了该代码。但在Ubuntu中,gcc 4.6.3会产生以下错误消息:
Main.cpp:151:46: warning: multi-character character constant [-Wmultichar]
In file included from /usr/include/boost/spirit/home/qi/auxiliary/attr.hpp:18:0,
from /usr/include/boost/spirit/home/qi/auxiliary.hpp:19,
from /usr/include/boost/spirit/home/qi.hpp:16,
from /usr/include/boost/spirit/include/qi.hpp:16,
from Main.cpp:4:
/usr/include/boost/spirit/home/qi/detail/assign_to.hpp: In static member function ‘static void boost::spirit::traits::assign_to_attribute_from_value<Attribute, T, Enable>::call(const T_&, Attribute&, mpl_::false_) [with T_ = std::basic_string<char>, Attribute = char, T = std::basic_string<char>, Enable = void, mpl_::false_ = mpl_::bool_<false>]’:
/usr/include/boost/spirit/home/qi/detail/assign_to.hpp:127:13: instantiated from ‘static void boost::spirit::traits::assign_to_attribute_from_value<Attribute, T, Enable>::call(const T&, Attribute&) [with Attribute = char, T = std::basic_string<char>, Enable = void]’
/usr/include/boost/spirit/home/qi/detail/assign_to.hpp:234:13: instantiated from ‘void boost::spirit::traits::detail::assign_to(const T&, Attribute&, P1, P2) [with T = std::basic_string<char>, Attribute = char, P1 = mpl_::bool_<false>, P2 = mpl_::bool_<true>]’
/usr/include/boost/spirit/home/qi/detail/assign_to.hpp:257:9: instantiated from ‘void boost::spirit::traits::assign_to(const T&, Attribute&) [with T = std::basic_string<char>, Attribute = char]’
/usr/include/boost/spirit/home/qi/detail/attributes.hpp:26:13: instantiated from ‘static void boost::spirit::qi::default_transform_attribute<Exposed, Transformed>::post(Exposed&, const Transformed&) [with Exposed = char, Transformed = std::basic_string<char>]’
/usr/include/boost/spirit/home/qi/detail/attributes.hpp:164:86: instantiated from ‘void boost::spirit::traits::post_transform(Exposed&, const Transformed&) [with Exposed = char, Transformed = std::basic_string<char>]’
/usr/include/boost/spirit/home/qi/nonterminal/rule.hpp:281:21: [ skipping 20 instantiation contexts ]
/usr/include/boost/spirit/home/qi/operator/sequence_base.hpp:123:50: instantiated from ‘bool boost::spirit::qi::sequence_base<Derived, Elements>::parse(Iterator&, const Iterator&, Context&, const Skipper&, Attribute&) const [with Iterator = __gnu_cxx::__normal_iterator<char*, std::basic_string<char> >, Context = boost::spirit::context<boost::fusion::cons<std::basic_string<char>&, boost::fusion::nil>, boost::fusion::vector0<> >, Skipper = boost::spirit::unused_type, Attribute = std::basic_string<char>, Derived = boost::spirit::qi::sequence<boost::fusion::cons<boost::spirit::qi::eps_parser, boost::fusion::cons<boost::spirit::qi::reference<const boost::spirit::qi::rule<__gnu_cxx::__normal_iterator<char*, std::basic_string<char> >, std::basic_string<char>(), boost::spirit::unused_type, boost::spirit::unused_type, boost::spirit::unused_type> >, boost::fusion::cons<boost::spirit::qi::kleene<boost::spirit::qi::sequence<boost::fusion::cons<boost::spirit::qi::alternative<boost::fusion::cons<boost::spirit::qi::omit_directive<boost::spirit::qi::reference<const boost::spirit::qi::rule<__gnu_cxx::__normal_iterator<char*, std::basic_string<char> >, std::basic_string<char>(), boost::spirit::unused_type, boost::spirit::unused_type, boost::spirit::unused_type> > >, boost::fusion::cons<boost::spirit::qi::omit_directive<boost::spirit::qi::reference<const boost::spirit::qi::rule<__gnu_cxx::__normal_iterator<char*, std::basic_string<char> >, std::basic_string<char>(), boost::spirit::unused_type, boost::spirit::unused_type, boost::spirit::unused_type> > >, boost::fusion::nil> > >, boost::fusion::cons<boost::spirit::qi::reference<const boost::spirit::qi::rule<__gnu_cxx::__normal_iterator<char*, std::basic_string<char> >, std::basic_string<char>(), boost::spirit::unused_type, boost::spirit::unused_type, boost::spirit::unused_type> >, boost::fusion::nil> > > >, boost::fusion::nil> > > >, Elements = boost::fusion::cons<boost::spirit::qi::eps_parser, boost::fusion::cons<boost::spirit::qi::reference<const boost::spirit::qi::rule<__gnu_cxx::__normal_iterator<char*, std::basic_string<char> >, std::basic_string<char>(), boost::spirit::unused_type, boost::spirit::unused_type, boost::spirit::unused_type> >, boost::fusion::cons<boost::spirit::qi::kleene<boost::spirit::qi::sequence<boost::fusion::cons<boost::spirit::qi::alternative<boost::fusion::cons<boost::spirit::qi::omit_directive<boost::spirit::qi::reference<const boost::spirit::qi::rule<__gnu_cxx::__normal_iterator<char*, std::basic_string<char> >, std::basic_string<char>(), boost::spirit::unused_type, boost::spirit::unused_type, boost::spirit::unused_type> > >, boost::fusion::cons<boost::spirit::qi::omit_directive<boost::spirit::qi::reference<const boost::spirit::qi::rule<__gnu_cxx::__normal_iterator<char*, std::basic_string<char> >, std::basic_string<char>(), boost::spirit::unused_type, boost::spirit::unused_type, boost::spirit::unused_type> > >, boost::fusion::nil> > >, boost::fusion::cons<boost::spirit::qi::reference<const boost::spirit::qi::rule<__gnu_cxx::__normal_iterator<char*, std::basic_string<char> >, std::basic_string<char>(), boost::spirit::unused_type, boost::spirit::unused_type, boost::spirit::unused_type> >, boost::fusion::nil> > > >, boost::fusion::nil> > >]’
/usr/include/boost/spirit/home/qi/nonterminal/detail/parser_binder.hpp:73:54: instantiated from ‘bool boost::spirit::qi::detail::parser_binder<Parser, mpl_::bool_<true> >::operator()(Iterator&, const Iterator&, Context&, const Skipper&) const [with Iterator = __gnu_cxx::__normal_iterator<char*, std::basic_string<char> >, Skipper = boost::spirit::unused_type, Context = boost::spirit::context<boost::fusion::cons<std::basic_string<char>&, boost::fusion::nil>, boost::fusion::vector0<> >, Parser = boost::spirit::qi::sequence<boost::fusion::cons<boost::spirit::qi::eps_parser, boost::fusion::cons<boost::spirit::qi::reference<const boost::spirit::qi::rule<__gnu_cxx::__normal_iterator<char*, std::basic_string<char> >, std::basic_string<char>(), boost::spirit::unused_type, boost::spirit::unused_type, boost::spirit::unused_type> >, boost::fusion::cons<boost::spirit::qi::kleene<boost::spirit::qi::sequence<boost::fusion::cons<boost::spirit::qi::alternative<boost::fusion::cons<boost::spirit::qi::omit_directive<boost::spirit::qi::reference<const boost::spirit::qi::rule<__gnu_cxx::__normal_iterator<char*, std::basic_string<char> >, std::basic_string<char>(), boost::spirit::unused_type, boost::spirit::unused_type, boost::spirit::unused_type> > >, boost::fusion::cons<boost::spirit::qi::omit_directive<boost::spirit::qi::reference<const boost::spirit::qi::rule<__gnu_cxx::__normal_iterator<char*, std::basic_string<char> >, std::basic_string<char>(), boost::spirit::unused_type, boost::spirit::unused_type, boost::spirit::unused_type> > >, boost::fusion::nil> > >, boost::fusion::cons<boost::spirit::qi::reference<const boost::spirit::qi::rule<__gnu_cxx::__normal_iterator<char*, std::basic_string<char> >, std::basic_string<char>(), boost::spirit::unused_type, boost::spirit::unused_type, boost::spirit::unused_type> >, boost::fusion::nil> > > >, boost::fusion::nil> > > >]’
/usr/include/boost/function/function_template.hpp:132:42: instantiated from ‘static R boost::detail::function::function_obj_invoker4<FunctionObj, R, T0, T1, T2, T3>::invoke(boost::detail::function::function_buffer&, T0, T1, T2, T3) [with FunctionObj = boost::spirit::qi::detail::parser_binder<boost::spirit::qi::sequence<boost::fusion::cons<boost::spirit::qi::eps_parser, boost::fusion::cons<boost::spirit::qi::reference<const boost::spirit::qi::rule<__gnu_cxx::__normal_iterator<char*, std::basic_string<char> >, std::basic_string<char>(), boost::spirit::unused_type, boost::spirit::unused_type, boost::spirit::unused_type> >, boost::fusion::cons<boost::spirit::qi::kleene<boost::spirit::qi::sequence<boost::fusion::cons<boost::spirit::qi::alternative<boost::fusion::cons<boost::spirit::qi::omit_directive<boost::spirit::qi::reference<const boost::spirit::qi::rule<__gnu_cxx::__normal_iterator<char*, std::basic_string<char> >, std::basic_string<char>(), boost::spirit::unused_type, boost::spirit::unused_type, boost::spirit::unused_type> > >, boost::fusion::cons<boost::spirit::qi::omit_directive<boost::spirit::qi::reference<const boost::spirit::qi::rule<__gnu_cxx::__normal_iterator<char*, std::basic_string<char> >, std::basic_string<char>(), boost::spirit::unused_type, boost::spirit::unused_type, boost::spirit::unused_type> > >, boost::fusion::nil> > >, boost::fusion::cons<boost::spirit::qi::reference<const boost::spirit::qi::rule<__gnu_cxx::__normal_iterator<char*, std::basic_string<char> >, std::basic_string<char>(), boost::spirit::unused_type, boost::spirit::unused_type, boost::spirit::unused_type> >, boost::fusion::nil> > > >, boost::fusion::nil> > > >, mpl_::bool_<true> >, R = bool, T0 = __gnu_cxx::__normal_iterator<char*, std::basic_string<char> >&, T1 = const __gnu_cxx::__normal_iterator<char*, std::basic_string<char> >&, T2 = boost::spirit::context<boost::fusion::cons<std::basic_string<char>&, boost::fusion::nil>, boost::fusion::vector0<> >&, T3 = const boost::spirit::unused_type&]’
/usr/include/boost/function/function_template.hpp:913:60: instantiated from ‘void boost::function4<R, T1, T2, T3, T4>::assign_to(Functor) [with Functor = boost::spirit::qi::detail::parser_binder<boost::spirit::qi::sequence<boost::fusion::cons<boost::spirit::qi::eps_parser, boost::fusion::cons<boost::spirit::qi::reference<const boost::spirit::qi::rule<__gnu_cxx::__normal_iterator<char*, std::basic_string<char> >, std::basic_string<char>(), boost::spirit::unused_type, boost::spirit::unused_type, boost::spirit::unused_type> >, boost::fusion::cons<boost::spirit::qi::kleene<boost::spirit::qi::sequence<boost::fusion::cons<boost::spirit::qi::alternative<boost::fusion::cons<boost::spirit::qi::omit_directive<boost::spirit::qi::reference<const boost::spirit::qi::rule<__gnu_cxx::__normal_iterator<char*, std::basic_string<char> >, std::basic_string<char>(), boost::spirit::unused_type, boost::spirit::unused_type, boost::spirit::unused_type> > >, boost::fusion::cons<boost::spirit::qi::omit_directive<boost::spirit::qi::reference<const boost::spirit::qi::rule<__gnu_cxx::__normal_iterator<char*, std::basic_string<char> >, std::basic_string<char>(), boost::spirit::unused_type, boost::spirit::unused_type, boost::spirit::unused_type> > >, boost::fusion::nil> > >, boost::fusion::cons<boost::spirit::qi::reference<const boost::spirit::qi::rule<__gnu_cxx::__normal_iterator<char*, std::basic_string<char> >, std::basic_string<char>(), boost::spirit::unused_type, boost::spirit::unused_type, boost::spirit::unused_type> >, boost::fusion::nil> > > >, boost::fusion::nil> > > >, mpl_::bool_<true> >, R = bool, T0 = __gnu_cxx::__normal_iterator<char*, std::basic_string<char> >&, T1 = const __gnu_cxx::__normal_iterator<char*, std::basic_string<char> >&, T2 = boost::spirit::context<boost::fusion::cons<std::basic_string<char>&, boost::fusion::nil>, boost::fusion::vector0<> >&, T3 = const boost::spirit::unused_type&]’
/usr/include/boost/function/function_template.hpp:722:7: instantiated from ‘boost::function4<R, T1, T2, T3, T4>::function4(Functor, typename boost::enable_if_c<boost::type_traits::ice_not<boost::is_integral<Functor>::value>::value, int>::type) [with Functor = boost::spirit::qi::detail::parser_binder<boost::spirit::qi::sequence<boost::fusion::cons<boost::spirit::qi::eps_parser, boost::fusion::cons<boost::spirit::qi::reference<const boost::spirit::qi::rule<__gnu_cxx::__normal_iterator<char*, std::basic_string<char> >, std::basic_string<char>(), boost::spirit::unused_type, boost::spirit::unused_type, boost::spirit::unused_type> >, boost::fusion::cons<boost::spirit::qi::kleene<boost::spirit::qi::sequence<boost::fusion::cons<boost::spirit::qi::alternative<boost::fusion::cons<boost::spirit::qi::omit_directive<boost::spirit::qi::reference<const boost::spirit::qi::rule<__gnu_cxx::__normal_iterator<char*, std::basic_string<char> >, std::basic_string<char>(), boost::spirit::unused_type, boost::spirit::unused_type, boost::spirit::unused_type> > >, boost::fusion::cons<boost::spirit::qi::omit_directive<boost::spirit::qi::reference<const boost::spirit::qi::rule<__gnu_cxx::__normal_iterator<char*, std::basic_string<char> >, std::basic_string<char>(), boost::spirit::unused_type, boost::spirit::unused_type, boost::spirit::unused_type> > >, boost::fusion::nil> > >, boost::fusion::cons<boost::spirit::qi::reference<const boost::spirit::qi::rule<__gnu_cxx::__normal_iterator<char*, std::basic_string<char> >, std::basic_string<char>(), boost::spirit::unused_type, boost::spirit::unused_type, boost::spirit::unused_type> >, boost::fusion::nil> > > >, boost::fusion::nil> > > >, mpl_::bool_<true> >, R = bool, T0 = __gnu_cxx::__normal_iterator<char*, std::basic_string<char> >&, T1 = const __gnu_cxx::__normal_iterator<char*, std::basic_string<char> >&, T2 = boost::spirit::context<boost::fusion::cons<std::basic_string<char>&, boost::fusion::nil>, boost::fusion::vector0<> >&, T3 = const boost::spirit::unused_type&, typename boost::enable_if_c<boost::type_traits::ice_not<boost::is_integral<Functor>::value>::value, int>::type = int]’
/usr/include/boost/function/function_template.hpp:1064:16: instantiated from ‘boost::function<R(T0, T1, T2, T3)>::function(Functor, typename boost::enable_if_c<boost::type_traits::ice_not<boost::is_integral<Functor>::value>::value, int>::type) [with Functor = boost::spirit::qi::detail::parser_binder<boost::spirit::qi::sequence<boost::fusion::cons<boost::spirit::qi::eps_parser, boost::fusion::cons<boost::spirit::qi::reference<const boost::spirit::qi::rule<__gnu_cxx::__normal_iterator<char*, std::basic_string<char> >, std::basic_string<char>(), boost::spirit::unused_type, boost::spirit::unused_type, boost::spirit::unused_type> >, boost::fusion::cons<boost::spirit::qi::kleene<boost::spirit::qi::sequence<boost::fusion::cons<boost::spirit::qi::alternative<boost::fusion::cons<boost::spirit::qi::omit_directive<boost::spirit::qi::reference<const boost::spirit::qi::rule<__gnu_cxx::__normal_iterator<char*, std::basic_string<char> >, std::basic_string<char>(), boost::spirit::unused_type, boost::spirit::unused_type, boost::spirit::unused_type> > >, boost::fusion::cons<boost::spirit::qi::omit_directive<boost::spirit::qi::reference<const boost::spirit::qi::rule<__gnu_cxx::__normal_iterator<char*, std::basic_string<char> >, std::basic_string<char>(), boost::spirit::unused_type, boost::spirit::unused_type, boost::spirit::unused_type> > >, boost::fusion::nil> > >, boost::fusion::cons<boost::spirit::qi::reference<const boost::spirit::qi::rule<__gnu_cxx::__normal_iterator<char*, std::basic_string<char> >, std::basic_string<char>(), boost::spirit::unused_type, boost::spirit::unused_type, boost::spirit::unused_type> >, boost::fusion::nil> > > >, boost::fusion::nil> > > >, mpl_::bool_<true> >, R = bool, T0 = __gnu_cxx::__normal_iterator<char*, std::basic_string<char> >&, T1 = const __gnu_cxx::__normal_iterator<char*, std::basic_string<char> >&, T2 = boost::spirit::context<boost::fusion::cons<std::basic_string<char>&, boost::fusion::nil>, boost::fusion::vector0<> >&, T3 = const boost::spirit::unused_type&, typename boost::enable_if_c<boost::type_traits::ice_not<boost::is_integral<Functor>::value>::value, int>::type = int]’
/usr/include/boost/function/function_template.hpp:1105:5: instantiated from ‘typename boost::enable_if_c<boost::type_traits::ice_not<boost::is_integral<Functor>::value>::value, boost::function<R(T0, T1, T2, T3)>&>::type boost::function<R(T0, T1, T2, T3)>::operator=(Functor) [with Functor = boost::spirit::qi::detail::parser_binder<boost::spirit::qi::sequence<boost::fusion::cons<boost::spirit::qi::eps_parser, boost::fusion::cons<boost::spirit::qi::reference<const boost::spirit::qi::rule<__gnu_cxx::__normal_iterator<char*, std::basic_string<char> >, std::basic_string<char>(), boost::spirit::unused_type, boost::spirit::unused_type, boost::spirit::unused_type> >, boost::fusion::cons<boost::spirit::qi::kleene<boost::spirit::qi::sequence<boost::fusion::cons<boost::spirit::qi::alternative<boost::fusion::cons<boost::spirit::qi::omit_directive<boost::spirit::qi::reference<const boost::spirit::qi::rule<__gnu_cxx::__normal_iterator<char*, std::basic_string<char> >, std::basic_string<char>(), boost::spirit::unused_type, boost::spirit::unused_type, boost::spirit::unused_type> > >, boost::fusion::cons<boost::spirit::qi::omit_directive<boost::spirit::qi::reference<const boost::spirit::qi::rule<__gnu_cxx::__normal_iterator<char*, std::basic_string<char> >, std::basic_string<char>(), boost::spirit::unused_type, boost::spirit::unused_type, boost::spirit::unused_type> > >, boost::fusion::nil> > >, boost::fusion::cons<boost::spirit::qi::reference<const boost::spirit::qi::rule<__gnu_cxx::__normal_iterator<char*, std::basic_string<char> >, std::basic_string<char>(), boost::spirit::unused_type, boost::spirit::unused_type, boost::spirit::unused_type> >, boost::fusion::nil> > > >, boost::fusion::nil> > > >, mpl_::bool_<true> >, R = bool, T0 = __gnu_cxx::__normal_iterator<char*, std::basic_string<char> >&, T1 = const __gnu_cxx::__normal_iterator<char*, std::basic_string<char> >&, T2 = boost::spirit::context<boost::fusion::cons<std::basic_string<char>&, boost::fusion::nil>, boost::fusion::vector0<> >&, T3 = const boost::spirit::unused_type&, typename boost::enable_if_c<boost::type_traits::ice_not<boost::is_integral<Functor>::value>::value, boost::function<R(T0, T1, T2, T3)>&>::type = boost::function<bool(__gnu_cxx::__normal_iterator<char*, std::basic_string<char> >&, const __gnu_cxx::__normal_iterator<char*, std::basic_string<char> >&, boost::spirit::context<boost::fusion::cons<std::basic_string<char>&, boost::fusion::nil>, boost::fusion::vector0<> >&, const boost::spirit::unused_type&)>&]’
/usr/include/boost/spirit/home/qi/nonterminal/rule.hpp:214:13: instantiated from ‘boost::spirit::qi::rule<Iterator, T1, T2, T3, T4>& boost::spirit::qi::operator%=(boost::spirit::qi::rule<Iterator, T1, T2, T3, T4>&, const Expr&) [with Expr = boost::proto::exprns_::expr<boost::proto::tag::shift_right, boost::proto::argsns_::list2<const boost::proto::exprns_::expr<boost::proto::tag::shift_right, boost::proto::argsns_::list2<const boost::spirit::terminal<boost::spirit::tag::eps>&, boost::spirit::qi::rule<__gnu_cxx::__normal_iterator<char*, std::basic_string<char> >, std::basic_string<char>(), boost::spirit::unused_type, boost::spirit::unused_type, boost::spirit::unused_type>&>, 2l>&, const boost::proto::exprns_::expr<boost::proto::tag::dereference, boost::proto::argsns_::list1<const boost::proto::exprns_::expr<boost::proto::tag::shift_right, boost::proto::argsns_::list2<const boost::proto::exprns_::expr<boost::proto::tag::bitwise_or, boost::proto::argsns_::list2<const boost::proto::exprns_::expr<boost::proto::tag::subscript, boost::proto::argsns_::list2<const boost::proto::exprns_::expr<boost::proto::tag::terminal, boost::proto::argsns_::term<boost::spirit::tag::omit>, 0l>&, boost::spirit::qi::rule<__gnu_cxx::__normal_iterator<char*, std::basic_string<char> >, std::basic_string<char>(), boost::spirit::unused_type, boost::spirit::unused_type, boost::spirit::unused_type>&>, 2l>&, const boost::proto::exprns_::expr<boost::proto::tag::subscript, boost::proto::argsns_::list2<const boost::proto::exprns_::expr<boost::proto::tag::terminal, boost::proto::argsns_::term<boost::spirit::tag::omit>, 0l>&, boost::spirit::qi::rule<__gnu_cxx::__normal_iterator<char*, std::basic_string<char> >, std::basic_string<char>(), boost::spirit::unused_type, boost::spirit::unused_type, boost::spirit::unused_type>&>, 2l>&>, 2l>&, boost::spirit::qi::rule<__gnu_cxx::__normal_iterator<char*, std::basic_string<char> >, std::basic_string<char>(), boost::spirit::unused_type, boost::spirit::unused_type, boost::spirit::unused_type>&>, 2l>&>, 1l>&>, 2l>, Iterator = __gnu_cxx::__normal_iterator<char*, std::basic_string<char> >, T1 = std::basic_string<char>(), T2 = boost::spirit::unused_type, T3 = boost::spirit::unused_type, T4 = boost::spirit::unused_type, boost::spirit::qi::rule<Iterator, T1, T2, T3, T4> = boost::spirit::qi::rule<__gnu_cxx::__normal_iterator<char*, std::basic_string<char> >, std::basic_string<char>(), boost::spirit::unused_type, boost::spirit::unused_type, boost::spirit::unused_type>]’
Main.cpp:161:6: instantiated from here
/usr/include/boost/spirit/home/qi/detail/assign_to.hpp:109:13: error: invalid static_cast from type ‘const std::basic_string<char>’ to type ‘char’
make: *** [part1] Error 1
我希望有人知道出了什么问题。
答案 0 :(得分:2)
所以,让我在一个单独的答案中发布重构。
花了不到30分钟。实际上,一个多小时。它基本上是一个改写。
它有171行代码(包括调试和样本测试)。看到 Live On Coliru 。跳到肉,这里你的整个语法:
identifier = lexeme[ char_("a-zA-Z_:.") >> *char_("0-9a-zA-Z_:.") ];
quoted_text = lexeme[ '"' >> *(char_ - '"') >> '"' ];
strAttrib = identifier >> '=' >> quoted_text >> ';';
realAttrib = identifier >> '=' >> double_ >> ';';
textNode = quoted_text;
nodelist = '{' >> *node >> '}';
node = tag
| strAttrib
| realAttrib
| textNode
;
tag = '(' >> identifier >> ')' >> -nodelist;
;
// allow only tags at root of parse tree
start = tag;
21行干净的语法作品。你印象深刻吗?我想你应该是。这是Boost Spirit最强大的力量。另见
现在您可能想知道AST的结果是什么:
namespace AST
{
struct TextNode {
std::string text;
// single element structs don't work well with Fusion Adapation...
TextNode(std::string text = "") : text(std::move(text)) {}
};
template <typename V> struct Attr_ {
std::string ID;
V Attrib;
Attr_(std::string ID = "", V Attrib = V())
: ID(std::move(ID)), Attrib(std::move(Attrib))
{ }
};
typedef Attr_<std::string> StringAttribute;
typedef Attr_<double> RealAttribute;
struct TagNode;
typedef boost::variant<
TextNode,
boost::recursive_wrapper<TagNode>,
StringAttribute,
RealAttribute
> Node;
// recursive node
struct TagNode {
std::string name;
std::vector<Node> nodes;
};
}
所以,更多的代码,但在36行,大约是原始位的一半。更重要的是:
节点较小。 小得多。在我的盒子上(gcc或clang优化的64bit / 32bit)
sizeof(sx::parserInternal::XNODE_): 88/48 bytes (!!!)
sizeof(sx::parserInternal::AST::Node): 24/16 bytes
3倍存储效率的提升。 无论实际数据如何。现在,对于许多非标记节点,由于缺少vector
的动态分配,节省可能更多。
但最重要的是:零开销属性传播。这就是
它也可以让我们在树上操作,访问它的节点,转换它等等。我已经超出了范围,但是让我展示一个小样本,它会告诉你如何可以递归地将新的AST::Node
样式树转换为您的“legace”XNODE_
树:
struct BuildLegacyXNode : boost::static_visitor<XNODE_> {
XNODE_ operator()(AST::TextNode const& n) const { XNODE_ r; r.type = XTEXT_; r.text = n.text; return r; }
XNODE_ operator()(AST::TagNode const& n) const { XNODE_ r; r.type = XTAG_; r.name = n.name; r.nodes = xform(n.nodes); return r; }
XNODE_ operator()(AST::StringAttribute const& n) const { XNODE_ r; r.type = S_ATTRIB_; r.strID = n.ID; r.strAttrib = n.Attrib; return r; }
XNODE_ operator()(AST::RealAttribute const& n) const { XNODE_ r; r.type = R_ATTRIB_; r.rID = n.ID; r.rAttrib = n.Attrib; return r; }
XNODE_ operator()(AST::Node const& n) const { return boost::apply_visitor(*this, n); }
private:
std::vector<XNODE_> xform(std::vector<AST::Node> const& n) const {
std::vector<XNODE_> r(n.size());
std::transform(n.begin(), n.end(), r.begin(), *this);
return r;
}
};
作为奖励,这是一个演示,显示在 c++03 mode on Coliru
工作using namespace sx::parserInternal;
const AST::Node output = parseSXdata2(data); // root of parsetree
BuildLegacyXNode transform;
XNODE_ legacy = transform(output);
std::cout << "Root tag is named '" << legacy.name << "' and has " << legacy.nodes.size() << " direct child nodes\n";
输出:
AST::Node: 24 bytes
XNODE_: 88 bytes
Root tag is named 'testsx' and has 2 direct child nodes
因此,即使将新AST转换为旧AST的完整代码也不能弥补我们仅在规则定义中保存的代码。编译时间减少了约20%。
TL; DR
- 简约是关键
- 简洁性来自约会(在一个良好的API框架中)
醇>
// #define BOOST_SPIRIT_DEBUG
#include <boost/config/warning_disable.hpp>
#include <boost/fusion/adapted/struct.hpp>
#include <boost/spirit/include/qi.hpp>
#include <boost/fusion/include/io.hpp>
#include <boost/variant/recursive_variant.hpp>
#include <stdexcept>
#include <vector>
#include <string>
#include <map>
namespace qi = boost::spirit::qi;
namespace phx = boost::phoenix;
namespace sx {
namespace parserInternal {
/**
* structure for boost spirit
* parsetree datastructure
*/
namespace AST
{
struct TextNode {
std::string text;
// single element structs don't work well with Fusion Adapation...
TextNode(std::string const& text = "") : text(text) {}
};
template <typename V> struct Attr_ {
std::string ID;
V Attrib;
Attr_(std::string const& ID = "", V const& Attrib = V())
: ID(ID), Attrib(Attrib)
{ }
};
typedef Attr_<std::string> StringAttribute;
typedef Attr_<double> RealAttribute;
struct TagNode;
typedef boost::variant<
TextNode,
boost::recursive_wrapper<TagNode>,
StringAttribute,
RealAttribute
> Node;
// recursive node
struct TagNode {
std::string name;
std::vector<Node> nodes;
};
}
/**
* example of how you can easily visit nodes
*/
enum XTYPE_ { XTEXT_ , XTAG_ , S_ATTRIB_, R_ATTRIB_ };
struct XNODE_ {
XTYPE_ type; // type code
std::string text; // TextNode
std::string name; std::vector<XNODE_> nodes; // TagNode
std::string strID, strAttrib; // StringAttribute
std::string rID; double rAttrib; // RealAttribute
std::string eat;
};
struct BuildLegacyXNode : boost::static_visitor<XNODE_> {
XNODE_ operator()(AST::TextNode const& n) const { XNODE_ r; r.type = XTEXT_; r.text = n.text; return r; }
XNODE_ operator()(AST::TagNode const& n) const { XNODE_ r; r.type = XTAG_; r.name = n.name; r.nodes = xform(n.nodes); return r; }
XNODE_ operator()(AST::StringAttribute const& n) const { XNODE_ r; r.type = S_ATTRIB_; r.strID = n.ID; r.strAttrib = n.Attrib; return r; }
XNODE_ operator()(AST::RealAttribute const& n) const { XNODE_ r; r.type = R_ATTRIB_; r.rID = n.ID; r.rAttrib = n.Attrib; return r; }
XNODE_ operator()(AST::Node const& n) const { return boost::apply_visitor(*this, n); }
private:
std::vector<XNODE_> xform(std::vector<AST::Node> const& n) const {
std::vector<XNODE_> r(n.size());
std::transform(n.begin(), n.end(), r.begin(), *this);
return r;
}
};
}
}
BOOST_FUSION_ADAPT_STRUCT(sx::parserInternal::AST::TagNode, (std::string, name) (std::vector<sx::parserInternal::AST::Node>, nodes))
BOOST_FUSION_ADAPT_STRUCT(sx::parserInternal::AST::TextNode, (std::string, text))
BOOST_FUSION_ADAPT_TPL_STRUCT((V), (sx::parserInternal::AST::Attr_)(V), (std::string, ID)(V, Attrib))
namespace sx {
namespace parserInternal {
/**
* grammar for the parser
*/
template <
typename It = std::string::const_iterator,
typename Skipper = qi::rule<It>
>
struct XGrammar: qi::grammar<It, AST::Node(), Skipper> {
qi::rule<It, std::vector<AST::Node>(), Skipper> nodelist;
qi::rule<It, AST::Node(), Skipper> node, start;
qi::rule<It, AST::TagNode(), Skipper> tag;
qi::rule<It, AST::TextNode(), Skipper> textNode;
qi::rule<It, AST::StringAttribute(), Skipper> strAttrib;
qi::rule<It, AST::RealAttribute(), Skipper> realAttrib;
// natural lexemes (using `lexeme` there is a bit redundant):
qi::rule<It, std::string()> identifier;
qi::rule<It, std::string()> quoted_text;
/**
* constructor, makes tag to the node's root
*/
XGrammar(): XGrammar::base_type(start) {
using namespace qi;
identifier = lexeme[ char_("a-zA-Z_:.") >> *char_("0-9a-zA-Z_:.") ];
quoted_text = lexeme[ '"' >> *(char_ - '"') >> '"' ];
strAttrib = identifier >> '=' >> quoted_text >> ';';
realAttrib = identifier >> '=' >> double_ >> ';';
textNode = quoted_text;
nodelist = '{' >> *node >> '}';
node = tag
| strAttrib
| realAttrib
| textNode
;
tag = '(' >> identifier >> ')' >> -nodelist;
;
// allow only tags at root of parse tree
start = tag;
BOOST_SPIRIT_DEBUG_NODES((start)(tag)(node)(nodelist)(textNode)(realAttrib)(strAttrib)(quoted_text)(identifier))
}
};
parserInternal::AST::Node parseSXdata2(std::string const& data) {
typedef std::string::const_iterator It;
typedef qi::rule<It> Skipper;
It iter1 = data.begin();
It iter2 = data.end();
static const Skipper skipper = qi::space
| ("/*" > *(qi::char_ - "*/") > "*/")
| ("//" > *(qi::char_ - qi::eol))
;
static const XGrammar<It, Skipper> grammar;
parserInternal::AST::Node output;
bool parsed = qi::phrase_parse(iter1, iter2, grammar, skipper, output);
if(!parsed || iter1 != iter2) {
throw std::runtime_error("Parsing failed");
}
return output;
}
}
}
int main() {
std::cout << "AST::Node: " << sizeof(sx::parserInternal::AST::Node) << " bytes\n";
std::cout << "XNODE_: " << sizeof(sx::parserInternal::XNODE_) << " bytes\n";
std::string const data =
"(testsx) {\n"
" (test) {\"hello world\"}\n"
" (test2) {\n"
" attrib1 = 123;\n"
" attrib2 = \"hey\";\n"
" }\n"
"}";
using namespace sx::parserInternal;
const AST::Node output = parseSXdata2(data); //root of parsetree
BuildLegacyXNode transform;
XNODE_ legacy = transform(output);
std::cout << "Root tag is named '" << legacy.name << "' and has " << legacy.nodes.size() << " direct child nodes\n";
}
答案 1 :(得分:1)
应该是
separator %= lexeme[(char_('\n') | lit("\r\n"))];
而不是
separator %= lexeme[(char_('\n') | char_('\r\n'))];
首发。 (注意引号)现在看看其余部分。
此外,以_
开头的标识符(经常)为标准库实现保留 - 使用它们调用未定义的行为。
在我看来,你混合/匹配自动属性传播(%=
)和语义动作相当疯狂和困惑。这可能是(许多)编译问题的一个因素。
实际上以表面的外观修复上述问题,使得在GCC上使用boost 1_55_0以及Clang(http://coliru.stacked-crooked.com/a/8710550143f4319a)
进行编译仍在寻找...
这里有大量的东西让我感到困惑。
为什么你融合了一个结构,只是通过序列索引从繁琐的semnatic行动中使用手动赋值?这是劳动密集型,冗长,难以阅读,容易出错且可能不必要的。我的意思是,你在哪里
strAttrib =
identifyer[at_c<4>(_val) = _1] >> char_('=') >>
textdata[at_c<5>(_val) = _1] >> char_(';')[at_c<0>(_val) = S_ATTRIB_];
你甚至可以说(没有任何融合适应)
strAttrib =
identifyer [ phx::bind(&XNODE_::strID, _val) = _1 ]
>> char_('=')
>> textdata [ phx::bind(&XNODE_::strAttrib, _val) = _1]
>> char_(';') [ phx::bind(&XNODE_::type, _val) = S_ATTRIB_];
我认为你会同意这对人类更好,对编译器更好。 当然 更适合维护。
这将我带到下一部分char_('=')
和char_(';')
应该是lit('=')
,或者只是';'
。这也无疑是
/**
* bug fix - stop parser from
* taking characters it shouldn't
* by assigning eat with the useless
* string sequences
*/
std::string eat;
可能与第一次观察结合(约%=
自动规则分配)。
此外,XNODE_
看起来应该是标记的联合。如果你不想干涉那些棘手的语义,那么你很幸运:提升你已经被Boost Variant所覆盖了,作为奖励,Spirit无法与你融为一体。所以我自然会想到这个:
typedef boost::variant<
Text,
boost::recursive_wrapper<Tag>,
SAttr,
RAttr
> Node;
这会缩小您的节点类型(不再需要在每个节点对象中都有vector
足迹!),无需显式类型代码管理(at_c<0>(_val) = XXXX
?)和< / strong>与Spirit的属性传播很好地集成。
我打算向您展示如何通过更少的代码实现更清晰的语法。给予足够的时间。我将在接下来的20-30分钟内尝试。