BOOST_FUSION_ADAPT_STRUCT
— автоматическое распространение атрибутов для пользовательских типов.В предыдущих частях (1-я, 2-я, 3-я, 4-я) я говорил об автоматическом заполнении STL структур атрибутами при парсинге. Таким образом мы, например, заполняли список пар «ключ=значение», пользуясь тем, что сами пары могли автоматически конвертироваться в std::pair<std::string, std::string>
, а список пар спокойно мог заполнить собой std::vector<std::pair<std::string, std::string> >
. Весь этот механизм, как тоже было сказано ранее, основывается на том, что для стандартных контейнеров STL существуют специальные обёртки, благодаря которым они могут считаться полноценными boost::fusion
последовательностями.
Как быть, если мы хотим, чтобы наша собственная структура при парсинге могла бы автоматически заполняться так же легко, как это например делают std::vector
или std::string
? Оказывается, способ есть. Притом достаточно простой. Я не зря сказал про обёртки, которыми снабжены стандартные контейнеры библиотеки STL. В нашем случае придётся сделать в точности то же самое — снабдить нашу структуру всем необходимым в этом плане, иными словами: сказать Boost.Fusion, что наша структура является полноправным Fusion контейнером, построенном на модели random access sequence
. Специально для этого в Fusion есть макрос BOOST_FUSION_ADAPT_STRUCT
, который позволяет адаптировать любую пользовательскую структуру в полноправный Fusion контейнер.
В предыдущих частях (первая, вторая, третья) мы занимались парсингом в простые структуры данных, не сложнее обычного списка величин. Сейчас же попробуем посмотреть, как можно с минимальными усилиями строить на выходе парсера иерархические структуры данных, такие как абстрактные синтаксические деревья.
Когда мы пользуемся тем или иным языком, будь то языком программирования или естественным языком, мы составляем фразы в соответствии с обпределённой иерархией подчинения. Одни смысловые конструкции включают в себя другие и сами являются составными частями более общих. Например: программа может состоять из функций; функции состоят из названия, типа возвращаемого значения, типов параметров, и исполняемого кода; исполняемый код состоит из операторов, ну и так далее.
Генерацией таких иерархических структур из текстового представления языка программирования занимается парсер. Обычно на выходе парсера мы получаем дерево разбора, то есть сущность, описывающую синтаксическую структуру программы в соответствии с описывающей её формальной грамматикой. Далее такие деревья уже преобразовываются в абстрактные синтаксические деревья (на русском) — структуры, которые избавлены от несущественных синтаксических деталей, из коих обычно состоит дерево разбора, и где присутствующие в них конструкции уже наполнены неким смысловым дополнительным содержанием, которое обычно добавляется на стадии семантического (контекстного) анализа.
В предыдущих частях (первая, вторая) мы познакомились непосредственно с основами фреймворка для написания парсеров Spirit.Qi.
Основное время в этой части я посвящу описанию библиотеки boost::phoenix
, которая в некоторых случаях очень сильно помогает облегчить написание семантических правил для грамматик, написанных на Спирите. Далее, увидим применение этого товарища на практике, сначала на демонстративных примерах, затем при реализации третьего шага нашего плана — написании компилирующего калькулятора.
Вот и вторая часть повествования, здесь мне придётся вас маленько огорчить — сразу же переходить ко второму пункту нашего плана я не стану, а прежде расскажу чуть более подробно о синтезируемых атрибутах, это нам очень пригодится в будущем. Понимание всех этих основных принципов для освоения Спирита очень важно, так что я просто не могу обойти эту тему стороной и сразу поместить читателя в гущу событий, чтобы он «как-нибудь там» разбирался с тем, что так внезапно свалилось на голову.
Несмотря на то, что данная статья имеет в большей степени ознакомительный характер, предполагается, что читатель знает (ну или хотя бы краем уха слышал) о таких вещах, как C++, шаблонное метапрограммирование, Boost, в противном случае горите в аду, сраные грешники возникнут проблемы с пониманием, на что мне совершенно будет наплевать — я же предупреждал, курите маны, если уж на то пошло. Впрочем, в некоторых местах всё же будут оставлены некоторые уточнения по той или иной теме, где я сочту нужным остановиться и рассказать чуть поподробнее о том, что вообще происходит.