【问题标题】:Boost Spirit code, compilable with msvc, but compilation erros with gccBoost Spirit 代码,可以用 msvc 编译,但是用 gcc 编译出错
【发布时间】:2014-02-12 18:10:31
【问题描述】:

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

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

【问题讨论】:

  • 请在 Main.cpp 中标记第 161 行
  • 我刚刚在第 161 行添加了注释 ""//LINE 161!!!!"" ;)。

标签: c++ ubuntu gcc boost-spirit


【解决方案1】:

所以让我在一个单独的答案中发布大重构。

花了 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 样式树添加到您的“遗留”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. 简洁带有约定(在一个好的 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";
}

【讨论】:

    【解决方案2】:

    应该是

                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)

    还在寻找……

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

    • 为什么你融合适应一个结构,只使用从繁琐的语义动作中通过序列索引手动分配?这是劳动密集型的、冗长的、难以阅读的、容易出错的并且可能是不必要的。我的意思是,你在哪里

      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&lt;0&gt;(_val) = XXXX?)集成与 Spirit 的属性传播相得益彰。

      我打算向您展示这将如何用更少的代码产生更简洁的语法。给了足够的时间。我会在接下来的 20-30 分钟内尝试。

    【讨论】:

    • 代码审查的初步结果在 :) 再给我几分钟... :)
    • 好的,我已经完成了一些工作。我已经包含了我认为相关的“良好精神风格”的任何元素,并最终将 AST 转换添加到您的 legacy :) XNODE_ 类型。即使添加了这一点,代码也缩减了 100 行。 Read all about it
    猜你喜欢
    • 1970-01-01
    • 2020-06-03
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-09-01
    • 2015-05-13
    • 1970-01-01
    相关资源
    最近更新 更多