Разбор токенизированной грамматики свободной формы с Boost.Spirit

Я застрял, пытаясь создать парсер Boost.Spirit для вывода инструмента callgrind, который является частью valgrind. Callgrind выводит специфичный для домена встроенный язык программирования (DSEL), который позволяет вам делать всякие интересные вещи, такие как пользовательские выражения для синтетических счетчиков, но это не так просто разобрать.

Я поместил некоторый пример вывода callgrind в https://gist.github.com/ned14/5452719#file-sample-callgrind-output. Я поместил мою лучшую попытку на лексер и анализатор Boost.Spirit на https://gist.github.com/ned14/5452719#file-callgrindparser-hpp а также https://gist.github.com/ned14/5452719#file-callgrindparser-cxx. Часть Lexer проста: она маркирует значения тегов, непробельный текст, комментарии, конец строк, целые числа, шестнадцатеричные числа, числа с плавающей точкой и операторы (игнорируйте знаки препинания в примере кода, они не используются). Пустое пространство пропущено.

Все идет нормально. Проблема заключается в разборе потока входных данных с токенами. Я еще даже не пробовал основные строфы, я все еще пытаюсь разобрать значения тегов, которые могут произойти в любой указать в файле. Значения тегов выглядят так:

tagtext: unknown series of tokens<eol>

Это может быть произвольный текст, например

desc: I1 cache: 32768 B, 64 B, 8-way associative, 157 picosec hit latency

В этой ситуации вы хотите преобразовать набор токенов в строку, т.е. в iterator_range и извлечь.

Однако это может быть выражение, например

event: EPpsec = 316 Ir + 1120 I1mr + 1120 D1mr + 1120 D1mw + 1362 ILmr + 1362 DLmr + 1362 DLmw

Это говорит о том, что с этого момента событие EPpsec должно быть синтезировано как Ir, умноженное на 316, добавленное к I1mr, умноженное на 1120, добавленное к … и т. Д.

Здесь я хочу подчеркнуть, что пары тег-значение должны накапливаться в виде произвольных наборов токенов и подвергаться последующей обработке во все, что мы превращаем в них позже.

С этой целью класс utree () Boost.Spirit выглядел в точности так, как я хотел, и это то, что использует пример кода. Но на VS2012 с использованием ноябрьского CTP-компилятора с переменными шаблонами в настоящее время я вижу эту ошибку компиляции:

1>C:\Users\ndouglas.RIMNET\documents\visual studio 2012\Projects\CallgrindParser\boost\boost/range/iterator_range_core.hpp(56): error C2440: 'static_cast' : cannot convert from 'boost::spirit::detail::list::node_iterator<const boost::spirit::utree>' to 'base_iterator_type'
1>          No constructor could take the source type, or constructor overload resolution was ambiguous
1>          C:\Users\ndouglas.RIMNET\documents\visual studio 2012\Projects\CallgrindParser\boost\boost/range/iterator_range_core.hpp(186) : see reference to function template instantiation 'IteratorT boost::iterator_range_detail::iterator_range_impl<IteratorT>::adl_begin<const Range>(ForwardRange &)' being compiled
1>          with
1>          [
1>              IteratorT=base_iterator_type
1>  ,            Range=boost::spirit::utree
1>  ,            ForwardRange=boost::spirit::utree
1>          ]

… который предполагает, что мой base_iterator_type, который является Boost.Spirit multi_pass<> Оберт istreambuf_iterator для прямой итераторной природы, как-то не понят реализацией utree () Boost.Spirit. Дело в том, что я не уверен, что это мой плохой код или плохой Boost.Spirit-код, который выглядит как line_pos_iterator<> не удалось правильно указать свой концептуальный тег forward_iterator.

Благодаря прошлой помощи Stackoverflow я мог написать чистую нетексенированную грамматику, но она была бы хрупкой. Правильное решение состоит в том, чтобы токенизировать и использовать грамматику произвольной формы, способную вводить произвольно. К сожалению, очень мало примеров того, как Лекс и Грамматика Boost.Spirit работают вместе на реальных примерах, а не на игрушечных примерах. Поэтому любая помощь будет принята с благодарностью.

Найл

1

Решение

Атрибут token предоставляет вариант, который, в дополнение к диапазону базовых итераторов, может _ссуждать типы, объявленные в token_type ЬурейеЕ:

typedef lex::lexertl::token<base_iterator_type, mpl::vector<std::string, int, double>> token_type;

Так: string, int а также double, Обратите внимание, что принуждение в один из возможных типов будет происходить только лениво, когда парсер на самом деле использует значение.

utreeэто очень универсальный контейнер [1]. Следовательно, когда вы выставляете spirit::utree атрибут по правилу и токен вариант значения содержит iterator_range, затем он пытается присвоить это в utree объект (это не удается, потому что итераторы … «фанки»).

Самый простой способ получить желаемое поведение — сила Ци, чтобы интерпретировать атрибут tag токен в виде строки, и есть тот назначен на utree, Поэтому следующая строка представляет исправление, которое сделает компиляцию успешной:

    unknowntagvalue = qi::as_string[tok.tag] >> restofline;

Заметки

Сказав все это, я бы действительно предложил следующее

  • Рассмотрите возможность использования Nabialek Trick отправлять разные ленивые правила в зависимости от tag соответствует — это делает ненужным иметь дело с сырым utreeпозже

  • Вы могли иметь успех, специализирующийся boost::spirit::traits::assign_to_XXXXXX черты (см. документация)

  • рассмотреть возможность использования чистого парсера Qi. Хотя я могу «чувствовать» ваше чувство, что «оно будет ломким» [2] кажется, вы уже продемонстрировали, что это повышает сложность до такой степени, что может не иметь ничего общего:

    • неожиданные способы, которыми материализуются атрибуты (этот вопрос)
    • проблема с line-pos итераторами (это часто задаваемый вопрос, и AFAIR имеет в основном жесткий или же безвкусный решения)
    • негибкость в отношении, например, оперативная отладка (доступ к исходным данным в SA), переключение / отключение шкипера и т. д.
    • мой личный опыт был то, что глядя на Лексер заявляет управлять ими не полезно, потому что переключение состояния лексера может только надежно работать с lexer token semantic actionsв то время как часто устранение неоднозначности Фаза ци

но я расходлюсь 🙂


[1] например у них есть средства для очень легкой «ссылки» на диапазоны итераторов (например, для символов, или чтобы избежать копирование персонажей из исходного буфера в атрибут, если не требуется)

[2] По сути, только потому, что использование последовательного лексера (сканера) значительно уменьшает количество возможностей возврата, поэтому упрощает ментальную модель синтаксического анализатора. Тем не менее, вы можете использовать expectation points к тому же эффекту.

3

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

Других решений пока нет …

По вопросам рекламы [email protected]