Jul 26

Un pseudo polimorfismo en perl

Aunque perl admite programación orientada a objetos, me he encontrado por casulidad con una cosa que me ha llamado la atención. Aprovechando que perl es interpretado y que no hay que declarar nada previamente -ni funciones, ni variables-, se puede hacer una especie de "trampa" para conseguir algo que se parece al polimorfismo.

La idea es la siguiente. En un fichero funcion.pl ponemos una función cualquiera. Por ejemplo, una que sume los dos parámetros que se le pasen. Una vez que la función obtiene el resultado, llama a otra función toma_suma() que de momento no está declarada. El código del fichero funcion.pl podría ser así

sub suma
{
   $s1 = shift;
   $s2 = shift;
   toma_suma ($s1+$s2);
}
return true;

Ahora, en otro fichero separado main1.pl, hacemos un código que incluya este fichero -con require, por ejemplo-, y que defina la función toma_suma(). Puede ser esto

require "funcion.pl";
suma(1,2);

sub toma_suma
{
   $s = shift;
   print "suma = $s\n";
}

Pues bien, esto funciona. Se llama a suma(1,2) y cuando la función tiene el resultado, llama a toma_suma() de este fichero main1.pl. De la misma forma, si hacemos un segundo fichero main2.pl que define toma_suma de otra forma, también funciona

require "funcion.pl";
suma(11,3);

sub toma_suma
{
   $resultado = shift;
   print "el cuadrado de la suma = ".$resultado*$resultado;
}

Esto se asemeja mucho, mucho al polimorfismo. La función suma() llama a toma_suma() que está sin definir y es el que llama a suma() el que la define. No es exactamente polimorfismo porque posiblemente, dentro de un fichero main.pl no podemos redefinir toma_suma() de varias maneras, para que según nos interese se haga una cosa u otra.

Supongo que esta no es una forma correcta de programar, pero no deja de ser una curiosidad con la que me he tropezado que me ha llamado mucho la atención.

Jul 25

cruise control, maven, ant y perl todo junto

Bueno, he terminado mi conversor de ficheros .h a fichero .java

Tengo instalado Cruise Control, de forma que todas las noches saca el proyecto de CVS con los últimos cambios y los compila. El proyecto tiene formato de maven y se compila con maven. Cruise Control se lleva muy bien con maven y no hay problemas, todas las noches Cruise Control llama al mvn install y compila el proyecto.

Como cosa maravillosa se me ha ocurrido que Cruise Control podría sacar de CVS los fuentes .h que hayamos tocado, llamar al script de perl que convierte esos .h a .java y luego compilar los ficheros java para construir el jar correspondiente. Como Cruise Control llama a maven, debería ser maven el que haga todo esto. Así que a ello. Lo que hice fue lo siguiente:

  • Un proyecto maven con src/main/c con todos los .h y luego, sin fuentes, src/main/java y src/main/ada -el script de .h a ada aun está por hacer-. Puse también un src/main/perl con el fuente del script de perl c2java.pl
  • Luego, en el fichero pom.xml del proyecto, copie el plugin para llamar a tareas de ant de aquí.
  • Dentro del "ahí", entre <tasks> y </tasks> puse un <exec> de ant para llamar al script de perl.

En fin, todo estupendo. Mi mvn install ahora, antes de compilar, ejecuta la tarea de ant que se encarga de llamar a perl para generar los fuentes de java en src/main/java. Luego compila los fuentes de java y genera el jar.

De esta forma, si en el proyecto necesito cambiar uno de estos tipos, simplemente lo cambio en el .h, lo meto en CVS y todo listo. Cuando compile la parte de java, automáticamente se generán primero los fuentes de java y luego se compilan, generando el jar.

Jul 24

Perl en la Chuwiki

Sigo dándole al Perl, haciendo mi conversor de tipos C a Java.

Puesto que es cosa de trabajo y puedo dedicarle tiempo "oficial", ya prácticamente está terminado y estoy en la fase de comprobar que el código Java generado compila y que compila el resto de código Java que utiliza esos tipos.

Luego me falta el conversor de C a Ada y, aunque parezca una chorrada, haré el de C a C. ¿Por qué este último?. Mi intención es que el código inicial para definir tipos no sea C, sino un lenguaje inventado más simple. Por ello, una vez que tenga los tres conversores, incluido el de C a C, iré modificando poco a poco los ficheros .h iniciales, quitando cosas como typedef, obligando a un formato del texto más simple y estricto, etc, etc. Ire en paralelo retocando los scripts de perl, y se acabarán convirtiendo de c2java.pl, c2ada.pl y c2c.pl a lenguajeinventado2java.pl, lenguajeinventado2ada.pl y lenguajeinventado2c.pl

Aprovechando todo esto, he comenzado en la Chuwiki una serie de tutoriales sobre perl. Son muy sencillotes -y quizás no del todo correctos-, pero estoy empezando con el lenguaje y no se me pueden pedir demasiadas filigranas. Sin embargo, me gusta escribir lo que voy aprendiendo, me ayuda a aclarar ideas y espero, que al menos, le sirvan a alguien que esté también empezando.

Jul 18

Sudoku en Perl

