xsubpp
en su labor de traducir dos pasos importantes:
Existe un fichero typemap por defecto
el cuál describe el proceso de conversión para los tipos
mas comunes.
El fichero de typemap usado por defecto puede obtenerse ejecutando
el siguiente inline:
pp2@nereida:~$ perl -MConfig -le 'print "$Config{installprivlib}/ExtUtils/typemap"'
/usr/share/perl/5.8/ExtUtils/typemap
Veamos un esquema del contenido del fichero typemap.
Las elipsis corresponden a zonas suprimidas del fichero.
pp2@nereida:~$ cat -n /usr/share/perl/5.8/ExtUtils/typemap
1 # basic C types
2 int T_IV
3 unsigned T_UV
4 unsigned int T_UV
5 long T_IV
6 unsigned long T_UV
7 short T_IV
8 unsigned short T_UV
9 char T_CHAR
10 unsigned char T_U_CHAR
11 char * T_PV
12 unsigned char * T_PV
13 const char * T_PV
14 caddr_t T_PV
.. ....... .....
43 Boolean T_BOOL
44 float T_FLOAT
45 double T_DOUBLE
46 SysRet T_SYSRET
47 SysRetLong T_SYSRET
48 FILE * T_STDIO
49 PerlIO * T_INOUT
50 FileHandle T_PTROBJ
51 InputStream T_IN
52 InOutStream T_INOUT
53 OutputStream T_OUT
54 bool T_BOOL
55
56 #############################################################################
57 INPUT
58 T_SV
59 $var = $arg
60 T_SVREF
61 if (SvROK($arg))
62 $var = (SV*)SvRV($arg);
63 else
64 Perl_croak(aTHX_ \"$var is not a reference\")
65 T_AVREF
66 if (SvROK($arg) && SvTYPE(SvRV($arg))==SVt_PVAV)
67 $var = (AV*)SvRV($arg);
68 else
69 Perl_croak(aTHX_ \"$var is not an array reference\")
70 T_HVREF
71 if (SvROK($arg) && SvTYPE(SvRV($arg))==SVt_PVHV)
72 $var = (HV*)SvRV($arg);
73 else
74 Perl_croak(aTHX_ \"$var is not a hash reference\")
75 T_CVREF
76 if (SvROK($arg) && SvTYPE(SvRV($arg))==SVt_PVCV)
77 $var = (CV*)SvRV($arg);
78 else
79 Perl_croak(aTHX_ \"$var is not a code reference\")
80 T_SYSRET
81 $var NOT IMPLEMENTED
82 T_UV
83 $var = ($type)SvUV($arg)
84 T_IV
85 $var = ($type)SvIV($arg)
86 T_INT
87 $var = (int)SvIV($arg)
88 T_ENUM
89 $var = ($type)SvIV($arg)
90 T_BOOL
91 $var = (bool)SvTRUE($arg)
92 T_U_INT
93 $var = (unsigned int)SvUV($arg)
... ..............................
110 T_DOUBLE
111 $var = (double)SvNV($arg)
112 T_PV
113 $var = ($type)SvPV_nolen($arg)
114 T_PTR
115 $var = INT2PTR($type,SvIV($arg))
... ................................
193 #############################################################################
194 OUTPUT
195 T_SV
196 $arg = $var;
197 T_SVREF
198 $arg = newRV((SV*)$var);
199 T_AVREF
200 $arg = newRV((SV*)$var);
201 T_HVREF
202 $arg = newRV((SV*)$var);
203 T_CVREF
204 $arg = newRV((SV*)$var);
205 T_IV
206 sv_setiv($arg, (IV)$var);
207 T_UV
208 sv_setuv($arg, (UV)$var);
209 T_INT
210 sv_setiv($arg, (IV)$var);
211 T_SYSRET
212 if ($var != -1) {
213 if ($var == 0)
214 sv_setpvn($arg, "0 but true", 10);
215 else
216 sv_setiv($arg, (IV)$var);
217 }
218 T_ENUM
219 sv_setiv($arg, (IV)$var);
220 T_BOOL
221 $arg = boolSV($var);
222 T_U_INT
223 sv_setuv($arg, (UV)$var);
224 T_SHORT
225 sv_setiv($arg, (IV)$var);
226 T_U_SHORT
227 sv_setuv($arg, (UV)$var);
228 T_LONG
229 sv_setiv($arg, (IV)$var);
230 T_U_LONG
231 sv_setuv($arg, (UV)$var);
232 T_CHAR
233 sv_setpvn($arg, (char *)&$var, 1);
234 T_U_CHAR
235 sv_setuv($arg, (UV)$var);
236 T_FLOAT
237 sv_setnv($arg, (double)$var);
238 T_NV
239 sv_setnv($arg, (NV)$var);
240 T_DOUBLE
241 sv_setnv($arg, (double)$var);
242 T_PV
243 sv_setpv((SV*)$arg, $var);
244 T_PTR
245 sv_setiv($arg, PTR2IV($var));
... .............................
307 T_OUT
308 {
309 GV *gv = newGVgen("$Package");
310 if ( do_open(gv, "+>&", 3, FALSE, 0, 0, $var) )
311 sv_setsv($arg, sv_bless(newRV((SV*)gv), gv_stashpv("$Package",1)));
312 else
313 $arg = &PL_sv_undef;
314 }
pp2@nereida:~$
TYPEMAP)
contiene una lista de tipos C básicos y una cadena que se asocia con el tipo.
El tipo C y la cadena/token van separados por un tabulador.
Obsérvese que varios tipos C pueden ser asignados a la misma cadena.
Por ejemplo unsigned y unsigned long se corresponden
con
T_UV
.
INPUT.
Es usado por xsubpp para convertir los parámetros de la llamada
Perl a sus equivalentes C.
OUTPUT.
Proporciona el código para traducir los valores retornados por la
función C a sus equivalentes Perl.
Por ejemplo, el código para traducir entre un valor escalar SV y un entero C
se obtiene en las entradas
T_IV
:
1 # basic C types 2 int T_IV .. ... .... 56 ############################################################################# 57 INPUT .. .... ........................ 84 T_IV 85 $var = ($type)SvIV($arg) ... .... ........................ 193 ############################################################################# 194 OUTPUT ... .... ........................ 205 T_IV 206 sv_setiv($arg, (IV)$var);Lo que indica que, al traducir un argumento Perl (de ahí el nombre
$arg) de una XSUB que espera un entero
se llamará a SvIV17.1
sobre dicho argumento para obtener
la variable c (denotada por $var).
Recíprocamente
se usará
sv_setiv
17.2
para asignar la parte entera
de la variable retornada al código Perl.
La notación $type se sustituye por el tipo C de la variable.
debe ser uno de los tipos listados en la primera parte del fichero typemap.
Consideremos el siguiente ejemplo:
lhp@nereida:~/Lperl/src/XSUB/TypeMapExample$ cat -n TypeMapExample.xs
1 #include "EXTERN.h"
2 #include "perl.h"
3 #include "XSUB.h"
4
5 #include "ppport.h"
6
7 void square(int x, int *x2) {
8 *x2 = x*x;
9 }
10
11 MODULE = TypeMapExample PACKAGE = TypeMapExample
12
13 void
14 square(x, x2)
15 int x
16 int &x2 = NO_INIT
17 OUTPUT:
18 x2
La palabra clave NO_INIT usada en la línea 16 indica que el parámetro es usado sólo como parámetro de salida. Si no se pone se producirán mensajes de advertencia:
lhp@nereida:~/Lperl/src/XSUB/TypeMapExample$ cat -n ./useypeMapexample.pl
1 #!/usr/local/bin/perl -w
2 use strict;
3 use blib;
4 use TypeMapExample;
5
6 my @a;
7 my $i = 0;
8 @ARGV = 1..5 unless @ARGV;
9 square($_, $a[$i++]) for @ARGV;
10
11 print "@a\n";
12
lhp@nereida:~/Lperl/src/XSUB/TypeMapExample$ ./useypeMapexample.pl
Use of uninitialized value in subroutine entry at ./useypeMapexample.pl line 9.
Use of uninitialized value in subroutine entry at ./useypeMapexample.pl line 9.
Use of uninitialized value in subroutine entry at ./useypeMapexample.pl line 9.
Use of uninitialized value in subroutine entry at ./useypeMapexample.pl line 9.
Use of uninitialized value in subroutine entry at ./useypeMapexample.pl line 9.
1 4 9 16 25
El
ampersand
en la declaración de x2 en la línea 16 advierte al compilador
que en la llamada a la función debe pasar la dirección del argumento. Hay una diferencia
en XSUB entre estas dos declaraciones:
int * x2; int &x2;La primera indica que x2 es un vector de enteros. El valor de
x2
será pasado a la función. La segunda indica que
x2 es un entero que será pasado por referencia: su dirección
será pasada a la función.
La compilación con xsubpp de este fuente produce la salida:
lhp@nereida:~/Lperl/src/XSUB/TypeMapExample$ xsubpp -typemap /usr/share/perl/5.8/ExtUtils/typemap \
TypeMapExample.xs | cat -n
Please specify prototyping behavior for TypeMapExample.xs (see perlxs manual)
1 /*
2 * This file was generated automatically by xsubpp version 1.9508 from the
3 * contents of TypeMapExample.xs. Do not edit this file, edit TypeMapExample.xs instead.
4 *
5 * ANY CHANGES MADE HERE WILL BE LOST!
6 *
7 */
8
9 #line 1 "TypeMapExample.xs"
10 #include "EXTERN.h"
11 #include "perl.h"
12 #include "XSUB.h"
13
14 #include "ppport.h"
15
16 void square(int x, int *x2) {
17 *x2 = x*x;
18 }
19
20 #line 21 "TypeMapExample.c"
21
22 XS(XS_TypeMapExample_square); /* prototype to pass -Wmissing-prototypes */
23 XS(XS_TypeMapExample_square)
24 {
25 dXSARGS;
26 if (items != 2)
27 Perl_croak(aTHX_ "Usage: TypeMapExample::square(x, x2)");
28 {
29 int x = (int)SvIV(ST(0));
30 int x2;
31
32 square(x, &x2);
33 sv_setiv(ST(1), (IV)x2);
34 SvSETMAGIC(ST(1));
35 }
36 XSRETURN_EMPTY;
37 }
.. .................. código para C++
int x = (int)SvIV(ST(0))
y su correspondencia directa con el esqueleto que figura en el
typemap: $var = ($type)SvIV($arg).
sv_setiv(ST(1), (IV)x2)
que se corresponde con el código de OUTPUT
que figura en el fichero typemap:
sv_setiv($arg, (IV)$var)
lhp@nereida:~/Lperl/src/perlcompilerssource/perl-5.8.8$ sed -ne '114,116p' XSUB.h
# define dXSARGS \
dSP; dAXMARK; dITEMS
#endif
lhp@nereida:~/Lperl/src/perlcompilerssource/perl-5.8.8$ grep -ni 'define dSP' *
pp.h:76:#define dSP register SV **sp = PL_stack_sp
lhp@nereida:~/Lperl/src/perlcompilerssource/perl-5.8.8$ sed -ne '103,105p' XSUB.h
#define dAXMARK \
I32 ax = POPMARK; \
register SV **mark = PL_stack_base + ax++
lhp@nereida:~/Lperl/src/perlcompilerssource/perl-5.8.8$ grep -ni 'define ditems' *
XSUB.h:107:#define dITEMS I32 items = SP - MARK
Casiano Rodríguez León
