编译错误::精灵解析器

时间:2022-10-31 20:20:55

I have a strange problem with a calculator made using boost::spirit. This calculator is supposed to take a string as argument representing a series of arithmetical expression separated by commas, like "a+4*5,77,(b-c)*4". It also allows the string "?" and returns the array containing a -1 in this case. The calculator is initialized with a SymTable, which is a template class argument to describe any class offering the [string] -> int operator (example: a map), to resolve the value of variables.

我有一个奇怪的问题,一个计算器用boost::spirit。这个计算器应该用一个字符串作为参数来表示一系列用逗号分隔的算术表达式,比如“a+4*5,77,(b-c)*4”。它还允许字符串“?”,并返回包含-1的数组。计算器是用SymTable初始化的,SymTable是一个模板类参数,用于描述提供[string] -> int运算符(例如:map)的任何类,以解析变量的值。

The following code works on my Ubuntu 10.4 with both gcc 4.6.2 and gcc 4.4, and both boost 1.47 and 1.48. It also worked in the past on a Cray Linux machine with gcc 4.5.3 and boost 1.47.

下面的代码在我的Ubuntu 10.4上运行,gcc 4.6.2和gcc 4.4都支持,boost 1.47和1.48。它也在过去的Cray Linux机器上使用了gcc 4.5.3和boost 1.47。

#include <boost/bind.hpp>
#include <boost/spirit/include/qi.hpp>
#include <boost/spirit/include/phoenix_core.hpp>
#include <boost/spirit/include/phoenix_operator.hpp>

namespace sp = boost::spirit;
namespace qi = boost::spirit::qi;
namespace ascii = boost::spirit::ascii;

namespace Damaris {

template <typename Iterator, typename SymTable>
struct Calc : qi::grammar<Iterator, std::vector<int>(), ascii::space_type>
{
        qi::rule<Iterator, std::vector<int>(), ascii::space_type> start;
        qi::rule<Iterator, int(), ascii::space_type> expr;
        qi::rule<Iterator, int(), ascii::space_type> qmark;
        qi::rule<Iterator, int(), ascii::space_type> factor;
        qi::rule<Iterator, int(), ascii::space_type> simple;
        qi::rule<Iterator, std::string(), ascii::space_type> identifier;
        qi::rule<Iterator, int(SymTable), ascii::space_type> value;

        /**
         * \brief Constructor.
         * \param[in] sym : table of symboles.
         */
        Calc(SymTable &sym) : Calc::base_type(start)
        {
                identifier = qi::lexeme[( qi::alpha | '_') >> *( qi::alnum | '_')];

                value   = identifier[qi::_val = qi::labels::_r1[qi::_1]];

                simple  = ('(' >> expr >> ')')
                        | qi::int_
                        | value(boost::phoenix::ref(sym));

                factor  %= (simple >> '*' >> factor)[qi::_val = qi::_1 * qi::_2]
                        |  (simple >> '/' >> factor)[qi::_val = qi::_1 / qi::_2]
                        |  (simple >> '%' >> factor)[qi::_val = qi::_1 % qi::_2]
                        |   simple;

                expr    %= (factor >> '+' >> expr)[qi::_val = qi::_1 + qi::_2]
                        |  (factor >> '-' >> expr)[qi::_val = qi::_1 - qi::_2]
                        |   factor;

                qmark   = qi::char_('?')[qi::_val = -1];

                start   = qmark
                        | (expr % ',');
        }
};

}

Today I tried again compiling the same code on the Cray machine (which has been upgraded since then, I think), I tried with gcc 4.6.2 and gcc 4.5.2, and both with boost 1.48 and 1.49, and I always get the same compilation error that I don't understand :

今天我再次尝试在Cray机器上编译相同的代码(我想从那以后已经升级了),我尝试使用gcc 4.6.2和gcc 4.5.2,使用boost 1.48和1.49,我总是得到我不理解的相同的编译错误:

/nics/b/home/mdorier/damaris-0.4/common/Calc.hpp:74:3:   instantiated from 'Damaris::Calc<Iterator, SymTable>::Calc(SymTable&) [with Iterator = __gnu_cxx::__normal_iterator<const char*, std::basic_string<char> >, SymTable = Damaris::ParameterSet]'
/nics/b/home/mdorier/damaris-0.4/common/MetadataManager.cpp:45:79:   instantiated from here
/nics/b/home/mdorier/deploy/include/boost/spirit/home/qi/detail/assign_to.hpp:123:13: error: invalid static_cast from type 'const boost::fusion::vector2<int, int>' to type 'int'

The line 74 in Calc.hpp corresponds to the line "factor = ...". The instantiation line indicated (MetadataManager.cpp:45) is the following:

Calc.hpp中的第74行对应于“factor =…”行。指示的实例化行(MetadataManager.cpp:45)如下:

layoutInterp = new Calc<std::string::const_iterator,ParameterSet>(*parameters);

