Мне нужно создать синтаксический анализатор строк в кавычках для моего пользовательского языка, который также будет правильно обрабатывать escape-последовательности, включая разрешение экранированных кавычек внутри строки. Это мой текущий синтаксический анализатор строк:
x3::lexeme[quote > *(x3::char_ - quote) > quote]
, где quote
- это просто постоянное выражение для '"'
. Он не обрабатывает управляющую последовательность. Я знаю про boost::spirit::classic::lex_escape_ch_p
, но понятия не имею, как использовать это с инструментами boost::spirit::x3
(или вообще). Как я мог создать парсер, который бы это делал? Синтаксическому анализатору придется распознавать большинство escape-последовательностей, таких как обычные, такие как '\n'
, '\t'
, и более сложные вещи, такие как escape-последовательности hex, oct и ansi.
Мои извинения, если что-то не так с этот пост, это моя первая публикация на SO.
EDIT:
Вот как я реализовал парсер:
x3::lexeme[quote > *(
("\\\"" >> &x3::char_) >> x3::attr(quote) | ~x3::char_(quote)
) > quote]
[handle_escape_sequences];
где handle_escape_sequences
- это lambda:
auto handle_escape_sequences = [&](auto&& context) -> void {
std::string& str = x3::_val(context);
uint32_t i{};
static auto replace = [&](const char replacement) -> void {
str[i++] = replacement;
};
if (!classic::parse(std::begin(str), std::end(str), *classic::lex_escape_ch_p[replace]).full)
throw Error{ "invalid literal" }; // invalid escape sequence most likely
str.resize(i);
};
Он выполняет полный синтаксический анализ управляющей последовательности ANSI, что означает, что вы можете использовать его для выполнения всех видов причудливых манипуляций с терминалом, таких как установка цвета текста, положения курсора и т. д. c. с ним.
Вот полное определение правила, а также все, от чего оно зависит (я просто выбрал все, что с ним связано, из своего кода, поэтому результат выглядит как правильное спагетти) на случай кому-то это понадобится:
#include <boost\spirit\home\x3.hpp>
#include <boost\spirit\include\classic_utility.hpp>
using namespace boost::spirit;
#define RULE_DECLARATION(rule_name, attribute_type) \
inline namespace Tag { class rule_name ## _tag; } \
x3::rule<Tag::rule_name ## _tag, attribute_type, true> rule_name = #rule_name; \
#define SIMPLE_RULE_DEFINITION(rule_name, attribute_type, definition) \
RULE_DECLARATION(rule_name, attribute_type) \
auto rule_name ## _def = definition; \
BOOST_SPIRIT_DEFINE(rule_name);
constexpr char quote = '"';
template <class Base, class>
struct Access_base_s : Base {
using Base::Base, Base::operator=;
};
template <class Base, class Tag>
using Unique_alias_for = Access_base_s<Base, Tag>;
using String_literal = Unique_alias_for<std::string, class String_literal_tag>;
SIMPLE_RULE_DEFINITION(string_literal, String_literal,
x3::lexeme[quote > *(
("\\\"" >> &x3::char_) >> x3::attr(quote) | ~x3::char_(quote)
) > quote]
[handle_escape_sequences];
);