将一个解析器从一个单独的翻译单元嵌入到另一个解析器中
Embedding a parser from a separate translation unit into another parser
我正在尝试将我在翻译单元 (unit1.h/unit1.cpp) 中隔离的解析器(名为 parser1_rule
)重用到另一个解析器(名称 trace_parser
).然而,我收到一条警告和一条错误消息(为了便于阅读,在下面复制和重新格式化)或多或少(这是我的解释)说明 parser1_rule
尚未为 new 定义(或实例化) 上下文 trace_context_t
.
的确,在X3中,规则有两个模板参数:迭代器和上下文。我想当混合两个规则时,必须确保它们都使用相同的上下文和迭代器的类型。所以我注意为 parser1_rule
和 trace_parser
使用相同的上下文:context_type
。迭代器也是如此,如
中所述
但它接缝这不是要走的路吗?我可以将规则的定义移动到一个 hpp 文件中吗(我希望我可以避免)。
我创建了一个最小的可重现示例来帮助理解问题:
编辑: 提升 1.71.0 和 Visual Studio 16.8.2
unit1.h
#ifndef UNIT1_H
#define UNIT1_H
#include <cstdint>
#include "boost/spirit/home/x3.hpp"
#include "boost/spirit/include/support_istream_iterator.hpp"
namespace x3 = boost::spirit::x3;
using iter_t = boost::spirit::istream_iterator;
using context_t = x3::phrase_parse_context<x3::ascii::space_type>::type;
using parser1_t = x3::rule<class p1, std::uint64_t>;
BOOST_SPIRIT_DECLARE(parser1_t);
parser1_t const & ATparser();
#endif /* UNIT1_H */
unit1.cpp
#include "unit1.h"
parser1_t const parser1 = "parser1_rule";
auto const parser1_def = x3::lexeme[x3::lit("AT") >> x3::uint_];
BOOST_SPIRIT_DEFINE(parser1);
BOOST_SPIRIT_INSTANTIATE(parser1_t, iter_t, context_t);
parser1_t const& ATparser() { return parser1; }
Source.h
#ifndef SOURCE_H
#define SOURCE_H
#include <cstdint>
#include "boost/spirit/home/x3.hpp"
#include "boost/spirit/include/support_istream_iterator.hpp"
namespace x3 = boost::spirit::x3;
namespace trace {
using trace_parser_tag = struct trace_parser;
using rule_type = x3::rule<trace_parser_tag>;
BOOST_SPIRIT_DECLARE(rule_type);
}
trace::rule_type const& trace_parser();
#endif
Source.cpp
#include <iostream>
#include <fstream>
#include "unit1.h"
#include "Source.h"
namespace x3 = boost::spirit::x3;
/** reading:
Trace address: AT123434 */
namespace trace {
rule_type const tr = "trace_parser";
auto fill = [](auto& ctx) {}; /* semantic action to break automatic attribute propagation (first step) */
auto const tr_def = ("Trace address: " >> ATparser())[fill];
BOOST_SPIRIT_DEFINE(tr);
BOOST_SPIRIT_INSTANTIATE(rule_type,iter_t,context_t)
}
trace::rule_type const& trace_parser() {
return trace::tr;
}
int main(int argc, char* argv[])
{
std::string input("Trace address: AT123434");
std::ifstream i(input);
std::cout << "parsing: " << input << "\n";
boost::spirit::istream_iterator b(i >> std::noskipws);
boost::spirit::istream_iterator e = {};
bool v = x3::phrase_parse(b, e, trace_parser(), x3::ascii::space);
std::cout << "result: " << (v ? "OK" : "Failed") << "\n";
return v;
}
编译输出
1>Source.cpp
1>H:\X\XXXXX\unit1.h(26,1): warning C5046: 'parse_rule': Symbol involving type with internal linkage not defined
1>Source.obj : error LNK2019: unresolved external symbol "bool __cdecl parse_rule<class boost::spirit::basic_istream_iterator<char,struct std::char_traits<char> >,struct boost::spirit::x3::context<struct trace::trace_parser,struct boost::spirit::x3::action<struct boost::spirit::x3::sequence<struct boost::spirit::x3::literal_string<char const *,struct boost::spirit::char_encoding::standard,struct boost::spirit::x3::unused_type>,struct boost::spirit::x3::rule<class p1,unsigned __int64,0> >,class <lambda_bca3e58e86871d1e58f1a6062ad05fd2> > const ,struct boost::spirit::x3::context<struct boost::spirit::x3::skipper_tag,struct boost::spirit::x3::char_class<struct boost::spirit::char_encoding::ascii,struct boost::spirit::x3::space_tag> const ,struct boost::spirit::x3::unused_type> > >(struct boost::spirit::x3::rule<class p1,unsigned __int64,0>,class boost::spirit::basic_istream_iterator<char,struct std::char_traits<char> > &,class boost::spirit::basic_istream_iterator<char,struct std::char_traits<char> > const &,struct boost::spirit::x3::context<struct trace::trace_parser,struct boost::spirit::x3::action<struct boost::spirit::x3::sequence<struct boost::spirit::x3::literal_string<char const *,struct boost::spirit::char_encoding::standard,struct boost::spirit::x3::unused_type>,struct boost::spirit::x3::rule<class p1,unsigned __int64,0> >,class <lambda_bca3e58e86871d1e58f1a6062ad05fd2> > const ,struct boost::spirit::x3::context<struct boost::spirit::x3::skipper_tag,struct boost::spirit::x3::char_class<struct boost::spirit::char_encoding::ascii,struct boost::spirit::x3::space_tag> const ,struct boost::spirit::x3::unused_type> > const &,unsigned __int64 &)" [...cut...] referenced in function "public: bool __cdecl boost::spirit::x3::rule<class p1,unsigned __int64,0>::parse<class boost::spirit::basic_istream_iterator<char,struct std::char_traits<char> >,struct boost::spirit::x3::context<struct trace::trace_parser,struct boost::spirit::x3::action<struct boost::spirit::x3::sequence<struct boost::spirit::x3::literal_string<char const *,struct boost::spirit::char_encoding::standard,struct boost::spirit::x3::unused_type>,struct boost::spirit::x3::rule<class p1,unsigned __int64,0> >,class <lambda_bca3e58e86871d1e58f1a6062ad05fd2> > const ,struct boost::spirit::x3::context<struct boost::spirit::x3::skipper_tag,struct boost::spirit::x3::char_class<struct boost::spirit::char_encoding::ascii,struct boost::spirit::x3::space_tag> const ,struct boost::spirit::x3::unused_type> >,unsigned __int64>(class boost::spirit::basic_istream_iterator<char,struct std::char_traits<char> > &,class boost::spirit::basic_istream_iterator<char,struct std::char_traits<char> > const &,struct boost::spirit::x3::context<struct trace::trace_parser,struct boost::spirit::x3::action<struct boost::spirit::x3::sequence<struct boost::spirit::x3::literal_string<char const *,struct boost::spirit::char_encoding::standard,struct boost::spirit::x3::unused_type>,struct boost::spirit::x3::rule<class p1,unsigned __int64,0> >,class <lambda_bca3e58e86871d1e58f1a6062ad05fd2> > const ,struct boost::spirit::x3::context<struct boost::spirit::x3::skipper_tag,struct boost::spirit::x3::char_class<struct boost::spirit::char_encoding::ascii,struct boost::spirit::x3::space_tag> const ,struct boost::spirit::x3::unused_type> > const &,struct boost::spirit::x3::unused_type,unsigned __int64 &)const "
警告:
1>H:\X\XXXXX\unit1.h(26,1): warning C5046: 'parse_rule': Symbol involving type with internal linkage not defined
错误信息:
unresolved external symbol:
bool __cdecl parse_rule<iterator_t,trace_context_t>(
parser1_t,
iterator_t &,
iterator_t const &,
trace_context_t const &,
unsigned __int64 &
)
referenced in function
public:
bool __cdecl boost::spirit::x3::rule<class p1,unsigned __int64,0>::parse<
iterator_t, trace_context_t, unsigned __int64>
(
iterator_t &,
iterator_t const &,
trace_context_t const &,
struct boost::spirit::x3::unused_type,
unsigned __int64 &
)const
Assuming the following shorcuts:
using action_t = struct boost::spirit::x3::action<
struct boost::spirit::x3::sequence<
struct boost::spirit::x3::literal_string<
char const *,
struct boost::spirit::char_encoding::standard,
struct boost::spirit::x3::unused_type>,
struct boost::spirit::x3::rule<class p1,unsigned __int64,0>>,
class <lambda_bca3e58e86871d1e58f1a6062ad05fd2>>
using ctxt_t = struct boost::spirit::x3::context<
struct boost::spirit::x3::skipper_tag,
struct boost::spirit::x3::char_class<
struct boost::spirit::char_encoding::ascii,
struct boost::spirit::x3::space_tag> const ,
struct boost::spirit::x3::unused_type>>
using iterator_t = class boost::spirit::basic_istream_iterator<char,struct std::char_traits<char> >
using trace_context_t = struct boost::spirit::x3::context<
struct trace::trace_parser,
action_t const ,
ctxt_t>
迁移到 Boost 1.74.0 解决了这个问题。
我正在尝试将我在翻译单元 (unit1.h/unit1.cpp) 中隔离的解析器(名为 parser1_rule
)重用到另一个解析器(名称 trace_parser
).然而,我收到一条警告和一条错误消息(为了便于阅读,在下面复制和重新格式化)或多或少(这是我的解释)说明 parser1_rule
尚未为 new 定义(或实例化) 上下文 trace_context_t
.
的确,在X3中,规则有两个模板参数:迭代器和上下文。我想当混合两个规则时,必须确保它们都使用相同的上下文和迭代器的类型。所以我注意为 parser1_rule
和 trace_parser
使用相同的上下文:context_type
。迭代器也是如此,如
但它接缝这不是要走的路吗?我可以将规则的定义移动到一个 hpp 文件中吗(我希望我可以避免)。
我创建了一个最小的可重现示例来帮助理解问题:
编辑: 提升 1.71.0 和 Visual Studio 16.8.2
unit1.h
#ifndef UNIT1_H
#define UNIT1_H
#include <cstdint>
#include "boost/spirit/home/x3.hpp"
#include "boost/spirit/include/support_istream_iterator.hpp"
namespace x3 = boost::spirit::x3;
using iter_t = boost::spirit::istream_iterator;
using context_t = x3::phrase_parse_context<x3::ascii::space_type>::type;
using parser1_t = x3::rule<class p1, std::uint64_t>;
BOOST_SPIRIT_DECLARE(parser1_t);
parser1_t const & ATparser();
#endif /* UNIT1_H */
unit1.cpp
#include "unit1.h"
parser1_t const parser1 = "parser1_rule";
auto const parser1_def = x3::lexeme[x3::lit("AT") >> x3::uint_];
BOOST_SPIRIT_DEFINE(parser1);
BOOST_SPIRIT_INSTANTIATE(parser1_t, iter_t, context_t);
parser1_t const& ATparser() { return parser1; }
Source.h
#ifndef SOURCE_H
#define SOURCE_H
#include <cstdint>
#include "boost/spirit/home/x3.hpp"
#include "boost/spirit/include/support_istream_iterator.hpp"
namespace x3 = boost::spirit::x3;
namespace trace {
using trace_parser_tag = struct trace_parser;
using rule_type = x3::rule<trace_parser_tag>;
BOOST_SPIRIT_DECLARE(rule_type);
}
trace::rule_type const& trace_parser();
#endif
Source.cpp
#include <iostream>
#include <fstream>
#include "unit1.h"
#include "Source.h"
namespace x3 = boost::spirit::x3;
/** reading:
Trace address: AT123434 */
namespace trace {
rule_type const tr = "trace_parser";
auto fill = [](auto& ctx) {}; /* semantic action to break automatic attribute propagation (first step) */
auto const tr_def = ("Trace address: " >> ATparser())[fill];
BOOST_SPIRIT_DEFINE(tr);
BOOST_SPIRIT_INSTANTIATE(rule_type,iter_t,context_t)
}
trace::rule_type const& trace_parser() {
return trace::tr;
}
int main(int argc, char* argv[])
{
std::string input("Trace address: AT123434");
std::ifstream i(input);
std::cout << "parsing: " << input << "\n";
boost::spirit::istream_iterator b(i >> std::noskipws);
boost::spirit::istream_iterator e = {};
bool v = x3::phrase_parse(b, e, trace_parser(), x3::ascii::space);
std::cout << "result: " << (v ? "OK" : "Failed") << "\n";
return v;
}
编译输出
1>Source.cpp
1>H:\X\XXXXX\unit1.h(26,1): warning C5046: 'parse_rule': Symbol involving type with internal linkage not defined
1>Source.obj : error LNK2019: unresolved external symbol "bool __cdecl parse_rule<class boost::spirit::basic_istream_iterator<char,struct std::char_traits<char> >,struct boost::spirit::x3::context<struct trace::trace_parser,struct boost::spirit::x3::action<struct boost::spirit::x3::sequence<struct boost::spirit::x3::literal_string<char const *,struct boost::spirit::char_encoding::standard,struct boost::spirit::x3::unused_type>,struct boost::spirit::x3::rule<class p1,unsigned __int64,0> >,class <lambda_bca3e58e86871d1e58f1a6062ad05fd2> > const ,struct boost::spirit::x3::context<struct boost::spirit::x3::skipper_tag,struct boost::spirit::x3::char_class<struct boost::spirit::char_encoding::ascii,struct boost::spirit::x3::space_tag> const ,struct boost::spirit::x3::unused_type> > >(struct boost::spirit::x3::rule<class p1,unsigned __int64,0>,class boost::spirit::basic_istream_iterator<char,struct std::char_traits<char> > &,class boost::spirit::basic_istream_iterator<char,struct std::char_traits<char> > const &,struct boost::spirit::x3::context<struct trace::trace_parser,struct boost::spirit::x3::action<struct boost::spirit::x3::sequence<struct boost::spirit::x3::literal_string<char const *,struct boost::spirit::char_encoding::standard,struct boost::spirit::x3::unused_type>,struct boost::spirit::x3::rule<class p1,unsigned __int64,0> >,class <lambda_bca3e58e86871d1e58f1a6062ad05fd2> > const ,struct boost::spirit::x3::context<struct boost::spirit::x3::skipper_tag,struct boost::spirit::x3::char_class<struct boost::spirit::char_encoding::ascii,struct boost::spirit::x3::space_tag> const ,struct boost::spirit::x3::unused_type> > const &,unsigned __int64 &)" [...cut...] referenced in function "public: bool __cdecl boost::spirit::x3::rule<class p1,unsigned __int64,0>::parse<class boost::spirit::basic_istream_iterator<char,struct std::char_traits<char> >,struct boost::spirit::x3::context<struct trace::trace_parser,struct boost::spirit::x3::action<struct boost::spirit::x3::sequence<struct boost::spirit::x3::literal_string<char const *,struct boost::spirit::char_encoding::standard,struct boost::spirit::x3::unused_type>,struct boost::spirit::x3::rule<class p1,unsigned __int64,0> >,class <lambda_bca3e58e86871d1e58f1a6062ad05fd2> > const ,struct boost::spirit::x3::context<struct boost::spirit::x3::skipper_tag,struct boost::spirit::x3::char_class<struct boost::spirit::char_encoding::ascii,struct boost::spirit::x3::space_tag> const ,struct boost::spirit::x3::unused_type> >,unsigned __int64>(class boost::spirit::basic_istream_iterator<char,struct std::char_traits<char> > &,class boost::spirit::basic_istream_iterator<char,struct std::char_traits<char> > const &,struct boost::spirit::x3::context<struct trace::trace_parser,struct boost::spirit::x3::action<struct boost::spirit::x3::sequence<struct boost::spirit::x3::literal_string<char const *,struct boost::spirit::char_encoding::standard,struct boost::spirit::x3::unused_type>,struct boost::spirit::x3::rule<class p1,unsigned __int64,0> >,class <lambda_bca3e58e86871d1e58f1a6062ad05fd2> > const ,struct boost::spirit::x3::context<struct boost::spirit::x3::skipper_tag,struct boost::spirit::x3::char_class<struct boost::spirit::char_encoding::ascii,struct boost::spirit::x3::space_tag> const ,struct boost::spirit::x3::unused_type> > const &,struct boost::spirit::x3::unused_type,unsigned __int64 &)const "
警告:
1>H:\X\XXXXX\unit1.h(26,1): warning C5046: 'parse_rule': Symbol involving type with internal linkage not defined
错误信息:
unresolved external symbol:
bool __cdecl parse_rule<iterator_t,trace_context_t>(
parser1_t,
iterator_t &,
iterator_t const &,
trace_context_t const &,
unsigned __int64 &
)
referenced in function
public:
bool __cdecl boost::spirit::x3::rule<class p1,unsigned __int64,0>::parse<
iterator_t, trace_context_t, unsigned __int64>
(
iterator_t &,
iterator_t const &,
trace_context_t const &,
struct boost::spirit::x3::unused_type,
unsigned __int64 &
)const
Assuming the following shorcuts:
using action_t = struct boost::spirit::x3::action<
struct boost::spirit::x3::sequence<
struct boost::spirit::x3::literal_string<
char const *,
struct boost::spirit::char_encoding::standard,
struct boost::spirit::x3::unused_type>,
struct boost::spirit::x3::rule<class p1,unsigned __int64,0>>,
class <lambda_bca3e58e86871d1e58f1a6062ad05fd2>>
using ctxt_t = struct boost::spirit::x3::context<
struct boost::spirit::x3::skipper_tag,
struct boost::spirit::x3::char_class<
struct boost::spirit::char_encoding::ascii,
struct boost::spirit::x3::space_tag> const ,
struct boost::spirit::x3::unused_type>>
using iterator_t = class boost::spirit::basic_istream_iterator<char,struct std::char_traits<char> >
using trace_context_t = struct boost::spirit::x3::context<
struct trace::trace_parser,
action_t const ,
ctxt_t>
迁移到 Boost 1.74.0 解决了这个问题。