The Perl Toolchain Summit needs more sponsors. If your company depends on Perl, please support this very important event.

NAME/НАИМЕНОВАНИЕ

perldebguts - Внутренности отладки в Perl

ОПИСАНИЕ

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

Внутренние компоненты отладчика (Debugger Internals)

Perl имеет специальные хуки (hooks) отладки во время компиляции и во время выполнения, используемые для создания среды отладки. Эти хуки не следует путать с командами perl -Dxxx, описанными в perlrun, которые используются только, если специальный Perl построен (built) по инструкции в pod странице INSTALL в дереве исходного кода Perl.

Например, когда вы называете встроенную в Perl функцию caller из пакета DB, аргументы, которые соответствующий стек фрейм был вызван копируются в @DB::args массива. Этот механизм включается, когда Perl вызывется с ключом -d. В частности включены следующие дополнительные функции (см. "$^P" in perlvar):

  • Perl вставляет содержимое $ENV{PERL5DB} (или BEGIN {require 'perl5db.pl'} если его нет) перед первой строкой вашей программы.

  • Каждый массив @{"_<$filename"} держит строки $filename для файла, скомпилированного с Perl. То же самое верно для выполняемых (eval) строк, которые содержат подпрограммы, или которых выполняются в настоящее время. $filename для выполняемых строк выглядит как (eval 34).

    Значения в этом массиве магическое в числовом контексте: они сравнивают равенство нулю только, если строка не ломается.

  • Каждый хэш %{"_<$filename"} содержит точки останова и действия с ключом по ее номеру. Отдельные записи (в отличие от всего хэша) устанавливаемы. Perl заботится только о логическом значении правда (true) здесь, хотя значения, используемые perl5db.pl имеют форму "$break_condition\0$action".

    То же самое хранится для исполняемых строк, которые содержат подпрограммы, или которые, выполняются в настоящее время. $filename для выполняемых строк выглядит как (eval 34).

  • Каждый скаляр ${"_<$filename"} содержит "_<$filename". Это также в случае выполнения строк, которые содержат подпрограммы, или которые в настоящее время выполняются. $filename для выполняемых строк выглядит как (eval 34).

  • После компиляции каждого требуемого файла, но перед выполнением, вызывается процедура DB::postponed(*{"_<$filename"}) , если существует DB::postponed. Здесь $filename - это развернутое имя требуемого файла, как он найдет в значениях (values) %INC.

  • После компиляции каждого подимени, проверяется $DB::postponed{subname} , если она существует. Если этот ключ существует, то вызывается DB::postponed(subname), если существует процедура DB::postponed.

  • Поддерживается хэш %DB::sub, чьи ключи являются именами подпрограмм и значения которых имеют форму filename:startline-endline. filename имеет форму (eval 34) для подпрограмм, определенные внутри eval.

  • Когда выполнение программы достигнет точки, на которой может стоять точка останова, подпрограмма DB::DB() вызывается, если любая из переменных $DB::trace, $DB::single, или $DB::signalимеет значение true. Эти переменные не являются локализованными. Эта функция отключена при выполнении внутри DB::DB(), включая функции, которые вызываются из нее Пока выражение $^D & (1<<30) имеет значение true.

  • Когда выполнение программы достигает вызова подпрограммы, вместо этого производится вызов &DB::sub(args) с $DB::sub, которая содержит имя вызываемой подпрограммы. (Этого не случиться, если подпрограмма была скомпилирована из DB пакета.)

Обратите внимание, что если &DB::sub нужны внешние данные, чтобы он работал, то без нее не возможен вызов подпрограммы. В качестве примера, стандартный отладчик &DB::sub зависит от переменной $DB::deep (Он определяет, сколько уровней рекурсии в глубину отладчика вы можете использовать До обязательного перерыва). Если $DB::deep не определено, вызовы подпрограммы невозможны, хотя существует &DB::sub.

Написание собственного отладчика (Writing Your Own Debugger)

Переменные среды (Environment Variables)

Переменная среды PERL5DB может использоваться для определения отладчика. Например, минимальный «рабочий» отладчик (он фактически ничего не делает) состоит из одной строки:

  sub DB::DB {}

Его можно легко определить следующим образом:

  $ PERL5DB="sub DB::DB {}" perl -d your-script

Можно создать еще один короткий отладчик в одну строку, несколько более полезный:

  sub DB::DB {print ++$i; scalar <STDIN>}

Этот отладчик выводит число, которое увеличивается для каждого оператора, с которым он сталкивается и ждет, пока вы нажмете новую строку, прежде чем перейдете к следующему оператору(statement).

Следующий отладчик действительно полезен:

  {
    package DB;
    sub DB  {}
    sub sub {print ++$i, " $sub\n"; &$sub}
  }

Он печатает порядковый номер каждого вызова подпрограммы и имя вызываемой подпрограммы. Обратите внимание, что &DB::sub компилируется в Пакет DB с помощью директивы package.

Когда он запускается, отладчик считывает ваш файл rc (./.perldb или ~/.perldb под Unix), который может устанавливать важные параметры. (Здесь также можно определить подпрограмму (&afterinit), она выполняется после того как отладчик завершит свою инициализацию.)

После считывания файла rc отладчик считывает переменную окружения PERLDB_OPTS и использует ее для установки параметров отладчика. СОДЕРЖАНИЕ Содержимое этой переменной обрабатывается так, как если бы они были аргументом o ... команды отладчика (q.v. в "Configurable Options" in perldebug) (q.v. в "Настраиваемые параметры" in perldebug).

