Tipos de Escalares Perl

El tipo enumerado svtype enuncia los tipos de escalar:
nereida:~/Lperl-5.9.4> sed -ne '46,64p' sv.h | cat -n
 1  typedef enum {
 2    SVt_NULL,  /* 0  Usado para undef */ 
 3    SVt_IV,    /* 1  Entero */
 4    SVt_NV,    /* 2  Flotante */
 5    SVt_RV,    /* 3  Referencia */
 6    SVt_PV,    /* 4  Cadena */
 7    SVt_PVIV,  /* 5  Cadena o Entero */
 8    SVt_PVNV,  /* 6  Cadena o Flotante */
 9    SVt_PVMG,  /* 7  Objeto o escalar mágico */
10    SVt_PVBM,  /* 8  Como SVt_PVMG: si es cadena usa Boyer-Moore para las búsquedas */
11    SVt_PVGV,  /* 9  Typeglob */
12    SVt_PVLV,  /* 10 Varios tipos con conducta Lvalue */
13    SVt_PVAV,  /* 11 Array */
14    SVt_PVHV,  /* 12 Hash */
15    SVt_PVCV,  /* 13 Código */
16    SVt_PVFM,  /* 14 Formato */
17    SVt_PVIO,  /* 15 Manejador de ficheros */
18    SVt_LAST   /* keep last in enum. used to size arrays */
19  } svtype;
En la jerga, estos tipos son conocidos como IV, NV, PV, etc. Nótese que arrays y hashes son formas de SVs. Existe toda una familia de funciones con nombres SvIV, SvNV, SvPV, etc para leer un escalar (SV) como entero, flotante, cadena, etc. El siguiente código muestra el uso de algunas de estas funciones de acceso:
lhp@nereida:~/Lperl/src/XSUB/inline$ cat -n dump_values.pl
 1  #!/usr/local/bin/perl -w
 2  use strict;
 3  use Inline C => <<'EOC';
 4  void dump_scalar(SV * sv) {
 5
 6    printf("Flotante: %f\n", SvNV(sv));
 7    printf("Entero: %i\n", SvIV(sv));
 8    printf("Cadena: %s\n", SvPV_nolen(sv));
 9    printf("Longitud de la cadena: %i\n", SvCUR(sv));
10    printf("Longitud del espacio asignado para la cadena: %i\n", SvLEN(sv));
11  }
12  EOC
13
14  my $a = "123.53";
15  dump_scalar($a)
El caso de las cadenas es mas complejo: se puede acceder a la longitud de la cadena mediante la macro SvCUR y a la longitud de su buffer mediante la macro SvLEN. Al ejecutar el programa anterior obtenemos la salida:
lhp@nereida:~/Lperl/src/XSUB/inline$ dump_values.pl
Flotante: 123.530000
Entero: 123
Cadena: 123.53
Longitud de la cadena: 6
Longitud del espacio asignado para la cadena: 8

Existe una familia de funciones sv_setiv, sv_setnv, sv_setpv, etc. que permiten la modificación del escalar. Por ejemplo:

lhp@nereida:~/projects/perl/src/XSUB/inline$ cat -n set_values.pl
 1  #!/usr/local/bin/perl -w
 2  use strict;
 3  use Inline C => <<'EOC';
 4  void set_string(SV * sv) {
 5    char h[256];
 6    printf("Input: ");
 7    scanf("%s", &h);
 8    sv_setpv(sv, h);
 9  }
10  EOC
11
12  my $a;
13  set_string($a);
14  print "$a\n";

Casiano Rodríguez León
2010-03-22
nv)

