使用 boost spirit x3 分离解析器时出现链接错误
linking errors while separate parser using boost spirit x3
我目前正在尝试使用 BOOST_SPIRIT_DEFINE/DECLARE/INSTANTIATE
将我的 boost spirit x3 解析器分成不同的 _def 和 .cpp 文件,但我一直收到链接错误。
HERE 是我的解析器,它是分开的。
链接器错误读取
<artificial>:(.text.startup+0xbb): undefined reference to `bool kyle::parser::impl::parse_rule<__gnu_cxx::__normal_iterator<char*, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > >, boost::spirit::x3::context<boost::spirit::x3::skipper_tag, boost::spirit::x3::char_class<boost::spirit::char_encoding::standard, boost::spirit::x3::space_tag> const, boost::spirit::x3::unused_type>, boost::spirit::x3::unused_type const>(boost::spirit::x3::rule<kyle::parser::impl::identifier_class, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >, false>, __gnu_cxx::__normal_iterator<char*, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > >&, __gnu_cxx::__normal_iterator<char*, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > > const&, boost::spirit::x3::context<boost::spirit::x3::skipper_tag, boost::spirit::x3::char_class<boost::spirit::char_encoding::standard, boost::spirit::x3::space_tag> const, boost::spirit::x3::unused_type> const&, boost::spirit::x3::unused_type const&)'
我做错了什么?我怎样才能让我的例子发挥作用?
config.hpp:
#include <boost/spirit/home/x3.hpp>
namespace kyle{
namespace parser{
namespace x3 = boost::spirit::x3;
typedef std::string::const_iterator iterator_type;
typedef x3::phrase_parse_context<x3::ascii::space_type>::type context_type;
}
}
literals.cpp:
#include "literals_def.hpp"
#include "config.hpp"
#include <boost/spirit/home/x3.hpp>
namespace kyle {
namespace parser {
namespace impl {
BOOST_SPIRIT_INSTANTIATE(identifier_type, iterator_type, context_type);
}
}
}
literals_def.hpp:
#include <boost/spirit/home/x3.hpp>
#include "literals.hpp"
namespace kyle {
namespace parser {
namespace impl {
namespace x3 = boost::spirit::x3;
const identifier_type identifier = "identifier";
auto const identifier_def = x3::alpha >> *x3::alnum;
BOOST_SPIRIT_DEFINE(identifier)
}
impl::identifier_type identifier(){
return impl::identifier;
}
}
}
literals.hpp:
#include <boost/spirit/home/x3.hpp>
namespace kyle{
namespace parser{
namespace impl {
namespace x3 = boost::spirit::x3;
struct identifier_class;
typedef x3::rule<identifier_class, std::string> identifier_type;
BOOST_SPIRIT_DECLARE(identifier_type)
}
impl::identifier_type identifier();
}
}
main.cpp:
#include "literals.hpp"
#include <iostream>
template<typename Parser>
bool test(std::string str, Parser&& p, bool full_match = true)
{
auto in = str.begin();
auto end = str.end();
bool ret = boost::spirit::x3::phrase_parse(in, end, p, boost::spirit::x3::space);
ret &= (!full_match || (in == end));
return ret;
}
int main(){
auto b = test("fobar", kyle::parser::identifier());
std::cout << b << std::endl;
}
两点:
您将上下文定义为
typedef x3::phrase_parse_context<x3::space_type>::type context_type;
但是,您尝试使用 x3::space
而不是 x3::ascii::space
来调用它。
提示在您没有包含的错误消息中:
/home/sehe/custom/boost/boost/spirit/home/x3/nonterminal/rule.hpp:116: undefined reference to 'bool kyle::parser::impl::parse_rule<__gnu_cxx::__normal_iterator<char const*, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > >, boost::spirit::x3::context<boost::spirit::x3::skipper_tag, boost::spirit::x3::char_class<boost::spirit::char_encoding::standard, boost::spirit::x3::space_tag> const, boost::spirit::x3::unused_type>, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > >(boost::spirit::x3::rule<kyle::parser::impl::identifier_class, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >, false>, __gnu_cxx::__normal_iterator<char const*, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > >&, __gnu_cxx::__normal_iterator<char const*, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > > const&, boost::spirit::x3::context<boost::spirit::x3::skipper_tag, boost::spirit::x3::char_class<boost::spirit::
char_encoding::standard
, boost::spirit::x3::space_tag> const, boost::spirit::x3::unused_type> const&, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >&)'
迭代器类型被推断为 std::string::iterator
,而不是 std::string::const_iterator
。修复它或者不要总是使用 auto
:
完整代码
为了子孙后代
config.hpp:
#include <boost/spirit/home/x3.hpp>
namespace kyle{
namespace parser{
namespace x3 = boost::spirit::x3;
typedef std::string::const_iterator iterator_type;
typedef x3::phrase_parse_context<x3::space_type>::type context_type;
}
}
literals.cpp:
#include "literals_def.hpp"
#include "config.hpp"
#include <boost/spirit/home/x3.hpp>
namespace kyle { namespace parser { namespace impl {
BOOST_SPIRIT_INSTANTIATE(identifier_type, iterator_type, context_type);
} } }
literals_def.hpp:
#include <boost/spirit/home/x3.hpp>
#include "literals.hpp"
namespace kyle {
namespace parser {
namespace impl {
namespace x3 = boost::spirit::x3;
const identifier_type identifier = "identifier";
auto const identifier_def = x3::alpha >> *x3::alnum;
BOOST_SPIRIT_DEFINE(identifier)
}
impl::identifier_type identifier(){
return impl::identifier;
}
}
}
literals.hpp:
#include <boost/spirit/home/x3.hpp>
namespace kyle{
namespace parser{
namespace impl {
namespace x3 = boost::spirit::x3;
struct identifier_class;
typedef x3::rule<identifier_class, std::string> identifier_type;
BOOST_SPIRIT_DECLARE(identifier_type)
}
impl::identifier_type identifier();
}
}
main.cpp:
#include "literals.hpp"
#include <iostream>
template<typename Parser>
bool test(std::string const& str, Parser p, std::string& output, bool full_match = true)
{
auto in = str.begin();
auto end = str.end();
bool ret = boost::spirit::x3::phrase_parse(in, end, p, boost::spirit::x3::space, output);
ret &= (!full_match || (in == end));
return ret;
}
int main(){
std::string s;
auto b = test("fobar", kyle::parser::identifier(), s);
std::cout << b << ": " << s << std::endl;
}
CMakeLists.txt:
ADD_EXECUTABLE(sox3 main.cpp literals.cpp)
SET(CMAKE_CXX_COMPILER g++-5)
SET(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -isystem /home/sehe/custom/boost -std=c++14 -O3 -pthread -march=native -flto)
除了sehe的回答,补充一下:
您需要对声明的内容和实际使用的内容非常准确。 X3 允许任何可能的类型,但链接器不允许。
提示:当出现链接器错误时,在 BOOST_SPIRIT_INSTANTIATE 之后声明如下内容:
int x = context_type{};
会报错,是的,因为context_type不能转成int。但该错误也会为您提供上下文的确切类型。将它与链接器错误进行比较,您会发现您的错误。
我目前正在尝试使用 BOOST_SPIRIT_DEFINE/DECLARE/INSTANTIATE
将我的 boost spirit x3 解析器分成不同的 _def 和 .cpp 文件,但我一直收到链接错误。
HERE 是我的解析器,它是分开的。
链接器错误读取
<artificial>:(.text.startup+0xbb): undefined reference to `bool kyle::parser::impl::parse_rule<__gnu_cxx::__normal_iterator<char*, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > >, boost::spirit::x3::context<boost::spirit::x3::skipper_tag, boost::spirit::x3::char_class<boost::spirit::char_encoding::standard, boost::spirit::x3::space_tag> const, boost::spirit::x3::unused_type>, boost::spirit::x3::unused_type const>(boost::spirit::x3::rule<kyle::parser::impl::identifier_class, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >, false>, __gnu_cxx::__normal_iterator<char*, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > >&, __gnu_cxx::__normal_iterator<char*, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > > const&, boost::spirit::x3::context<boost::spirit::x3::skipper_tag, boost::spirit::x3::char_class<boost::spirit::char_encoding::standard, boost::spirit::x3::space_tag> const, boost::spirit::x3::unused_type> const&, boost::spirit::x3::unused_type const&)'
我做错了什么?我怎样才能让我的例子发挥作用?
config.hpp:
#include <boost/spirit/home/x3.hpp> namespace kyle{ namespace parser{ namespace x3 = boost::spirit::x3; typedef std::string::const_iterator iterator_type; typedef x3::phrase_parse_context<x3::ascii::space_type>::type context_type; } }
literals.cpp:
#include "literals_def.hpp" #include "config.hpp" #include <boost/spirit/home/x3.hpp> namespace kyle { namespace parser { namespace impl { BOOST_SPIRIT_INSTANTIATE(identifier_type, iterator_type, context_type); } } }
literals_def.hpp:
#include <boost/spirit/home/x3.hpp> #include "literals.hpp" namespace kyle { namespace parser { namespace impl { namespace x3 = boost::spirit::x3; const identifier_type identifier = "identifier"; auto const identifier_def = x3::alpha >> *x3::alnum; BOOST_SPIRIT_DEFINE(identifier) } impl::identifier_type identifier(){ return impl::identifier; } } }
literals.hpp:
#include <boost/spirit/home/x3.hpp> namespace kyle{ namespace parser{ namespace impl { namespace x3 = boost::spirit::x3; struct identifier_class; typedef x3::rule<identifier_class, std::string> identifier_type; BOOST_SPIRIT_DECLARE(identifier_type) } impl::identifier_type identifier(); } }
main.cpp:
#include "literals.hpp" #include <iostream> template<typename Parser> bool test(std::string str, Parser&& p, bool full_match = true) { auto in = str.begin(); auto end = str.end(); bool ret = boost::spirit::x3::phrase_parse(in, end, p, boost::spirit::x3::space); ret &= (!full_match || (in == end)); return ret; } int main(){ auto b = test("fobar", kyle::parser::identifier()); std::cout << b << std::endl; }
两点:
您将上下文定义为
typedef x3::phrase_parse_context<x3::space_type>::type context_type;
但是,您尝试使用
x3::space
而不是x3::ascii::space
来调用它。提示在您没有包含的错误消息中:
/home/sehe/custom/boost/boost/spirit/home/x3/nonterminal/rule.hpp:116: undefined reference to 'bool kyle::parser::impl::parse_rule<__gnu_cxx::__normal_iterator<char const*, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > >, boost::spirit::x3::context<boost::spirit::x3::skipper_tag, boost::spirit::x3::char_class<boost::spirit::char_encoding::standard, boost::spirit::x3::space_tag> const, boost::spirit::x3::unused_type>, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > >(boost::spirit::x3::rule<kyle::parser::impl::identifier_class, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >, false>, __gnu_cxx::__normal_iterator<char const*, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > >&, __gnu_cxx::__normal_iterator<char const*, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > > const&, boost::spirit::x3::context<boost::spirit::x3::skipper_tag, boost::spirit::x3::char_class<boost::spirit::
char_encoding::standard
, boost::spirit::x3::space_tag> const, boost::spirit::x3::unused_type> const&, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >&)'
迭代器类型被推断为
std::string::iterator
,而不是std::string::const_iterator
。修复它或者不要总是使用auto
:
完整代码
为了子孙后代
config.hpp:
#include <boost/spirit/home/x3.hpp> namespace kyle{ namespace parser{ namespace x3 = boost::spirit::x3; typedef std::string::const_iterator iterator_type; typedef x3::phrase_parse_context<x3::space_type>::type context_type; } }
literals.cpp:
#include "literals_def.hpp" #include "config.hpp" #include <boost/spirit/home/x3.hpp> namespace kyle { namespace parser { namespace impl { BOOST_SPIRIT_INSTANTIATE(identifier_type, iterator_type, context_type); } } }
literals_def.hpp:
#include <boost/spirit/home/x3.hpp> #include "literals.hpp" namespace kyle { namespace parser { namespace impl { namespace x3 = boost::spirit::x3; const identifier_type identifier = "identifier"; auto const identifier_def = x3::alpha >> *x3::alnum; BOOST_SPIRIT_DEFINE(identifier) } impl::identifier_type identifier(){ return impl::identifier; } } }
literals.hpp:
#include <boost/spirit/home/x3.hpp> namespace kyle{ namespace parser{ namespace impl { namespace x3 = boost::spirit::x3; struct identifier_class; typedef x3::rule<identifier_class, std::string> identifier_type; BOOST_SPIRIT_DECLARE(identifier_type) } impl::identifier_type identifier(); } }
main.cpp:
#include "literals.hpp" #include <iostream> template<typename Parser> bool test(std::string const& str, Parser p, std::string& output, bool full_match = true) { auto in = str.begin(); auto end = str.end(); bool ret = boost::spirit::x3::phrase_parse(in, end, p, boost::spirit::x3::space, output); ret &= (!full_match || (in == end)); return ret; } int main(){ std::string s; auto b = test("fobar", kyle::parser::identifier(), s); std::cout << b << ": " << s << std::endl; }
CMakeLists.txt:
ADD_EXECUTABLE(sox3 main.cpp literals.cpp) SET(CMAKE_CXX_COMPILER g++-5) SET(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -isystem /home/sehe/custom/boost -std=c++14 -O3 -pthread -march=native -flto)
除了sehe的回答,补充一下:
您需要对声明的内容和实际使用的内容非常准确。 X3 允许任何可能的类型,但链接器不允许。
提示:当出现链接器错误时,在 BOOST_SPIRIT_INSTANTIATE 之后声明如下内容:
int x = context_type{};
会报错,是的,因为context_type不能转成int。但该错误也会为您提供上下文的确切类型。将它与链接器错误进行比较,您会发现您的错误。