Boost Spirit代码,可与msvc编译,但与gcc编译错误

Boost Spirit code, compilable with msvc, but compilation erros with gcc

本文关键字:编译 但与 gcc 错误 可与 Spirit 代码 Boost msvc      更新时间:2023-10-16

不久前,我在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_('rn'))];
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;
}

我在MSVC 2008中使用boost库1.47成功编译了该代码。但是在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

我希望有人知道出了什么问题。

因此,让我在另一个答案中发布重大重构。

花了30多分钟。事实上,一个多小时。这基本上是一次重写。

它包含171行代码(包括调试和示例测试)。请参阅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行干净的语法作品
你印象深刻吗?我认为你应该是。这是提升精神的力量,它是最好的。另请参见

  • 提升精神:"语义行为是邪恶的">

现在你可能想知道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行,大约是原始位的一半。更重要的是:

  • 代码表达并加强了设计(例如,XTAG节点中没有SAttr成员)
  • 节点较小小得多。在我的盒子上(gcc或clang优化的64bit/32bit)

    sizeof(sx::parserInternal::XNODE_):      88/48 bytes (!!!)
    sizeof(sx::parserInternal::AST::Node):   24/16 bytes
    

    这是存储效率的3倍不管实际数据如何。现在,对于许多非标记节点,由于缺少对vector的动态分配,节省可能更多。

  • 但最重要的是:零开销属性传播。这就是

    • 使我们能够将Fusion和Phoenix从画面中删除(compiletimes,有人吗?)
    • 使我们能够在不执行单个语义操作的情况下传播所有属性
  • 它还将允许我们对树进行操作,访问它的节点,转换它,等等。我已经远远超出了这里的范围,但让我展示一个小示例,它向您展示了如何将新的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;
    }
    };
    

作为奖励,这里有一个演示显示在Coliru上以c++03模式工作

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 nodesn";

输出:

AST::Node: 24 bytes
XNODE_:    88 bytes
Root tag is named 'testsx' and has 2 direct child nodes

因此,即使是将新AST转换为旧AST的完整代码,也无法弥补我们单独保存在规则定义中的代码。编译时间减少了约20%。

TL;DR

  1. 简洁是关键
  2. 简单性伴随着惯例(在一个好的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) << " bytesn";
std::cout << "XNODE_:    " << sizeof(sx::parserInternal::XNODE_)    << " bytesn";
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 nodesn";
}

应该是

separator %= lexeme[(char_('n') | lit("rn"))];

而不是

separator %= lexeme[(char_('n') | char_('rn'))];

对于初学者来说。(注意引号)现在看剩下的。

此外,以_开头的标识符(经常)保留给标准库实现——使用它们调用未定义的行为。

在我看来,您将自动属性传播(%=)和语义操作混合/匹配得相当混乱。这可能是(许多)汇编问题中的一个因素。

事实上在表面上修复了上述问题,使事情在GCC上编译,并使用boost 1_55_0和Clang(http://coliru.stacked-crooked.com/a/8710550143f4319a)

还在看。。。

这里有很多事情让我很困惑。

  • 为什么要对结构进行融合调整,只使用乏味的语义操作的序列索引手动赋值?这是劳动密集型的、冗长的、难以阅读的、容易出错的,而且可能没有必要。我的意思是,在你有的地方

    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为你提供了boost Variant,作为奖励,Spirit似乎与之完美融合。所以我自然会想到:

    typedef boost::variant<
    Text,
    boost::recursive_wrapper<Tag>,
    SAttr,
    RAttr
    > Node;
    

    这缩小了节点类型(不再需要在每个节点对象中都有vector封装!),消除了对显式类型代码管理(at_c<0>(_val) = XXXX?)的需要,并且与Spirit的属性传播很好地集成。

    我打算向您展示如何用更少的代码实现更干净的语法。只要有足够的时间。我会在接下来的20-30分钟内尝试。