Как мне проанализировать выражение с вложенной круглой скобкой с помощью boost.Spirit?

#c #grammar #boost-spirit #boost-spirit-qi

#c #грамматика #boost-spirit #boost-spirit-qi

Вопрос:

Мне нужно проанализировать выражения из 1 строки, содержащие пары ключ / значение и пары ключ / подвыражение, например:

 123=a 456=b 789=(a b c) 111=((1=a 2=b 3=c) (1=x 2=y 3=z) (123=(x y z))) 666=evil
  

Чтобы упростить синтаксический анализатор, я готов выполнить синтаксический анализ в несколько этапов, разделив теги первого уровня (здесь 123, 456, 789, 111 и 666), а затем проанализировать их содержимое на другом шаге.
Здесь значение 789 будет "a b c" , значение 111 будет (1=a 2=b 3=c) (1=x 2=y 3=z) (123=(x y z)) .

Но грамматики превзошли меня на этом этапе, поэтому я могу найти способ получить выражения между соответствующими круглыми скобками. Все, что я получаю для 111, это (1=a 2=b 3=c , которое заканчивается на первой закрывающей круглой скобке.

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

 #include <map>
#include <string>
#include <boost/spirit/include/classic.hpp>
#include <boost/spirit/include/qi.hpp>
#include <boost/fusion/include/std_pair.hpp>

namespace qi = boost::spirit::qi;

void main()
{
    auto                                                                   value =  qi::char_("a-zA-Z_0-9");
    auto                                                                   key   =  qi::char_("a-zA-Z_") >> *qi::char_("a-zA-Z_0-9");
    qi::rule<std::string::iterator, std::pair<std::string, std::string>()> pair  =  key >> -('=' >> value);
    qi::rule<std::string::iterator, std::map<std::string, std::string>()>  query =  pair >> *((qi::lit(';') | 'amp;') >> pair);

    std::string input("key1=value1;key2;key3=value3");  // input to parse
    std::string::iterator begin = input.begin();
    std::string::iterator end = input.end();

    std::map<std::string, std::string> m;        // map to receive results
    bool result = qi::parse(begin, end, query, m);   // returns true if successful
}
  

Как я могу это сделать?

Редактировать: Я нашел пример на http://boost-spirit.com/home/articles/qi-example/parsing-a-list-of-key-value-pairs-using-spirit-qi/

Ответ №1:

Вы могли бы записать это как:

 qi::rule<std::string::iterator, std::pair<std::string, std::string>()> pair = 
        key >> -(
           '=' >> ( '(' >> raw[query] >> ')' | value )
        )
    ;
  

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

 qi::rule<std::string::iterator, std::pair<std::string, std::string>()> pair = 
        key >> -(
           '=' >> ( raw['(' >> query >> ')'] | value )
        )
    ;
  

Комментарии:

1. Для компиляции мне пришлось бы объявить (а не определить) query перед определением pair . Сработает ли это в любом случае?

2. Да, вы можете объявлять, определять и / или инициализировать правило до или после его фактического использования. Лучше всего использовать грамматики, где правила являются членами и они инициализируются в конструкторе грамматики.

3. @hkaiser Что такое «raw» в вашем примере? Я не могу найти никаких ссылок на него в этом сообщении.

4. @ForeverLearning: смотрите здесь соответствующую документацию: boost.org/doc/libs/1_63_0/libs/spirit/doc/html/spirit/qi /…