with layoutInterp being of type Calc* and parameters being of type ParameterSet*.

使用layoutInterp类型的Calc*和参数设置的参数*。

Any idea where this error comes from? Thanks

知道这个错误来自哪里吗?谢谢

1 个解决方案

#1


4  

I'm pretty sure you might have been rearranging stuff in your rules. In fact, the %= auto-rule expression assignments won't work because the synthesized type of the parser expression doesn't resemble an int.

我敢肯定你可能是在重新安排你的规则。实际上,%=自动规则表达式赋值不会起作用,因为解析器表达式的合成类型不像int类型。

Basically, you'd change

基本上,你会改变

factor %= (simple >> '*' >> factor)[ _val = _1 * _2 ]
    |  (simple >> '/' >> factor)[ _val = _1 / _2 ]
    |  (simple >> '%' >> factor)[ _val = _1 % _2 ]
    |   simple;

expr   %= (factor >> '+' >> expr)[ _val = _1 + _2 ]
    |  (factor >> '-' >> expr)[ _val = _1 - _2 ]
    |   factor;

into

factor  = (simple >> '*' >> factor)[ _val = _1 * _2 ]
        | (simple >> '/' >> factor)[ _val = _1 / _2 ]
        | (simple >> '%' >> factor)[ _val = _1 % _2 ]
        | (simple) [_val = _1 ];

expr    = (factor >> '+' >> expr)[ _val = _1 + _2 ]
        | (factor >> '-' >> expr)[ _val = _1 - _2 ]
        | (factor) [_val = _1 ];

I have fixed up some small issues and created a SSCCE of your post that works, as far as I can tell 1:

我已经解决了一些小问题,并创建了一个SSCCE你的工作,据我所知:

#include <boost/spirit/include/qi.hpp>
#include <boost/spirit/include/karma.hpp>
#include <boost/spirit/include/phoenix.hpp>

namespace sp = boost::spirit;
namespace qi    = boost::spirit::qi;
namespace ascii = boost::spirit::ascii;
namespace karma = boost::spirit::karma;
namespace phx   = boost::phoenix;

namespace Damaris {

    template <typename Iterator, typename SymTable>
    struct Calc : qi::grammar<Iterator, std::vector<int>(), ascii::space_type>
    {
        qi::rule<Iterator, std::vector<int>(), ascii::space_type> start;
        qi::rule<Iterator, int(), ascii::space_type> expr;
        qi::rule<Iterator, int(), ascii::space_type> qmark;
        qi::rule<Iterator, int(), ascii::space_type> factor;
        qi::rule<Iterator, int(), ascii::space_type> simple;
        qi::rule<Iterator, std::string(), ascii::space_type> identifier;
        qi::rule<Iterator, int(SymTable), ascii::space_type> value;

        Calc(SymTable &sym) : Calc::base_type(start)
        {
            using namespace qi;

            identifier = lexeme[( alpha | '_') >> *( alnum | '_')];

            value   = identifier[ _val = _r1[_1] ];

            simple  = ('(' >> expr >> ')')
                    | int_
                    | value(boost::phoenix::ref(sym));

            factor  = (simple >> '*' >> factor)[ _val = _1 * _2 ]
                    | (simple >> '/' >> factor)[ _val = _1 / _2 ]
                    | (simple >> '%' >> factor)[ _val = _1 % _2 ]
                    | (simple) [_val = _1 ];

            expr    = (factor >> '+' >> expr)[ _val = _1 + _2 ]
                    | (factor >> '-' >> expr)[ _val = _1 - _2 ]
                    | (factor) [_val = _1 ];

            qmark   = char_('?')[ _val = -1 ];

            start   = qmark 
                | (expr % ',');

            BOOST_SPIRIT_DEBUG_NODE(start);
            BOOST_SPIRIT_DEBUG_NODE(qmark);
            BOOST_SPIRIT_DEBUG_NODE(expr);
            BOOST_SPIRIT_DEBUG_NODE(factor);
            BOOST_SPIRIT_DEBUG_NODE(simple);
            BOOST_SPIRIT_DEBUG_NODE(value);
            BOOST_SPIRIT_DEBUG_NODE(identifier);
        }
    };

}

int main(int argc, const char *argv[])
{
    typedef std::map<std::string, int> SymTable;
    SymTable symbols;
    Damaris::Calc<std::string::const_iterator, SymTable> calc(symbols);

    symbols["TheAnswerToLifeUniverse"] = 100;
    symbols["Everything"] = -58;

    std::string input = "3*4+5/4, TheAnswerToLifeUniverse + Everything";
    std::string::const_iterator f(input.begin()), l(input.end());
    std::vector<int> data;

    if (qi::phrase_parse(f,l,calc,ascii::space,data))
        std::cout << "output: " << karma::format(karma::int_ % ", " << karma::eol, data);
    else
        std::cout << "problem: '" << std::string(f,l) << "'\n";

    return 0;
}

Output:

输出:

