//------------------------------------------------------------------------- // Programa: Forma normal de Greibach // // // Manera de ejecutarse: // 2.- Dar enter cuando se termine // 3.- Dar las producciones que genera cada una de las variables // por separado (con enter) // 4.- Dar enter cuando se termine // cciones) // A1 ---------> A2 A3 // A2 ---------> A3 A1 | b // A3 ---------> A1 A2 | a //------------------------------------------------------------------------- #include <stdlib.h> #include <stdio.h> #include <conio.h> #include <string.h> #include <iostream.h> class conv_fn_greibach { public: // forma normal de chomsky. void genera_chomsky(void); // Genera la forma normal de chomsky. void convierte_a_greibach(void); // Genera a la forma normal de greibach. }; class producciones { public: char *produccion; producciones *sig; producciones *ant; void lee_producciones(void); }; class gramatica { public: char *nombre; producciones *prods; gramatica *sig; gramatica *ant; void lee_variables(void); o void genera_chomsky(void); // Genera la forma normal de chomsky. void convierte_a_greibach(void); // Genera a la forma normal de greibach. void imprime(void); // Imprime resultados. }; class lista { public: void append(char *, producciones *, gramatica *); producciones *copia_lista(producciones *); gramatica *invierte(gramatica *); }; class correccion { public: char *nombre; correccion *sig; correccion *ant; void lista_a_corregir(char *); // Genera lista de variables a modificar }; gramatica *inicio; correccion *pri_correccion; void gramatica::lee_variables(void) { gramatica *act = NULL, *ant = NULL; conv_fn_greibach algoritmo; producciones produce; char *copia_nombre; if (!(act = new gramatica)) { cout << "\n No hay memoria"; return; } gotoxy(40,18); cout << "<enter> para terminar"; inicio = act; while (1) { cout << "\nNombre de variable: "; gets(copia_nombre); if (copia_nombre[0] == '\0') break; act->nombre = strdup(copia_nombre); act->prods = NULL; ant = act; if (!(act = new gramatica)) { cout << "\n No hay memoria"; break; } ant->sig = act; act->ant = ant; } inicio->ant = ant->sig = NULL; delete act; produce.lee_producciones(); algoritmo.verifica(); //<------- OK --------> algoritmo.genera_chomsky(); //<------- OK --------> //pri_correccion->nombre = "A3"; // linea temporal de prueba algoritmo.genera_chomsky(); //<------- OK --------> } void producciones::lee_producciones(void) { producciones *ant=NULL, *act = NULL; gramatica *gram = inicio; int contador; char *copia_produccion; while(gram) { if (!(act = new producciones)) { cout << "\n No hay memoria"; return; } gram->prods = act; cout << "Nombre de la variable: " << gram->nombre; contador = 1; while(1) { cout << "\nProduccion {" << contador << "}: "; gets(copia_produccion); cout << copia_produccion; if (copia_produccion[0] == '\0') break; act->produccion= strdup(copia_produccion); ant = act; if (!(act = new producciones)) { cout << "\n No hay memoria"; break; } ant->sig = act; act->ant = ant; contador++; copia_produccion = NULL; } ant->sig = NULL; delete act; gram = gram->sig; } } void gramatica::imprime(void) { gramatica *gram = inicio; producciones *prod; while(gram) { cout << "\nVariable: {" << gram->nombre << "}"; cout << "\nProducciones: "; prod = gram->prods; cout << "{"; while(prod) { cout << prod->produccion; prod = prod->sig; if (prod) cout << " | "; } cout << "}"; gram = gram->sig; } } int conv_fn_greibach::obten_numero(char *cadena) { return cadena[1]; } void correccion::lista_a_corregir(char *variable) { correccion *act = NULL, *ant = NULL; act = pri_correccion; while(act) // Colocarse al final de la lista { ant = act; act = act->sig; } if (!(act = new correccion)) { cout << "\n No hay memoria"; return; } if (!ant) //es el primero { pri_correccion = act; act->ant = NULL; } else { ant->sig = act; act->ant = ant; } act->sig = NULL; act->nombre = strdup(variable); } void conv_fn_greibach::verifica() { gramatica *gram = inicio; producciones *prod; correccion modo; conv_fn_greibach grei; int numero1, numero2; while(gram) { numero1 = grei.obten_numero(gram->nombre); numero2 = grei.obten_numero(gram->prods->produccion); if (numero1 > numero2) modo.lista_a_corregir(gram->nombre); gram = gram->sig; } } void conv_fn_greibach::genera_chomsky(void) { correccion *act_correc = NULL; gramatica *act_gram = NULL; gramatica algoritmo; act_correc = pri_correccion; while(act_correc) { act_gram = inicio; while(act_gram) { if ((strcmp(act_correc->nombre, act_gram->nombre)) == 0) { algoritmo.corrige(act_gram->prods, act_gram); break; } else act_gram = act_gram->sig; } act_correc = act_correc->sig; } } void gramatica::corrige(producciones *act_produccion, gramatica *act_gram) { conv_fn_greibach algoritmo, grei; lista operacion; gramatica gram; char *nombre, *produccion; int numero1, numero2; strncpy(nombre, act_produccion->produccion, 2); nombre[2] = '\0'; act_produccion->produccion++; //Eliminar act_produccion->produccion++; //la variable act_produccion->produccion++; //de la lista (el head) operacion.append(nombre, act_produccion, act_gram); // unir NOMBRE al inicio de ACT_PRODUCCION } void lista::append(char *variable, producciones *act_produccion, gramatica *act_gram) { gramatica *gram = inicio; producciones *prod=NULL, *primero=NULL, *ant=NULL; lista auxiliar; char *inserto, *copia, *produccion; while(gram) // localizar al inicio de las producciones { copia = strdup(gram->nombre); if ((strcmp(variable, copia)) == 0) break; gram = gram->sig; } primero = prod = auxiliar.copia_lista(gram->prods); inserto = strdup(act_produccion->produccion); while(prod) { produccion = strdup(prod->produccion); strcat(produccion, " "); strcat(produccion, inserto); strcpy(prod->produccion, produccion); ant = prod; prod = prod->sig; produccion = NULL; } ant->sig = act_produccion->sig; act_produccion->sig->ant = ant; //delete act_produccion; } producciones *lista::copia_lista(producciones *actual) { producciones *primero, *copia, *ant, *act; char *copia_produccion; if (!(copia = new producciones)) { cout << "\n No hay memoria"; return NULL; } primero = copia; act = actual; while(act) { strcpy(copia_produccion, act->produccion); copia->produccion = strdup(copia_produccion); ant = copia; if (!(copia = new producciones)) { cout << "\n No hay memoria"; break; } ant->sig = copia; copia->ant = ant; copia_produccion = NULL; act = act->sig; } ant->sig = NULL; primero->ant = NULL; delete copia; return primero; } void conv_fn_greibach::convierte_a_greibach(void) { correccion *act_correc = NULL; gramatica *gram = inicio; lista operacion; char *nueva_variable, *nombre; act_correc = pri_correccion; while(gram) { if (gram->nombre == act_correc->nombre) break; gram = gram->sig; } nueva_variable = strdup(gram->prods->produccion); // obtiene la cabeza de la lista gram->prods = gram->prods->sig; // elimina la cabeza de la lista nueva_variable++; nueva_variable++; // elimina la nueva_variable++; // primera variable a la gramatica operacion.append(nueva_variable, gram->prods, gram); // actualizar la produccion modificada gram = operacion.invierte(inicio); // genera lista inversa while(gram) { strncpy(nombre, gram->prods->produccion, 2); nombre[2] = '\0'; gram->prods->produccion++; //Eliminar gram->prods->produccion++; //la variable gram->prods->produccion++; //de la lista (el head) operacion.append(nombre, gram->prods, gram); // actualizar la produccion con la nueva variable gram = gram->sig; } } gramatica *lista::invierte(gramatica *gram) { gramatica *primero, *invertida, *ant; if (!(invertida = new gramatica)) { cout << "\n No hay memoria"; return NULL; } invertida->sig = NULL; while(gram) { invertida->nombre = gram->nombre; ant = invertida; if (!(invertida = new gramatica)) { cout << "\n No hay memoria"; return NULL; } invertida->sig = ant; ant->ant = invertida; gram = gram->sig; } delete invertida; ant->ant = NULL; return ant; } void main(void) { gramatica gram; inicio = NULL; pri_correccion = NULL; clrscr(); gram.lee_variables(); //<------- OK --------> gram.convierte_a_greibach(); gram.imprime(); //<------- OK --------> cout << "\n<----- [ FIN ] Presiona una tecla ----->"; getch(); }