CONTENIDO Usando Subrutinas ......................................................................................................... 1 Qué es una Subrutina ................................................................................................. 1 Definiendo e invocando una subrutina........................................................................ 1 Forward References a Subrutinas ....................................................................... 4 Retornando un valor desde una Subrutina ................................................................. 4 Valores de Retorno y Expresiones Condicionales............................................... 6 La Sentencia return..................................................................................................... 8 Usando variables locales en Subrutinas ..................................................................... 9 Inicialización de variables locales ...................................................................... 11 Pasando valores a una Subrutina ............................................................................. 11 Pasando una lista a una Subrutina .................................................................... 13 Llamando Subrutinas desde otras Subrutinas .......................................................... 14 Subrutinas Predefinidas ............................................................................................ 16 Ejemplo de BEGIN .................................................................................... 16 Ejemplo de END ......................................................................................... 16 AUTOLOAD ......................................................................................................... 17 QUE ESTA MAL?...................................................................................................... 18 Usando Subrutinas Qué es una Subrutina En Perl, 1 subrutina es una porción de código separada usada para efectuar una tarea particular. El programa PERL ejecuta esa porción de código llamando o invocando la subrutina. Una Subrutina se usa para alguno de estos dos propósitos: • Para partir un programa en partes pequeñas haciéndolo mas fácil de leer y mas entendible. • Para permitirnos usar una porción de código para llevar a cabo la misma tarea varias veces eliminando la duplicación. Definiendo e invocando una subrutina. Listado 9.1 muestra como una subrutina trabaja. Este programa llama una subrutina que lee una línea con números desde el standard input file y los separa. El programa luego efectúa su suma. Listado 9.1. Un programa que usa una subrutina. 1: 2: 3: 4: 5: 6: 7: 8: 9: 10: 1 #!/usr/local/bin/perl $total = 0; &getnumbers; foreach $number (@numbers) { $total += $number; } print ("El total es $total\n"); sub getnumbers { 11: 12: 13: 14: } $line = <STDIN>; $line =~ s/^\s+|\s*\n$//g; @numbers = split(/\s+/, $line); SALIDA $ program9_1 11 8 16 4 El total es 39 $ ANALISIS Líneas 10-14 son un ejemplo de una subrutina. La palabra reservada (keyword) sub le dice al Intérprete de Perl que eso es una definición de una subrutina. El getnumbers inmediatamente seguido al sub es el nombre de la subrutina; el programa Perl usa ese nombre cuando invoca la subrutina. El programa comienza su ejecución normal empezando por la línea 3. starts execution in the normal way, beginning with la línea 3. La línea 4 invoca la subrutina getnumbers; el carácter & le dice al Intérprete de Perl que el siguiente nombre es el nombre de la subrutina. (Esto asegura que el Intérprete de Perl no confunda nombres de subrutina con nombres de variables escalares o arreglos) El Intérprete de Perl ejecuta la línea 4 bifurcando a la primera sentencia ejecutable dentro de la subrutina, la cual es la línea 11. El intérprete entonces ejecuta las Líneas 11-13. Las Líneas 11-13 crean el arreglo @numbers de la siguiente manera: • La línea 11 lee una línea de input desde el standard input file. • La línea 12 remueve los espacios iniciales y finales (incluído el newline) desde la línea de input. • La línea 13 parte la línea de input en números y asigna el resultado a @numbers. Antes de que la línea 13 finalice, el Intérprete de Perl vuelve al main program y ejecuta la línea inmediatamente siguiente a la llamada de la subrutina, la cual es la línea 5. Las Líneas 5-7 suman los números usando la sentencia foreach para loopear la lista de números almacenada en @numbers. (Ojo, el programa no chequea si son números, si fueran otra cosa los convierte a cero) La sintaxis para la definición de una subrutina es: sub subname { statement_block } subname es el nombre de la subrutina. Como todos los nombres en Perl, subname consiste en un carácter alfabético seguido de una o más letras, dígitos o guiones (_). Es aconsejable evitar nombres iguales al de una palabra reservada de perl, y no poner todo el nombre con letras mayúsculas ya que así es como Perl llama a sus subrutinas internas. 2 statement_block es el cuerpo de la subrutina y consiste en una o mas sentencias Perl. Cualquier sentencia que puede aparecer en un main program, puede aparecer en una subrutina. NOTA El Intérprete de Perl nunca confunde un nombre de subrutina con el nombre de una variable escalar o cualquier otro porque puede deducir del contexto cual nombre estamos haciendo referencia. Pro lo tanto podemos tener una subrutina y una variable escalar con el mismo nombre. Por ejemplo: $word = 0; &word; Aquí, cuando el Intérprete de Perl ve el & en la segunda sentencia, asume que esta llamando una subrutina llamada word. Atención Cuando se definen nombres de subrutinas, es conveniente no usar nombres iguales a las funciones de librería de Perl para evitar errores involuntarios. Si bien nosotros podemos definir una subrutina llamada split y el Intérprete de Perl puede distinguir la invocación de la subrutina split de la función de librería split, (porque el nombre de la subrutina está precedido por un & cuando se invoca), es muy fácil olvidar tipear el & y caer en el error. @words = &split(1, 2); # subrutina @words = split(/\s+/, $line); # library function Las subrutinas pueden aparecer en cualquier parte de un programa. Listado 9.2. Un programa conteniendo una subrutina en el medio del main program. 1: 2: 3: 4: 5: 6: 7: 8: 9: 10: 11: #!/usr/local/bin/perl while (1) { &readaline; last if ($line eq ""); sub readaline { $line = <STDIN>; } print ($line); } print ("FIN\n"); SALIDA $ program9_2 Aquí esta la linea de input Aquí esta la linea de input ^D FIN $ ANALISIS Este programa lee lineas del std input file y las escribe en el standard output file. La línea 4 llama la subrutina readaline. Cuando examina la subrutina, la encuentra contenida entre las lineas 6 y 8. Ahí vemos que lee una línea y la asigna a la variable escalar $line. 3 Cuando readaline termina, la ejecución del programa continúa en la línea 5. Cuando la línea 5 es ejecutada, el programa saltea las sentencias correspondientes a la definición de la subrutina y continúa en la línea 9. El código dentro de una subrutina nunca es ejecutado directamente. TIP Si bien las subrutinas pueden aparecer en cualquier parte de un programa, es usual definirlas al principio o al final de un programa. Esto lo hace mas “legible”. FORWARD REFERENCES A SUBRUTINAS Como vimos, el Intérprete de Perl usa el carácter & para indicar que viene una subrutina. En Perl 5 no es ne4cesrio el & antes del nombre en la invocación si la subrutina ya fue definida. Ejemplo: sub readaline { $line = <STDIN>; } ... readaline; Esto es porque el intérprete ya sabe que readaline es una subrutina. Si escribimos todas las subrutinas hacia el final de un programa, entonces si debemos preceder su invocación con el carácter & salvo que hagamos al principio una forward reference de la misma: sub readaline; # forward reference ... readaline; ... sub readaline { $line = <STDIN>; } El forward reference le dice al Intérprete de Perl que readaline es el nombre de una subrutina. De esta manera no necesitamos adicionarle el & en la invocación. Atención Algunas veces si invocamos una subrutina sin el & no obtenemos el resultado esperado, en estos casos aconsejamos usarlo. Retornando un valor desde una Subrutina Veamos nuevamente la subrutina getnumbers del Listado 9.1. 10: sub getnumbers { 11: $line = <STDIN>; 12: $line =~ s/^\s+|\s*\n$//g; 13: @numbers = split(/\s+/, $line); 14: } 4 Si bien esta subrutina es util, tiene una seria limitación: sobreescribe el arreglo @numbers (tambien sobrescribe $line). Esto puede traer problemas… Por ejemplo, si consideramos lo siguiente: @numbers = ("the", "a", "an"); &getnumbers; print ("El valor de \@numbers es: @numbers\n"); Cuando la subrutina getnumbers es invocada, el valor de @numbers es sobreescrito. Esto no resulta obvio cuando miramos el programa de arriba. En torno a esto, podemos usar una propiedad de las subrutinas en Perl: el valor de la última expresión evaluada por la subrutina es considerada automáticamente como el valor de retorno (return value) de la subrutina. Por ejemplo, en la subrutina getnumbers del Listado 9.1, la última expresión evaluada es: @numbers = split(/\s+/, $temp); El valor de esta expresión es la lista de números obtenida del splitting de la línea de input. De esta manera, la lista de números es el valor de retorno de la subrutina. Para ver como usar el valor de retorno de una subrutina, veamos el Listado 9.3, el cual modifica las líneas 4 y 13 del listado 9.1 original para usar el valor de retorno de la subrutina getnumbers. Listado 9.3. Un programa que usa en una subrutina el return value. 1: 2: 3: 4: 5: 6: 7: 8: 9: 10: 11: 12: 13: 14: #!/usr/local/bin/perl $total = 0; @numbers = &getnumbers; # así getnumbers retornará su valor en @numbers foreach $number (@numbers) { $total += $number; } print ("El total es $total\n"); sub getnumbers { $line = <STDIN>; $line =~ s/^\s+|\s*\n$//g; split(/\s+/, $line); # Este es el return value } SALIDA $ program9_3 11 8 16 4 El total es 39 $ ANALISIS La línea 4, nuevamente llama a la subrutina getnumbers, pero esta vez, el arreglo @numbers es asignado a la lista de números leídos desde el standard input file; de esta manera la asignación se hace en el cuerpo principal del programa, no en la subrutina, esto lo hace mas fácil de seguir. La otra diferencia está en la llamada a la función split de la línea 13. Ahora no se asigna su resultado a @numbers. De hecho no se le asigna a nada, porque no es necesario hacerlo. 5 La línea 13 es la última expresión evaluada en getnumbers, por eso automáticamente se convierte en el valor de retorno de la subrutina. De esta manera cuando en la línea 4 se llama a la subrutina getnumbers, el listado retornado por el split es asignado a @numbers. NOTA Si la idea de la última expresión evaluada es confusa para Uds. No hay nada malo en crear una variable dentro de la subrutina solo para contener el valor de retorno. Por ejemplo: sub getnumbers { $line = <STDIN>; $line =~ s/^\s+|\s*\n$//g; @retval = split(/\s+/, $temp); # the return value } Aquí es obvio que el valor de retorno está contenido en @retval. La desventaja está solo en usar una asignación cuando no es necesaria. Eliminarla hace la subrutina mas eficiente. Usar una variable especial para retornar valores elimina unos cuantos errores que veremos mas adelante. Se puede usar el valor de retorno de una subrutina en cualquier parte de una expresión. Por ejemplo: foreach $number (&getnumbers) { print ("$number\n"); } Este foreach itera sobre la lista de números retornados por getnumbers. Cada elemento de la lista es asignado a $number por turno, lo que produce la impresión de todos los números de la lista. VALORES DE RETORNO Y EXPRESIONES CONDICIONALES Como el valor de retorno de una subrutina es siempre la última expresión evaluada, a veces el valor de retorno no devuelve lo que esperamos. Listado 9.5: Consideremos nuevamente el ejemplo del Listado 9.1, pero esta vez todo el trabajo hecho dentro de una subrutina llamada get_total: se leen líneas del Standard input file, luego se separa en números y los suma. Listado 9.5. Un programa que ilustra un potencial problema con los valores de retorno desde las subrutinas. 1: 2: 3: 4: 5: 6: 7: 8: 9: 10: 11: 12: 13: 14: 15: 6 #!/usr/local/bin/perl $total = &get_total; print("El total es $total\n"); sub get_total { $value = 0; $inputline = <STDIN>; $inputline =~ s/^\s+|\s*\n$//g; @subwords = split(/\s+/, $inputline); $index = 0; while ($subwords[$index] ne "") { $value += $subwords[$index++]; } } SALIDA $ program9_5 11 8 16 4 El total es $ ANALISIS Obviamente que el propósito de Este programa es asignar el contenido de la variable escalar $value a la variable escalar $total. Pero cuando la la línea 4 trata de imprimir el total, el valor de $total está vacío. Que sucedió? El problema en la subrutina get_total es que la última expresión evaluada no es la que nosotros esperábamos sino la expresión condicional de la Línea 12. $subwords[$index] ne "" El loop de las Líneas 12-14 itera hasta que el valor de la expresión es 0. Cuando el valor de la expresión es cero, el loop termina, y la subrutina también. Por lo tanto el 0 es lo que retorna y como en un print el 0 se interpreta como string nulo, la línea 4 imprime lo siguiente (lo cual no es lo que esperábamos) El total es Listado 9.6 muestra como solucionar este problema Listado 9.6. Un programa que corrige el problema del 9.5 1: 2: 3: 4: 5: 6: 7: 8: 9: 10: 11: 12: 13: 14: 15: 16: #!/usr/local/bin/perl $total = &get_total; print("El total es $total.\n"); sub get_total { $value = 0; $inputline = <STDIN>; $inputline =~ s/^\s+|\s*\n$//g; @subwords = split(/\s+/, $inputline); $index = 0; while ($subwords[$index] ne "") { $value += $subwords[$index++]; } $retval = $value; } SALIDA $ program9_6 11 8 16 4 El total es 39. $ ANALISIS Este programa es igual al 9.5 excepto por el agregado de la línea 15: Esta línea asigna el total almacenado en $value a la variable escalar $retval. 7 La línea 15 asegura que el valor de la última expresion evaluada en la subrutina get_total contenga el total buscado. Luego la línea 3 efectúa una nueva asignación e imprime. Pero en realidad … no sería necesario efectuar la asignación a retval, la subrutina get_total podría quedar como sigue y seguir siendo efectiva: sub get_total { $value = 0; $inputline = <STDIN>; $inputline =~ s/^\s+|\s*\n$//g; @subwords = split(/\s+/, $inputline); $index = 0; while ($subwords[$index] ne "") { $value += $subwords[$index++]; } $value; } Aquí la última expresión evaluada es simplemente $value. El valor de esta expresión es el valor corriente almacenado en $value, es decir la suma de los números de la línea. TIP Las subrutinas que dan su valor de retorno al final (como get_total en Listado 9.6) son conocidas como single-exit modules. Estas subrutinas salvan problemas como los vistos en Listado 9.5, y normalmente son mucho más fáciles de leer. Por estas razones es una muy buena idea definirlas así. La Sentencia return Otra manera de asegurar el valor de retorno de una subrutina es usando la sentencia return . La sintaxis es la siguiente: return (retval); retval es el valor que queremos retornar. Puede ser un valor escalar (incluido el resultado de una expresión) o una lista. Listado 9.7 da un ejemplo de su uso Listado 9.7. Un programa que usa la sentencia return 1: 2: 3: 4: 5: 6: 7: 8: 9: 10: 11: 12: 13: 14: 15: 16: 17: 18: 8 #!/usr/local/bin/perl $total = &get_total; if ($total eq "error") { print ("No se ingresó nada.\n"); } else { print("el total es $total.\n"); } sub get_total { $value = 0; $inputline = <STDIN>; $inputline =~ s/^\s+|\s*\n$//g; if ($inputline eq "") { return ("error"); } @subwords = split(/\s+/, $inputline); $index = 0; 19: 20: 21: 22: 23: } while ($subwords[$index] ne "") { $value += $subwords[$index++]; } $retval = $value; SALIDA $ program9_7 ^D No se ingresó nada. $ ANALISIS Este programa es similar al Listado 9.6. La única diferencia de este programa es que chequea si la línea de input existe. Si la línea de input no existe, la expresión condicional en la línea 14 es verdadera, y la línea 15 es ejecutada. La línea 15 sale de la subrutina con return value error; Luego error se asigna a $total en la línea 3. Este programa muestra también como es útil permitir almacenar en variables escalares números o character strings. Cuando la subrutina get_total detecta el error, asigna un valor no numérico a $total, lo que permite fácilmente determinar que algo anduvo mal. En otros lenguajes, no se ofrece esta flexibilidad. Usando variables locales en Subrutinas La subrutina get_total en Listado 9.7 define algunas variables que solo se usan dentro de la subrutina: El arreglo @subwords, y 4 variables escalares $inputline, $value, $index, y $retval. Si tenemos la certeza que estas variables solo serán usadas dentro de la subrutina, podemos decirle a Perl que defina estas variables como locales (local variables). En Perl 5, existen dos sentencias para definir local variables: • La sentencia my, la cual define variables que solo van a existir dentro de la subrutina. • La sentencia local, la cual define variables que solo van a existir dentro de la subrutina y cualquier otra subrutina llamada por esta (como hacer esto lo veremos luego). Listado 9.8 muestra como podemos usar my para definir variables que existan solo en la subrutina. Listado 9.8. Un programa que usa local variables. 1: 2: 3: 4: 5: 6: 7: 8: 9 #!/usr/local/bin/perl $total = 0; while (1) { $linetotal = &get_total; last if ($linetotal eq "done"); print ("Total para esta línea: $linetotal\n"); $total += $linetotal; 9: 10: 11: 12: 13: 14: 15: 16: 17: 18: 19: 20: 21: 22: 23: 24: 25: 26: 27: } print ("Total para todas las Líneas: $total\n"); sub get_total { my ($total, $inputline, @subwords); my ($index, $retval); $total = 0; $inputline = <STDIN>; if ($inputline eq "") { return ("done"); } $inputline =~ s/^\s+|\s*\n$//g; @subwords = split(/\s+/, $inputline); $index = 0; while ($subwords[$index] ne "") { $total += $subwords[$index++]; } $retval = $total; } SALIDA $ program9_8 11 8 16 4 Total para esta línea: 39 7 20 6 1 Total para esta línea: 34 ^D Total para todas las Líneas: 73 $ ANALISIS Este programa usa dos copias de la variable escalar $total. Una copia de $total esta definida en el main program y almacena el total de todas las Líneas. La variable escalar $total está también definida en la subrutina get_total; en esta subrutina, $total referencia al total para una linea en particular, y la línea 13 define que ésta es una local variable. Como esta variable $total esta definida en la subrutina, la copia de $total definida en el main program no se ve afectada por la línea 15 o 24. Atención Como la variable local no es conocida fuera de la subrutina, se destruye cuando la subrutina es completada. Si la subrutina es llamada nuevamente una nueva copia de la variable local es definida. El siguiente ejemplo muestra como NO funcionan: sub subrutina_count { my($number_of_calls); $number_of_calls += 1; } Esta subrutina no devuelve el numero de veces que la subrutina es llamada, ya que cada vez que se la invoca, una nueva copia de $number_of_calls es definida. Siempre devuelve 1. Las variables locales pueden aparecer en cualquier parte de un programa, pero para dar claridad en el código, es preferible ubicarlas al principio. 10 INICIALIZACIÓN DE VARIABLES LOCALES Las variables locales pueden ser inicializadas. Ejemplo: sub my_sub { my($scalar) = 43; my(@array) = ("here's", "a", "list"); # code goes here } Aqui la variable local $scalar toma un valor inicial de 43, y el arreglo @array es inicializado con la lista ("here's", "a", "list"). Pasando valores a una Subrutina Podemos hacer mas flexibles nuestras subrutinas si permitimos que ellas acepten valores pasados desde el main program. Estos valores se los llama Argumentos. Listado 9.9 provee un simple ejemplo de una subrutina que acepta tres argumentos Listado 9.9. Un programa que usa una subrutina to print three numbers and their total. 1: 2: 3: 4: 5: 6: 7: 8: 9: 10: 11: 12: 13: 14: 15: 16: 17: 18: 19: #!/usr/local/bin/perl print ("Ingrese 3 numeros, uno por vez:\n"); $number1 = <STDIN>; chop ($number1); $number2 = <STDIN>; chop ($number2); $number3 = <STDIN>; chop ($number3); &printnum ($number1, $number2, $number3); sub printnum { my($number1, $number2, $number3) = @_; my($total); print ("Los numeros ingresados son: "); print ("$number1 $number2 $number3\n"); $total = $number1 + $number2 + $number3; print ("El total es: $total\n"); } SALIDA $ program9_9 Ingrese 3 numeros, uno por vez: 5 11 4 Los numeros ingresados son: 5 11 4 El total es: 20 $ ANALISIS La línea 10 llama a la subrutina printnum. Tres argumentos son pasados a printnum, los valores almacenados en: $number1, $number2, y $number3. Notar que estos argumentos son pasados a la subrutina en la misma forma que se pasan a las built-in library functions. 11 La línea 13 define copias locales de las variables escalares $number1, $number2, y $number3 al mismo tiempo que asigna el contenido de la variable de sistema @_. @_ es creada cada vez que una subrutina es llamada con argumentos. Contiene una lista con los argumentos en el orden en el cual fueron pasados. En este caso, @_ contiene la lista (5, 11, 4). La asignación de la línea 13 trabaja igual que siempre: el primer elemento de la lista, 5, es asignado a la primera variable, $number1; el segundo, 11, es asignado a $number2; y finalmente, 4, es asignado a $number3. NOTA Después que la variable @_ es creada, puede ser usada dentro de la subrutina como cualquier arreglo. La siguiente subrutina es equivalente a las Líneas 12-19 de Listado 9.9: sub printnum { my($total); print ("The numbers you entered: "); print ("$_[0] $_[1] $_[2]\n"); $total = $_[0] + $_[1] + $_[2]; print ("The total: $total\n"); } Aquí, $_[0] referencia al primer elemento del arreglo @_, $_[1] referencia al Segundo elemento, y $_[2] referencia al tercero. Esta subrutina es mas eficiente, pero mas difícil de escribir y leer. TIP Usualmente es mejor definir variables locales y asignar @_ a ellas para que así sea mas fácil de entender el código. Listado 9.10 es otro ejemplo de un programa que pasa argumentos a una subrutina. Este programa usa la misma subrutina para contar el numero de palabras y el numero de caracteres que recibe por STDIN. Listado 9.10. Otro ejemplo de una subrutina con argumentos pasados. 1: 2: 3: 4: 5: 6: 7: 8: 9: 10: 11: 12: 13: 14: 15: 16: 17: 18: 19: 20: 21: 22: 12 #!/usr/local/bin/perl $wordcount = $charcount = 0; $charpattern = ""; $wordpattern = "\\s+"; while ($line = <STDIN>) { $charcount += &count($line, $charpattern); $line =~ s/^\s+|\s+$//g; $wordcount += &count($line, $wordpattern); } print ("Total: $wordcount palabras, $charcount caracteres\n"); sub count { my ($line, $pattern) = @_; my ($count); if ($pattern eq "") { @items = split (//, $line); } else { @items = split (/$pattern/, $line); } $count = @items; } SALIDA $ program9_10 Esta es la línea de input. Aqui hay otra linea. ^D Total: 10 palabras, 46 caracteres $ PASANDO UNA LISTA A UNA SUBRUTINA Si queremos pasar una lista a una subrutina veamos el siguiente ejemplo: La siguiente subrutina suma los elementos de una lista e imprime el resultado sub addlist { my (@list) = @_; $total = 0; foreach $item (@list) { $total += $item; } print ("The total is $total\n"); } Invocaciones ejemplo: &addlist (@mylist); &addlist ("14", "6", "11"); &addlist ($value1, @sublist, $value2); En cada caso, los valores son juntados en una sola lista, y pasados como una lista simple a addlist. Como los valores son juntados, entonces solo se debe incluir una lista en los argumentos de una sub y es conveniente ponerla COMO ULTIMO ARGUMENTO La subrutina: sub twolists { my (@list1, @list2) = @_; } No es útil porque las dos listas se juntan y SIEMPRE la se asigna la lista vacía a @list2, ya que @list1 absorbe TODO el contenido de @_. Otro Ejemplo: sub twoargs { my ($scalar, @list) = @_; } Invocación: &twoargs(47, @mylist); 13 EL VALOR 47 es asignado a $scalar, y @mylist es asignado a @list. Si queremos podemos invocar a twoargs con una lista simple como sigue: &twoargs(@mylist); Con el mismo resultado que antes, el primer elemento de la lista se asigna a $scalar, y el resto a @list. Llamando Subrutinas desde otras Subrutinas En Perl, podemos llamar subrutinas desde otra subrutina. Para hacerlo, se usa la misma sintaxis que vinimos empleando. Las Subrutinas que son llamadas desde otras subrutinas se las conoce como nested subrutinas Listado 9.11. Ejemplo de nested 1: 2: 3: 4: 5: 6: 7: 8: 9: 10: 11: 12: 13: 14: 15: 16: 17: 18: 19: 20: 21: 22: 23: 24: 25: 26: 27: 28: 29: 30: 31: 32: 33: 34: 35: 36: 37: #!/usr/local/bin/perl ($wordcount, $charcount) = &getcounts(3); print ("Totals for three lines: "); print ("$wordcount words, $charcount characters\n"); sub getcounts { my ($numLines) = @_; my ($charpattern, $wordpattern); my ($charcount, $wordcount); my ($line, $linecount); my (@retval); $charpattern = ""; $wordpattern = "\\s+"; $linecount = $charcount = $wordcount = 0; while (1) { $line = <STDIN>; last if ($line eq ""); $linecount++; $charcount += &count($line, $charpattern); $line =~ s/^\s+|\s+$//g; $wordcount += &count($line, $wordpattern); last if ($linecount == $numLines); }; @retval = ($wordcount, $charcount); } sub count { my ($line, $pattern) = @_; my ($count); if ($pattern eq "") { @items = split (//, $line); } else { @items = split (/$pattern/, $line); } $count = @items; } SALIDA $ program9_11 This is a line of input. Here is another line. 14 Here is the last line. Totals for three Lines: 15 words, 70 characters 15 Subrutinas Predefinidas Perl considera las subrutinas cuyo nombre está todo en mayúsculas como parte del núcleo, y son llamadas automáticamente por el sistema • BEGIN subrutina, se llama ANTES que cualquier sentencia. Es más, se ejecuta ANTES que los script regulares sean analizados. • END subrutina, se llama ANTES que termine el script regular, al mismo tiempo que sale del intérprete de perl • AUTOLOAD subrutina, se carga si hacemos una llamada a una subrutina inexistente. La variable $AUTOLOAD contiene el nombre de la sub que dio error, la variable @_ contiene la información pasada en la rutina que dio error. Ejemplo de BEGIN BEGIN { print("Hi! Welcome to Perl!\n"); } Cuando comienza la ejecución del script aparece: Hi! Welcome to Perl! Ejemplo de END END { print("Thank you for using Perl!\n"); } El código de la subrutina END SIEMPRE se ejecuta, salvo aún si el programa termina con die. Por ejemplo: die("Prepare to die!\n"); END { print("Ha! You can't kill me!\n"); } Salida: Prepare to die! Ha! You can't kill me! 16 NOTA Se pueden definer varias subrutinas END, en ese caso, se ejecutan en el orden inverso de apariencia (la ultima se ejecuta primero) AUTOLOAD Se carga si hacemos una llamada a una subrutina inexistente. La variable $AUTOLOAD contiene el nombre de la sub que dio error, la variable @_ contiene la información pasada en la rutina que dio error. Ejemplo: Listado 9.15. Un programa que usa AUTOLOAD. 1: #!/usr/local/bin/perl 2: 3: &nothere("hi", 46); 4: 5: AUTOLOAD { 6: print("subrutina $AUTOLOAD not found\n"); 7: print("arguments passed: @_\n"); 8: } SALIDA $ program9_15 subrutina main::nothere not found arguments passed: hi 46 $ TIP AUTOLOAD es útil para organizar el Programa Perl en módulos 17 QUE ESTA MAL? 1. #!/usr/local/bin/perl for ($count = 1; $count <= 10; $count++) { &print_ten ($count); } sub print_ten { local ($multiplier) = @_; for ($count = 1; $count <= 10; $count++) { $printval = $multiplier * 10 + $count; print ("$printval\n"); } } 2. #!/usr/local/bin/perl $line = <STDIN>; @words = split(/\s+/, $line); $searchword = <STDIN>; &search_for_word (@words, $searchword); sub search_for_word { local (@searchlist, $searchword) = @_; foreach $word (@searchlist) { return (1) if ($word eq $searchword); } $retval = 0; } 3. #!/usr/local/bin/perl $line = <STDIN>; @words = &split_la línea($line); print ("@words\n"); sub split_la línea { local ($line) = @_; local (@words); @words = split(/\s+/, $line); if (@words == 0) { @words = ("empty list"); } } 18