предел длины perlre - PullRequest
       1

предел длины perlre

6 голосов
/ 04 января 2011

С man perlre:

Квантор "*" эквивалентен "{0,}", квантификатор "+" - "{1,}" и "?" квантификатор "{0,1}". n и m ограничены целочисленными значениями, которые меньше заданного предела, определенного при сборке perl. Обычно это 32766 на самых распространенных платформах. Фактический предел можно увидеть в сообщении об ошибке, сгенерированном с помощью такого кода:

       $_ **= $_ , / {$_} / for 2 .. 42;

Да, это уродливо - разве я не могу получить какую-то константу?

Редактировать: Как указал даксим (и perlretut намекает на это), возможно, 32767 - это магически закодированное число. Небольшой поиск в коде Perl имеет большое значение, но я не уверен, как перейти к следующему шагу и выяснить, где на самом деле установлены значения по умолчанию reg_infty или REG_INFTY:

~/dev/perl-5.12.2
$ grep -ri 'reg_infty.*=' *
regexec.c:      if (max != REG_INFTY && ST.count == max)
t/re/pat.t:        $::reg_infty   = $Config {reg_infty} // 32767;
t/re/pat.t:        $::reg_infty_m = $::reg_infty - 1;
t/re/pat.t:        $::reg_infty_p = $::reg_infty + 1;
t/re/pat.t:        $::reg_infty_m = $::reg_infty_m;   # Surpress warning.

Редактировать 2: DVK, конечно, прав: это define d во время компиляции, и, вероятно, может быть переопределено только с REG_INFTY.

1 Ответ

8 голосов
/ 04 января 2011

Резюме: есть 3 способа найти предел: эмпирический, «сопоставление тестов Perl» и «теоретический».

  • Эмпирический:

    eval {$_ **= $_ , / {$_} / for 2 .. 129};
    # To be truly portable, the above should ideally loop forever till $@ is true.
    $@ =~ /bigger than (-?\d+) /; 
    print "LIMIT: $1\n"'
    

    Это кажется достаточно очевидным, что не требует объяснения.

  • Соответствует тестам Perl:

    Perl имеет ряд тестов для регулярных выражений, некоторые из которых (в pat.t) разобраться с проверкой этого максимального значения.Итак, вы можете приблизить, что максимальное значение, вычисленное в этих тестах, «достаточно хорошо» и следовать логике теста:

    use Config;
    $reg_infty = $Config {reg_infty} // 2 ** 15 - 1; # 32767
    print "Test-based reg_infinity limit: $reg_infty\n";
    

    Объяснение того, где в тестах это основано, приведено ниже.

  • Теоретический: Это попытка воспроизвести логику EXACT, используемую кодом C для генерации этого значения.

    Это звучит сложнее, потому что на него влияют 2 вещи: Конфигурация сборки Perl и куча операторов C #define с логикой ветвления.Мне удалось довольно глубоко вникнуть в эту логику, но я застрял в двух проблемах: #ifdefs ссылается на набор токенов, которые фактически не определены нигде в коде Perl, который я могу найти - и я не знаю, как найтиизнутри Perl, что это были за значения define s, и конечное значение по умолчанию (при условии, что я прав, и эти #ifdef s всегда заканчиваются значением по умолчанию) #define PERL_USHORT_MAX ((unsigned short)~(unsigned)0) (фактический предел получается путем удаления 1откусил полученный итоговый номер - подробности ниже).

    Я также не уверен, как получить доступ к количеству байтов в short из Perl для любой реализации, использованной для создания perl исполняемого файла.

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

Ниже я приведу подробную информацию о том, где различные кусочки логики, связанные с этим пределом, живут в коде Perl, а также мои попыткичтобы прийти к «Теоретически правильному» решению, совпадающему с логикой C.


