Documenti di Didattica
Documenti di Professioni
Documenti di Cultura
Sign up
fcpauldiaz updates
1 contributor
**
Universidad Del Valle de Guatemala
07-ago-2015
Pablo Díaz 13203
/
ackage thomson;
mport java.util.ArrayList;
mport java.util.Collection;
mport java.util.HashMap;
mport java.util.HashSet;
mport java.util.Iterator;
mport java.util.LinkedList;
mport java.util.Map;
mport java.util.Queue;
mport java.util.TreeSet;
**
* Clase que construye un AFD a partir de un AFN
* @author Pablo
*/
ublic class AFDConstructor {
public AFDConstructor(){
this.resultadoFollowPos = new HashMap();
simulador = new Simulacion();
afd = new Automata();
}
/**
* Conversion de un automata AFN a uno AFD por el
* metodo de subconjuntos
* @param afn AFN
*/
public void conversionAFN(Automata afn){
//se crea una estructura vacia
Automata automata = new Automata();
//se utiliza una cola como la estructura para guardar los subconjuntos a analizar
Queue<HashSet<Estado>> cola = new LinkedList();
//se crea un nuevo estado inicial
Estado inicial = new Estado(0);
automata.setEstadoInicial(inicial);
automata.addEstados(inicial);
//el algoritmo empieza con el e-Closure del estado inicial del AFN
HashSet<Estado> array_inicial = simulador.eClosure(afn.getEstadoInicial());
//si el primer e-closure contiene estados de aceptacion hay que agregarlo
for (Estado aceptacion:afn.getEstadosAceptacion()){
if (array_inicial.contains(aceptacion))
automata.addEstadosAceptacion(inicial);
}
}
//si el subconjunto no existe, se crea un nuevo estado
else
{
temporal.add(resultado);
cola.add(resultado);
}
indexEstadoInicio++;
this.afd = automata;
//metodo para definir el alfabeto, se copia el del afn
definirAlfabeto(afn);
this.afd.setTipo("AFD");
System.out.println(afd);
/**
* Método general que crea el AFD de forma directa
* @param arbolSintactico
*/
public void creacionDirecta(SyntaxTree arbolSintactico){
crearEstados(arbolSintactico);
// System.out.println("******************************");
/**
* Método para verificar si el nodo puede generar epsilon
* @param expresion
* @return true si lo puede generar, false si no
*/
public boolean nullable(Nodo expresion){
//cerradura de kleene siempre retorna verdadero
if (expresion.getId().equals(AutomataMain.EPSILON))
return true;
//si contiene epsilon, es true
else if (expresion.getId().equals("*"))
return true;
//cuando es or, se verifica cada una las hojas del nodo
else if (expresion.getId().equals("|"))
return (nullable(expresion.getIzquierda()))||(nullable(expresion.getDerecha()));
//cuando es concatenacion solo si los dos nodos son true, devuelve true
else if (expresion.getId().equals("."))
return (nullable(expresion.getIzquierda()))&&(nullable(expresion.getDerecha()));
//verificar si es una hoja terminal
else if (expresion.isIsLeaf()==true)
return false;
/**
* Devuelve una lista de elementos que contiene la primera posicion del nodo
* @param nodoEval
* @return ArrayList con el resultado
*/
public TreeSet firstPos(Nodo nodoEval){
TreeSet resultado = new TreeSet();
//regresar i en caso de que sea epsilon, regresa vacio
if (nodoEval.getId().equals(AutomataMain.EPSILON))
return resultado;
//en caso de sea una hoja regresa el nodo i en el arreglo
else if (nodoEval.isIsLeaf()){
resultado.add(nodoEval);
//return resultado;
}
//en caso del OR hace la union de firstPos de los nodos hijos
else if (nodoEval.getId().equals("|")){
resultado.addAll(firstPos(nodoEval.getIzquierda()));
resultado.addAll(firstPos(nodoEval.getDerecha()));
return resultado;
}
/*en el caso de la concatenacion primero revisa el nullable y
despues realiza la union */
else if (nodoEval.getId().equals(".")){
if (nullable(nodoEval.getIzquierda())){
resultado.addAll(firstPos(nodoEval.getIzquierda()));
resultado.addAll(firstPos(nodoEval.getDerecha()));
}
else{
resultado.addAll(firstPos(nodoEval.getIzquierda()));
}
}
//en el caso de la cerradura de kleene regresa firstPos del nodo hijo izquierdo
else if (nodoEval.getId().equals("*")){
resultado.addAll(firstPos(nodoEval.getIzquierda()));
}
return resultado;
}
/**
* Metodo que retorna una lista con los elementos de la operacion
* last pos del nodo especificado
* @param nodoEval
* @return ArrayList con el resultado
*/
public ArrayList lastPos(Nodo nodoEval){
ArrayList resultado = new ArrayList();
if (nodoEval.getId().equals(AutomataMain.EPSILON))
return resultado;
else if (nodoEval.isIsLeaf()){
resultado.add(nodoEval);
return resultado;
}
else if (nodoEval.getId().equals("*")){
resultado.addAll(lastPos(nodoEval.getIzquierda()));
}
else if (nodoEval.getId().equals("|")){
resultado.addAll(lastPos(nodoEval.getIzquierda()));
resultado.addAll(lastPos(nodoEval.getDerecha()));
}
else if (nodoEval.getId().equals(".")){
if (nullable(nodoEval.getDerecha())){
resultado.addAll(lastPos(nodoEval.getIzquierda()));
resultado.addAll(lastPos(nodoEval.getDerecha()));
}
else{
resultado.addAll(lastPos(nodoEval.getDerecha()));
}
}
return resultado;
}
/**
* metodo para calcular el follow pos de cada hoja terminal del árbol
* @param nodoEval
*
*/
public void followPos(Nodo nodoEval){
//por definicion follow pos aplica para cerradura de kleene y concatenacion
//System.out.println(nodoEval.getId());
for(int j=0;j<lastPosition.size();j++){
int numero = lastPosition.get(j).getNumeroNodo();
if(resultadoFollowPos.containsKey(numero)){
//si ya la tiene, es agregar
firstPosition.addAll((Collection)resultadoFollowPos.get(numero));
//this.Sort_Set((LinkedList<Integer>)SiguientePos.get(numero));
}
}
}
//si es concatenación
else if (nodoEval.getId().equals(".")){
/*según el algoritmo el follow pos del cada posicion del last pos
del hijo izquierdo debe incluir el el first pos del hijo derecho*/
resultadoFollowPos.put(numero, firstPosition);
firstPosition = firstPos(nodoEval.getDerecha());
}
/**
* Método para numerar los nodos hoja del árbol sintáctico
* @param arbol
*/
private void generarNumeracionNodos(SyntaxTree arbol){
ArrayList<Nodo> arrayNodos = arbol.getArrayNodos();
int index = 1;
for (int i = 0 ;i<arrayNodos.size();i++){
if (arrayNodos.get(i).isIsLeaf()){
arrayNodos.get(i).setNumeroNodo(index);
index++;
}
}
// System.out.println(arrayNodos);
arbol.setArrayNodos(arrayNodos);
/**
* Método que crea el nuevo automata a partir de follow pos
* @param arbolSintactico
*/
public void crearEstados(SyntaxTree arbolSintactico){
Automata afd_result = new Automata();
afd_result.setTipo("AFD DIRECTO");
definirAlfabeto(afd_result, arbolSintactico);
//el estado inicial se crear a partir del first pos de la raiz
Estado inicial = new Estado(0);
TreeSet<Nodo> resultadoInicial = firstPos(arbolSintactico.getRoot());
afd_result.setEstadoInicial(inicial);
afd_result.addEstados(inicial);
estadosCreados.add(conversionInicial);
int indexEstadoInicio=0;
int indexEstados=1;
//La cola sirve para evaluar los nodos nuevos creados
Queue<ArrayList> cola = new LinkedList();
cola.add(conversionInicial);
while(!cola.isEmpty()){
}
if (control){
//termina el merge
// System.out.println(estadosCreados);
//System.out.println(temporal);
//si el resultado del merge no existe, se crea un nuevo estao
if (!estadosCreados.contains(temporal)){
estadoAnterior.setTransiciones(new Transicion(estadoAnterior,siguiente,le
afd_result.addEstados(siguiente);
cola.add(temporal);
estadosCreados.add(temporal);
//afd_result = quitarEstadosTrampa(afd_result);
System.out.println(afd_result);
this.afdDirecto=afd_result;
}
/**
* Método para quitar los estados de trampa de un autómata
* @param afd
* @return AFD con menos estados
*/
public Automata quitarEstadosTrampa(Automata afd){
ArrayList<Estado> estadoAQuitar = new ArrayList();
/* 1. primero se calcula los estados que son de trampa
* Se considera de trampa los estados que tienen transiciones
* con todas las letras del alfabeto hacia si mismos
*/
for (int i = 0;i<afd.getEstados().size();i++){
int verificarCantidadTransiciones = afd.getEstados().get(i).getTransiciones().siz
int contadorTransiciones=0;
for (Transicion t : (ArrayList<Transicion>)afd.getEstados().get(i).getTransicione
if (afd.getEstados().get(i)==t.getFin()){
contadorTransiciones++;
}
}
if (verificarCantidadTransiciones==contadorTransiciones&&contadorTransiciones!=0)
estadoAQuitar.add(afd.getEstados().get(i));
}
}
/*2. una vez ya sabido que estados son los de trampa
* se quitan las transiciones que van hacia ese estado
* y al final se elimina el estado del autómata
*/
for (int i = 0;i<estadoAQuitar.size();i++){
for (int j = 0;j<afd.getEstados().size();j++){
ArrayList<Transicion> arrayT = afd.getEstados().get(j).getTransiciones();
int cont =0;
// System.out.println(arrayT);
while(arrayT.size()>cont){
Transicion t = arrayT.get(cont);
//se verifican todas las transiciones que de todos los estados
//que van hacia el estado a eliminar
if (t.getFin()==estadoAQuitar.get(i)){
afd.getEstados().get(j).getTransiciones().remove(t);
cont--;
}
cont++;
}
}
//eliminar el estao al final
afd.getEstados().remove(estadoAQuitar.get(i));
}
//3. arreglar la numeración cuando se quita un estado
for (int i = 0;i<afd.getEstados().size();i++){
afd.getEstados().get(i).setId(i);
}
return afd;
}
/**
* Metodo para mostrar el hash map
* en forma de tabla
*/
private void toStringFollowPos() {
System.out.println("follow pos");
Iterator it = resultadoFollowPos.entrySet().iterator();
while (it.hasNext()) {
Map.Entry<Integer,Nodo> e = (Map.Entry)it.next();
System.out.println(e.getKey() + " " + e.getValue());
}
}
/**
* Minimizacion con algoritmo de Hopcroft de particiones
* @param AFD
* Este método no es funcional, fue el primer intento
*/
public void minimizacionAFD(Automata AFD){
ArrayList<ArrayList<Estado>> particionP = new ArrayList();
/*separar los estados entre los que perteneen al conjunto de estados de aceptacion
* y los que no, y agregar estos grupos aun conjutno de partició P
* Ojo: esto significa que la particion P al principio tiene un conjunto con
* los estados de no acpetacion y otro grupo con los de aceptacion
*/
ArrayList<Estado> estadosSinAceptacion = new ArrayList();
for (int i = 0 ; i<AFD.getEstados().size();i++){
if (!AFD.getEstadosAceptacion().contains(AFD.getEstados().get(i))){
estadosSinAceptacion.add(AFD.getEstados(i));
}
}
particionP.add(estadosSinAceptacion);
particionP.add(AFD.getEstadosAceptacion());
//System.out.println(particionP);
int key= 0;
HashMap<Estado,ArrayList<Integer>> L = new HashMap();
if (particionP.get(j).contains(t)){
Ds.add(j);
}
L.put(s, Ds);
//System.out.println(Ds + "Ds");
}
}
//System.out.println(Ds+ " Ds");
key++;
}
// System.out.println(L);
/*
tabla2 = new HashMap();
for (Estado e : grupoG) {
ArrayList<Integer> alcanzados = tablaDs.get(e);
if (tabla2.containsKey(alcanzados))
tabla2.get(alcanzados).add(e);
else {
ArrayList<Estado> tmp = new ArrayList();
tmp.add(e);
tabla2.put(alcanzados, tmp);
}
}
*/
int i = 0;
i++;
System.out.println("----");
System.out.println(particionP);
System.out.println(Ki);
System.out.println(grupoG);
System.out.println("----");
if (Ki.get(0)!=grupoG){
particionP.remove(grupoG);
System.out.println(Ki);
System.out.println("ki" + Ki.get(1));
for (int j =0 ;j<Ki.size();j++){
particionP.add((ArrayList<Estado>) Ki.get(j));
}
}
System.out.println(particionP);
}
}
/**
* Automata de prueba para comprobar la minimización
* @return Automata
*/
public Automata automataPrueba(){
Automata prueba = new Automata();
return prueba;
}
/**
* Método para definir el alfabeto del automata a partir del árbol sináctico
* @param afd
* @param arbol
*/
public void definirAlfabeto(Automata afd, SyntaxTree arbol){
HashSet alfabeto = new HashSet();
String expresion = arbol.getRoot().postOrder();
for (Character ch: expresion.toCharArray()){
if (ch!='*'&&ch!='.'&&ch!='|'&&ch!='#'&&ch!=AutomataMain.EPSILON_CHAR){
alfabeto.add(Character.toString(ch));
}
}
afd.setAlfabeto(alfabeto);
/**
* Copiar el alfabeto del AFN al AFD
* @param afn
*/
private void definirAlfabeto(Automata afn){
//System.out.println("ALFABETO");
//System.out.println(afn.getAlfabeto());
this.afd.setAlfabeto(afn.getAlfabeto());
}
/**
* Algoritmo de minimización y creación de un AFD minimizado
* @param AFD
* @return AFD minimizado
* Referencia: https://github.com/fcpauldiaz/tp-compiladores-2008/tree/master/Codigo/Gene
*/
public Automata minimizar (Automata AFD){
HashMap<Estado,ArrayList<Integer>> tablaGruposAlcanzados;
HashMap<ArrayList<Integer>, ArrayList<Estado>> tablaParticiones;
/* Conjunto de las particiones del AFD */
ArrayList<ArrayList<Estado>> particion = new ArrayList();
/*
* 1.
* Separar el AFD en dos grupos, los estados finales y
* los estados no finales.
* separar los estados entre los que perteneen al conjunto de estados de aceptacion
* y los que no, y agregar estos grupos aun conjutno de partició P
* Ojo: esto significa que la particion P al principio tiene un conjunto con
* los estados de no acpetacion y otro grupo con los de aceptacion
*/
ArrayList<Estado> estadosSinAceptacion = new ArrayList();
for (int i = 0 ; i<AFD.getEstados().size();i++){
if (!AFD.getEstadosAceptacion().contains(AFD.getEstados().get(i))){
estadosSinAceptacion.add(AFD.getEstados(i));
}
}
/*agrear los grupos a la particion inicial */
particion.add(estadosSinAceptacion);
particion.add(AFD.getEstadosAceptacion());
/*
* 2
*
* Construcción de nuevas particiones
*/
ArrayList<ArrayList<Estado>> nuevaParticion;
while (true) {
if (grupoG.size() == 1) {
/*
* Los grupos con un solo estado se agregan directamente,
* debido a que ya no pueden ser particionados.
*/
nuevaParticion.add(grupoG);
}
else {
/*
* Hallar los grupos alcanzados por
* cada estado del grupo actual.
*/
tablaGruposAlcanzados = new HashMap();
if (grupoH.contains(t))
{
gruposAlcanzados.add(pos);
tablaGruposAlcanzados.put(s, gruposAlcanzados);
}
/*
* calcular las nuevas particiones con los grupos creados
*/
tablaParticiones = new HashMap();
for (Estado e : grupoG) {
ArrayList<Integer> alcanzados = tablaGruposAlcanzados.get(e);
if (tablaParticiones.containsKey(alcanzados))
tablaParticiones.get(alcanzados).add(e);
else {
ArrayList<Estado> tmp = new ArrayList();
tmp.add(e);
tablaParticiones.put(alcanzados, tmp);
}
}
/*
* Copiar las nuevas particiones al conjunto de
* nuevas particiones.
*/
for (ArrayList<Estado> c : tablaParticiones.values())
nuevaParticion.add(c);
}
}
/*
* Si las particiones son iguales, significa que no
* hubo cambios y se debe terminar. En caso contrario,
* seguimos particionando.
*/
if (nuevaParticion.equals(particion))
break;
else
particion = nuevaParticion;
}
System.out.println("particiones");
System.out.println(particion);
/*
* Termina la minimizacion de las particiones
* Empieza la creacion del nuevo AFD Mínimo
*/
Automata afd_min = new Automata();
HashMap<Estado, Estado> gruposMin = new HashMap<>();
/**
* Si el grupo contiene un estado inicial del automata no minimizado
* entonces el estado creado anteriormente es el estado inicial
*/
if (particion.get(i).contains(AFD.getEstadoInicial())){
afd_min.setEstadoInicial(nuevo);
}
/**
* Si el grupo contiene un estado de aceptacion del AFD no minimizado
* entonces el estado creado anteriormente se agrega a los estado de
* aceptacion
*/
for (int j = 0 ;j<AFD.getEstadosAceptacion().size();j++){
if (particion.get(i).contains(AFD.getEstadosAceptacion().get(j)))
afd_min.addEstadosAceptacion(nuevo);
}
//se agrega el estado nuevo creado al AFD minimo
afd_min.addEstados(nuevo);
System.out.println(gruposMin);
/*
* Se agregan las transiciones al nuevo AFD utilizando
* la relación entre los estados de la partición y los
* estado nuevos creados
*/
for (int i=0; i < particion.size(); i++) {
/*
* Debido a que supuestamente cada estado de cada grupo
* de la particion no tienen transiciones con el mismo estado
* del mismo grupo, se puede escoger cualquier estado del grupo
* como representante del grupo, se escoge el primero porque al menos
* cada grupo tiene un estado.
*/
Estado representante = particion.get(i).get(0);
/*
* La definición formal de AFD incluye transiciones con todos los simbolos del alfabet
* lo genera estados trampa para los estados. Para hacer más eficiente la minimización
* estos se calculan y se eliminan los estados y transiciones hacia el
* estado trampa
*/
afd_min = quitarEstadosTrampa(afd_min);
this.afdMinimo=afd_min;
return afd_min;
}
/**
* Retornar el AFD creado
* @return Autoamta generado
*/
public Automata getAfd() {
return afd;
}
/**
* Retornar el AFD Directo
* @return tipo Automata
*/
public Automata getAfdDirecto(){
return this.afdDirecto;
}
/**
* Retornar el AFD Minimio
* @return tipo Autoamta
*/
public Automata getAfdMinimo() {
return afdMinimo;
}