//*******************************************************************************
//prueba.c
//*******************************************************************************
//This file is part of the Orb compiler,
//Copyright (C) 2007 Adrian Fraga Fernandez
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
// 
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
// GNU General Public License for more details.
// 
// You should have received a copy of the GNU General Public License
// along with this program.  If not, see <http://www.gnu.org/licenses/>.
//*******************************************************************************

/*************************************************************************************/
/* Crea una representacion del arbol sintactico abstracto en formato .dot (GraphViz) */
/*************************************************************************************/

#include <stdio.h>
#include <string.h>
#include "error.h"
#include "ast.h"
#include "lexer.h"
#include "parser.h"
#include "prueba.h"
#include "y.tab.h"

	/************************************************/	
	/* Funciones auxiliares comunes                 */
	/************************************************/

		/* Abrir un fichero para escritura */
	
static FILE *abrirFichero(char *raiz,char *sufijo){
FILE *fp;
char *fichero;

		/* Construir nombre de fichero de prueba */
	
	fichero=(char *)malloc(strlen(raiz)+strlen(sufijo)+1);
	if (fichero==NULL) e_fatal(NULL,"Sin memoria para realizar prueba\n");
	fichero[0]=0;
	strcat(fichero,raiz);
	strcat(fichero,sufijo);
	
		/* Abrir fichero */
	
	fp=fopen(fichero,"wt");
	if (fp==NULL) e_fatal(NULL,"Error al abrir fichero \"%s\" para escritura\n",fichero);
	
		/* Liberar memoria asociada a la construcción del */
		/* nombre del fichero */
	
	free(fichero);
	
	return fp;
}	
	
	/************************************************/	
	/* Referencias hacia delante                    */
	/************************************************/

static void visitar2(A_NODO *nodo);
static void visitar3(A_NODO *nodo);

/***********************************************************************/
/* Prueba 1: Listado de tokens del analisis lexico 	 	       */
/***********************************************************************/

	/************************************************/	
	/* Tabla de correspondencias con tipos de token */
	/************************************************/
	
static struct {	
	int token;
	char *descripcion;
} 
tablaTiposToken[]={
	{L_NEWLINE,"L_NEWLINE"},
	{L_INDENT,"L_INDENT"},
	{L_DEDENT,"L_DEDENT"},
	{L_ID,"L_ID"},
	{L_LITERALENTERO,"L_LITERALENTERO"},
	{L_LITERALREAL,"L_LITERALREAL"},
	{L_LITERALCADENA,"L_LITERALCADENA"},
	{L_ABSTRACT,"L_ABSTRACT"},
	{L_NATIVE,"L_NATIVE"},
	{L_HIDDEN,"L_HIDDEN"},
	{L_EXTERN,"L_EXTERN"},
	{L_SHARED,"L_SHARED"},
	{L_FALSE,"L_FALSE"},
	{L_VAR,"L_VAR"},
	{L_BREAK,"L_BREAK"},
	{L_CONTINUE,"L_CONTINUE"},
	{L_DO,"L_DO"},
	{L_ELSE,"L_ELSE"},
	{L_FOR,"L_FOR"},
	{L_IF,"L_IF"},
	{L_IN,"L_IN"},
	{L_LET,"L_LET"},
	{L_RESEND,"L_RESEND"},
	{L_RETURN,"L_RETURN"},
	{L_STATIC,"L_STATIC"},
	{L_THEN,"L_THEN"},
	{L_TRUE,"L_TRUE"},
	{L_WHILE,"L_WHILE"},
	{L_IS,"L_IS"},
	{L_HAS,"L_HAS"},
	{L_UNION,"L_UNION"},
	{L_MAYORIGUAL,"L_MAYORIGUAL"},
	{L_MENORIGUAL,"L_MENORIGUAL"},
	{L_IGUAL,"L_IGUAL"},
	{L_NOIGUAL,"L_NOIGUAL"},
	{L_IDENTICO,"L_IDENTICO"},
	{L_NOIDENTICO,"L_NOIDENTICO"},
	{L_AND,"L_AND"},
	{L_OR,"L_OR"},
	{L_NOT,"L_NOT"},
	{-1,NULL}
};

static char *obtenerTipoToken(int token){
int i;
	for (i=0;tablaTiposToken[i].descripcion!=NULL && tablaTiposToken[i].token!=token;i++);
	return tablaTiposToken[i].descripcion;
}

	/************/
	/* Interfaz */
	/************/

