Проблема анализа Spirit Qi с простым структурированным вводом в стиле C

Я пытаюсь настроить базовый синтаксический анализатор для некоторых игровых данных, который использует знакомый и очень простой формат «C-style». В основном, называя фигурные скобки «структуры», затем помещая параметры и вложенные «структуры» внутрь. Он будет разбирать что-то вроде этого:

Name0
{
 Name1
 {
  Param0 *= 2
  Param2 = "lol"
 }
 Param0 = 1
 Param1 = "test"

 Name2 { }
}

Name3 {
 Param0 = "test"
}

Тем не менее, он терпит неудачу даже при простом входном тесте «Test {}», не говоря уже о том, чтобы получить что-то настолько сложное, как в моем примере выше. Структуры настроены на использование слияния, и это кажется достаточно простым, поэтому я сомневаюсь, что это проблема. В настоящее время я не использую пару правил, и большинство моих правил не проверены, потому что они терпят неудачу, когда пытаются выполнить первое правило category в root. Это ошибка, которую я получаю при вводе «Test {}»:

Error! Expecting <sequence>"{"<node> here: ""

Вот класс Parser:

 template<typename Iterator>
 struct Parser : qi::grammar<Iterator, std::vector<Category>(), ascii::space_type>
 {
  qi::rule<Iterator, std::vector<Category>(), ascii::space_type> root;

  qi::rule<Iterator, Category(), ascii::space_type> category;
  qi::rule<Iterator, Param(), ascii::space_type> param;

  qi::rule<Iterator, Node(), ascii::space_type> node;

  qi::rule<Iterator, Value(), ascii::space_type> value;

  qi::rule<Iterator, char()> escape;
  qi::rule<Iterator, std::string()> quotedstring;
  qi::rule<Iterator, std::string()> normalstring;

  qi::rule<Iterator> comment;
  qi::rule<Iterator> commentblock;

  Parser() : Parser::base_type(root, "root")
  {
   using namespace qi;

   using ascii::char_;

   using phoenix::construct;
   using phoenix::val;

   escape %= '\\' > char_("\\\"");
   quotedstring %= '"' >> *((char_ - '"') | escape) > '"';
   normalstring %= *(char_ - qi::eol);

   comment = "//" >> *(char_ - qi::eol);
   commentblock = "/*" >> *(char_ - "*/") > "*/";

   node %= category | param; //comment? comment block? holding off for now

   value %= normalstring | float_;

   param %=
    lexeme[+(char_ - operators)]
    > operators
    > value
    > qi::eol;

   category %=
    lexeme[+(char_ - '{')] //won't this grab all whitespace around the tag too?
    > '{'
    >> *node
    > '}';

    root %= *category;

    root.name("root");

    category.name("category");
    param.name("param");

    node.name("node");

    value.name("value");

    escape.name("escape");
    quotedstring.name("quotedstring");
    normalstring.name("normalstring");

    comment.name("comment");
    commentblock.name("commentblock");

    debug(root);
    debug(category);
    debug(param);
    debug(node);
    debug(value);
    debug(escape);
    debug(quotedstring);
    debug(normalstring);
    debug(comment);
    debug(commentblock);

    on_error<fail>
     (
     root,
     std::cout
     << val("Error! Expecting ")
     << _4
     << val(" here: \"")
     << construct<std::string>(_3, _2)
     << val("\"")
     << std::endl
     );
  }
 };

И не связанная с этим вещь: можно ли использовать лямбда-выражения С++ 11 в вызовах on_success и on_error? Я просмотрел функцию on_error, и, похоже, ее параметры шаблонизированы в соответствии с типом правила, а это означает, что лямбда должна быть определена для каждого отдельного типа правила (в основном для каждого правила). Это правильно? Очень жаль, эти лямбда-фэниксы настолько непрозрачны, что я понятия не имею, как даже вытащить номер строки и поместить его в структуру.

редактировать:

Вот таблица operators:

 struct Operators : qi::symbols<char, Operator>
 {
  Operators()
  {
   add
    ("=", Operator::equal)
    ("+=", Operator::plusequal)
    ("-=", Operator::minusequal)
    ("*=", Operator::timesequal)
    ("/=", Operator::divideequal)
    ;
  }
 } operators;

person user173342    schedule 17.02.2014    source источник
comment
Возможно, вам подойдет расширение property_tee с форматом информационного файла.   -  person Mike M    schedule 18.02.2014
comment
@MikeM Парсер INFO в дереве свойств выглядит очень интересно, и в основном это то, чем я сейчас занимаюсь. Мой текущий формат не является окончательным форматом, я думал добавить более сложные вещи (еще не решил, как их сделать), поэтому я не уверен, что INFO Parser справится с ними... Так что я' Мне все еще любопытно, как это исправить, на всякий случай. Но да, очень хорошее предложение! редактировать: Ах, на самом деле, он не поддерживает изменение существующих значений, например, с *=   -  person user173342    schedule 18.02.2014


