martes, 8 de octubre de 2013

Exportar un pseudocódigo a un lenguaje real

Desde hace muchísimo tiempo, PSeInt tiene la opción para exportar un pseudocódigo a C++. Es decir, para generar un código C++ que haga exactamente lo mismo que hace un algoritmo en pseudocódigo al ejecutarse en PSeInt. No siempre es posible, pero en general se puede obtener una buena aproximación. El objetivo de esta funcionalidad es bastante dudoso. Definitivamente no está pensado para que generen a través de PSeInt programas reales (es decir, para no tener que aprender un lenguaje real, sino hacerlo acá y convertirlo). Está pensado para servir como ayuda cuando el estudiante empieza a aprender un lenguaje real, luego de haber adquirido lo básico mediante el pseudocódigo. Para generar una sintonía entre lo que ya conoce y lo que está aprendiendo.

El único motivo por el cual se convierte a C++ y no a otro lenguaje es porque C++ es el lenguaje que domino bien, en el cual me siento cómodo, y del cual creo conocer lo suficiente como para decidir cómo conviene hacer las traducciones. Pero muchos docentes que utilizan PSeInt para comenzar, luego pasan a otros lenguajes, y me gustaría que PSeInt también pudiera exportar a muchos de esos otros. En este post voy a contar un poco cómo espero lograrlo, solicitando la colaboración de los docentes (o usuarios en general) que tengan gran conocimiento de esos otros lenguajes para proporcionar ejemplos, y voy a hablar también de los problemas y desafíos que esta traducción supone.

La estrategia entonces para lograrlo, sin que yo tenga que estudiar a fondo esos lenguajes, ni que la gente que sabe de esos lenguajes tenga que estudiar a fondo C++ y meterse en el código de PSeInt, es a través de ejemplos. Mi idea es armar una lista de ejemplos en pseudocódigo que cubran todos los casos o aspectos que necesito considerar a la hora de exportar a un lenguaje real. Cuando alguien quiera colaborar para que PSeInt pueda exportar a un lenguaje X, todo lo que deberá hacer es traducir esos ejemplos desde pseudocódigo a su lenguaje X. Luego yo, a partir de esos ejemplos podré observar y transcribir la reglas de ese lenguaje X.

Ejemplo de un pseudocódigo exportado automáticamente a C++ por PSeInt. 

Desde hace algunas versiones, tengo el código fuente del ejecutable que realiza la traducción relativamente bien modularizado, y preparado para reemplazar las partes que son fuertemente dependientes del lenguaje de salida por versiones alternativas. La mayor parte del trabajo que este traductor realiza, es independiente del lenguaje de salida, y aún en las partes que dependen del lenguaje, hay cosas que son comunes a varios lenguajes. Por ello espero que teniendo los ejemplos apropiados, no sea excesivamente trabajoso agregar estas alternativas.

Traducir las estructuras de control es en general lo más simple. Los problemas para pasar de pseudocódigo a un lenguaje real son los mismos que tengo a la hora de interpretarlo, pero con un agregado. Ahora los tengo que resolver antes de ejecutarlo, ya no puedo tomarme la libertad de esperar a ver qué datos ingresa el usuario antes de terminar de decidir algo. Por esto, muchos pseudocódigo se exportan haciendo suposiciones que no siempre serán válidas. En estos casos, el código generado tendrá un comentario advirtiendo sobre el potencial problema, o indicando la limitación. El ejemplo más claro es el de los tipos de variables: esto es un problema aún al interpretar, peor lo es intentar traducir a un lenguaje fuertemente tipado. Por otro lado, los mecanismos del lenguaje de salida también pueden tener sus particularidades, como por ejemplo el problema de las lecturas de cadenas de texto con cin en C++, donde o bien leemos con getline (y luego tenemos que ver dónde poner un cin.ignore() para evitar los problemas "raros" que aparecen), o bien leemos con >> y limitamos las cadenas a una sola palabra.

