boost :: spirit :: qi парсинг дубликатов на выходе

У меня есть этот очень простой парсер, использующий Boost :: Spirit:

rule<std::string::iterator, std::string()> zeroTo255 = (string("25") >> char_('0', '5'))
| (char_('2') >> char_('0', '4') >> digit)
| (char_('1') >> repeat[2](digit))
| (char_('1', '9') >> digit) | digit;

Когда я пытаюсь разобрать

std::string o{"1"};
std::string s;
parse(o.begin(), o.end(), zeroTo255, s);
std::cout << o << ": " << s << std::endl;

У меня как выходной

1: 111

Я явно что-то делаю не так, но что?

5

Решение

qi::hold это один из способов, как правильно сказал @Andrzej

Я думаю, что у меня есть несколько замечаний, которые могут помочь, а также лучшее решение.


Дело в том, что Spirit не будет требовать временного хранения атрибутов по дизайну. На самом деле, он не может предположить, что атрибут в первую очередь копируемый. Это причина здесь (представьте, что все разбирается в одном std :: vector<> а копирование для каждого шага парсера?).

На более существенном уровне мне кажется, что здесь не обратная обработка атрибутов, а само выражение синтаксического анализатора: Это не в состоянии заявить намерение, и несет в себе все виды сложности, связанные с представлениями чисел когда … на самом деле это не должно

Мой взгляд на это будет

rule<std::string::iterator, std::string()> zeroTo255, alternatively;

alternatively %= raw [ uint_ [ _pass = (_1 <= 255) ] ];

Вы видите: вы позволяете Духу анализировать число, и на самом деле просто проверяете диапазон, что вы и хотели сделать в первую очередь.

Второе, что мне кажется типичным, это то, что правило выставляет std::string атрибут, а не unsigned char например Это почему?

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

  • негативный взгляд (!parser) — который не влияет на атрибуты
  • позитивный взгляд (&parser) — который не влияет на атрибуты
  • Познакомиться с qi::as_string, qi::raw, qi::lexeme а также qi::no_skip
  • семантические действия (не полагайтесь на автоматические правила)

Вот что минимальное изменение в вашем первоначальном правиле будет иметь работал:

zeroTo255 = raw [
("25" >> char_("0-5"))
| ('2' >> char_("0-4") >> digit)
| ('1' >> digit >> digit)
| (char_("1-9") >> digit)
| digit
];

Это имеет примерно тот же эффект, что и код, использующий qi::hold но не недостаток производительности значений атрибута _hold_ing.

Надеюсь это поможет.

Полный образец: Live on http://liveworkspace.org/code/4v4CQW$0:

#include <boost/spirit/include/qi.hpp>
#include <boost/spirit/include/phoenix.hpp>

namespace qi = boost::spirit::qi;

int main()
{
using namespace qi;
rule<std::string::iterator, std::string()> zeroTo255, alternatively;

zeroTo255 = raw [
("25" >> char_("0-5"))
| ('2' >> char_("0-4") >> digit)
| ('1' >> digit >> digit)
| (char_("1-9") >> digit)
| digit
];

alternatively %= raw [ uint_ [ _pass = (_1 <= 255) ] ];

for (auto& input : std::vector<std::string> { "255", "249", "178", "30", "4" })
{
std::string output;
std::cout << "zeroTo255:\t" << std::boolalpha
<< parse(std::begin(input), std::end(input), zeroTo255, output)
<< ": " << output << std::endl;

output.clear();
std::cout << "alternatively:\t" << std::boolalpha
<< parse(std::begin(input), std::end(input), alternatively, output)
<< ": " << output << std::endl;
}

}

Выход

zeroTo255:      true: 255
alternatively:  true: 255
zeroTo255:      true: 249
alternatively:  true: 249
zeroTo255:      true: 178
alternatively:  true: 178
zeroTo255:      true: 30
alternatively:  true: 30
zeroTo255:      true: 4
alternatively:  true: 4
8

Другие решения

Однажды я столкнулся с подобной проблемой. Это особый способ работы альтернативного оператора в Spirit. Ваш пример должен работать, если вы используете дополнительную директиву «hold».

rule<std::string::iterator, std::string()> zeroTo255
= hold[string("25") >> char_('0', '5')]
| hold[char_('2') >> char_('0', '4') >> digit]
| hold[char_('1') >> repeat[2](digit)]
| hold[char_('1', '9') >> digit] | digit;

Подробнее об этом поведении смотрите эта тема.

5

По вопросам рекламы ammmcru@yandex.ru
Adblock
detector