Внутренние переменные отладчика (Debugger Internal Variables)

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

  • @DB::dbline является псевдонимом для @{"::_<current_file"}, который содержит строки выбранного в данный момент файла (скомпилированного Perl), либо явно выбранный с помощью команды отладчика f или неявно по потоку исполнения.

    Значения в этом массиве являются магическими в числовом контексте: они сравнивают равенство нулю только в том случае, если строка не является хрупкой.(they compare equal to zero only if the line is not breakable.)

  • %DB::dbline является псевдонимом для %{"::_<current_file"}, который содержит точки останова и действия, заданные номером строки в выбранный в данный момент файл, либо явно выбранный с помощью команды отладчика f , или неявно по потоку выполнения.

    Как отмечалось ранее, отдельные записи (в отличие от всего хеша) могут устанавливаться. Perl только заботится о булевой истине здесь, хотя значения, используемые perl5db.pl имеют вид "$break_condition\0$action".

Функции настройки отладчика

Некоторые функции предусмотрены для упрощения настройки.

  • См. "Configurable Options" in perldebug ("Настраиваемые параметры" in perldebug) для описания параметров, проанализированных DB::parse_options(string).

  • DB::dump_trace(skip[,count]) пропускает указанное количество кадров и возвращает список, содержащий информацию о вызывающих кадрах (все из них, если count отсутствует). Каждая запись является ссылкой на хэш с ключами context (либо ., $, or @), sub (имя подпрограммы или сведения о eval), args (undef или ссылка на массив), file, и line.

  • DB::print_trace(FH, skip[, count[, short]]) печатает отформатированную информацию о кадрах вызывающего (caller frames). Последние две функции могут быть удобными в качестве аргументов командам <, <<.

Обратите внимание, что любые переменные и функции, не документированные в эти манах (или в perldebug) рассматриваются только для внутреннего использования и, как таковые, могут быть изменены без предварительного уведомления.

Примеры вывода списка кадров (Frame Listing Output Examples)

Опцию frame можно использовать для управления выходом кадра информации. Например, сравните этот вывод трейса:

 $ perl -de 42
 Дамп стека во время смерти включен за пределами проверки. (Stack dump during die enabled outside of evals.)

 Loading DB routines from perl5db.pl patch level 0.94
 Emacs support available.

 Enter h or 'h h' for help.

 main::(-e:1):   0
   DB<1> sub foo { 14 }

   DB<2> sub bar { 3 }

   DB<3> t print foo() * bar()
 main::((eval 172):3):   print foo() + bar();
 main::foo((eval 168):2):
 main::bar((eval 170):2):
 42

с этим, как только option frame=2 был установлен:

   DB<4> o f=2
                frame = '2'
   DB<5> t print foo() * bar()
 3:      foo() * bar()
 entering main::foo
  2:     sub foo { 14 };
 exited main::foo
 entering main::bar
  2:     sub bar { 3 };
 exited main::bar
 42

