<?xml version="1.0" encoding="UTF-8"?>
<?xml-stylesheet type="text/xsl" media="screen" href="/~d/styles/atom10full.xsl"?><?xml-stylesheet type="text/css" media="screen" href="http://feeds.feedburner.com/~d/styles/itemcontent.css"?><feed xmlns="http://www.w3.org/2005/Atom"><title>Personal notes</title><id>tag:zag.ru,2011:1</id><link rel="alternate" href="http://zag.ru" type="text/html" /><updated>2012-02-25T22:50:55Z</updated><author><name>Aliaksandr Zahatski</name><uri>http://zag.ru</uri><object-type xmlns="http://activitystrea.ms/spec/1.0/">http://activitystrea.ms/schema/1.0/person</object-type></author><atom10:link xmlns:atom10="http://www.w3.org/2005/Atom" rel="self" type="application/atom+xml" href="http://feeds.feedburner.com/PerlZagPersonalBlog" /><feedburner:info xmlns:feedburner="http://rssnamespace.org/feedburner/ext/1.0" uri="perlzagpersonalblog" /><atom10:link xmlns:atom10="http://www.w3.org/2005/Atom" rel="hub" href="http://pubsubhubbub.appspot.com/" /><entry><title>Техническое задание в формате Perl 6 Pod</title><id>tag:zag.ru,2011:1.828d9501fe15492cbf34b2337d26a96d</id><content type="html">&lt;div xmlns='http://www.w3.org/1999/xhtml'&gt;&lt;p /&gt;&lt;p&gt;Ранее я уже рассказывал о полезных свойствах такого документа как техническое задание &lt;sup&gt;&lt;a href='#ftn.nid1' name='nid1'&gt;[1]&lt;/a&gt;&lt;/sup&gt;. В этот раз я расскажу о том, как я пишу подобные документы.
&lt;/p&gt;&lt;p&gt;Я пробовал когда-то создавать проектную документацию по ГОСТу &lt;sup&gt;&lt;a href='#ftn.nid2' name='nid2'&gt;[2]&lt;/a&gt;&lt;/sup&gt;, но данный подход оказался «несовместим»
с реальной жизнью. В итоге я пришел к менее формальному решению и использую последние годы
следующую структуру этого документа: 
&lt;/p&gt;&lt;pre&gt;&lt;code&gt; Заголовок: Техническое задание на разработку
 Изменения
 Основные положения
 Release Notes
 Терминология и Соглашения
 Что необходимо сделать
 Идеи и дополнения
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;где, 
&lt;/p&gt;&lt;dl&gt;&lt;dt&gt;&lt;strong&gt;Изменения&lt;/strong&gt;&lt;/dt&gt;&lt;dd&gt;&lt;p&gt;
Список значимых изменений в документе. Каждая запись начинается с даты и версии документа. Изменения отсортированы в порядке устаревания.&lt;/p&gt;&lt;pre&gt;&lt;code&gt;    =CHANGES
    Jan 22th 2012(v0.3)[zag]   Изменения в алгоритме работы crawler (+ определение качества фильма). 
    Jan  6th 2012(v0.2)[zag]   Основные функциональные блоки.
    Dec 24th 2011(v0.1)[zag]   Начальная версия&lt;/code&gt;&lt;/pre&gt;&lt;/dd&gt;&lt;dt&gt;&lt;strong&gt;Основные положения&lt;/strong&gt;&lt;/dt&gt;&lt;dd&gt;&lt;p&gt; 
Здесь описывается идея и общий результат. Данный раздел начинается с фразы:
«Требуется разработать ...».&lt;/p&gt;&lt;pre&gt;&lt;code&gt;  =head1 Основные положения&lt;/code&gt;&lt;/pre&gt;&lt;pre&gt;&lt;code&gt;   Требуется разработать систему размещения рекламных объявлений 
   на виджетах со следующими возможностями:&lt;/code&gt;&lt;/pre&gt;&lt;pre&gt;&lt;code&gt;  =item Создание и редактирование рекламных компаний
  =item Отображение рекламы на виджетах
  =item Сбор статистической информации (показы, переходы)&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Описание целей сопровождаются снимками прототипов &lt;em&gt;(или набросками от руки)&lt;/em&gt;. &lt;/p&gt;&lt;/dd&gt;&lt;dt&gt;&lt;strong&gt;Release Notes&lt;/strong&gt;&lt;/dt&gt;&lt;dd&gt;&lt;p&gt;
Список задач, которые станут частью выпускаемых версий. Задачи формулируются в виде строк,
которые будут затем перенесены в Release Notes к каждой версии.&lt;/p&gt;&lt;p&gt;Например:&lt;/p&gt;&lt;pre&gt;&lt;code&gt; =head1 Release Notes&lt;/code&gt;&lt;/pre&gt;&lt;pre&gt;&lt;code&gt; * Отображение рекламы на виджетах 
 * Рабочее место менеджера рекламных компаний ( управление рекламными компаниями 
   и просмотр статистики)
 * Регистрация отображения рекламных сообщений и переходов по ссылкам&lt;/code&gt;&lt;/pre&gt;&lt;/dd&gt;&lt;dt&gt;&lt;strong&gt;Терминология и соглашения&lt;/strong&gt;&lt;/dt&gt;&lt;dd&gt;&lt;p&gt;
Здесь полезно дать определение базовым терминам.&lt;/p&gt;&lt;p&gt;Если в ТЗ вводится новая терминология, то 
в таких случаях желательно разместить более подробную информацию, например копии
экранов, возможно указать часть бизнес логики, где та или иная сущность используется.&lt;/p&gt;&lt;pre&gt;&lt;code&gt; =head1 Терминология и соглашения&lt;/code&gt;&lt;/pre&gt;&lt;pre&gt;&lt;code&gt; Термины, котороые появляются в контексте «Системы рекламных сообщений»:&lt;/code&gt;&lt;/pre&gt;&lt;pre&gt;&lt;code&gt; =defn Медиаплан
 реклмное объявление, которое ...
 =defn Карточка медиаплана
 форма отображения свойств медиаплана, содержащая ...&lt;/code&gt;&lt;/pre&gt;&lt;/dd&gt;&lt;dt&gt;&lt;strong&gt;Что необходимо сделать ?&lt;/strong&gt;&lt;/dt&gt;&lt;dd&gt;&lt;p&gt;
