X3:非终端解析器上的链接器错误(未解析的外部符号"parse_rule")

X3: Linker Error (unresolved external symbol "parse_rule") on nonterminal parser

本文关键字:符号 外部 rule parse 链接 终端 错误 X3      更新时间:2023-10-16

首先,我使用的是MSVC 2017(最新版本(。 这是我的非终端解析器代码:

玩家.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

播放器.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;
};

我愿意打赌 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::p layer_type const& player((; impl::p layer_vector_type const& player_vector((;

    注意:这应该没问题,静态初始化顺序惨败

  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;
    }
    }
    

完整演示

在魔杖盒上直播

  • 东西.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 {}; } 
    };
    
  • 测试.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
    
  • 测试.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
    
  • 主.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"
相关文章: