Titulación: Grado en Ingeniería Informática

Asignatura: Entornos de Programación - Curso 2012/13

Práctica final: Prototipo de entorno de programación


PF. Prototipo de entorno de programación para Ada, C++ o Java

Este ejercicio práctico consiste en desarrollar un prototipo de entorno de programación mediante combinación de herramientas (entorno "toolkit"). Como elemento básico se empleará un editor configurable (MED o Programmer's Notepad), que se combinará con diversas herramientas para dar soporte a una variedad importante de funciones.

El entorno debe soportar un lenguaje de programación de amplio uso. En concreto Ada, C++ o Java. Basta con que soporte uno de ellos, es decir, se trata de un entorno orientado a un lenguaje.

El objetivo final sería conseguir un entorno comparable a otros bien conocidos, con capacidad para ser usados en un ambiente profesional: GNAT-GPS (para Ada), VisualStudio (para C++) o Eclipse (para Java). Por supuesto, el prototipo a desarrollar será sólo un esbozo o maqueta de un entorno profesional, pero el ejemplo profesional que se tome como objetivo servirá para clarificar cómo se espera que operen las funciones concretas que finalmente se implementen en el prototipo. Incluso es posible implementar alguna función concreta que no esté soportada por los entornos profesionales mencionados.

La lista de funciones a implementar es potencialmente ilimitada. Inicialmente se plantea dar soporte a las siguientes:

No se espera que se lleguen a implementar todas ellas. Para obtener la máxima puntuación (10/10) bastará con dar soporte a las funciones básicas (las primeras de la lista) e implementar un cierto número de las otras. Si se implementan más funciones de las esperadas se podrá obtener puntuación suplementaria (hasta un 20% adicional) y compensar calificaciones medianas en otras prácticas.

El trabajo debe empezar por aprender a manejar y configurar el editor (MED o PN), y luego ir implementando poco a poco las funciones indicadas.

PF.1 El editor configurable MED

MED dispone de varios mecanismos de personalización o configuración. Cada elemento de configuración es aplicable en uno de los siguientes ámbitos:

A continuación se describen brevemente los principales mecanismos que se podrán usar en el desarrollo de esta práctica. Para conocer en detalle la manera de configurar cada elemento se debe consultar la información de ayuda (help) en el propio editor MED. Para entender bien los mecanismos lo mejor es ver cómo están configurados los distintos elementos que forman parte de la distribución original de MED.

IMPORTANTE: La descripción que se da aquí corresponde a la versión de MED instalada en el aula, y puede ser ligeramente distinta de la versión actual (MedCX) que puede descargarse de Internet. Si un alumno desea usar la versión del aula en un equipo distinto de los de las aulas, debe realizar una copia del editor instalado en el aula (no se requiere instalación, basta copiar los ficheros).

PF.1.1 Resaltado de sintaxis

Es parte de la configuración de tipo de fichero (file mode). Se configura en OptionsFile mode settings. Se pueden asignar colores y tipos de letra a:

PF.1.2 Secciones de código

El código fuente en edición se considera descompuesto en secciones (sections). Una sección se identifica por la línea de texto en la que comienza y se extiende hasta el comienzo de la siguiente sección o hasta el final del programa. La definición de las secciones es parte de la configuración de tipo de fichero (file mode).

Excepción: la identificación de secciones de código C o C++ está prefijada en el editor, y no puede configurarse.

Las líneas de comienzo de sección se identifican mediante un patrón de texto en forma de expresión regular:

El nombre de la sección donde esté el cursor aparece el recuadro correspondiente a Section display (arriba a la derecha). El recuadro se podrá desplegar para ver la lista de secciones. También se puede ver la lista de secciones en el Section browser, que se activa con el botón  MAIN{}  de la barra de herramientas superior.

PF.1.3 Descripción de proyecto

Se configura en ProjectCreate new project (nuevo proyecto) y en ProjectEdit project (proyecto en uso). La descripción del proyecto incluye, entre otras, información de:

La descripción de un nuevo proyecto se crea a partir de una plantilla de proyecto (project template). A su vez, la descripción de un proyecto concreto se puede guardar como plantilla para crear otros proyectos similares. Esto último se hace mediante ProjectSave project as, marcado la casilla [_] Save as project template.

Una plantilla de proyecto debe incluir sólo elementos genéricos (nombres de los grupos de ficheros, órdenes externas) pero no elementos particulares de un proyecto (nombre del proyecto, directorio de trabajo, ficheros concretos).

PF.1.4 Herramientas externas

Desde el editor se pueden invocar programas externos. Se definen en ToolsTool manager (globales) y como parte de la descripción de proyecto (plantilla de proyecto o proyecto concreto) en la pestaña Commands.

NOTA: Aunque la documentación de MED dice que se puede definir un número ilimitado de herramientas externas, en realidad no es exactamente así. El menú Tools de órdenes globales sólo tiene capacidad para 20 elementos, y cada fichero de definición de proyecto tiene sitio exactamente para 13 órdenes. Esto quiere decir que en un momento dado sólo pueden llegar a estar disponibles simultáneamente 33 herramientas u órdenes externas. Por lo tanto hay que elegir adecuadamente el repertorio total de órdenes a implementar y decidir si conviene definirlas como globales o como locales al proyecto.

NOTA: Para que funcione la opción de recargar el fichero en edición después de ser modificado por una herramienta externa hay que forzar que MED espere a que termine la ejecución de esa herramienta externa. Para ello hay que marcar expresamente la opción de capturar la salida de la herramienta, aunque luego no se haga nada con ella.

PF.1.5 Ayuda sensible al contexto

Un tipo especial de herramienta externa es la que suministra información de ayuda sobre el contenido en edición (external help). Es parte de la configuración de tipo de fichero (file mode).

La función de ayuda se puede definir mediante los siguientes pasos:

La ayuda sensible al contexto corresponde a la función Help on keyword, que se puede invocar poniendo el cursor de texto en un término clave y pulsando el botón derecho del ratón, que abre un menú contextual. También se puede invocar mediante SearchHelp on keyword. Si se han definido varias herramientas de ayuda se usará la primera.

Se puede invocar ayuda general con el botón derecho y el cursor situado en una zona en blanco, o mediante SearchSelect help. En este caso aparece un cuadro de diálogo que permite seleccionar la herramienta de ayuda deseada, si se han definido varias.

PF.1.6 Plantillas de texto

El editor MED permite definir plantillas de texto que sirven para:

Estas plantillas aparecen en la ventana lateral TextLib, organizadas en librerías o grupos de plantillas. La librería Document Templates contiene las plantillas que serán usadas como contenido inicial de los ficheros nuevos. Estos esquemas de fichero se usarán automáticamente al crear un fichero con el menú FileOpen...File selector... (o el icono de abrir), indicando un nombre de fichero que no exista todavía. La elección de la plantilla a aplicar se hace según la extensión del nombre de fichero indicado.

Las plantillas con esquemas de código a insertar en un fichero en edición se agruparán en librerías específicas (no deben estar en Document Templates). En general se creará una librería por cada lenguaje de programación a soportar, que contendrá los esqueletos de diversas construcciones del lenguaje.

Las plantillas pueden tener parámetros, cuyos valores se dan en el momento de invocarlas o se extraen de la configuración de MED o de las variables de entorno del equipo. Estos parámetros pueden aparecer en diversos puntos de la propia plantilla.

PF.2 Preparación del ambiente de trabajo

PF.2.1 Organización de directorios

Se usará una organización de directorios similar al de las prácticas anteriores, separando el código de las herramientas de los ficheros de datos de usuario sobre los que operan. Eso significa que los guiones de las órdenes externas deben estar en un directorio, y el código de ejemplo en otro.

IMPORTANTE: no usar nombres de ficheros o directorios con espacios en blanco.

Por otra parte, los ficheros de configuración de MED estarán en un lugar prefijado establecido en la configuración del equipo. En una instalación normal de MED (o MedCx) la configuración está en un subdirectorio de la propia instalación:

      directorio-de-MED\profiles\usuario\
      directorio-de-MED\profiles\MedCx\usuario\

En el aula informática la ubicación establecida es H:\med\usuario\ (donde usuario es el nombre de usuario del alumno). Esa ubicación se establece con la variable de entorno MED_USER_PATH, y el nombre del usuario se encuentra en la variable predefinida USERNAME.

Los ficheros de configuración de MED son particulares para cada usuario. La primera vez que un usuario invoque MED se creará el directorio con su configuración personal, y ahí se copiará la configuración que se distribuye por defecto.

La estructura del conjunto será como la del siguiente ejemplo:

...\bin                →   directorio con las órdenes externas
    |- xxx.bat           →   guiones de órdenes
    |- yyy.txt           →   ficheros de datos, etc. (en su caso)
    |- zzz.awk           →   programas AWK (en su caso)
    `- ...

...\ejemploA           →   directorio con ficheros Ada
    |- uno.adb           →   fichero fuente Ada
    |- dos.ads           →   fichero fuente Ada
    |- uno.mpj           →   descripción de proyecto MED
    `- ...

...\ejemploB           →   directorio con ficheros C++
    |- xxx.cpp           →   fichero fuente C++
    |- xxx.h             →   fichero fuente C++
    |- yyy.cpp           →   fichero fuente C++
    |- ppp.mpj           →   descripción de proyecto MED
    `- ...

H:\med\usuario         →   directorio con la configuración de MED
       |- med-bmp        →   iconos
       |- med-cft        →   herramientas externas
       |- med-mpj        →   plantillas de proyecto
       |- med-syn        →   "modos" de fichero (sintaxis, etc.)
       `- ...

El editor MED invocará las herramientas externas desde el directorio del fichero que se esté editando, en este caso el directorio con los ficheros de ejemplo. Para que la herramienta se invoque simplemente por su nombre, el directorio bin se incluirá en la lista del PATH al comienzo de una sesión de trabajo, antes de invocar MED:

...> path camino-a-bin;%PATH%   →   directorio de órdenes en el PATH
...> cd camino-a-ejemplos       →   ir al directorio con el código de ejemplo
...> med                        →   invocar MED con el PATH adecuado

PF.2.2 Cómo copiar la configuración de MED

Como se ha indicado, la configuración de MED es para un usuario determinado en un equipo determinado. Si se quiere transferir la configuración a otro usuario o equipo hay que copiar todo el árbol de directorios y ficheros.

Para que la configuración siga operando en la ubicación de destino es necesario que no contenga referencias a elementos particulares del equipo, sino que todas las referencias a ficheros o directorios sean relativas. En particular hay que evitar incluir ningún camino (path) al designar los ficheros con órdenes o heramientas externas, incluidos los ficheros de ayuda (.hlp). Hay que hacer referencia a todos estos ficheros sólo por su nombre, y organizar el ambiente de trabajo de modo que estén en el PATH activo en el momento de invocar MED.

Para facilitar la copia de la configuración de la versión MED instalad en el aula se suministran dos guiones de órdenes para salvar y restaurar la configuración. La manera de invocarlos es:

...> med-salvar camino-a-la-copia
...> med-restaurar camino-a-la-copia

La primera orden (med-salvar) copia todo el contenido de H:\med\usuario al destino que se indica. La segunda (med-restaurar) hace la operación inversa. Ejemplos:

...> med-salvar backup\prueba1
     ... modificar configuración ...
...> med-salvar backup\prueba2     (se guarda la nueva configuración)
...> med-restaurar backup\prueba1  (se vuelve a la configuración anterior)

NOTA IMPORTANTE: Para que la copia de la configuración de MED pueda restaurarse y probarse en otro equipo es fundamental que las referencias a ficheros (ejecutables u otros) no contengan ningún "path" fijo, es decir, que no hagan referencia a unidades de disco o directorios particulares de una máquina. Para facilitar la detección de este posible problema se suministra una utilidad pf-check que puede descargarse desde esta página web (pf-check.zip - descomprimirla en cualquier directorio y ejecutar ahí pf-check.bat). Esta utilidad analiza el contenido de los ficheros de configuración de MED e imprime una lista de las referencias a ficheros que pueden resultar problemáticas.

PF.2.3 Entorno para cada lenguaje de programación

En algunos casos puede haber conflicto de nombres entre los compiladores o herramientas correspondientes a los lenguajes de programación a soportar. Por ejemplo, el compilador GNAT de Ada y el compilador de C++ de GNU comparten ciertos elementos de la herramienta de compilación gcc, pero con versiones distintas e incompatibles.

El conflicto se da al pretender invocar las utilidades sólo por su nombre, sin indicar un path específico. Esto es necesario para que la configuración de MED se pueda transportar a otro lugar.

Para evitar conflictos se han preparado sistemas de arranque diferentes para iniciar la ventana de órdenes con un PATH de sistema diferente según el lenguaje de programación de los ejemplos. El arranque se hará usando el icono de acceso directo apropiado en la raíz del disco J: con el material de la asignatura:

PF.3 Funciones y herramientas de soporte

En la tabla siguiente se muestra una lista detallada de funciones a implementar en el prototipo de entorno. Por cada función se indican algunas herramientas externas concretas o mecanismos de configuración de MED que pueden usarse para implementarla, dependiendo del lenguaje de programación a soportar.

Herramienta o mecanismo de soporte
Función Ada C++ Java
* Definición de proyecto MED (project) MED (project) MED (project)
* Resaltado de sintaxis MED (file mode) MED (file mode) MED (file mode)
+ Compilar gnat-gcc g++ javac / gcj
+ Montar (make) gnatmake make javac / gcj
+ Ejecutar script / gdb script / gdb script / jdb
+ Navegar MED (sections) / gnatfind MED (sections) / cscope MED (sections) / Global
  Prettyprint gnatpp astyle BeautyJ
  Crear código MED (textlib) / gnatstub MED (textlib) MED (textlib)
  Ayuda sobre el lenguaje Ada WikiBook cppreference j2se7.chm
  Pruebas de unidades AUnit / gcov CppUnit / gcov JUnit
  Control de versiones Subversion Subversion Subversion
  Documentación AdaBrowse / AdaDoc Doxygen Javadoc
  Diagramas [----] [----] [----]
  Métricas gnatmetric cccc CyVis

Las funciones marcadas con (*) o (+) se consideran básicas, y deben ser implementadas en todo o en parte, respectivamente. Las siguientes secciones describen con más detalle los requisitos de cada función y la manera de implementarla.

Sugerencia: Revisar el material de la asignatura sobre las funciones de un entorno de programación. En particular:

PF.4 Mecanismo de definición de proyecto

En esta parte de la práctica se definirá una plantilla de proyecto para usar el compilador que corresponda y agrupar los ficheros fuente de manera organizada. Para ello se creará primero un proyecto particular usando el código de ejemplo del programa dibujar, y luego se registrará como plantilla de proyecto (project template) para poder crear proyectos nuevos a partir de él.

Los pasos a dar para crear el proyecto de ejemplo "Dibujar" son los siguientes:

  1. Crear un directorio de trabajo y copiar en él los ficheros fuente del ejemplo.
  2. Invocar ProjectCreate new project.... El nombre del fichero con el nuevo proyecto será dibujar.mpj, y se creará en el directorio de trabajo anterior. Se usará como esquema de partida una plantilla de proyecto apropiada entre las que están predefinidas en MED:
  3. Dar  Ok .
  4. Dar nombre al proyecto (en la pestaña Project). Se llamará "Ajustar".
  5. Especificar el directorio de trabajo (en la pestaña Project). Se indicará el directorio de trabajo con los ficheros fuente.
  6. Corregir los grupos de ficheros, si es necesario (en la pestaña File groups):
  7. Dar  Aceptar .
  8. En el panel izquierdo (pestaña project) seleccionar cada grupo de ficheros, dar botón derecho → Add files... y seleccionar los ficheros adecuados.

A continuación se comprobará que el proyecto se puede utilizar adecuadamente, y se irán añadiendo las órdenes para compilar ficheros individuales y montar y ejecutar el programa, etc., tal como se indica en los siguientes apartados. Cada vez que se añadan satisfactoriamente nuevas funciones se guardará el proyecto como plantilla de proyecto mediante los siguientes pasos:

  1. Sacar una copia temporal del proyecto:
    1. Invocar ProjectSave project as...
    2. Dar un nombre de fichero apropiado: ep-gnat / ep-gcc / ep-java.
    3. Dar  Guardar .
  2. Eliminar elementos particulares:
    1. Invocar ProjectOpen project...
    2. Seleccionar la copia temporal anterior.
    3. Editar los grupos de ficheros y dejarlos vacíos.
    4. Editar el nombre del proyecto y poner un valor genérico: EP-Ada / EP-C++ / EP-Java.
    5. Dar  Guardar .
  3. Guardar como plantilla:
    1. Invocar ProjectSave project as...
    2. Marcar la casilla [_] Save as project template.
    3. Dar un nombre de fichero apropiado: ep-gnat / ep-gcc / ep-java.
    4. Dar  Guardar .

PF.5 Lectura del código

Aquí se incluyen funciones para facilitar la lectura del código en edición.

PF.5.1 Resaltado de sintaxis

Se partirá de la definición de la sintaxis que ya está incluida en MED, y se corregirá lo que se considere apropiado para subsanar erratas y omisiones, distinguir categorías de palabras clave, mejorar colores de presentación, etc.

En general se trata sólo de realizar cambios menores.

PF.5.2 Encolumnado

Para conseguir que el código tenga una apariencia uniforme se usará una utilidad de reforma adecuada al lenguaje de programación utilizado. Por ejemplo:

Se definirán dos órdenes para implementar esta funcionalidad. Ambas órdenes se aplicarán al fichero que esté en edición en ese momento:

Sugerencia: Poner la copia de reserva en un subdirectorio con nombre ORG, y con el mismo nombre del fichero original.

PF.6 Construcción del proyecto

PF.6.1 Compilación de un fichero

Deberá implementarse una orden para compilar el fichero en edición, capturando los mensajes de diagnóstico del compilador y facilitando el salto a la posición del error en el código fuente. La orden de compilar, para cada uno de los compiladores recomendados, es:

En todos los casos el nombre del fichero debe incluir la extensión (p.ej. programa.adb/.cpp/.java).

Al definir la orden hay que especificar los patrones para reconocer y analizar las líneas de texto con mensajes de diagnóstico del compilador. En algún caso se pueden usar como guía los patrones de las plantillas de proyecto distribuidas con MED. El formato concreto de los mensajes de error y aviso puede verse simplemente compilando algún fragmento de código con errores.

Opcional: Definir una orden complementaria para realizar sólo una comprobación rápida de sintaxis del código fuente, sin compilarlo a código objeto. Esto depende de si el compilador dispone de opciones para hacerlo.

Opcional: Definir una orden complementaria para realizar una comprobación de consistencia del código (lint), tal como se hizo en la Práctica 1. Esta orden no debe dejar ficheros objeto que puedan interferir en el posterior proceso de compilación o construcción del proyecto.

PF.6.2 Montar el ejecutable de la aplicación

Deberá implementarse una orden para construir el ejecutable de la aplicación. Además esta orden debe recompilar selectivamente los ficheros fuente si es necesario (es decir, siguiendo la idea de make). La ejecución de la orden no debe depender del fichero fuente particular que se esté usando en ese momento. Es decir, la información de cuál es el módulo principal debe poder deducirse del proyecto. Lo más sencillo para eso es obligar a que el nombre del proyecto coincida con el del programa principal, y ese será el nombre que se dé al ejecutable, en su caso.

La orden a invocar, dependiendo del compilador, será:

Puesto que la generación del ejecutable puede implicar la recompilación de algunos ficheros, se debe capturar y analizar la salida de la herramienta externa exactamente igual que se hizo con la orden de compilar.

Opcional: Se puede implementar una orden complementaria (clean) para eliminar los ficheros intermedios de la compilación (.o, .ali, .class, según convenga). O incluso otra orden (rebuild) que limpie los ficheros intermedios y luego invoque la generación del ejecutable, forzando así la recompilación de todos los ficheros fuente.

Opcional: En el caso del lenguaje Java la compilación del programa principal equivale a generar el ejecutable de la aplicación (clase principal, con main). Como complemento se puede implementar una orden adicional para generar el archivo .jar apropiado, que pueda ser distribuido a los usuarios. Para ello hay que generar e incluir en el 'jar' un fichero 'manifest' indicando cuál es la clase principal.

PF.6.3 Ejecutar el programa

Los programas de ejemplo son todos aplicaciones de consola, es decir, se ejecutarán en una ventana de órdenes (consola o terminal de texto), que deberá crearse en el momento de lanzar la ejecución y quedar abierta, para ver los resultados, al terminar el programa, hasta que se pulse alguna tecla. Para conseguirlo la ejecución se hará mediante un guión de órdenes intermedio, que lance el programa y haga luego una pausa.

La orden a definir en MED no debe capturar la salida. Al mandar ejecutar el programa debe ser posible especificar parámetros en la llamada, y opcionalmente redirigir la entrada (y quizá también la salida) desde un fichero de datos. La orden final para ejecutar el programa cambia ligeramente según los casos:

Tal como se ha dicho en la orden de montar el ejecutable, el nombre del programa o fichero ejecutable coincidirá con el nombre del proyecto. Los parámetros (y fichero de datos, en su caso) se pueden introducir sobre la marcha usando la macro %P en la definición de la orden externa en MED.

Opcional: Como complemento se podría desarrollar otra orden para ejecutar el programa mediante un depurador (debugger). Existen depuradores simbólicos para los lenguajes propuestos: gdb para Ada y C++, jdb para Java.

PF.7 Creación de código

Las funciones siguientes ayudan en la creación de código nuevo

P.7.1 Plantilla de fichero

Las plantillas para ser usadas como contenido inicial de ficheros nuevos deben incluirse en la librería Document Templates. Estas plantillas deben tener una cabecera de documentación, con datos de proyecto, autor, fecha, etc. obtenidos automáticamente. Además contendrán un esqueleto de código adecuado al tipo de fichero que se está creando. La plantilla debe especificar el patrón de nombre de fichero al que se aplica (en general, la extensión). Si hay más de un tipo de fichero con la misma extensión, habrá que intentar parametrizar la plantilla usando variables de usuario (Userdefined variables) para elegir entre los tipos posibles, es decir, para elegir entre varios fragmentos de texto que distingan un tipo de otro.

Las plantillas a implementar, dependiendo del lenguaje elegido, serán:

Las plantillas se usan automáticamente al abrir un fichero que no exista de antemano: File open (File selector), dar un nombre nuevo. Se usará la plantilla que corresponda a la extensión del nuevo nombre de fichero.

PF.7.2 Plantillas de elementos

Estas plantillas no deben estar en la librería Document Templates, sino en librerías particulares para cada lenguaje de programación. MED incluye ya una para C++, que se usará como base. Para los otros lenguaje hay que crear librerías nuevas (TextLib). Debe haber plantillas para los elementos de nivel superior del código (paquetes, clases, procedmientos, funciones, ...) y para las sentencias estructuradas principales (if-then-else, switch/case, try-catch, bucles, ...).

Las plantillas pueden pedir algún dato indispensable en el momento de aplicarlas (tal como el nombre del procedimiento o función), pero no deben insistir en que se rellene desde el principio todo el esquema de código. Sólo debe generarse un esqueleto vacío, que se irá editando luego poco a poco.

Las plantillas se insertarán activándolas en el panel izquierdo con el cursor situado en el punto del fichero fuente deseado.

PF.7.3 Generación automática

En este punto se trata de implementar facilidades para la creación automática de ciertos fragmentos de código a partir de una especificación declarativa más sencilla. En este caso nos limitaremos a generar un esqueleto de código de implementación a partir del código de la especificación de un módulo. Esto sólo es aplicable en los lenguajes Ada y C++, que usan ficheros fuente separados para la especificación y la implementación de cada módulo. En el caso del lenguaje Java sólo hay un fichero fuente por cada módulo.

PF.8 Ayuda sensible al contexto

El objetivo es disponer de acceso directo a un documento de ayuda o referencia indexado por las palabras clave del lenguaje y, si fuera posible, por los nombres de las funciones de librería estándar. Realmente la parte más difícil es localizar un documento de ese tipo ya preparado.

Una vez encontrado ese documento (o documentos) se escribirá un guión de órdenes para activarlo, pasándole como argumento el término de índice. Si se trata de un documento con formato de Ayuda de Windows (.hlp o .chm) no es necesaria ninguna orden intermedia.

Se usará el mecanismo de configuración External help de MED dentro del File mode correspondiente al lenguaje de programación elegido: Ada, C++ o Java. La ayuda se invoca como se ha indicado anteriormente al describir las capacidades de configuración de MED.

Un ejemplo de fichero de ayuda Windows para Java es j2se7.chm, que ya está instalado y se puede usar directamente. Para C/C++ se dispone de cppreferencecom_feb09.chm, también ya instalado.

Otro ejemplo, para usar mediante una orden intermedia, son los manuales de la librería de C de Cygwin. Se puede pedir ayuda sobre una función estándar mediante la orden:

info cygwin Newlib Library función

Si no se dispone de un fichero de ayuda local, también es posible invocar ayuda en Internet. Para eso hace falta conocer un sitio con la información de referencia y alguna forma de componer una URL válida para cada término clave. Por ejemplo, se puede obtener ayuda sobre las palabras reservadas de Ada o Java, respectivamente, con las órdenes:

start http://en.wikibooks.org/wiki/Ada_Programming/Keywords/palabra-clave
start http://en.wikibooks.org/wiki/Java_Programming/Keywords/palabra-clave

Finalmente, si existe un documento de ayuda pero no está indexado exactamente por los términos deseados (palabras clave y nombres de funciones de librería), se podría crear un índice que traduzca esos términos deseados a los términos del índice real del documento de ayuda. Así se permitiría un uso amigable de dicha ayuda.

Objetivos:

  1. Encontrar la declaración o definición de un identificador desde un punto en el que se use.
  2. Encontrar todas las referencias a un identificador desde donde se declara o define.

El concepto de secciones del editor MED permite cumplir el objetivo (1) para ciertos tipos de identificadores. Para conseguir el objetivo (2) es preciso utilizar herramientas externas específicas para cada lenguaje de programación.

PF.9.1 Encontrar la definición de un símbolo

La distribución de MED incluye definición de secciones para muchos lenguajes, incluidos Ada, C++ y Java. Esa configuración inicial puede tomarse como base de partida y corregir lo necesario para mejorarla. En el caso de C++ no es posible modificar nada (a menos que se configure totalmente partiendo de cero). En el caso de Ada y Java conviene hacer algunos retoques para subsanar deficiencias, y ampliar si es posible los tipos de símbolos que pueden usarse para navegar por el código fuente.Por ejemplo:

Si se definen correctamente los patrones para identificar las líneas de comienzo de sección, y extraer como nombre de la sección el identificador definido en ella, será posible navegar por el código usando los botones Section Browser  MAIN{} , Jump to section  ↓MAIN  y Return to calling section  ↑MAIN  para localizar la declaración y definición de un símbolo desde donde se esté usando, y volver a ese punto.

PF.9.2 Encontrar las referencias a un símbolo

Existen programas de utilidad que realizan un análisis del código fuente y generan tablas indicando los puntos en que está definido y utilizado cada símbolo. Por ejemplo:

La salida de la herramienta debe capturarse y analizarla con los patrones adecuados para extraer el nombre del fichero y el número de la línea de cada aparición del símbolo. Haciendo clic sobre estas líneas de salida se debe saltar automáticamente al punto del fichero fuente correspondiente.

PF.10 Prueba de unidades

PF.10.1 Preparación del código de pruebas

Existe un framework para pruebas de unidades cuyo uso está bastante extendido. Se denomina genéricamente xUnit, y existen versiones particulares, es decir, herramientas de soporte, para cada lenguaje de programación en particular:

El código de prueba se desarrolla usando una notación específica (en Java se emplean anotaciones: @Before, @After, @Test, ...) y puede contener llamadas a una librería de soporte específica que facilita comprobar el estado y resultados de las pruebas (assert(), ...).

Para facilitar las escritura de las pruebas se pueden desarrollar plantillas con el esquema global de una clase Java que siga el esquema JUnit, y plantillas individuales para cada fragmento de código (@Before, @After, @Test, ...) con sus variantes.

PF.10.2 Ejecución de las pruebas

El código de prueba puede compilarse como cualquier otra pieza de código fuente. La ejecución suele hacerse usando código de apoyo específico que captura los resultados de la ejecución y genera informes con un resumen de los resultados.

En Java el código de apoyo es la librería junit-x.y.jar (x.y es la versión, p.ej. 4.10). La ejecución de un código de pruebas, tal como TestPalabra, se invoca con la orden:

java -cp .../junit-4.10.jar org.junit.runner.JUnitCore TestPalabra

Esta orden se definirá como herramienta externa, indicando que se capture la salida y se identifique el punto del código fuente al que corresponda cada fallo detectado, de manera similar a como se analizan los mensajes de error en la compilación.

PF.10.3 Pruebas de cubrimiento

Este tipo de pruebas tiene como objetivo particular comprobar que los ensayos a los que se somete un programa provocan, en lo posible, que se ejecute al menos una vez cada una de las sentencias que componen el código fuente.

Para dar soporte a este tipo de pruebas no basta con disponer de librerías de apoyo específicas, sino que es precisa la colaboración del propio compilador, que debe ser capaz de generar código objeto que incluya internamente instrucciones para contar la ejecución de cada sentencia o línea de código. Estos recuentos se almacenan en ficheros binarios, que pueden ser leídos e interpretados por alguna utilidad específica una vez realizadas las pruebas.

En el caso de Ada, C y C++ compilado mediante GNAT/gcc la utilidad de apoyo es el programa gcov, que lee los ficheros con los recuentos y genera un informe en forma de listado del código fuente anotado con el número de veces que se ha ejecutado el código de cada línea.

El procedimiento a seguir para realizar pruebas de cubrimiento es el siguiente (particularizado para C++):

  1. La compilación debe hacerse con opciones adicionales para generar el código complementario que va registrando la traza de ejecución:
        g++ -fprofile-arcs -ftest-coverage -Wall -c fichero.cpp
  2. En la orden de montar el programa ejecutable puede ser necesario incluir explícitamente la librería gcov:
        g++ -o programa fichero1.o fichero2.o ... -lgcov
  3. La ejecución del programa se realiza normalmente. La única diferencia es que se generarán los ficheros especiales con información de la traza de ejecución. Estos ficheros llevan el mismo nombre de cada fichero fuente, y la extensión .gcda.
  4. Si se ejecuta el programa varias veces los resultados se van acumulando en los ficheros .gcda. De esta manera se puede saber el resultado global de una serie de pruebas. Por supuesto, antes de iniciar una nueva serie hay que reponer a cero los contadores de la traza, lo cual se consigue simplemente borrando los ficheros .gcda.
  5. El análisis de la traza de ejecución se realiza con la herramienta gcov, que se invoca de la forma:
        gcov fichero.cpp
    Esta orden genera un fichero de texto, con el nombre fichero.cpp.gcov, que contiene un listado del fichero fuente, anotado con el número de veces que se ha ejecutado cada línea que contenga alguna sentencia ejecutable. Las líneas de código con sentencias que no se han ejecutado nunca aparecen marcadas con #####. Esta marca señala, por tanto, las partes del código que no han sido probadas durante la ejecución del programa.

PF.11 Control de versiones

Estas funciones son independientes del lenguaje de programación utilizado. Simplemente operan sobre ficheros de texto cualesquiera (o incluso ficheros binarios). Por lo tanto se configurarán como herramientas globales en el menú Tools.

La puesta a punto de un procedimiento de trabajo con control de versiones suele ser bastante laboriosa. Hay que establecer una organización razonable del repositorio, los directorios de trabajo, la política de cambios, etc. A continuación se da una receta sencilla aplicable en esta práctica usando Subversion. Las acciones iniciales se han de realizar desde fuera del editor MED (dando las órdenes a mano, o ejecutando guiones de órdenes preparados de antemano). Por lo tanto estas órdenes iniciales no se configuran como herramientas externas de MED:

  1. Crear el repositorio, inicialmente vacío. Sólo hay que hacerlo una vez en esta práctica final:
    svnadmin create H:\SVN
  2. Importar los ficheros fuente de un ejemplo como versión inicial en el repositorio ya creado. Sólo hay que hacerlo una vez con cada aplicación de ejemplo:
    svn import fuentes-1 file:///H:/SVN/ejemplo-1 -m "Inicial"
    El nombre fuentes-1 corresponde al material que se suministra para probar. El nombre ejemplo-1 es con el que quedará registrado en el repositorio. Si se estropea el contenido del repositorio es posible importar de nuevo el ejemplo con otro nombre.
  3. Crear una copia de trabajo para operar bajo control de versiones. Esto se puede hacer tantas veces como se desee:
    svn checkout file:///H:/SVN/ejemplo-1
    attrib +R ejemplo-1\*
    Esta orden crea un subdirectorio ejemplo-1 en el directorio actual, conteniendo copias de trabajo de las últimas versiones de los ficheros fuente, y marca todas esas copias como de sólo lectura, para evitar modificaciones accidentales.
  4. En este momento se puede pasar ya a operar con el editor MED:
    cd ejemplo-1
    med

El objetivo de la práctica es poder invocar desde MED algunas funciones básicas para operar con ficheros individuales, es decir, con el fichero en edición (salvo excepciones). Las órdenes externas pueden ser:

PF.12 Generación de documentación

Utilizando una herramienta externa específica para cada lenguaje de programación:

Se usarán estas herramientas para generar documentación de código de un fichero individual, o bien del conjunto de los ficheros del proyecto. La documentación generada se usará de forma totalmente externa al editor MED.

PF.13 Generación de diagramas

El objetivo es generar una representación gráfica de la estructura modular o de clases del proyecto. Posibilidades:

Sugerencias:

El diagrama obtenido se visualizará de forma totalmente externa al editor MED.

PF.14 Obtención de métricas

Se usará una herramienta externa específica para cada lenguaje de programación:

Se invocará la herramienta para procesar todos los ficheros del proyecto, o bien sólo el fichero en edición. Se especificará, si es necesario, que el resultado sea en forma de texto. El informe de métricas se presentará en la ventana de edición de MED, y se definirá un resaltado de "sintaxis" (File mode) específico, para sea fácilmente legible.

El artificio para conseguir que un fichero se abra automáticamente en el editor es hacer que la salida de la herramienta externa sea el equivalente a un mensaje de diagnóstico (como los del compilador) con información del nombre del fichero (no hace falta número de línea ni columna). La configuración MED de la herramienta externa especificará que se debe abrir automáticamente el fichero referenciado si se detecta un mensaje de diagnóstico (error, aviso o simplemente información).

Si la utilidad externa no es capaz de generar el informe con formato de texto plano, entonces se podrá visualizar dicho informe fuera del entorno MED, aunque sería mejor procesar dicho informe con un formato apropiado (tal como XML) y convertirlo a texto mediante código AWK o otro adecuado para poder visualizarlo dentro del entorno.

Opcional: Como complemento, se puede analizar el texto del informe de métricas y marcar aquellos valores que se salgan de ciertos límites establecidos.

Apéndice A. Sugerencias para implementación

En general es preferible escribir un guión (script) por cada herramienta o función externa, en lugar de invocar directamente el programa externo ejecutable. De esta manera se pueden simplificar los parámetros que ha de suministrar MED, y además se pueden probar bien las funciones externas ejecutándolas primero manualmente desde la consola de órdenes, antes de intentarlo desde el editor.

Las referencias a órdenes externas deben hacerse simplemente por su nombre, sin indicar el "path" particular en que se encuentren en una máquina en concreto. Para que un programa se pueda invocar simplemente por su nombre hay que incluir previamente en el PATH del equipo el directorio en que se encuentra el programa ejecutable.

Apéndice B. Lista de comprobaciones

Como ya se ha ido indicando, la manera de probar el funcionamiento del entorno es abrir con el editor MED algunos de los ficheros de ejemplo que se suministran, e ir invocando las distintas funciones. Por supuesto, se pueden hacer pruebas con otros ficheros de los que disponga el alumno, obtenidos de Internet u otras fuentes.

Las pruebas con ejemplos de código de proyectos reales son especialmente interesantes, porque pueden poner de manifiesto las limitaciones del prototipo de entorno desarrollado respecto a un entorno de programación profesional.