Этот раздел самый большой. В нем содержится общее описание проекта, а так же последующее 
уточнение составляющих его частей.&lt;/p&gt;&lt;p&gt;В качестве иллюстраций используются фотоснимки набросков от руки, полученные во время 
совместных обсуждений с разработчиками и менеджерами. Позже, данные
эскизы могут быть перерисованы в графических программах, но в самом начале работы
достаточно набросков.&lt;/p&gt;&lt;pre&gt;&lt;code&gt; =head1 Что необходимо сделать ?
 =head2 Общая структура&lt;/code&gt;&lt;/pre&gt;&lt;pre&gt;&lt;code&gt; Рассмотрим общую структуру, на которой выделим составные части и связи между ними:&lt;/code&gt;&lt;/pre&gt;&lt;pre&gt;&lt;code&gt;     РИСУНОК ОБЩЕЙ СТРУКТУРЫ&lt;/code&gt;&lt;/pre&gt;&lt;pre&gt;&lt;code&gt; , где (1) - web интерфейс (рабочее место менеджера рекламных компаний)&lt;/code&gt;&lt;/pre&gt;&lt;pre&gt;&lt;code&gt; =head3 Рабочее место менеджера рекламных компаний&lt;/code&gt;&lt;/pre&gt;&lt;/dd&gt;&lt;dt&gt;&lt;strong&gt;Идеи и дополнения&lt;/strong&gt;&lt;/dt&gt;&lt;dd&gt;&lt;p&gt;
Во время обсуждений в данном разделе собираются в основном идеи, высказанные вне
совместных встреч участников проекта.&lt;/p&gt;&lt;p&gt;Обычное содержимое этого раздела следующее:&lt;/p&gt;&lt;pre&gt;&lt;code&gt;  =head1 Идеи и дополнения&lt;/code&gt;&lt;/pre&gt;&lt;pre&gt;&lt;code&gt;  ___________________________________________________
  ___________________________________________________
  ___________________________________________________
  ___________________________________________________
  ___________________________________________________&lt;/code&gt;&lt;/pre&gt;&lt;/dd&gt;&lt;/dl&gt;&lt;p /&gt;&lt;p&gt;За основу такой структуры ТЗ, я взял документ из какого-то зарубежного блога, посвященного тематике
разработки Web проектов. Возможно подойдет определение «функциональная спецификация»,
но как бы то ни было, наличие этого документа облегчает жизнь всем.
&lt;/p&gt;&lt;div class='footnote'&gt;&lt;p&gt;NOTES&lt;/p&gt;&lt;p&gt;&lt;a href='#nid1' name='ftn.nid1'&gt;&lt;sup&gt;1.&lt;/sup&gt;&lt;/a&gt; Как POD помог мне. &lt;a href='http://zag.ru/a4C81'&gt;http://zag.ru/a4C81&lt;/a&gt;&lt;/p&gt;&lt;p&gt;&lt;a href='#nid2' name='ftn.nid2'&gt;&lt;sup&gt;2.&lt;/sup&gt;&lt;/a&gt;  Техническое задание согласно ГОСТу. &lt;a href='http://it-gost.ru/content/view/101/51/'&gt;http://it-gost.ru/content/view/101/51/&lt;/a&gt;&lt;/p&gt;&lt;/div&gt;&lt;/div&gt;</content><object-type xmlns="http://activitystrea.ms/spec/1.0/">http://activitystrea.ms/schema/1.0/article</object-type><link2 xmlns="http://activitystrea.ms/spec/1.0/" rel="alternate" href="http://zag.ru/2012/027/a1/tekhnicheskoe-zadanie-v-formate-Perl-6-Pod.html" title="Техническое задание в формате Perl 6 Pod" type="text/html" /><link rel="alternate" href="http://zag.ru/2012/027/a1/tekhnicheskoe-zadanie-v-formate-Perl-6-Pod.html" title="Техническое задание в формате Perl 6 Pod" type="text/html" /><published>2012-01-27T10:00:00Z</published><updated>2012-01-27T10:00:00Z</updated></entry><entry><title>Грамматики для Perl 5 и JavaScript</title><id>tag:zag.ru,2011:1.4ae5662c37474dc98af92ec9cad28f2c</id><content type="html">&lt;div xmlns='http://www.w3.org/1999/xhtml'&gt;&lt;p /&gt;&lt;p&gt;В продолжение темы инструментов синтаксического анализа &lt;sup&gt;&lt;a href='#ftn.nid1' name='nid1'&gt;[1]&lt;/a&gt;&lt;/sup&gt; опишу еще пару.
&lt;/p&gt;&lt;p&gt;Прежде приведу ссылку на статью про основу построений грамматик в Perl 5 &lt;sup&gt;&lt;a href='#ftn.nid2' name='nid2'&gt;[2]&lt;/a&gt;&lt;/sup&gt;.
&lt;/p&gt;&lt;h2&gt;Парсер Marpa для Perl 5
&lt;/h2&gt;&lt;p&gt;Alexey Shrub &lt;em&gt;(за что ему отдельное спасибо)&lt;/em&gt; подбросил ссылку на еще одну библиотеку для Perl 5 - Marpa &lt;sup&gt;&lt;a href='#ftn.nid3' name='nid3'&gt;[3]&lt;/a&gt;&lt;/sup&gt;. Этому проекту около 4 лет и недавно вышла XS версия за номером 1.0 &lt;sup&gt;&lt;a href='#ftn.nid4' name='nid4'&gt;[4]&lt;/a&gt;&lt;/sup&gt;, что вроде как намекает на стабильность.
&lt;/p&gt;&lt;p&gt;Вот пример грамматики, описывающей простой калькулятор:
&lt;/p&gt;&lt;pre&gt;&lt;code&gt;
my $grammar = Marpa::PP::Grammar-&amp;gt;new(
    {   start   =&amp;gt; 'Expression',
        actions =&amp;gt; 'My_Actions',
        default_action =&amp;gt; 'first_arg',
        rules   =&amp;gt; [
            { lhs =&amp;gt; 'Expression', rhs =&amp;gt; [qw/Term/] },
            { lhs =&amp;gt; 'Term', rhs =&amp;gt; [qw/Factor/] },
            { lhs =&amp;gt; 'Factor', rhs =&amp;gt; [qw/Number/] },
            { lhs =&amp;gt; 'Term', rhs =&amp;gt; [qw/Term Add Term/], action =&amp;gt; 'do_add' },
            {   lhs    =&amp;gt; 'Factor',
                rhs    =&amp;gt; [qw/Factor Multiply Factor/],
                action =&amp;gt; 'do_multiply'
            },
        ],
    }
);
&lt;/code&gt;&lt;/pre&gt;&lt;p /&gt;&lt;p&gt;Непосредственно правила описываются в виде массива хэшей, в которых ключи
&lt;code&gt;lhs&lt;/code&gt; - имена правил, а ключи &lt;code&gt;rhs&lt;/code&gt; описывают возможные комбинации значений. Marpa умеет вызывать обработчики правил для выполнения каких-либо
действий (ключ &lt;strong&gt;action&lt;/strong&gt;).
&lt;/p&gt;&lt;p&gt;В правилах &lt;em&gt;не&lt;/em&gt; используются регулярные выражения. Чтобы описать количество повторений используется  ключ "min". 
&lt;/p&gt;&lt;p&gt;Например:
&lt;/p&gt;&lt;pre&gt;&lt;code&gt;  # Эквивалент * в регулярных выражениях
  { lhs =&amp;gt; 'sequence', rhs =&amp;gt; ['item'], &lt;strong&gt;min&lt;/strong&gt; =&amp;gt; 0 } 
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Возможные значения должны быть перечислены явно:
&lt;/p&gt;&lt;pre&gt;&lt;code&gt;    $recce-&amp;gt;read( &lt;strong&gt;'Number', 42&lt;/strong&gt; );
    $recce-&amp;gt;read( 'Multiply', );
    $recce-&amp;gt;read( &lt;strong&gt;'Number', 1&lt;/strong&gt; );
    $recce-&amp;gt;read( 'Add', );
    $recce-&amp;gt;read( &lt;strong&gt;'Number', 7&lt;/strong&gt; );
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Это и есть расплата за игнорирование регулярных выражений в угоду скорости :-). Советую посмотреть программу по разбору CSS &lt;sup&gt;&lt;a href='#ftn.nid5' name='nid5'&gt;[5]&lt;/a&gt;&lt;/sup&gt;. Там, в начале, производится анализ и сбор возможных значений с помощью регулярных выражений &lt;em&gt;(никуда тут не денешься)&lt;/em&gt;.
&lt;/p&gt;&lt;p&gt;Также возможно будет интерсна стратья об  использовании библиотеки Marpa-HTML &lt;sup&gt;&lt;a href='#ftn.nid6' name='nid6'&gt;[6]&lt;/a&gt;&lt;/sup&gt; для обработки HTML. И я &lt;em&gt;не&lt;/em&gt; советую смотреть в исходный код самого парсера Marpa-HTML &lt;sup&gt;&lt;a href='#ftn.nid7' name='nid7'&gt;[7]&lt;/a&gt;&lt;/sup&gt;.
&lt;/p&gt;&lt;h2&gt;Грамматики для JavaScript
&lt;/h2&gt;&lt;p&gt;Наиболее развитым, на мой взгляд, является PEG.js &lt;sup&gt;&lt;a href='#ftn.nid8' name='nid8'&gt;[8]&lt;/a&gt;&lt;/sup&gt;&lt;/p&gt;&lt;p&gt;Парсер грамматик работает по принципу Javacc &lt;em&gt;(да и по синтаксису очень похож)&lt;/em&gt;: сначала описываются грамматики, а затем генерируется парсер. Генератор кода запускается под Node.js.
&lt;/p&gt;&lt;p&gt;Вот пример грамматики для обработки арифметического выражения &lt;code&gt;2*(3+4)&lt;/code&gt;:
&lt;/p&gt;&lt;pre&gt;&lt;code&gt;start
  = additive