Ответы (1)


operators не дается.

Я предполагаю, что ваше правило node съедает закрывающее }, поэтому правило catagory не может быть успешным.

person Mike M    schedule 17.02.2014
comment
Ах, может быть, первое правило category попадает в Test {, затем оно входит в node и пытается выполнить другое правило category... Но category игнорирует только символ '{', поэтому съедает '}' и умирает? param также не игнорирует '}'... Хотя это становится сложно. Можете ли вы вычесть более одной вещи, потому что в настоящее время я вычитаю свою таблицу символов из char_ в param... Если это вообще разрешено, у меня не было возможности проверить это, ха-ха. - person user173342; 18.02.2014
comment
rule - (sub1|sub2|sub3) вычитает больше. Да, } съеден и category закрыть уже нечем. Поскольку вы используете >, вы получаете исключение с >>, синтаксический анализ не увенчается успехом. - person Mike M; 18.02.2014
comment
Итак, первая проблема устранена, и вложенные категории работают!... но затем я пытаюсь param, и снова ничего не получается. Придется поэкспериментировать, но я заметил одну странную вещь. Мое правило node %= category | param; сильно меняет свою ошибку и вывод отладки в зависимости от порядка (если я сначала поставлю param или category). Кажется, что если category является первым, он пытается интерпретировать node как category (согласно выходным данным отладки), а когда это не удается, просто сдается и даже не исследует использование его как param? Должен ли порядок иметь значение? - person user173342; 18.02.2014
comment
Порядок имеет значение, правило, которое вы пишете первым, используется первым, но если оно терпит неудачу, синтаксический анализатор возвращается и пробует следующее правило. Но если вы получите исключение, используя >, синтаксический анализатор полностью остановится. - person Mike M; 18.02.2014
comment
Хорошо, я просто избегаю >, так как не знаю, когда его следует использовать прямо сейчас. Использование >> вывело меня на правильный путь! Спасибо! - person user173342; 18.02.2014
comment
Что ж, > следует использовать, когда вы хотите сообщать пользователям об ошибках парсера. С >> вы просто видите, что его не удалось разобрать, а не почему. - person Mike M; 18.02.2014
comment
Относительно %=: это сокращение для семантического действия [qi::_val = qi::_1]. Это означает, что какой бы ни была ваша структура Value, она должна принимать либо вектор‹char› (или std::string), либо число с плавающей запятой. Лично я справлялся с этим в прошлом, создавая абстрактный базовый класс с производными классами, которые содержат либо один, либо другой, и тогда ваше правило «значение» будет иметь указатель на базовый класс в качестве атрибута. Конечно, вам нужно будет использовать BOOST_FUSION_ADAPT_STRUCT для любой структуры, которую вы используете в качестве атрибута. В качестве альтернативы вы можете сделать это с помощью boost::variant, но я никогда не пробовал. - person FatalFlaw; 18.02.2014
comment
Относительно ›: просто чтобы расширить комментарий Майка М - вы используете его только тогда, когда знаете, что правое ДОЛЖНО следовать за левым, иначе это ошибка. Между прочим, у меня были проблемы с смешиванием › и ›› в одном правиле, моему компилятору это, похоже, не нравится, поэтому я стараюсь структурировать свои правила так, чтобы они использовали либо ›, либо ››. Использование › очень полезно для получения обратной связи о том, почему синтаксический анализ завершается неудачно, и, насколько мне известно, ваша функция on_error‹fail› будет вызываться только в случае сбоя ›. В другом случае функция синтаксического анализа просто возвращает false, что не очень полезно. - person FatalFlaw; 18.02.2014
comment
@FatalFlaw Спасибо за совет! На самом деле я использую variant (это то, что делает официальный учебник по qi doc), например: typedef boost::variant<std::string, float> Value. Очень полезно попробовать, найдено внизу этой страницы: boost.org/doc/libs/1_55_0/libs/spirit/doc/html/spirit/qi/ . Необходимо использовать шаблон посетителя для доступа к значениям, что они делают в mini_xml_printer в примере mini_xml2.cpp. Также в некоторых местах используется fusion. Что касается >, то я его сейчас использую только для закрытия фигурных скобок и тому подобного. - person user173342; 19.02.2014
comment
@ user173342: Да, boost::variant кажется подходящим вариантом. Виной тому слишком много лет программирования на C :) Единственным недостатком, возможно, является неэффективное использование пространства, если у вас есть массивный поток для анализа. - person FatalFlaw; 19.02.2014