Práctica 2
Tecnología de Programación
Grado en Ingeniería Informática
Objetivos
• Aprovechar los mecanismos que proporciona la herencia para maximizar la reutilización
de código.
• Diseñar jerarquías de herencia que permitan polimorfismo por inclusión.
• Utilizar algunos de los contenedores estándar de C++ y Java.
Tarea :
Elige un lenguaje orientado a objetos (C++ o Java). Realizarás toda la práctica en dicho
lenguaje.
1 Expresiones matemáticas
Para implementar la maquina virtual que va a ejecutar un nuevo lenguaje de programación se
necesita la posibilidad de almacenar expresiones matemáticas de tipo real, y realizar ciertas
operaciones con ellas. Las expresiones pueden utilizar constantes y nombres de variable (de
tipo real), y los operadores de suma, resta, multiplicación y división. Por ejemplo:
3+2×5 (1)
(3 + 2) × 5 (2)
3+2×a (3)
(3 + a) × 5 (4)
Para evaluar una expresion, es necesario conocer el valor de las variables que se utlicen el
ella, normalmente mediante una tabla de símbolos que contiene parejas (nombre,valor).
Por ejemplo, si el valor de "a" es 7:
3 + 2 × 5 = 13
(3 + 2) × 5 = 25
3 + 2 × a = 17
(3 + a) × 5 = 50
1
Una expresión matemática se puede representar mediante un arbol sintáctico de térmi-
nos, donde cada nodo no terminal representa una operación (binaria en este caso), y cada
nodo terminal es un valor constante o variable.
+ X
3 X + 5
2 5 3 2
Árbol para la expresion (1) Árbol para la expresion (2)
+ X
3 X + 5
2 a 3 a
Árbol para la expresion (3) Árbol para la expresion (4)
La evaluación de una expresión representada de esa forma puede hacerse fácilmente de
forma recursiva.
Para comprobar que un árbol es correcto, se quiere poder imprimir por pantalla la expresión
en la notación habitual, teniendo en cuenta que dependiendo de la precedencia estándar de
los operadores, pueden ser necesarios paréntesis para que la operación esté correctamente
escrita:
• Dentro de el mismo nivel de precedecia (por ejemplo varias sumas concatenadas), el
orden normal de evaluación de las operaciones es de izquerda a derecha.
• La precedencia de las operaciones la siguiente: primero se evalúan las multiplica-
ciones y divisiones, y después las sumas y las restas.
Para facilitar el interfaz con el analizador sintáctico del lenguaje, se quiere también poder
construir una expresión a partir de la notación RPN1 (notación polaca inversa) para la
expresión:
Expression e("3 2 5 * +"); // Expresion 1
Expression e("3 2 + 5 *"); // Expresion 2
Expression e("3 2 a * +"); // Expresion 3
Expression e("3 a + 5 *"); // Expresion 4
1
https://es.wikipedia.org/wiki/Notación_polaca_inversa
2
La construcción de la expresión puede hacerse mediante una pila de términos con la que se va
operando segun se leen de forma secuencial de la expresion. Por ejemplo, para la expresión
3 del caso anterior:
• ”3”: apilar una constante 3
• ”2”: apilar una constante 2
• ”a”: apilar una variable ”a”
• ”*”: desapila ”2” y ”a” y apila un nodo ”producto(2,a)”
• ”+”: desapila ”3” y ”producto(2,a)” y aplila ”suma(3,producto(2,a))”
Al terminar de leer la expresión, la cima de la pila es la raíz del árbol de la expresión.
2 Tareas
En un lenguaje orientado a objetos a tu elección (C++ o Java) lleva a cabo las siguientes
tareas:
• Define las clases necesarias para almacenar en memoria una expresión, mediante un árbol
de términos.
• Define un método que devuelva la representación textual de la expresión (to_string()
en C++ o toString() en Java), que usan los operadores de escritura en ambos
lenguajes.
• Añande a las expresiones un método eval(...), que evalue la expresión, devolviendo un
número real, y que recibe como parámetro una tabla de símbolos con los valores de las
variables. Para ello necesitarás definir y usar el tipo SymbolTab, que almacena los valores
de las variables.
• Completa el método parse(...) que recibe una cadena con la representación RPN de la
expresión y genera el árbol correspondiente. A partir de dicho método, implementa el
constructor de una expresión a partir de una cadena RPN.
Verifica el comportamiento de tu código con el programa principal suministrado en la práctica.
Entrega
Los archivos de código fuente de la práctica deberán estar organizados en dos subdirectorios
diferentes, con la siguiente estructura:
<directorio−raiz−de−la−practica>
3
\−−−− c++
\−−−− Makefile
\−−−− main . cc
\−−−− expression . h
\−−−− expression . cc
\−−−− ...
\−−−− java
\−−−− Main . java
\−−−− Expression . java
\−−−− ...
Cada subdirectorio podrá incluir otros archivos de código fuente si se considera necesario.
No deben incluir ficheros objeto (*.o) o ejecutables en el caso de C++, ni ficheros de clases
compiladas (*.class) de Java.
El programa en C++ deberá ser compilable y ejecutable con los archivos que has entregado
desde la subcarpeta c++ mediante los siguientes comandos:
make
. / main
El programa en Java deberá ser compilable y ejecutable con los archivos que has entregado
desde la subcarpeta java mediante los siguientes comandos:
javac Main . java
java Main
En caso de no compilar siguiendo estas instrucciones, el resultado de la evaluación de
la práctica será de 0. No se deben utilizar paquetes ni librerías ni ninguna infraestructura
adicional fuera de las librerías estándar de los propios lenguajes.
Todos los archivos de código fuente solicitados en este guión deberán ser comprimidos en
un único archivo zip con el siguiente nombre:
• practica2_<nip1>_<nip2>.zip (donde <nip1> y <nip2> son los NIPs de
6 dígitos los estudiantes involucrados) si el trabajo ha sido realizado por parejas. En
este caso sólo uno de los dos estudiantes deberá hacer la entrega.
• practica2_<nip>.zip (donde <nip> es el NIP de 6 dígitos del estudiante in-
volucrado) si el trabajo ha sido realizado de forma individual.
El archivo comprimido a entregar no debe contener ningún fichero aparte de los fuentes
que te pedimos: ningún fichero ejecutable o de objeto, ni ningún otro fichero adicional.
La entrega se hará en la tarea correspondiente a través de la plataforma Moodle: http::
//moodle.unizar.es.