void prueba1_write(char *raiz,char *ficheroEntrada){
FILE *fp;
int token;
char *s;

		/* Abrir fichero */

	fp=abrirFichero(raiz,".txt");
	
		/* Inicializar analizador lexico */
			
	l_init(ficheroEntrada);
	
		/* Procesar fichero como una secuencia de tokens */
	
	for(;;){
		if ((token=l_lex())==0) break;
		
		fprintf(fp,"<%s>\n",l_texto());
		
		fprintf(fp,"\t\tToken: ");
		if (token<256)
			fprintf(fp,"'%c'",token);
		else if ((s=obtenerTipoToken(token))!=NULL)
			fprintf(fp,"%s",s);
		else
			fprintf(fp,"*ERROR*");
	
		switch(token){
			case L_LITERALENTERO:
				fprintf(fp," (%d)",l_token()->i);
				break;
			case L_LITERALREAL:
				fprintf(fp," (%f)",l_token()->f);
				break;
			case L_ID:
				fprintf(fp," (%s)",l_token()->id);
				break;
			case L_LITERALCADENA:
				fprintf(fp," (\"%s\")",l_token()->s);
				break;
		}
		
		fprintf(fp,"\n\t\t\t\tPosicion: %s, linea %d",
			l_token()->posicion.fichero,
			l_token()->posicion.lineaInicio);
		if (l_token()->posicion.lineaInicio!=l_token()->posicion.lineaFin)
			fprintf(fp,"-%d",l_token()->posicion.lineaFin);
		
		fprintf(fp,"\n");
	}	
	
		/* Finalizar analizador léxico */
	
	l_close();
	
		/* Cerrar fichero */
		
	fclose(fp);
}

/***********************************************************************/
/* Prueba  2: Representacion en formato texto y grafico (GraphViz)     */
/*            del arbol sintactico abstracto                           */
/***********************************************************************/

	/**********************/
	/* Ficheros de salida */
	/**********************/

static FILE *fpGrafico2;/* fichero de salida para representación gráfica */
static FILE *fpTexto2;  /* fichero de salida para representación textual */
static int altura2;	/* Control de tabulaciones para salida textual   */
	
	/***********************************************/
	/* Tabla de correspondencias con tipos de nodo */
	/***********************************************/
	
static char *tablaTiposNodo[]={
	"programa","objeto","idLista","modObjetoLista","abstract",
	"hidden","cuerpoObjetoLista","miembro","miembroExterno",
	"modMiembroLista","shared","var","argumentosLista","parametrosLista",
	"if","while","doWhile","for","break","continue","return",
	"static","resend","let","declaracionLista","secuencia","bloque",
	"asignacion","or","and","igual","noIgual","mayor","menor","mayorIgual",
	"menorIgual","identico","noIdentico","union","concatenacion",
	"suma","resta","multiplicacion","division","modulo","menos","mas",
	"not","is","isNot","has","hasNot","accesoArray","accesoMiembro",
	"idAtomico","literalSecuencia","literalSecuenciaLista",
	"literalCadena","literalEntero","literalReal","id",
	"error","native","literlTrue","literalFalse"
};	

	/************************/
	/* Funciones auxiliares */
	/************************/

		/* Indicar la posición de un nodo en el programa fuente */
		
void mostrarPosicionGrafico(void *nodo,E_POSICION *posicion){
	fprintf(fpGrafico2,"\t{rank=same\n\t\tnodo%p\n\t\tnodo%pPos\n\t}",nodo,nodo);
	fprintf(fpGrafico2,"\tnodo%p -> nodo%pPos [arrowhead=none,color=gray]\n",nodo,nodo);
	fprintf(fpGrafico2,"\tnodo%pPos [fontsize=9,color=gray,shape=box,label=\"%s\\n",nodo,posicion->fichero);
	if (posicion->lineaInicio==posicion->lineaFin)
		fprintf(fpGrafico2,"linea %d\"]\n",posicion->lineaInicio);
	else
		fprintf(fpGrafico2,"lineas %d-%d\"]\n",posicion->lineaInicio,posicion->lineaFin);
}	

void mostrarPosicionTexto(void *nodo,E_POSICION *posicion){
	fprintf(fpTexto2,"[%s:%d",posicion->fichero,posicion->lineaInicio);
	if (posicion->lineaInicio!=posicion->lineaFin)
		fprintf(fpTexto2,"-%d",posicion->lineaFin);
	fprintf(fpTexto2,"]");	
}	

		/* Función para resumir la salida de los distintos nodos */
		