additive
  = left:multiplicative "+" right:additive { return left + right; }
  / multiplicative

multiplicative
  = left:primary "*" right:multiplicative { return left * right; }
  / primary

primary
  = integer
  / "(" additive:additive ")" { return additive; }

integer "integer" 
  = digits:[0-9]+ { return parseInt(digits.join(""), 10); }
&lt;/code&gt;&lt;/pre&gt;&lt;p /&gt;&lt;p&gt;Peg.js используется для обработки SQL-подобных запросов в http://ql.io/ &lt;sup&gt;&lt;a href='#ftn.nid9' name='nid9'&gt;[9]&lt;/a&gt;&lt;/sup&gt;.
&lt;/p&gt;&lt;div class='footnote'&gt;&lt;p&gt;NOTES&lt;/p&gt;&lt;p&gt;&lt;a href='#nid1' name='ftn.nid1'&gt;&lt;sup&gt;1.&lt;/sup&gt;&lt;/a&gt; Грамматики в Java, Perl 6 и Perl 5. &lt;a href='http://zag.ru/2011/318/a1/grammatiki-v-Java-Perl-6-i-Perl-5.html'&gt;http://zag.ru/2011/318/a1/grammatiki-v-Java-Perl-6-i-Perl-5.html&lt;/a&gt;&lt;/p&gt;&lt;p&gt;&lt;a href='#nid2' name='ftn.nid2'&gt;&lt;sup&gt;2.&lt;/sup&gt;&lt;/a&gt;  О грамматиках в v5.10. &lt;a href='http://www.effectiveperlprogramming.com/blog/1479'&gt;http://www.effectiveperlprogramming.com/blog/1479&lt;/a&gt;&lt;/p&gt;&lt;p&gt;&lt;a href='#nid3' name='ftn.nid3'&gt;&lt;sup&gt;3.&lt;/sup&gt;&lt;/a&gt; Библиотека для синтаксического анализа Marpa. &lt;a href='http://www.jeffreykegler.com/marpa'&gt;http://www.jeffreykegler.com/marpa&lt;/a&gt;&lt;/p&gt;&lt;p&gt;&lt;a href='#nid4' name='ftn.nid4'&gt;&lt;sup&gt;4.&lt;/sup&gt;&lt;/a&gt; Marpa::XS is now 1.000000. &lt;a href='http://blogs.perl.org/users/jeffrey_kegler/2011/12/marpaxs-is-now-1000000.html'&gt;http://blogs.perl.org/users/jeffrey_kegler/2011/12/marpaxs-is-now-1000000.html&lt;/a&gt;&lt;/p&gt;&lt;p&gt;&lt;a href='#nid5' name='ftn.nid5'&gt;&lt;sup&gt;5.&lt;/sup&gt;&lt;/a&gt; Sample CSS Parser using Marpa::XS. &lt;a href='https://gist.github.com/1511584'&gt;https://gist.github.com/1511584&lt;/a&gt;&lt;/p&gt;&lt;p&gt;&lt;a href='#nid6' name='ftn.nid6'&gt;&lt;sup&gt;6.&lt;/sup&gt;&lt;/a&gt; How to Parse HTML. &lt;a href='http://blogs.perl.org/users/jeffrey_kegler/2011/11/how-to-parse-html.html'&gt;http://blogs.perl.org/users/jeffrey_kegler/2011/11/how-to-parse-html.html&lt;/a&gt;&lt;/p&gt;&lt;p&gt;&lt;a href='#nid7' name='ftn.nid7'&gt;&lt;sup&gt;7.&lt;/sup&gt;&lt;/a&gt;  Marpa-HTML.&lt;a href='http://search.cpan.org/dist/Marpa-HTML/'&gt;http://search.cpan.org/dist/Marpa-HTML/&lt;/a&gt;&lt;/p&gt;&lt;p&gt;&lt;a href='#nid8' name='ftn.nid8'&gt;&lt;sup&gt;8.&lt;/sup&gt;&lt;/a&gt; Parser Generator for JavaScript.&lt;a href='http://pegjs.majda.cz/'&gt;http://pegjs.majda.cz/&lt;/a&gt;&lt;/p&gt;&lt;p&gt;&lt;a href='#nid9' name='ftn.nid9'&gt;&lt;sup&gt;9.&lt;/sup&gt;&lt;/a&gt; Анонс инструментария для разработки mashup-приложений. &lt;a href='http://www.opennet.ru/opennews/art.shtml?num=32463'&gt;http://www.opennet.ru/opennews/art.shtml?num=32463&lt;/a&gt;&lt;/p&gt;&lt;/div&gt;&lt;/div&gt;</content><object-type xmlns="http://activitystrea.ms/spec/1.0/">http://activitystrea.ms/schema/1.0/article</object-type><link2 xmlns="http://activitystrea.ms/spec/1.0/" rel="alternate" href="http://zag.ru/2012/013/a1/grammatiki-dlja-Perl-5-i-JavaScript.html" title="Грамматики для Perl 5 и JavaScript" type="text/html" /><link rel="alternate" href="http://zag.ru/2012/013/a1/grammatiki-dlja-Perl-5-i-JavaScript.html" title="Грамматики для Perl 5 и JavaScript" type="text/html" /><published>2012-01-13T10:00:00Z</published><updated>2012-01-13T10:00:00Z</updated></entry><entry><title>Plosurin: Perl реализация Closure Templates</title><id>tag:zag.ru,2011:1.e3d90e4309f44c96bf84d00844a0dfe5</id><content type="html">&lt;div xmlns='http://www.w3.org/1999/xhtml'&gt;&lt;p /&gt;&lt;p&gt;Мой процесс избавления от Template::Toolkit &lt;sup&gt;&lt;a href='#ftn.nid1' name='nid1'&gt;[1]&lt;/a&gt;&lt;/sup&gt; и вообще шаблонизаторов в какой-то момент замедлился. Причиной тому стали ситуации, когда перенос представления на сторону клиента грозил появлением новых проблем.
&lt;/p&gt;&lt;p&gt;Вот пару типичных случаев:
&lt;/p&gt;&lt;ul&gt;&lt;li&gt;&lt;p&gt;статический текст из документации&lt;/p&gt;&lt;p&gt;Иногда, бывает очень удобно (&lt;em&gt;в первую очередь для пользователя!&lt;/em&gt;) в интерфейсе сайта привести выдержку из документации. Обычно это статический текст в несколько абзацев, но может быть и целая страница  с несколькими главами. Подобного рода данные, в случае, когда представление полностью перенесено на сторону клиента, помещаются в JavaScript библиотеки и затем загружаются браузером клиента. &lt;/p&gt;&lt;p&gt;Проблема здесь вполне очевидная: растет объем загружаемых данных. К тому же, не факт, что некоторые из них могут пригодится. Есть решения: это сжатие библиотек, использование отложенной загрузки требуемых частей (например, в GWT можно подгружать как код, так и ресурсы). Подобные рецепты приходится использовать, несмотря на привнесение некоторого усложнения разработки.
&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p&gt;форматирование потока данных&lt;/p&gt;&lt;p&gt;Зачастую, возникают задачи потоковой обработки данных. К примеру, нужно сформировать объемную страницу (&lt;em&gt;это может быть XML, HTML или тот же JSON&lt;/em&gt;) из потока данных, извлекаемых из базы. В этом случае проще формировать результирующий текст по мере извлечения записей. К тому же, браузер или устройство может обладать ограниченными возможностями, чтобы собрать страницу. Например, не хватит памяти в игровой приставке или телевизоре :-).
&lt;/p&gt;&lt;/li&gt;&lt;/ul&gt;&lt;p /&gt;&lt;p&gt;В client-side разработке я использую GWT и Google Closure, где тоже есть шаблоны. Я имею в виду Closure Templates, которые транслируются в программный код JavaScript и Java. 
&lt;/p&gt;&lt;p&gt;И если уж не получается полностью избавиться от шаблонов, то пусть хотя бы они будут едины как для серверной стороны, так и для  клиентской.
&lt;/p&gt;&lt;p&gt;Таким образом появилось желание реализовать Closure Templates &lt;sup&gt;&lt;a href='#ftn.nid2' name='nid2'&gt;[2]&lt;/a&gt;&lt;/sup&gt; для Perl. Транслятор Closure Templates реализован на Java и в Google работает небольшая команда &lt;em&gt;(буквально пара-тройка)&lt;/em&gt; разработчиков, которые не в состоянии регулярно поддерживать сторонние языки. Поэтому логично было реализовать эту систему целиком на Perl &lt;sup&gt;&lt;a href='#ftn.nid3' name='nid3'&gt;[3]&lt;/a&gt;&lt;/sup&gt;.
&lt;/p&gt;&lt;h2&gt;Plosurin - Perl реализация Closure Templates
&lt;/h2&gt;&lt;img src='http://zag.ru//2012/012/a1/plosurin-logo-175.png' class='image-block cnt' /&gt;&lt;p /&gt;&lt;p&gt;Perl реализаций на сегодня две:
&lt;/p&gt;&lt;dl&gt;&lt;dt&gt;&lt;strong&gt;Perl 6 &lt;sup&gt;&lt;a href='#ftn.nid4' name='nid4'&gt;[4]&lt;/a&gt;&lt;/sup&gt;&lt;/strong&gt;&lt;/dt&gt;&lt;dd&gt;
Благодаря шикарной встроенной поддержке синтаксического анализа я начал разработку с реализации 
на Perl 6. На данный момент есть вероятность, что изменения в предстоящем
релизе Rakudo  привнесут нестабильность для некоторых программ &lt;sup&gt;&lt;a href='#ftn.nid5' name='nid5'&gt;[5]&lt;/a&gt;&lt;/sup&gt;. По этой 
причине реализация на Perl 6 отложена.
&lt;/dd&gt;&lt;dt&gt;&lt;strong&gt;Perl 5 &lt;sup&gt;&lt;a href='#ftn.nid6' name='nid6'&gt;[6]&lt;/a&gt;&lt;/sup&gt;&lt;/strong&gt;&lt;/dt&gt;&lt;dd&gt;
Данная реализация, конечно, еще далека от совершенства, но минимально
необходимый функционал реализован. Plosurin понимает структуру файлов
с шаблонами, грамматику шаблонов и умеет обрабатывать переменные 
в математических выражениях. К тому же есть режим, когда Plosurin
превращается в web сервер и позволяет ускорить разработку шаблонов.

