Разобрать '.' связанный список идентификаторов с qi :: lexeme и предотвращает пропуск пробелов - PullRequest
1 голос
/ 23 марта 2020

В настоящее время я работаю над анализатором выражений на основе Spirit, который должен разрешать в конце (в далеком будущем) выражения, такие как

"a*b*c"
"10+20*x.y.z"
"a.b.c[ a.b ][ e.c( d.e()*4 )].e.f( (a.b+23)*d, -23*b.e(a.b.c) ).x.y"

дикое сочетание доступа к элементам, подписок массивов, вызова функций и выражений

[] -> subscription
() -> function call or expression bracket
. member chaining

в настоящее время я борюсь с пропуском пробелов в цепочке членов

"a  . b  . c"

недопустимо в моем мире - но анализируется из-за возможности пропуска пробелов

try онлайн моя уменьшенная выборка: https://wandbox.org/permlink/o5kcYtUQEfKZqJgw

Проблема в строке 23:

qi::rule<std::string::iterator, qi::blank_type, utree()> identifier_chain 
    = identifier >> *('.' >> identifier);

Я не могу использовать qi :: lexeme вокруг правила, я ' Я получу ошибку, которая не может быть преобразована в Skipper, но это сработает, если я скопирую свое полное правило идентификатора в правило identifier_chain

qi::rule<std::string::iterator, qi::blank_type, utree()> identifer_chain 
   = qi::lexeme[qi::ascii::alpha >> *(qi::ascii::alnum | '_') 
   >> *('.' >> qi::ascii::alpha >> *(qi::ascii::alnum | '_'))];

, но это кажется излишним, и я думаю, что копирование вызовет у меня проблемы в будущем когда синтаксический анализатор растет

любая идея, как использовать лексему или что-то еще, чтобы сохранить мой '.' подключается без пробелов, так что подписка заканчивается и цепочка членов сильно соединена

].a
a.b

, это единственное место в моем парсере, где пропуск пространства не нужен, в остальном идеально подходит для уменьшения кода парсера

Спасибо за любую помощь / подсказки

1 Ответ

2 голосов
/ 24 марта 2020

Вот как работают шкиперы (см. Проблемы повышения духа шкипера )

Ваше правило объявляет шкипера:

qi::rule<std::string::iterator, qi::blank_type, utree()> identifier_chain;

Так что, чтобы запретить его, вы можете окружить с лексемой, но вы могли бы просто выкинуть шкипера из декларации. То же самое относится и к правилу идентификатора, поскольку оно также полностью заключено в lexeme[].

Предлагаемое минимальное исправление:

Live On Coliru

#include <iostream>
#include <iomanip>
#include <string>
#include <boost/spirit/include/qi.hpp>
#include <boost/spirit/include/support_utree.hpp>

namespace qi = boost::spirit::qi;
using boost::spirit::utree;

int main() {
    auto tests = std::vector<std::string>{
        "a",       // ok
        "a.b",     // ok
        " a.b ",   // ok
        "a . b",   // error
        "a . b. c" // error
    };
    for (std::string const str : tests) {
        auto iter = str.begin(), end = str.end();

        qi::rule<std::string::const_iterator, utree()> 
            identifier = qi::ascii::alpha >> *(qi::ascii::alnum | '_'),
            identifier_chain = identifier >> *('.' >> identifier);

        utree ut;
        bool r = qi::phrase_parse(iter, end, identifier_chain >> qi::eoi, qi::blank, ut);

        std::cout << std::quoted(str) << " ";
        if (r) {
            std::cout << "OK: " << ut << "\n";
        } else {
            std::cout << "Failed\n";
        }
        if (iter!=end) {
            std::cout << "Remaining unparsed: " << std::quoted(std::string(iter,end)) << "\n";
        }
        std::cout << "----\n";
    }
    return 0;
}

Отпечатки:

"a" OK: ( "a" ) 
----
"a.b" OK: ( "a" "b" ) 
----
" a.b " OK: ( "a" "b" ) 
----
"a . b" Failed
Remaining unparsed: "a . b"
----
"a . b. c" Failed
Remaining unparsed: "a . b. c"
----
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...