строка цитаты синтаксического анализа boost не работает

Это мой граммер

unesc_char.add(L"\\a", L'\a')(L"\\b", L'\b')(L"\\f", L'\f')(L"\\n", L'\n')
              (L"\\r", L'\r')(L"\\t", L'\t')(L"\\v", L'\v')(L"\\\\", L'\\')
              (L"\\\'", L'\'')(L"\\\"", L'\"');
unesc_str = '\"' >> *((boost::spirit::standard_wide::char_ - '\"') | unesc_char) >> '\"';

с участием

qi::rule<Iterator, std::wstring()> unesc_str;
qi::symbols<wchar_t const, wchar_t const> unesc_char;

Не удается выполнить синтаксический анализ: "Hello \" "-> должен вернуть Hello"
Разбор правильный: "Hello \\" -> должен вернуть Hello \

изменение правила на

unesc_str = '\"' >> *(unesc_char | (boost::spirit::standard_wide::char_ - '\"')) >> '\"';

Разбор правильный: "Hello \" "-> должен вернуть Hello"
Анализ не удался: "Hello \\" -> должен вернуть Hello \

как заставить работать оба?


person Markus    schedule 22.02.2018    source источник


Ответы (1)


Грамматики PEG анализируют слева направо, поэтому вам нужно иметь unesc_char впереди, чтобы обрабатывать escape-последовательности.

Кроме того, я думаю, вы, вероятно, путаете себя с уровнями экранирования ввода:

Live On Coliru

#include <boost/spirit/include/qi.hpp>

namespace qi = boost::spirit::qi;

template <typename It>
struct Parser : qi::grammar<It, std::wstring()> {
    Parser() : Parser::base_type(unesc_str) {
        unesc_char.add
            (L"\\a",  L'\a')
            (L"\\b",  L'\b')
            (L"\\f",  L'\f')
            (L"\\n",  L'\n')
            (L"\\r",  L'\r')
            (L"\\t",  L'\t')
            (L"\\v",  L'\v')
            (L"\\\\", L'\\')
            (L"\\'",  L'\'')
            (L"\\\"", L'\"');

        unesc_str = L'"' >> *(unesc_char | ~qi::standard_wide::char_(L'"')) >> L'"';
    }
  private:
    qi::rule<It, std::wstring()> unesc_str;
    qi::symbols<wchar_t const, wchar_t const> unesc_char;
};

int main() {
    using It = std::wstring::const_iterator;
    Parser<It> const p {};
    for (std::wstring const input : { 
            L"\"abaca\\tdabra\"",
            LR"("Hello\"")", L"\"Hello\\\"\"", // equivalent
            LR"("Hello\\")", L"\"Hello\\\\\"", 
    }) {
        It f = input.begin(), l = input.end();
        std::wstring s;
        if (parse(f, l, p, s)) {
            std::wcout << L"Unescape: " << input << L" -> " << s << L"\n";
        }

        if (f != l)
            std::wcout << "Remaining input: '" << std::wstring(f,l) << "'\n";

    }
}

Печать

Unescape: "abaca\tdabra" -> abaca   dabra
Unescape: "Hello\"" -> Hello"
Unescape: "Hello\"" -> Hello"
Unescape: "Hello\\" -> Hello\
Unescape: "Hello\\" -> Hello\

БОНУС

Я бы, наверное, не усложнял без symbols. Это более гибкий и, вероятно, более эффективный способ, если вам не нужен динамический список экранирований:

Live On Coliru

namespace enc = qi::standard_wide;

unesc_str = '"' >> *(
        '\\' >> (
            'a' >> qi::attr('\a')
          | 'b' >> qi::attr('\b')
          | 'f' >> qi::attr('\f')
          | 'n' >> qi::attr('\n')
          | 'r' >> qi::attr('\r')
          | 't' >> qi::attr('\t')
          | 'v' >> qi::attr('\v')
          | enc::char_
      ) | ~enc::char_('"')) >> '"';
person sehe    schedule 22.02.2018
comment
Добавлен упрощенный бонусный прием - person sehe; 22.02.2018
comment
работает сейчас спасибо! .. ты прав, я тоже не совпадает с некоторыми побегами 8-) - person Markus; 22.02.2018
comment
@sehe Можно ли использовать строку вместо wstring? - person user2987773; 21.02.2021
comment
@ user2987773 Эмм, да. wstring - это мерзость :) Пробовали? coliru.stacked-crooked.com/a/55a40147410b9308 - person sehe; 21.02.2021