&lt;/dd&gt;&lt;/dl&gt;&lt;p /&gt;&lt;p&gt;Наиболее важным для меня результатом является &lt;strong&gt;снижение «энтропии» в разработке, благодаря появлению единой системы шаблонов для серверной и клиентской части&lt;/strong&gt;.
&lt;/p&gt;&lt;div class='footnote'&gt;&lt;p&gt;NOTES&lt;/p&gt;&lt;p&gt;&lt;a href='#nid1' name='ftn.nid1'&gt;&lt;sup&gt;1.&lt;/sup&gt;&lt;/a&gt; Perl 5 модули, которые я использую реже и реже. &lt;a href='http://zag.ru/b48j1'&gt;zag.ru/b48j1&lt;/a&gt;&lt;/p&gt;&lt;p&gt;&lt;a href='#nid2' name='ftn.nid2'&gt;&lt;sup&gt;2.&lt;/sup&gt;&lt;/a&gt; Closure Templates Documentation. &lt;a href='http://code.google.com/intl/ru-RU/closure/templates/docs/overview.html'&gt;http://code.google.com/intl/ru-RU/closure/templates/docs/overview.html&lt;/a&gt;&lt;/p&gt;&lt;p&gt;&lt;a href='#nid3' name='ftn.nid3'&gt;&lt;sup&gt;3.&lt;/sup&gt;&lt;/a&gt; Сайт проекта Plosurin. &lt;a href='http://plosur.in'&gt;plosur.in&lt;/a&gt;&lt;/p&gt;&lt;p&gt;&lt;a href='#nid4' name='ftn.nid4'&gt;&lt;sup&gt;4.&lt;/sup&gt;&lt;/a&gt;  Perl 6 реализация Closure Templates. &lt;a href='http://github.com/zag/plosurin'&gt;http://github.com/zag/plosurin&lt;/a&gt;&lt;/p&gt;&lt;p&gt;&lt;a href='#nid5' name='ftn.nid5'&gt;&lt;sup&gt;5.&lt;/sup&gt;&lt;/a&gt; ‘nom’ branch is now default, release status. &lt;a href='http://rakudo.org/2011/09/09/nom-branch-default/'&gt;rakudo.org/2011/09/09/nom-branch-default/&lt;/a&gt;&lt;/p&gt;&lt;p&gt;&lt;a href='#nid6' name='ftn.nid6'&gt;&lt;sup&gt;6.&lt;/sup&gt;&lt;/a&gt;  Perl 5 реализация Closure Templates. &lt;a href='http://github.com/zag/p5-plosurin'&gt;http://github.com/zag/p5-plosurin&lt;/a&gt;&lt;/p&gt;&lt;/div&gt;&lt;/div&gt;</content><object-type xmlns="http://activitystrea.ms/spec/1.0/">http://activitystrea.ms/schema/1.0/article</object-type><link2 xmlns="http://activitystrea.ms/spec/1.0/" rel="alternate" href="http://zag.ru/2012/012/a1/Plosurin-Perl-realizacija-Closure-Templates.html" title="Plosurin: Perl реализация Closure Templates" type="text/html" /><link rel="alternate" href="http://zag.ru/2012/012/a1/Plosurin-Perl-realizacija-Closure-Templates.html" title="Plosurin: Perl реализация Closure Templates" type="text/html" /><published>2012-01-12T10:00:00Z</published><updated>2012-01-12T10:00:00Z</updated></entry><entry><title>Реализация приоритетности операторов с помощью грамматик Perl 5</title><id>tag:zag.ru,2011:1.28b4f5f8e857453491ca7d394f43ce1a</id><content type="html">&lt;div xmlns='http://www.w3.org/1999/xhtml'&gt;&lt;p /&gt;&lt;p&gt;С таблицей приоритетности сталкиваются дизайнеры языков программирования на этапе проектирования, а так же те, кто затем изучает эти языки. 
Наиболее оптимальным способом реализовать приоритетность - совместить данный этап с построением синтаксического дерева. 
&lt;/p&gt;&lt;h2&gt;Таблица приоритетности операторов
&lt;/h2&gt;&lt;p&gt;Приоритетность в математических ( и в любых других ) выражениях - вещь очень привычная. Для простого выражения:
&lt;/p&gt;&lt;pre&gt;&lt;code&gt;    3 + 5 * 6 
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;сначала будет выполнена операция умножения, а затем - сложения. Синтаксическое дерево можно представить в следующем виде :
&lt;/p&gt;&lt;pre&gt;&lt;code&gt;    +( *(5,6), 3 )
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Возьмем пример с группирующими скобками. С их помощью можно влиять на порядок вычислений:
&lt;/p&gt;&lt;pre&gt;&lt;code&gt;    ( 3 + 5 ) * 6 
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Синтаксическое дерево будет выглядеть иначе:
&lt;/p&gt;&lt;pre&gt;&lt;code&gt;    *( +(3,5), 6 )
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Как видим группирующие скобки вносят корректировку в последовательность вычислений.
&lt;/p&gt;&lt;p&gt;И еще один пример выражения:
&lt;/p&gt;&lt;pre&gt;&lt;code&gt;    - (2 * -3)
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;в котором используется унарный оператор &lt;strong&gt;-&lt;/strong&gt; (минус) перед группирующей скобкой. Для него дерево будет следующее:
&lt;/p&gt;&lt;pre&gt;&lt;code&gt;  -( *(2,-3) )
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Унарный &lt;code&gt;-&lt;/code&gt; имеет более высокий приоритет по сравнению с &lt;code&gt;*&lt;/code&gt;.
&lt;/p&gt;&lt;p&gt;Исходя из приведенных примеров можно составить таблицу приоритетов (&lt;em&gt;3 - высший приоритет&lt;/em&gt;):
&lt;/p&gt;&lt;table&gt;&lt;caption&gt;Таблица приоритетов&lt;/caption&gt;&lt;tr&gt;&lt;th&gt;приоритет&lt;/th&gt;&lt;th&gt;оператор&lt;/th&gt;&lt;th&gt;описание, действие&lt;/th&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;1&lt;/td&gt;&lt;td&gt;+, -&lt;/td&gt;&lt;td&gt;сложение, вычитание&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;2&lt;/td&gt;&lt;td&gt;*, /&lt;/td&gt;&lt;td&gt;операторы умножения, деления&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;3&lt;/td&gt;&lt;td&gt;unary -&lt;/td&gt;&lt;td&gt;унарный минус&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&lt;p /&gt;&lt;p&gt;Грамматика, реализующая приоритетность, выглядит так:
&lt;/p&gt;&lt;pre&gt;&lt;code&gt; my $q = qr{
     &amp;lt;expr&amp;gt;
    &amp;lt;rule: expr&amp;gt;
                # бинарные операции +-
                &amp;lt;a=mult&amp;gt; &amp;lt;op=([+-])&amp;gt; &amp;lt;b=expr&amp;gt; 
                | &amp;lt;MATCH=mult&amp;gt; 

    &amp;lt;rule: mult&amp;gt; 
                &amp;lt;a=term&amp;gt; &amp;lt;op=([*/])&amp;gt; &amp;lt;b=mult&amp;gt; 
                | &amp;lt;MATCH=term&amp;gt;

     &amp;lt;rule: term&amp;gt; 
              &amp;lt;MATCH=Digit&amp;gt; 
            | &amp;lt;Sign=([+-])&amp;gt; \( &amp;lt;expr&amp;gt;\) &lt;strong&gt;# unary-&lt;/strong&gt;
            | \( &amp;lt;MATCH=expr&amp;gt; \)   &lt;strong&gt;# группирующие скобки&lt;/strong&gt;

    &lt;strong&gt;#токен, описывающий допустимый числовой агрумент&lt;/strong&gt;
    &amp;lt;token: Digit&amp;gt;
            [+-]? \d++ (?: \. \d++ )?+ 
    }xms;