void salida2Generica(void *nodo,E_POSICION *posicion,
			char *labelNodo,
			A_NODO *h1,char *labelh1,
			A_NODO *h2,char *labelh2,
			A_NODO *h3,char *labelh3,
			A_NODO *h4,char *labelh4,
			A_NODO *hLista
			){
int i;
A_TIPO tipo;

	tipo=((A_NODO *)nodo)->tipo;
				
	fprintf(fpGrafico2,"\tnodo%p [label=%s%s%s]\n",nodo,tablaTiposNodo[tipo],labelNodo==NULL?"":",",labelNodo==NULL?"":labelNodo);
	if (posicion!=NULL && hLista==NULL) mostrarPosicionGrafico(nodo,posicion);
	
	fprintf(fpTexto2,"\n");for(i=0;i<altura2;i++) fprintf(fpTexto2,"   ");
	fprintf(fpTexto2,"%s",tablaTiposNodo[tipo]);
	if (posicion!=NULL) mostrarPosicionTexto(nodo,posicion);	
	fprintf(fpTexto2,"(");
	altura2++;
	
	if (h1!=NULL){
		if (labelh1==NULL)
			fprintf(fpGrafico2,"\tnodo%p -> nodo%p\n",nodo,h1);
		else
			fprintf(fpGrafico2,"\tnodo%p -> nodo%p [label=\"%s\",fontsize=10]\n",nodo,h1,labelh1);
		visitar2(h1);
	}
	if (h2!=NULL){
		if (labelh2==NULL)
			fprintf(fpGrafico2,"\tnodo%p -> nodo%p\n",nodo,h2);
		else
			fprintf(fpGrafico2,"\tnodo%p -> nodo%p [label=\"%s\",fontsize=10]\n",nodo,h2,labelh2);
		visitar2(h2);
	}
	if (h3!=NULL){
		if (labelh3==NULL)
			fprintf(fpGrafico2,"\tnodo%p -> nodo%p\n",nodo,h3);
		else
			fprintf(fpGrafico2,"\tnodo%p -> nodo%p [label=\"%s\",fontsize=10]\n",nodo,h3,labelh3);
		visitar2(h3);
	}
	if (h4!=NULL){
		if (labelh4==NULL)
			fprintf(fpGrafico2,"\tnodo%p -> nodo%p\n",nodo,h4);
		else
			fprintf(fpGrafico2,"\tnodo%p -> nodo%p [label=\"%s\",fontsize=10]\n",nodo,h4,labelh4);
		visitar2(h4);
	}
	if (hLista!=NULL)
		fprintf(fpGrafico2,"\t{\n\trank=same\n\t\tnodo%p\n\t\tnodo%p\n\t}\n",nodo,hLista);
	
	altura2--;
	fprintf(fpTexto2,"\n");for(i=0;i<altura2;i++) fprintf(fpTexto2,"   ");
	fprintf(fpTexto2,")");
	
}

	/********************************/
	/* Metodos del patron visitante */
	/********************************/

static void visitar2NodoPrograma(A_NODOPROGRAMA *nodo){
	fprintf(fpGrafico2,"digraph programa%p{\n",nodo);
	fprintf(fpGrafico2,"\tordering=out\n");
	fprintf(fpGrafico2,"\tnodesep=.2\n");
	fprintf(fpGrafico2,"\tnode [shape=box]\n");
	salida2Generica(nodo,&nodo->posicion,
		"peripheries=2",
		nodo->h1,NULL,
		NULL,NULL,
		NULL,NULL,
		NULL,NULL,
		NULL);
	fprintf(fpGrafico2,"}\n");
}

static void visitar2NodoObjeto(A_NODOOBJETO *nodo){
	salida2Generica(nodo,&nodo->posicion,
		"peripheries=2",
		nodo->h1,"mod",
		nodo->h2,"id",
		nodo->h3,"padres",
		nodo->h4,"cuerpo",
		NULL);
}	

static void visitar2NodoMiembro(A_NODOMIEMBRO *nodo){
	salida2Generica(nodo,&nodo->posicion,
		"peripheries=2",
		nodo->h1,"mod",
		nodo->h2,"id",
		nodo->h3,"argumentos",
		nodo->h4,"cuerpo",
		NULL);
}	

static void visitar2Nodo0(A_NODO0 *nodo){
	salida2Generica(nodo,&nodo->posicion,NULL,
		NULL,NULL,
		NULL,NULL,
		NULL,NULL,
		NULL,NULL,
		NULL);
}	
static void visitar2Nodo1(A_NODO1 *nodo){
	salida2Generica(nodo,&nodo->posicion,NULL,
		nodo->h1,NULL,
		NULL,NULL,
		NULL,NULL,
		NULL,NULL,
		NULL);
}	
static void visitar2Nodo2(A_NODO2 *nodo){
	salida2Generica(nodo,&nodo->posicion,NULL,
		nodo->h1,NULL,
		nodo->h2,NULL,
		NULL,NULL,
		NULL,NULL,
		NULL);
}	
static void visitar2NodoLet(A_NODOLET *nodo){
	salida2Generica(nodo,&nodo->posicion,NULL,
		nodo->h1,NULL,
		nodo->h2,NULL,
		NULL,NULL,
		NULL,NULL,
		NULL);
}	
static void visitar2Nodo3(A_NODO3 *nodo){
	salida2Generica(nodo,&nodo->posicion,NULL,
		nodo->h1,NULL,
		nodo->h2,NULL,
		nodo->h3,NULL,
		NULL,NULL,
		NULL);
}	
static void visitar2Nodo4(A_NODO4 *nodo){
	salida2Generica(nodo,&nodo->posicion,NULL,
		nodo->h1,NULL,
		nodo->h2,NULL,
		nodo->h3,NULL,
		nodo->h4,NULL,
		NULL);
}	

static void visitar2NodoLista2(A_NODO2 *nodo){
	salida2Generica(nodo,&nodo->posicion,NULL,
		nodo->h1,NULL,
		nodo->h2,NULL,
		NULL,NULL,
		NULL,NULL,
		nodo->h2);
}	

