2011-01-04 9 views
6

De man perlre: "?"perlre límite de longitud

El "*" cuantificador es equivalente a "{0,}", el cuantificador "+" a "{1,}", y el cuantificador a "{0,1}". nym están limitados a valores integrales menores que un límite preestablecido definido cuando se construye perl. Esto es usualmente 32766 en las plataformas más comunes. El límite real se puede ver en el mensaje de error generado por el código como este:

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

Ay eso es feo - ¿No hay alguna constante que puedo conseguir en su lugar?

Editar: Como señaló daxim (y perlretut insinuaciones hacia) podría ser que 32767 es un número mágico codificado. Un poco searching en el código Perl va un largo camino, pero no estoy seguro de cómo llegar al siguiente paso y, de hecho localizar el origen del defecto o reg_infty REG_INFTY es en realidad establecen:

~/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. 

Edición 2: DVK por supuesto, es correcto: es define d en tiempo de compilación, y probablemente solo se puede sobrescribir con REG_INFTY.

+5

Véase también http://perl.plover.com/yak/regex/samples/slide050.html – daxim

+0

@daxim: Creo tienes una respuesta completa allí, no solo un comentario. "Incluso si conociera el límite, no sería un número útil para saber porque el motor de expresiones regulares probablemente moriría antes de que alcanzara el límite teórico". –

Respuesta

8

Resumen: hay 3 formas en que puedo pensar para encontrar el límite: empíricos, "encajando pruebas de Perl" y "teórico".

  • empírica:

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

    esto parece bastante obvio que no requiere explicación.

  • Coincide prueba Perl:

    Perl tiene una serie de pruebas para la expresión regular, algunos de los cuales (en pat.t) tratan de las pruebas de este valor máximo. Por lo tanto, se puede aproximar que el valor máximo calculado en estas pruebas es "suficientemente bueno" y sigue la lógica de la prueba:

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

    La explicación de dónde en las pruebas de esto se basa fuera de está en los detalles a continuación.

  • teórico: Este está tratando de replicar la lógica exacto utilizado por el código C para generar este valor.

    Esto es más difícil de lo que parece, porque se ve afectado por dos cosas: la configuración de compilación Perl y un montón de sentencias C #define con lógica de bifurcación. Pude profundizar bastante en esa lógica, pero me quedé estancado en dos problemas: el #ifdefs hace referencia a un grupo de tokens que NO están realmente definidos en ningún lugar del código Perl que pueda encontrar, y no sé cómo averiguarlo. Perl dentro de lo que eran los valores define s, y el valor predeterminado final (suponiendo que tengo razón y esos #ifdef s siempre termino con el valor por defecto) de #define PERL_USHORT_MAX ((unsigned short)~(unsigned)0) (el límite real se incorpora mediante la eliminación de 1 bit que fuera número resultante de todos unos - detalles abajo).

    Tampoco estoy seguro de cómo acceder a la cantidad de bytes en short de Perl para la implementación que se usó para compilar el ejecutable perl.

    Por lo tanto, incluso si la respuesta a ambas preguntas se puede encontrar (que no estoy seguro), la lógica resultante sería sin duda más "fea" y más compleja que la simple "empírica basada en la evaluación" Ofrecí como primera opción.

A continuación voy a dar los detalles de donde varios fragmentos de la lógica relacionada a este límite en vivo en el código Perl, así como mis intentos para llegar a la lógica solución adecuada C "teóricamente correcto".


OK, aquí es de alguna manera parte de investigación, puede completarlo por sí mismo ya que tengo ejecución Ti o voy a completar más adelante:

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

    Por lo tanto, la El límite obviamente se toma de REG_INFTY define. Las cuales se declara en:

  • 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 
    

    Tenga en cuenta que SHORTSIZE es reemplazable por medio Config - Voy a dejar los detalles de eso, pero la lógica tendrá que incluir $Config{shortsize} :)

  • Desde handy.h (esto no parece ser parte de la fuente Perl a primera vista, por lo que parece un paso dudoso):

    #if defined(UINT8_MAX) && defined(INT16_MAX) && defined(INT32_MAX) 
    #define I16_MAX INT16_MAX 
    #else 
    #define I16_MAX PERL_SHORT_MAX 
    
  • no pude encontrar CUALQUIER lugar que definió INT16_MAX en absoluto :(

    Alguien ayuda por favor !!!

  • PERL_SHORT_MAX se define en 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 
    

    yo no era capaz de encontrar cualquier lugar que definió SHORT_MAX, MAXSHORT o SHRT_MAX hasta ahora. Por lo que el valor predeterminado de ((short) (PERL_USHORT_MAX >> 1)) que se supone que es por ahora :)

  • PERL_USHORT_MAX se define de manera muy similar en perl.h, y otra vez no pude encontrar un rastro de definición de USHORT_MAX/MAXUSHORT/USHRT_MAX.

    Lo que parece implicar que está configurado por defecto en: #define PERL_USHORT_MAX ((unsigned short)~(unsigned)0). Cómo extraer ese valor del lado de Perl, no tengo ni idea - es básicamente un número que obtienes por bit negando un corto 0, entonces si el corto sin firmar tiene 16 bytes, entonces PERL_USHORT_MAX serán 16 unidades, y PERL_SHORT_MAX serán 15 unidades, p. 2^15-1, p. 32767.

  • También, desde t/re/pat.t (pruebas de expresión regular): $::reg_infty = $Config {reg_infty} // 32767; (para ilustrar dónde se almacena el valor no compilado en valor se almacena).

Por lo tanto, para obtener su constante, que hace:

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"; 
+0

El código abierto es como la ciencia: ¡todos obtenemos los mismos resultados! : D – l0b0

+0

OK, en este punto creo que llegué al final de mi conocimiento de las partes internas de Perl: alguien con más pistas, por favor, síganme y OP sobre cómo encontrar los valores correctos para 'PERL_SHORT_MAX' y' INT16_MAX' define desde dentro de Perl si eso es posible. – DVK

+0

Lo mejor que pude pensar fue 'Devel-PPPort/parts/inc/limits', pero eso parece un enfoque equivocado – DVK

Cuestiones relacionadas