&lt;/code&gt;&lt;/pre&gt;&lt;p /&gt;&lt;p&gt;Как видим поиск совпадений начинается с поиска наиболее приоритетного унарного минуса и учета группирующих скобок (токен &lt;em&gt;term&lt;/em&gt;), затем - операции &lt;code&gt;*&lt;/code&gt; и &lt;code&gt;/&lt;/code&gt; (правило &lt;em&gt;mult&lt;/em&gt;) и т.д. 
&lt;/p&gt;&lt;h2&gt;Представление синтаксичеcкого дерева в памяти
&lt;/h2&gt;&lt;p&gt;Результат успешной работы грамматик (структура совпадений правил) сохраняется в переменной &lt;code&gt;%/&lt;/code&gt;. Отобразить результат можно следующим кодом:
&lt;/p&gt;&lt;pre&gt;&lt;code&gt;    use Data::Dumper;
    my $t = q! 3 + 5 * 6 !;
    if ($t =~ $q) {
        print Dumper \%/;
    } else {
     warn "Error parse"
    }
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Так, для исходного примера &lt;code&gt; 3 + 5 * 6&lt;/code&gt;, результат применения грамматик будет выглядеть следующим образом:
&lt;/p&gt;&lt;pre&gt;&lt;code&gt;
      # 3 + 5 * 6 
      {
          'a' =&amp;gt; '3', # первый аргумент - &lt;strong&gt;число&lt;/strong&gt;
          # второй аргумент - &lt;strong&gt;выражение&lt;/strong&gt;
          'b' =&amp;gt; {    
                   'a' =&amp;gt; '5',
                   'b' =&amp;gt; '6',
                   'op' =&amp;gt; '*'
                 },
          &lt;strong&gt;'op'&lt;/strong&gt; =&amp;gt; '+' # &lt;strong&gt;оператор&lt;/strong&gt;
       };