output: 13, 42

1 gcc 4.6.1, boost 1_48

1 gcc 4.6.1, boost 1_48

#1


4  

I'm pretty sure you might have been rearranging stuff in your rules. In fact, the %= auto-rule expression assignments won't work because the synthesized type of the parser expression doesn't resemble an int.

我敢肯定你可能是在重新安排你的规则。实际上,%=自动规则表达式赋值不会起作用,因为解析器表达式的合成类型不像int类型。

Basically, you'd change

基本上,你会改变

factor %= (simple >> '*' >> factor)[ _val = _1 * _2 ]
    |  (simple >> '/' >> factor)[ _val = _1 / _2 ]
    |  (simple >> '%' >> factor)[ _val = _1 % _2 ]
    |   simple;

expr   %= (factor >> '+' >> expr)[ _val = _1 + _2 ]
    |  (factor >> '-' >> expr)[ _val = _1 - _2 ]
    |   factor;

into

factor  = (simple >> '*' >> factor)[ _val = _1 * _2 ]
        | (simple >> '/' >> factor)[ _val = _1 / _2 ]
        | (simple >> '%' >> factor)[ _val = _1 % _2 ]
        | (simple) [_val = _1 ];

expr    = (factor >> '+' >> expr)[ _val = _1 + _2 ]
        | (factor >> '-' >> expr)[ _val = _1 - _2 ]
        | (factor) [_val = _1 ];

I have fixed up some small issues and created a SSCCE of your post that works, as far as I can tell 1:

我已经解决了一些小问题,并创建了一个SSCCE你的工作,据我所知:

#include <boost/spirit/include/qi.hpp>
#include <boost/spirit/include/karma.hpp>
#include <boost/spirit/include/phoenix.hpp>

namespace sp = boost::spirit;
namespace qi    = boost::spirit::qi;
namespace ascii = boost::spirit::ascii;
namespace karma = boost::spirit::karma;
namespace phx   = boost::phoenix;

namespace Damaris {

    template <typename Iterator, typename SymTable>
    struct Calc : qi::grammar<Iterator, std::vector<int>(), ascii::space_type>
    {
        qi::rule<Iterator, std::vector<int>(), ascii::space_type> start;
        qi::rule<Iterator, int(), ascii::space_type> expr;
        qi::rule<Iterator, int(), ascii::space_type> qmark;
        qi::rule<Iterator, int(), ascii::space_type> factor;
        qi::rule<Iterator, int(), ascii::space_type> simple;
        qi::rule<Iterator, std::string(), ascii::space_type> identifier;
        qi::rule<Iterator, int(SymTable), ascii::space_type> value;

        Calc(SymTable &sym) : Calc::base_type(start)
        {
            using namespace qi;

            identifier = lexeme[( alpha | '_') >> *( alnum | '_')];

            value   = identifier[ _val = _r1[_1] ];

            simple  = ('(' >> expr >> ')')
                    | int_
                    | value(boost::phoenix::ref(sym));

            factor  = (simple >> '*' >> factor)[ _val = _1 * _2 ]
                    | (simple >> '/' >> factor)[ _val = _1 / _2 ]
                    | (simple >> '%' >> factor)[ _val = _1 % _2 ]
                    | (simple) [_val = _1 ];

            expr    = (factor >> '+' >> expr)[ _val = _1 + _2 ]
                    | (factor >> '-' >> expr)[ _val = _1 - _2 ]
                    | (factor) [_val = _1 ];

            qmark   = char_('?')[ _val = -1 ];

            start   = qmark 
                | (expr % ',');

            BOOST_SPIRIT_DEBUG_NODE(start);
            BOOST_SPIRIT_DEBUG_NODE(qmark);
            BOOST_SPIRIT_DEBUG_NODE(expr);
            BOOST_SPIRIT_DEBUG_NODE(factor);
            BOOST_SPIRIT_DEBUG_NODE(simple);
            BOOST_SPIRIT_DEBUG_NODE(value);
            BOOST_SPIRIT_DEBUG_NODE(identifier);
        }
    };

}

int main(int argc, const char *argv[])
{
    typedef std::map<std::string, int> SymTable;
    SymTable symbols;
    Damaris::Calc<std::string::const_iterator, SymTable> calc(symbols);

    symbols["TheAnswerToLifeUniverse"] = 100;
    symbols["Everything"] = -58;

    std::string input = "3*4+5/4, TheAnswerToLifeUniverse + Everything";
    std::string::const_iterator f(input.begin()), l(input.end());
    std::vector<int> data;

    if (qi::phrase_parse(f,l,calc,ascii::space,data))
        std::cout << "output: " << karma::format(karma::int_ % ", " << karma::eol, data);
    else
        std::cout << "problem: '" << std::string(f,l) << "'\n";

    return 0;
}

Output:

输出:

output: 13, 42

1 gcc 4.6.1, boost 1_48

1 gcc 4.6.1, boost 1_48