В качестве демонстрации ниже мы приведем трудоемкий список в результате установки переменной окружения PERLDB_OPTS на значение f=n N, и запуск perl -d -V из командной строки. Показано, что примеры, использующие различные значения n дают вам почувстовать разницу между настройками. Хотя это может быть длинно, это не полный список, а только выдержки.

  1.   entering main::BEGIN
       entering Config::BEGIN
        Package lib/Exporter.pm.
        Package lib/Carp.pm.
       Package lib/Config.pm.
       entering Config::TIEHASH
       entering Exporter::import
        entering Exporter::export
      entering Config::myconfig
       entering Config::FETCH
       entering Config::FETCH
       entering Config::FETCH
       entering Config::FETCH
  2.   entering main::BEGIN
       entering Config::BEGIN
        Package lib/Exporter.pm.
        Package lib/Carp.pm.
       exited Config::BEGIN
       Package lib/Config.pm.
       entering Config::TIEHASH
       exited Config::TIEHASH
       entering Exporter::import
        entering Exporter::export
        exited Exporter::export
       exited Exporter::import
      exited main::BEGIN
      entering Config::myconfig
       entering Config::FETCH
       exited Config::FETCH
       entering Config::FETCH
       exited Config::FETCH
       entering Config::FETCH
  3.   in  $=main::BEGIN() from /dev/null:0
       in  $=Config::BEGIN() from lib/Config.pm:2
        Package lib/Exporter.pm.
        Package lib/Carp.pm.
       Package lib/Config.pm.
       in  $=Config::TIEHASH('Config') from lib/Config.pm:644
       in  $=Exporter::import('Config', 'myconfig', 'config_vars') from /dev/null:0
        in  $=Exporter::export('Config', 'main', 'myconfig', 'config_vars') from li
      in  @=Config::myconfig() from /dev/null:0
       in  $=Config::FETCH(ref(Config), 'package') from lib/Config.pm:574
       in  $=Config::FETCH(ref(Config), 'baserev') from lib/Config.pm:574
       in  $=Config::FETCH(ref(Config), 'PERL_VERSION') from lib/Config.pm:574
       in  $=Config::FETCH(ref(Config), 'PERL_SUBVERSION') from lib/Config.pm:574
       in  $=Config::FETCH(ref(Config), 'osname') from lib/Config.pm:574
       in  $=Config::FETCH(ref(Config), 'osvers') from lib/Config.pm:574
  4.   in  $=main::BEGIN() from /dev/null:0
       in  $=Config::BEGIN() from lib/Config.pm:2
        Package lib/Exporter.pm.
        Package lib/Carp.pm.
       out $=Config::BEGIN() from lib/Config.pm:0
       Package lib/Config.pm.
       in  $=Config::TIEHASH('Config') from lib/Config.pm:644
       out $=Config::TIEHASH('Config') from lib/Config.pm:644
       in  $=Exporter::import('Config', 'myconfig', 'config_vars') from /dev/null:0
        in  $=Exporter::export('Config', 'main', 'myconfig', 'config_vars') from lib/
        out $=Exporter::export('Config', 'main', 'myconfig', 'config_vars') from lib/
       out $=Exporter::import('Config', 'myconfig', 'config_vars') from /dev/null:0
      out $=main::BEGIN() from /dev/null:0
      in  @=Config::myconfig() from /dev/null:0
       in  $=Config::FETCH(ref(Config), 'package') from lib/Config.pm:574
       out $=Config::FETCH(ref(Config), 'package') from lib/Config.pm:574
       in  $=Config::FETCH(ref(Config), 'baserev') from lib/Config.pm:574
       out $=Config::FETCH(ref(Config), 'baserev') from lib/Config.pm:574
       in  $=Config::FETCH(ref(Config), 'PERL_VERSION') from lib/Config.pm:574
       out $=Config::FETCH(ref(Config), 'PERL_VERSION') from lib/Config.pm:574
       in  $=Config::FETCH(ref(Config), 'PERL_SUBVERSION') from lib/Config.pm:574
  5.   in  $=main::BEGIN() from /dev/null:0
       in  $=Config::BEGIN() from lib/Config.pm:2
        Package lib/Exporter.pm.
        Package lib/Carp.pm.
       out $=Config::BEGIN() from lib/Config.pm:0
       Package lib/Config.pm.
       in  $=Config::TIEHASH('Config') from lib/Config.pm:644
       out $=Config::TIEHASH('Config') from lib/Config.pm:644
       in  $=Exporter::import('Config', 'myconfig', 'config_vars') from /dev/null:0
        in  $=Exporter::export('Config', 'main', 'myconfig', 'config_vars') from lib/E
        out $=Exporter::export('Config', 'main', 'myconfig', 'config_vars') from lib/E
       out $=Exporter::import('Config', 'myconfig', 'config_vars') from /dev/null:0
      out $=main::BEGIN() from /dev/null:0
      in  @=Config::myconfig() from /dev/null:0
       in  $=Config::FETCH('Config=HASH(0x1aa444)', 'package') from lib/Config.pm:574
       out $=Config::FETCH('Config=HASH(0x1aa444)', 'package') from lib/Config.pm:574
       in  $=Config::FETCH('Config=HASH(0x1aa444)', 'baserev') from lib/Config.pm:574
       out $=Config::FETCH('Config=HASH(0x1aa444)', 'baserev') from lib/Config.pm:574
  6.   in  $=CODE(0x15eca4)() from /dev/null:0
       in  $=CODE(0x182528)() from lib/Config.pm:2
        Package lib/Exporter.pm.
       out $=CODE(0x182528)() from lib/Config.pm:0
       scalar context return from CODE(0x182528): undef
       Package lib/Config.pm.
       in  $=Config::TIEHASH('Config') from lib/Config.pm:628
       out $=Config::TIEHASH('Config') from lib/Config.pm:628
       scalar context return from Config::TIEHASH:   empty hash
       in  $=Exporter::import('Config', 'myconfig', 'config_vars') from /dev/null:0
        in  $=Exporter::export('Config', 'main', 'myconfig', 'config_vars') from lib/Exporter.pm:171
        out $=Exporter::export('Config', 'main', 'myconfig', 'config_vars') from lib/Exporter.pm:171
        scalar context return from Exporter::export: ''
       out $=Exporter::import('Config', 'myconfig', 'config_vars') from /dev/null:0
       scalar context return from Exporter::import: ''

Во всех случаях, показанных выше, отступ строки показывает дерево вызовов. Если бит 2 frame установлен, строка будет успешно напечатана при выходе из подпрограммы. Если бит 4 установлен, аргументы печатаются наряду с информацией о вызывающей функции Если бит 8 установлен, аргументы напечатаются, даже если они связаны или ссылаются. (even if they are tied or references.) Если бит 16 установлен, то возвращаемое значение также печатается.

Когда пакет компилируется, строка, подобная этой

    Package lib/Carp.pm.

Печатается с правильным отступом.

Отладка регулярных выражений

Есть два способа включить вывод отладки для регулярных выражений.

Если ваш perl скомпилирован с помощью -DDEBUGGING, вы можете использовать флаг -Dr в командной строке.

В противном случае вы можете использовать use re 'debug', который работает и во время компиляции и во время выполнения. Начиная с Perl 5.9.5, эта прагма имеет лексическую область видимости.

Вывод лога во время компиляции (Compile-time Output)