static void visitar2NodoLista3(A_NODO3 *nodo){
	salida2Generica(nodo,&nodo->posicion,NULL,
		nodo->h1,NULL,
		nodo->h2,NULL,
		nodo->h3,NULL,
		NULL,NULL,
		nodo->h3);
}	
static void visitar2NodoLiteralCadena(A_NODOLITERALCADENA *nodo){
int i;	
	
	fprintf(fpGrafico2,"\tnodo%p [label=\"%s: \\\"%s\\\"\",style=filled,color=gray]\n",
		nodo,tablaTiposNodo[nodo->tipo],nodo->s);
	mostrarPosicionGrafico(nodo,&nodo->posicion);	
		
	fprintf(fpTexto2,"\n");for(i=0;i<altura2;i++) fprintf(fpTexto2,"   ");		
	fprintf(fpTexto2,"%s:\"%s\"",tablaTiposNodo[nodo->tipo],nodo->s);
	mostrarPosicionTexto(nodo,&nodo->posicion);	
}
static void visitar2NodoLiteralEntero(A_NODOLITERALENTERO *nodo){
int i;

	fprintf(fpGrafico2,"\tnodo%p [label=\"%s: %d\",style=filled,color=gray]\n",
		nodo,tablaTiposNodo[nodo->tipo],nodo->i);
	mostrarPosicionGrafico(nodo,&nodo->posicion);	
		
	fprintf(fpTexto2,"\n");for(i=0;i<altura2;i++) fprintf(fpTexto2,"   ");		
	fprintf(fpTexto2,"%s:%d",tablaTiposNodo[nodo->tipo],nodo->i);		
	mostrarPosicionTexto(nodo,&nodo->posicion);	
}
static void visitar2NodoLiteralReal(A_NODOLITERALREAL *nodo){
int i;	
	
	fprintf(fpGrafico2,"\tnodo%p [label=\"%s: %f\",style=filled,color=gray]\n",
		nodo,tablaTiposNodo[nodo->tipo],nodo->f);
	mostrarPosicionGrafico(nodo,&nodo->posicion);	
		
	fprintf(fpTexto2,"\n");for(i=0;i<altura2;i++) fprintf(fpTexto2,"   ");		
	fprintf(fpTexto2,"%s:%f",tablaTiposNodo[nodo->tipo],nodo->f);	
	mostrarPosicionTexto(nodo,&nodo->posicion);		
}
static void visitar2Id(A_NODOID *nodo){
int i;
	
	fprintf(fpGrafico2,"\tnodo%p [label=\"%s: %s\",style=filled,color=gray]\n",
		nodo,tablaTiposNodo[nodo->tipo],nodo->id);
	mostrarPosicionGrafico(nodo,&nodo->posicion);	
		
	fprintf(fpTexto2,"\n");for(i=0;i<altura2;i++) fprintf(fpTexto2,"   ");		
	fprintf(fpTexto2,"%s:%s",tablaTiposNodo[nodo->tipo],nodo->id);	
	mostrarPosicionTexto(nodo,&nodo->posicion);			
}
static void visitar2Error(A_NODO0 *nodo){
int i;
	
	fprintf(fpGrafico2,"\tnodo%p [label=\"%s\",style=filled,color=red]\n",nodo,tablaTiposNodo[nodo->tipo]);
	mostrarPosicionGrafico(nodo,&nodo->posicion);	
	
	fprintf(fpTexto2,"\n");for(i=0;i<altura2;i++) fprintf(fpTexto2,"   ");
	fprintf(fpTexto2,"%s",tablaTiposNodo[nodo->tipo]);
	mostrarPosicionTexto(nodo,&nodo->posicion);	
}
	/**********************************/
	/* Patrón visitante               */
	/**********************************/
	
static void *tablaVisitante2[A_TIPO_SIZE];

