Как объединить правила пропуска и пропуска (лексемы)? - PullRequest
1 голос
/ 25 марта 2020

мой синтаксический анализатор почти работает :) (все еще пораженный набором функций Spirit (и временем компиляции) и очень приветливым сообществом здесь по переполнению стека)

небольшой пример для онлайн-попытки: http://coliru.stacked-crooked.com/a/1c1bf88909dce7e3

так что я научился использовать больше лексем-правил и пытаться предотвратить no_skip - мои правила меньше и лучше читать в результате, но теперь я застрял с объединением лексем-правил и правил пропуска, что кажется невозможным (ошибка времени компиляции с предупреждением о невозможности преобразования в Skipper)

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

синтаксический анализ:

"a.b[a,b]"

терпит неудачу:

"a.b[ a , b ]"

это мои правила:

qi::rule<std::string::const_iterator, std::string()> identifier_chain;

qi::rule<std::string::const_iterator, std::string()>
    expression_list = identifier_chain >> *(qi::char_(',') >> identifier_chain);

qi::rule < std::string::const_iterator, std::string() >
    subscription = qi::char_('[') >> expression_list >> qi::char_(']');

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

identifier_chain = identifier >> *(('.' >> identifier) | subscription);

, как вы видите, все правила "лексемы", и я думаю, что правило подписки должно быть ascii :: space_type Skipper, но это не компилирует

, если я добавлю метки пространства в начале и в конце identifier_chains в expression_list?

похоже на написание регулярного выражения :(

expression_list = *qi::blank >> identifier_chain >> *(*qi::blank >> qi::char_(',') >> *qi::blank >> identifier_chain >> *qi::blank);

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

спасибо за любой совет

кстати: любая идея, почему я не могу скомпилировать, если окружить '.' в indentifier_chain с qi::char_('.')

identifier_chain = identifier >> *(('.' >> identifier) | subscription);

UPDATE :

я обновил свой список выражений в соответствии с предложением sehe

qi::rule<std::string::const_iterator, spirit::ascii::blank_type, std::string()>
expression_list = identifier_chain >> *(qi::char_(',') >> identifier_chain);

qi::rule < std::string::const_iterator, std::string() >
subscription = qi::char_('[') >> qi::skip(qi::blank)[expression_list] >> qi::char_(']');

, но все еще получаю ошибку компиляции из-за некабельного шкипера: http://coliru.stacked-crooked.com/a/adcf665742b055dd

я также пытался изменить идентификатор_цепи к

identifier_chain = identifier >> *(('.' >> identifier) | qi::skip(qi::blank)[subscription]);

, но я все еще не могу скомпилировать пример

1 Ответ

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

Ответ, на который я ссылался ранее, описывает все комбинации (если я правильно помню): Проблемы шкипера в духе повышения

Короче:

  • любое правило, которое объявляет шкипер (поэтому rule<It, Skipper[, Attr()]> или rule<It, Attr(), Skipper>), ДОЛЖНО быть вызвано совместимым шкипером (выражение, которое может быть назначено типу Skipper).

  • любое правило, которое НЕ объявляет шкипер (например, в форме rule<It[, Attr()]>), будет неявно вести себя как лексема , что означает, что никакие входные символы не пропускаются.

Это оно. Немного более тонкие последствия заключаются в том, что с учетом двух правил:

rule<It, blank_type> a;
rule<It> b; // b is implicitly lexeme

Вы можете вызывать b из a:

a = "test" >> b;

Но когда вы будете sh для вызова a из b вы обнаружите, что должны предоставить шкипера:

b = "oops" >> a; // DOES NOT COMPILE
b = "okay" >> qi::skip(qi::blank) [ a ];

Это почти все, что нужно сделать. Есть еще несколько директив о шкиперах и лексемах в Ци, см. Снова ответ, связанный выше.

Дополнительный вопрос:

, если я добавлю едоков пространства в передней и задней части identifier_chains в expression_list?

Если вы внимательно посмотрите пример ответа здесь Разобрать '.' При помощи связанного списка идентификаторов с помощью qi :: lexeme и предотвращения пропуска пробелов вы можете видеть, что он уже правильно выполняет до и после пропуска, потому что я использовал phrase_parse:

" a.b " OK: ( "a" "b" ) 
----
"a . b" Failed
Remaining unparsed: "a . b"
----

Вы МОЖЕТЕ также обернуть все это во «внешнее» правило:

rule<std::string::const_iterator> main_rule = 
     qi::skip(qi::blank) [ identifier_chain ];

Это то же самое, но позволяет пользователям звонить parse без указания шкипера.

...