Práctica 5

Anuncio
UNIVERSIDAD DEL ISTMO
Ingeniería en computación
Compiladores
PROFESOR
M. en C. J. Jesús Arellano Pimentel
NÚMERO DE PRÁCTICA
5
NOMBRE DE LA PRÁCTICA
Redireccionamiento de la entrada-salida en Flex y apertura
de archivos en aplicaciones nativas Win32.
OBJETIVO GENERAL
OBJETIVOS ESPECÍFICOS
EQUIPO REQUERIDO
SOFTWARE REQUERIDO
Aprender a redireccionar la entrada-salida en
especificaciones Flex y el manejo del cuadro de diálogo
estándar para la apertura de archivos en aplicaciones
nativas Win32.
- Construir una especificación Flex en consola que
redireccione la entrada a través del yyin y la salida a
través del yyout.
- Construir una aplicación Win32 que implemente la
apertura de archivos a través del uso del cuadro de
diálogo estándar para la apertura de archivos.
- Construir una aplicación Wi32 que integre una el
generador léxico generado por Flex y permita
redireccionar la entrada (yyin) empleando el cuadro
de diálogo estándar para la apertura de archivos.
Computadora personal con 512 MB de RAM mínimo.
- Windows 7/8
- Microsoft Visual Studio Express 2012 para escritorio
de Windows
1.- Fundamentos.
1.1.- Cuadros de diálogo comunes
Uno de los objetivos primarios de Windows es promover una interfaz de usuario
estándar [Petzold96]. Windows provee de una “librería cuadros de diálogo comunes” la cual
esta formada por varias funciones que invocan cuadros de diálogo estándares para: abrir y
guardar archivos, buscar y sustituir, imprimir, entre otros. El uso de estas funciones
básicamente consiste en rellenar los datos (campos) de una estructura y pasarla por referencia
a una función de la librería de cuadros de diálogo comunes. La función crea y muestra el
cuadro de diálogo común. Cuando el usuario termina su trabajo con el cuadro de diálogo, la
función de librería retorna el control a la aplicación principal dejando la información capturada
por el usuario en la estructura que previamente se le pasó a la función de librería.
En esta práctica se va a emplear el cuadro de diálogo estándar para abrir archivos. El
propósito es obtener en nombre del archivo a abrir el cual que será asignado como valor de
inicio a yyin y con ello redireccionar la entrada de la especificación Flex para analizar
léxicamente el archivo de texto plano que el usuario determine.
Ingeniería en Computación
M. C. J. Jesús Arellano Pimentel
1
2.- Desarrollo
2.1 Aplicación Flex de consola para redireccionar la entrada-salida
Paso 1 Crear la especificación Flex.
La especificación debe permitir copiar la entrada a la salida sustituyendo la palabra
hola por “primero” cuando la línea donde se encuentre inicie con la letra a, por
“segundo” cuando la línea inicie con la letra b, por “tercero” cuando la línea inicie con
la letra c. Todas las demás palabra y todas la líneas no varían. Dicha especificación
emplea el uso de flags y es la siguiente:
%{
#include<stdlib.h>
#include<stdio.h>
#include<string.h>
int
%}
%%
^a
^b
^c
\n
hola
flag ='\0';
{flag = 'a'; ECHO;}
{flag = 'b'; ECHO;}
{flag = 'c'; ECHO;}
{flag = '\0'; ECHO;}
switch(flag){
case 'a':
fprintf(yyout, "primero"); flag ='\0'; break;
case 'b':
fprintf(yyout, "segundo"); flag ='\0'; break;
case 'c':
fprintf(yyout, "tercero"); flag ='\0'; break;
default: ECHO; break;
}
%%
int yywrap()
{
return 1;
}
int main(int argc, char *argv[])
{
if(argc != 3){
printf("Parámetros incorrectos\n
Uso:%s entrada.txt salida.txt\n", argv[0]);
return 0;
}
yyin = fopen(argv[1], "r");
if(yyin == NULL){
printf("Imposible abrir archive de entrada %s\n",argv[1]);
return 0;
}
yyout = fopen(argv[2], "w");
if(yyout == NULL){
printf("Imposible abrir archivo de salida %s\n",argv[2]);
return 0;
}
yylex();
return 0;
}
Ingeniería en Computación
M. C. J. Jesús Arellano Pimentel
2
Utilizando la aplicación de Notepad de Windows editamos la especificación anterior.
Es importante que al guardarla seleccionemos en Tipo de documento “Todos los
archivos”, en lugar de “Documentos de texto *.txt”, de esta forma es posible guardar el
archivo con extensión .l (punto ele). Se sugiere que el nombre del archivo sea EjeLex2.l
y que se guarde en la misma ruta donde se tiene el archivo flex.exe en la carpeta bin.
Paso 2 Compilar la especificación guardada en el archivo EjeLex2.l con flex.
Para compilar la especificación .l se debe abrir la consola de comandos y cambiarse a
la ruta donde previamente se descomprimió el archivo Flex.exe, que es el mismo lugar
donde debe encontrarse el archivo EjeLex2.l. El comando de compilación puede verse
en la Figura 1. La opción -o indica el nombre del archivo fuente a generar, en nuestro
caso el archivo se llamará EjeLex2.c.
Figura 1. Carpetas contenidas en el archivo flex-2.5.4a-1-bin.zip y compilación con Flex.
Hecho lo anterior se debe crear una aplicación de consola en el Visual Studio Express
2012 para compilar el código generado por Flex.
Paso 3 Iniciar el MVS Express 2012 y crear un nuevo proyecto Win32 de consola vacío.
Seleccionar la opción del menú Archivo->Nuevo Proyecto. Del cuadro de diálogo
Nuevo proyecto en Plantillas seleccionar Visual C++ y Win32; en tipo de aplicación
seleccionar Aplicación de consola Win32 Visual C++. El nombre del proyecto o
solución podría ser EjeLex2. Presionar el botón Aceptar.
En el Asistente para aplicaciones Win32 presionar el botón siguiente; después
seleccionar la casilla de verificación correspondiente a la opción adicional Proyecto
vacío, posteriormente deshabilitar la casilla de verificación de Comprobación del ciclo
de vida de desarrollo de seguridad(SDL); finalmente oprimir el botón Finalizar.
Ingeniería en Computación
M. C. J. Jesús Arellano Pimentel
3
Paso 4 Adicionar al proyecto vacío el archivo generado por Flex.
Copiar el archivo generado por Flex a la ruta del proyecto generado por el MVS
Express 2012. En nuestro caso esta en:
\Documents\Visual Studio 2012\Projects\EjeLex2\EjeLex2
Una vez copiado el archivo, en la interfaz del MVC Express 2012 dar clic derecho
sobre el elemento Archivos de código fuente del Explorador de soluciones situado a la
izquierda, del menú que aparece seleccionar Agregar -> Elemento existente … (ver
Figura 2). Cuando aparezca el cuadro de diálogo para seleccionar el archivo se debe
elegir el archivo copiado anteriormente, es decir: EjeLex2.c.
Figura 2. Adicionando un archivo de código fuente al proyecto vacío.
Paso 5 Compilar y Ejecutar la aplicación
Compilar oprimiendo la tecla F7. El resultado de la compilación puede producir
algunas advertencias, sin embargo se debe generar un ejecutable en la carpeta Debug
de la solución. Lo anterior es posible verificarlo en el sistema de archivos.
La ejecución se debe realizar desde la consola de comandos de Windows de la forma
como se presenta en la Figura 3. Observe que no solo se invoca el nombre del archivo
ejecutable (EjeLex2.exe), también se incluyen los archivos que han de tomarse como
entrada y como salida. El contenido del archivo de entrada puede ser el siguiente:
a
b
c
x
hola
hola
hola
hola
cara
cara
cara
cara
de
de
de
de
bola
bola
bola
bola
El resultado final de la ejecución debe generar el segundo archivo con un contenido
similar al archivo de entrada pero tomando en cuenta la especificación del archivo .l,
de tal forma que el archivo de salida quedaría de la siguiente forma:
a
b
c
x
primero cara
segundo cara
tercero cara
hola cara de
Ingeniería en Computación
de bola
de bola
de bola
bola
M. C. J. Jesús Arellano Pimentel
4
Figura 3. Ejecución de la aplicación EjeLex2.exe.
2.2 Aplicación Win32 para implementar el cuadro de diálogo estándar “Abrir archivo”
Paso 1 Iniciar el MVS Express 2012.
Paso 2 Crear un nuevo proyecto Win32.
Seleccionar la opción del menú Archivo->Nuevo Proyecto. Del cuadro de diálogo
Nuevo proyecto en Plantillas seleccionar Visual C++ y Win32; en tipo de aplicación
seleccionar Proyecto Win32 Visual C++ (ver Figura 1). El nombre del proyecto o
solución podría ser CDlgAbrir. Presionar el botón Aceptar.
Figura 4. Cuadro de diálogo Nuevo Proyecto para la aplicación CDlgAbrir.
Paso 3 Configurar el Proyecto Actual.
En el Asistente para aplicaciones Win32 presionar el botón siguiente; después
deshabilitar la casilla de verificación de Comprobación del ciclo de vida de desarrollo
de seguridad(SDL); finalmente oprimir el botón Finalizar.
Ingeniería en Computación
M. C. J. Jesús Arellano Pimentel
5
Paso 4 Adicionar un nuevo elemento al menú.
Para adicionar un nuevo elemento al menú es necesario editar el archivo de recursos
con extensión .rc. En el explorador de soluciones del Visual Studio podemos localizar
el archivo CDlgAbrir.rc correspondiente a los recursos (ver Figura 5), para editarlo
será necesario dar un clic derecho sobre el archivo y del menú flotante elegir la opción
<>Ver código.
Figura 5. Apertura del archivo de recursos de la aplicación CDlgAbrir.
Una vez abierto el archivo se adicionará, después de la línea 41, la siguiente línea de
código:
MENUITEM "&Abrir",
IDM_ABRIR
de tal forma que la sección del menú quede de la siguiente forma:
IDC_MENUWIN32 MENU
BEGIN
POPUP "&Archivo"
BEGIN
MENUITEM "&Abrir",
MENUITEM "&Salir",
END
POPUP "Ay&uda"
BEGIN
MENUITEM "&Acerca de...",
END
END
Ingeniería en Computación
IDM_ABRIR
IDM_EXIT
IDM_ABOUT
M. C. J. Jesús Arellano Pimentel
6
Una vez hecho lo anterior, adicionar al archivo de encabezado Resource.h la constante
simbólica asociada al menú (IDM_ABRIR). La Figura 6 muestra un segmento de dicho
archivo con la nueva línea de código resaltada en azul.
Figura 6. Adición de la constante simbólica IDM_ABRIR en el archivo Resoruce.h.
Finalmente se deberán guardar ambos archivos.
Paso 5 Modificar el archivo stdafx.h
El Archivo stdafx.h deberá ser modificado con la adición de la librería que permite el
uso de los cuadros de diálogo comunes en Windows. La línea de código a agregar en
este archivo debe ir al final del mismo y es la siguiente:
#include <commdlg.h>
Paso 6 Procesar el mensaje de la nueva opción del menú.
El procesamiento del mensaje para la nueva opción del menú se hará a través de su
constante simbólica asociada. Para esto será necesario editar el archivo MenuWin32, en
particular la función WndProc que inicia aproximadamente en la línea de código #126.
Habrá que adicionar un nuevo caso a la estructura switch (wmId) que es la encargada
de procesar los mensajes generados por las opciones del menú, dicha estructura inicia
aproximadamente en la línea de código #138. El nuevo caso deberá colocarse previo al
caso default:, de esta forma, el código de la estructura deberá quedar de la siguiente
forma1:
1
Las líneas de código resaltadas en amarillo son las que deberán adicionarse a la estructura original.
Ingeniería en Computación
M. C. J. Jesús Arellano Pimentel
7
// Analizar las selecciones de menú:
switch (wmId)
{
case IDM_ABOUT:
DialogBox(hInst, MAKEINTRESOURCE(IDD_ABOUTBOX), hWnd, About);
break;
case IDM_EXIT:
DestroyWindow(hWnd);
break;
case IDM_ABRIR:
TCHAR szFile[MAX_PATH], szCaption[64 + _MAX_FNAME + _MAX_EXT];
OPENFILENAME ofn;
ZeroMemory(szFile, MAX_PATH);
ZeroMemory(&ofn, sizeof(OPENFILENAME));
ofn.lStructSize = sizeof(OPENFILENAME);
ofn.Flags
= OFN_FILEMUSTEXIST | OFN_PATHMUSTEXIST |
OFN_HIDEREADONLY | OFN_CREATEPROMPT;
ofn.hwndOwner = hWnd;
ofn.lpstrFilter = _T("Tipos de Archivos soportados(*.txt)
\0*.txt\0Archivos de texto (*.txt)\0\0");
ofn.lpstrTitle = _T("Abrir archivo");
ofn.lpstrFile = szFile;
ofn.nMaxFile = MAX_PATH;
if (IDOK == GetOpenFileName(&ofn)){
wsprintf(szCaption,_T("%s - %s"),szTitle, szFile[0] ? szFile :
_T("Sin archivo abierto"));
SetWindowText(hWnd, szCaption);
}
break;
default:
return DefWindowProc(hWnd, message, wParam, lParam);
}
En el código resaltado en amarillo la primera línea corresponden a las variables que
van a almacenar el nombre del archivo y el título de la ventana principal, la segunda
línea corresponde al nombre de la estructura que se debe configurar para personalizar
el cuadro de diálogo estándar de Abrir archivo. Las siguientes líneas de código limpian
las variables definidas y establecen los valores para la estructura ofn configurando el
cuadro de diálogo para que solo acepte archivos del tipo *.txt. El llamado a la función
GetOpenFileName(&ofn) permite visualizar el cuadro de diálogo y retorna IDOK en
caso de que el usuario seleccione un archivo para abrir y pulse el botón de Aceptar. Si
lo anterior ocurre entonces se cambia el título de la ventana principal adicionando el
nombre, con la ruta, del archivo seleccionado para abrir.
Nota: Es importante mencionar que la línea de código correspondiente a ofn.lpstrFilter
debe ser editada en una sola línea, en este documento quedó en 2 líneas por razones de
espacio.
Paso 6 Compilar y ejecutar para visualizar los cambios
Una vez realizados los cambios de los pasos anteriores guardar el archivo y ejecutar
presionando la tecla F5. El resultado debería ser el mostrado en la Figura 7 una vez que
seleccione el la nueva opción del menú Archivo.
Ingeniería en Computación
M. C. J. Jesús Arellano Pimentel
8
Figura 7. Ejecución de la aplicación CDlgAbrir.
Después de que se ha seleccionado un archivo el título de la ventana principal debe
contener el archivo a abrir.
2.3 Integrar a la aplicación CDlgAbrir la especificación Flex del apartado 2.1
Paso 1 Modificar la especificación Flex eliminando la función main.
Debido a que las aplicaciones Win32 cuentan con su propia función principal será
necesario eliminar la función main de la especificación .l descrita en el apartado 2.1 e
incluir una nueva librería (io.h) Ahora la especificación deberá ser la siguiente:
%{
#include<stdlib.h>
#include<stdio.h>
#include<string.h>
#include<io.h>
int
%}
%%
^a
^b
^c
\n
hola
flag ='\0';
{flag = 'a'; ECHO;}
{flag = 'b'; ECHO;}
{flag = 'c'; ECHO;}
{flag = '\0'; ECHO;}
switch(flag){
case 'a':
fprintf(yyout, "primero"); flag ='\0'; break;
case 'b':
fprintf(yyout, "segundo"); flag ='\0'; break;
case 'c':
fprintf(yyout, "tercero"); flag ='\0'; break;
default: ECHO; break;
}
%%
int yywrap()
{
return 1;
}
Ingeniería en Computación
M. C. J. Jesús Arellano Pimentel
9
Esta nueva especificación se puede renombrar como EjeLex3.l.
Paso 2 Compilar la especificación guardada en el archivo EjeLex3.l con flex.
Para compilar la especificación .l se debe abrir la consola de comandos y cambiarse a
la ruta donde previamente se descomprimió el archivo Flex.exe, que es el mismo lugar
donde debe encontrarse el archivo EjeLex3.l. El comando de compilación cambia en
cuanto a la extensión del archivo a generar, dicho comando es el siguiente:
flex.exe -oEjeLex3.h EjeLex3.l
La ejecución anterior del comando generará un archivo de encabezado .h en lugar de
un archivo fuente .c.
Paso 3 Adicionar el archivo EjeLex3.h generado por flex a la aplicación CDlgAbrir
Copiar el archivo EjeLex3.h a la ruta del proyecto CDlgAbrir y agregarlo al proyecto
como “Archivo de encabezado” (esta operación es similar a la descrita en el paso 4 del
apartado 2.1 de ésta práctica). Hecho lo anterior, se debe agregar la inclusión de este
nuevo archivo de encabezado al archivo CDlgAbrir.cpp, aproximadamente después de
la línea #5 con la siguiente línea de código:
#include "EjeLex3.h"
Paso 4 Modificar el procesamiento del mensaje IDM_ABRIR
Ahora el código del procesamiento de dicho mensaje deberá ser el siguiente:
case IDM_ABRIR:
TCHAR szFile[MAX_PATH], szCaption[64 + _MAX_FNAME + _MAX_EXT];
OPENFILENAME ofn;
ZeroMemory(szFile, MAX_PATH);
ZeroMemory(&ofn, sizeof(OPENFILENAME));
ofn.lStructSize = sizeof(OPENFILENAME);
ofn.Flags= OFN_FILEMUSTEXIST | OFN_PATHMUSTEXIST | OFN_HIDEREADONLY | OFN_CREATEPROMPT;
ofn.hwndOwner
= hWnd;
ofn.lpstrFilter = _T("Archivos soportados(*.txt)\0*.txt\0Archivos de texto (*.txt)\0\0" );
ofn.lpstrTitle = _T("Abrir archivo");
ofn.lpstrFile
= szFile;
ofn.nMaxFile
= MAX_PATH;
if (IDOK == GetOpenFileName(&ofn)){
wsprintf(szCaption,_T("%s - %s"),szTitle, szFile[0] ? szFile :
_T("Sin archivo abierto"));
SetWindowText(hWnd, szCaption);
char scFile[MAX_PATH];
wcstombs(scFile,szFile,MAX_PATH);
yyin = fopen(scFile, "r");
if(yyin == NULL){
MessageBox(hWnd, L"No es posible cargar yyin", L"Error",MB_OK | MB_ICONERROR);
}else{
yyout = fopen("salidaw.txt", "w");
if(yyout == NULL){
MessageBox(hWnd, L"No es posible crear yyout", L"Error",MB_OK |
MB_ICONERROR);
}else{
yylex();
fclose(yyin); fclose(yyout);
}
}
}
break;
Ingeniería en Computación
M. C. J. Jesús Arellano Pimentel
10
Paso 5 Guardar, compilar, corregir y ejecutar
Guardar todos los archivos y compilar. El resultado de la compilación arrojará un error
en el archivo EjeLex3.h, en la línea correspondiente a al inclusión de la librería
unistd.h, basta con comentar esta línea y el error se corrige (//#include <unistd.h>).
Entonces estamos en la posibilidad de ejecutar la aplicación redireccionando la entrada
(yyin) de Flex al archivo seleccionado desde el cuadro de diálogo estándar para abrir
archivos en Windows.
3.- Referencias
[Petzold96] Petzold Charles, et al. Programación en Windows 95. Mc Graw Hill –
Microsoft Press. 1996.
Ingeniería en Computación
M. C. J. Jesús Arellano Pimentel
11
Descargar