static void inicializarTablaVisitante2(void){
	tablaVisitante2[A_PROGRAMA]=&visitar2NodoPrograma;
	tablaVisitante2[A_OBJETO]=&visitar2NodoObjeto;
	tablaVisitante2[A_IDLISTA]=&visitar2NodoLista2;
	tablaVisitante2[A_MODOBJETOLISTA]=&visitar2NodoLista2;
	tablaVisitante2[A_ABSTRACT]=&visitar2Nodo0;
	tablaVisitante2[A_HIDDEN]=&visitar2Nodo0;
	tablaVisitante2[A_NATIVE]=&visitar2Nodo0;
	tablaVisitante2[A_CUERPOOBJETOLISTA]=&visitar2NodoLista2;
	tablaVisitante2[A_MIEMBRO]=&visitar2NodoMiembro;
	tablaVisitante2[A_MIEMBROEXTERNO]=&visitar2Nodo3;
	tablaVisitante2[A_MODMIEMBROLISTA]=&visitar2NodoLista2;
	tablaVisitante2[A_SHARED]=&visitar2Nodo0;
	tablaVisitante2[A_VAR]=&visitar2Nodo0;
	tablaVisitante2[A_ARGUMENTOSLISTA]=&visitar2NodoLista2;
	tablaVisitante2[A_PARAMETROSLISTA]=&visitar2NodoLista2;
	tablaVisitante2[A_IF]=&visitar2Nodo3;
	tablaVisitante2[A_WHILE]=&visitar2Nodo2;
	tablaVisitante2[A_DOWHILE]=&visitar2Nodo2;
	tablaVisitante2[A_FOR]=&visitar2Nodo4;
	tablaVisitante2[A_BREAK]=&visitar2Nodo0;
	tablaVisitante2[A_CONTINUE]=&visitar2Nodo0;
	tablaVisitante2[A_RETURN]=&visitar2Nodo1;
	tablaVisitante2[A_STATIC]=&visitar2Nodo1;
	tablaVisitante2[A_RESEND]=&visitar2Nodo3;
	tablaVisitante2[A_LET]=&visitar2NodoLet;
	tablaVisitante2[A_DECLARACIONLISTA]=&visitar2NodoLista3;
	tablaVisitante2[A_SECUENCIA]=&visitar2Nodo2;
	tablaVisitante2[A_BLOQUE]=&visitar2Nodo2;
	tablaVisitante2[A_ASIGNACION]=&visitar2Nodo2;
	tablaVisitante2[A_OR]=&visitar2Nodo2;
	tablaVisitante2[A_AND]=&visitar2Nodo2;
	tablaVisitante2[A_IGUAL]=&visitar2Nodo2;
	tablaVisitante2[A_NOIGUAL]=&visitar2Nodo2;
	tablaVisitante2[A_MAYOR]=&visitar2Nodo2;
	tablaVisitante2[A_MENOR]=&visitar2Nodo2;
	tablaVisitante2[A_MAYORIGUAL]=&visitar2Nodo2;
	tablaVisitante2[A_MENORIGUAL]=&visitar2Nodo2;
	tablaVisitante2[A_IDENTICO]=&visitar2Nodo2;
	tablaVisitante2[A_NOIDENTICO]=&visitar2Nodo2;
	tablaVisitante2[A_UNION]=&visitar2Nodo2;
	tablaVisitante2[A_CONCATENACION]=&visitar2Nodo2;
	tablaVisitante2[A_SUMA]=&visitar2Nodo2;
	tablaVisitante2[A_RESTA]=&visitar2Nodo2;
	tablaVisitante2[A_MULTIPLICACION]=&visitar2Nodo2;
	tablaVisitante2[A_DIVISION]=&visitar2Nodo2;
	tablaVisitante2[A_MODULO]=&visitar2Nodo2;
	tablaVisitante2[A_MENOS]=&visitar2Nodo1;
	tablaVisitante2[A_MAS]=&visitar2Nodo1;
	tablaVisitante2[A_NOT]=&visitar2Nodo1;
	tablaVisitante2[A_IS]=&visitar2Nodo2;
	tablaVisitante2[A_ISNOT]=&visitar2Nodo2;
	tablaVisitante2[A_HAS]=&visitar2Nodo2;
	tablaVisitante2[A_HASNOT]=&visitar2Nodo2;
	tablaVisitante2[A_ACCESOARRAY]=&visitar2Nodo2;
	tablaVisitante2[A_ACCESOMIEMBRO]=&visitar2Nodo3;
	tablaVisitante2[A_IDATOMICO]=&visitar2Nodo2;
	tablaVisitante2[A_LITERALSECUENCIA]=&visitar2Nodo1;
	tablaVisitante2[A_LITERALSECUENCIALISTA]=&visitar2NodoLista2;
	tablaVisitante2[A_LITERALCADENA]=&visitar2NodoLiteralCadena;
	tablaVisitante2[A_LITERALENTERO]=&visitar2NodoLiteralEntero;
	tablaVisitante2[A_LITERALREAL]=&visitar2NodoLiteralReal;
	tablaVisitante2[A_LITERALTRUE]=&visitar2Nodo0;
	tablaVisitante2[A_LITERALFALSE]=&visitar2Nodo0;
	tablaVisitante2[A_ID]=&visitar2Id;
	tablaVisitante2[A_ERROR]=&visitar2Error;
}

static void visitar2(A_NODO *nodo){
void (*ptr)(void *n);

	if (nodo!=NULL){
		if (nodo->tipo<0 || nodo->tipo>=A_TIPO_SIZE)
			e_fatal(NULL,"Se ha encontrado un nodo desconocido recorriendo el arbol\n"
				"sintactico abstracto");
	
		ptr=tablaVisitante2[nodo->tipo];
		ptr(nodo);
	}
}

	/************/
	/* Interfaz */
	/************/

