X3: Ошибка компоновщика (неразрешенный внешний символ "parse_rule") в нетерминальном парсере - PullRequest
0 голосов
/ 10 мая 2018

Прежде всего я использую MSVC 2017 (последняя версия).Вот мой код для нетерминального парсера:

player.hpp

namespace parse
{
    namespace impl
    {
        namespace x3 = boost::spirit::x3;

        struct _tag;

        using player_type = x3::rule<_tag, PlayerIterator>;
        using player_vector_type = x3::rule<_tag, std::vector<PlayerIterator>>;
        BOOST_SPIRIT_DECLARE(player_type);
        BOOST_SPIRIT_DECLARE(player_vector_type);
    }; //impl

    impl::player_type player();
    impl::player_vector_type player_vector();
}; //parse

player.cpp

namespace parse
{
    namespace impl
    {
        const player_type player = "player";
        const player_vector_type player_vector = "player_vector";
        auto player_find = [](auto &ctx)
        {
            auto &attr = x3::_attr(ctx);
            if(attr.which() == 0)
                return x3::_val(ctx) = PlayerManager::find(boost::get<int>(attr));
            return x3::_val(ctx) = PlayerManager::find(boost::get<std::string>(attr));
        };
        auto player_vector_find = [](auto &ctx)
        {
            return x3::_val(ctx) = PlayerManager::vector_find(x3::_attr(ctx));
        };
        auto const player_def = (x3::int_ | (+x3::char_))[player_find];
        auto const player_vector_def = (((+x3::char_)[player_vector_find]));
        BOOST_SPIRIT_DEFINE(player);
        BOOST_SPIRIT_DEFINE(player_vector);
        BOOST_SPIRIT_INSTANTIATE(player_type, iterator_type, context_type);
        BOOST_SPIRIT_INSTANTIATE(player_vector_type, iterator_type, context_type);
    } //impl
    parse::impl::player_type player() { return impl::player; }
    parse::impl::player_vector_type player_vector() { return impl::player_vector; }
}//parse

Я получаю ошибки компоновщика LNK2019 о "неразрешенных внешних символах, на которые ссылаются":
Ссылка Pastebin.com с ошибками Есть идеи о них?Заранее спасибо.

РЕДАКТИРОВАТЬ: Вот как я называю это в моем исходном файле:

void test(std::string &params)
{
    std::tuple<PlayerIterator, std::vector<PlayerIterator>, std::string> tuple;
    if (!x3::phrase_parse(params.begin(), params.end(), parse::player()>> parse::player_vector() >> (+x3::char_), x3::space,tuple))
    {
        std::cout << "Error: Parsing failed" << std::endl;
        return;
    }
    std::cout << "Parsing succeded" << std::endl;
    std::cout << "Found player, size of player vector: "<< std::get<1>(tuple).size() << ", also parsed string:" << std::get<2>(tuple);
    return;
};

1 Ответ

0 голосов
/ 12 мая 2018

Я готов поставить 10 $, что вы не соответствовали контексту или типам итераторов в экземплярах.

например. в вашей функции test аргумент равен std::string&, следовательно, params.begin() будет std::string::iterator. Если вы настроили iterator_type следующим образом:

using iterator_type = std::string::const_iterator; // very sensible!

у вас будут неразрешенные внешние объекты, поскольку тип итератора не соответствует фактически необходимому.

То же самое для контекста. Чтобы соответствовать вашему вызову, оно должно быть точно:

using context_type = x3::phrase_parse_context<x3::space_type>::type;

К сожалению, вы не показали весь код, поэтому вам придется проверить самостоятельно.

Примечания

  1. Повторное использование типа тега - это рецепт катастрофы. Я не думаю, что это может работать. Теги правила - это то, что отправляет функцию реализации в случае отдельных блоков компиляции. Исправьте это:

    using player_type        = x3::rule<struct player_tag,        PlayerIterator>;
    using player_vector_type = x3::rule<struct player_vector_tag, std::vector<PlayerIterator>>;
    
  2. копирование правил кажется расточительным, рассмотрите возможность возврата по ссылке:

    impl :: player_type const & player (); impl :: player_vector_type const & player_vector ();

    Примечание: все должно быть в порядке w.r.t. статический порядок инициализации фиаско

  3. использование which() для варианта является анти-паттерном. Вы можете заменить

    auto player_find = [](auto &ctx) {
        auto &attr = x3::_attr(ctx);
        if (attr.which() == 0)
            return x3::_val(ctx) = PlayerManager::find(boost::get<int>(attr));
        return x3::_val(ctx) = PlayerManager::find(boost::get<std::string>(attr));
    };
    

    С

    auto find = [](auto const& key) { return PlayerManager::find(key); };
    auto player_find = [](auto &ctx) {
        return x3::_val(ctx) = boost::apply_visitor(find, x3::_attr(ctx));
    };
    
  4. (+x3::char_) всегда соответствует всем входным данным

  5. (+x3::graph) все еще соответствует всем данным из-за шкипера
  6. Вместо этого вы хотели лексему:

    auto const name              = x3::lexeme[+x3::graph];
    auto const player_def        = (x3::int_ | name) [player_find];
    auto const player_vector_def = name[ player_vector_find];
    
  7. Могу я предложить написать функцию test гораздо более кратко:

    void test(std::string const &params) {
        auto comment_ = x3::lexeme[+x3::char_];
    
        PlayerIterator player;
        PlayerIterators vec;
        std::string comment;
        auto tuple = std::tie(player, vec, comment);
    
        if (phrase_parse(params.cbegin(), params.cend(), parse::player() >> parse::player_vector() >> comment_, x3::space, tuple)) {
            std::cout << "Parsing succeded" << std::endl;
            std::cout << "Found player, size of player vector: " << vec.size() << "\n";
            std::cout << "Also parsed string: " << std::quoted(comment);
        } else {
            std::cout << "Error: Parsing failed" << std::endl;
        }
    }
    

