Инструменты пользователя

Инструменты сайта


wiki:devel:parser

Различия

Показаны различия между двумя версиями страницы.

Ссылка на это сравнение

Предыдущая версия справа и слеваПредыдущая версия
Следующая версия
Предыдущая версия
wiki:devel:parser [2025/01/16 13:11] vladpolskiywiki:devel:parser [2025/01/17 13:53] (текущий) – [Преобразователь] vladpolskiy
Строка 46: Строка 46:
 ==== Лексический анализатор ==== ==== Лексический анализатор ====
  
-Определяется в [[xref>inc:parsing:lexer:lexer.php|inc/Parsing/Lexer.php]]+Определяется в [[xref>inc:parsing:lexer:lexer.php|inc/Parsing/Lexer/Lexer.php]]
  
-В самом общем смысле, он реализует инструмент для управления комплексными регулярными выражениями, где важным является состояние. Анализатор появился из [[http://www.lastcraft.com/simple_test.php|простого теста]], но содержит три модификации (читай: хака ;-)):+В самом общем смысле, он реализует инструмент для управления комплексными регулярными выражениями, где важным является состояние. Анализатор появился из [[https://simpletest.sourceforge.net/en/start-testing.html|Simple Test ]], но содержит три модификации (читай: "хака"):
  
-  * поддержка шаблонов с просмотром вперёд и назад((Прим. переводчика: возможно, речь идёт т. н. **незахватывающем поиске**, подробнее см. литературу по регулярным выражениям, например, Джеффри Фридла «Регулярные выражения: библиотека программиста. Второе издание.» --- СПб.: Питер, 2003, или документацию по PHP --- [[http://ru.php.net/manual/en/ref.pcre.php|ru.php.net/manual/en/ref.pcre.php]].));+  * поддержка шаблонов просмотра назад и просмотра вперед((Прим. переводчика: возможно, речь идёт о т.н. **незахватывающем поиске**, подробнее см. литературу по регулярным выражениям, например, Джеффри Фридла «Регулярные выражения: библиотека программиста. Второе издание.» --- СПб.: Питер, 2003, или документацию по PHP --- [[http://ru.php.net/manual/en/ref.pcre.php|ru.php.net/manual/en/ref.pcre.php]].));
   * поддержка изменения модификаторов шаблона в пределах шаблона;   * поддержка изменения модификаторов шаблона в пределах шаблона;
-  * уведомление обработчика об индексе стартового байта в исходном тексте, когда найдено вхождение.+  * уведомление обработчика о начальном индексе байта в необработанном тексте, где был сопоставлен токен.
  
-Анализатор как целое состоит из трёх основных классов;+Короче говоря, лексер Simple Test действует как инструмент, упрощающий управление регулярными выражениями — вместо гигантских регулярных выражений вы пишете много маленьких/простых. Лексер заботится об их эффективном объединении, а затем предоставляет вам API обратного вызова в стиле SAX , чтобы вы могли писать код для ответа на соответствующие «события».
  
-  ''Doku_LexerParallelRegex'': позволяет регулярному выражению состоять из множества отдельных шаблонов, каждый шаблон связан с идентифицирующей «меткой» , класс объединяет их в единое регулярное выражение, используя подшаблоны. //Используя анализатор, вам не нужно беспокоится об этом классе//. +В целом Lexer состоит из трех основных классов; 
-  * ''Doku_LexerStateStack'': реализует простой конечный автомат (state mashine((FIXME Уточнить перевод термина.))), так что анализ может быть «осведомлённым о контексте». //Используя анализатор, вам не нужно беспокоится об этом классе//. + 
-  * ''Doku_Lexer'': реализует точку доступа для клиентского кода, использующего анализатор. Управляет множеством объектов ParallelRegex, используя StateStack (стэк состояний) для применения корректных объектов ParallelRegexв зависимости от «контекста». При нахождении «интересного текста» он вызывает функции реализуемого пользователем объекта (обработчика).+  [[xref>inc:parsing:lexer:parallelregex.php|inc/Parsing/Lexer/ParallelRegex]]: позволяет строить регулярные выражения из нескольких отдельных шаблонов, каждый шаблон связан с идентифицирующей «меткой», класс объединяет их в одно регулярное выражение с помощью подшаблонов. //При использовании Lexer вам не нужно беспокоиться об этом классе.// 
 +  * [[xref>inc:parsing:lexer:statestack.php|inc/Parsing/Lexer/StateStack]]: предоставляет простой конечный автоматчтобы лексирование могло быть «контекстно-зависимым». //При использовании Lexer вам не нужно беспокоиться об этом классе.// 
 +  * [[xref>inc:parsing:lexer:lexer.php|inc/Parsing/Lexer/Lexer]]: предоставляет точку доступа для клиентского кода с помощью Lexer. Управляет несколькими экземплярами ParallelRegex, используя StateStack для применения правильного экземпляра ParallelRegex в зависимости от «контекста». При обнаружении «интересного текста» вызывает функции для предоставленного пользователем объекта (Handler).
  
 === Необходимость в состояниях === === Необходимость в состояниях ===
Строка 72: Строка 74:
 === API анализатора === === API анализатора ===
  
-Краткое введение в лексический анализатор можно найти в [[http://www.phppatterns.com/index.php/article/articleview/106/1/2/|Simple Test Lexer Notes]]. Здесь предлагается более подробное описание.+Краткое введение в лексический анализатор можно найти в [[wiki:devel:parser:test:simple_test_lexer_notes|Simple Test Lexer Notes]]. Здесь предлагается более подробное описание.
  
 Ключевыми методами анализатора являются: Ключевыми методами анализатора являются:
Строка 78: Строка 80:
 == Конструктор == == Конструктор ==
  
-Принимает ссылку на обработчикнаименование начального режима и (необязательно) логический флаг чувствительности сравнения шаблона к регистру.+Принимает ссылку на объект Handler, имя начального режима, в котором должен запускаться Lexer, и (необязательно) логический флагуказывающий, должно ли сопоставление с образцом учитывать регистр.
  
 Пример: Пример:
  
 <code php> <code php>
-$Handler new MyHandler(); +$handler   new MyHandler ( ) ;  
-$Lexer new Doku_Lexer($Handler, 'base', TRUE);+$lexer   new dokuwiki\Lexer\Lexer ( $handler  'base' true ) ;
 </code> </code>
  
Строка 91: Строка 93:
 == addEntryPattern / addExitPattern == == addEntryPattern / addExitPattern ==
  
-Используется, чтобы зарегистрировать шаблон при входе и выходе из особенного режима обработки. Например:+''%%addEntryPattern()%%'' в [[xref>inc:parsing:lexer:lexer.php|Lexer.php]] 
 +<code php Lexer.php [enable_line_numbers="true", start_line_numbers_at="75"]> 
 +    public function addEntryPattern($pattern, $mode, $new_mode) 
 +    { 
 +        if (! isset($this->regexes[$mode])) { 
 +            $this->regexes[$mode] = new ParallelRegex($this->case); 
 +        } 
 +        $this->regexes[$mode]->addPattern($pattern, $new_mode); 
 +    } 
 +</code>
  
-<code php> +''%%addExitPattern()%%'' в [[xref>inc:parsing:lexer:lexer.php|Lexer.php]] 
-// arg0регулярное выражение для сравнения — заметьте, что нет необходимости добавлять ограничители шаблона +<code php Lexer.php [enable_line_numbers="true", start_line_numbers_at="89"]
-// arg1: наименование режима, где этот шаблон может быть использован +    public function addExitPattern($pattern, $mode) 
-// arg2: наимерование режима, в который следует войти +    { 
-$Lexer->addEntryPattern('<file>','base','file');+        if (! isset($this->regexes[$mode])) { 
 +            $this->regexes[$mode] = new ParallelRegex($this->case); 
 +        } 
 +        $this->regexes[$mode]->addPattern($pattern, "__exit"); 
 +    } 
 +</code> 
 +[[xref>inc:parsing:lexer:lexer.php|addEntryPattern()]] и [[xref>inc:parsing:lexer:lexer.php|addExitPattern()]] используются для регистрации шаблона для входа и выхода из определенного режима анализа. Например;
  
-// arg0: регулярное выражение для сравнения +<code php> 
-// arg1: наименование режима, из которого следует выйти +// arg0: регулярное выражение для сопоставления — обратите внимание, что нет необходимости добавлять разделители начального/конечного шаблона  
-$Lexer->addExitPattern('</file>','file');+// arg1: имя режима, в котором может использоваться этот шаблон записи  
 +// arg2: имя режима для ввода  
 +$lexer -> addEntryPattern ( '<file>' , 'base' , 'file' ) ; 
 +  
 +// arg0: регулярное выражение для сопоставления  
 +// arg1: имя режима для выхода  
 +$lexer -> addExitPattern ( '</file>' , 'file' ) ;
 </code> </code>
  
 Код, приведённый выше, позволяет тэгу %%<file/>%% быть использованный при входе из базового в новый режим (''file''). Если в дальнейшем следует применить режимы, пока анализатор находится в режиме ''file'', они должны быть зарегистрированы с режимом ''file''. Код, приведённый выше, позволяет тэгу %%<file/>%% быть использованный при входе из базового в новый режим (''file''). Если в дальнейшем следует применить режимы, пока анализатор находится в режиме ''file'', они должны быть зарегистрированы с режимом ''file''.
  
-**Замечание:** в паттернах не требуется использование ограничителей.+**Замечание:** в паттернах не требуется использование ограничителей (разделителей начала и конца шаблона).
  
 == addPattern == == addPattern ==
  
-Используется, чтобы реагировать на дополнительные «вхождения» внутри существующего режима (без переходов). Он принимает паттерн и наименование режима, внутри которого должен использоваться.+''%%addEntryPattern()%%'' в [[xref>inc:parsing:lexer:lexer.php|Lexer.php]] 
 +<code php Lexer.php [enable_line_numbers="true", start_line_numbers_at="57"]> 
 +    public function addPattern($pattern, $mode = "accept"
 +    { 
 +        if (! isset($this->regexes[$mode])) { 
 +            $this->regexes[$mode] = new ParallelRegex($this->case); 
 +        } 
 +        $this->regexes[$mode]->addPattern($pattern); 
 +    } 
 +</code> 
 + 
 +''%%addEntryPattern()%%'' в [[xref>inc:parsing:lexer:parallelregex.php|ParallelRegex.php]] 
 +<code php ParallelRegex.php [enable_line_numbers="true", start_line_numbers_at="53"]> 
 +    public function addPattern($pattern, $label = true) 
 +    { 
 +        $count = count($this->patterns); 
 +        $this->patterns[$count] = $pattern; 
 +        $this->labels[$count] = $label; 
 +        $this->regex = null; 
 +    } 
 +</code> 
 + 
 +[[xref>inc:parsing:lexer:lexer.php|addEntryPattern()]] используется, чтобы реагировать на дополнительные «вхождения» внутри существующего режима (без переходов). Он принимает паттерн и наименование режима, внутри которого должен использоваться.
  
 Это наиболее наглядно видно из разбора парсером синтаксиса списков. Синтаксис списков выглядит в «Докувики» следующим образом; Это наиболее наглядно видно из разбора парсером синтаксиса списков. Синтаксис списков выглядит в «Докувики» следующим образом;
Строка 122: Строка 167:
 </code> </code>
  
-Использование ''%%addPattern%%'' делает возможным сравнивать полный список, одновременно корректно захватывая каждый элемент списка;+Использование ''%%addPattern()%%'' делает возможным сравнивать полный список, одновременно корректно захватывая каждый элемент списка;
  
 <code php> <code php>
-// Сравнить начальный элемент списка и изменить режим +// Сопоставляем открывающий элемент списка и меняем режим  
-$Lexer->addEntryPattern('\n {2,}[\*]','base','list');+$lexer -> addEntryPattern ( '\n {2,}[\*]' , 'base' , 'list' ) ; 
 +  
 +// Сопоставить новые элементы списка, но остаться в режиме списка  
 +$lexer -> addPattern ( '\n {2,}[\*]' , 'list' ) ; 
 +  
 +// Если это перевод строки, который не соответствует указанному выше правилу addPattern, выходим из режима  
 +$lexer -> addExitPattern ( '\n' , 'list' ) ; 
 +</code>
  
-// Сравнить новый элемент списка, но остаться в режиме ''list'' +== addSpecialPattern ==
-$Lexer->addPattern('\n {2,}[\*]','list');+
  
-// Если строка не совпадает с указанным выше правилом addPatternвыйти из режима +''%%addSpecialPattern()%%'' в [[xref>inc:parsing:lexer:lexer.php|Lexer.php]] 
-$Lexer->addExitPattern('\n','list');+<code php Lexer.php [enable_line_numbers="true"start_line_numbers_at="107"]> 
 +    public function addSpecialPattern($pattern, $mode, $special) 
 +    { 
 +        if (! isset($this->regexes[$mode])) { 
 +            $this->regexes[$mode] = new ParallelRegex($this->case); 
 +        } 
 +        $this->regexes[$mode]->addPattern($pattern"_$special"); 
 +    }
 </code> </code>
  
-== addSpecialPattern == +[[xref>inc:parsing:lexer:lexer.php|addSpecialPattern()]] используется для входа в новый режим только для совпадения, а затем сразу возвращается в «родительский» режим. Принимает шаблон, имя режима, в котором он может быть применен, и имя «временного» режима для входа для совпадения. Обычно это используется, если вы хотите заменить разметку wiki чем-то другим. Например, чтобы сопоставить смайлик, например %%:-)%%, у вас может быть:
- +
-Используется для входа в новый режим только для сравнения, затем возвращается в «родительский» режим. Принимает в качестве аргументов паттерн, наименование режима, внутри которого его (паттернможно применять, и наименование «временного режима", в который нужно войти для сравнения. Обычно может быть использовано, если вы хотите заменить разметку вики на что-нибудь другое. Например, сравнить смайл вроде %%:-)%%;+
  
 <code php> <code php>
-$Lexer->addSpecialPattern(':-)','base','smiley');+$lexer -> addSpecialPattern ( ':-)' , 'base' , 'smiley' ) ;
 </code> </code>
  
 == mapHandler == == mapHandler ==
  
-Позволяет особому режиму быть прикреплённым к методу с разными наименованиями в обработчикеЭто может быть полезнымкогда различные синтаксические конструкции следует обрабатывать таким образомкак конструкции «Докувики», отключающие другие синтаксические конструкции в особенном текстовом блоке:+''%%mapHandler()%%'' в [[xref>inc:parsing:lexer:lexer.php|Lexer.php]] 
 +<code php Lexer.php [enable_line_numbers="true"start_line_numbers_at="121"]> 
 +    public function mapHandler($mode$handler) 
 +    { 
 +        $this->mode_handlers[$mode] = $handler; 
 +    } 
 +</code>
  
-<code php+[[xref>inc:parsing:lexer:lexer.php|mapHandler()]] позволяет сопоставить определенный именованный режим с методом с другим именем в Handler. Это может быть полезнокогда разный синтаксис должен обрабатываться одинаковонапримерсинтаксис DokuWiki для отключения другого синтаксиса внутри определенного текстового блока;
-$Lexer->addEntryPattern('<nowiki>','base','unformatted')+
-$Lexer->addEntryPattern('%%','base','unformattedalt'); +
-$Lexer->addExitPattern('</nowiki>','unformatted'); +
-$Lexer->addExitPattern('%%','unformattedalt');+
  
-// Оба вида синтаксических конструкций должны обрабатываться одинаковым образом... +<code php> 
-$Lexer->mapHandler('unformattedalt','unformatted');+$lexer -> addEntryPattern ( '<nowiki>' , 'base' ,  'unformatted' ) ;  
 +$lexer -> addEntryPattern ( '%%' , 'base' ,  'unformattedalt' ) ;  
 +$lexer -> addExitPattern ( '</nowiki>' ,  'unformatted' ) ;  
 +$lexer -> addExitPattern ( '%%' ,  'unformattedalt' ) ; 
 +  
 +// Оба синтаксиса должны обрабатываться одинаково...  
 +$lexer -> mapHandler ( 'unformattedalt' 'unformatted' ) ;
 </code> </code>
  
 === Подшаблоны не допускаются === === Подшаблоны не допускаются ===
  
-Поскольку анализатор сам использует **подшаблоны** (внутри класса ''ParallelRegex''), код, //использующий// анализатор, этого не может. Иногда это может пригодиться, но, по общему правилу, метод ''%%addPattern%%'' может быть применён для решения проблем, когда обычно применяются подшаблоны. Его преимуществом является упрощение регулярных выражений, таким образомуправления ими.+Поскольку Lexer (анализаторсам использует **подшаблоны** (внутри класса ''ParallelRegex''), код, //использующий// анализатор, этого не может. Иногда это может пригодиться, но, по общему правилу, метод ''%%addPattern()%%'' может быть применён для решения проблем, когда обычно применяются подшаблоны. Его преимущество в том, что он делает регулярные выражения более простыми и, следовательно, более простыми в управлении.
  
 **Замечание:** если вы используете в шаблоне круглые скобки, они будут //автоматически// пропущены анализатором. **Замечание:** если вы используете в шаблоне круглые скобки, они будут //автоматически// пропущены анализатором.
Строка 165: Строка 229:
 === Синтаксические ошибки и состояния === === Синтаксические ошибки и состояния ===
  
-Для предотвращение «плохо форматируемой» (особенно при пропуске закрывающих тэгов) разметки, приводящей к тому, что анализатор входит в состояние (режим), который он никогда не покинет, может быть полезным использование паттерна просмотра вперёд для проверки наличия закрывающей разметки((Смысл «плохо форматируемый» не применим к парсеру «Докувики» --- он разработан так, чтобы предотвращать случаи, когда пользователь забывает добавить закрывающий тэг некоторой разметки, полностью игнорируя эту разметку.)). Например:+Для предотвращение «плохо форматируемой» (особенно при пропуске закрывающих тэгов) разметки, приводящей к тому, что Lexer (анализаторвходит в состояние (режим), который он никогда не покинет, может быть полезным использование паттерна просмотра вперёд для проверки наличия закрывающей разметки((Смысл «плохо форматируемый» не применим к парсеру «Докувики» --- он разработан так, чтобы предотвращать случаи, когда пользователь забывает добавить закрывающий тэг некоторой разметки, полностью игнорируя эту разметку.)). Например:
  
 <code php> <code php>
 // Использование просмотра вперёд во входном шаблоне... // Использование просмотра вперёд во входном шаблоне...
-$Lexer->addEntryPattern('<file>(?=.*</file>)','base','file'); +// Использовать предпросмотр в шаблоне записи...  
-$Lexer->addExitPattern('</file>','file');+$lexer -> addEntryPattern ( '<file>(?=.*</file>)' , 'base' , 'file' ) ;  
 +$lexer -> addExitPattern ( '</file>' , 'file' ) ;
 </code> </code>
  
-Входной шаблон проверяет, может ли он найти закрывающий тэг ''%%</file>%%'', до входа в состояние.+Шаблон входа проверяет, может ли он найти закрывающий ''</file>'' тегпрежде чем войти в состояние.
  
  
-==== Обработчик ====+==== Handler (Обработчик====
  
-Определяется в ''inc/parser/handler.php''.+Определено в [[xref>inc:parser:handler.php|inc/parser/handler.php]] и папке ''inc/Parsing/Handler''
  
-Обработчик --- это класс, реализующий методы, которые вызываются лексическим анализатором, когда тот обнаруживает вхожденияЗатем он «тонко преобразует» вхождения в последовательность инструкций, готовых для передачи преобразователю.+<diagram> 
 +|AAA||AAA{text-align:left;border-color:white}={{fa>folder?}} Handler 
 +|)|BBB|BBB{text-align:left;border-color:white}={{fa>file?}} AbstractRewriter.php 
 +|)|CCC|CCC{text-align:left;border-color:white}={{fa>file?}} Block.php 
 +|)|DDD|DDD{text-align:left;border-color:white}={{fa>file?}} CallWriter.php 
 +|)|EEE|EEE{text-align:left;border-color:white}={{fa>file?}} Nest.php 
 +|)|FFF|FFF{text-align:left;border-color:white}={{fa>file?}} Lists.php 
 +|)|GGG|GGG{text-align:left;border-color:white}={{fa>file?}} CallWriterInterface.php 
 +|)|KKK|KKK{text-align:left;border-color:white}={{fa>file?}} Preformatted.php 
 +|)|LLL|LLL{text-align:left;border-color:white}={{fa>file?}} Quote.php 
 +|)|MMM|MMM{text-align:left;border-color:white}={{fa>file?}} ReWriterInterface.php 
 +|`|NNN|NNN{text-align:left;border-color:white}={{fa>file?}} Table.php 
 +</diagram>
  
-Обработчик как целое состоит из следующих классов:+Handler — это класс, предоставляющий методы, которые вызывает Lexer, когда он сопоставляет токены. Затем он «тонко настраивает» токены в последовательность инструкций, готовых для Renderer.
  
-  * ''Doku_Handler'': все вызовы из анализатора адресованы этому классу. Для каждого режима, зарегистрированного анализатором, будет соответствующий ему метод в обработчике. +Обработчик в целом содержит следующие классы:
-  * ''Doku_Handler_CallWriter'': реализует «прокладку» между массивом инструкций (массив ''Doku_Handler::$calls'') и методами обработчика, //записывающими// эти инструкции. Пока идёт лексический анализ, он будет временно перемещён другими объектами, вроде ''Doku_Handler_List''+
-  * ''Doku_Handler_List'': отвечает за трансформацию перечня вхождений в инструкции, пока идёт лексический разбор. +
-  * ''Doku_Handler_Preformatted'': отвечает за трансформацию предварительно отформатированных вхождений (врезки в «Докувики») в инструкции, пока идёт лексический разбор. +
-  * ''Doku_Handler_Quote'': отвечает за трансформацию вхождений цитат (текста, начинающего с одной или более «>») в инструкции, пока идёт лексический разбор. +
-  * ''Doku_Handler_Table'': отвечает за трансформацию вхождений таблиц в инструкции, пока идёт лексический разбор. +
-  * ''Doku_Handler_Section'': отвечает за вставку инстукций секций, основываясь на позиции инструкций заголовков, только когда лексический анализ завершён --- повторяется однократно. +
-  * ''Doku_Handler_Block''отвечает за вставку инструкций 'p_open' и 'p_close', будучи осведомлённым об инструкциях 'block level' instructions, только когда лексический анализ завершён (т. е. он повторяется однократно посредством, выдавая полный перечень инструкций и вставляет дополнитльеный инструкции). +
-  * ''Doku_Handler_Toc'': отвечает за добавление инструкций таблицы содержания в начало последовательности, основываясь на инструкциях заголовка, только когда лексический анализ завершён (т. е. он повторяется однократно посредством, выдавая полный перечень инструкций и вставляет дополнитльеный инструкции).+
  
-=== Методы вхождений обработчика ===+  * [[wiki:devel:parser:doku_handler|Doku_Handler]]: все вызовы из Lexer производятся в этот класс. Для каждого режима, зарегистрированного в Lexer, будет соответствующий метод в Handler
  
-Обработчик должен реализовывать методы, соответствующие режимам, зарегистрированным анализатором (подразумевается метод ''%%mapHandler()%%'' анализатора --- см. выше).+''Doku_Handler'' в [[xref>inc:extension:syntaxplugin.php|/dokuwiki/inc/Extension/SyntaxPlugin.php]] 
 +<code php SyntaxPlugin.php > 
 +  use Doku_Handler; 
 +57  * @see Doku_Handler_Block 
 +75  * @param Doku_Handler $handler The Doku_Handler object 
 +77  * @param   Doku_Handler $handler The Doku_Handler object 
 +80  abstract public function handle($match, $state, $pos, Doku_Handler $handler); 
 +</code> 
 +''Doku_Handler'' в [[xref>inc:parsing:parser.php|/dokuwiki/inc/Parsing/Parser.php]] 
 +<code php Parser.php > 
 +6 use Doku_Handler; 
 +17  /** @var Doku_Handler */ 
 +32  * @param Doku_Handler $handler 
 +34  public function __construct(Doku_Handler $handler) 
 +</code> 
 +''Doku_Handler'' в [[xref>inc:parser:handler.php|/dokuwiki/inc/parser/handler.php]] 
 +<code php handler.php > 
 +16   * Class Doku_Handler 
 +18   class Doku_Handler { 
 +40   * Doku_Handler constructor. 
 +795  $link[1] = Doku_Handler_Parse_Media($link[1]); 
 +878  $p = Doku_Handler_Parse_Media($match); 
 +1023 function Doku_Handler_Parse_Media($match) { 
 +</code> 
 + 
 +  * [[xref>inc:parsing:handler:callwriter.php|CallWriter]]: обеспечивает слой между массивом инструкций (массив ''Doku_Handler::$calls'' и методами Handler, //записывающими// эти инструкции. Пока идёт лексический анализ, он будет временно перемещён другими объектами, вроде ''dokuwiki\Parsing\Handler\List''
 +  * [[xref>inc:parsing:handler:lists.php|List]]: отвечает за преобразование токенов списка в инструкции, пока выполняется лексический анализ 
 +  * [[xref>inc:parsing:handler:quote.php|Quote]]: отвечает за преобразование токенов ''blockquote'' (текст, начинающийся с одного или нескольких >) в инструкциипока выполняется лексический анализ 
 +  * [[xref>inc:parsing:handler:table.php|Table]]: отвечает за преобразование токенов таблицы в инструкции, пока выполняется лексический анализ 
 +  * [[xref>inc:parsing:handler:block.php|Block]]: отвечает за вставку инструкций «p_open» и «p_close», при этом отслеживая инструкции «уровня блока»после завершения всего лексического анализа (т.е. выполняет цикл один раз по всему списку инструкций и вставляет больше инструкций) 
 +  * [[xref>inc:parsing:handler:abstractrewriter.php|AbstractRewriter]]: расширено Preformattedи Nest… FIXME 
 +  * [[xref>inc:parsing:handler:nest.php|Nest]]: ...FIXME 
 +  * [[xref>inc:parsing:handler:preformatted.php|Preformatted]]: отвечает за преобразование предварительно отформатированных токенов (отступ в тексте dokuwiki) в инструкции, пока лексический анализ еще выполняется 
 + 
 +=== Методы токенов обработчиков === 
 + 
 +Обработчик должен предоставлять методы, названные в соответствии с режимами, зарегистрированными в лексическом анализаторе (имея в виду %%mapHandler()%% метод лексического анализатора — см. выше).
  
-Например, если вы зарегистировали в анализаторе режим ''file'' наподобие:+Например, если вы зарегистрировали режим файла с помощью Lexer, например:
  
 <code php> <code php>
-$Lexer->addEntryPattern('<file>(?=.*</file>)','base','file'); +$lexer->addEntryPattern('<file>(?=.*</file>)','base','file'); 
-$Lexer->addExitPattern('</file>','file');+$lexer->addExitPattern('</file>','file');
 </code> </code>
  
-Обработчику требуется метод вроде:+Обработчику понадобится такой метод:
  
 <code php> <code php>
 class Doku_Handler { class Doku_Handler {
 + 
     /**     /**
-    * @строковый параметр match содержит текст, который был обнаружен +    * @param string match содержит совпавший текст 
-    * @целочисленный параметр state - тип совпадения (см. ниже) +    * @param int state - тип найденного соответствия (см. ниже) 
-    * @целочисленный параметр pos - индекс байта, где было найдено совпадение+    * @param int pos - индекс байта, где было найдено совпадение
     */     */
-    function file($match, $state, $pos) { +    public function file($match, $state, $pos) { 
-        return TRUE;+        return true;
     }     }
 } }
 </code> </code>
  
-**Замечание:** метод обработчика //обязан// вернуть «TRUE» или анализатор будет немедленно остановленПодобное поведение может быть полезным, когда встречаются другие проблемы обработки, но в парсере «Докувики» все методы обработчика //всегда// возвращают «TRUE».+**Примечание:** метод Handler //должен// возвращать **true**, иначе Lexer немедленно остановитсяТакое поведение может быть полезным при работе с другими типами проблем синтаксического анализа, но для парсера DokuWiki все методы Handler //всегда// будут возвращать **true**.
  
 Аргументы, реализумые методом обработчика; Аргументы, реализумые методом обработчика;
Строка 344: Строка 449:
 В случае со списками, это требует помощи класса ''Doku_Handler_List'', который принимает вхождения, заменяя их на корректные инструкции для Преобразователя. В случае со списками, это требует помощи класса ''Doku_Handler_List'', который принимает вхождения, заменяя их на корректные инструкции для Преобразователя.
  
-==== Парсер ====+==== Parser (Парсер====
  
-Парсер играет роль переднего рубежа для внешнего кода и устанавливает для лексического анализатора паттерны и режимы, описывающие синтаксис «Докувики».+Определено в [[xref>inc:parsing:parser.php|/dokuwiki/inc/Parsing/Parser.php]] и [[xref>inc:parser:parser.php|/dokuwiki/inc/parser/parser.php]].
  
-Использование парсера в общем случае выглядит следущим образом:+dokuwiki [[xref>inc:parsing:parser.php|\Parsing\Parser]] действует как интерфейс для внешнего кода и настраивает Lexer с помощью шаблонов и режимов, описывающих синтаксис DokuWiki. 
 + 
 +Использование парсера обычно выглядит так:
  
 <code php> <code php>
-// Создать парсер +// Создаем обработчик Handler 
-$Parser new Doku_Parser();+$handler = new Doku_Handler();
  
-// Создать обработчик и поместить в парсер +// Создаем парсер с обработчиком  
-$Parser->Handler new Doku_Handler();+$parser = new dokuwiki\Parsing\Parser($handler);
  
-// Добавить требуемые синтаксические режимы в парсер +// Добавить требуемые режимы синтаксиса в парсер  
-$Parser->addMode('footnote',new Doku_Parser_Mode_Footnote()); +$parser->addMode('footnote', new dokuwiki\Parsing\ParserMode\Footnote()); 
-$Parser->addMode('hr',new Doku_Parser_Mode_HR()); +$parser->addMode('hr', new dokuwiki\Parsing\ParserMode\Hr()); 
-$Parser->addMode('unformatted',new Doku_Parser_Mode_Unformatted());+$parser->addMode('unformatted', new dokuwiki\Parsing\ParserMode\Unformatted());
 # etc. # etc.
  
 $doc = file_get_contents('wikipage.txt.'); $doc = file_get_contents('wikipage.txt.');
-$instructions = $Parser->parse($doc);+$instructions = $parser->parse($doc);
 </code> </code>
  
 Более подробные примеры приведены ниже. Более подробные примеры приведены ниже.
  
-В целом, парсер также содержит классы, предсталяющие по отдельности каждый из доступных режимов, базовым классом для всех них является ''Doku_Parser_Mode''. Поведение этих режимов лучше всего понять, посмотрев на примеры добавления синтаксиса ниже в этом документе.+В целом Parser также содержит классы, представляющие каждый доступный режим синтаксиса, базовым классом для всех них является [[xref>inc:parsing:parsermode:abstractmode.php|dokuwiki\Parsing\ParserMode\AbstractMode]]. Поведение этих режимов лучше всего понять, рассмотрев примеры добавления синтаксиса далее в этом документе.
  
-//Причиной// для представления режимов как классов является желание избежать повторяющихся вызовов методов анализатора. Без них было бы необходимо упорно разрабатывать каждое правило паттерна для каждого режима, в котором паттерн мог бы сравниваться, например, для регистрации единого правила паттерна для синтаксиса ссылок ВерблюжьегоСтиля (CamelCase) требовалось бы что-то вроде:+Причина представления режимов с помощью классов заключается в том, чтобы избежать повторных вызовов методов Lexer. Без них пришлось бы жестко кодировать каждое правило шаблона для каждого режима, в котором может быть сопоставлен шаблон, например, регистрация одного правила шаблона для синтаксиса ссылок CamelCase потребовала бы чего-то вроде:
  
 <code php> <code php>
-$Lexer->addSpecialPattern('\b[A-Z]+[a-z]+[A-Z][A-Za-z]*\b','base','camelcaselink'); +$lexer->addSpecialPattern('\b[A-Z]+[a-z]+[A-Z][A-Za-z]*\b', 'base', 'camelcaselink'); 
-$Lexer->addSpecialPattern('\b[A-Z]+[a-z]+[A-Z][A-Za-z]*\b','footnote','camelcaselink'); +$lexer->addSpecialPattern('\b[A-Z]+[a-z]+[A-Z][A-Za-z]*\b', 'footnote', 'camelcaselink'); 
-$Lexer->addSpecialPattern('\b[A-Z]+[a-z]+[A-Z][A-Za-z]*\b','table','camelcaselink'); +$lexer->addSpecialPattern('\b[A-Z]+[a-z]+[A-Z][A-Za-z]*\b', 'table', 'camelcaselink'); 
-$Lexer->addSpecialPattern('\b[A-Z]+[a-z]+[A-Z][A-Za-z]*\b','listblock','camelcaselink'); +$lexer->addSpecialPattern('\b[A-Z]+[a-z]+[A-Z][A-Za-z]*\b', 'listblock', 'camelcaselink'); 
-$Lexer->addSpecialPattern('\b[A-Z]+[a-z]+[A-Z][A-Za-z]*\b','strong','camelcaselink'); +$lexer->addSpecialPattern('\b[A-Z]+[a-z]+[A-Z][A-Za-z]*\b', 'strong', 'camelcaselink'); 
-$Lexer->addSpecialPattern('\b[A-Z]+[a-z]+[A-Z][A-Za-z]*\b','underline','camelcaselink'); +$lexer->addSpecialPattern('\b[A-Z]+[a-z]+[A-Z][A-Za-z]*\b', 'underline', 'camelcaselink'); 
-// etc.+// и т.д.
 </code> </code>
  
-Каждый режим, который позволяет содержать ссылки ВерблюжьегоСтиля должен был быть явно указан.+Каждый режим, которому разрешено содержать ссылки CamelCase, должен быть явно назван.
  
-Вместо этого используется единый класс вроде:+Вместо того, чтобы жестко кодировать это, вместо этого это реализовано с использованием одного класса, например:
  
 <code php> <code php>
-class Doku_Parser_Mode_CamelCaseLink extends Doku_Parser_Mode +namespace dokuwiki\Parsing\ParserMode; 
-     + 
-    function connectTo($mode) {+class CamelCaseLink extends AbstractMode 
 + 
 +    public function connectTo($mode) {
         $this->Lexer->addSpecialPattern(         $this->Lexer->addSpecialPattern(
-                '\b[A-Z]+[a-z]+[A-Z][A-Za-z]*\b',$mode,'camelcaselink' +            '\b[A-Z]+[a-z]+[A-Z][A-Za-z]*\b', $mode, 'camelcaselink' 
-            );+        );
     }     }
-     
 } }
 </code> </code>
  
-При установке параметров лексического анализаторапарсер вызывает метод ''%%connectTo%%'' объекта ''Doku_Parser_Mode_CamelCaseLink'' для любого режима, который принимает синтаксис ВерблюжьегоСтиля.+При настройке лексического анализатора парсер вызывает ''%%connectTo()%%'' метод объекта ''dokuwiki\Parsing\ParserMode\CamelCaseLink'' для каждого другого режима, который принимает синтаксис CamelCase (некоторым такой ''%%<code />%%'' синтаксис не нравится). 
 + 
 +За счет усложнения понимания настройки лексического анализатора это позволяет сделать код более гибким при добавлении нового синтаксиса. 
  
-Это позволяет коду быть более гибким при добавлении новых синтаксических конструкций. 
  
 ==== Формат данных инструкций ==== ==== Формат данных инструкций ====
  
-Следующее показывает пример исходного текста вики и соответствующий вывод парсера:+[[wiki:plugin:parserarray|Плагин Parserarray]] — это экспортный рендерер, который показывает инструкции для текущей страницы. Он может помочь вам понять формат данных. Ниже показан пример сырого текста вики и соответствующий вывод парсера;
  
 Исходный текст (содержит таблицу): Исходный текст (содержит таблицу):
Строка 419: Строка 529:
  
 <code> <code>
-Array +Array( 
-+    [0] => Array(
-    [0] => Array +
-        (+
             [0] => document_start             [0] => document_start
-            [1] => Array +            [1] => Array()
-                ( +
-                ) +
             [2] => 0             [2] => 0
         )         )
- +    [1] => Array(
-    [1] => Array +
-        (+
             [0] => p_open             [0] => p_open
-            [1] => Array +            [1] => Array()
-                ( +
-                ) +
             [2] => 0             [2] => 0
         )         )
- +    [2] => Array(
-    [2] => Array +
-        (+
             [0] => cdata             [0] => cdata
-            [1] => Array +            [1] => Array(
-                (+
                     [0] =>                      [0] => 
  
 abc abc
                 )                 )
- 
             [2] => 0             [2] => 0
         )         )
- +    [3] => Array(
-    [3] => Array +
-        (+
             [0] => p_close             [0] => p_close
-            [1] => Array +            [1] => Array()
-                ( +
-                ) +
             [2] => 5             [2] => 5
         )         )
- +    [4] => Array(
-    [4] => Array +
-        (+
             [0] => table_open             [0] => table_open
-            [1] => Array +            [1] => Array(
-                (+
                     [0] => 3                     [0] => 3
                     [1] => 2                     [1] => 2
                 )                 )
- 
             [2] => 5             [2] => 5
         )         )
- +    [5] => Array(
-    [5] => Array +
-        (+
             [0] => tablerow_open             [0] => tablerow_open
-            [1] => Array +            [1] => Array()
-                ( +
-                ) +
             [2] => 5             [2] => 5
         )         )
- +    [6] => Array(
-    [6] => Array +
-        (+
             [0] => tablecell_open             [0] => tablecell_open
-            [1] => Array +            [1] => Array(
-                (+
                     [0] => 1                     [0] => 1
                     [1] => left                     [1] => left
                 )                 )
- 
             [2] => 5             [2] => 5
         )         )
- +    [7] => Array(
-    [7] => Array +
-        (+
             [0] => cdata             [0] => cdata
-            [1] => Array +            [1] => Array(
-                (+
                     [0] =>  Row 0 Col 1                     [0] =>  Row 0 Col 1
                 )                 )
- 
             [2] => 7             [2] => 7
         )         )
- +    [8] => Array(
-    [8] => Array +
-        (+
             [0] => cdata             [0] => cdata
-            [1] => Array +            [1] => Array(
-                (+
                     [0] =>                          [0] =>     
                 )                 )
- 
             [2] => 19             [2] => 19
         )         )
- +    [9] => Array(
-    [9] => Array +
-        (+
             [0] => tablecell_close             [0] => tablecell_close
-            [1] => Array +            [1] => Array()
-                ( +
-                ) +
             [2] => 23             [2] => 23
         )         )
- +    [10] => Array(
-    [10] => Array +
-        (+
             [0] => tablecell_open             [0] => tablecell_open
-            [1] => Array +            [1] => Array(
-                (+
                     [0] => 1                     [0] => 1
                     [1] => left                     [1] => left
                 )                 )
- 
             [2] => 23             [2] => 23
         )         )
- +    [11] => Array(
-    [11] => Array +
-        (+
             [0] => cdata             [0] => cdata
-            [1] => Array +            [1] => Array(
-                (+
                     [0] =>  Row 0 Col 2                     [0] =>  Row 0 Col 2
                 )                 )
- 
             [2] => 24             [2] => 24
         )         )
- +    [12] => Array(
-    [12] => Array +
-        (+
             [0] => cdata             [0] => cdata
-            [1] => Array +            [1] => Array(
-                (+
                     [0] =>                           [0] =>      
                 )                 )
- 
             [2] => 36             [2] => 36
         )         )
- +    [13] => Array(
-    [13] => Array +
-        (+
             [0] => tablecell_close             [0] => tablecell_close
-            [1] => Array +            [1] => Array()
-                ( +
-                ) +
             [2] => 41             [2] => 41
         )         )
- +    [14] => Array(
-    [14] => Array +
-        (+
             [0] => tablecell_open             [0] => tablecell_open
-            [1] => Array +            [1] => Array(
-                (+
                     [0] => 1                     [0] => 1
                     [1] => left                     [1] => left
                 )                 )
- 
             [2] => 41             [2] => 41
         )         )
- +    [15] => Array(
-    [15] => Array +
-        (+
             [0] => cdata             [0] => cdata
-            [1] => Array +            [1] => Array(
-                (+
                     [0] =>  Row 0 Col 3                     [0] =>  Row 0 Col 3
                 )                 )
- 
             [2] => 42             [2] => 42
         )         )
- +    [16] => Array(
-    [16] => Array +
-        (+
             [0] => cdata             [0] => cdata
-            [1] => Array +            [1] => Array(
-                (+
                     [0] =>                              [0] =>         
                 )                 )
- 
             [2] => 54             [2] => 54
         )         )
- +    [17] => Array(
-    [17] => Array +
-        (+
             [0] => tablecell_close             [0] => tablecell_close
-            [1] => Array +            [1] => Array()
-                ( +
-                ) +
             [2] => 62             [2] => 62
         )         )
- +    [18] => Array(
-    [18] => Array +
-        (+
             [0] => tablerow_close             [0] => tablerow_close
-            [1] => Array +            [1] => Array()
-                ( +
-                ) +
             [2] => 63             [2] => 63
         )         )
- +    [19] => Array(
-    [19] => Array +
-        (+
             [0] => tablerow_open             [0] => tablerow_open
-            [1] => Array +            [1] => Array()
-                ( +
-                ) +
             [2] => 63             [2] => 63
         )         )
- +    [20] => Array(
-    [20] => Array +
-        (+
             [0] => tablecell_open             [0] => tablecell_open
-            [1] => Array +            [1] => Array(
-                (+
                     [0] => 1                     [0] => 1
                     [1] => left                     [1] => left
                 )                 )
- 
             [2] => 63             [2] => 63
         )         )
- +    [21] => Array(
-    [21] => Array +
-        (+
             [0] => cdata             [0] => cdata
-            [1] => Array +            [1] => Array(
-                (+
                     [0] =>  Row 1 Col 1                     [0] =>  Row 1 Col 1
                 )                 )
- 
             [2] => 65             [2] => 65
         )         )
- +    [22] => Array(
-    [22] => Array +
-        (+
             [0] => cdata             [0] => cdata
-            [1] => Array +            [1] => Array(
-                (+
                     [0] =>                          [0] =>     
                 )                 )
- 
             [2] => 77             [2] => 77
         )         )
- +    [23] => Array(
-    [23] => Array +
-        (+
             [0] => tablecell_close             [0] => tablecell_close
-            [1] => Array +            [1] => Array()
-                ( +
-                ) +
             [2] => 81             [2] => 81
         )         )
- +    [24] => Array(
-    [24] => Array +
-        (+
             [0] => tablecell_open             [0] => tablecell_open
-            [1] => Array +            [1] => Array(
-                (+
                     [0] => 1                     [0] => 1
                     [1] => left                     [1] => left
                 )                 )
- 
             [2] => 81             [2] => 81
         )         )
- +    [25] => Array(
-    [25] => Array +
-        (+
             [0] => cdata             [0] => cdata
-            [1] => Array +            [1] => Array(
-                (+
                     [0] =>  Row 1 Col 2                     [0] =>  Row 1 Col 2
                 )                 )
- 
             [2] => 82             [2] => 82
         )         )
- +    [26] => Array(
-    [26] => Array +
-        (+
             [0] => cdata             [0] => cdata
-            [1] => Array +            [1] => Array(
-                (+
                     [0] =>                           [0] =>      
                 )                 )
- 
             [2] => 94             [2] => 94
         )         )
- +    [27] => Array(
-    [27] => Array +
-        (+
             [0] => tablecell_close             [0] => tablecell_close
-            [1] => Array +            [1] => Array()
-                ( +
-                ) +
             [2] => 99             [2] => 99
         )         )
- +    [28] => Array(
-    [28] => Array +
-        (+
             [0] => tablecell_open             [0] => tablecell_open
-            [1] => Array +            [1] => Array(
-                (+
                     [0] => 1                     [0] => 1
                     [1] => left                     [1] => left
                 )                 )
- 
             [2] => 99             [2] => 99
         )         )
- +    [29] => Array(
-    [29] => Array +
-        (+
             [0] => cdata             [0] => cdata
-            [1] => Array +            [1] => Array(
-                (+
                     [0] =>  Row 1 Col 3                     [0] =>  Row 1 Col 3
                 )                 )
- 
             [2] => 100             [2] => 100
         )         )
- +    [30] => Array(
-    [30] => Array +
-        (+
             [0] => cdata             [0] => cdata
-            [1] => Array +            [1] => Array(
-                (+
                     [0] =>                              [0] =>         
                 )                 )
- 
             [2] => 112             [2] => 112
         )         )
- +    [31] => Array(
-    [31] => Array +
-        (+
             [0] => tablecell_close             [0] => tablecell_close
-            [1] => Array +            [1] => Array()
-                ( +
-                ) +
             [2] => 120             [2] => 120
         )         )
- +    [32] => Array(
-    [32] => Array +
-        (+
             [0] => tablerow_close             [0] => tablerow_close
-            [1] => Array +            [1] => Array()
-                ( +
-                ) +
             [2] => 121             [2] => 121
         )         )
- +    [33] => Array(
-    [33] => Array +
-        (+
             [0] => table_close             [0] => table_close
-            [1] => Array +            [1] => Array()
-                ( +
-                ) +
             [2] => 121             [2] => 121
         )         )
- +    [34] => Array(
-    [34] => Array +
-        (+
             [0] => p_open             [0] => p_open
-            [1] => Array +            [1] => Array()
-                ( +
-                ) +
             [2] => 121             [2] => 121
         )         )
- +    [35] => Array(
-    [35] => Array +
-        (+
             [0] => cdata             [0] => cdata
-            [1] => Array +            [1] => Array(
-                (+
                     [0] => def                     [0] => def
  
                 )                 )
- 
             [2] => 122             [2] => 122
         )         )
- +    [36] => Array(
-    [36] => Array +
-        (+
             [0] => p_close             [0] => p_close
-            [1] => Array +            [1] => Array()
-                ( +
-                ) +
             [2] => 122             [2] => 122
         )         )
- +    [37] => Array(
-    [37] => Array +
-        (+
             [0] => document_end             [0] => document_end
-            [1] => Array +            [1] => Array()
-                ( +
-                ) +
             [2] => 122             [2] => 122
         )         )
- 
 ) )
 </code> </code>
  
-Верхний уровень массива --- это просто список. Каждый из его дочерних элементов описывает возвратную функцию, которая будет запущена под преобразователем (см. описание [[#преобразователь|преобразователя]] ниже), также как и индекс байта исходного текста, где был найден особенный «элемент» синтаксиса вики.+Верхний уровень массива --- это просто список. Каждый из его дочерних элементов описывает возвратную функцию, которая будет запущена под преобразователем (см. описание [[#Renderer (преобразователь)|Renderer]] ниже), также как и индекс байта исходного текста, где был найден особенный «элемент» синтаксиса вики.
  
 === Единственная инструкция === === Единственная инструкция ===
Строка 850: Строка 790:
  
                 )                 )
- 
             [2] => 122             [2] => 122
         )         )
 </code> </code>
  
-Первый элемент (индекс 0 ) --- это наименование метода или функции, исполняемой преобразователем.+Первый элемент (индекс 0) — это имя метода или функции в Rendererкоторую необходимо выполнить.
  
-Второй элемент (индекс 1) --- сам является массивом, каждый из элементов //которого// будет аргументом вызываемого метода преобразователя.+Второй элемент (индекс 1) сам по себе является массивом, каждый из элементов которого является аргументом для метода Renderer, который будет вызван.
  
-В этом случае это будет единственный аргумент со значением ''%%"def\n"%%'', так что вызов метода будет:+В этом случае имеется один аргумент со значением ''%%"def\n"%%'', поэтому вызов метода будет выглядеть так:
  
 <code php> <code php>
Строка 865: Строка 804:
 </code> </code>
  
-Третий элемент (индекс 2) --- является индексом байта первого символа, на котором «сработает» эта инструкция в исходном тексте. Он должен быть точно таким же, как и значение, возвращённое PHP-функцией «[[phpfn>strpos]]». Это может использоваться для обнаружения секции исходного текста викиоснованной на позиции сгенерированной инструкции (позже будет пример).+Третий элемент (индекс 2) — это индекс байта первого символа, который «запустил» эту инструкцию в необработанном текстовом документе. Он должен быть таким же, как значение, возвращаемое функцией PHP [[phpfn>strpos]]. Это можно использовать для извлечения разделов необработанного текста вики на основе позиций сгенерированных из него инструкций (пример ниже).
  
-**Замечание:** метод ''parse'' парсера разбивает исходный вики текст на предыдущий и последующий символы, чтобы гарантировать корректный выход анализатора из состояний, так что вам требуется вычесть единицу из индекса байта, чтобы получить корректную позицию оригинального исходного вики-текстаТакже парсер нормализует строки под стиль Unix’а (т. е. все''%%\r\n%%'' становятся ''%%\n%%''), так что документ, который видит анализатор, может быть меньше, чем тот, который вы в действительности загрузили.+**Примечание**: Метод парсера ''parse'' дополняет необработанный текст вики предшествующим и последующим символом перевода строки, чтобы гарантировать корректный выход определенных состояний лексерапоэтому вам может потребоваться вычесть из индекса байта, чтобы получить правильное местоположение в исходном необработанном тексте викиПарсер также нормализует переводы строк в соответствии со стилем Unix (т. е. все ''%%\r\n%%'' становятся ''%%\n%%''), поэтому документ, который видит лексер, может быть меньше того, который вы ему фактически дали.
  
-Пример массив инструкций страницы с описанием [[wiki:syntax|синтаксиса]] --- [[devel:parser:sample_instructions]].+Пример массив инструкций страницы с описанием [[wiki:syntax|синтаксиса]] можно найти [[wiki:devel:parser:sample_instructions|здесь]].
  
-==== Преобразователь ====+==== Renderer (преобразователь====
  
-Преобразователь --- это класс (или коллекция функций), определяемый вами. Его интерфейс описан в файле ''inc/parser/renderer.php'' и выглядит так:+Renderer (преобразователь--- это класс (или коллекция функций), определяемый вами. Его интерфейс описан в файле ''inc/parser/renderer.php'' и выглядит так:
  
 <code php> <code php>
Строка 879: Строка 818:
 class Doku_Renderer { class Doku_Renderer {
  
-    // snip+    // вырезка
          
-    function header($text, $level) {}+    public function header($text, $level) {}
          
-    function section_open($level) {}+    public function section_open($level) {}
          
-    function section_close() {}+    public function section_close() {}
          
-    function cdata($text) {}+    public function cdata($text) {}
          
-    function p_open() {}+    public function p_open() {}
          
-    function p_close() {}+    public function p_close() {}
          
-    function linebreak() {}+    public function linebreak() {}
          
-    function hr() {}+    public function hr() {}
          
-    // snip+    // вырезка
 } }
 </code> </code>
  
-Он используется для документирования преобразователя, хотя также может быть расширен, если вы захотите написать преобразователь, который лишь перехватывает определённые вызовы.+Он используется для документирования Renderer, хотя его также можно расширить, если вы хотите написать Renderer, который захватывает только определенные вызовы.
  
-Основной принцип того, как инструкции, возвращаемые парсером, используются преобразователем, близок по смыслу к [[wp>ru:SAX|SAX XML API]] --- инструкции являются перечнем имён функций / методов и их аргуменов. Каждая инструкция может быть вызвана через преобразователь (т. е. реализуемые им методы являются [[wp>ru:Callback_(программирование)|обратными]]). В отличие от «SAX API», где доступно совсем немного, достаточно общих, обратно вызываемых методов (например, tag_start, tag_end, cdata и т. д.), преобразователь определяет более точную API, где методы обычно соответствуют один-к-одному действию по генерации выходных данных.+Основной принцип того, как инструкции, возвращаемые парсером, используются против Renderer, аналогичен понятию [[wp>Simple_API_for_XML|SAX XML API]] - инструкции представляют собой список имен функций/методов и их аргументов. Проходя по списку инструкций, каждая инструкция может быть вызвана против Renderer (т. е. методы, предоставляемые Renderer, являются [[wp>Callback_(computer_science)|callbacks]]). Unlike the SAX API, where only a few, fairly general, callbacks are available (e.g. tag_start, tag_end, cdata etc.). В отличие от SAX API , где доступно только несколько, довольно общих, обратных вызовов (например, tag_start, tag_end, cdata и т. д.), Renderer определяет более явный API , где методы обычно соответствуют один к одному акту генерации вывода. В разделе Renderer, показанном выше, методы ''p_open'' и ''p_close'' будут использоваться для вывода тегов ''%%<p>%%'' и ''%%</p>%%'' в XHTML, соответственно, в то время как ''header'' функция принимает два аргумента — некоторый текст для отображения и «уровень» заголовка, поэтому вызов типа ''%%header('Some Title', 1)%%'' будет выведен в XHTML типа ''%%<h1>Some Title</h1>%%''.
  
-Во фрагменте преобразователя, показанном выше методы ''p_open'' и ''p_close'' будут использованы для вывода тэгов ''%%<p>%%'' и ''%%</p>%%'' в XHTML, соответственно, в то время, как функция ''header'' принимает два аргумента --- некоторый текст для отображения и «уровень» заголовка, так что вызов типа ''%%header('Some Title',1)%%'' выведет в XHTML ''%%<h1>Some Title</h1>%%''.+=== Вызов рендерера с инструкциями ===
  
-=== Вызов преобразователя через инструкции === +Клиентскому кодуиспользующему Parser, остается выполнить список инструкций для Renderer. Обычно это делается с помощью функции PHP [[phpfn>call_user_func_array()]] function. Например;
- +
-К **клиентскому коду** относится использование парсера для выполнения перечня инструкций через преобразователь. Обычно это делается использованием php-функции «[[phpfn>call_user_func_array]]». Например:+
  
 <code php> <code php>
-// Получить перечень инструкций из парсера +// Получить список инструкций от парсера  
-$instructions = $Parser->parse($rawDoc);+$instructions = $parser->parse($rawDoc);
  
-// Создать преобразователь +// Создаем рендерер  
-$Renderer new Doku_Renderer_XHTML();+$renderer = new Doku_Renderer_xhtml();
  
-// Пройтись по всем инструкциям +// Проходим по инструкциям  
-foreach ( $instructions as $instruction ) { +foreach ($instructions as $instruction) { 
-     +    // Выполняем обратный вызов для Renderer  
-    // Выполнить инструкции через преобразователь +    call_user_func_array([$renderer, $instruction[0]], $instruction[1]);
-    call_user_func_array(array(&$Renderer, $instruction[0]),$instruction[1]);+
 } }
 </code> </code>
  
-=== Методы преобразователя для ссылок ===+=== Методы связи с рендерером ===
  
-Ключевыми методами преобразователя для обработки различного рода ссылок являются:+Ключевые методы Renderer для обработки различных типов ссылок:
  
-  * ''%%function camelcaselink($link) {} // $link вида «SomePage"%%'' +  * ''function [[xref>camelcaselink($link)]] %%{} // $link like "SomePage"%%'' 
-    * Возможно, это будет проигнорировано проверкой на спам-адрес --- маловероятно, что кто-нибудь подобным образом поставить ссылку вне сайта. +    *Вероятно, это можно проигнорировать для проверки на спам — никто не должен иметь возможности ссылаться на сторонние сайты с таким синтаксисом
-  * ''%%function internallink($link, $title = NULL) {} // $link вида «[[syntax]]"%%'' +  * ''function [[xref>internallink($link, $title = null)]]%% {} // $link like "[[syntax]]"%%'' 
-    * Хотя ''$link'' сама по себе является внутренней, ''$title'' может быть недоступным изображением, так что требуется проверка. +    *Хотя ''$link'' сам по себе является внутренним, ''$title'' может быть изображением, которое находится вне сайта, поэтому необходимо проверить 
-  * ''%%function externallink($link, $title = NULL) {}%%'' +  * ''function [[xref>externallink($link, $title = null)]] {}'' 
-    * И ''$link''и ''$title'' (изображениетребуют проверки. +    *Оба изображения ''$link'' и ''$title'' (изображениянуждаются в проверке 
-  * ''%%function interwikilink($link, $title = NULL, $wikiName, $wikiUri) {}%%'' +  * ''function [[xref>interwikilink($link, $title = null, $wikiName, $wikiUri)]] {}'' 
-    * ''$title'' требует проверки для изображений. +    *Необходимость ''$title'' проверки изображений 
-  * ''%%function filelink($link, $title = NULL) {}%%'' +  * ''function [[xref>filelink($link, $title = null)]] {}'' 
-    * Техническитолько годные ''%%file://%%'' URL будут совпадать, но всё равно лучше проверить плюс проверка ''$title'', которое может быть недоступным изображением. +    *Технически должны совпадать только действительные ''%%file://%%'' URLдреса, новероятнолучше все равно проверитьплюс ''$title'' может быть стороннее изображение 
-  * ''%%function windowssharelink($link, $title = NULL) {}%%'' +  * ''function [[xref>windowssharelink($link, $title = null)]] {}'' 
-    * Требуется проверить только годные адреса доступа к общим ресурсам Windows, но всё равно лучше проверить плюс проверка ''$title'', которое может быть недоступным изображением. +    *Должен соответствовать только допустимым URL-адресам общих ресурсов Windows, но в любом случае проверять наличие ''$title'' изображений 
-  * ''%%function email($address, $title = NULL) {}%%'' +  * ''function [[xref>emaillink($address, $title = null)]] {}'' 
-    * ''$title'' может быть изображением. Проверять ли адрес электропочты+    *''$title'' может быть изображение. Проверить почту тоже?$titleможет быть изображение. Проверить почту тоже
-  * ''%%function internalmedialink ($src,$title=NULL,$align=NULL,$width=NULL,$height=NULL,$cache=NULL) {}%%'' +  * ''function [[xref>internalmedialink($src, $title = null, $align = null $width = null, $height = null, $cache = null)]] {}'' 
-    * Здесь проверка не требуется --- следует только поставить ссылки на локальные изображения. ''$title'' сам по себе не может быть изображением. +    *Это не требует проверки — должно ссылаться только на локальные изображения. ''$title'' само по себе не может быть изображением 
-  * ''%%function externalmedialink($src,$title=NULL,$align=NULL,$width=NULL,$height=NULL,$cache=NULL) {}%%'' +  * ''function [[xref>externalmedialink($src, $title = null, $align = null, $width = null, $height = null, $cache = null)]] {}'' 
-    * ''$src'' требует проверки.+    *''$src'' нуждается в проверке
  
-Особое внимание следует уделит методам, принимающим в качестве параметра ''%%$title%%'', который представляет видимый текст ссылки, например:+Особого внимания требуют методыкоторые принимают''%%$title%%'' аргумент, представляющий видимый текст ссылки, например;
  
 <code html> <code html>
-<a href="http://www.example.com/">This is the title</a>+<a href="https://www.example.com">This is the title</a>
 </code> </code>
  
-Аргумент ''%%$title%%'' может принимать три возможных типа значений:+Аргумент ''%%$title%%'' может иметь три возможных типа значений;
  
-  - ''NULL'': у документа вики нет заголовка; +  - ''null'': в вики-документе заголовок не указан. 
-  - строка: в качестве заголовка использована простая тестовая строка; +  - string: в качестве заголовка использовалась простая текстовая строка 
-  - массив (хэш): в качестве заголовка использовано изображение.+  - array (hash): в качестве заголовка использовано изображение.
  
-Если ''%%$title%%'' является массивом, он будет содержать ассоциированные значения, описывающие изображение:+Если это ''%%$title%%'' массив, он будет содержать ассоциативные значения, описывающие изображение;
  
 <code php> <code php>
-$title = array( +$title = [ 
-    // Может быть 'internalmedia' (локальное изображение) или 'externalmedia' (внешнее изображение) +    // Может быть 'internalmedia' (локальное изображение) или 'externalmedia' (внешнее изображение)  
-    'type'=>'internalmedia',+    'type' => 'internalmedia',
          
-    // URL изображения (может быть вики-URL или http://static.example.com/img.png) +    // URL-адрес изображения (может быть URL-адресом wiki или https://static.example.com/img.png)  
-    'src'=>'wiki:php-powered.png',+    'src' => 'wiki:php-powered.png',
          
-    // Для альтернативного атрибута - a string or NULL +    // Для атрибута alt строка или null  
-    'title'=>'Powered by PHP',+    'title' => 'Powered by PHP',
          
-    // 'left', 'right', 'center' или NULL +    // 'left', 'right', 'center' или null 
-    'align'=>'right',+    'align' => 'right',
          
-    // Ширина в пикселях или NULL +    // Ширина в пикселях или null  
-    'width'=> 50,+    'width' => 50,
          
-    // Высота в пикселях или NULL +    // Высота в пикселях или null  
-    'height'=>75,+    'height' => 75,
          
-    // Следует ли кэшировать изображение (для внешних изображений)? +    // Кэшировать ли изображение (для внешних изображений) 
-    'cache'=>FALSE+    'cache' => false
-);+];
 </code> </code>
  
wiki/devel/parser.1737022316.txt.gz · Последнее изменение: vladpolskiy