También hay que tener en cuenta que algunas instrucciones, funciones, o hasta operadores pueden no tener equivalentes en el lenguaje real y habrá que "simularlos" declarando funciones auxiliares para ello, o utilizando bibliotecas. Por ejemplo, en C++ el operador de potencia ^ se reemplaza por una llamada a la función pow (lo cual obliga además a incluir la biblioteca cmath). Otro ejemplo, sería el caso de la función ConvertirANúmero, que no tiene equivalente, y cuando se requiere debe ser implementada en el código de salida haciendo uso de funciones como sprintf u objetos como los stringstream.

Finalmente, voy a pedir que se abstengan de colaborar quienes muy recientemente hayan aprendido esos lenguajes, ya que me interesa más el punto de vista de alguien con alguna experiencia para que sea capaz de ver los problemas y sopesar las alternativas. Seguramente encontrarán muchas formas de traducir lo mismo, y se requiere un criterio formado para elegir una. Yo he escrito cosas en Python o Java por ejemplo, pero mi poca experiencia con estos lenguajes no me permite detectar los detalles importantes, o preveer las ventajas y desventajas de cada alternativa (si es que al menos soy consiente de su existencia). En el caso de C++, que es el que sí hice, todavía no estoy 100% conforme con las alternativas que elegí, pero de momento es lo mejor que se me ocurre.

En conclusión, para los que dominen bien un lenguaje y quieran contribuir, aquí encontrarán los ejemplos (que iré completando a medida que vaya detectando los problemas) y los lineamientos para hacer y enviar las traducciones. Me interesa primero empezar por lenguajes populares y requeridos como Phyton, Java, Javascript, C# por ejemplo. No voy a poner muy arriba en mi lista de cosas para hacer las traducciones a lenguajes muy específicos y poco populares o que no estén en contexto (que claramente no sean adecuados para aprender a programar). Por ejemplo, difícilmente empiece por la traducción a Befunge, a ensamblador para microcontroladores de máquinas de hacer botellas, o al último grito de la moda en lenguajes que nació ayer y no sabemos todavía si vivirá más de una semana. La idea es que sea útil para docentes que utilizan PSeInt en sus cursos.

