Как использовать boost :: spirit для изменения строки, как это делает регулярное выражение? - PullRequest
0 голосов
/ 12 марта 2020

Я пишу небольшой домен Specifi c Язык для моей программы, используя JUCE :: JavascriptEngine в качестве механизма сценариев. Это принимает строку в качестве входных данных и затем анализирует ее, но мне нужно выполнить некоторую предварительную обработку строки, чтобы адаптировать ее из моего DSL к JavaScript. Предварительная обработка в основном состоит из переноса некоторых терминов внутри функций и размещения имен объектов перед функциями. Так, например, я хочу сделать что-то вроде этого:

взять специальный ввод строки "~/1/2" ...

обернуть его внутри функции: "find("~/1/2")" ...

и затем присоедините к нему объект: "someObject.find("~/1/2")" (имя объекта должно быть переменной).

Я использовал для этого регулярное выражение (теперь у меня две проблемы ...) , Регулярные выражения становятся сложными и нечитаемыми, и в нем пропущено множество особых случаев. Поскольку то, что я делаю, грамматически, я подумал, что я бы перешел с регулярного выражения на правильный парсер (теперь у меня три проблемы ...). После долгих исследований я выбрал Boost.Spirit. Я просматриваю документацию, но она не ведет меня в правильном направлении. Может кто-нибудь подсказать, как я могу использовать эту библиотеку для манипулирования строками так, как я ищу? Учитывая, что я только пытаюсь манипулировать строкой и не заинтересован в сохранении проанализированных данных, нужно ли мне использовать karma для вывода или я могу вывести строку с qi или x3 во время синтаксического анализа процесс?

Если я иду по неверному пути, пожалуйста, не стесняйтесь меня перенаправить.

1 Ответ

1 голос
/ 13 марта 2020

Это кажется слишком широким, чтобы отвечать.

Что вы делаете, это парсинг ввода и преобразование его во что-то другое. То, что вы не делаете, это находите / заменяйте (в противном случае вы будете в порядке с помощью регулярных выражений).

Конечно, вы можете делать то же, что и регулярные выражения, но я не уверен, что это что-то вас купит:

template <typename It, typename Out>
Out preprocess(It f, It l, Out out) {
    namespace qi = boost::spirit::qi;
    using boost::spirit::repository::qi::seek;

    auto passthrough = [&out](boost::iterator_range<It> ignored, auto&&...) {
        for (auto ch : ignored) *out++ = ch;
    };
    auto transform = [&out](std::string const& literal, auto&&...) {
        for (auto ch : "someObject.find(\"~"s) *out++ = ch;
        for (auto ch : literal) *out++ = ch;
        for (auto ch : "\")"s) *out++ = ch;
    };

    auto pattern = qi::copy("\"~" >> (*~qi::char_('"')) >> '"');
    qi::rule<It> ignore = qi::raw[+(!pattern >> qi::char_)] [passthrough];
    qi::parse(f, l, -qi::as_string[pattern][transform] % ignore);
    return out;
}

Хорошая особенность этого способа записи в том, что он будет работать с любым исходным итератором:

for (std::string const input : {
    R"(function foo(a, b) { var path = "~/1/2"; })",
})
{
    std::cout << "Input: " << input << "\n";

    std::string result;
    preprocess(begin(input), end(input), back_inserter(result));

    std::cout << "Result: " << result << "\n";
}

std::cout << "\n -- Or directly transformed stdin to stdout:\n";
preprocess(
    boost::spirit::istream_iterator(std::cin >> std::noskipws), {},
    std::ostreambuf_iterator<char>(std::cout));

Просмотр Live On Coliru , печать вывод:

Input: function foo(a, b) { var path = "~/1/2"; }
Result: function foo(a, b) { var path = someObject.find("~/1/2"); }

 -- Or directly transformed stdin to stdout:
function bar(c, d) { var path = someObject.find("~/1/42"); }

Но это очень ограничено, поскольку он даже не будет делать правильные вещи, если такие вещи являются частями комментариев или многострочных строк et c.

Так что вместо этого вы, вероятно, захотите выделенную библиотеку, которая знает, как анализировать javascript и использовать ее для выполнения преобразования, например (один из первых попаданий при поиске в Google tooling library preprocess javascript transform): https://clojurescript.org/reference/javascript-library-preprocessing

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...