您实际上并没有显示所有声明,因此设置的方式并不完全清楚。所以让我快速模拟一些东西:
Live On Wandbox
#define BOOST_SPIRIT_X3_DEBUG
#include <iomanip>
#include <boost/spirit/home/x3.hpp>
namespace x3 = boost::spirit::x3;
namespace P {
using namespace x3;
static auto const comment = lexeme [
"/*" >> *(char_ - "*/") >> "*/"
| "//" >> *~char_("\r\n") >> eol
];
static auto const skipper = comment | blank;
static auto const property_type = lexeme["type"];
static auto const property_id = lexeme["id"];
auto const demo =
skip(skipper | eol) [
lit("#")
> property_type
> property_id
];
}
int main() {
for (std::string const input : {
"#type id",
"#type\nid",
})
{
std::cout << "==== " << std::quoted(input) << " ====" << std::endl;
auto f = begin(input), l = end(input);
if (parse(f, l, P::demo)) {
std::cout << "Parsed successfully" << std::endl;
} else {
std::cout << "Failed" << std::endl;
}
if (f!=l) {
std::cout << "Remaining input unparsed: " << std::quoted(std::string(f,l)) << std::endl;
}
}
}
如您所见,除非涉及到规则声明,否则实际上没有问题:
==== "#type id" ====
Parsed successfully
==== "#type
id" ====
Parsed successfully
让我们从这里放大
static auto const demo_def =
skip(skipper | eol) [
lit("#")
> property_type
> property_id
];
static auto const demo = x3::rule<struct demo_> {"demo"} = demo_def;
还可以:Live On Wandbox
<demo>
<try>#type id</try>
<success></success>
</demo>
<demo>
<try>#type\nid</try>
<success></success>
</demo>
Parsed successfully
==== "#type
id" ====
Parsed successfully
所以,我们知道x3::rule<> 实际上不是问题所在。这将是关于基于标签类型的静态调度(我认为,也就是规则 ID,在本例中为 struct demo_)。
直截了当:
static auto const demo_def =
skip(skipper | eol) [
lit("#")
> property_type
> property_id
];
static auto const demo = x3::rule<struct demo_> {"demo"};
BOOST_SPIRIT_DEFINE(demo)
还可以:Live On Wandbox
嗯,还有什么问题。也许如果有冲突的船长上下文?更换
if (parse(f, l, P::demo)) {
与
if (phrase_parse(f, l, P::demo, P::skipper)) {
还可以:Live On Wandbox
所以,也不是这样。好的,让我们尝试单独的实例化:
单独编译
Live On Wandbox
-
规则.h
#pragma once
#define BOOST_SPIRIT_X3_DEBUG
#include <boost/spirit/home/x3.hpp>
#include <boost/spirit/home/x3/support/utility/error_reporting.hpp>
namespace x3 = boost::spirit::x3;
namespace P {
using namespace x3;
static auto const comment = lexeme [
"/*" >> *(char_ - "*/") >> "*/"
| "//" >> *~char_("\r\n") >> eol
];
static auto const skipper = comment | blank;
using demo_type = x3::rule<struct demo_>;
extern demo_type const demo;
BOOST_SPIRIT_DECLARE(demo_type)
}
-
规则.cpp
#include "rule.h"
#include <iostream>
#include <iomanip>
namespace P {
using namespace x3;
static auto const property_type = lexeme["type"];
static auto const property_id = lexeme["id"];
static auto const demo_def =
skip(skipper | eol) [
lit("#")
> property_type
> property_id
];
struct demo_ {
template<typename It, typename Ctx>
x3::error_handler_result on_error(It f, It l, expectation_failure<It> const& ef, Ctx const&) const {
std::string s(f,l);
auto pos = std::distance(f, ef.where());
std::cout << "Expecting " << ef.which() << " at "
<< "\n\t" << s
<< "\n\t" << std::setw(pos) << std::setfill('-') << "" << "^\n";
return error_handler_result::fail;
}
};
demo_type const demo {"demo"};
BOOST_SPIRIT_DEFINE(demo)
// for non-skipper invocation (x3::parse)
using iterator_type = std::string::const_iterator;
BOOST_SPIRIT_INSTANTIATE(demo_type, iterator_type, x3::unused_type)
// for skipper invocation (x3::phrase_parse)
using skipper_type = decltype(skipper);
using phrase_context_type = x3::phrase_parse_context<skipper_type>::type;
BOOST_SPIRIT_INSTANTIATE(demo_type, iterator_type, phrase_context_type)
}
-
test.cpp
#include "rule.h"
#include <iostream>
#include <iomanip>
int main() {
std::cout << std::boolalpha;
for (std::string const input : {
"#type id",
"#type\nid",
})
{
std::cout << "\n==== " << std::quoted(input) << " ====" << std::endl;
{
auto f = begin(input), l = end(input);
std::cout << "With top-level skipper: " << phrase_parse(f, l, P::demo, P::skipper) << std::endl;
if (f!=l) {
std::cout << "Remaining unparsed: " << std::quoted(std::string(f,l)) << std::endl;
}
}
{
auto f = begin(input), l = end(input);
std::cout << "Without top-level skipper: " << parse(f, l, P::demo) << std::endl;
if (f!=l) {
std::cout << "Remaining unparsed: " << std::quoted(std::string(f,l)) << std::endl;
}
}
}
}
打印预期:
==== "#type id" ====
With top-level skipper: <demo>
<try>#type id</try>
<success></success>
</demo>
true
Without top-level skipper: <demo>
<try>#type id</try>
<success></success>
</demo>
true
==== "#type
id" ====
With top-level skipper: <demo>
<try>#type\nid</try>
<success></success>
</demo>
true
Without top-level skipper: <demo>
<try>#type\nid</try>
<success></success>
</demo>
true
或者,不启用调试:
==== "#type id" ====
With top-level skipper: true
Without top-level skipper: true
==== "#type
id" ====
With top-level skipper: true
Without top-level skipper: true
最后的想法
很遗憾,也许我无法重现您描述的症状。但是,我希望上面的一些步骤确实阐明了规则定义的单独链接实际上是如何与船长/上下文相关的。
如果你的情况实际上更复杂,我只能想到另一种情况,X3 的情况可能不同于 QI 的情况。在 Qi 中,一条规则静态地声明了它的船长。在 X3 中,skipper 严格来自上下文(规则可以限制支持的skipper 数量的唯一方法是分离实例化并将定义隐藏在单独的TU 中)。
这意味着很容易意外地继承一个被覆盖的船长。这可能是违反直觉的,例如嵌套规则。如果您有不同的船长,我建议不要完全依赖继承的船长上下文。