如何定义从任何编码空间解析单个字符的 spirit x3 解析器?
How to define a spirit x3 parser that parses a single char from any encoding spaces?
如果我们忽略该属性,这个 test::char_
将完成工作。
namespace test {
struct any_char: x3::char_parser<any_char> {
static bool const has_attribute = false;
template <typename Char, typename Context>
bool test(Char ch_, Context const&) const {
return true;
}
};
auto const char_ = any_char{};
}
但是如果我们想从test::char_
中获取属性呢?我不知道如何正确设置 attribute_type 因为这个 attribute_type 应该是
typename std::iterator_traits<Iterator>::value_type
这在 spirit qi 中不是问题,因为 qi 解析器有一个模板属性结构,我们可以在其中从 Iterator 获取 char 类型。
编辑: 感谢 sehe 回答这个问题。自动属性传播适用于 test::char_
,但它仍然无法传播复合属性 +test::char_
的正确属性。
Edit2: 我想用这个test::char_来替换x3中的各种char_encoding::char_。例如我有一个简单的解析器函数 foo。输入字符串可以是 ascii 编码字符串或宽字符编码字符串。因此,我可以在任何地方使用带有#IFDEF 的test::char_ 而不是x3::char_ 和x3::standard_wide::char_。
#ifdef NARROW_CHAR
using _char = char;
#define _STR(str) str
#else
using _char = wchar_t;
#define _STR(str) L ## str
#endif
bool foo(std::basic_string<_char> const& input, std::basic_string<_char>& attr) {
return x3::parse(
input.begin(),
input.end(),
+(test::char_ - _STR('X')),
attr);
}
Edit3: 将 attribute_type 设置为 void 或 x3::unused_type 将使 test::char_ 传播正确的属性。
namespace test {
struct any_char: x3::char_parser<any_char> {
using attribute_type = void; // or x3::unused_type
static bool const has_attribute = true;
template <typename Char, typename Context>
bool test(Char ch_, Context const&) const {
return true;
}
};
auto const char_ = any_char{};
}
Edit4: sehe 的 http://coliru.stacked-crooked.com/a/0a487591fbaedef4 可能比这个 test::char_ 更好。谢谢。
自动属性传播已经解决了:
#include <boost/spirit/home/x3.hpp>
#include <string>
#include <iostream>
#include <iostream>
using namespace std::string_literals;
namespace x3 = boost::spirit::x3;
namespace test {
struct any_char: x3::char_parser<any_char> {
static bool const has_attribute = false;
template <typename Char, typename Context>
bool test(Char /*ch_*/, Context const&) const {
return true;
}
};
auto const char_ = any_char{};
}
template <typename S>
void doTest(S const& s) {
typename S::value_type ch;
if (x3::parse(s.begin(), s.end(), test::char_, ch)) {
std::wcout << L"Parsed: " << std::wcout.widen(ch) << std::endl;
} else {
std::wcout << L"Not parsed\n";
}
}
int main() {
doTest("Hello"s);
doTest(L"World"s);
}
版画
Parsed: H
Parsed: W
如果我们忽略该属性,这个 test::char_
将完成工作。
namespace test {
struct any_char: x3::char_parser<any_char> {
static bool const has_attribute = false;
template <typename Char, typename Context>
bool test(Char ch_, Context const&) const {
return true;
}
};
auto const char_ = any_char{};
}
但是如果我们想从test::char_
中获取属性呢?我不知道如何正确设置 attribute_type 因为这个 attribute_type 应该是
typename std::iterator_traits<Iterator>::value_type
这在 spirit qi 中不是问题,因为 qi 解析器有一个模板属性结构,我们可以在其中从 Iterator 获取 char 类型。
编辑: 感谢 sehe 回答这个问题。自动属性传播适用于 test::char_
,但它仍然无法传播复合属性 +test::char_
的正确属性。
Edit2: 我想用这个test::char_来替换x3中的各种char_encoding::char_。例如我有一个简单的解析器函数 foo。输入字符串可以是 ascii 编码字符串或宽字符编码字符串。因此,我可以在任何地方使用带有#IFDEF 的test::char_ 而不是x3::char_ 和x3::standard_wide::char_。
#ifdef NARROW_CHAR
using _char = char;
#define _STR(str) str
#else
using _char = wchar_t;
#define _STR(str) L ## str
#endif
bool foo(std::basic_string<_char> const& input, std::basic_string<_char>& attr) {
return x3::parse(
input.begin(),
input.end(),
+(test::char_ - _STR('X')),
attr);
}
Edit3: 将 attribute_type 设置为 void 或 x3::unused_type 将使 test::char_ 传播正确的属性。
namespace test {
struct any_char: x3::char_parser<any_char> {
using attribute_type = void; // or x3::unused_type
static bool const has_attribute = true;
template <typename Char, typename Context>
bool test(Char ch_, Context const&) const {
return true;
}
};
auto const char_ = any_char{};
}
Edit4: sehe 的 http://coliru.stacked-crooked.com/a/0a487591fbaedef4 可能比这个 test::char_ 更好。谢谢。
自动属性传播已经解决了:
#include <boost/spirit/home/x3.hpp>
#include <string>
#include <iostream>
#include <iostream>
using namespace std::string_literals;
namespace x3 = boost::spirit::x3;
namespace test {
struct any_char: x3::char_parser<any_char> {
static bool const has_attribute = false;
template <typename Char, typename Context>
bool test(Char /*ch_*/, Context const&) const {
return true;
}
};
auto const char_ = any_char{};
}
template <typename S>
void doTest(S const& s) {
typename S::value_type ch;
if (x3::parse(s.begin(), s.end(), test::char_, ch)) {
std::wcout << L"Parsed: " << std::wcout.widen(ch) << std::endl;
} else {
std::wcout << L"Not parsed\n";
}
}
int main() {
doTest("Hello"s);
doTest(L"World"s);
}
版画
Parsed: H
Parsed: W