void prueba2_write(char *raiz,A_NODO *ast){
int i;

		/* Abrir ficheros */

	fpGrafico2=abrirFichero(raiz,".dot");	
	fpTexto2=abrirFichero(raiz,".txt");

		/* Realizar recorrido por el árbol sintáctico abstracto */

	inicializarTablaVisitante2();	
	altura2=0;
	visitar2(ast);
	
		/* Cerrar ficheros */
	
	fclose(fpGrafico2);
	fclose(fpTexto2);
}

/***********************************************************************/
/* Prueba  3: Representacion en formato texto y grafico (GraphViz)     */
/*            de las anotaciones al arbol sintactico abstracto         */
/***********************************************************************/

	/**********************/
	/* Ficheros de salida */
	/**********************/

static FILE *fpGrafico3;/* fichero de salida para representación gráfica*/
static FILE *fpTexto3;  /* fichero de salida para representación textual*/
static int altura3;	/* Control de tabulaciones para salida textual  */
	
	/************************/
	/* Funciones auxiliares */
	/************************/
			
static void salida3Nodo(void *nodo,char *id,char *estilo){
int i;
	fprintf(fpGrafico3,"\tnodo%p [shape=ellipse,label=\"%s\"%s]\n",nodo,id==NULL?"(anonimo)":id,estilo);
	fprintf(fpTexto3,"\n");for(i=0;i<altura3;i++) fprintf(fpTexto3,"   ");
	fprintf(fpTexto3,"%s",id);
}	

static void salida3Enlace(void *nodo,void *nodo2){
	fprintf(fpGrafico3,"\tnodo%p -> nodo%p\n",nodo,nodo2);
}

static void aperturaParentesisTexto(void){
	fprintf(fpTexto3,"(");altura3++;	
}

static void cierreParentesisTexto(void){
int i;
	altura3--;
	fprintf(fpTexto3,"\n");for(i=0;i<altura3;i++) fprintf(fpTexto3,"   ");
	fprintf(fpTexto3,")");
}

static void comenzarAnotacion(void *nodo){
	fprintf(fpTexto3,"[");
	fprintf(fpGrafico3,"\tnodo%p->anot%p\n",nodo,nodo);
	fprintf(fpGrafico3,"\tanot%p [fontsize=10,shape=box,color=gray,label=\"",nodo);
}

static void finalizarAnotacion(void *nodo){
	fprintf(fpTexto3,"]");
	fprintf(fpGrafico3,"\"]\n");
	fprintf(fpGrafico3,"\t{rank=same\n\t\tnodo%p\n\t\tanot%p\n\t}\n",nodo,nodo);
}

static void anotar(char *s){
	fprintf(fpTexto3,"%s",s);
	fprintf(fpGrafico3,"%s",s);
}

static void anotarTdsAux(char *simbolo,unsigned char parametros,void *datos){
char temp[8];
	anotar(simbolo);
	if (parametros){sprintf(temp,"%d",parametros);anotar("(");anotar(temp);anotar(")");}
	anotar(" ");
}

static void anotarTds(void *tabla){
	t_forAll(tabla,&anotarTdsAux);
}

static void anotarModObjeto(A_MOD mod){
	if (mod&A_MODABSTRACT) anotar("abstract ");
	if (mod&A_MODHIDDEN) anotar("hidden ");
	if (mod&A_MODHERENCIAMULTIPLE) anotar("(herencia_multiple) ");
	if (mod&A_MODSOLAPADOS) anotar("(solapamiento) ");
	if (mod&A_MODNATIVE) anotar("native ");
}

static void anotarModMiembro(A_MOD mod){
	if (mod&A_MODABSTRACT) anotar("abstract ");
	if (mod&A_MODVAR) anotar("var ");
	if (mod&A_MODSHARED) anotar("shared ");
	if (mod&A_MODEXTERN) anotar("extern ");
	if (mod&A_MODNATIVE) anotar("native ");
}
	
	/****************************************************************/
	/* Metodos del patron visitante                   	        */
	/****************************************************************/

