Proyecto Fin de Carrera I Enunciado 2: Analizador de programas escritos en Turbo Pascal Orientado a Objetos Indice: Pag. 1. Introducción.
3
2. Especificación de Requerimientos Software de la aplicación a desarrollar.
4
3. Manual de Usuario.
12
4. Manual del Programador.
16
5. Listados del código fuente de la aplicación desarrollada.
23
6. Listados de las propiedades y eventos empleados en la aplicación.
48
7. Calendario del Proyecto
63
Introducción Este proyecto consiste en implementar un explorador de código sobre un programa en Turbo Pascal Orientado a Objetos. Para la ejecución de nuestro proyecto partimos de un programa en Pascal compilado y que funciona correctamente, por tanto no podemos ejecutar un programa escrito con otro compilador ni, por supuesto, uno que no funcione correctamente. Partiendo de estos hechos, abrimos un programa fuente, y al ejecutar nuestro proyecto generamos un fichero de tipo registro con el formato dado, en el cual vamos introduciendo las clases, atributos, asociaciones, métodos, herencia ... El proyecto ha sido implementado en Delphi, por tanto es necesario Windows para poder ejecutarlo (3.1 o superior). Decir que hemos utilizado una resolución de 800x600, con un color de alta calidad (high color). De no ser ejecutado bajo estas condiciones, algunas cosas pueden aparecer desplazadas de sitio, llegando incluso a no verse en pantalla, así como las fotografías no visualizarse con la calidad que nosotros deseáramos. Junto al programa se adjuntan los consiguientes manuales, tanto de programador como de usuario, para intentar resolver los problemas que puedan surgir al utilizar el proyecto, así como analizar la forma en la que lo hemos implementado. De todos modos, el programa es muy fácil de manejar al funcionar bajo Windows y ser la interfaz muy simple. Especificación de Requerimientos Software del Proyecto Fin de Carrera I ( Enunciado 2 ). 1
1. Introducción. 1.1. Propósito. El propósito del presente apartado es definir cuales son los requerimientos que debe tener un programa que analice el código fuente de una aplicación escrita en Turbo Pascal Orientado a Objetos y a partir del mismo genere el Modelo de Objetos correspondiente. Esta especificación de requerimientos está destinada a ser leída tanto por los usuarios de la aplicación como por cualquier sujeto que tenga interés en saber como funciona el programa. 1.2. Ámbito. El programa que vamos a describir puede clasificarse como una aplicación de análisis y depuración de programas desarrollados con el lenguaje Turbo Pascal Orientado a Objetos. El presente producto analiza el código fuente de la aplicación en estudio y guarda los resultados de dicho análisis en una Base de Datos interna, a partir de la cual se podrá obtener el Modelo de Objetos de la misma y representarlo en el formato A DETERMINAR. 1.3. Definiciones, acrónimos y abreviaturas. TPOO. Turbo Pascal Orientado a Objetos. OMT. Modelo de Objetos. BDA.. Base de Datos. IEEE. Asociación internacional dedicada a la estandarización de procesos de fabricación y desarrollo. API. Término con el que se conoce un documento asociado a un producto de desarrollo de aplicaciones en el que se explica detalladamente el mismo (Interfaz del Programador de Aplicaciones). CUA. Documento desarrollado por IBM que normaliza el comportamiento de una aplicación de ventanas. [4] Icono. Una imagen de bits miniatura que normalmente realiza una acción al ser seleccionada. 1.4. Referencias. Para la realización de este texto se han tenido en cuenta los siguientes documentos: [1] Guía del IEEE para la Especificación de Requerimientos de Software. Boletín de prácticas de la asignatura de Ing. del Software de la EUI, UPV. 1996. [2] Object Modeling Technique. XXXXX [3] El API de Windows se explica en muchos libros, pero una relación completa del mismo puede encontrarse en el archivo windows.h del paquete Borland C++. [4] Lee Adams. Programación Avanzada en de Gráficos en C para Windows. McGraw−Hill / Interamericana de España, S.S. 1993. Pág. 24.
2
2. Descripción general. A continuación vamos a ver los factores que afectan al producto y a sus requerimientos. 2.1. Perspectivas del producto. El presente producto debe ser un programa en Borland Delphi para Windows y como tal debe cumplir todas las especificaciones de un programa que funcione bajo Windows, así como beneficiarse de las ventajas que ello supone, como es la sencillez de la interface con el usuario que tal sistema utiliza. Por lo tanto el programa podrá ser ejecutado en cualquier estación de trabajo que funcione bajo el sistema Windows. Como el programa a desarrollar es, básicamente, un analizador de código, ello permitirá que con la misma estructura de este programa se pueda generar otro semejante que trabaje sobre aplicaciones escritas en otros lenguajes similares al TPOO, como por ejemplo el TURBO C++ y el BORLAND C. 2.2. Funciones del producto. Las funciones que debe realizar el producto las podemos clasificar en varios bloques: a) Obtención de los datos necesarios para realizar el análisis. − Obtención del código fuente del programa principal de la aplicación a estudiar. − Obtención del código fuente de los distintos subprogramas que componen la aplicación a estudiar. − Obtener los objetos de la aplicación a estudiar y almacenarlos en una BD para su utilización posterior. − Obtener los atributos y métodos de dichos objetos y almacenarlos en una BD para su utilización posterior. − Obtener los enlaces entre objetos de la aplicación y almacenarlos en una BD para su utilización posterior. b) Almacenamiento del fichero de resultados. − Almacenar en un fichero los datos contenidos en la BD. − Almacenar en un fichero los datos de un archivo de texto que se utilizará para comprobar el buen funcionamiento de la aplicación. c) Herramientas de ayuda en el uso de la aplicación. − Imprimir tanto los datos obtenidos de la aplicación como el fichero de texto generado en el formato determinado. − Configurar la impresora por defecto y el modo de impresión. − Poder cambiar las opciones de representación del fichero de texto con los resultados en lo referente a colores y tipos de letra. 2.3. Características del usuario.
3
A continuación vamos a ver qué tipo de usuario van a usar el producto y como afectan estos a las funciones que debe realizar el producto. En primer lugar aparecen los iniciados en la programación con TPOO que pueden usar el producto para la obtención rápida del Modelo de Objetos de una aplicación sobre la que estén trabajando. Este tipo de usuarios esperarán un tiempo de respuesta muy breve y la posibilidad de obtener el OMT de la aplicación que estén estudiando en el formato que ellos deseen, así como una copia impresa de los resultados, tanto del modelo como de la información obtenida de los objetos de la aplicación. El otro tipo de usuarios serán aquellos que están comenzando con la programación en lenguaje TPOO y quieren obtener información fiable, es decir, corregida por un programa de análisis, de la aplicación que estén desarrollando. Dado que el programa trabajará sobre aplicaciones ya acabadas y el proceso de análisis deberá ser rápido y prácticamente automático, la interacción con el usuario será poca y eso hace que el programa no tenga ningún tipo de limitación idiomática, por lo que puede fácilmente ser utilizado por usuarios extranjeros. Cabe la posibilidad de hacer que el programa funcionara en otros tipos de máquinas con distintos sistemas operativos (MS−DOS, Linux, etc.) escribiéndolo en TP, tal modificación es bastante sencilla, ya que el Borland Delphi y el Turbo Pascal son muy similares. De esta forma se podría realizar todo el proceso de obtención del OMT desde la línea de comandos, lo cual daría más rapidez a la aplicación. 2.5. Supuestos y dependencias. El presente producto depende enteramente de Windows y donde llega Windows 3.1 y sus futuras versiones (Win `95, Windows NT ...) debe poder llegar el programa, ya que debe cumplir todas las normas Windows expresadas en su API (Interfaz de para el Programador de Aplicaciones). 3. Requerimientos específicos. 3.1. Requerimientos funcionales. 3.1.1. Obtención del código fuente del programa principal de la aplicación a estudiar. El programa a desarrollar deberá abrir el fichero fuente del programa principal de la aplicación que se estudie, para poder analizar el código de esta, así como aquellos otros módulos de código (unidades de programación) de los cuales se sirva. 3.1.2. Obtención del código fuente de los distintos subprogramas que componen la aplicación a estudiar. El presente producto debe ser capaz de acceder al código fuente de aquellos subprogramas en los que se basa la aplicación que se estudie, para poder analizar también dicho código. Sin esta operación solo se podría analizar un bloque de código fuente, el del programa principal, perdiendo toda relación con las demás unidades en las cuales se apoye, por lo tanto, esta operación se deberá realizar sobre el programa principal y sobre cada uno de los subprogramas que utilice. Esta función deberá tomar de la línea uses del código fuente de la unidad en estudio los nombres de las unidades en las cuales se basa, comprobar si esta disponible el código fuente de las mismas, para que en caso negativo sean ignoradas, y en caso de que exista pueda se analizado posteriormente. 3.1.3. Obtener los objetos de la aplicación a estudiar y almacenarlos en una BD para su utilización posterior. 4
La aplicación en una primera pasada del código en estudio deberá obtener los nombres de los objetos que se definan en la unidad estudiada y almacenarlos en un formato determinado en una BD. Para ello bastará con estudiar las líneas donde se halla la instrucción Object de TPOO y comprobar si se trata o no de una herencia, a fin de poder incluir tal información en la BD, tomar el nombre y guardar la información obtenida en la BD. 3.1.4. Obtener los atributos y métodos de dichos objetos y pasar a almacenarlos en una BD para su utilización posterior. En el lenguaje TPOO cuando se define un objeto, a continuación se definen los atributos y métodos propios de él, esto es lo que analizará nuestro programa, línea a línea en el código a estudiar. Para ello se deberá tener en cuenta que cada nombre de atributo va seguido de dos puntos (:), a continuación el tipo de dato de que se trata (integer, real, string...) y finalmente un punto y coma (;). No hay que olvidar que varios atributos pueden ser definidos en la misma instrucción separando sus nombres con comas (,). En lo referente a los métodos, estos siempre van precedidos de la instrucción procedure o function, por lo que su identificación aún es más simple. Toda la información obtenida deberá guardarse en la BD incluyendo para cada método y atributo a qué objeto pertenece. 3.1.5. Obtener los enlaces entre objetos de la aplicación y pasar a almacenarlos en una BD para su utilización posterior. Nuestra aplicación deberá ser capaz de identificar las relaciones entre los distintos objetos del código en estudio, es decir, deberá estudiar las llamadas que cada método del objeto hace a los otros objetos y comprobar si tal llamada es a un método propio o pertenece a otro objeto. Esta función deberá leer cada línea de código, verificar si hay llamadas a los métodos asociados a objetos (objeto.método), extraer el objeto al cual se llama y comprobar si es el objeto al cual pertenece el método que se esta estudiando en ese momento. Si no lo es ya podremos decir que entre los dos objetos se establece una relación. Luego deberemos recorrer la lista de objetos de la BD para ver si el objeto al cual se llamaba esta en ella, en caso afirmativo solo estableceremos la relación entre los dos objetos, pero en caso negativo deberemos averiguar a que unidad pertenece ese objeto y analizarla posteriormente. 3.1.6. Almacenar en un fichero los datos contenidos en la BD. La aplicación deberá disponer de capacidad para almacenar en un fichero los datos que haya almacenado en la BD interna, como fruto del análisis de un programa en TPOO. Dicha función deberá ser similar a las que utilizan los demás productos desarrollados para Windows, ya que al trabajar bajo ese entorno los usuarios están acostumbrados a emplear una interface que les resulta tan familiar. 3.1.7. Almacenar en un fichero los datos de un archivo de texto que se utilizará para comprobar el buen funcionamiento de la aplicación. Además del fichero anterior y con el fin de evitar confusión a la hora de comprobar el correcto funcionamiento del programa, se creará un archivo de texto, visible desde la propia aplicación a traves de la apertura de un archivo, cuyo contenido será igual al del fichero de resultados pero esta vez en formato de texto.
5
3.1.8. Imprimir tanto los datos obtenidos de la aplicación como el fichero de texto generado en el formato determinado. 3.1.9. Configurar la impresora por defecto y el modo de impresión. 3.1.10. Poder cambiar las opciones de representación del fichero de texto con los resultados en lo referente a colores y tipos de letra. 3.2. Requerimientos de interfaces externos. 3.2.1. Interfaces de usuario. En este apartado, vamos a hablar de los procesos existentes entre el ordenador y el usuario. Para ello abordaremos en primer lugar el comportamiento del producto en la pantalla. El usuario pretende ver cuando ejecuta una aplicación Windows un comportamiento semejante al de todas las aplicaciones diseñadas para este sistema. Por ejemplo todas las aplicaciones permiten configurar la impresora, realizan llamadas a Windows y muestran un cuadro de dialogo común diseñado por el fabricante.
Por ello, la aplicación contendrá cuadros de dialogo para acceder a los ficheros (obtener y almacenar), semejantes a los que ofrece Windows. Otro aspecto a tener en cuenta, es que la aplicación deberá tener zonas de selección, iconos o botones que activen distintas acciones del programa. Los menús de la aplicación deben seguir el orden que encontramos en 6
todas las aplicaciones y que esta plasmado en el documento CUA de IBM. En cuanto a las entradas realizadas a través de teclado, debemos destacar algunos aspectos, como tener teclas de acceso rápido a los elementos del menú, así como a los elementos dentro de los cuadros de dialogo. Por supuesto deben respetarse los comportamientos estándares dentro de los cuadros de dialogo, como por ejemplo, usar la tecla
para avanzar los campos de textos. 3.2.2. Interfaces hardware. Inicialmente, el presente producto puede usar todos los dispositivos que admite Windows. Hacer una lista de todo el hardware compatible Windows es demasiado extenso y contraproducente. Hay que destacar el concepto de independencia que aporta el desarrollo de programas bajo sistemas tan extendidos como Windows. 3.2.3. Interfaces software. El producto que estamos describiendo se desarrolla bajo el sistema operativo MSDOS en su versión 6.2, y sobre dicho sistema, se ha usado Windows 3.1 como entorno sobre el que se va a ejecutar la aplicación. En ultima instancia, la aplicación usa las funciones de los interfaces de Windows y por tanto, realmente no depende de MSDOS. De hecho existen versiones superiores de Windows que son completos sistemas operativos, como Windows NT o Windows 95. En principio, el presente producto debe usar las funciones de los tres interfaces que presenta Windows 3.1. Dado que el API de Windows 3.1 posee cerca de 1000 funciones, a continuación se presenta una breve descripción de los más usuales. 3.4. Restricciones de diseño. 3.4.1. Estándares cumplidos. Como ya se ha especificado, la aplicación desarrollada deberá cumplir todos los estándares propios del sistema Windows bajo el cual va a trabajar. Manual de usuario Como hemos mencionado anteriormente, la interfaz de usuario es muy sencilla de entender y manejar, aun así comentaremos brevemente el manejo de la aplicación. Hemos dividido la pantalla en: − Menú principal de aplicación. − Barra de herramientas. − Panel de controles. − Tres cajas de edición. Menú principal. El menú principal de la aplicación consta de cuatro opciones, que pasamos a enumerar: Fichero: En esta opción se incluye un submenú bastante estandard de todas las acciones que se suelen realizar con archivos. Estas son: 7
Abrir: Aparece la pantalla estandard de Windows para abrir ficheros y abre el fichero seleccionado, colocándolo en una de las cajas de edición. Imprimir: Aparece la pantalla estandard de Windows para imprimir ficheros. Imprime el texto situado en la caja de edición activa (donde está el cursor). Las cajas se activan pinchando sobre ellas con el ratón. Por problemas con el Delphi, para poder imprimir con un tamaño normal, hay que ampliar considerablemente el tamaño de la fuente. Configurar impresoras: Aparece la pantalla estandard de Windows para configurar impresoras, pudiendo adaptar la impresión a la impresora que se posea. Preferencias: En esta opción hay otro submenú, que tepermite cambiar el color de fondo y el estilo, color y tamaño de la fuente de la caja de edición activa en ese momento. También utilizamos las ventanas estandard de Windows. Salir: Termina la aplicacion. Ejecutar: Contiene un submenú con la opción Ejecución que permite ejecutar la aplicación. Esta opción no estará activa hasta que no se tenga un fichero abierto. Ver Resultados: Contiene un submenú con la opción Visualizar Resultados que permite visualizar el fichero donde ha sido almacenada la ejecución de la aplicación. El submenú no estará activo hasta que no se haya ejecutado el programa. Acerca de... : Contiene un submenú con la opción Acerca de... que visualiza los componentes que han realizado esta aplicación. En todas las opciones se han incluido aceleradores de teclas para su manejo mediante teclado. La combinación a utilizar es la tecla + la letra subrayada de la opción correspondiente. Barra de herramientas. En esta barra se incluyen cuatro botones que se corresponden con las subsiguientes opciones del menú principal. Estas son: − Abrir fichero. − Imprimir. − Cambiar color, estilo y tamaño de fuente. − Cambiar color de fondo. De todos modos, al situar el ratón sobre cada uno de los botones, aparece un comentario explicativo de la función que desempeña. Los botones de Imprimir y Cambiar color,estilo y tamaño de fuente no están habilitados hasta que no se abra ningún fichero. Panel de Controles.
8
En este panel se incluyen tres botones que se corresponden con las subsiguientes opciones del menú principal. Son estas: − Ejecutar. − Visualizar. − Salir. El botón de Ejecutar no está habilitado hasta que no se abra ningún fichero y el de Visualizar hasta que no se ejecute la aplicación. Cajas de Edición. En la aplicación aparecen dos cajas de edición, inicialmente vacías. Al abrir un fichero, éste aparece en una de ellas. Cuando se ejecuta el programa, las unidades que explora van apareciendo en la otra caja de edición. Además existen etiquetas explicativas sobre cada caja. Al pulsar la opción de Visualizar, aparece otra caja en la cual se situa el fichero con los resultados de la ejecución del programa. Todas las cajas de edición son de sólo lectura, no pudiendo modificar ninguno de los archivos, pese a que el cursor aparezca en la que esté activa en cada momento. Funcionamiento normal de la aplicación. − Se abre el fichero a explorar. − Aparece en una de las cajas de edición. − Se ejecuta la aplicación. El programa pregunta la ruta y el nombre del archivo donde colocar el fichero de registros (los resultados). En caso de existir este archivo, pregunta si se desea sobreescribirlo. Si la ruta introducida no es válida, aparece un mensaje de error y vuelve a pedir una válida. A su vez graba un fichero imprimible en el directorio actual, con el nombre datos.txt. − Si se desea, se visualizan los resultados, apareciendo éstos en otra caja de edición. − El programa permite repetir estos pasos tantas veces como archivos se deseen explorar, saliendo cuando el usuario considere oportuno. Manual del programador. En este manual nos vamos a centrar única y exclusicamente a la explicación de la programación propia de Turbo Pascal, dejando un poco de lado la interfaz de usuario que ha sido implementada en Borland Delphi. De todos modos se adjuntan los listados correspondientes a las propiedades y eventes de todos y cada uno de los componentes de la aplicación (*.DFM). A continuación pasamos a comentar el desarrollo del programa: La aplicación Explorador de codigo consta de dos unidades que se corresponden con dos formularios. La unidad explorar contiene el código principal de la aplicación y la unidad acercade contiene la 9
implementación correspondiente a la ventana de Acerca de, por lo cual nos vamos a centrar en la primera. Dicha unidad contine una clase Texplorador compuesta por los atributos y métodos que se corresponden con las posibles operaciones a realizar desde la interfaz de usuario. Obviaremos el comentario de estos atributos ya que no forma parte de la programación propiamente dicha sino que utilizan las facilidades visuales de Delphi. Si que comentaremos los métodos cuando entremos en la parte de implementación. La estructura de datos que hemos utilizado es un registro que contiene todos los posibles elementos que nos podemos encontrar al explorar las clases de cada programa o unidad. La estrutura básica es la siguiente: elem_diag=record case tipo_elemento(...............) of tipo1: (atributo1, atributo2,...); tipo2: (atributo1, atributo2,...); tipo3: (atributo1, atributo2,...); ... ... tipon: (atributo1, atributo2,...); end; end; Los elementos que nos podemos encontrar son: − programa. − clase. − atributo. − métodos. − especializaciones. − asociaciones. Para cada uno de estos elementos que formarán el archivo de salida se definen los siguientes atributos: Programa: (nombre_pro:string); donde nombre_pro es el nombre de la unidad o programa que estamos explorando.
10
Clase: (nombre_clase:string); donde nombre_clase indica el nombre de cada clase que nos vamos encontrando. Atributo: (nombre_atrib,tipo_atrib:string); donde indican respectivamente el nombre y el tipo del atributo. Método: (nombre_método:string; parametros:reg_parametros); donde el primero corresponde al nombre del método y el segundo es el registro de parámetros que contiene. Especialización: (superclase:string); donde indicamos cuál es la clase padre. Asociación: (con_clase:string); donde indicamos la clase con la que está asociada. Respecto a las variables utilizadas en la aplicación, creemos que quedan suficientemente explicadas en los comentarios del código. Lo único a destacar es que la variable fichero utiliza la estructura de datos comentada anteriormente por lo que contendrá los resultados de la exploración. También nos hemos declarado un fichero de texto auxiliar f para poder visualizar ordenadamente los resultados por pantalla e impresora. Hemos definido el vector registros para contener las posibles asociaciones que puedan surgir dentro de otro registro que se encuentre fuera de la clase. Pasamos a comentar la implementación explicando cada uno de los procedimientos: Procedure AbrirClick(Sender:TObject); Abre el fichero seleccionado mediante la ventana Abrir de Windows y lo asignamos a nombre_fichero. Lo colocamos en la cajaedicion1. En path guardamos la ruta del fichero abierto para la posterior búsqueda de las demás unidades a explorar. El resto es para habilitar o deshabilitar los botones que sean oportunos y para mostrar las etiquetas. En este momento unidades_programa contiene la primera unidad que vamos a explorar (la que acabamos de abrir). Procedure SalirClick(Sender:TObject); Cierra la aplicación. Procedure ColoresClick(Sender:TObject); Cambia el color de fondo de la caja de edición seleccionada (la que tiene el cursor). Procedure TiposdeLetraClick(Sender:TObject); Cambia el color, estilo y tamaño de la fuente de la caja de edición seleccionada. Procedure ImprimirClick(Sender:TObject); Imprime el contenido de la caja de edición seleccionada. Como Delphi sólo permite imprimir objetos Canvas 11
es necesario asignar cada línea de la caja de edición seleccionada a dicho objeto y desde ahí, mandarlo a impresora. Procedure ConfigurarImpresorasClick(Sender:TObject); Permite configurar la impresora que se vaya a utilizar. Procedure AcercadeClick(Sender:TObject); Muestra la ventana del Acerca de... Procedure Leepalabra; Introduce en palabra cada carácter que pueda formar parte de una palabra válida (consideramos caracteres válidos los que forman parte de este conjunto: ['0'..'9' , 'A'..'Z' , 'a'..'z' , 'ñ'..'Ñ' , '.' , '_' , '^'] ) y la convierte a minúscula (función ansilowercase). Procedure Elimina_blancos; Lee caracteres mientras que sean blancos. Function Unidades:boolean; Devuelve true cuando la unidad leída de la cláusula uses de un programa es predefinida de Turbo Pascal. Function TipoAtributo:boolean; Devuelve true cuando el tipo del atributo leído es predefinido de Turbo Pascal o definido por el usuario. Function TipoRegistro(var auxi:string):boolean; Cuando esta función toma el valor true devuelve en auxi la clase con la que está asociada. En el procedimiento Ejecucion explicaremos cuándo utilizamos el registro registro comentado en la estructura de datos. Function repe:boolean; Controla que no se introduzca dos veces la misma unidad en el vector unidades_programa, para no explorarla más de una vez. Function Puntero:boolean; Comprueba si la palabra leída se encuentra en el vector punteros, siendo éstas de tipo puntero y que están en el type de la unidad que está explorando. Procedure InicializaVectores; Este procedimiento borra lo que haya en los vectores puntero, tipos, asoc y registros, que son propios de la última unidad explorada, para introducir los de la nueva. Function AsociacionRepe(pal:string):boolean; 12
Esta función comprueba si la palabra que le pasamos por parámetro, que es una asociacion, ya ha sido almacenada en el fichero de salida, con el fín de no almacenar más de una vez la misma asociación de una clase. Procedure Ejecucion(nombre_fichero:string); El funcionamiento de este procedimiento lo vamos a comentar secuencialmente, simulando el funcionamiento normal del programa. −Recibe par parámetro el nombre del fichero a explorar. −Mientras no encontremos las palabra implementación, var o begin leemos palabra: − Si la palabra es program o unit, leemos el nombre del mismo y lo introducimos en los dos ficheros (el de registros y el de texto). − Si la palabra es uses, vamos guardando en el vector unidades_programa las unidades que no son de librería, controlando que no se repitan. − Si la palabra es const, guardamos en el vector tipos las constantes que haya definidas. − Si la palabra es type, examinamos todo su contenido hasta encontrar la palabra implementation o var (esta segunda es para no examinar variables que no formen parte de la clase en la que nos encontremos). Vamos leyendo palabras; si encontramos Object, en aux está el nombre de la clase por lo que ya podemos introducirlo en los ficheros. Comprobamos si después del Object hay un paréntesis, lo que significaría que hay herencia y también introduciríamos la superclase en los ficheros. Vamos examinando los atributos y métodos de esta clase hasta encontrar un end que indica el fin de la misma. Cuando examinamos atributos, los almacenamos en el vector atributos hasta encontrar su tipo. Comprobamos si son definidos por el usuario o predefinidos de Turbo Pascal para introducir ambos (nombre y tipo del atributo) en los ficheros; de no ser así, es porque es una asociación, por tanto guardamos en los ficheros la clase con la que está asociada. Cuando examinamos métodos, introducimos en los ficheros su nombre así como los parámetros que tengan (con sus respectivos tipos). Si la palabra encontrada no es Object es porque se trata de un tipo definido por el usuario, por lo que los vamos almacenando en el vector tipos. Como podemos encontrarnos una asociación dentro de los campos de un registro, ha sido necesario declarar el vector registro. Para su mayor comprensión situamos un ejemplo de esta situación a continuación: nombrePtr=^nombreObj; nombreObj=record campo1:nombrePtr; campo2:nombreclasePtr; {nombreclasePtr hace referencia a una clase}
13
end; Dentro de otra clase habrá un atributo cuyo tipo será nombrePtr, por lo que utilizamos la función TipoRegistro que nos devolverá la clase con la que está asociada. Procedure EjecucionClick(Sender:TObject); Primero pregunta la ruta y nombre del fichero donde almacenar los resultados (fichero de registros). Si la ruta no existe da un mensaje de error y vuelve a pedirla de nuevo. Si ya existe el fichero, pregunta si se desea sobreescribirlo o no. Asigna el fichero de registros al nombre que se acaba de introducir. Además asigna al fichero de texto f el nombre datos.txt, que será almacenado en el directorio actual. Va recorriendo el vector unidades_programa, pasándole cada nombre al procedimiento Ejecucion que recorrerá (conforme hemos explicado anteriormente) todas y cada una de las unidades que en él se encuentren. Procedure FormCreate(Sender:TObject); Inicializa los vectores unidades_Pascal y Tipos con las unidades y tipos predefinidos en Pascal. Activa la cajaedicion1. Procedure VisualizarResultadosClick(Sender:TObject); Asigna al fichero de texto f el nombre datos.txt. Hace más pequeña la cajaedicion1 y muestra cajaedicion3 donde irá añadiendo dicho fichero. Procedure Cajaedicion1Click(Sender:TObject); Activa cajaedicion1 y desactiva las otras dos. Procedure Cajaedicion2Click(Sender:TObject); Activa cajaedicion2 y desactiva las otras dos. Procedure Cajaedicion3Click(Sender:TObject); Activa cajaedicion3 y desactiva las otras dos. NOTA: En todos los procedimientos asociados a las pulsaciones sobre botones u opciones del menú, Delphi añade el parámetro Sender de tipo TObject. Esta último es la clase padre de todas las demás por defecto y el Sender se utiliza para indicar el objeto que en realidad activa este evento. Por ejemplo, si se pulsa un botón, el objeto Explorador es el que en realidad lo activa. Nosotros no hemos utilizado esto para nada, pero lo hemos dejado por seguir la sintaxis de Delphi. Listado del programa. program Proyecto; uses 14
Forms, Explorar in 'EXPLORAR.PAS' {Explorador}, Acercade in 'ACERCADE.PAS' {AboutBox}; {$R *.RES} begin Application.CreateForm(TExplorador, Explorador); Application.CreateForm(TAboutBox, AboutBox); Application.Run; end. unit Explorar; interface uses SysUtils, WinTypes, WinProcs, Messages, Classes, Graphics, Controls, Forms, Dialogs, Menus, StdCtrls, ExtCtrls, Buttons, Printers,Acercade; type TExplorador = class(TForm) MenuPrincipal: TMainMenu; Fichero1: TMenuItem; Ejecutar: TMenuItem; VerResultados: TMenuItem; Imprimir: TMenuItem; ConfigurarImpresoras: TMenuItem; N2: TMenuItem; Preferencias: TMenuItem; Colores: TMenuItem; Tiposdeletra: TMenuItem;
15
N3: TMenuItem; Salir: TMenuItem; BarraHerramientas: TPanel; N4: TMenuItem; Ayuda: TMenuItem; ColorDialog1: TColorDialog; FontDialog1: TFontDialog; Ejecucion1: TMenuItem; Acercade: TMenuItem; PrintDialog1: TPrintDialog; PrinterSetupDialog1: TPrinterSetupDialog; Visualizarresultados: TMenuItem; PanelPresentacion: TPanel; CajaEdicion1: TMemo; botonabrir: TSpeedButton; botonimprimir: TSpeedButton; PanelControles: TPanel; botonejecutar: TButton; botonvisualizar: TButton; botonsalir: TButton; botonfuente: TSpeedButton; boton Etiqueta1: TLabel; Etiqueta2: TLabel; Etiqueta3: TLabel; N1: TMenuItem;
16
CajaEdicion2: TMemo; etiqueta4: TLabel; CajaEdicion3: TMemo; AbrirFuente: TMenuItem; OpenDialog1: TOpenDialog; procedure AbrirClick(Sender: TObject); procedure SalirClick(Sender: TObject); procedure ColoresClick(Sender: TObject); procedure TiposdeletraClick(Sender: TObject); procedure ImprimirClick(Sender: TObject); procedure ConfigurarImpresorasClick(Sender: TObject); procedure AcercadeClick(Sender: TObject); procedure Leepalabra; procedure Elimina_blancos; function Unidades:boolean; function TipoAtributo:boolean; function TipoRegistro(var auxi:string):boolean; function repe:boolean; function puntero:boolean; procedure inicializavectores; function AsociacionRepe(pal:string):boolean; procedure Ejecucion(nombre_fichero:string); procedure Ejecucion1Click(Sender: TObject); procedure FormCreate(Sender: TObject); procedure VisualizarresultadosClick(Sender: TObject); procedure CajaEdicion1Click(Sender: TObject);
17
procedure CajaEdicion3Click(Sender: TObject); procedure CajaEdicion2Click(Sender: TObject); private { Private declarations } public { Public declarations } end; tipo_elemento=(programa,clase,atributo,metodo,especializacion,asociacion); { contiene los posibles elementos del fichero registro} reg_parametros=record nombre,tipo_para:string; end; {registro para guardar los parametros de cada metodo de las clases} elemento=record case tipo_elemento of programa:(nombre_pro:string); clase:(nombre_clase:string); atributo:(nombre_atri,tipo_atri:string); metodo:(nombre_metodo:string;tipo_met:boolean;parametros:reg_parametros); especializacion:(superclase:string); asociacion:(con_clase:string); end; {registro para almacenar el fichero de resultados} regis=record nom_reg,asoc:string; end;
18
{registro para almacenar asociaciones que estén dentro de un campo del mismo} var f:textfile; {fichero de visualizacion de resultados} ele:elemento; {variable de tipo registro} explorador: TExplorador; {objeto} fichero:file of elemento; {fichero de resultados} fich:text; {fichero que contiene el codigo fuente que exploramos} Nombre_fichero:string; {Nombre del fichero que vamos a explorar} resultados:string; {Nombre del fichero en el cual almacenamos los resultados} nom:string; {Nombre del fichero de visualización} palabra:string; {almacenamos cada palabra que leemos del fichero fuente} path:string; {continene la ruta donde se encuentran los ficheros a explorar} c:char; {cada caracter que leemos del fichero fuente} unidades_pascal:array[1..23] of string; {vector que contiene las unidades predefinidas del pascal} unidades_programa:array[1..40] of string; {vector que contine las unidades que tenemos que explorar} tipos:array[1..30] of string; {contiene tanto los tipos predefinidos como los definidos por el usuario} atributos:array[1..10] of string; {guardamos los atributos que encontramos en cada clase} punteros:array[1..10] of string; {almacenamos las clases que nos encontramos} registros:array[1..10] of regis; {almacenamos asociaciones las cuales están en un campo del registro } j,cont,ind:integer; {indices de los distintos vectores} caja1,caja2,caja3:boolean; {variables para controlar que caja de edicion esta activa} asoc:array[1..10] of string; {almacenamos las asociaciones que nos encontramos en cada programa} implementation {$R *.DFM} procedure TExplorador.AbrirClick(Sender: TObject); {Procedimiento mediante el cual abrimos el fichero fuente}
19
var s:string; {variable auxiliar para el nombre de la etiqueta de la caja de edicion1} begin if OpenDialog1.Execute then {si pulsamos la opcion de Abrir} begin CajaEdicion1.Lines.LoadFromFile(OpenDialog1.Filename); Nombre_fichero:=OpenDialog1.Filename; unidades_programa[1]:=nombre_fichero; path:=extractfilepath(unidades_programa[1]); unidades_programa[1]:=extractfilename(unidades_programa[1]); configurarimpresoras.enabled:=true; ejecucion1.enabled:=true; tiposdeletra.enabled:=true; imprimir.enabled:=true; colores.enabled:=true; botonejecutar.enabled:=true; botonimprimir.enabled:=true; botonfuente.enabled:=true; visualizarresultados.enabled:=false; botonvisualizar.enabled:=false; cajaedicion2.Clear; s:=etiqueta1.Caption; delete(s,22,255); etiqueta1.Caption:=s+' "'+unidades_programa[1]+'"'; etiqueta2.Visible:=false; cajaedicion3.visible:=false;
20
cajaedicion1.Width:=577; end; end; procedure TExplorador.SalirClick(Sender: TObject); {cierra la aplicación} begin Close; end; procedure TExplorador.ColoresClick(Sender: TObject); {cambia el color de fondo de la caja de edición seleccionada} begin if ColorDialog1.Execute then begin if caja1 then Cajaedicion1.Color:=ColorDialog1.Color; if caja2 then cajaedicion2.Color:=ColorDialog1.Color; if caja3 then cajaedicion3.Color:=ColorDialog1.Color; end; end; procedure TExplorador.TiposdeletraClick(Sender: TObject); {cambia el color, tipo y tamaño de letra de la caja de edición seleccionada} begin if FontDialog1.Execute then begin
21
if caja1 then cajaedicion1.Font:=FontDialog1.font; if caja2 then cajaedicion2.Font:=FontDialog1.font; if caja3 then cajaedicion3.Font:=FontDialog1.font; end; end; procedure TExplorador.ImprimirClick(Sender: TObject); {Imprimimos el contenido de la caja de edición seleccionada} var prn:system.text; n:integer; begin if printDialog1.execute then begin if caja1 then begin printer.canvas.font:=cajaedicion1.font; assignprn(prn); rewrite(prn); for n:=0 to cajaedicion1.lines.count−1 do writeln(prn,cajaedicion1.lines[n]); system.close(prn); end; if caja2 then
22
begin printer.canvas.font:=cajaedicion2.font; assignprn(prn); rewrite(prn); for n:=0 to cajaedicion2.lines.count−1 do writeln(prn,cajaedicion2.lines[n]); system.close(prn); end; if caja3 then begin printer.canvas.font:=cajaedicion3.font; assignprn(prn); rewrite(prn); for n:=0 to cajaedicion3.lines.count−1 do writeln(prn,cajaedicion3.lines[n]); system.close(prn); end; end; end; procedure TExplorador.ConfigurarImpresorasClick(Sender: TObject); {configuramos la impresora} begin printerSetupDialog1.execute; end; procedure TExplorador.AcercadeClick(Sender: TObject); {llamamos a la unidad acercade para visualizarlo}
23
begin aboutbox.Show; end; procedure TExplorador.Leepalabra; { procedimiento para ir leyendo palabras del fichero fuente } var i:integer; begin while (c in ['0'..'9','A'..'Z','a'..'z','ñ'..'Ñ','.','_','^'])=false do read(fich,c); i:=0; palabra[i]:=c; i:=i+1; while c in ['0'..'9','A'..'Z','a'..'z','ñ'..'Ñ','.','_','^'] do begin palabra[i]:=c; i:=i+1; read(fich,c); end; delete(palabra,i,255); palabra:=ansilowercase(palabra); elimina_blancos; end; procedure TExplorador.elimina_blancos; {leemos caracteres del fichero mientras encontremos espacios en blanco} begin
24
while (c=' ') do read(fich,c); end; function TExplorador.unidades:boolean; {comprobamos si las unidades contenidas en el use del fichero fuente son unidades predefinidas del pascal o no } var i:integer; begin unidades:=false; for i:=1 to 23 do if palabra=unidades_pascal[i] then unidades:=true end; function TExplorador.TipoAtributo:boolean; {comprobamos si el tipo de los atributos que vamos obteniendo del fichero fuente son predefinidos del pascal o definidos por el usuario} var i:integer; begin tipoatributo:=false; for i:=1 to cont do if palabra=tipos[i] then tipoatributo:=true end; function TExplorador.TipoRegistro(var auxi:string):boolean;
25
{esta funcion nos devuelve una asociación cuando la misma está en un campo del registro} var i:integer; begin TipoRegistro:=false; for i:=1 to ind do if palabra=registros[i].nom_reg then begin TipoRegistro:=true; auxi:=registros[i].asoc end; end; function TExplorador.repe:boolean; {comprobamos que las unidades que nos encontramos en los USES de los ficheros fuentes que examinamos no hayan sido ya almacenadas en el vector de unidades de programa} var i:integer; begin repe:=false; for i:=1 to j−1 do if (unidades_programa[i]=palabra) then repe:=true; end; function TExplorador.puntero:boolean;
26
{ comprueba si la palabra que hemos leido es un puntero} var i:integer; begin puntero:=false; for i:=0 to 20 do if palabra=punteros[i] then puntero:=true; end; procedure TExplorador.inicializavectores; { borra todo lo que haya en los vectores que utilizamos en el procedimiento de ejecucion y que son independientes para cada unidad que exploramos } var i:integer; begin for i:=1 to ind do begin delete(registros[i].nom_reg,1,255); delete(registros[i].asoc,1,255); end; for i:=1 to 10 do delete(punteros[i],1,255); for i:=1 to 10 do delete(asoc[i],1,255); for i:=13 to cont do delete(tipos[i],1,255);
27
for i:=1 to 10 do delete(atributos[i],1,255); end; function TExplorador.AsociacionRepe(pal:string):boolean; { comprueba si la asociación que le pasamos como parámetro ya ha sido almacenada en el fichero, para no hacerlo más de una vez } var i:integer; begin AsociacionRepe:=false; for i:=1 to 10 do if pal=asoc[i] then asociacionRepe:=true; end; procedure TExplorador.Ejecucion(nombre_fichero:string); {este procedimiento va examinando cada unidad que le pasamos como parametro y vamos construyendo el fichero de resultados} var i,n,k,a,p:integer; esta_en,repetida:boolean; aux,auxi,s:string; begin assignFile(fich,nombre_fichero); reset(fich); delete(palabra,1,255); p:=1;
28
inicializavectores; ind:=1; while (ansicomparetext(palabra,'implementation')<>0) and (ansicomparetext(palabra,'var')<>0) and (ansicomparetext(palabra,'begin')<>0) do begin leepalabra; if (ansicomparetext(palabra,'program')=0) then {escribimos en el fichero de salida el nombre del programa} begin leepalabra; ele.nombre_pro:=palabra; write(fichero,ele); writeln(f,'Programa : ',palabra); end; if (ansicomparetext(palabra,'unit')=0) then {escribimos en el fichero de salida el nombre de la unidad} begin leepalabra; ele.nombre_pro:=palabra; write(fichero,ele); writeln(f,'Unit : ',palabra); end; if (ansicomparetext(palabra,'uses')=0) then {almacenamos en el vector de unidades de programa el nombre de las unidades que vamos encontrando, que no sean predefinidas del pascal, para examinarlas posteriormente}
29
begin while (c<>';') do begin leepalabra; esta_en:=unidades; if not esta_en then begin esta_en:=repe; if not esta_en then begin unidades_programa[j]:=palabra; j:=j+1; end; end; end; end; if (ansicomparetext(palabra,'const')=0) then {guardamos en el vector tipos las constantes definidas por el usuario} begin while (ansicomparetext(palabra,'type')<>0) and (ansicomparetext(palabra,'var')<>0) do begin if c<>'=' then begin leepalabra; tipos[cont]:=palabra; cont:=cont+1;
30
end else begin leepalabra; { Lee el valor de la constante } leepalabra; { Lee la siguiente palabra: otra constante, type o var } end; end; end; if (ansicomparetext(palabra,'type')=0) then {vamos almacenando en el fichero de salida las distintas clases que nos vamos encontrando, asi como atributos, métodos, asociaciones...} begin i:=0; while (ansicomparetext(palabra,'implementation')<>0) and (ansicomparetext(palabra,'var')<>0) do begin aux:=palabra; leepalabra; if (ansicomparetext(palabra,'object')=0) then {comprobamos si hemos encotrado una clase } begin i:=i+1; ele.nombre_clase:=aux; write(fichero,ele); {introducimos el nombre de la clase en el fichero} writeln(f,'Clase: ',aux); if (c='(') then {comprobamos si hay herencia} begin
31
leepalabra; ele.superclase:=palabra; write(fichero,ele); writeln(f,'Clase Padre: ',palabra); end; a:=0; leepalabra; while (ansicomparetext(palabra,'end')<>0) do {vamos almacenando los metodos y atributos de la clase que hemos encontrado} begin n:=0; if ( ansicomparetext (palabra,'procedure') <> 0 ) and ( ansicomparetext (palabra,'function') <> 0 ) then {examinamos los atributos de la clase encontrada} while ( (c=',') or (c=':') )do if c=',' then {almacenamos en el vector atributos aquellos que sean del mismo tipo} begin atributos[n]:=palabra; n:=n+1; leepalabra; end else { Se han encontrado ':' } begin atributos[n]:=palabra; read(fich,c); elimina_blancos;
32
delete(s,1,255); if (c='(') or (c in ['0'..'9']) then {comprobamos si son tipos definidos por el usuario} begin if c='(' then begin while (c<>')') do begin leepalabra; s:=s+palabra+c; end; s:='('+s; end else begin s:=c; leepalabra; s:=s+palabra; end; for k:=1 to n do begin ele.nombre_atri:=atributos[n]; ele.tipo_atri:=s; end; write(fichero,ele); {introducimos en el fichero de salida los atributos
33
y el tipo de los mismos} writeln(f,'Atributo: ',atributos[n],': ',s); end {del if} else {el tipo de atributos no es definido por el usuario} begin leepalabra; palabra:=ansilowercase(palabra); esta_en:=TipoRegistro(auxi); {comprobamos si existe una asociación} if esta_en then begin repetida:=asociacionrepe(auxi); if not repetida then begin asoc[p]:=auxi; p:=p+1; ele.con_clase:=auxi; write(fichero,ele); {almacenamos en el fichero de salida con que clase esta asociada} writeln(f,'Clase ',aux,' asociada con ',auxi); end end else begin esta_en:=tipoatributo;
34
{comprobamos si el tipo de atributo es predefinido} if esta_en then begin for k:=0 to n do begin ele.nombre_atri:=atributos[k]; ele.tipo_atri:=palabra; write(fichero,ele); {guardamos en fichero de salida los atributos y el tipo de los mismos} writeln(f,'Atributo: ',atributos[k],':',palabra); end; if palabra='record' then repeat leepalabra; until palabra='end'; end else begin repetida:=asociacionrepe(palabra); if not repetida then begin asoc[p]:=palabra; p:=p+1; ele.con_clase:=palabra; write(fichero,ele);
35
{introducimos en el fichero de salida la clase con la que está asociada} writeln(f,'Clase ',aux,' asociada con ',palabra); end end end {del else sino está_en} end {del else de tipo de atributos no definido por el usuario} end {del primer else} else begin { Analisis de procedure y function } leepalabra; ele.nombre_metodo:=palabra; write(fichero,ele); {alamacenamos en el fichero de salida el nombre del método} writeln(f,'Método: ',palabra); if c='(' then {vamos guardando en el fichero de salida los nombres y tipo de atributos de cada metodo} while c<>')' do begin leepalabra; if (ansicomparetext(palabra,'var')<>0) then while ( (c=',') or (c=':') )do if c=',' then begin atributos[n]:=palabra;
36
n:=n+1; leepalabra; elimina_blancos; end else { Se han encontrado ':' } begin atributos[n]:=palabra; leepalabra; esta_en:=tipoatributo; if esta_en then for k:=0 to n do begin ele.parametros.nombre:=atributos[k]; ele.parametros.tipo_para:=palabra; write(fichero,ele); writeln(f,'Parámetro: ',atributos[k],':',palabra); end end end {del while} end ; {del else del analisis de procedure y function} leepalabra; end; {del while del end} leepalabra; end {del if del object} else { guardamos el tipo que no es un objeto } if (aux<>'type') then
37
{examinamos lo que hay en el type fuera de una clase} begin if palabra='record' then {comprobamos si algun campo del registro es de tipo clase} begin while palabra<>'end' do begin while c<>';' do leepalabra; esta_en:=puntero; if not esta_en then begin esta_en:=tipoatributo; if not esta_en then begin registros[ind].asoc:=palabra; ind:=ind+1; end end; leepalabra; end; tipos[cont]:=aux; cont:=cont+1; end else begin
38
while (c<>')') and (c<>';') and (aux<>'end') do leepalabra; if aux<>'end' then if palabra[1]<>'^' then begin tipos[cont]:=aux; cont:=cont+1; leepalabra; end else begin punteros[i]:=aux; i:=i+1; registros[ind].nom_reg:=aux; leepalabra; end; end; {del else} end {del if de aux<>type} end; {del while de implementacion y var} end; {del if del type} end {del primer while del procedimiento} end; procedure TExplorador.Ejecucion1Click(Sender: TObject); {llama al procedimiento ejecutar pasandole el nombre de la unidad a explorar} var i:integer;
39
nombre,re:string; sobre:boolean; begin repeat sobre:=true; resultados:=Inputbox('Ruta fichero salida','Introduce la ruta del fichero de salida','c:\noname.reg'); {muestra por pantalla una caja de dialogo para introducir la ruta y nombre del fichero de salida} re:=extractfilepath(resultados)+'*.*'; if fileexists(re) then {comprueba si existe la ruta, de no ser así muestra un mensaje de error} begin if FileExists(resultados) then {comprueba si el nombre del fichero introducido existe, en cuyo caso muestra un mensaje de error} if MessageDlg('El fichero "'+ExtractFileName(resultados)+'" existe, ¿Desea sobreescribirlo?',mtInformation, [mbYes,mbNo],0) = mrNo then sobre:=false end else begin MessageDlg('¡ La ruta "'+resultados+'" no existe !',mtInformation,[mbOK],0); sobre:=false; end; until (resultados<>'') and (sobre=true); cajaedicion2.clear; assignfile(fichero,resultados); rewrite(fichero);
40
nom:='datos.txt'; assignfile(f,nom); rewrite(f); i:=1; j:=2; nombre:=path+unidades_programa[i]; repeat {llama al procedimiento ejecucion pasandole como parametro el nombre del fichero a explorar, hasta recorrer todo el vector que contiene las unidades de programa} ejecucion(nombre); cajaedicion2.Lines.Add(unidades_programa[i]); i:=i+1; nombre:=path+unidades_programa[i]+'.pas'; until (i=j); closefile(fichero); closefile(f); visualizarresultados.enabled:=true; botonvisualizar.enabled:=true; end; procedure TExplorador.FormCreate(Sender: TObject); {almacenamos en un vector las unidades y los tipos predefinidos del pascal} begin unidades_pascal[1]:='app'; unidades_pascal[2]:='colorsel'; unidades_pascal[3]:='dialogs'; unidades_pascal[4]:='dos'; unidades_pascal[5]:='drivers';
41
unidades_pascal[6]:='crt'; unidades_pascal[7]:='editors'; unidades_pascal[8]:='graph'; unidades_pascal[9]:='graph3'; unidades_pascal[10]:='histlist'; unidades_pascal[11]:='memory'; unidades_pascal[12]:='menus'; unidades_pascal[13]:='msgbox'; unidades_pascal[14]:='objects'; unidades_pascal[15]:='outline'; unidades_pascal[16]:='stdlg'; unidades_pascal[17]:='strings'; unidades_pascal[18]:='textview'; unidades_pascal[19]:='turbo3'; unidades_pascal[20]:='validate'; unidades_pascal[21]:='views'; unidades_pascal[22]:='wincrt'; unidades_pascal[23]:='windos'; tipos[1]:='integer'; tipos[2]:='boolean'; tipos[3]:='string'; tipos[4]:='real'; tipos[5]:='double'; tipos[6]:='array'; tipos[7]:='record'; tipos[8]:='word';
42
tipos[9]:='extended'; tipos[10]:='byte'; tipos[11]:='shorting'; tipos[12]:='longint'; cont:=13; caja1:=true; caja2:=false; caja3:=false; end; procedure TExplorador.VisualizarresultadosClick(Sender: TObject); {visualizamos en una caja de edición el fichero de texto que hemos ido creando durante la ejecución de la aplicación} var s:string; x:string; begin resultados:='datos.txt'; assignfile(f,resultados); reset(f); cajaedicion1.Width:=273; cajaedicion3.clear; x:=etiqueta2.Caption; delete(x,18,255); etiqueta2.Caption:=x+' "'+resultados+'"'; etiqueta2.Visible:=true; cajaedicion3.Visible:=true;
43
while not eof(f) do begin readln(f,s); cajaedicion3.Lines.Add(s); end; end; procedure TExplorador.CajaEdicion1Click(Sender: TObject); {activa la caja de edicion1} begin caja1:=true; caja2:=false; caja3:=false; end; procedure TExplorador.CajaEdicion3Click(Sender: TObject); {activa la caja de edicion2} begin caja1:=false; caja2:=false; caja3:=true; end; procedure TExplorador.CajaEdicion2Click(Sender: TObject); {activa la caja de edicion3} begin caja1:=false; caja2:=true; caja3:=false;
44
end; END. unit Acercade; interface uses WinTypes, WinProcs, Classes, Graphics, Forms, Controls, StdCtrls, Buttons, ExtCtrls; type TAboutBox = class(TForm) Panel1: TPanel; OKButton: TBitBtn; ProgramIcon: TImage; ProductName: TLabel; Version: TLabel; Copyright: TLabel; Comments: TLabel; Label1: TLabel; Label2: TLabel; Label3: TLabel; Label4: TLabel; procedure OKButtonClick(Sender: TObject); private { Private declarations } public { Public declarations } end; var
45
AboutBox: TAboutBox; implementation {$R *.DFM} procedure TAboutBox.OKButtonClick(Sender: TObject); begin close end; end. Listado de propiedades y eventos del programa. Unidad Explorar object Explorador: TExplorador Left = 224 Top = 133 Width = 491 Height = 409 Caption = 'Explorador de código' Font.Color = clBlack Font.Height = −16 Font.Name = 'Times New Roman' Font.Style = [] Menu = MenuPrincipal PixelsPerInch = 96 WindowState = wsMaximized OnCreate = FormCreate TextHeight = 19 object BarraHerramientas: TPanel
46
Left = 0 Top = 0 Width = 483 Height = 41 Align = alTop BevelOuter = bvNone BorderStyle = bsSingle Color = 10526880 Ctl3D = True Locked = True ParentCtl3D = False ParentShowHint = False ShowHint = True TabOrder = 0 object botonabrir: TSpeedButton Left = 8 Top = 8 Width = 25 Height = 25 Hint = 'Abrir' Glyph.Data = {} OnClick = AbrirClick end object botonimprimir: TSpeedButton Left = 40 Top = 8
47
Width = 25 Height = 25 Hint = 'imprimir' Enabled = False Glyph.Data = {} NumGlyphs = 2 OnClick = ImprimirClick end object botonfuente: TSpeedButton Left = 72 Top = 8 Width = 25 Height = 25 Hint = 'fuente' Enabled = False Glyph.Data = {} NumGlyphs = 2 OnClick = TiposdeletraClick end object botoncolor: TSpeedButton Left = 104 Top = 8 Width = 25 Height = 25 Hint = 'color de fondo' Glyph.Data = {}
48
Layout = blGlyphBottom NumGlyphs = 2 OnClick = ColoresClick end end object PanelPresentacion: TPanel Left = 0 Top = 41 Width = 483 Height = 322 Align = alClient Color = 10526880 Font.Color = clBlack Font.Height = −20 Font.Name = 'Times New Roman' Font.Style = [fsBold] ParentFont = False TabOrder = 1 object Etiqueta1: TLabel Left = 24 Top = 16 Width = 147 Height = 19 Caption = 'Codigo fuente fichero ' Font.Color = clBlack Font.Height = −16
49
Font.Name = 'Times New Roman' Font.Style = [fsBold] ParentFont = False end object Etiqueta2: TLabel Left = 336 Top = 16 Width = 118 Height = 19 Caption = 'Contenido fichero' Color = 10526880 Font.Color = clBlack Font.Height = −16 Font.Name = 'Times New Roman' Font.Style = [fsBold] ParentColor = False ParentFont = False Visible = False end object Etiqueta3: TLabel Left = 616 Top = 256 Width = 82 Height = 15 Caption = 'CONTROLES:' Font.Color = clBlack
50
Font.Height = −13 Font.Name = 'Times New Roman' Font.Style = [fsBold] ParentFont = False end object etiqueta4: TLabel Left = 624 Top = 48 Width = 144 Height = 19 Caption = 'Unidades exploradas:' Font.Color = clBlack Font.Height = −16 Font.Name = 'Times New Roman' Font.Style = [fsBold] ParentFont = False end object CajaEdicion1: TMemo Left = 24 Top = 48 Width = 577 Height = 449 Color = 15793151 Font.Color = clBlack Font.Height = −16 Font.Name = 'Times New Roman'
51
Font.Style = [fsBold] Lines.Strings = ( '') ParentFont = False ReadOnly = True ScrollBars = ssBoth TabOrder = 0 OnClick = CajaEdicion1Click end object PanelControles: TPanel Left = 640 Top = 280 Width = 121 Height = 193 BevelInner = bvLowered BevelOuter = bvLowered BevelWidth = 2 Color = 10526880 TabOrder = 1 object botonejecutar: TButton Left = 16 Top = 24 Width = 89 Height = 33 Caption = 'EJECUTAR' Enabled = False
52
Font.Color = clGray Font.Height = −13 Font.Name = 'Times New Roman' Font.Style = [fsBold] ParentFont = False TabOrder = 0 OnClick = Ejecucion1Click end object botonvisualizar: TButton Left = 16 Top = 80 Width = 89 Height = 33 Caption = 'VISUALIZAR' Enabled = False Font.Color = clBlack Font.Height = −13 Font.Name = 'Times New Roman' Font.Style = [fsBold] ParentFont = False TabOrder = 1 OnClick = VisualizarresultadosClick end object botonsalir: TButton Left = 16 Top = 136
53
Width = 89 Height = 33 Caption = 'SALIR' Font.Color = clBlack Font.Height = −13 Font.Name = 'Times New Roman' Font.Style = [fsBold] ParentFont = False TabOrder = 2 OnClick = SalirClick end end object CajaEdicion2: TMemo Left = 632 Top = 80 Width = 129 Height = 137 Color = 16777088 Font.Color = clBlack Font.Height = −15 Font.Name = 'Times New Roman' Font.Style = [fsBold] Lines.Strings = ( '') ParentFont = False ReadOnly = True
54
ScrollBars = ssBoth TabOrder = 2 OnClick = CajaEdicion2Click end object CajaEdicion3: TMemo Left = 328 Top = 48 Width = 273 Height = 449 Color = 15793151 Font.Color = clBlack Font.Height = −16 Font.Name = 'Times New Roman' Font.Style = [fsBold] Lines.Strings = ( '') ParentFont = False ScrollBars = ssBoth TabOrder = 3 Visible = False OnClick = CajaEdicion3Click end end object MenuPrincipal: TMainMenu Left = 216 Top = 104
55
object Fichero1: TMenuItem Caption = '&Fichero' object AbrirFuente: TMenuItem Caption = '&Abrir Fuente' OnClick = AbrirClick end object N1: TMenuItem Caption = '−' end object Imprimir: TMenuItem Caption = '&Imprimir' Enabled = False OnClick = ImprimirClick end object ConfigurarImpresoras: TMenuItem Caption = 'Configurar I&mpresoras' Enabled = False OnClick = ConfigurarImpresorasClick end object N2: TMenuItem Caption = '−' end object Preferencias: TMenuItem Caption = '&Preferencias' object Colores: TMenuItem Caption = '&Color de fondo'
56
OnClick = ColoresClick end object Tiposdeletra: TMenuItem Caption = '&Tipo y color de letra' Enabled = False OnClick = TiposdeletraClick end end object N3: TMenuItem Caption = '−' end object Salir: TMenuItem Caption = '&Salir' OnClick = SalirClick end end object Ejecutar: TMenuItem Caption = '&Ejecutar' object Ejecucion1: TMenuItem Caption = 'E&jecución' Enabled = False OnClick = Ejecucion1Click end end object VerResultados: TMenuItem Caption = '&Ver Resultados'
57
object Visualizarresultados: TMenuItem Caption = 'Visualizar &resultados' Enabled = False OnClick = VisualizarresultadosClick end end object N4: TMenuItem end object TMenuItem end object Ayuda: TMenuItem Caption = '&Acerca de...' object Acercade: TMenuItem Caption = '&Acerca de ...' OnClick = AcercadeClick end end end object OpenDialog1: TOpenDialog Filter = 'Fichero fuente|*.pas' Options = [ofNoChangeDir] Left = 56 Top = 104 end object ColorDialog1: TColorDialog Left = 88
58
Top = 104 end object FontDialog1: TFontDialog Font.Color = clWindowText Font.Height = −13 Font.Name = 'System' Font.Style = [] MinFontSize = 0 MaxFontSize = 0 Left = 184 Top = 104 end object PrintDialog1: TPrintDialog Left = 152 Top = 104 end object PrinterSetupDialog1: TPrinterSetupDialog Left = 120 Top = 104 end end Unidad Acercade object AboutBox: TAboutBox Left = 169 Top = 105 ActiveControl = OKButton
59
BorderStyle = bsDialog Caption = 'Acerca de...' ClientHeight = 367 ClientWidth = 528 Font.Color = clBlack Font.Height = −13 Font.Name = 'System' Font.Style = [fsBold, fsItalic] PixelsPerInch = 96 Position = poScreenCenter TextHeight = 16 object Panel1: TPanel Left = 8 Top = 8 Width = 513 Height = 313 BevelInner = bvRaised BevelOuter = bvLowered TabOrder = 0 object ProgramIcon: TImage Left = 8 Top = 8 Width = 241 Height = 233 Picture.Data = {} Stretch = True
60
IsControl = True end object ProductName: TLabel Left = 264 Top = 16 Width = 226 Height = 16 Caption = 'PROYECTO FIN DE CARRERA 1' Font.Color = clNavy Font.Height = −13 Font.Name = 'MS LineDraw' Font.Style = [fsBold] ParentFont = False IsControl = True end object Version: TLabel Left = 264 Top = 64 Width = 99 Height = 13 Caption = 'COMPONENTES:' Font.Color = clNavy Font.Height = −12 Font.Name = 'MS Sans Serif' Font.Style = [fsBold] ParentFont = False
61
IsControl = True end object Copyright: TLabel Left = 288 Top = 160 Width = 169 Height = 22 Caption = 'Rubén Andrés Calvo' Font.Color = clPurple Font.Height = −19 Font.Name = 'Times New Roman' Font.Style = [fsBold] ParentFont = False IsControl = True end object Comments: TLabel Left = 288 Top = 192 Width = 185 Height = 25 Caption = 'Miguel López Gómez' Font.Color = clPurple Font.Height = −19 Font.Name = 'Times New Roman' Font.Style = [fsBold] ParentFont = False
62
WordWrap = True IsControl = True end object Label1: TLabel Left = 288 Top = 96 Width = 204 Height = 22 Caption = 'Pepa Deogracia Guirado' Font.Color = clPurple Font.Height = −19 Font.Name = 'Times New Roman' Font.Style = [fsBold] ParentFont = False end object Label2: TLabel Left = 288 Top = 128 Width = 200 Height = 22 Caption = 'Paco Martínez González' Font.Color = clPurple Font.Height = −19 Font.Name = 'Times New Roman' Font.Style = [fsBold] ParentFont = False
63
end object Label3: TLabel Left = 288 Top = 224 Width = 174 Height = 22 Caption = 'Marcelo Raso Mateo' Font.Color = clPurple Font.Height = −19 Font.Name = 'Times New Roman' Font.Style = [fsBold] ParentFont = False end object Label4: TLabel Left = 24 Top = 272 Width = 191 Height = 16 Caption = 'Copyright 1996' Font.Color = clGray Font.Height = −13 Font.Name = 'Wide Latin' Font.Style = [] ParentFont = False end end
64
object OKButton: TBitBtn Left = 215 Top = 330 Width = 77 Height = 27 Font.Color = clBlack Font.Height = −12 Font.Name = 'MS Sans Serif' Font.Style = [fsBold] ParentFont = False TabOrder = 1 OnClick = OKButtonClick Kind = bkOK Margin = 2 Spacing = −1 IsControl = True end end NOTA: La propiedad Glyph no se ha incluido en el listado de propiedades y eventeos en su totalidad, por contener caracteres ASCII que carecen de información, además de ocupar un tamaño excesivo.
65