Я новичок в 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 :: фразу_parse продолжает возвращать false, а std :: vector v в конце все еще пусто …
Какие-либо предложения?
РЕДАКТИРОВАТЬ:
После добавления пробелов (это правильное имя?), Только первый ‘v’ добавляется к std :: vector, закодированному как float (118.0f), но фактические числа не добавляются. Я думаю, что мое правило не правильно. Я хочу только добавить цифры и пропустить буквы.
Вот моя измененная функция:
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 );
}
Ваше правило объявляет неверный выставленный атрибут. Измени это:
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);
}
Я думаю, вы согласитесь, что это более важно. И в качестве бонуса, он «просто работает» (ТМ) из-за удивительности, которая автоматическое распространение атрибутов правила.
Однако, увидев свою грамматику, вы наверняка захотите увидеть это:
Как быстро проанализировать разделенные пробелами числа в C ++? показывая, как разобрать в вектор структур
struct float3 {
float x,y,z;
};
typedef std::vector<float3> data_t;
с небольшим или без дополнительной работы. О, и это сравнивает дух подхода, читающего файл размером 500 Мб с конкурирующим fscanf
а также atod
звонки. Таким образом, он анализирует несколько строк одновременно 🙂
Использовать qi::double_
парсер вместо qi::float_
даже если вы в конечном итоге назначаете с одинарной точностью float
переменные. Увидеть Повышение точности анализатора плавающих чисел
Других решений пока нет …