static void visitar3Programa(A_NODOPROGRAMA *nodo){

	fprintf(fpGrafico3,"digraph programa%p{\n",nodo);
	//fprintf(fpGrafico3,"\tordering=out\n");
	//fprintf(fpGrafico3,"\tnodesep=.2\n");

	salida3Nodo(nodo,"main",",peripheries=3");

	comenzarAnotacion(nodo);
	anotar("DECLARADOS: \\{");anotarTds(nodo->tds);anotar("\\}");
	finalizarAnotacion(nodo);
				
	aperturaParentesisTexto();		
	if (nodo->h1!=NULL) visitar3(nodo->h1);
	cierreParentesisTexto();
	
	fprintf(fpGrafico3,"}\n");
}
static void visitar3Objeto(A_NODOOBJETO *nodo){

	salida3Enlace(nodo->nodoEspNombres,nodo);
	salida3Nodo(nodo,nodo->id==NULL?"(anonimo)":nodo->id,",peripheries=2");
	
	comenzarAnotacion(nodo);
	anotar("ID: ");anotar(nodo->id==NULL?"(anonimo)":nodo->id);anotar("\\n");
	anotar("MOD: \\{");anotarModObjeto(nodo->mod);anotar("\\}\\n");
	anotar("PADRES: \\{");anotarTds(nodo->padres);anotar("\\}\\n");
	anotar("DECLARADOS: \\{");anotarTds(nodo->tds);anotar("\\}\\n");
	anotar("HEREDADOS: \\{");anotarTds(nodo->heredados);anotar("\\}\\n");	anotar("SOLAPADOS: \\{");anotarTds(nodo->solapados);anotar("\\}\\n");
	finalizarAnotacion(nodo);
	
	aperturaParentesisTexto();		
	if (nodo->h1!=NULL) visitar3(nodo->h1);
	if (nodo->h2!=NULL) visitar3(nodo->h2);
	if (nodo->h3!=NULL) visitar3(nodo->h3);
	if (nodo->h4!=NULL) visitar3(nodo->h4);
	cierreParentesisTexto();
}
static void visitar3Miembro(A_NODOMIEMBRO *nodo){
char temp[8];

	salida3Nodo(nodo,nodo->id,"");
	salida3Enlace(nodo->nodoEspNombres,nodo);

	comenzarAnotacion(nodo);
	anotar("ID: ");anotar(nodo->id);anotar("\\n");
	anotar("PARAMETROS: ");sprintf(temp,"%d",nodo->parametros);anotar(temp);anotar("\\n");
	anotar("MOD: \\{");anotarModMiembro(nodo->mod);anotar("\\}\\n");
	anotar("DECLARADOS: \\{");anotarTds(nodo->tds);anotar("\\}\\n");
	finalizarAnotacion(nodo);
	
	aperturaParentesisTexto();		
	if (nodo->h1!=NULL) visitar3(nodo->h1);
	if (nodo->h2!=NULL) visitar3(nodo->h2);
	if (nodo->h3!=NULL) visitar3(nodo->h3);
	if (nodo->h4!=NULL) visitar3(nodo->h4);
	cierreParentesisTexto();
}
static void visitar3Let(A_NODOLET *nodo){

	salida3Nodo(nodo,"LET",",style=dotted");
	salida3Enlace(nodo->nodoEspNombres,nodo);

	comenzarAnotacion(nodo);
	anotar("DECLARADOS: \\{");anotarTds(nodo->tds);anotar("\\}");
	finalizarAnotacion(nodo);
	
	aperturaParentesisTexto();		
	if (nodo->h1!=NULL) visitar3(nodo->h1);
	if (nodo->h2!=NULL) visitar3(nodo->h2);
	cierreParentesisTexto();
}
static void visitar3Nodo1(A_NODO1 *nodo){
	if (nodo->h1!=NULL) visitar3(nodo->h1);
}
static void visitar3Nodo2(A_NODO2 *nodo){
	if (nodo->h1!=NULL) visitar3(nodo->h1);
	if (nodo->h2!=NULL) visitar3(nodo->h2);
}
static void visitar3Nodo3(A_NODO3 *nodo){
	if (nodo->h1!=NULL) visitar3(nodo->h1);
	if (nodo->h2!=NULL) visitar3(nodo->h2);
	if (nodo->h3!=NULL) visitar3(nodo->h3);
}
static void visitar3Nodo4(A_NODO4 *nodo){
	if (nodo->h1!=NULL) visitar3(nodo->h1);
	if (nodo->h2!=NULL) visitar3(nodo->h2);
	if (nodo->h3!=NULL) visitar3(nodo->h3);
	if (nodo->h4!=NULL) visitar3(nodo->h4);
}

	/****************************************************************/
	/* Patrón Visitante                    	 	       		*/
	/****************************************************************/

static void *tablaVisitante3[A_TIPO_SIZE];