Полная демонстрация

Посмотреть Live On Wandbox

  • stuff.h

    Содержит макет PlayerManager

    #pragma once
    #include <string>
    #include <vector>
    #include <iostream>
    
    struct PlayerIterator { };
    using PlayerIterators = std::vector<PlayerIterator>;
    
    struct PlayerManager {
        static PlayerIterator              find(std::string const&)        { std::cout << __PRETTY_FUNCTION__ << "\n"; return {}; } 
        static PlayerIterator              find(int)                       { std::cout << __PRETTY_FUNCTION__ << "\n"; return {}; } 
        static PlayerIterators vector_find(std::string const&) { std::cout << __PRETTY_FUNCTION__ << "\n"; return {}; } 
    };
    
  • test.h

    #pragma once
    #include <boost/spirit/home/x3.hpp>
    #include <boost/fusion/adapted.hpp>
    #include "stuff.h"
    
    namespace x3 = boost::spirit::x3;
    
    namespace parse
    {
        namespace impl
        {
            using player_type        = x3::rule<struct player_tag,        PlayerIterator>;
            using player_vector_type = x3::rule<struct player_vector_tag, PlayerIterators>;
    
            BOOST_SPIRIT_DECLARE(player_type)
            BOOST_SPIRIT_DECLARE(player_vector_type)
        } //impl
    
        impl::player_type const& player();
        impl::player_vector_type const& player_vector();
    } //parse
    
  • test.cpp

    #include "stuff.h"
    #include "test.h"
    
    using iterator_type = std::string::const_iterator;
    using context_type = x3::phrase_parse_context<x3::space_type>::type;
    
    namespace parse {
        namespace impl {
            const player_type player               = "player";
            const player_vector_type player_vector = "player_vector";
    
            auto find               = [](auto const& key) { return PlayerManager::find(key); } ;
            auto player_find        = [](auto &ctx)       { return x3::_val(ctx) = boost::apply_visitor(find, x3::_attr(ctx)); } ;
            auto player_vector_find = [](auto &ctx)       { return x3::_val(ctx) = PlayerManager::vector_find(x3::_attr(ctx)); } ;
    
            auto const name              = x3::lexeme[+x3::graph];
            auto const player_def        = (x3::int_ | name) [player_find];
            auto const player_vector_def = name[ player_vector_find];
    
            BOOST_SPIRIT_DEFINE(player)
            BOOST_SPIRIT_DEFINE(player_vector)
    
            BOOST_SPIRIT_INSTANTIATE(player_type,        iterator_type, context_type)
            BOOST_SPIRIT_INSTANTIATE(player_vector_type, iterator_type, context_type)
        } // namespace impl
    
        parse::impl::player_type const& player()               { return impl::player; }
        parse::impl::player_vector_type const& player_vector() { return impl::player_vector; }
    } // namespace parse
    
  • main.cpp

    #include "stuff.h"
    #include "test.h"
    #include <iostream>
    #include <iomanip>
    
    void test(std::string const &params) {
        auto comment_ = x3::lexeme[+x3::char_];
    
        PlayerIterator player;
        PlayerIterators vec;
        std::string comment;
        auto tuple = std::tie(player, vec, comment);
    
        if (phrase_parse(params.cbegin(), params.cend(), parse::player() >> parse::player_vector() >> comment_, x3::space, tuple)) {
            std::cout << "Parsing succeded" << std::endl;
            std::cout << "Found player, size of player vector: " << vec.size() << "\n";
            std::cout << "Also parsed string: " << std::quoted(comment);
        } else {
            std::cout << "Error: Parsing failed" << std::endl;
        }
    }
    
    int main() {
        test("42 someword # bogus trailing comment");
    }
    

Печать:

static PlayerIterator PlayerManager::find(int)
static PlayerIterators PlayerManager::vector_find(const std::string &)
Parsing succeded
Found player, size of player vector: 0
Also parsed string: "# bogus trailing comment"
...