Резюме: есть 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";