Хорошо, вот часть исследования, часть способа, вы можете завершить его самостоятельно, как я выполнил, или я выполню позже:

  • С regcomp.c: vFAIL2("Quantifier in {,} bigger than %d", REG_INFTY - 1);

    Итак, предел, очевидно, взят из REG_INFTY define.Который объявлен в:

  • rehcomp.h:

     /* XXX fix this description.
        Impose a limit of REG_INFTY on various pattern matching operations
        to limit stack growth and to avoid "infinite" recursions.
     */
     /* The default size for REG_INFTY is I16_MAX, which is the same as
        SHORT_MAX (see perl.h).  Unfortunately I16 isn't necessarily 16 bits
        (see handy.h).  On the Cray C90, sizeof(short)==4 and hence I16_MAX is
        ((1<<31)-1), while on the Cray T90, sizeof(short)==8 and I16_MAX is
        ((1<<63)-1).  To limit stack growth to reasonable sizes, supply a
        smaller default.
             --Andy Dougherty  11 June 1998
     */
     #if SHORTSIZE > 2
     #  ifndef REG_INFTY
     #    define REG_INFTY ((1<<15)-1)
     #  endif
     #endif
     #ifndef REG_INFTY
     #  define REG_INFTY I16_MAX
     #endif
    

    Обратите внимание, что SHORTSIZE можно переопределить через Config - я уйдуподробности об этом, но логика должна будет включать $Config{shortsize}:)

  • Из handy.h (на первый взгляд это не является частью исходного кода Perl, поэтому выглядиткак ненадежный шаг):

     #if defined(UINT8_MAX) && defined(INT16_MAX) && defined(INT32_MAX)
     #define I16_MAX INT16_MAX
     #else
     #define I16_MAX PERL_SHORT_MAX
    
  • Я не смог найти ЛЮБОЙ место, которое определило INT16_MAX вообще: (

    Кто-то поможетпожалуйста !!!

  • PERL_SHORT_MAX определен в perl.h:

     #ifdef SHORT_MAX
     #  define PERL_SHORT_MAX ((short)SHORT_MAX)
     #else
     #  ifdef MAXSHORT    /* Often used in <values.h> */
     #    define PERL_SHORT_MAX ((short)MAXSHORT)
     #  else
     #    ifdef SHRT_MAX
     #      define PERL_SHORT_MAX ((short)SHRT_MAX)
     #    else
     #      define PERL_SHORT_MAX      ((short) (PERL_USHORT_MAX >> 1))
     #    endif
     #  endif
     #endif
    

    Мне не удалось найти место, которое определило бы SHORT_MAX, MAXSHORT или SHRT_MAX такдалеко. Таким образом, по умолчанию ((short) (PERL_USHORT_MAX >> 1)) предполагается, что на данный момент:)

  • PERL_USHORT_MAX определено очень похоже в perl.h, и снова я не смог найти следопределение USHORT_MAX / MAXUSHORT / USHRT_MAX.

    Из этого следует, что по умолчанию установлено: #define PERL_USHORT_MAX ((unsigned short)~(unsigned)0).Как извлечь это значение со стороны Perl, я понятия не имею - это в основном число, которое вы получаете, поразрядно отрицая короткий 0, поэтому, если беззнаковый короткий равен 16 байтов, то PERL_USHORT_MAX будет 16 единиц, а PERL_SHORT_MAX будет15 единиц, например 2 ^ 15-1, например 32767.

  • Также из t/re/pat.t (тесты регулярных выражений): $::reg_infty = $Config {reg_infty} // 32767; (чтобы проиллюстрировать, гдезначение, скомпилированное в значение по умолчанию, сохраняется).

Итак, чтобы получить свою константу, вы делаете:

use Config;
my $shortsize = $Config{shortsize} // 2;
$c_reg_infty = (defined $Config {reg_infty}) ? $Config {reg_infty}
                                             : ($shortsize > 2) ? 2**16-1
                                             : get_PERL_SHORT_MAX();
# Where get_PERL_SHORT_MAX() depends on logic for PERL_SHORT_MAX in perl.h
# which I'm not sure how to extract into Perl with any precision
# due to a bunch of never-seen "#define"s and unknown size of "short".
# You can probably do fairly well by simply returning 2**8-1 if shortsize==1 
# and 2^^16-1 otherwise.
say "REAL reg_infinity based on C headers: $c_reg_infty";
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...