El Módulo Event::RPC

Véase Event::RPC. Estudie los ejemplos del cliente y el servidor que acompañan a la distribución Puede encontrarlos en http://search.cpan.org/src/JRED/Event-RPC-0.90/examples/. Compruebe que es la última distribución.

Casiano Rodríguez León
2010-03-22
/A>pcgull
Sig: El Módulo Event::RPC Sup: Demonios y Daemons Ant: El Módulo Continuity: CGIs
Casiano Rodríguez León
2010-04-19
rofundidad del tema puede consultar los libros de Simon Cozens [6] y [7].

Recorrer el Árbol

El siguiente programa Btree3.pl implanta una subrutina treetrav que muestra el árbol generado por el compilador para una subrutina dada.

pp2@nereida:~/src/perl/B$ cat -n Btree3.pl
 1  #!/usr/local/bin/perl -w
 2  use strict;
 3  use B::Utils;
 4
 5  my $s = sub {
 6    my $a = shift;
 7    print $a+1;
 8  };
 9
10  sub treetrav {
..    ...........
22  }
23
24  my $b = B::svref_2object($s); # Objeto B::CV 
25  print "*** Tree ***\n";
26  my $op = $b->ROOT;
27  treetrav($op, 0);

Las Funciones B::main_root, B::main_start y B::svref_2object

Hay dos formas de acceder al árbol de código. Una es através de las funciones B::main_root y B::main_start:

pp2@nereida:~/src/perl/B$ perl -MB -le 'print B::main_root,"\n",B::main_start'
B::LISTOP=SCALAR(0x814fb60)
B::OP=SCALAR(0x814f8e4)

La otra forma - que es la usada en el ejemplo - es llamando a la función B::svref_2object con argumento una referencia al código. Nos retorna un objeto B::CV que representa el árbol de codigo resultante.

La Salida

Cuando treetrav es llamada con el objeto y un sangrado inicial igual a 0 nos produce la siguiente salida:



pp2@nereida:~/src/perl/B$ Btree3.pl
*** Tree ***
leavesub(               #subroutine exit
  lineseq(              #line sequence
    sassign(            #scalar assignment
      shift(            #shift
        rv2av(          #array dereference
          gv(           #glob value
          ) # end gv
        ) # end rv2av
      ) # end shift
      padsv(            #private variable
      ) # end padsv
    ) # end sassign
    nextstate(          #next statement
    ) # end nextstate
    print(              #print
      add(              #addition (+)
        padsv(          #private variable
        ) # end padsv
        const(          #constant item
        ) # end const
      ) # end add
    ) # end print
  ) # end lineseq
) # end leavesub
 5  my $s = sub {
 6    my $a = shift;
 7    print $a+1;
 8  };


La Función de Recorrido del Árbol

La función treetrav usa los métodos name y desc de la subclase B::OP para obtener el nombre y la descripción de la operación actual. El método kids en B::Utils devuelve la lista de hijos:

10  sub treetrav {
11    my $op = shift;
12    my $indent = shift;
13
14    my $spaces = " "x$indent;
15    print $spaces.$op->name."(\t\t#".$op->desc;
16      print "\n";
17      for ($op->kids()) {
18        treetrav($_, $indent+2);
19      }
20      print "$spaces) # end ".$op->name;
21    print "\n";
22  }

La Función walkoptree_simple

Una alternativa a nuestra función de recorrido habría sido usar una de las proveídas por B::Utils.

Hay varias subrutinas de recorrido del árbol de códigos. Una de las mas sencillas es walkoptree_simple (en B::Utils):

     walkoptree_simple($op, \&callback, [$data])
La función &callback es llamada para cada operación pasándole como argumentos la operación y cuales quiera datos adicionales en $data.

Todas las funciones de recorrido establecen las variables $B::Utils::file y $B::Utils::line al fichero y número de línea actual. Sólo los nodos de clase COP disponen de esa información.

Grafo de Flujo de Control

En el párrafo anterior recorríamos el árbol según su orden jerárquico. Sin embargo el árbol está a su vez hilvanado en orden de ejecución. Esto es: superpuesta a la estructura de árbol existe una lista que recorre el árbol según el flujo de control. A esta estructura de datos se la denomina Grafo de Flujo de Control o Control flow Graph (CFG).

El método START

El método START de un objeto B::CV nos da el punto de entrada en la ejecución. El método next de un objeto B::OP proporciona el siguiente nodo a ejecutar.

Recorrido en Orden de Ejecución

pp2@nereida:~/src/perl/B$ cat -n bex2.pl
 1  #!/usr/local/bin/perl -w
 2  use strict;
 3  use B;
 4
 5  my $s = sub {
 6    my $a = shift;
 7    print $a+1;
 8  };
 9
10  my $b = B::svref_2object($s); 
11  my $op = $b->START;
12  my ($class, $name, $desc);
13  format STDOUT =
14  @<<<<<<<<<@|@<<<<<<<<<<<<@|@<<<<<<<<<<<<<<<<<<<<<<<<<
15  $class,   '|', $name,    '|', $desc
16  .
17  do {
18    ($class, $name, $desc) = (B::class($op), $op->name, $op->desc);
19    write;
20  } while $op = $op->next and !$op->isa("B::NULL");
Es necesario comprobar que $op no es un objeto B::NULL ya que el puntero next es un puntero C que B deja disponible sin envoltorio alguno.

Salida en Orden de Ejecución

La ejecución produce la secuencia de operaciones en orden de ejecución:

pp2@nereida:~/src/perl/B$ bex2.pl | cat -n
 1  COP       | nextstate    | next statement
 2  PADOP     | gv           | glob value
 3  UNOP      | rv2av        | array dereference
 4  UNOP      | shift        | shift
 5  OP        | padsv        | private variable
 6  BINOP     | sassign      | scalar assignment
 7  COP       | nextstate    | next statement
 8  OP        | pushmark     | pushmark
 9  OP        | padsv        | private variable
10  SVOP      | const        | constant item
11  BINOP     | add          | addition (+)
12  LISTOP    | print        | print
13  UNOP      | leavesub     | subroutine exit
 my $s = sub {
   my $a = shift;
   print $a+1;
 };

El Módulo B::Terse

El módulo B::Terse tiene una opción -exec que permite ver el orden de ejecución de un código:

pp2@nereida:~/src/perl/B$ perl -MO=Terse,-exec -e 'my $s = 4'
OP (0x816d298) enter
COP (0x816d300) nextstate
SVOP (0x816d588) const [2] IV (0x8150388) 4
OP (0x816d4a0) padsv [1]
BINOP (0x816d5e0) sassign
LISTOP (0x816d468) leave [1]
-e syntax OK



Subsecciones
Casiano Rodríguez León
2010-04-20