Professional Documents
Culture Documents
1
Resumen
El proyecto de final de carrera que se desarrolla a continuacin consiste en
un intrprete integrado en un entorno de desarrollo que de un modo enteramente visual ejecuta y facilita la depuracin de programas escritos en un cdigo
intermedio de tres direcciones, potente y polivalente. A su vez detecta todos los
errores que pueda tener el programa tanto en tiempo de carga como en tiempo
de ejecucin. Para ello se pueden usar herramientas como los puntos de ruptura,
la inspeccin contnua de los valores en memoria, la ejecucin paso a paso o la
entrada y salida de datos por consola. El entorno de desarrollo permite adems
una integracin total con el compilador y permite la modificacin del cdigo
durante su uso, mejorando claramente las herramientas disponibles hasta ahora
para ello.
Se ha hecho especial incapi en conseguir que sea un programa de fcil uso
y rpido aprendizaje, y que sea muy minucioso a la hora de detectar y mostrar
los errores, pues el principal uso del programa es el docente o didctico aunque
no por ello el programa deja de tener toda la potencia necesaria para usarse
con un propsito general, soportando varios tipos de datos y permitiendo una
interaccin cmoda con el usuario mientras se ejecutan los programas. Adems,
pensando en posibles cambios y ampliaciones del conjunto de instrucciones de
cdigo intermedio se ha programado y documentado pensando en la fcil ampliacin del mismo por cualquier interesado.
ndice general
1. Introduccin
1.1. Breve descripcin y motivacin del proyecto . . . . . . . . . . . .
1.2. Conceptos generales . . . . . . . . . . . . . . . . . . . . . . . . .
1.2.1. Traductores: Compiladores e intrpretes . . . . . . . . . .
1.2.1.1. Traductores . . . . . . . . . . . . . . . . . . . . .
1.2.1.2. Compiladores . . . . . . . . . . . . . . . . . . . .
1.2.1.3. Ventajas e inconvenientes entre compiladores e
intrpretes . . . . . . . . . . . . . . . . . . . . .
1.2.2. Lenguajes y gramticas . . . . . . . . . . . . . . . . . . .
1.2.2.1. Lenguajes . . . . . . . . . . . . . . . . . . . . . .
1.2.2.2. Gramaticas . . . . . . . . . . . . . . . . . . . . .
1.2.3. El proceso de anlisis del programa fuente . . . . . . . . .
1.2.3.1. Anlisis lxico . . . . . . . . . . . . . . . . . . .
1.2.3.2. Anlisis sintctico . . . . . . . . . . . . . . . . .
1.2.3.3. Anlisis semntico . . . . . . . . . . . . . . . . .
1.3. Funcionamiento terico del intrprete . . . . . . . . . . . . . . . .
8
9
9
9
10
10
11
11
13
16
16
16
19
22
22
23
23
25
25
25
25
26
26
26
27
27
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
5
5
6
6
6
7
NDICE GENERAL
27
27
30
30
30
31
35
35
36
36
37
38
38
40
4. Manual de usuario
4.1. Introduccin rpida . . . . . . . . . . . . . . . . . . . . .
4.2. Instalacin . . . . . . . . . . . . . . . . . . . . . . . . . .
4.3. Primera vista . . . . . . . . . . . . . . . . . . . . . . . .
4.4. Carga de un programa . . . . . . . . . . . . . . . . . . .
4.4.1. Recargar un programa . . . . . . . . . . . . . . .
4.4.2. Posibles errores al cargar un programa . . . . . .
4.5. Cambiar el ancho de los paneles y las columnas de datos
4.6. Ejecutar paso a paso un programa . . . . . . . . . . . .
4.6.1. Detalles en la ejecucin de un programa . . . . .
56
56
56
57
59
60
60
61
61
62
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
41
43
44
44
46
47
47
48
49
49
51
51
52
53
54
54
NDICE GENERAL
. . . . . .
. . . . . .
. . . . . .
. . . . . .
el estado
. . . . . .
63
64
65
65
66
66
67
67
68
69
71
71
74
77
78
79
84
Captulo 1
Introduccin
1.1.
En la asignatura de procesadores de lenguajes de cuarto curso de ingeniera informtica los alumnos como prctica deben realizar un compilador para
programas fuente escritos en un lenguaje similar a C, llamado MenosC. Este
lenguaje, que vara ao tras ao, incluye los tipos bsicos de C para enteros y
reales, estructuras de control tales como los bucles FOR, los bucles WHILE, las
condiciones IF, llamadas a funciones y estructuras de datos como los vectores.
Sin embargo se descartan conceptos ms complicados como las estructuras de
datos compuestas o los punteros que complicaran demasiado el compilador. De
cualquier forma el lenguaje un subconjunto de C es suficientemente til para
programar cualquier algoritmo de forma imperativa con relativa sencillez.
Como para generar cdigo objeto para un computador del laboratorio, basado en el juego de instrucciones del Intel i386 es demasiado complicado y lo que
se pretende con la prctica es que el alumno se encargue de crear un compilador
sin tener la necesidad de conocer los entresijos que implica generar un ejecutable
de un sistema Linux o las numerosas instrucciones del procesador se decidi que
la salida del programa no fuese un fichero ejecutable estndar sino un cdigo
intermedio con tres argumentos por instruccin y de sencillo acceso a memoria.
Dicho cdigo intermedio, muy similar en concepto al del procesador MIPS usado
como ejemplo en las asignaturas de arquitectura de computadores lo denominaremos Cdigo de tres direcciones. A partir de este cdigo podra generarse
cdigo objeto, pero esto va ms all del objetivo del presente proyecto.
Para ejecutar nuestro programa MenosC compilado en cdigo de tres direcciones se hace necesario un intrprete que vaya ejecutando cada instruccin para
comprobar que el compilador realizado por el alumno genera las instrucciones
oportunas. Es dicho intrprete el que ha de encargarse de la carga y ejecucin
de las instrucciones y de la entrada y salida de datos del programa.
Hasta ahora el intrprete facilitado para las prcticas es un programa de
lnea de comandos, con una funcionalidad muy limitada para el usuario, donde
CAPTULO 1. INTRODUCCIN
1.2.
Conceptos generales
1.2.1.
Antes de mostrar las diferencias y similitudes entre un compilador y un intrprete hay que dar una definicin formal de los datos que procesan, programas
escritos en lenguajes de alto nivel.
Para especificar formalmente un lenguaje de alto nivel debemos dar tres
niveles de especificaciones para que los programas escritos en dicho lenguaje sean
correctos y no provoquen situaciones de ambiguedad. Adems pondr ejemplos
basados en uno de los lenguajes ms difundidos, C 1 .
Especificacin lxica: Contiene las reglas que deben cumplir las palabras
que forman el lenguaje. Identificadores, palabras reservadas, operadores...
Por ejemplo, en un programa escrito en C la palabra while est reservada
para indicar un bucle mientras que cualquier otro uso de la palabra est
prohibida, las variables no pueden empezar por un dgito, los corchetes se
usan para desreferenciar una posicin de un vector...
Especificacin sintctica: Contiene las reglas que construyen el lenguaje
a partir de su especificacin lxica. Por ejemplo, en C un bucle while ha
de tener una condicin entre parntesis y a continuacin una instruccin
o bloque de instrucciones, o la necesidad de cerrar todas las llaves que se
abren.
Especificacin semntica: Da el significado y las reglas que transforman
la especificacin sintctica en un programa consistente. Como ejemplo, en
C no se puede declarar varias veces la misma variable, o un bucle while
implica que debe ejecutarse el cdigo mientras la condicin se cumpla.
1.2.1.1.
Traductores
CAPTULO 1. INTRODUCCIN
7
Datos de entrada
Cdigo fuente
Fichero ejecutable
Compilador
Hardware destino
Datos de salida
Fase de compilacin
Fase de ejecucin
Intrprete
Datos de salida
Cdigo fuente
Fase de traduccin
Fase de ejecucin
Errores
Datos de entrada
Compiladores
CAPTULO 1. INTRODUCCIN
C++ a i386
PC i386
Calculadora.cpp
C++ a PowerPC
Mac PowerPC
C++ a C
C a Sistema propietario
Sistema empotrado
CAPTULO 1. INTRODUCCIN
1.2.2.
Lenguajes y gramticas
1.2.2.1.
Lenguajes
Gramaticas
CAPTULO 1. INTRODUCCIN
10
1.2.3.
1.2.3.1.
Anlisis lxico
En el anlisis lxico se extraen de la cadena de entrada los smbolos (tambin conocidos como tokens) que componen el lenguaje. Los tokens pueden ser
identificadores, palabras reservadas, smbolos matemticos... Estas unidades de
informacin son bsicas del lenguaje y no importa el rden en el que estn escritos de cara a la fase del anlisis lxico, ya que el encargado de discernir si los
tokens detectados estn en un orden aceptado por el lenguaje ser el analizador
sintctico.
Para ello se emplean autmatas finitos definidos con la expresin A =
(Q, , , q0 , F ), donde el autmata finito est definido por el conjunto de estados,
smbolos de entrada, funciones de transicin, y estados finales de aceptacin. [5]
Los espacios en blanco, tabuladores, comentarios y smbolos suprfluos usados por el programador para facilitar la lectura del cdigo fuente a otras personas
son desechados.
En el anlisis lxico se emplean gramticas regulares que definen los autmatas finitos antes descritos para discernir cual es el token adecuado para los
caracteres de entrada.
A continuacin mostramos un ejemplo con una lnea de lenguaje MenosC,
los tokens encontrados y las expresiones regulares que los identifican.
if (3.14 <= limite) a = a + 1;
1. Token if. Palabra reservada del lenguaje. Detectada por la expresin if
2. Token Abrir parntesis. Smbolo reservado del lenguaje. Detectado por la
expresin (
3. Token Constante real. Detectado por la expresin -?[0-9]+.[0-9]*
4. Token Menor o igual. Smbolo reservado del lenguaje. Detectado por la expresin <=. No es confundido por la concatenacin del token Menor que
seguido del token Igual, dado que el anlisis lxico acepta por definicin
la expresin regular ms larga.
5. Token Identificador. Detectada por la expresin [a-zA-Z]+{a-zA-Z0-9}*
6. Token Cerrar parntesis. Smbolo reservado del lenguaje. Detectado por
la expresin )
7. Token Identificador.
8. Token Asignacin. Smbolo reservado del lenguaje. Detectado por la expresin =
CAPTULO 1. INTRODUCCIN
11
9. Token Identificador.
10. Token Signo positivo. Smbolo reservado del lenguaje. Detectado por la
expresin +
11. Token Constante entera. Detectado por la expresin -?[0-9]+
12. Token Punto y coma. Detectado por la expresin ;
1.2.3.2.
Anlisis sintctico
L(G) = w T | S = w
G
Significando que el lenguaje definido por la gramtica G son todas las palabras que pertenecen al conjunto de palabras que se pueden formar con el alfabeto
T y surgen al derivar el smbolo inicial de la gramtica hasta formarla. [5]
Los tokens encontrados en el ejemplo anterior se pueden organizar en el
siguiente rbol sintctico, pudiendo derivarse usando las reglas de la gramtica
del lenguaje MenosC. Mostramos el rbol formado por el ejemplo de la seccin
1.2.3.1 en la figura 1.3.
1.2.3.3.
Anlisis semntico
Ahora que sabemos que la cadena de entrada pertenece lxica y sintcticamente al lenguaje, debemos comprobar si tiene sentido. Alguna de las comprobaciones que realiza un traductor de C puede ser [7]:
Comprobacin de tipos: Debemos asegurarnos que los tipos empleados
en las operaciones son compatibles. Por ejemplo, no podemos sumar un
entero con un real.
Comprobacin de unicidad: Una variable o funcin solo puede ser definida
una vez.
Comprobacin de flujo: Habra un error si por ejemplo usamos un break
desde fuera de un bucle.
CAPTULO 1. INTRODUCCIN
12
Inst_if
IF
(
Exp_simple
Termino
Instruccion
Expresion
Op_rel
Exp_simple
Inst_asignacion
<=
Termino
Asignacion
Factor
Factor
Parte_izquierda
CTE
ID
ID
Expresion
Exp_simple
Exp_simple
Op_add
Termino
Termino
Factor
Factor
ID
ID
CAPTULO 1. INTRODUCCIN
1.3.
13
CAPTULO 1. INTRODUCCIN
14
R. Activacin fact(3)
Datos
Dato retorno
Variable local
Variables temporales
Dato retorno
Parametro
Direccin retorno
Direccin de enlace
R. Activacin fact(2)
Variables temporales
Dato retorno
Parametro
Direccion retorno
Direccin enlace
R. Activacin fact(1)
Variables temporales
Dato retorno
Parametro
Direccion retorno
Direccin enlace
Variables temporales
Valores
0
x
...
6
3
Apilado por la instruccin
CALL del main
Antiguo FP del Registro de
activacin de main()
...
2
2
Apilado por la instruccin
CALL de fact(3)
Antiguo FP del registro de
activacin de fact(3)
...
1
1
Apilado por la instruccin
CALL de fact(2)
Antiguo FP del registro de
activacin de fact(2)
...
CAPTULO 1. INTRODUCCIN
15
modos se puede observar que slo se puede acceder a las variables contenidas
en el registro de activacin actual y en el caso de usar displays, en cada una de
las funciones anidadas superiores a la actual.
Para profundizar en el tema acudir al captulo Ambientes para el momento
de la ejecucin en [1].
Captulo 2
2.1.
Anlisis de requisitos
2.1.1.
Requisitos funcionales
Requisito 01
Descripcin: Se ha de poder cargar un fichero fuente en cdigo de tres direcciones en texto plano.
16
17
Importancia: 5
Justificacin: Hasta ahora, en el intprete proporcionado a los alumnos se
deba introducir un programa guardado en forma binaria. Debamos compilar las fuentes dos veces, una vez con salida en modo texto para poder
leer el cdigo y la otra en modo binario para ejecutarlo. El fichero que
podamos ejecutar por tanto no poda ser modificado.
Validacin: Hecho. Nuestro intrprete se carga con ficheros en modo texto. En
la seccin 4.4 se explica cmo.
Requisito 02
Descripcin: Se ha de poder ejecutar el programa paso a paso.
Importancia: 5
Justificacin: El usuario debe poder ver como afecta cada instruccin al contenido de la memoria, los saltos en el flujo del programa y los posibles
mensajes de error, sabiendo en cada momento por qu se han producido.
Validacin: Hecho. La seccin 4.6 muestra toda su utilidad.
Requisito 03
Descripcin: Se ha de poder ejecutar el programa de forma continua.
Importancia: 4
Justificacin: El usuario debe poder ejecutar de forma contnua programas
que por su longitud o elevada recursividad no sea factible ejecutarlos paso
a paso por el tiempo que se tardara.
Validacin: Hecho. Puede ver la forma de uso en la seccin 4.7.
Requisito 04
Descripcin: Se ha de poder manejar distintos tipos de datos.
Importancia: 5
Justificacin: Aunque los usuarios del intrprete grfico actualmente solo usen
datos de tipo entero, debe estar preparada para ejecutar programas que
contengan instrucciones con operadores reales y estar preparada para que
con ligeras modificaciones de cdigo, admitir cualquier otro tipo de dato
(por ejemplo, punteros).
18
Validacin: Hecho.
Requisito 05
Descripcin: El programa no debe fallar al pedir datos al usuario.
Importancia: 3
Justificacin: Cuando el usuario cargue un programa y al ejecutarlo se llegue
a una instruccin que pida un dato al usuario (ya sea entero, real o carcter) el intrprete debe validar que el dato de entrada corresponde al tipo
solicitado.
Validacin: Hecho. Para ms informacin acudir a la seccin 4.12.
Requisito 06
Descripcin: Se ha de poder parar el programa en cualquier momento.
Importancia: 4
Justificacin: Cuando el usuario vea que su programa tiene errores o no desee
acabar su ejecucin debe poder pararlo, reiniciando de este modo el estado
del intrprete.
Validacin: Parcialmente. El intrprete no puede reiniciarse si entra en un
bucle infinito en el modo de ejecucin contnua.
Requisito 07
Descripcin: Se deben poder establecer breakpoints.
Importancia: 5
Justificacin: El usuario debe poder establecer breakpoints en cualquier instruccin. As, en la ejecucin contnua del programa el intrprete grfico
se detendr antes de decodificar la instruccin.
Validacin: Hecho. Para informarse sobre sus usos o activacin ver la seccin
4.8 o la figura de la pgina 50.
19
Requisito 08
Descripcin: El intrprete grfico debe detectar cualquier fallo que contenga
el programa de entrada en tiempo de carga y mostrarlo claramente.
Importancia: 5
Justificacin: El usuario debe poder ver todos los errores que tenga su programa en tiempo de carga. De esta forma no perder el tiempo ejecutando
programas en los que se sepa que contienen errores de antemano, adems
de una inestimable ayuda al programador del compilador. Sin embargo es
una caracterstica que debe poder desactivarse por parte del usuario para
hacer pruebas en programas parcialmente correctos.
Validacin: Hecho. En la seccin 4.4.2 se detallan y ejemplifican los errores en
tiempo de carga que se detectan.
Requisito 09
Descripcin: El intrprete grfico debe detectar cualquier fallo o situacin
sospechosa que se produzca durante la ejecucin de un programa y avisar.
Importancia: 5
Justificacin: El usuario debe poder ver todos los errores que su programa
cometa en tiempo de ejecucin, ya que por lo general suelen ser errores
sutiles o de concepto (uso de la pila de memoria, uso del frame pointer,
etc.
Validacin: Hecho. En la seccin 4.6.3 se encuentra una lista con todos los
errores detectables.
2.1.2.
Requisitos de usabilidad
Requisito 10
Descripcin: Se ha de poder recargar un fichero.
Importancia: 3
Justificacin: El usuario puede volver a cargar el fichero que ya est ejecutndose. Esto es til cuando se ha compilado una nueva versin del mismo.
Validacin: Hecho. Puede ver su forma de uso en la seccin 4.4.1.
20
Requisito 11
Descripcin: No se debe visualizar el contenido de la memoria a partir del
puntero a cima.
Importancia: 2
Justificacin: Cualquier dato que est por encima del puntero de pila no debera ser vlido y por tanto debe ser ignorado en la memoria y ocultada su
representacin de cara al usuario. Se puede confiar en que el usuario sepa
que los datos por encima del puntero a cima son residuales, advirtiendo
al usuario que intente escribir o leer posiciones de memoria superiores al
puntero a cima. Debe poder desactivarse por parte del usuario para poder
depurar programas que fallen escribiendo o leyendo por encima del vector
cima.
Validacin: Hecho. Para conocer las implicaciones que resultan de activar esta
opcin leer la seccin 4.6.2.
Requisito 12
Descripcin: Se ha de introducir algn mecanismo de comentarios.
Importancia: 3
Justificacin: Los programas escritos en cdigo de tres direcciones suelen ser
difciles de comprender en una primera lectura. Se debe dejar al usuario
la libertad para que su compilador emita comentarios que luego muestre
el intrprete grfico. Es de gran ayuda para comprender cual bloque de
instrucciones del cdigo MenosC est sustituyendo las instrucciones mostradas en el intrprete.
Validacin: Parcialmente. En un fichero de cdigo de tres dimensiones se aceptan dos tipos de comentario, basados en texto y en el uso de la instruccin
NOP con un argumento entero identificativo. Sin embargo en la representacin del programa en el intrprete slo se mostrarn las instrucciones
NOP.
Requisito 13
Descripcin: El intrprete grfico ha de ser fcil de instalar
Importancia: 2
Justificacin: El intrprete depende de varias libreras, principalmente de Qt
4. Adems para compilarlo se necesitan algunos programas adicionales al
compilador de C++. Es por ello que es recomendable distribuirlo bien sea
en un fichero .deb o con un makefile automtico.
21
Requisito 14
Descripcin: Se debe distribur el intrprete grfico en diversos idiomas.
Importancia: 1
Justificacin: El intrprete va a ser fundamentalmente usado por alumnos a
los que se les ofrece la asignatura en castellano, valenciano e ingls. El
intrprete debera estar traducida al menos a esos idiomas.
Validacin: Parcial. A ampliar en futuras versiones. El intrprete est en castellano, pero todo el texto que se muestra al usuario est marcado para
que pueda traducirse sin esfuerzo usando la herramienta Qt Linguist. En
cualquier caso la abundancia de iconos sencillos de entender no hace excesivamente importante la traduccin.
Requisito 15
Descripcin: Se debe poder llamar al compilador y al editor desde el mismo
intrprete.
Importancia: 3
Justificacin: En un entorno de desarrollo normalmente se recompila el cdigo
cada vez que se corrige algn error. Es por ello que la introduccin de una
orden que compilase el cdigo y abriese un editor sera una buena ayuda.
Validacin: Hecho. Adems para ello se ha aadido un men de configuracin
indicando cual es la ruta del compilador o editor que queremos usar (ver
seccin 4.13).
Requisito 16
Descripcin: El intrprete debe guardar sus opciones de configuracin cada
vez que se cierra para recordarlas la prxima vez que se ejecute.
Importancia: 3
22
2.1.3.
Requisitos de rendimiento
Requisito 17
Descripcin: El intrprete grfico debe ejecutar el cdigo en modo contnuo
de forma rpida.
Importancia: 3
Justificacin: Aunque el intrprete va a ser utilizado principalmente para fines didcticos, es necesario que la ejecucin de cdigo de forma contnua
sea lo ms rpida posible para evitar largas esperas en algoritmos poco
optimizados.
Validacin: Hecho. El intrprete mientras est ejecutando cdigo en modo
contnuo no modifica ningn objeto de la interfaz de usuario. Los cambios
se aplican cuando la ejecucin finaliza, ya sea por llegar al fin del cdigo,
un error de ejecucin o a un punto de ruptura.
2.1.4.
Requisito 18
Descripcin: El cdigo del intrprete grfico debe ser modular, fcil de comprender y de ampliar.
Importancia: 5
Justificacin: El intrprete cumple un propsito eminentemente didctico.
Aunque el conjunto de instruccines de cdigo de tres direcciones es suficientemente amplio para cualquier tarea, es posible que en un futuro se
necesiten inclur ms o cambiar su semntica.
Validacin: Hecho. El intrprete grfico centraliza el cdigo referente a la implantacin de las instrucciones y se detalla en su manual como codificar
nuevas instrucciones, adems el cdigo est profusamente comentado.
23
Requisito 19
Descripcin: El intrprete grfico debe poder compilarse de forma sencilla.
Importancia: 4
Justificacin: Aunque el cdigo fuente del intrprete no es muy extenso, para
compilarse necesita la presencia de varios programas y libreras auxiliares,
ejecutndose en un rden determinado. No debemos presuponer que el
usuario que necesite compilarlo pueda hacerlo.
Validacin: Hecho. El manual hace referencia a los pasos y dependencias necesarias para compilar el intrprete. Adems se incluye un fichero con las
rdenes necesarias que automatizan su compilacin.
2.2.
Los casos de uso son las secuencias de interacciones que se desarrollarn entre
un sistema y sus actores en respuesta a un evento que inicia un actor principal
sobre el sistema, en este caso el usuario sobre el intrprete grfico. Forma parte
del la fase de diseo junto a la especificacin de requisitos en cualquier desarrollo
software [6].
En la figura 2.1 mostramos de forma esquemtica los casos de uso del programa.
Cabe recordar que para ver en detalle todas las opciones disponibles en
detalle puede consultar el manual de usuario en la seccin 4.
2.2.1.
Abrir programa
Aadir
breakpoint
Ejecutar de
forma continua
Desplazar el
visor de memoria
<<Incluye>>
Solicitar ayuda
Usuario
Borrar breakpoint
Abrir programa
<<Incluye>>
<<Incluye>>
Recargar programa
Borrar todos
los breakpoints
<<Incluye>>
<<Incluye>>
24
2.2.2.
25
Recargar programa
2.2.3.
2.2.4.
2.2.5.
Borrar un breakpoint
2.2.6.
26
2.2.7.
2.2.8.
Aadir breakpoint
2.2.9.
27
2.2.10.
Solicitar ayuda
2.3.
2.4.
28
Recargar
programa
Iniciar el
intrprete
Intrprete
descargado
Cargar
programa
Intrprete
cargado
Ejecutar
Reiniciar el
estado del
intrprete
Ejecucin finalizada
(o abortada)
Fin de programa
o excepcin
Instruccin
de entrada
de datos
Peticin
de datos
Intrprete
en ejecucin
Dato de
entrada
29
Captulo 3
Una aproximacin a Qt
3.1.1.
Historia de Qt
Qt es una librera multiplataforma para desarrollar intefaces grficas de usuario aunque tambin es til para el desarrollo de programas sin interfaz grfica
como herramientas de consola y servidores. Qt es muy conocida al ser usada
en el entorno de ventanas KDE, adems de otras muchas aplicaciones como
KOffice, K3B, Opera o VideoLAN, entre otros. Es producido por la divisin de
software Qt de Nokia, que entr en vigor despus de la adquisicin por parte
de Nokia de la empresa noruega Trolltech, el productor original de Qt, el 17 de
junio de 2008. [3]
Inicialmente Qt apareci como biblioteca desarrollada por Trolltech (en aquel
momento Quasar Technologies) en 1992 siguiendo un desarrollo basado en el
cdigo abierto, pero no completamente libre. Originalmente permita desarrollo
de software cerrado mediante la compra de una licencia comercial, o el desarrollo
de software libre usando la licencia Free Qt. Esta ltima no era una licencia real
de software libre dado que no permita redistribuir versiones modificadas de Qt.
Se us activamente en el desarrollo del escritorio KDE con un notable xito
y rpida expansin, camino de convertirse en uno de los escritorios ms populares de GNU/Linux. Este hecho causaba preocupacin desde el proyecto GNU,
30
31
ya que vean como una amenaza para el software libre que uno de los escritorios libres ms usados se apoyase en software propietario. Para contrarrestar
esta situacin se plantearon dos iniciativas: por un lado el equipo de GNU en
1997 inici el desarrollo del entorno de escritorio GNOME con GTK+ para
GNU/Linux. Por otro lado se intent hacer una biblioteca compatible con Qt
pero totalmente libre, llamada Harmony.
En 1998 desarrolladores de KDE se reunieron con Trolltech para establecer
la Free Qt Foundation, que estableca que si Trolltech dejaba de desarrollar la
versin gratuita y semi-libre de Qt la propia Fundacin podra liberar la ltima
versin publicada de la biblioteca Qt bajo una licencia tipo BSD.
En el ao 2000 Trolltech comenz a ofrecer la biblioteca Qt 2.1 bajo la
licencia GPL en su versin para Linux. La versin para MacOS X no se public
bajo GPL hasta 2003, mientras que la versin para Windows fue publicada bajo
la licencia GPL en junio de 2005.
Qt cuenta actualmente con un sistema de triple licencia: GPL para el desarrollo de software de cdigo abierto y software libre, la licencia de pago QPL
para el desarrollo de aplicaciones comerciales, y a partir de la versin 4.5 una
licencia gratuita pensada para aplicaciones comerciales, LGPL.
3.1.2.
Aunque Qt utiliza el lenguaje de programacin C++ de forma nativa, adicionalmente puede ser utilizado en varios otros lenguajes de programacin a
travs de bindings, siendo los ms populares QTJambi, para Java y PythonQt
para Python.
Qt es una librera orientada a clases, habiendo clases para cualquier necesidad
que tengamos: creacin de dilogos, ventanas, widgets predefinidos y creados por
el programador, grficos 2D y 3D, proceso de eventos, entrada y salida, conexin
a bases de datos, conexin a redes, programacin concurrente...
Mirando ms de cerca las funciones que vamos a emplear, es decir, las que
se refieren a la creacin de interfaces de usuario, Qt es sencillo de usar. Con
Qt usaremos el concepto de accin, elemento que define un trabajo concreto y
puede mostrarse tanto en la barra de mens, las cajas de herramientas o en los
atajos de teclado.
A una ventana en Qt puede aadirse una barra de estado, diferentes paneles,
widgets y otros elementos con las que el usuario puede interactuar. La forma
de unir las interacciones del usuario con el cdigo que escriba el programador
es a travs de la instruccin connect y disconnect. Estas instrucciones no
pertenecen al lenguaje C++, lo que hace que el cdigo deba preprocesarse por la
herramienta de precompilacin de Qt antes de ser compilado por un compilador
de C++ como puede ser el g++.
A continuacin se propone un ejemplo de clase Qt comentada para ver sus
funcionalidades principales:
1 /* Fichero dialogo.h */
#include <QDialog>
32
10
15
20
#include <QtGui>
class FindDialog : public QDialog {
Q_OBJECT
public:
FindDialog(QWidget *parent = 0);
signals:
void findNext(const QString &str, Qt::CaseSensitivity cs);
void findPrevious(const QString &str, Qt::CaseSensitivity cs);
private slots:
void findClicked();
void enableFindButton(const QString &text);
private:
QLabel *label;
QLineEdit *lineEdit;
QCheckBox *caseCheckBox, *backwardCheckBox;
QPushButton *findButton, *closeButton;
};
33
En la lnea 12 definimos slots privados. Los slots son mtodos que se pueden
activar mediante la interaccin del usuario. En este ejemplo el slot findClicked
lo activaremos cuando el usuario pulse el botn find, y el slot enableFindButton
se activar cuando el usuario introduzca algn caracter en la caja de texto. Los
slots los uniremos con las seales adecuadas usando connect ms adelante.
Finalmente declaramos los seis widgets con los que cuenta el ejemplo.
01 FindDialog::FindDialog(QWidget *parent)
: QDialog(parent){
label = new QLabel(tr("Find &what:"));
lineEdit = new QLineEdit;
05
caseCheckBox = new QCheckBox(tr("Match &case"));
backwardCheckBox = new QCheckBox(tr("Search &backward"));
findButton = new QPushButton(tr("&Find"));
findButton->setDefault(true);
findButton->setEnabled(false);
10
closeButton = new QPushButton(tr("Close"));
connect(lineEdit, SIGNAL(textChanged(const QString &)),
this, SLOT(enableFindButton(const QString &)));
connect(findButton, SIGNAL(clicked()),
this, SLOT(findClicked()));
15
connect(closeButton, SIGNAL(clicked()),
this, SLOT(close()));
QHBoxLayout *topLeftLayout = new QHBoxLayout;
topLeftLayout->addWidget(label);
topLeftLayout->addWidget(lineEdit);
20
QVBoxLayout *leftLayout = new QVBoxLayout;
leftLayout->addLayout(topLeftLayout);
leftLayout->addWidget(caseCheckBox);
leftLayout->addWidget(backwardCheckBox);
QVBoxLayout *rightLayout = new QVBoxLayout;
25
rightLayout->addWidget(findButton);
rightLayout->addWidget(closeButton);
QHBoxLayout *mainLayout = new QHBoxLayout;
mainLayout->addLayout(leftLayout);
mainLayout->addLayout(rightLayout);
30
setLayout(mainLayout);
setWindowTitle(tr("Find"));
}
El constructor del dilogo hace lo que cabra esperar. Crea la etiqueta de texto
que solicita la palabra a buscar, la caja de texto y los botones de opcin que
indican si se buscar distinguiendo maysculas de minsculas o si se buscar
hacia atrs. En la lnea 7 se crea el botn Find y establece las opciones para que
el botn sea el predefinido se pulsar cuando el usuario aprete la tecla intro
y que aparezca desactivado. A continuacin se declara el botn que cierra el
dilogo.
34
En la lnea 11 se declaran las conexiones, donde tenemos que unir una seal
de una clase Qt con el slot de otra. En este ejemplo se hacen tres conexiones:
La primera une la interaccin del usuario con la caja de texto con un
mtodo que comprobar que la entrada sea vlida y activar el botn
find.
La segunda conecta la accin de hacer clic sobre el botn find con un
mtodo que enviar los datos a la ventana principal.
La tercera conecta el botn cerrar con el slot predefinido close, heredado
de la clase QDialog.
A partir de la lnea 17 se establecen diferentes capas para que Qt ordene los
widgets de forma automtica. Este mecanismo es muy cmodo ya que dejamos
que recaiga sobre Qt la tarea de ordenar las ventanas de modo que los widgets
queden perfectamente alineados y se redimensionen cuando se redimensione el
dilogo. Por ltimo se pone el ttulo a la barra superior del dilogo.
01 void FindDialog::findClicked()
{
QString text = lineEdit->text();
Qt::CaseSensitivity cs =
05
caseCheckBox->isChecked() ? Qt::CaseSensitive
: Qt::CaseInsensitive;
if (backwardCheckBox->isChecked()) {
emit findPrevious(text, cs);
} else {
10
emit findNext(text, cs);
}
}
El mtodo findClicked se activa cuando el usuario pulsa el botn find. Como
puede verse lo que hace es tomar el texto de la caja de texto, comprobar que
el botn de opcin caseCheckBox est o no pulsado y dependiendo si hemos
activado la bsqueda inversa emitir la seal findPrevious o findNext con los
datos que hemos recojido en las lneas 3 y 4.
3.1.3.
35
3.2.
introducirentero.h
introducirentero.cpp
introducircaracter.h
introducircaracter.cpp
introducirreal.h
introducirreal.cpp
36
ejecuta.cpp
sigpaso.cpp
principal.h
cod3d.cpp
definiciones.h
parser.y
acc_mem.cpp
main.cpp
parsea.c
Iconos
lexer.l
carga.cpp
Virtual.qrc
principal.cpp
3.3.
3.3.1.
Para el analizador lxico y sintctico he preferido usar Flex y Bison1 , herramientas de generacin de cdigo consolidadas en vez de nuevas herramientas
1 Se puede encontrar ms informacin en su web dentro del proyecto GNU:
http://www.gnu.org/software/
37
3.3.2.
:=
negativo
38
negativo
negativo
39
datos de los dos primeros argumentos y en el caso de cumplirla se salta a la instruccin sealada por el tercer parmetro. Adems hay intrucciones de entrada
y salida, saltos incondicionales, instrucciones para el manejo de vectores, que
modifican el puntero a pila, que modifican el puntero a frame...
Nuestro intrprete se comporta como una mquina de memoria en forma
de pila, sin registros de propsito general. La memoria del intrprete puede
representarse como un vector de mil posiciones donde en cada una de las cuales
puede escribirse un nmero entero o real3 y se accede a l de forma aleatoria,
aunque el cdigo de tres direcciones est orientado a que se use en forma de
pila de control. Los registros de activacin se introducen y se sacan cuando los
procedimientos empiezan y terminan respectivamente.
Adems hay tres importantes punteros:
El puntero a cima marca la posicin de memoria donde se deber escribir
el prximo registro de activacin. Se modifica con las instrucciones de tipo
PUSH, POP, TOPFP, INCTOP y DECTOP.
Nuestro cdigo de tres direcciones no contiene instrucciones para el manejo
de un display, as que no ser posible traducir lenguajes de programacin
en los que se puedan anidar definiciones de funciones. (Ver el captulo
Acceso a variables no locales en [1]) Sin embargo tenemos un puntero
de marco que separar las variables globales de las locales. Para modificar
este puntero se deben usar las instrucciones FPTOP y FPPOP.
El contador de programa, que siempre apuntar a la siguiente instruccin
que deba ser ejecutada. Cada vez que se ejecute una instruccin deber
incrementarse en una unidad excepto en una instruccin de salto, donde
el contador se actualizar al valor del destino del salto.
Todos los datos de las instrucciones sern datos inmediatos se obtienen al
decodificar la instruccin o bien se indicar la posicin de memoria donde se
encuentra en un formato de nivel y desplazamiento. La forma de decodificar esta
tupla a la direccin fsica es sumndole al desplazamiento el puntero a marco en
el caso que nivel indique que buscamos una variable local (valor de nivel true) y
solo el desplazamiento si lo que queremos es una variable global (valor de nivel
false). Sin embargo para dejar los resultados se deber indicar la direccin de
memoria.
Hay varios tipos de instrucciones:
Aritmticas, tanto para enteros como para reales.
De conversin entre enteros y reales.
De modificacin del flujo del programa, tanto para saltos incondicionales
como condicionales, incluyendo comparaciones entre reales y enteros.
De modificacin del puntero a pila y el puntero a marco.
3 Aunque
40
3.3.3.
Las instrucciones de cdigo intermedio pueden contener los siguientes tokens que sern identificados gracias al cdigo Flex contenido en el archivo parser_c3d/lexer.l. Si en el fichero de entrada se encuentran tokens no definidos
aqu, al cargar el programa se mostrar un error lxico. La especificacin lxica del fichero de entrada se comprueba mediante las siguientes expresiones
regulares:
#.\n
[ \t]+
Cualquier aparicin, separada o seguida de espacios en blanco o tabuladores son separadores sin ningn significado sintctico. El analizador lxico los deshecha.
\n
-?[0-9]+ Token entero. Ms tarde el analizador sintctico lo emplear en varios casos. Le pasa al analizador sintctico un nmero entero como
valor semntico.
-?[0-9]+.[0-9]* Token real. Luego el analizador sintctico lo emplear en el
caso de un argumento real. Le pasa al analizador sintctico un nmero en punto flotante como valor semntico.
(
Token abrir parntesis. Sintcticamente se usa al delimitar un puntero, para resolver la ambiguedad de la coma, que separa tanto un
argumento como las dos partes que componen una posicin de memoria.
41
3.3.4.
42
43
3.3.5.
3.4.
44
En el intrprete se trabajar bsicamente con dos tipos de datos, las instrucciones del programa cargado y los datos guardados en la memoria por dichas
instrucciones. A su vez han de guardarse de dos modos distintos, uno para que
al algoritmo de ejecucin le sea fcil de manejar y otro para que pueda ser
representado en los widgets que muestran los datos al usuario. De modo que
en la clase principal que defina nuestra aplicacin encontramos las siguientes
instancias de objetos (en el archivo principal.h):
QList<QTreeWidgetItem *> rep_inst, rep_mem;
QList<c_tipo_ctd *> list_inst;
QList<c_tipo_mem *> list_mem;
Las cuatro instancias son listas. Rep_inst y rep_mem representan en los paneles las instrucciones y las memoria respectivamente. Contienen elementos del
tipo QTreeWidgetItem, clase predefinida en Qt. En cambio las listas list_inst
y list_mem contienen las intrucciones y la memoria que ejecuta el intrprete.
Estas listas contienen instancias de las clases c_tipo_ctd y c_tipo_mem, que
paso a describir a continuacin.
3.4.1.
Las instrucciones que se leen en el proceso de carga acaban finalmente guardadas en una lista que contiene elementos de la clase c_tipo_ctd. La clase est
definida en el archivo virtual/principal.h como:
enum t_cod_ins {NULO = 0, ESUM, RSUM, EDIF,
RDIF, EMULT, RMULT, EDIVI,
RDIVI, RESTO, CONV /*...*/};
enum t_cod_arg {ARG_NULO = 0, ARG_ENTERO, ARG_REAL,
ARG_POSICION, ARG_ETIQUETA};
enum error_mem {NO_ERROR = 0, ERROR_VACIA, ERROR_NOEXISTE,
ERROR_TIPO, ERROR_ARG};
struct st_posmem {
int i_e_pos;
bool niv;
};
union un_arg {
float r;
st_posmem i_e_pos_niv;
};
struct st_arg {
t_cod_arg tipo_arg;
un_arg dato;
};
class c_tipo_ctd {
45
public:
c_tipo_ctd();
t_cod_ins r_cop();
bool r_brp();
error_mem r_arg(int p_arg, t_cod_arg *p_cod);
error_mem r_int(int p_arg, int *p_val);
error_mem r_eti(int p_arg, int *p_val);
error_mem r_pos(int p_arg, bool *p_niv, int *p_pos);
error_mem r_rea(int p_arg, float *p_fval);
void s_cop(t_cod_ins p_cop);
void s_brp(bool p_brp);
error_mem s_int(int p_arg, int p_val);
error_mem s_eti(int p_arg, int p_val);
error_mem s_pos(int p_arg, bool p_niv, int p_pos);
error_mem s_rea(int p_arg, float p_fval);
void setnull(); // Resetea todos los campos
error_mem setnull(int p_arg); // Resetea un argumento
private:
t_cod_ins cop;
// Cdigo de instruccin
bool breakpoint; // Indica la condicin de punto de ruptura
st_arg v_arg[3]; // Vector con los tres argumentos
};
En el cdigo se puede apreciar tanto los datos privados como los mtodos pblicos que modifican su estado. Los mtodos estn diferenciados por el prefijo r_
para los que leen un dato de la clase y el s_ para los que escriben. Mientras no
se advierta lo contrario, las llamadas pasan los datos por valor y devuelven por
referencia, ya que se aprovecha el valor de retorno de las funciones para indicar
errores.
El constructor de la clase crea una nueva instruccin con todos los valores
nulos. As despus de crearlo debemos insertar con los mtodos adecuados los
valores. Si tenemos la siguiente instruccin:
23 EDIVI i:8, p:(0,2), p:(1,4)
Para almacenarla adecuadamente debemos ejecutar los siguientes pasos:
c_tipo_ctd *instruccion = new c_tipo_ctd;
instruccion->s_cop(EDIVI);
instruccion->s_int(0 /*Nmero de argumento*/, 8 /*Valor*/);
instruccion->s_pos(1 /*Nmero de argumento*/, false /*Nivel*/,
2 /*Desplazamiento*/);
instruccion->s_pos(2 /*Nmero de argumento*/, true /*Nivel*/,
4 /*Desplazamiento*/);
Aunque no es estrictamente necesario es una buena idea comprobar el tipo error
devuelto para cerciorarse de que el mtodo se ha ejecutado correctamente. Cada
error tiene un significado distinto:
46
3.4.2.
Codificacin de la memoria
3.4.3.
47
p_top:
p_fp:
Frame pointer.
3.5.
En las secciones siguientes mostraremos como se ejecuta una instruccin desde el momento de su bsqueda hasta la actualizacin del contador de programa.
El cdigo puede encontrarse en los archivos sigpaso.cpp y ejecuta.cpp.
3.5.1.
48
Cada vez que el intrprete necesite ejecutar una instruccin utiliza alguno de
los siguientes mtodos para decodificar la instruccin y buscar los operadores.
Los mtodos de esta seccin se encuentran en definidos en el archivo principal.h.
Para leer el cdigo de instruccin usamos r_cop(), como hemos visto en
la seccin 3.4.1.
t_cod_ins codigo = instruccion->r_cop();
Comparamos el cdigo de la instruccin en un switch para usar el mtodo
correspondiente con la semntica de la operacin. Se puede encontrar en
el archivo ej_inst.cpp.
/* la instruccin tiene un codigo == ESIG */
switch(codigo){
/*...*/
case ESIG:
Recuperamos el nico operador que tiene la instruccin ESIG. Recordemos que el analizador sintctico nos evita tener que comprobar que sus
parmetros sean correctos:
int op;
error_mem error = recupera_op(0, instruccion, &op);
Ahora en la variable op tendremos el dato correspondiente al primer argumento
de la instruccin, sin importar si el argumento de la instruccin es un entero o
una posicin de memoria. El mtodo recupera_op la recupera por nosotros.
El mtodo recupera_op est sobrecargado para que sea posible usarlo con
cualquier argumento:
error_mem recupera_op(int narg, c_tipo_ctd *inst, int *val) se usa para
recuperar valores enteros, ya sea entero, etiqueta o posicin de memoria
que contenga un entero.
error_mem recupera_op(int narg, c_tipo_ctd *inst, float *fval) recupera
reales, ya sea de un real o de una posicin de memoria que contenga un
real.
error_mem recupera_op(int narg, c_tipo_ctd *inst, bool *niv, int *pos)
recuperar el nivel y el desplazamiento de un argumento tipo posicin.
Realmente lo usan las dos funciones anteriores.
Si ha habido problemas recuperando en memoria algn dato, el valor error_mem
de retorno nos informa, ya bien sea ERROR_NOEXISTE si la posicin de memoria es negativa o supera el lmite, ERROR_TIPO si el dato en la memoria no
era del tipo solicitado o ERROR_VACIA si intentbamos leer de una posicin de
memoria en la que an no se ha escrito.
3.5.2.
49
3.5.3.
Adems de las instrucciones tpicas que leen datos y finalmente los escriben
en la memoria tambin tenemos instrucciones que modifican el flujo de ejecucin, el frame pointer o el puntero a cima. Para ello, despus de decodificar la
instruccin y buscar sus operadores, si una instruccin modifica la cima (por
ejemplo INCTOP, EPUSH, EPOP, etc.) puede usar la instruccin:
error_mem set_top(int n_top, bool p_muestra = true)
50
Salto = false
Decodificar instruccin
Bsqueda de operadores
Pide datos
al usuario
Ejecucin
Modifica el flujo del programa
Muestra al
usuario
Modifica punteros
Cond.
salto?
True
Salto = true
False
True
salto?
inst_act = direccion
direccion = etiqueta
False
inst_act++
1
3.6.
51
3.6.1.
La clase QMainWindow es el eje donde gira nuestro programa4 . La clase principal hereda directamente de la anterior. Entre sus propiedades se encuentra la de
poder aadirle barras de estado, barras de mens, barras de herramientas, etc.
En el proyecto la configuracin de la ventana principal se ejecuta bsicamente
en el constructor de la clase principal. Entre todas las acciones destacamos:
menuBar() devuelve un puntero a la barra de mens de la ventana. Podremos aadirle mens usando el mtodo addMenu(). Por ejemplo, para
establecer el men archivo usaramos:
menu_archivo = menuBar()->addMenu(Archivo);
Al que luego tendramos que aadir las acciones del men mediante el
mtodo addAction():
menu_archivo->addAction(accion_abrir);
menu_archivo->addAction(accion_recargar);
menu_archivo->addAction(accion_salir);
addToolBar() permite introducir una barra de herramientas en la posicin
de la ventana que queramos. Por defecto la aade arriba de la ventana,
debajo de la barra de mens. El intrprete grfico tiene tres barras de
men: barra_ejecutar, barra_archivo y barra_Ayuda. Un ejemplo de su uso
puede ser el siguiente:
barra_ayuda = addToolBar(Ayuda);
Al que luego, como en el caso anterior, debemos introducir las acciones
necesarias:
barra_ayuda->addAction(accion_ayuda);
barra_ayuda->addAction(accion_acerca);
statusBar() nos permite aadir una barra de estado en la que podemos
poner el widget que queramos. En el proyecto la barra de estado cuenta
con una etiqueta de texto con la que lanzamos mensajes cada vez que
ejecutamos una accin. La forma en la que inicializamos la barra es:
4 Recomiendo acudir a la documentacin Qt 4 Assistant se instala a la vez que las libreras
de desarrollo para profundizar en la gran cantidad de posibilidades que ofrece.
52
Figura 3.5: Como puede comprobarse, las tres barras desplazables que hay entre
los cuatro espacios son la representacin de los QSplitter, mientras que los dos
cuadros de abajo son de texto y los superiores son QTreeWidget.
QLabel *texto_barra_estado = new QLabel(Listo);
statusBar()->addWidget(texto_barra_estado);
Por ltimo podemos poner un icono y un ttulo a la ventana con setWindowIcon() y setWindowTitle() respectivamente, y establecer el widget
principal de la ventana con setCentralWidget().
La ventana principal se define en el archivo principal.h y se modifican sus parmetros para que muestre el estado que deseamos en el mtodo Principal::Principal().
3.6.2.
Tras definir la ventana principal debemos establecer un widget como elemento pricipal de la ventana. Para ello debemos hacer una aclaracin. Hay dos
tipos de widgets:
Widgets interactivos Son los widgets con los que el usuario interacta, como los
botones, botones de opcin, cajas de texto...
Widgets contenedores Son widgets diseados para contener otros widgets, como
las carpetas de pestaas, frames, cajas de scroll...
Por lo tanto en la ventana principal hemos aadido tres QSplitter donde insertaremos en los cuatro huecos que dejan una caja de salida de texto para los
datos de salida del intrprete, otra caja de texto para la salida de errores y
dos QTreeWidget para representar los paneles de las intrucciones y la memoria.
En la figura 3.5 se puede ver claramente, mientras que en la figura 3.6 se ve la
organizacin jerrquica de la misma.
53
Ventana
Principal
Barra de
herramientas
Barra de
men
Barra de
estado
Splitter
secundario
izquierdo
Panel de
instrucciones
Splitter
principal
Splitter
secundario
derecho
Panel de
errores
Panel de
memoria
Panel de
salida de
datos
3.6.3.
La clase QTreeWidget proporciona un espacio para mostrar de forma ordenada y jerrquica iconos y textos que estn empaquetados en instancias de la
clase QTreeWidgetItem. Aunque estemos familiarizados con el widget gracias a
su utilidad a la hora de mostrar los ficheros de un medio de almacenamiento,
tambin se puede usar perfectamente para mostrar informacin que no est jerarquizada. Simplemente asumiremos que todos los items representados forman
parte del nivel inicial.
Para usarlo en nuestro proyecto es llamado de la siguiente forma, mostrado
en el archivo virtual/principal.cpp:
QTreeWidget *tree_inst = new QTreeWidget();
tree_inst->setIndentation(0);
tree_inst->setHeaderLabels(QStringList()
<< tr("Ej")<< tr("Bp") << tr("No")
<< tr("Instruccion") << tr("Arg 1")
<< tr("Arg 2") << tr("Arg 3"));
Con las instrucciones nos aseguramos un panel con una indentacin de cero no
es necesaria porque no necesitamos el espacio donde se representa el rbol y
con siete columnas de representacin de datos.
Ms tarde cuando se necesite llenar de instrucciones el panel se usar el
siguiente cdigo:
54
3.7.
Para mejorar la legibilidad del cdigo intermedio generado por los compiladores realizados por los alumnos y evitar en medida de lo posible las confusiones
que puedan acarrear que el compilador tenga una salida de programa binaria
y otra ASCII, he decidido modificar el fichero MenosC/utils.c. En este fichero
encontramos funciones tiles para el desarrollador de un compilador, ya que contiene funciones para volcar el cdigo, crear listas de argumentos no satisfechos
o tablas de smbolos entre otras muchas posibilidades. Para que el programa
se escriba de forma correcta hemos debido modificar unas pocas opciones. Las
modificaciones son:
Las posiciones de memoria pasan a escribirse de forma p: (nivel, desplazamiento)
Dejan de emplearse tabuladores para separar los argumentos entre s, pasando a ser separados por comas.
Los ficheros pasan a tener una extensin .c3d
La salida del fichero en modo binario muestra un aviso por la salida de
error desaconsejando su uso.
3.8.
Manual de ampliaciones
En esta seccin vamos a mostrar como ampliar el intrprete grfico empleando un ejemplo sencillo. Imaginmonos que queremos aadir una instruccin especfica que calcule el seno de un ngulo dado un nmero real expresado
en radianes. Para ello debemos tener en cuenta que el equipo donde pensemos
compilar el intrprete debe contar con las herramientas necesarias, mostradas
en la seccin B.1. A partir de ah, debemos modificar los ficheros siguientes:
55
Captulo 4
Manual de usuario
4.1.
Introduccin rpida
4.2.
Instalacin
57
4.3.
Primera vista
Al lanzar la aplicacin se abre la ventana principal del programa, que ser similar a la mostrada en la figura 4.1, dependiendo del tema que tenga su
escritorio configurado:
Se puede observar que est dividida en el panel de instrucciones (1), un panel
de memoria (2), panel de salida (3), panel de salida de errores (4), barra de men,
barra de herramientas y barra de estado. Antes de cargar ningn programa
los tres paneles aparecen vacos. Cada panel tiene multidud de informacin
disponible.
En el panel de instrucciones:
1 No
hay que olvidar que para ello necesitaremos instalar algunas libreras y programas
dependientes. Ver la seccin B.1.
58
59
4.4.
Carga de un programa
Para cargar un programa fuente hay que realizar una de las tres acciones
siguientes:
1. Usando la ruta de mens Fichero . Abrir.
2. Pulsar el botn abrir, indicado con la imgen de una carpeta abierta.
3. Con la combinacin de teclas Ctrl+A.
Tras lo cual se muestra un dilogo pidiendo un fichero con extensin .c3d en
el directorio actual. Si nuestro fichero tiene otra extensin debemos cambiar el
filtro de Mostrar ficheros *.c3d a Mostrar todos los ficheros *.*. Adems podemos
navegar por todo el espacio de directorios hasta encontrar el ficher necesario.
Tras elegirlo, el intrprete grfico realiza un barrido del cdigo para verificar
que no existan fallos lxicos, sintcticos o semnticos detectables en tiempo de
carga (ver seccin 4.4.2 para profundizar en los errores detectados). Solo si pasa
60
4.4.1.
Recargar un programa
4.4.2.
Puede ocurrir que el fichero fuente de cdigo de tres direcciones est mal
generado. Ocurrir especialmente si abrimos el fichero con un editor y modificamos las lneas sin meditar las consecuencias. En ese caso la carga del fichero
se interrumpir y una ventana nos avisar del problema. Los posibles errores
detectados, junto a un ejemplo y la deteccin son los siguientes:
Error lxico:
4 EADDI p:(1,-2), i:5, p:(1,1)
No existe ninguna instruccin con ese mnemotcnico. El intrprete grfico
mostrar un error lxico en la lnea 4.
4 RMULT p:(-1,-2), r:5.6, p:(1,1)
El primer parmetro es invlido dado que el primer valor de una posicin
de memoria debe ser obligatoriamente un cero o un uno.
Error sintctico:
6 EMULT i:8 i:5 p:(1,1)
61
Las instrucciones no estn separadas por comas. El intrprete grfico mostrar un error sintctico en la lnea 6.
Errores semnticos:
8 RMULT r:3.2, e:8, p:(0,0)
El segundo parmetro es incompatible con la instruccin, debiendo
ser un real o una posicin de memoria (que deber apuntar a un real).
El intrprete grfico mostrar un error semntico en la lnea 8.
12 EREAD , , p:(1, -1)
14 EWRITE , , p:(1, -1)
No deben faltar instrucciones. Los nmeros de lnea deben ser correlativos, sin saltos y empezar desde la instruccin nmero 0. El
intrprete grfico mostrar un error semntico en la lnea 13.
18 GOTOS , , e:115 #Nuestro programa tiene 60 lneas
No debe haber etiquetas que apuntes a instrucciones que no existan.
El intrprete grfico marcar como errnea la instruccin, avisando
de un error en la lnea 18 y no cargar el programa.
153 PUSHFP , ,
Por definicin solo se permiten programas de 150 lneas como mximo. El intrprete grfico marcar como errneo cualquier programa
que lo supere, avisando de un error en la lnea 150.
4.5.
4.6.
62
4.6.1.
En un programa que est siendo depurado hay algunas marcas tiles para
su depuracin:
La instruccin que ser ejecutada en la siguiente iteracin est marcada
por una flecha2 .
La ltima posicin de memoria donde se ha escrito un resultado aparecer
sombreada, como la tercera posicin de memoria en en la figura 4.2. Si
la ltima instruccin no ha escrito nada en memoria (por ejemplo, una
instruccin de salto o entrada y salida de datos) la indicacin desaparecer
hasta que no se vuelva a escribir en memoria.
La posicin del puntero a cima estar en cada momento sealada por una
flecha azul en la columna TOP. Se debe tener en cuenta que la posicin
de memoria sealada es la primera libre, no la ltima escrita.
La posicin del frame pointer est indicado en cada momento con una
flecha verde en la columna FP.
Si pasamos el puntero sobre el panel de instrucciones y lo detenemos encima de un parmetro posicin de memoria, aparecer un pequeo cuadro
2 El dibujo de la flecha puede ser ligeramente distinto dependiendo de la versin de la
librera de ejecucin Qt4 instalada en su sistema.
63
Figura 4.3: Pequeo cuadro de ayuda que indica la direccin fsica de memoria.
de ayuda indicando la direccin fsica de memoria en vez de la lgica. Evidentemente la informacin mostrada cambia cada vez vara la direccin
del frame pointer. Un ejemplo se muestra en la figura 4.3. Como puede
comprobarse la direccin fsica mostrada es la posicin tercera, resultado
de sumar al frame pointer el desplazamiento (2+1).
4.6.2.
4.6.3.
64
65
10. Aunque sean enteros, el intrprete analiza que los nmeros que escribe la
instruccion CALL en la memoria solo puedan ser usados por la instruccin
RET y por ninguna otra.
11. Aunque sean enteros, el intrprete tambin hace lo mismo con las cifras
escritas por la instruccin FPTOP y TOPFP.
Sin embargo hemos de remarcar que no se indicar ninguna condicin de overflow o underflow en la ejecucin de los clculos.
4.7.
Aunque es conveniente ejecutar antes el programa paso a paso para cerciorarse de que funciona correctamente, tambin podemos ejecutarlo de forma contnua. Un programa as ejecutado solo parar ante una instruccin FIN, ante la
excepcin sealada con el nmero 4 de la seccin anterior o ante una instruccin
marcada como breakpoint. Hay que tener en cuenta que un programa ejecutado
de forma continua no modificar la representacin del panel de memoria ni la
indicacin de instruccin prxima a ejecutarse hasta que la ejecucin finalice.
Para ejecutar el programa de este modo usaremos cualquiera de estos mtodos:
1. Navegando por el men, haremos clic en Ejecutar . Ejecutar.
2. Pulsar el botn ejecutar, indicado con la imgen de una persona corriendo
dentro de un crculo verde.
3. Con la combinacin de teclas Ctrl+E.
Aadir que se pueden mezclar los dos tipos de ejecucin (contnua y paso a paso)
en una misma traza sin ningn problema. Tambin debemos tener la precaucin
que el programa no entre un estado de bucle infinito. En ese caso deberemos
detener el proceso de nuestro intrprete grfico usando una instruccin kill -9
y abrirla de nuevo.
4.8.
Los breakpoints son muy tiles para, por ejemplo, ejecutar de forma contnua
un bucle y parar la ejecucin a la salida, pudiendo ver entonces el estado de la
memoria. Evidentemente los breakpoints no tienen sentido cuando se ejecuta el
programa paso a paso ya que el intrprete grfico detiene su ejecucin del cdigo
tras cada instruccin automticamente. Para insertar un breakpoint basta con
hacer doble clic en la instruccin que queremos que el intrprete pare antes
de ejecutarla. Para quitar el breakpoint haremos tambin doble clic sobre la
instruccin. Las instrucciones marcadas con breakpoints se distinguen por un
pequeo smbolo en la columna Bp (breakpoint) similar a una seal de trfico.
66
4.9.
4.10.
67
4.11.
4.12.
68
4.13.
Ayudas al desarrollo
69
4.14.
70
4 Para ms informacin sobre QSettings, lugar donde guarda los archivos de configuracin
y dems cuestiones mirar la seccin QSettings en Qt 4 Assistant.
Apndice A
Instrucciones de cdigo
intermedio
A continuacin se mostrarn las instrucciones de cdigo de tres direcciones
que nuestro intrprete grfico puede ejecutar. Se parte del hecho que todas las
instrucciones tienen tres argumentos, aunque algunos de ellos, incluso los tres,
pueden ser nulos. El esquema de las instrucciones sera:
Num_lnea Instruccin Arg_1, Arg_2, Arg_3
A.1.
ESUM
Instrucciones aritmticas
Suma dos enteros y deja el resultado en una posicin de memoria.
Argumento 1 y 2: Entero o puntero a una posicin de memoria
que contenga un entero.
Argumento 3: Puntero a una posicin de memoria donde dejar
el resultado.
RSUM
EDIF
72
EMULT
RMULT
EDIVI
RDIVI
RESTO
73
TRUNC
ESIG
RSIG
EASIG
Toma un entero y lo asigna a una posicin de memoria. Es un instruccin anloga a usar la instruccin ESUM para sumar un nmero
con 0, o con la instruccin EDIF, pero lo realiza de forma ms rpida
y es semnticamente ms claro.
Argumento 1: Entero o puntero a una posicin de memoria que
contenga un entero.
74
Toma un real y lo asigna a una posicin de memoria. Es un instruccin anloga a usar la instruccin RSUM para sumar un nmero con
0.0, o con la instruccin RDIF, pero lo realiza de forma ms rpida
y es semnticamente ms claro.
Argumento 1: Real o puntero a una posicin de memoria que
contenga un real.
Argumento 2: Argumento nulo.
Argumento 3: Puntero a una posicin de memoria donde dejar
el resultado.
A.2.
GOTOS
EIGUAL
Efecta el salto a la etiqueta indicada en el tercer argumento a condicin de que los dos enteros que tome en los argumentos uno y dos
sean iguales.
Argumento 1 y 2: Entero o puntero a una posicin de memoria
que contenga un entero.
Argumento 3: Etiqueta al nmero de instruccin que saltar
dado el caso.
RIGUAL
Efecta el salto a la etiqueta indicada en el tercer argumento a condicin de que los dos reales que tome en los argumentos uno y dos
sean iguales.
Argumento 1 y 2: Real o puntero a una posicin de memoria
que contenga un real.
Argumento 3: Etiqueta al nmero de instruccin que saltar
dado el caso.
75
Efecta el salto a la etiqueta indicada en el tercer argumento a condicin de que los dos enteros que tome en los argumentos uno y dos
sean distintos.
Argumento 1 y 2: Entero o puntero a una posicin de memoria
que contenga un entero.
Argumento 3: Etiqueta al nmero de instruccin que saltar
dado el caso.
RDIST
Efecta el salto a la etiqueta indicada en el tercer argumento a condicin de que los dos reales que tome en los argumentos uno y dos
sean distintos.
Argumento 1 y 2: Real o puntero a una posicin de memoria
que contenga un real.
Argumento 3: Etiqueta al nmero de instruccin que saltar
dado el caso.
EMEN
Efecta el salto a la etiqueta indicada en el tercer argumento a condicin de que el entero del primer argumento sea menor que el segundo
(Salta si Arg1 < Arg2).
Argumento 1 y 2: Entero o puntero a una posicin de memoria
que contenga un entero.
Argumento 3: Etiqueta al nmero de instruccin que saltar
dado el caso.
RMEN
Efecta el salto a la etiqueta indicada en el tercer argumento a condicin de que el real del primer argumento sea menor que el segundo
(Salta si Arg1 < Arg2).
Argumento 1 y 2: Real o puntero a una posicin de memoria
que contenga un real.
Argumento 3: Etiqueta al nmero de instruccin que saltar
dado el caso.
EMAY
Efecta el salto a la etiqueta indicada en el tercer argumento a condicin de que el entero del primer argumento sea mayor que el segundo
(Salta si Arg1 > Arg2).
Argumento 1 y 2: Entero o puntero a una posicin de memoria
que contenga un entero.
Argumento 3: Etiqueta al nmero de instruccin que saltar
dado el caso.
76
Efecta el salto a la etiqueta indicada en el tercer argumento a condicin de que el real del primer argumento sea mayor que el segundo
(Salta si Arg1 > Arg2).
Argumento 1 y 2: Real o puntero a una posicin de memoria
que contenga un real.
Argumento 3: Etiqueta al nmero de instruccin que saltar
dado el caso.
EMENEQ Efecta el salto a la etiqueta indicada en el tercer argumento a condicin de que el entero del primer argumento sea menor o igual que
el segundo (Salta si Arg1 Arg2).
Argumento 1 y 2: Entero o puntero a una posicin de memoria
que contenga un entero.
Argumento 3: Etiqueta al nmero de instruccin que saltar
dado el caso.
RMENEQ Efecta el salto a la etiqueta indicada en el tercer argumento a condicin de que el real del primer argumento sea menor o igual que el
segundo (Salta si Arg1 Arg2).
Argumento 1 y 2: Real o puntero a una posicin de memoria
que contenga un real.
Argumento 3: Etiqueta al nmero de instruccin que saltar
dado el caso.
EMAYEQ Efecta el salto a la etiqueta indicada en el tercer argumento a condicin de que el entero del primer argumento sea mayor o igual que
el segundo (Salta si Arg1 Arg2).
Argumento 1 y 2: Entero o puntero a una posicin de memoria
que contenga un entero.
Argumento 3: Etiqueta al nmero de instruccin que saltar
dado el caso.
RMAYEQ Efecta el salto a la etiqueta indicada en el tercer argumento a condicin de que el real del primer argumento sea mayor o igual que el
segundo (Salta si Arg1 Arg2).
Argumento 1 y 2: Real o puntero a una posicin de memoria
que contenga un real.
Argumento 3: Etiqueta al nmero de instruccin que saltar
dado el caso.
A.3.
EAV
77
RAV
EVA
78
A.4.
EREAD
RREAD
CREAD
79
A.5.
FIN
RET
CALL
80
EPUSH
RPUSH
EPOP
81
FPTOP
Modifica el frame pointer para que pase a apuntar a la misma posicin de memoria que el puntero a cima. Es decir:
Frame pointerPuntero a cima
Argumento 1, 2 y 3: Argumento nulo.
TOPFP
INCTOP
Modifica el puntero a cima sumndole el nmero entero que le pasemos como tercer argumento. Es decir:
Puntero a cimaPuntero a cima + Arg3
Argumento 1y 2: Argumento nulo.
Argumento 3: Entero o posicin de memoria donde hay un nmero entero.
DECTOP Modifica el puntero a cima restndole el nmero entero que le pasemos como tercer argumento. Es decir:
Puntero a cimaPuntero a cima - Arg3
Argumento 1y 2: Argumento nulo.
Argumento 3: Entero o posicin de memoria donde hay un nmero entero.
Apndice B
Software necesario en la
creacin del proyecto
B.1.
Para poder compilar el intrprete cmodamente usando el script de compilacin do es necesario tener instalado ciertos programas y libreras:
El generador de analizadores lxicos Flex.
El generador de analizadores sintcticos Bison.
El compilador GCC.
El compilador G++.
Las libreras de desarrollo de Qt4.
Todo ello es fcilmente instalable con tan solo una lnea de comandos:
sudo apt-get install flex bison gcc g++ libqt4-dev
B.2.
Bibliografa
[1] Alfred V. Aho, Monica S. Lam, Ravi Sethi, and Jeffrey D. Ullman. Compiladores. Principios, tcnicas y herramientas. Segunda edicin. Pearson
Educacin, 2008.
[2] Andrew W. Appel. Modern compiler implementation in C. Cambridge University Press, 1998.
[3] Jasmin Blanchette, Mark Summerhill, and Others. C++ GUI programming
with Qt4. Prentice Hall, 2006.
[4] J. L. Hennessy and D. A. Patterson. Computer Architecture: A Quantitative
Approach, Third edition. Morgan Kaufmann Publishers, 2002.
[5] John E. Hopcroft, Rajeev Motwani, and Jeffrey D. Ullman. Teora de autmatas, lenguajes y computacin. Pearson Addison Wesley, 2008.
[6] Dean Leffingwell. Managing software requierements, a use case approach.
Second edition. Addison-wesley, 2003.
[7] Dennis M. Ritchie and Brian W. Kernigan. The C programming language.
Second edition. Prentice Hall, 1988.
[8] Cndido Zuriaga. Proyecto fin de carrera. Facultad de Infromtica. Universidad Politcnica de Valencia: Mquina abstracta para la depuracin y
ejecucin de cdigo intermedio, 1999.
84