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>.
|
|
|