Ошибка анализа грамматики с помощью Spirit::Qi

Я новичок в Spirit::Qi и пытаюсь написать простой парсер Wavefront Obj. Я следовал руководствам с сайта документации Boost::Spirit (ссылка), и у меня работает большинство встроенных правил. Я начал экспериментировать с грамматиками, но не могу заставить их работать. Через некоторое время я скомпилировал его, но синтаксический анализ не удался. Я действительно не знаю, что я делаю неправильно.

Для начала я создал простой текстовый файл, содержащий следующее:

v  -1.5701 33.8087 0.3592
v  -24.0119 0.0050 21.7439
v  20.8717 0.0050 21.7439
v  20.8717 0.0050 -21.0255
v  -24.0119 0.0050 -21.0255
v  -1.5701 0.0050 0.3592

Просто чтобы быть уверенным: чтение входного файла работает нормально.

Я написал небольшую функцию, которая должна анализировать входную строку, но по какой-то причине она не работает:

bool Model::parseObj( std::string &data, std::vector<float> &v )
{
    struct objGram : qi::grammar<std::string::const_iterator, float()>
    {
        objGram() : objGram::base_type(vertex)
        {
            vertex = 'v' >> qi::float_
                         >> qi::float_
                         >> qi::float_; 
        }

        qi::rule<std::string::const_iterator, float()> vertex;
    };

    objGram grammar;

    return qi::phrase_parse( data.cbegin(), data.cend(),
                                grammar, iso8859::space, v );
}

qi::phrase_parse продолжает возвращать false, а std::vector v все еще пуст в конце...

Какие-либо предложения?

РЕДАКТИРОВАТЬ:

После добавления пробельных шкиперов (это правильное имя?) к std::vector добавляется только первый 'v', закодированный как число с плавающей запятой (118.0f), но фактические числа не добавляются. Я предполагаю, что мое правило неверно. Я хочу добавить только цифры и пропустить v.

Вот моя модифицированная функция:

bool Model::parseObj( std::string &data, std::vector<float> &v )
{
    struct objGram : qi::grammar<std::string::const_iterator, float(), iso8859::space_type>
    {
        objGram() : objGram::base_type(vertex)
        {
            vertex = qi::char_('v') >> qi::float_
                         >> qi::float_
                         >> qi::float_; 
        }

        qi::rule<std::string::const_iterator, float(), iso8859::space_type> vertex;
    } objGrammar;

    return qi::phrase_parse( data.cbegin(), data.cend(),
                                objGrammar, iso8859::space, v );
}

person Krienie    schedule 08.07.2013    source источник
comment
1) Если вы предоставите полный код, у вас есть шанс привлечь больше внимания. 2) Беглый взгляд... 118 - это код ascii для вашего 'v', поэтому он по ошибке распространяется на вывод. Если вы хотите избежать этого, у вас есть два варианта (а может и больше): a) qi::lit('v') ›› qi::float_ ›› qi::float_ ›› qi::float_ b) qi::omit [ qi::char_('v') ] ›› qi::float_ ›› qi::float_ ›› qi::float_   -  person G. Civardi    schedule 09.07.2013
comment
@ Г.Чиварди А. Вы нашли вопрос примерно в то же время, что и я. Вы пропустили виновника, но я связался с вашим ответом на вопрос о точности поплавка :) Ура   -  person sehe    schedule 09.07.2013
comment
@sehe нет проблем и большое спасибо :-) Ура   -  person G. Civardi    schedule 09.07.2013


Ответы (1)


Ваше правило объявляет неправильный открытый атрибут. Измени это:

qi::rule<std::string::const_iterator, std::vector<float>(), iso8859::space_type> vertex;

Однако, поскольку вы не шаблонируете свою грамматическую структуру ни на чем (например, на типе итератора/шкипера), нет смысла иметь грамматическую структуру. Вместо этого пусть phrase_parse просто выведет типы итератора, шкипера и правила одновременно и напишет:

bool parseObj(std::string const& data, std::vector<float> &v )
{
    return qi::phrase_parse( 
            data.cbegin(), data.cend(),
            'v' >> qi::float_ >> qi::float_ >> qi::float_, 
            qi::space, v);
}

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

Однако, увидев свою грамматику, вы наверняка захотите увидеть это:

person sehe    schedule 08.07.2013
comment
Отличный ответ! Большое Вам спасибо. Итак, в начале вы говорите, что я должен использовать грамматические структуры только в том случае, если я использую шаблоны? Другой вопрос: как я могу реализовать несколько правил при использовании фразы_parse так, как вы описываете? Потому что в конечном итоге я также хочу проанализировать числа с плавающей запятой, которым предшествуют vn и vt, которые находятся в одном и том же файле *.obj. Я просто запускаю функцию фразы_parse для каждого отдельного правила? Спасибо :) - person Krienie; 09.07.2013
comment
@KrienLinnenbank Я говорил, что грамматическая структура не выдерживает своего веса. Есть больше причин для использования грамматических структур, но в любом случае вы не будете определять их локально. - person sehe; 09.07.2013
comment
Что касается второго вопроса: я бы в любом случае разделил структуру грамматики и проанализировал вашу грамматику как она есть (в конце концов, для этого вы используете генератор синтаксических анализаторов!). т.е. Я бы не пропускал отдельные строки через отдельные правила. Возможно, вам следует задать вопрос, если вы застряли. (На данный момент обязательно посетите первый связанный другой ответ для идей) - person sehe; 09.07.2013