16 comentarios:

  1. Me encanta la actitud que usted promueve (AYUDAR A EDUCAR) soy un seguidor de su programa PSeInt, aun cuando lo conocí después de tratar el lenguaje C++ precisamente por que imaginaba una manera de presentar el algoritmo de manera sencilla usando pseudocódigo o diagramas de flujos, técnicas muy poco usadas en la universidad en la que estudio, me encantaría colaborar pero no tengo la amplia experiencia que usted propone, y me falta mucho aun por aprender. Adoro la programación e imparto clases a estudiantes de niveles inferiores usando su software y así des-estigmatizando un poco este bello arte de programar.

    Puesto que no puedo colaborar como querría solo me resta desearle existo en este proyecto y éxito en su vida...

    ResponderEliminar
    Respuestas
    1. Gracias por los comentarios! Utilizando PSeInt en sus clases ya está colaborando con la difusión del proyecto.

      Eliminar
  2. Hola, te comento que en unos días haré una ponencia en un congreso, sobre el uso del pseudocódigo en la enseñanza de la Lógica, y usaré PSeInt para los ejemplos (y te haré publicidad, por supuesto). Veré si puedo ayudarte en tu proyecto con Python. Saludos!

    ResponderEliminar
  3. Mas info de como colaborar en:

    http://pseint.sourceforge.net/index.php?page=psexport.html

    ResponderEliminar
  4. Este el port a HP-BASIC

    EXPORT Deducir_Numero2()
    // port (version 0.0.3) to HP-Prime by compSystems, source code original by PABLO. coder ZINJAI, PSEINT : http://pseint.sourceforge.net
    begin
    print();
    print( "*** Ejecución Iniciada. ***");
    freeze; wait;
    local num_ingresado:=0;
    local total_intentos:=8;
    local num_secreto:= ( rand() mod 100 ) + 1;

    print("Adivine el numero (de 1 a 100)");
    print("Ingrese el # de intentos");
    freeze; wait(2);
    if NOT(input(total_intentos,"Total de Intentos","Intentos=","Digite un # como total de intentos")) then kill; end;
    print(">"+total_intentos);
    local intentos:=total_intentos;
    print("Debug: "+num_secreto);

    if NOT(input(num_ingresado,"Deducir_Numero","Num Ingresado=","Digite un #")) then kill; end;
    print(">"+num_ingresado);
    while num_secreto <> num_ingresado and intentos>1 do

    if num_secreto>num_ingresado then
    print("Muy bajo");
    else
    print("Muy alto");
    end;
    intentos:=intentos-1;
    print("Le quedan "+intentos+" intento(s):");
    freeze; wait;
    if NOT(input(num_ingresado,"Deducir_Numero","Num Ingresado=","Digite un #")) then kill; end;
    print(">"+num_ingresado);
    end;

    if num_secreto <> num_ingresado then
    print("El numero era: "+num_secreto);
    else
    print("Exacto! Usted adivino en: "+ ((total_intentos+1)-intentos) +" intento(s.)");
    end;
    print("*** Ejecución Finalizada. ***");

    freeze;
    return "Done";

    end;

    ResponderEliminar
  5. Estimado: Me gustaria colaborar con este proyecto. Yo soy instructor de PHP en FagDut de Rosario y proximamente usare PSeInt como inicio a la programacion el proximo año. De ser posible una traduccion a PHP seria sumamente util. Espero tus comentarios de como podriamos articular esta traduccion aprovechando los meses de vacaciones. Salu2!

    ResponderEliminar
    Respuestas
    1. Hola Hector. Para colaborar con la traduccion a PHP lo mejor sería trabajar sobre los ejemplos que menciona el post. Los archivos y las instrucciones estan en http://pseint.sourceforge.net/index.php?page=psexport.html

      Eliminar
  6. Hola Pablo, te envié por e.mail los 10 códigos convertidos a "HP-Prime Language"

    Muchas gracias

    Jaime

    ResponderEliminar
  7. Hola Pablo Inicie en el foro, la publicación de como seria un programa codificado en MATLAB según los ejemplos psexport-ejemplos.zip, por favor incorpora este tipo de exportación

    Gracias nuevamente

    ResponderEliminar
    Respuestas
    1. Gracias! En cuanto tenga tiempo trato de agregarlo para la próxima versión.

      Eliminar
  8. Wikipedia sobre el lenguaje D:

    https://es.wikipedia.org/wiki/D_(lenguaje_de_programaci%C3%B3n)

    Para que lo lancen nueva updates de Pseint y agregar en Zinjal al Lenguaje D y los compiladores se descargan desde: http://dlang.org/ (recomienda descargar la version 2) y compiladores debugeadores llamado dub (Paquete de sistema administrado para el entorno D) se descargan desde: https://code.dlang.org/download

    Gracias de antemano, en respuesta desde sourceforge.

    ResponderEliminar
    Respuestas
    1. Ejemplo del Lenguaje D:

      Este programa imprime sus argumentos de la línea de comandos. La función principal main es el punto de inicio de un programa en D, y args es un arreglo de cadena de caracteres que representa los argumentos de línea de comandos. En D, string es un an arreglo de caracteres, que se representa con char[] en D1, o immutable(char)[] en D2.

      1 import std.stdio: writefln;
      2
      3 void main(string[] args)
      4 {
      5 foreach (i, arg; args)
      6 writefln("args[%d] = '%s'", i, arg);
      7 }

      La palabra reservada foreach puede iterar cualquier colección. En este caso, produce una sucesión de índices (i) y valores (arg) desde el arreglo args. El índice i y el valor arg tiene sus tipos inferidos desde del tipo del arreglo args.

      Eliminar
    2. El Ejemplo de "Hola Mundo" en Lenguaje D:

      /* Hola Mundo */

      import std.stdio;

      void main()

      {
      // Iniciar "Hola Mundo"

      writeln("Hello world!");
      }

      O tambien asi:

      /* Hola Mundo */

      import std.stdio;

      void main() {

      // Iniciar "Hola Mundo"

      writeln("Hello world!");
      }

      Eliminar
    3. Para ver el manual online (inclusive lo descargan en PDF, epub, AZW3 y MOBI):

      http://ddili.org/ders/d.en/index.html

      Eliminar
    4. Se de la existencia del lenguaje D, pero nunca lo use para nada ni me puse a investigarlo. Si quiere colaborar con la traducción a ese lenguaje: http://pseint.sourceforge.net/index.php?page=psexport.html

      Eliminar