&lt;/code&gt;&lt;/pre&gt;&lt;p /&gt;&lt;p&gt;Для выражения с унарным минусом:
&lt;/p&gt;&lt;pre&gt;&lt;code&gt;     #- (2 * -3)
     {
     'expr' =&amp;gt; {
                  'a' =&amp;gt; '2',
                  'b' =&amp;gt; '-3',
                  'op' =&amp;gt; '*'
                },
     &lt;strong&gt;'Sign'&lt;/strong&gt; =&amp;gt; '-' 
     }
&lt;/code&gt;&lt;/pre&gt;&lt;p /&gt;&lt;p&gt;Чтобы полученные структуры можно было использовать как элементы синтаксического дерева, требуется ассоциировать с каждым правилом класс. Для этого достаточно заменить &lt;code&gt;rule&lt;/code&gt; на &lt;code&gt;objrule&lt;/code&gt; с указанием класса:
&lt;/p&gt;&lt;pre&gt;&lt;code&gt;    &amp;lt;&lt;strong&gt;objrule: ExpClass::mult&lt;/strong&gt;&amp;gt;  # объект оператора
                &amp;lt;a=term&amp;gt; &amp;lt;op=([*/])&amp;gt; &amp;lt;b=mult&amp;gt; 
                | &amp;lt;MATCH=term&amp;gt;
