Boost Spirit код, скомпилированный с msvc, но ошибки компиляции с gcc

0

Некоторое время назад я писал код синтаксического анализа в окнах, который просто отлично работал. Теперь я пытаюсь создать его на 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 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

Надеюсь, у кого-то есть идея, что пошло не так.

  • 1
    пожалуйста, отметьте строку 161 в Main.cpp
  • 0
    Я просто добавил комментарий "" // LINE 161 !!!! "" в строку 161;).
Теги:
gcc
boost-spirit

2 ответа

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 строчка чистой грамматики.
Вы впечатлены? Думаю, ты должен быть. Это лучшая сила Духа Боста. Смотрите также

Теперь вы можете задаться вопросом, чем оказался АСТ:

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 строк, примерно половина исходных бит. Важнее:

  • Код выражает и усиливает дизайн (без элементов SAttr в узле XTAG, например)
  • Узлы меньше. Гораздо меньше. На моей коробке (gcc или clang оптимизированный 64-битный /32-битный)

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

    Это 3-кратное повышение эффективности хранения. Независимо от фактических данных. Теперь, когда множество узлов без тегов, сохранение может быть еще больше из-за отсутствия динамических распределений для vector.

  • Но самое главное: распространение атрибутов с нулевой нагрузкой. Это то, что

    • позволили нам вырезать Fusion и Phoenix из картинки (compiletimes, кто-нибудь?)
    • позволили нам распространять все атрибуты без единого семантического действия
  • Это также тривиально позволяет нам работать на дереве, посещать его узлы, трансформировать его и т.д. Я получаю выход за рамки области, но позвольте мне показать небольшой пример, который показывает вам, как вы могли бы рекурсивно преобразовывать новый AST::Node Дерево стиля 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;
        }
    };
    

В качестве бонуса здесь показана демонстрация того, что работает в режиме С++ 03 на 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

Таким образом, даже полный код для преобразования нового АСТ в старый АСТ даже не компенсирует код, который мы сохранили только в определениях правил. И время компиляции уменьшается на ~ 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 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

Должен быть

            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<0>(_val) = XXXX необходимость в явном управлении кодом типа (at_c<0>(_val) = XXXX?) И прекрасно сочетается с распространением атрибутов Spirit.

    Я намерен показать вам, как это приведет к более чистой грамматике с гораздо меньшим количеством кода. Дано достаточно времени. Я попробую в ближайшие 20-30 минут.

  • 0
    Предварительные результаты проверки кода приведены :) Дайте мне еще несколько минут ... :)
  • 0
    Хорошо, я сделал кое-что из этого. Я включил любые элементы «Good Style Spirit» я думал , что это уместно, и в конечном итоге с добавлением трансформации AST к вашему типу наследство :) XNODE_. Даже с учетом этого код сократился на 100 строк. Прочитать все об этом

Ещё вопросы

Сообщество Overcoder
Наверх
Меню