使用msvc编译的Boost Spirit代码,但是使用gcc编译错误

时间:2014-02-12 18:10:32

标签: c++ ubuntu gcc boost-spirit

前段时间我在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

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

2 个答案:

答案 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行,大约是原始位的一半。更重要的是:

  • 代码表达并强化了设计(例如,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从图片中删除(编译时,有人吗?)
    • 使我们能够传播所有属性而无需单一语义操作
  • 它也可以让我们在树上操作,访问它的节点,转换它等等。我已经超出了范围,但是让我展示一个小样本,它会告诉你如何可以递归地将新的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

     
      
  1. 简约是关键
  2.   
  3. 简洁性来自约会(在一个良好的API框架中)
  4.   

完整代码

// #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分钟内尝试。