&lt;/code&gt;&lt;/pre&gt;&lt;p /&gt;&lt;p&gt;В результате мы получаем структуру объектов, построенную в соответствии с приоритетностью, определенной на уровне грамматик.
&lt;/p&gt;&lt;/div&gt;</content><object-type xmlns="http://activitystrea.ms/spec/1.0/">http://activitystrea.ms/schema/1.0/article</object-type><link2 xmlns="http://activitystrea.ms/spec/1.0/" rel="alternate" href="http://zag.ru/2011/346/a1/realizacija-prioritetnosti-operatorov-s-pomoshhju-grammatik-Perl-5.html" title="Реализация приоритетности операторов с помощью грамматик Perl 5" type="text/html" /><link rel="alternate" href="http://zag.ru/2011/346/a1/realizacija-prioritetnosti-operatorov-s-pomoshhju-grammatik-Perl-5.html" title="Реализация приоритетности операторов с помощью грамматик Perl 5" type="text/html" /><published>2011-12-12T10:00:00Z</published><updated>2011-12-12T10:00:00Z</updated></entry><entry><title>Синтаксический анализ XML</title><id>tag:zag.ru,2011:1.f545ef5d2dc54b808e1fabda00d0c106</id><content type="html">&lt;div xmlns='http://www.w3.org/1999/xhtml'&gt;&lt;p /&gt;&lt;p&gt;Скорее всего можно было бы написать другую тему для этой статьи. Например: "когда можно применять грамматики, а когда нет" или "не всегда грамматики подходят", или вот такую модную "эти грамматики - они не всегда серебрянные". Но речь пойдет о обработке XML, в том числе с помощью грамматик  Perl 5.
&lt;/p&gt;&lt;p&gt;Задачей процесса синтаксического анализа текста почти всегда является построение дерева объектов. Каждый из объектов ассоциируется с той или иной сущностью обрабатываемого текста. Например, если производится обработка текста языка программирования, то объектами в итоге становятся операторы, подпрограммы, циклы или арифметические операторы. Поэтому, какие бы не взяли инструменты синтаксического анализа, в каждом присутствует механизм построения деревьев.
&lt;/p&gt;&lt;p&gt;У меня возникла ситуация, когда грамматики оказались не самым оптимальным с точки зрения &lt;em&gt;простоты&lt;/em&gt; решением. Конечно же важную роль играют исходные условия, а они такие: необходим синтаксический анализ XML. Ниже приведу пример такого XML:
&lt;/p&gt;&lt;pre&gt;&lt;code&gt;    &amp;lt;wd&amp;gt;
      &amp;lt;object class="isauth" id="auth_switch"&amp;gt;
       &amp;lt;auth&amp;gt; 
        &amp;lt;object class="comp_unauth" id="ExitCP"/&amp;gt;
      &amp;lt;/auth&amp;gt;
    &amp;lt;/object&amp;gt;
    &amp;lt;/wd&amp;gt;
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Тэг &lt;code&gt;wd&lt;/code&gt; является корневым, а его содержимое должно в итоге отобразиться в виде некой структуры в памяти:
&lt;/p&gt;&lt;pre&gt;&lt;code&gt;    &amp;lt;object class="isauth" id="auth_switch" &amp;gt;
        └── auth
            └──&amp;lt;object class="comp_unauth" id="ExitCP"&amp;gt;
&lt;/code&gt;&lt;/pre&gt;&lt;h2&gt;Решение с помощью грамматик Perl 5
&lt;/h2&gt;&lt;p&gt;Итоговое решение с помощью грамматик Perl 5 получилось следующее:
&lt;/p&gt;&lt;pre&gt;&lt;code&gt;
    use Regexp::Grammars;
    my $q = qr{
    \A &amp;lt;File&amp;gt; \Z
    
    # Описание блока целиком
    # &amp;lt;wd&amp;gt;...&amp;lt;/wd&amp;gt;
    &amp;lt;rule: File&amp;gt;&amp;lt;start_block&amp;gt; &amp;lt;[childs]&amp;gt;+ &amp;lt;end_block&amp;gt;
    &amp;lt;rule: start_block&amp;gt;\&amp;lt;wd&amp;gt;
    &amp;lt;rule: end_block&amp;gt;\&amp;lt;\/wd&amp;gt;
    
    #Допустимые тэги
    &amp;lt;token: childs&amp;gt;           
                     &amp;lt;MATCH=object&amp;gt; |
                     &amp;lt;MATCH=any_tag&amp;gt; 
    
    &lt;strong&gt;#objrule - создает объект указанного класса&lt;/strong&gt;
    &amp;lt;&lt;strong&gt;objrule&lt;/strong&gt;: WebDAO::Lexer::object&amp;gt; &amp;lt;tag( tagname=&amp;gt;'object' )&amp;gt;
    &amp;lt;objrule: WebDAO::Lexer::any_tag&amp;gt; &amp;lt;tag&amp;gt;
    
    &amp;lt;rule: attribute&amp;gt; &amp;lt;name=([_\w]+)&amp;gt;=['"]&amp;lt;value=(?: ([^'"]+) )&amp;gt;['"]
    
    #argument :tagname
    &amp;lt;rule: tag&amp;gt;
        &amp;lt;matchpos&amp;gt;
        &amp;lt;matchline&amp;gt;
        (?{  
            $ARG{'tagname'} = 
                defined ($ARG{'tagname'}) 
                    ? quotemeta $ARG{'tagname'}
                    : '(\w+)';
            # setup defaults
                $MATCH{childs} //=[];
                $MATCH{attribute} //=[];
         })
        (?:         
         &amp;lt; &amp;lt;tagname=:tagname&amp;gt; 
               &amp;lt;[attribute]&amp;gt;* /&amp;gt;
        )
        |
        (?:
        &amp;lt; &amp;lt;tagname=:tagname&amp;gt; &amp;lt;[attribute]&amp;gt;* &amp;gt;
                    &amp;lt;[childs]&amp;gt;*
           &amp;lt;/ &amp;lt;:tagname&amp;gt; &amp;gt;
        )
  }xms;

&lt;/code&gt;&lt;/pre&gt;&lt;p /&gt;&lt;p&gt;Для описания отдельно взятого тэга в примере используется правило &lt;code&gt;rule:tag&lt;/code&gt;. Грамматики Perl 5 предоставляют возможность передачи параметров для правил. Эта особенность позволяет точно описать допустимые тэги:
&lt;/p&gt;&lt;pre&gt;&lt;code&gt;
    #Допустимые тэги
    &amp;lt;token: childs&amp;gt;           
                     &amp;lt;MATCH=object&amp;gt; |
                     &amp;lt;MATCH=any_tag&amp;gt; 
    # правило для тэга 'object' 
    &amp;lt;objrule: WebDAO::Lexer::object&amp;gt; &amp;lt;tag( &lt;strong&gt;tagname&lt;/strong&gt;=&amp;gt;&lt;strong&gt;'object'&lt;/strong&gt; )&amp;gt;&amp;gt;
    #если параметр &lt;em&gt;tagname&lt;/em&gt; не указан, то допускается любой тэг
    &amp;lt;objrule: WebDAO::Lexer::any_tag&amp;gt; &amp;lt;tag&amp;gt;

&lt;/code&gt;&lt;/pre&gt;&lt;p /&gt;&lt;p&gt;Параметр &lt;em&gt;tagname&lt;/em&gt; используется в описании тэга XML для двух допустимых форм:
&lt;/p&gt;&lt;pre&gt;&lt;code&gt;        (?:
         # пустой тэг
         &amp;lt; &amp;lt;tagname=&lt;strong&gt;:tagname&lt;/strong&gt;&amp;gt;  &amp;lt;[attribute]&amp;gt;* /&amp;gt;
        )
        |
        (?:
        &amp;lt; &amp;lt;tagname=&lt;strong&gt;:tagname&lt;/strong&gt;&amp;gt; &amp;lt;[attribute]&amp;gt;* &amp;gt;
            # допускаются вложенные тэги
                    &amp;lt;[childs]&amp;gt;*
           &amp;lt;/ &amp;lt;&lt;strong&gt;:tagname&lt;/strong&gt;&amp;gt; &amp;gt;
        )
