Universidad de Costa Rica
|
|
La
primera tarea programada de
los estudiantes del curso
CI-1322 Autómatas y
Compiladores de este semestre consistió en implementar una
calculadora para expresiones aritméticas con
paréntesis:
http://anubis.ecci.ucr.ac.cr/~ci1322/2001-1/ac-ta-1.htm
Su trabajo consiste en tomar la calculadora que implementaron sus
compañeros del curso de compiladores y luego reprogramarla
usando los números super enormes que implementó en
la tarea programada
anterior. Para facililtar su
trabajo, use como base alguna de las dos soluciones que los
asistentes del curso han preparado:
http://anubis.ecci.ucr.ac.cr/~e962047/Calculadora.zip
http://anubis.ecci.ucr.ac.cr/~e972856
Después de terminar su trabajo, instale la documentación en Internet como lo hizo en las tareas anteriores, y envíe su trabajo a los asistentes del curso por correo electrónico. No se olvide de entregar en clase la documentación impresa de su trabajo.
Kenneth Mora y Tomás Rodriguez
|
// Parser.cpp (C) adolfo@di-mare.com // - Como base puede usar esta código, pero debe // eliminarle los errores de compilación. using namespace std; // ANSII #include "stdafx.h" // class CString #include "string" // class string class Pila { Pila() { _top = 0; } void P.Push(double d); double P.Pop(); double Top() { return vector[_top-1]; } private; static const Capacidad = 132; int _top; // tope de la pila double vector[Capacidad]; // vector para la pila }; // Pila inline void Pila::P.Push(double d) { vector[_top] = d; _top++; } inline double Pila::P.Pop() { _top--; return vector[_top]; } class Expression { public: void Trabaje(const CString& exp); Expression() : P() , infix("") {} private: // expr ==> term r1 void expr(); // r1 ==> + term r1 void r1(); // r1 ==> - term r1 void r2(); // void term(); // term ==> factor r2 void factor(); // r2 ==> * factor r2 void match(); // r2 ==> / factor r2 void Evaluar(); // // factor ==> ( expr ) // factor ==> num void num(); // // num ==> 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 void OnConvertir(); OnPad(); OnBorrar(); OnReset(); private; char lookahead; CString infix; // hilera inicial CString posfix; // hilera resultado Pila P; bool error; int totPuntos; // para controlar que no entre más de un punto int k_infix; // k_infix para accesar el arreglo infix int k_posfix; // puntero de la k_posfixición actual de infix }; // Expression void Expression::Trabaje(const char *exp) { /* resultado Calcula el resultado de evaluar la expresión "exp" y lo almacena en un campo de la clase. - Para recuperar el valor calculado, hay que invocar a Expression::Posfija(). */ /* requiere - "exp" no debe tener errores de sintaxis. */ infix = exp; if (infix == "") { // No se digitó ninguna expresión cout << "Debe digitar una expresión infix válida\n"; return -1; } posfix = ""; k_infix = 0; k_posfix = 0; error = false; totPuntos = 0; while (infix[infix] == ' ') { // ignorar blancos al inicio k_infix++; k_posfix++; } lookahead = infix[k_infix]; //iniciar lookahead expr(); //reconocer la expresión infix if (!error) { Evaluar(); // evaluar la expresión posfix } else { posfix = ""; } } void Expression::expr() { // expr ==> term r1 if (!error) { term(); r1(); } } void Expression::r1() { // r1 ==> + term r1 // r1 ==> - term r1 if (!error) { if (lookahead == '+') { match(); term(); posfix += '+'; r1(); } else if (lookahead == '-') { match(); term(); posfix += '-'; r1(); } } } void Expression::r2() { // r2 ==> * factor r2 // r2 ==> / factor r2 if (!error) { if (lookahead == '*') { match(); factor(); posfix += '*'; r2(); } else if (lookahead == '/') { match(); factor(); posfix += '/'; r2(); } } } void Expression::term() { // term ==> factor r2 if (!error) { factor(); r2(); } } void Expression::factor() { // factor ==> ( expr ) // factor ==> num if (!error) { if (lookahead == '(') { match(); if (k_posfix >= strlen(infix)) { // si no se ha terminado la hilera infix AfxMessageBox("ERROR: Los parétesis no coinciden"); m_CtrlInfija.SetFocus(); error = true; } else { expr(); } if (lookahead == ')' ) { match(); } else { //No se puso el paréntesis que cierra. if (!error) { AfxMessageBox("ERROR: Los parétesis no coinciden"); m_CtrlInfija.SetFocus(); error = true; } } } else if (isdigit(lookahead)) { if (posfix != "") posfix += ' '; totPuntos = 0; num(); } else { //No es paréntesis ni dígito if (!error) { AfxMessageBox("Expresión no válida"); m_CtrlInfija.SetFocus(); error = true; } } } } void Expression::match() { if (!error) { k_posfix++; if (k_posfix < strlen(infix)) { // si no se ha terminado la hilera infix lookahead = infix[++k_infix]; while (infix[k_infix] == ' ') { //ignorar blancos lookahead = infix[++k_infix]; k_posfix++; } } } } void Expression::Evaluar() { // Evalúa la expresión que estú en "this->posfix" int i = 0; double op1, op2; CString s; while (i < strlen(posfix)) { // recorrer toda la expresión if (isdigit(posfix[i])) { // si es un dígito meterlo en la pila // reconocer números de más de un dígito while ( (i < strlen(posfix)) && (posfix[i] != ' ') && (posfix[i] != '*') && (posfix[i] != '/') && (posfix[i] != '+') && (posfix[i] != '-') ) { // los dígitos de cada número se agregan en s s += posfix[i++]; } P.Push(atof(s)); // convertir s a double y meterlo en la pila s = ""; } else if (posfix[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 i++; } else if (posfix[i] == '-') { // Si es - resta op1 = P.Pop(); op2 = P.Pop(); P.Push(op2 - op1); // lo mete en la pila i++; } else if (posfix[i] == '*') { op1 = P.Pop(); op2 = P.Pop(); P.Push(op2 * op1); i++; } else if (posfix[i] == '/') { op1 = P.Pop(); op2 = P.Pop(); if (op1 != 0) { // para no dividir entre 0 P.Push(op2 / op1); } else { AfxMessageBox("ERROR: No se puede dividir entre cero"); m_CtrlInfija.SetFocus(); error = true; } i++; } if ( (i < strlen(posfix)) && (posfix[i] == ' ')) i++; } if (!error) m_fresultado = vector[0]; } void Expression::num() { /* resultado Este método sirve para reconocer números. Regla: num -> 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 */ if (!error) { if (isdigit(lookahead)) { posfix += lookahead; match(); if (k_posfix < strlen(infix)) { num(); } } else if ( (lookahead == '.') ) { //punto decimal if (totPuntos > 0) { AfxMessageBox("Expresión no válida"); m_CtrlInfija.SetFocus(); error = true; } else { totPuntos++; posfix += lookahead; match(); if (k_posfix < strlen(infix)) { num(); } } } else if (lookahead == ',') { //para aceptar comas if ( (strlen(infix)-k_posfix > 3) && isdigit(infix[ k_infix+1 ]) && isdigit(infix[ k_infix+2 ]) && isdigit(infix[ k_infix+3 ]) ) { match(); num(); } else { AfxMessageBox("ERROR: Expresión no válida"); m_CtrlInfija.SetFocus(); error = true; } } } } void Expression::OnPad() { UpdateData(true); CWnd *pWnd = GetFocus(); // Puntero al objeto que tiene el foco int m_IdWnd = pWnd->GetDlgCtrlID(); if (m_IdWnd == IDC_ABRE) { infix += '('; } else if (m_IdWnd == IDC_CIERRA) { infix += ')'; } else if (m_IdWnd == IDC_CERO) { infix += '0'; } else if (m_IdWnd == IDC_PUNTO) { infix += '.'; } else if (m_IdWnd == IDC_COMA) { infix += ','; } else if (m_IdWnd == IDC_MAS) { infix += '+'; } else if (m_IdWnd == IDC_MENOS) { infix += '-'; } else if (m_IdWnd == IDC_DIV) { infix += '/'; } else if (m_IdWnd == IDC_POR) { infix += '*'; } else if (m_IdWnd == IDC_UNO) { infix += '1'; } else if (m_IdWnd == IDC_DOS) { infix += '2'; } else if (m_IdWnd == IDC_TRES) { infix += '3'; } else if (m_IdWnd == IDC_CUATRO) { infix += '4'; } else if (m_IdWnd == IDC_CINCO) { infix += '5'; } else if (m_IdWnd == IDC_SEIS) { infix += '6'; } else if (m_IdWnd == IDC_SIETE) { infix += '7'; } else if (m_IdWnd == IDC_OCHO) { infix += '8'; } else if (m_IdWnd == IDC_NUEVE) { infix += '9'; } UpdateData(false); } void Expression::OnReset() { posfix = ""; infix = ""; m_fresultado = 0; UpdateData(false); m_CtrlInfija.SetFocus(); } void Expression::OnBorrar() { if (strlen(infix) > 0) { UpdateData(true); CString nueva = ""; int l; for (int i = 0; i < strlen(infix)-1; i++) { l = infix[i]; nueva += l; } infix = nueva; UpdateData(false); } } // EOF: Parser.cpp |
Adolfo Di Mare <adolfo@di-mare.com>.
|