static void inicializarTablaVisitante3(void){
	tablaVisitante3[A_PROGRAMA]=&visitar3Programa;	
	tablaVisitante3[A_OBJETO]=&visitar3Objeto;	
	tablaVisitante3[A_MIEMBRO]=&visitar3Miembro;
	tablaVisitante3[A_LET]=&visitar3Let;
	tablaVisitante3[A_ERROR]=NULL;
	tablaVisitante3[A_ABSTRACT]=NULL;
	tablaVisitante3[A_SHARED]=NULL;
	tablaVisitante3[A_VAR]=NULL;
	tablaVisitante3[A_BREAK]=NULL;
	tablaVisitante3[A_CONTINUE]=NULL;
	tablaVisitante3[A_HIDDEN]=NULL;
	tablaVisitante3[A_RETURN]=&visitar3Nodo1;
	tablaVisitante3[A_LITERALTRUE]=NULL;
	tablaVisitante3[A_LITERALFALSE]=NULL;
	tablaVisitante3[A_STATIC]=&visitar3Nodo1;
	tablaVisitante3[A_MAS]=&visitar3Nodo1;
	tablaVisitante3[A_MENOS]=&visitar3Nodo1;
	tablaVisitante3[A_NOT]=&visitar3Nodo1;
	tablaVisitante3[A_LITERALSECUENCIA]=&visitar3Nodo1;
	tablaVisitante3[A_OR]=&visitar3Nodo2;
	tablaVisitante3[A_AND]=&visitar3Nodo2;
	tablaVisitante3[A_IGUAL]=&visitar3Nodo2;
	tablaVisitante3[A_NOIGUAL]=&visitar3Nodo2;
	tablaVisitante3[A_IDENTICO]=&visitar3Nodo2;
	tablaVisitante3[A_NOIDENTICO]=&visitar3Nodo2;
	tablaVisitante3[A_MAYOR]=&visitar3Nodo2;
	tablaVisitante3[A_MENOR]=&visitar3Nodo2;
	tablaVisitante3[A_MAYORIGUAL]=&visitar3Nodo2;
	tablaVisitante3[A_MENORIGUAL]=&visitar3Nodo2;
	tablaVisitante3[A_UNION]=&visitar3Nodo2;
	tablaVisitante3[A_CONCATENACION]=&visitar3Nodo2;
	tablaVisitante3[A_SUMA]=&visitar3Nodo2;
	tablaVisitante3[A_RESTA]=&visitar3Nodo2;
	tablaVisitante3[A_MULTIPLICACION]=&visitar3Nodo2;
	tablaVisitante3[A_DIVISION]=&visitar3Nodo2;
	tablaVisitante3[A_MODULO]=&visitar3Nodo2;
	tablaVisitante3[A_IS]=&visitar3Nodo2;
	tablaVisitante3[A_ISNOT]=&visitar3Nodo2;
	tablaVisitante3[A_HAS]=&visitar3Nodo2;
	tablaVisitante3[A_HASNOT]=&visitar3Nodo2;
	tablaVisitante3[A_ACCESOARRAY]=&visitar3Nodo2;
	tablaVisitante3[A_IDATOMICO]=&visitar3Nodo2;
	tablaVisitante3[A_LITERALSECUENCIALISTA]=&visitar3Nodo2;
	tablaVisitante3[A_MODOBJETOLISTA]=&visitar3Nodo2;
	tablaVisitante3[A_IDLISTA]=&visitar3Nodo2;
	tablaVisitante3[A_CUERPOOBJETOLISTA]=&visitar3Nodo2;
	tablaVisitante3[A_DOWHILE]=&visitar3Nodo2;
	tablaVisitante3[A_MODMIEMBROLISTA]=&visitar3Nodo2;
	tablaVisitante3[A_WHILE]=&visitar3Nodo2;
	tablaVisitante3[A_ARGUMENTOSLISTA]=&visitar3Nodo2;
	tablaVisitante3[A_ASIGNACION]=&visitar3Nodo2;
	tablaVisitante3[A_PARAMETROSLISTA]=&visitar3Nodo2;
	tablaVisitante3[A_SECUENCIA]=&visitar3Nodo2;
	tablaVisitante3[A_BLOQUE]=&visitar3Nodo2;
	tablaVisitante3[A_RESEND]=&visitar3Nodo3;
	tablaVisitante3[A_DECLARACIONLISTA]=&visitar3Nodo3;
	tablaVisitante3[A_IF]=&visitar3Nodo3;
	tablaVisitante3[A_ACCESOMIEMBRO]=&visitar3Nodo3;
	tablaVisitante3[A_MIEMBROEXTERNO]=&visitar3Nodo3;
	tablaVisitante3[A_FOR]=&visitar3Nodo4;	
	tablaVisitante3[A_LITERALCADENA]=NULL;
	tablaVisitante3[A_LITERALENTERO]=NULL;
	tablaVisitante3[A_LITERALREAL]=NULL;
	tablaVisitante3[A_ID]=NULL;
}

static void visitar3(A_NODO *nodo){
void (*ptr)(void *n);

	if (nodo!=NULL){
		if (nodo->tipo<0 || nodo->tipo>=A_TIPO_SIZE)
			e_fatal(NULL,"Se ha encontrado un nodo desconocido recorriendo el arbol\n"
				"sintactico abstracto");
	
		ptr=tablaVisitante3[nodo->tipo];
		if (ptr!=NULL) ptr(nodo);
	}
}

	/************/
	/* Interfaz */
	/************/

void prueba3_write(char *raiz,A_NODO *ast){
int i;

		/* Abrir ficheros */

	fpGrafico3=abrirFichero(raiz,".dot");	
	fpTexto3=abrirFichero(raiz,".txt");

		/* Realizar recorrido por el árbol sintáctico abstracto */

	altura3=0;
	inicializarTablaVisitante3();	
	visitar3(ast);
	
		/* Cerrar ficheros */
	
	fclose(fpGrafico3);
	fclose(fpTexto3);
}

/***********************************************************************/
/* Prueba  4: Representacion en formato texto y grafico (GraphViz)     */
/*            del arbol sintactico abstracto                           */
/***********************************************************************/

void prueba4_write(char *raiz,A_NODO *ast){
	prueba2_write(raiz,ast);
}