&lt;/code&gt;&lt;/pre&gt;&lt;p /&gt;&lt;p&gt;В случае, если правило совпадает, то создается объект указанного класса:
&lt;/p&gt;&lt;pre&gt;&lt;code&gt;    &amp;lt;objrule: &lt;strong&gt;WebDAO::Lexer::object&lt;/strong&gt;&amp;gt; &amp;lt;tag( tagname=&amp;gt;'object' )&amp;gt;
    &amp;lt;objrule: &lt;strong&gt;WebDAO::Lexer::any_tag&lt;/strong&gt;&amp;gt; &amp;lt;tag&amp;gt;
&lt;/code&gt;&lt;/pre&gt;&lt;p /&gt;&lt;p&gt;Итоговое дерево доступно после применения грамматики к исходному тексту:
&lt;/p&gt;&lt;pre&gt;&lt;code&gt;    if ( $txt =~ $q ) {
        #результат в переменной %/ 
        return {%/}-&amp;gt;{File}-&amp;gt;{childs};
    }
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Наличие параметров для правил позволяет сократить количество кода и делает
грамматики отдельным языком программирования.
&lt;/p&gt;&lt;h2&gt;Решение с помощью XML::Flow
&lt;/h2&gt;&lt;p&gt;Так как целью является синтаксическое дерево и простота решения, то 
здесь пригодилась библиотека XML::FLow для работы с XML &lt;sup&gt;&lt;a href='#ftn.nid1' name='nid1'&gt;[1]&lt;/a&gt;&lt;/sup&gt;:
&lt;/p&gt;&lt;pre&gt;&lt;code&gt; sub parse {
    my $self     = shift;
    my $txt      = shift || return [];

    #Соответствие тэгов классам
    my %classmap = (
        object    =&amp;gt; 'WebDAO::Lexer::object',
        default   =&amp;gt; 'WebDAO::Lexer::any_tag',
    );
    our $result = [];
    
    # обработчики тэгов
    my %tags = (
        # &lt;strong&gt;корневой тэг&lt;/strong&gt;
        wd =&amp;gt; sub { shift; $result = \@_ },
        # * обработчик для любого тэга XML
        '*' =&amp;gt; sub {
            my $name   = shift;
            my $a      = shift;
            my $childs = \@_;
            my $class  = $classmap{$name} || $classmap{'default'};
            #&lt;strong&gt;создаем экземпляр класса&lt;/strong&gt;
            my $o = $class-&amp;gt;new(
                name   =&amp;gt; $name,
                attr   =&amp;gt; $a,
                childs =&amp;gt; $childs
            );
            #&lt;strong&gt;и возвращаем его как результат обработчика&lt;/strong&gt;
            return $o;
        }
    );
    my $rd = new XML::Flow:: \$txt;
    $rd-&amp;gt;read( \%tags );
    $result;
 }

&lt;/code&gt;&lt;/pre&gt;&lt;p /&gt;&lt;p&gt;Несмотря на то, что основное предназначение библиотеки - это серилизация структур данных в XML, есть и дополнительная возможность - синтаксическая обработка XML в потоковом режиме.
&lt;/p&gt;&lt;p&gt;Принцип работы следующий: встретив закрывающий тэг XML, вызывается обработчик, которому в качестве параметров передаются атрибуты тэга и результаты обработчиков вложенных в него тэгов.
&lt;/p&gt;&lt;p&gt;Например, для следующего XML:
&lt;/p&gt;&lt;pre&gt;&lt;code&gt;    &amp;lt;wd&amp;gt;
          &amp;lt;object&amp;gt;
                 &amp;lt;auth /&amp;gt;
          &amp;lt;/object&amp;gt;
    &amp;lt;/wd&amp;gt;
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Схема вызовов будет следующей:
&lt;/p&gt;&lt;pre&gt;&lt;code&gt;   call_wd (
        call_object ( 
               call_auth()
         )
    )
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Как видно результаты вызовов вложенный тэгов будут в конечном итоге переданы
в обработчик корневого тэга и ему останется только сохранить их в переменной:
&lt;/p&gt;&lt;pre&gt;&lt;code&gt;        # корневой тэг
        wd =&amp;gt; sub { shift; $result = \@_ },
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;А так как обработчики тэгов возвращают созданные объекты, то в переменную &lt;code&gt;$result&lt;/code&gt; сохранится уже готовое дерево.
&lt;/p&gt;&lt;h2&gt;Итоги обоих решений
&lt;/h2&gt;&lt;p&gt;Решение с помощью &lt;code&gt;XML::Flow&lt;/code&gt; получилось простым главным образом из-за наличия уже готовой библиотеки для работы с XML. Но это не уменьшает значимость грамматик в Perl 5 и вообще средств синтаксического анализа.
&lt;/p&gt;&lt;p&gt;&lt;strong&gt;Если учесть прекращение развития XHTML и вообще общую тенденцию ухода от XML, то будущее однозначно за грамматиками !&lt;/strong&gt;
&lt;/p&gt;&lt;div class='footnote'&gt;&lt;p&gt;NOTES&lt;/p&gt;&lt;p&gt;&lt;a href='#nid1' name='ftn.nid1'&gt;&lt;sup&gt;1.&lt;/sup&gt;&lt;/a&gt;  Библиотека XML::Flow. &lt;a href='http://search.cpan.org/perldoc?XML::Flow'&gt;http://search.cpan.org/perldoc?XML::Flow&lt;/a&gt;&lt;/p&gt;&lt;/div&gt;&lt;/div&gt;</content><object-type xmlns="http://activitystrea.ms/spec/1.0/">http://activitystrea.ms/schema/1.0/article</object-type><link2 xmlns="http://activitystrea.ms/spec/1.0/" rel="alternate" href="http://zag.ru/2011/336/a1/sintaksicheskij-analiz-XML.html" title="Синтаксический анализ XML" type="text/html" /><link rel="alternate" href="http://zag.ru/2011/336/a1/sintaksicheskij-analiz-XML.html" title="Синтаксический анализ XML" type="text/html" /><published>2011-12-02T10:00:00Z</published><updated>2011-12-02T10:00:00Z</updated></entry></feed>