Empuja un doble en la pila. La pila debe tener espacio para este elemento.

  • PUSHp Prototipo: void PUSHp(char* str, STRLEN len)

    Empuja una cadena en la pila. La pila debe tener espacio para la misma. len es la longitud de la cadena.

  • PUSHs Prototipo: void PUSHs(SV* sv)

    Empuja un escalar en la pila. La pila debe tener espacio para este elemento.

  • PUSHu Prototipo: void PUSHu(UV uv)

    Empuja un entero sin signo en la pila. La pila debe tener espacio para este elemento.

  • En la línea 20 se usan dos funciones de la API de Perl. La función newSViv tiene el prototipo SV* newSViv(IV i). Crea un nuevo valor escalar y lo inicializa con el entero en i. El contador de referencia del nuevo escalar se pone a 1.

    La función sv_2mortal marca el SV como mortal: El SV será destruido cuando termine el contexto de la subrutina. La función tiene el prototipo SV* sv_2mortal(SV* sv). Si no llamáramos a esta función la memoria alojada nunca sería liberada y se produciría una pérdida (leak).

  • Procedamos ahora a estudiar la subrutina matches.

    25  void
    26  matches(number, ...)
    27          long number
    28      PROTOTYPE: $@
    29      INIT:
    30          long base[items], cmp[items], prev_base[items];
    31          long b, c, i, p = 0;
    32          bool Skip_multiple, skip = 0;
    33          SV* skip_multiple;
    34          AV* match;
    35      PPCODE:
    36          skip_multiple = get_sv("Math::Factor::XS::Skip_multiple", FALSE);
    37          Skip_multiple = skip_multiple != NULL ? SvIV(skip_multiple) : 0;
    38          for (i = 0; i < items; i++) {
    39              base[i] = SvIV(ST(i));
    40              cmp[i]  = SvIV(ST(i));
    41          }
    42          for (b = 0; b < items; b++) {
    43              for (c = 0; c < items; c++) {
    44                  if (cmp[c] >= base[b] && base[b] * cmp[c] == number) {
    45                      if (Skip_multiple) {
    46                          skip = 0;
    47                          for (i = 0; i < p; i++) {
    48                              if (base[b] % prev_base[i] == 0) skip = 1;
    49                          }
    50                      }
    51                      if (!skip) {
    52                          match = (AV*)sv_2mortal((SV*)newAV());
    53                          av_push(match, newSViv(base[b]));
    54                          av_push(match, newSViv(cmp[c]));
    55                          EXTEND(SP,2);
    56                          PUSHs(sv_2mortal(newRV((SV*)match)));
    57                          if (Skip_multiple) {
    58                              prev_base[p++] = base[b];
    59                          }
    60                      }
    61                  }
    62              }
    63          }
    

    1. En la línea 34 declaramos match como un puntero al tipo Perl array value denotado por AV.

    2. La línea 36
      skip_multiple = get_sv("Math::Factor::XS::Skip_multiple", FALSE)
      
      nos muestra como obtener el valor de una variable escalar de paquete. El formato de llamada de get_sv es SV* get_sv(const char* name, I32 create). Si la variable Perl no existe y el parámetro create está a 1 la variable será creada. Si create está a 0 y la variable Perl no existe se devuelve NULL.

    3. En las líneas 38-40 se inicializan los arrays base y cmp con las valores escalares enteros de los índices del array.

      La función IV SvIV(SV* sv) y NV SvNV(SV* sv) encorseta el SV al tipo entero.

    4. En la línea 52 se crea un nuevo array value (AV) usando newAV . Esta función tiene el prototipo AV* newAV(). Además de crearlo pone el contador de referencias a 1. Estamos creando así una referencia a un array. Para darle un ámbito léxico llamamos a la función sv_2mortal , la cual hace que el SV sea destruido cuando termine el contexto de la subrutina. Si no llamáramos a esta función la memoria alojada nunca sería liberada y se produciría una pérdida (leak).

    5. En las líneas 53 y 54 usamos av_push para apilar los dos factores en el array apuntado por match La función void av_push(AV* ar, SV* val) además de apilar el valor apuntado por val hace que el array ar crezca automáticamente haciendo espacio para el nuevo valor.

    6. En la línea 56 La macro PUSHs empuja el valor escalar newRV((SV*)match en la pila.

    Casiano Rodríguez León
    2010-04-20
    HREF="node355.html"> index PP2PP2 moodlepsmodulosperlmonksperldocperlcriticpbpgoogle code project hostingintro a PerlModern Perlblogsgoogleetsiiullpcgull
    Sig: Wheels (part 2) Sup: A Non Forking Echo Ant: Mapping our server to
    Casiano Rodríguez León
    2011-03-18