Universidad de Costa Rica
Escuela de Ciencias de la
Computación e Informática
|
|
CI-1322 Autómatas y compiladores
Calculadora en C# o Java
El programa de la Figura 1 es una
calculadora que evalúa expresiones complejas, con
paréntesis. Tiene la limitación de que trabaja con
dígitos simples.
Modifique este programa para que pueda procesar expresiones con
números de varios dígitos. Además, escriba su
implementación en el lenguaje Java o en C#.
// CLC.cpp (C) adolfo@di-mare.com
/* resultado
Evalúa expresiones aritméticas simples en que los
operandos son números del 0 al 9.
*/
#if defined(__BORLANDC__) // Definida para Borland C++
#if (__BORLANDC__ <= 0x0410) // Versión v3.1 o inferior
#include <bool.h> // Define tipo bool
#endif
#endif
#include "Astring.h" // class string
#include <iostream.h>
#include <cctype>
class Pila {
public:
Pila() { _top = 0; }
void Push(T d);
long Pop();
long Top() { return _vec[_top-1]; }
private:
enum { Capacidad = 132 };
int _top; // tope de la pila
long _vec[Capacidad]; // vector para la pila
}; // Pila
inline void Pila::Push(T d) {
_vec[_top] = d;
_top++;
}
inline long Pila::Pop() {
_top--;
return _vec[_top];
}
class Compilador {
public:
Compilador(const char* exp=0) : _infijo (exp) { Trabaje(); }
void operator = (const char* exp) { _infijo = exp; Trabaje(); }
long Evaluar();
// expr ==> term r1
private: // r1 ==> + term r1
void expr(); // r1 ==> - term r1 | £
void r1(); //
void term(); // term ==> factor r2
void r2(); // r2 ==> * factor r2 | £
void factor(); // r2 ==> / factor r2
void num(); //
// factor ==> ( expr ) | num
//
void aparea(); // num ==> 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9
void Trabaje();
void error(const char * msg);
private:
char preAnalisis; // siguiente token
Astring _infijo; // hilera inicial
Astring _posfijo; // hilera resultado
size_t _cursor; // posición en _infijo
}; // Compilador
void Compilador::Trabaje() {
/* resultado
Traduce a notación posfija la expresión almancenada
en *this.
- Para evaluarla, hay que invocar a Compilador::Evaluar().
*/
/* requiere
- La expresión almacenada no debe tener errores de sintaxis.
*/
_posfijo = "";
if (_infijo == "") { // No se digitó ninguna expresión
return;
}
_cursor = 0;
while (_infijo[_cursor] == ' ') { // ignorar blancos al inicio
_cursor++;
}
preAnalisis = _infijo[_cursor]; // inicializa preAnalisis
expr(); // reconoce la expresión _infijo
}
void Compilador::error(const char * msg) {
/* resultado
Graba un mensaje de error y cancela el programa.
*/
if (msg != 0) {
if (msg[0] != 0) {
cout << "ERROR: " << msg;
}
else {
cout << "ERROR";
}
}
else {
cout << "ERROR";
}
exit(1); // cancela el programa
}
void Compilador::expr() {
// expr ==> term r1
term();
r1();
}
void Compilador::r1() {
// r1 ==> + term r1
// r1 ==> - term r1
// r1 ==> £
if (preAnalisis == '+') {
aparea();
term(); {{ _posfijo += '+'; }}
r1();
} else if (preAnalisis == '-') {
aparea();
term(); {{ _posfijo += '-'; }}
r1();
} else { } // r1 ==> £
}
void Compilador::term() {
// term ==> factor r2
factor();
r2();
}
void Compilador::r2() {
// r2 ==> * factor r2
// r2 ==> / factor r2
// r2 ==> £
if (preAnalisis == '*') {
aparea();
factor(); {{ _posfijo += '*'; }}
r2();
} else if (preAnalisis == '/') {
aparea();
factor(); {{ _posfijo += '/'; }}
r2();
} else { } // r2 ==> £
}
void Compilador::factor() {
// factor ==> ( expr )
// factor ==> num
if (preAnalisis == '(') {
aparea();
expr();
if (preAnalisis == ')' ) {
aparea();
}
} else if (isdigit(preAnalisis)) {
num();
} else { //
error("El factor no es paréntesis ni dígito");
}
}
void Compilador::aparea() {
/* resultado
Consume el terminal, y avanza al siguiente lexema.
*/
if (preAnalisis != _infijo[_cursor]) {
error(0);
}
preAnalisis = _infijo[++_cursor];
while (_infijo[_cursor] == ' ') { // ignora blancos
preAnalisis = _infijo[++_cursor];
}
}
void Compilador::num() {
// num ==> 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9
/* resultado
Este método sirve para reconocer números.
*/
if (isdigit(preAnalisis)) {
{{ _posfijo += preAnalisis; }}
aparea();
num();
}
}
long Compilador::Evaluar() {
/* resultado
Evalúa la expresión contenida en "*this"
*/
Pila P; // pila usada para evaluar _posfijo
size_t len = strlen(_posfijo.c_str());
if (len==0) {
return 0;
}
for (size_t i=0; i < len; ++i) { // recorre toda la expresión
long op1, op2;
if (isdigit(_posfijo[i])) {
// si es un dígito lo mete en la pila
P.Push( _posfijo[i] - '0');
} else if (_posfijo[i] == '+') { // Si es +, saca los operandos
op1 = P.Pop(); // de la pila y los suma
op2 = P.Pop();
P.Push(op2 + op1); // mete el resultado intermedio en la pila
} else if (_posfijo[i] == '-') { // Si es - resta
op1 = P.Pop();
op2 = P.Pop();
P.Push(op2 - op1); // lo mete en la pila
} else if (_posfijo[i] == '*') {
op1 = P.Pop();
op2 = P.Pop();
P.Push(op2 * op1);
} else if (_posfijo[i] == '/') {
op1 = P.Pop();
op2 = P.Pop();
if (op1 != 0) { // para no dividir entre 0
P.Push(op2 / op1);
} else {
error("No se puede dividir entre cero");
}
}
}
return P.Pop();
}
int main() {
char str[200];
Compilador C;
long V;
strcpy(str, "(5 * 3)");
C = str;
V = C.Evaluar();
cout << V << " == " << str << endl;
strcpy(str, "(1 + 2) * (3 - 4 - 5)");
C = str;
V = C.Evaluar();
cout << V << " == " << str << endl;
strcpy(str, "(( (((((1 + 2))))) * ((((3 - 4 - 5)))) ))" );
C = str;
V = C.Evaluar();
cout << V << " == " << str << endl;
return 0;
}
// EOF: CLC.cpp
|
Figura 1
Luego de imprimir la documentación de su programa, y
entregarla en clase, envíe su trabajo por
correo electrónico. Para esto, haga un archivo empacado
.zip
cuyo nombre sea su número de carnet. Incluya en ese archivo
lo siguiente:
- Un documento en formato
HTML
que describa el trabajo que realizó. Incluya el nombre
del compilador que usó.
- La especificación de su programa.
- El código fuente de su programa de prueba.
- Los datos de prueba para su programa.
Las cuentas de computador en la
ECCI se asignan de acuerdo
al número de carnet. Por ejemplo, si su carnet es el
número 95-28-09, para entregar su tarea usted debe crear el
archivo
952809.zip
para enviarlo por
correo electrónico.
Luego haga en su cuenta personal un subdirectorio llamado
public_html
, que es bajo el que se instalan todas sus
páginas Internet. Por ejemplo, si su solución
está en el archivo
HTML
llamado
"OLP/t3sol952809.htm
", entonces usted debe instalar esa
página en el archivo
public_html/OLP/t3sol952809.htm
de su cuenta. Luego, para acceder esa página Internet, debe
entrar a este sitio:
http://anubis.ecci.ucr.ac.cr/~e952809/OLP/t3sol952809.htm
Como todas las cuentas de estudiante son la letra "e" seguida del
número de carnet, para el estudiante de carnet "952809" la
cuenta es
"e952809
".
Para indicarle al servidor Internet a cuál cuenta entrar se
usa el caracter "~" (Alt-126), seguido del nombre de
la cuenta:
"~e952809
".
Después de la fecha de entrega del programa, puede usted
instalar en su cuenta personal su solución (no instale
antes su solución en Internet, pues en ese caso
sería usted culpable de facilitar la copia de su trabajo, y
en consecuencia se haría acreedor a la sanción
respectiva).
Entrega de Tareas
Tiempo de entrega: |
2 semanas |
Modalidad: |
Individual |
|
Soluciones
Adolfo Di Mare <adolfo@di-mare.com>.
Copyright © 2002
Derechos de autor reservados © 2002