Hace tiempo que lo conocía, pero ahora que me he puesto con perl, lo he recordado y he ido a mirarlo, sólo para ver si entiendo algo.

Un programa para resolver sudokus, hecho en perl, con sólo tres líneas de código. Viene explicado.

Sigue siendo tan críptico como cuando lo miré la primera vez, pero al menos, una vez "sangrado", entiendo la sintaxis -más o menos, los map todavía se me escapan-.

Jul 16

He empezado con Perl.

Como comenté en un post anterior, me apetecía empezar con Perl. Hoy ha sido un día tonto, puesto que tenía dentista y no he ido al monte con el resto de compañeros del trabajo, sino a la empresa. Puesto que es sólo un día -mañana me toca otra vez ir de monte, ¿para qué ponerme a hacer algo en serio?.  He dedicado el día a empezar mi conversor de tipos de C a Java en Perl.

Me he puesto a ello y tras buscar algunos tutoriales completitos a los que poder consultar, hacer un "hola mundo" y un comando "type" o "cat" de fichero, he empezado directamente. No es la mejor forma, pero soy de esos impacientes que prefieren tocar los mandos del video antes de leerse el manual.

La verdad es que no me ha costado mucho pillarle el truco -salvo alguna pequeña cosa endemoniada-, pero contaba con algunas ventajas previas:

  • Estoy muy acostumbrado a usar el vi y sus comandos de búsqueda y las expresiones regulares de Perl son muy similares. También, en su día, miré algo de awk. El caso es que los "chismes" estilo s/#include/import/ me resultan conocidos.
  • El código en C está generado por una herramienta automática, por lo que tengo algunas ventajas, como saber que los campos de una estructura van en líneas separadas, los enumerados también, etc, etc. Eso simplifica mucho el "parser" y no necesito hacerlo para que funcione al 100% de los casos.

En fin, que ya tengo pillado el truco y a partir del fichero .h ya soy capaz de generar los enumerados, estructuras y typedef de arrays en java. Si tengo tiempo libre en el monte -habitualmente tengo mucho- seguiré un poco con el tema.

Por supuesto, es código de principiante en este lenguaje, así que seguro, seguro, seguro que se puede hacer más mejor, más eficiente y más todo. Pero por algo hay que empezar…

Jul 14

Perl

En el libro "the pragmatic programmer" que estoy leyendo he leído una idea que me ha resutlado muy interesante.

Llevamos años peleándonos con tipos de datos -estructuras, enumerados, etc- que deben ser compartidas en los proyectos por varios lenguajes de programación -ada, C++ y java-. Para no tener que generar las estructuras de datos tres veces, cada una en uno de los lenguajes, y no tener que modificar tres veces cuando hay algún cambio, solemos usar una herramienta de elaboración propia. A esa herramienta se le pasan las estructuras en alguno de los lenguajes y genera automáticamente el código en los otros dos.

Sin embargo, no estoy demasiado contento con esa herramienta -la hemos heredado, no es nuestra-. En su primera versión las estructuras, enumerados, constantes y demás se escribian en ficheros de texto, en un lenguaje inventado. Con unos scripts se convertían a C++ y Ada -no a java-. Se nos quedó corta cuando empezamos a meter java y buscamos en el departamento adecuado la siguiente versión, que sí tenía java.

La siguiente versión eran unos scripts de Access, de forma que las estructuras se metían en una base de datos de access y se generaba el código java, ada y C++. Esto tiene dos problemas gordos. El primero es que no era compatible con el antiguo fichero de texto inventado, por lo que no había forma de importar nada. Tuvimos que escribir todos los tipos a mano. El segundo es que meter datos en unas tablas con herramientas visuales es sumamente incómodo. Imagina que en un documento de requisitos en formato word tienes todos los posibles valores de un enumerado. O bien los escribes uno a uno en las tablas de access, o bien los pones en un fichero de texto, con formato de comas y comillas, inventando los campos que faltan a la tabla de access para luego importarla. En fin, un incordio.

En el libro mencionado comenta que el lenguaje ideal para generar estas cosas el perl. Tiene funciones muy potentes para el manejo de cadenas -hereda muchas cosas de awk-, por lo que es fácil interpretar ficheros de texto y generar otros -es decir, leer ficheros de tipos por ejemplo en C++ o XML y generar el equivalente en java-. Al ser scripts, también se pueden lanzar automáticamente en los procesos de compilación, por lo que el la compilación diaria se podrían generar automáticamente todos los tipos para todos los lenguajes utilizados.

Total, que me he puesto a mirar perl para ver si es verdad. Si no me resulta muy costoso, trataré de hacer el script que genere los tipos en los tres lenguajes. Supongo que usaré C++ o Ada como base inicial, puesto que tenemos muchos ficheros en C++, -java me parece más complicado para interpretar-. Lo de perl de momento parece un "lenguaje del demonio", tan complejo de interpretar como awk, aunque supongo que es cuestión de tiempo y paciencia.

Claro, que la otra opción es hacer esta herramienta en java -sin interface de usuario, simplemente comandos, para que asemeje un script y poder lanzarlo automáticamente por las noches- usando la librería javacc, que es capaz de leer muchos ficheros estándar, como los .h de C++.