Вывод отладки во время компиляции выглядит так:

  Compiling REx '[bc]d(ef*g)+h[ij]k$'
  size 45 Got 364 bytes for offset annotations.
  first at 1
  rarest char g at 0
  rarest char d at 0
     1: ANYOF[bc](12)
    12: EXACT <d>(14)
    14: CURLYX[0] {1,32767}(28)
    16:   OPEN1(18)
    18:     EXACT <e>(20)
    20:     STAR(23)
    21:       EXACT <f>(0)
    23:     EXACT <g>(25)
    25:   CLOSE1(27)
    27:   WHILEM[1/1](0)
    28: NOTHING(29)
    29: EXACT <h>(31)
    31: ANYOF[ij](42)
    42: EXACT <k>(44)
    44: EOL(45)
    45: END(0)
  anchored 'de' at 1 floating 'gh' at 3..2147483647 (checking floating) 
        stclass 'ANYOF[bc]' minlen 7 
  Offsets: [45]
        1[4] 0[0] 0[0] 0[0] 0[0] 0[0] 0[0] 0[0] 0[0] 0[0] 0[0] 5[1]
        0[0] 12[1] 0[0] 6[1] 0[0] 7[1] 0[0] 9[1] 8[1] 0[0] 10[1] 0[0]
        11[1] 0[0] 12[0] 12[0] 13[1] 0[0] 14[4] 0[0] 0[0] 0[0] 0[0]
        0[0] 0[0] 0[0] 0[0] 0[0] 0[0] 18[1] 0[0] 19[1] 20[0]  
  Omitting $` $& $' support.

Первая строка показывает предварительно скомпилированную форму регулярного выражения. Вторая показывает размер скомпилированной формы (в произвольных единицах, обычно 4-байтные слова) и общее количество байт, выделенных для таблицы смещения/длины, обычно 4+размер* 8 (offset/length table, usually 4+size*8). Следующая строка показывает метку id первого узла, с которым выполнилось сопоставление (первого найденного узла).

 Привязанный 'de' к 1 плавающей 'gh' в 3..2147483647 (проверка плавающей)
        Stclass 'ANYOF [bc]' minlen 7

  (anchored 'de' at 1 floating 'gh' at 3..2147483647 (checking floating) 
        stclass 'ANYOF[bc]' minlen 7) 
        

cтрока (разделенная на две строки) содержит информацию оптимизатора. В показанном примере оптимизатор обнаружил, что совпадение должно содержать подстроку de со смещением 1 плюс подстрока gh при некотором смещении между 3 и бесконечностью. Более того, при проверке на эти подстроки (чтобы отказаться от невозможных совпадений быстро), Perl проверит для подстроки gh перед проверкой подстроки de. Оптимизатор также может использовать знания о том, что начало матча (на first id) с символьным классом и строка короче 7 символов не может быть найдена.

Поля, представляющие интерес, могут отображаться в этой строке:

anchored STRING at POS
floating STRING at POS1..POS2

См. Выше.

matching floating/anchored

Какую подстроку проверить в первую очередь.

minlen

Минимальная длина поиска(match).

stclass TYPE

Тип первого совпадающего узла.

noscan

Не сканируйте найденные подстроки.

isall

Означает, что информация оптимизатора - это все, что содержит регулярное выражение, и, таким образом, нет необходимости вводить регулярное выражение вообще (does not need to enter the regex engine at all.)

GPOS

Установите, если шаблон содержит \G.

plus

Установите, если шаблон начинается с повторяющегося символа (как в x+y).

implicit

Установите, если шаблон начинается с .*.

with eval

Установите, если шаблон содержит eval-группы, такие как (?{ code }) и (??{ code }).

якорный(ТИП) (anchored(TYPE))

Если шаблон может соответствовать нескольким местам, с TYPE будучи BOL, С<MBOL> или С<GPOS>. Смотрите таблицу ниже.

Если подстрока, как известно, должна соответствует только в конце строки , то за ней нужно ставить символ $, как в плавающий 'k'$ (floating 'k'$).

Информация для оптимизатора используется, чтобы избежать ввода (медленного) регекс двигателя для строк, которые не будут соответствовать определенно. Если флаг isall задан, вызов обработчика регулярных выражений можно избежать даже когда оптимизатор нашел соответствующее место для поиска.

Раздел про оптимизатор выше представляет собой список узлов (nodes) из скомпилированных форм регекса. Каждая строка имеет формат

id: ТИП ОПЦИОНАЛЬНАЯ-ИНФОРМАЦИЯ (следующий-ид) id: TYPE OPTIONAL-INFO (next-id)

Типы узлов (Types of Nodes)

Ниже приведены возможные типы, с кратким описанием:

 # ТИП описание-аргумента [число-аргументов] [прыжок-в-длину-длина] ОПИСАНИЕ
 # TYPE arg-description [num-args] [longjump-len] DESCRIPTION

 # Точки выхода
 # Exit points

 END                no         Конец программы.
 SUCCEED            no         Вернуться из подпрограммы, в основном. (Return from a subroutine, basically.)

 # Якоря:

 BOL                no         Найдет "" в начале строки.
 MBOL               no         То же,предполагая мультистроку.
 SBOL               no         То же,предполагая одностроку. (Same, assuming singleline.)
 EOS                no         Найдет "" в конце строки. (string)
 EOL                no         Найдет "" в конце линии. (line)
 MEOL               no         То же,предполагая мультистроку.
 SEOL               no         То же,предполагая одностроку.
 BOUND              no         Найдет "" при любом использовании границы слова
                               при родной семантике кодировки для не-utf8
 BOUNDL             no         Найдет "" в любой локальной границе слова ( Match "" at any locale word boundary)
 BOUNDU             no         Найдет "" в любой локальной границе слова
                               используя семантику Юникода
 BOUNDA             no         Найдет "" в любой локальной границе слова используя ASCII
                               семантику
 NBOUND             no         Найдет "" в любой не-границе слова используя
                               родные не-UTF кодировку (native charset semantics for non-utf8)
 NBOUNDL            no         Найдет "" в любой локальной не-границе слова
 NBOUNDU            no         Найдет "" в любой не-границе слова используя
                               семантику Юникода
 NBOUNDA            no         Найдет "" в любой не-границе слова используя
                               ASCII семантику
 GPOS               no         Совпадения, в которых остановились последние m//g.

 # [Специальные] альтернативы:

 REG_ANY            no         Соответствует любому символу (кроме символа новой строки).
 SANY               no         Соответствует любому одному символу.
 CANY               no         Соответствует любому одному байту.
 ANYOF              sv         Сопоставить символ в (или не в) этого
                               класса, только односимвольное соответствие
 ANYOF_WARN_SUPER   sv         Сопоставить символ в (или не в) этого
                               класса, кидает ворнинги (если включено) после нахождения
                               Char выше Unicode максимального юникода (max);
                               (Match character in (or not in) this
                               class, warn (if enabled) upon matching a
                               char above Unicode max;)
 ANYOF_SYNTHETIC    sv         Синтетический стартовый класс (Synthetic start class)

 POSIXD             none       Некоторым [[:class:]] под /d; 
                               ставит один флаг (the FLAGS field gives which one)
 POSIXL             none       Некоторым [[:class:]] под /l; 
                               ставит один флаг (the FLAGS field gives which one)
 POSIXU             none       Некоторым [[:class:]] под /u; 
                               ставит один флаг (the FLAGS field gives which one)
 POSIXA             none       Некоторым [[:class:]] под /a; 
                               ставит один флаг (the FLAGS field gives which one)
 NPOSIXD            none       дополнение класса POSIXD, [[:^class:]] (его отрицание)
 NPOSIXL            none       дополнение класса POSIXL, [[:^class:]]
 NPOSIXU            none       дополнение класса POSIXU, [[:^class:]]
 NPOSIXA            none       дополнение класса POSIXA, [[:^class:]]

 CLUMP              no         Находит расширенную последовательность графема кластера -
                               (специальное юникодной комбинации - примечание переводчика)
                               (Match any extended grapheme cluster sequence)

 # Альтернатива (Alternation)

 # BRANCH        Совокупность веток(branches), образующих единый выбор
 #               связанный вместе с их "следующими" указателями, так
 #               приоритет предотвращает все, что объединено в
 #               любых отдельных ветвях. "Следующий" указатель последней
 #               ВЕТКИ в моменты выбора следует за
 #               всем выбором. Это также, где в финале "далее"
 #               указатель каждой отдельной точки ветвления; каждая ветвь
 #               начинается с узлом операнда узла ВЕТКИ.
 
 #
 BRANCH             node       Найдет эту альтернативу или следующую ...(Match this alternative, or the next)

 # Обратный указатель (Back pointer)

 # BACK          Нормальные указатели "next" все неявно указывают вперед;
 #               BACK существует, чтобы сделать возможной структуру цикла.
 # not used
 BACK               no         Найдет "", "next" ptr показывает назад.

 # Literals

 EXACT              str        Соответствует этой строке (ей предшествует длина). (Match this string (preceded by length).)
 EXACTF             str        Найдет эту не-UTF-8 строку (нет
                               гарантии сложения (to be folded)) используя /id правил
                               (w/len).
 EXACTFL            str        Найдёт эту строку (нет
                               гарантии сложения) используя /il правила (w/len).
 EXACTFU            str        Найдёт эту строку (сложенный iff в UTF-8,
                               длина при складывании не изменяется, если не
                               в UTF-8) используя /iu правила (w/len).
 EXACTFA            str        Найдёт эту строку (нет
                               гарантии сложения) используя /iaa правила (w/len).
 EXACTFU_SS         str        Найдёт эту строку (сложенный iff в UTF-8,
                               длина в сложенном состоянии может измениться, даже если не
                               в UTF-8) используя /iu правила (w/len).
 EXACTFU_TRICKYFOLD str        Найдет эту свернутую(folded) строку UTF-8, используя /iu
                               правила

 # Ничего не делать

 NOTHING            no         Соответствует пустой строке.
 # Вариант выше, который ограничивает группу, тем самым останавливает оптимизацию
 TAIL               no         Соответствует пустой строке. Может прыгать сюда из-
                               за пределов (Match empty string. Can jump here from
                               outside).

 # Циклы


 # STAR,PLUS    '?', И сложные '*' и '+', реализованы как
 #               круговые BRANCH структуры с использованием BACK. Простые случаи
 #               (один символ в поиске (per match)) реализованы с помощью STAR
 #               и PLUS для скорости и минимизации рекурсивных погружений (plunges).
 #

 STAR               node       Найдет эту (простую) вещь 0 или более раз
 PLUS               node       Найдет эту (простую) вещь 1 или более раз

 CURLY              sv 2       Найдет эту (простую) вещь {n,m} раз
 CURLYN             no 2       Захватит следующую после этого простую вещь (сapture next-after-this simple thing)
 CURLYM             no 2       Захватит эту средне-сложную вещь {n,m} раз.
 CURLYX             sv 2       Найдет эту сложную вещь {n,m} раз.

 # Этот терминатор(разделитель) создает структуру цикла для 
 WHILEM             no         Делайте кудрявую обработку и смотрите, остались ли данные для поиска.
                               (Do curly processing and see if rest matches.0

 # Связанные с буфером

 # OPEN,CLOSE,GROUPP     ...нумеруются во время компиляции.
 OPEN               num 1      Отметьте эту точку ввода как начало #n.
 CLOSE              num 1      Аналогично OPEN.

 REF                num 1      Соответствует некоторой уже найденной строке
 REFF               num 1      Найти уже найденную строку, свернутую
                               с использованием встроенной семантики кодировки для не-
                               utf8
 REFFL              num 1      Найти уже найденную строку, свернутую в
                               loc.
 REFFU              num 1      Найти уже найденную строку, свернутую
                               с использованием семантики Unicode для non-utf8
 REFFA              num 1      Найти уже найденную строку, свернутую
                               с использованием семантики Unicode для non-utf8, но
                               смешанную с ASCII, не-ASCII

 # Именованные ссылки. Код в regcomp.c предполагает, что все они после
 # пронумерованных ссылок
 NREF               no-sv 1    Найдет некоторую уже найденную строку
 NREFF              no-sv 1    Найти уже найденную строку, свернутую
                               с использованием встроенной семантики кодировки для не-
                               utf8
 NREFFL             no-sv 1    Найти уже найденную строку, свернутую в
                               loc.
 NREFFU             num 1      Найти уже найденную строку, свернутую
                               с использованием семантики Unicode для non-utf8
 NREFFA             num 1      Найти уже найденную строку, свернутую
                               с использованием семантики Unicode для non-utf8, но
                               смешанную с ASCII, не-ASCII

 IFMATCH            off 1 2    Успешно, если следующие совпадают.
 UNLESSM            off 1 2    Сбой, если следующие совпадают.
 SUSPEND            off 1 1    "Независимое" sub-RE (подрегулярное выражение).
 IFTHEN             off 1 1    Переключатель, которому должен предшествовать переключатель. (Switch, should be preceded by switcher.)
 GROUPP             num 1      Где находится группа. (Whether the group matched.)

 # Поддержка длинных RE

 LONGJMP            off 1 1    Прыгай далеко.
 BRANCHJ            off 1 1    BRANCH с длинным смещением.

 # Тяжелый рабочий (The heavy worker)

 EVAL               evl 1      Выполнить некоторый Perl-код.

 # Модификаторы

 MINMOD             no         Следующий оператор не жадный.
 LOGICAL            no         Следующий опкод должен устанавливать только флаг.

 # Это еще не используется
 RENUM              off 1 1    Группа с независимой нумерацией.

 # Связанные темы

 # Ведёт себя так же, как A|LIST|OF|WORDS. Варианты '..C' 
 # имеют встроенные данные charclass (только ascii), где 'C' хранит его
 # в составе.

 TRIE               trie 1     Найдет много EXACT(F[ALU]?)? один раз (at once).
                               flags==type
 TRIEC              trie       То же, что и TRIE, но со встроенным charclass

 AHOCORASICK        trie 1     Aho Corasick stclass. flags==type
 AHOCORASICKC       trie       То же, что и AHOCORASICK, но со встроенным charclass

 # Подпрограммы регулярных выражений (Regex Subroutines)
 GOSUB              num/ofs 2L рекурсия к родительскому arg1 на (подписанных) ofs arg2 (recurse to paren arg1 at (signed) ofs)
                               
 GOSTART            no         рекурсия к началу шаблона (recurse to start of pattern)

 # Специальные условия
 NGROUPP            no-sv 1    Соответствовала ли группа. (Whether the group matched.)
 INSUBP             num 1      Будем ли мы в конкретной рекурсии.
 DEFINEP            none 1     Никогда не выполняйте непосредственно.

 # Глаголы с отступами (Backtracking Verbs)
 ENDLIKE            none       Используется только для поля типа глагола (Used only for the type field of verbs)
 OPFAIL             none       Тоже, что и (?!)
 ACCEPT             parno 1    Принимает текущую найденную строку. (Accepts the current matched string.)


 # Глаголы с аргументами (Verbs With Arguments)
 VERB               no-sv 1    Используется только для поля типа глаголов (verbs)
 PRUNE              no-sv 1    Образец терпит неудачу в этой начальной точке, если нет возврата через этот 
                               (Pattern fails at this startpoint if no-
                               backtracking through this)
 MARKPOINT          no-sv 1    Нажмите текущее местоположение для отката путем вырезания. (Push the current location for rollback by
                               cut.)
 SKIP               no-sv 1    При отказе пропустить вперед (до отметки) перед повторной попыткой (On failure skip forward (to the mark)
                               before retrying)
 COMMIT             no-sv 1    Шаблон выходит из строя, если возврат (Pattern fails outright if backtracking
                               through this)
 CUTGROUP           no-sv 1    При сбое перейдите к следующему чередованию в группе (On failure go to the next alternation in
                               the group)

 # Контролируйте, что нужно держать в $&.
 KEEPS              no         $& начинается здесь.

 # Новые charclass(классы символов), похожие на шаблоны (New charclass like patterns)
 LNBREAK            none       создать шаблон начала строки (generic newline pattern)

 # СПЕЦИАЛЬНЫЕ РЕГУЛЯРКИ (SPECIAL  REGOPS)

# Это не совсем узел, а оптимизированный кусок "длинного" узла #. Для упрощения отладки, мы отмечаем его, как будто это был узел OPTIMIZED off Заполнителя для сброса.

# Специальные свойства операции(opcode), которые не код(opcode) в скомпилированной программе # никогда не будет этого типа. Таким образом, он может использоваться в качестве значения флага, что # никакие другие операции(opcode) не видно. END используется аналогичным образом, в том, что END # узел не может быть оптимизирован. Так что END предполагает "неоптимизируемость" "unoptimizable" и PSEUDO # в смысле "не видел ничего, чтобы оптимизировать". PSEUDO off Pseudo код для внутреннего использования.

Следующим оптимизатором информация представляет собой дамп смещение/длина стола, здесь разделены на несколько линий:

  Offsets: [45]
        1[4] 0[0] 0[0] 0[0] 0[0] 0[0] 0[0] 0[0] 0[0] 0[0] 0[0] 5[1]
        0[0] 12[1] 0[0] 6[1] 0[0] 7[1] 0[0] 9[1] 8[1] 0[0] 10[1] 0[0]
        11[1] 0[0] 12[0] 12[0] 13[1] 0[0] 14[4] 0[0] 0[0] 0[0] 0[0]
        0[0] 0[0] 0[0] 0[0] 0[0] 0[0] 18[1] 0[0] 19[1] 20[0]  

Первая строка указывает на то, что таблица смещений/длин содержит 45 записей. Каждая запись является парой чисел(integers), обозначается смещение[длина] (offset[length].). Записи нумеруются начиная с 1, поэтому запись #1 вот это 1[4] и запись #12 это С<5[1]>. С<1[4]> указывает, что узел, обозначенный как 1: (1: что-нибудь из[до н. э.])(the 1: ANYOF[bc]) начинается в позиции символа 1 в предварительно скомпилированном виде регулярного выражения, и имеет длину 4 символа. С<5[1]> в положении 12 указывает, что узел, обозначенный как c<12:> (12: точные <д>)(the 12: EXACT <d>) начинается на символ 5 в предварительно скомпилированном виде регулярного выражения, и имеет длину 1 символ. С<12[1]> в позиции 14 указывает, что узел, обозначенный как 14: (14: CURLYX[0] {1,32767}) начинается в позиции знака 12 В предварительно скомпилированном виде регулярного выражения, и имеет длину 1 символ - - -, что является, оно соответствует + символ в предварительно скомпилированном регулярном выражении (in the precompiled regex)

С<0[0]> элементы указывают на то, что нет соответствующего узла.

Вывод времени выполнения (Run-time Output)

В первую очередь, когда происходит совпадение, может не быть времени на output даже если включена отладка. Это означает, что регулярное выражение никогда не вошло , и поэтому вся работа была сделана оптимизатором.

Если регулярное выражение было введено, то на выходе может выглядеть следующим образом:

  Matching '[bc]d(ef*g)+h[ij]k$' against 'abcdefg__gh__'
    Setting an EVAL scope, savestack=3
     2 <ab> <cdefg__gh_>    |  1: ANYOF
     3 <abc> <defg__gh_>    | 11: EXACT <d>
     4 <abcd> <efg__gh_>    | 13: CURLYX {1,32767}
     4 <abcd> <efg__gh_>    | 26:   WHILEM
                                0 out of 1..32767  cc=effff31c
     4 <abcd> <efg__gh_>    | 15:     OPEN1
     4 <abcd> <efg__gh_>    | 17:     EXACT <e>
     5 <abcde> <fg__gh_>    | 19:     STAR
                             EXACT <f> can match 1 times out of 32767...
    Setting an EVAL scope, savestack=3
     6 <bcdef> <g__gh__>    | 22:       EXACT <g>
     7 <bcdefg> <__gh__>    | 24:       CLOSE1
     7 <bcdefg> <__gh__>    | 26:       WHILEM
                                    1 out of 1..32767  cc=effff31c
    Setting an EVAL scope, savestack=12
     7 <bcdefg> <__gh__>    | 15:         OPEN1
     7 <bcdefg> <__gh__>    | 17:         EXACT <e>
       restoring \1 to 4(4)..7
                                    failed, try continuation...
     7 <bcdefg> <__gh__>    | 27:         NOTHING
     7 <bcdefg> <__gh__>    | 28:         EXACT <h>
                                    failed...
                                failed...

Наиболее существенная информация в выводе о том, что узел (node) скомпилированного регулярного выражения в настоящее время тестируется в отношении к целевой строке. Формат этих строк

STRING-OFFSET <PRE-STRING> <POST-STRING> |ID: TYPE

Информация о ТИПЕ (TYPE) форматируется относительно уровне трекинга (backtracking level). Другая информация об инциденте появляется и пересекается внутри.

Использования Памяти при Отладке в Perl (Debugging Perl Memory Usage)

Perl-это распутный бездельник, когда дело доходит до использования памяти. Говорят, чтобы оценить использование памяти в Perl нужно подразумевать разумный алгоритм выделения памяти, умножить эту оценку на 10, и хотя вы можете промазать, но по крайней мере, вы не будете так удивлены. Это не совсем так, но может обеспечить хорошее понимание о том, что происходит.

Предположим, что целое число(integer) не может принимать меньше 20 байт памяти, a плавающее(float) не может занимать менее 24 байт, а строка(string) не может занимать меньше 32 байта (все эти примеры предполагают 32-разрядные архитектуры, результат немного хуже на 64-битных архитектурах). Если к переменной осуществляется доступ двумя из трех различных способов (для которых требуется целое число(integer), плавающее(float), или строку(string)), объем памяти возможно увеличить еще на 20 байт. Неаккуратная реализация функции malloc(3) может раздуть эти значения драматически.

На противоположном конце шкалы, объявление

  sub foo;

может потребовать до 500 байт памяти, в зависимости от версии языка Perl под которым вы запускаетесь.

Анекдотические оценки наворотов кода для копиляции (source-to-compiled) предполагают 8-кратное увеличение. Это означает, что скомпилированная форма разумного (хорошо скомментированного, с правильно отступом и т. д.) кода возьмёт принял примерно в восемь раз больше места в памяти, чем код на диске.

Переключатель командной строки -DL устарел начиная с 5.6.0 (он был доступен, только если Perl был построен c -DDEBUGGING). Этот ключ использовался для отслеживания распределения памяти в Perl и возможной утечки памяти. В наши дни для отладки использования malloc вместо этого предлагаются такие инструменты, как Purify или valgrind. Смотрите также "PERL_MEM_LOG" in perlhacktips.

Один из способов узнать, сколько памяти используется данными Perl структуры - установить модуль Devel::Size из CPAN: он дает вам минимальное количество байтов, необходимых для хранения определенных данных. Помните о различии между size() и total_size ().

Если Perl был скомпилирован с использованием malloc Perl, вы можете проанализировать использования памяти Perl, задав $ENV{PERL_DEBUG_MSTATS}.

С помощью $ENV{PERL_DEBUG_MSTATS}

Если ваш perl использует malloc() и был скомпилирован с необходимые переключатели (это значение по умолчанию), то после этого он напечатает память статистики использования после компиляции кода, когда $ENV{PERL_DEBUG_MSTATS} > 1, и до окончания программы, когда $ENV{PERL_DEBUG_MSTATS} >= 1. Формат отчета похож на следующий пример:

  $ PERL_DEBUG_MSTATS=2 perl -e "require Carp"
  Статистика выделения памяти после компиляции: (buckets 4(4)..8188(8192)
     14216 free:   130   117    28     7     9   0   2     2   1 0 0
                437    61    36     0     5
     60924 used:   125   137   161    55     7   8   6    16   2 0 1
                 74   109   304    84    20
  Total sbrk(): 77824/21:119. Odd ends: pad+heads+chain+tail: 0+636+0+2048.
  Статистика выделения памяти после выполнения:   (buckets 4(4)..8188(8192)
     30888 free:   245    78    85    13     6   2   1     3   2 0 1
                315   162    39    42    11
    175816 used:   265   176  1112   111    26  22  11    27   2 1 1
                196   178  1066   798    39
  Total sbrk(): 215040/47:145. Odd ends: pad+heads+chain+tail: 0+2192+0+6144.
  

Можно попросить такую статистику в произвольных точках при выполнении с использованием функции mstat() вне стандарта модуля Devel::Peek.

Вот некоторые объяснения этого формата:

buckets SMALLEST(APPROX)..GREATEST(APPROX)

В Perl функция malloc() использует распределение по периодам. Каждый запрос округляется до ближайшего размера бакета, и бакет извлекается из пула бакетов такого размера.

В приведенной выше строке описаны пределы используемых в настоящее время бакетов. Каждый бакет имеет два размера: объем памяти и максимальный размер пользовательских данных, которые могут поместиться в бакет. Предположим, в приведенном выше примере, чтобы наименьший бакет было размером 4. Самый большой бакет имел бы полезный размер 8188, и след памяти был бы 8192.

В Perl, скопилирлованном для отладки, некоторые бакеты могут иметь отрицательное использование размера. Это означает, что эти бакеты не могут (и не будут) использоваться. Для больших контейнеров объем памяти может быть на одну страницу больше чем квадрат 2(power of 2). Если это так, соответствующая сила двух печатает в поле APPROX выше.

Свободный/используемый (Free/Used)

1 или 2 строки чисел, которые соответствуют числу пакетов (бакетов) каждый размер между НАИМЕНЬШИМ и НАИБОЛЬШИМ. В первой строке, размеры (следы памяти) пакетов сильны из двух--или, возможно, на одну страницу больше. Во второй строке, если имеется, следы памяти пакетов находятся между следами памяти из двух пакетов "выше".

Например, предположим, что в предыдущем примере, следы памяти(memory footprints) были

     свободно:    8     16    32    64    128  256 512 1024 2048 4096 8192
           4     12    24    48    80

С не-DEBUGGING perl, пачки (buckets) начинающиеся с 128 имеют 4-байтовые накладные расходы, и, таким образом, 8192-длинная пачка может занять до 8188-байт.

Total sbrk(): SBRKed/SBRKs:CONTINUOUS

Первые два поля дают общий объем памяти в Perl сбрк(2)Эд (есс-сломался? :-) и количество сбрк(2)использованных. Третий номер то, что Perl думает о продолжительном возвращении кусками. Пока это число является положительным, malloc() будет предполагать, что такое возможно что сбрк(2) будет обеспечивать продолженную память.

Память, выделенная с помощью внешних библиотек не учитывается.

pad: 0

Количество sbrk(2)(linux комманда - изменить размер сегмента данных) памяти, необходимой для поддержания выравненных пачек(needed to keep buckets aligned).

heads: 2192

Хотя память больших пачках хранится внутри пачки(bucket), для меньших пакетов она хранится в отдельных зонах. Это поле дает общую площадь этих участков.

chain: 0

функции malloc() может хотеть разделить большой пакет на мелкие пакеты. Если только часть умершего пакета осталась неразделенная, остальные хранятся как элемент связанного списка. Это поле дает общий размер этих блоков.

tail: 6144

Чтобы свести к минимуму количество сбрк(2)с(sbrk(2)s) функциями malloc() запрашивает больше памяти. Это поле дает Размер еще неиспользованной части, которая сбрк(2)Эд(sbrk(2)ed), собрана но никогда не трогалась.

СМОТРЕТЬ ТАКЖЕ

perldebug, perlguts, perlrun re, and Devel::DProf.

ПЕРЕВОДЧИКИ

  • Николай Мишин <mi@ya.ru>