//*******************************************************************************
//ast.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/>.
//*******************************************************************************

/***********************************************************************/
/* Arbol sintactico abstracto                                          */
/***********************************************************************/

#include <stdio.h>
#include <string.h>
#include "error.h"
#include "ast.h"
#include "lexer.h"

/***********************************************************************/
/* Manejo de memoria                        			       */
/***********************************************************************/

static void *a_malloc(unsigned int size){
	void *x=(void *)malloc(size);
	if (x==NULL)
		e_fatal(NULL,"Sin memoria para construir el arbol sintactico");
	return x;
}

void a_free (void *nodo){
	if (nodo!=NULL) free(nodo);
}

/***********************************************************************/
/* Constructores						       */
/***********************************************************************/

A_NODO *a_literalCadena(char *s,E_POSICION *posicion){
	A_NODOLITERALCADENA *nodo=a_malloc(sizeof(A_NODOLITERALCADENA));
	nodo->tipo=A_LITERALCADENA;
	nodo->s=s;
	e_copiaPosicion(&nodo->posicion,posicion);
	return (A_NODO *)nodo;
}
A_NODO *a_literalEntero(int i,E_POSICION *posicion){
	A_NODOLITERALENTERO *nodo=a_malloc(sizeof(A_NODOLITERALENTERO));
	nodo->tipo=A_LITERALENTERO;
	nodo->i=i;
	e_copiaPosicion(&nodo->posicion,posicion);
	return (A_NODO *)nodo;
}
A_NODO *a_literalReal(double f,E_POSICION *posicion){
	A_NODOLITERALREAL *nodo=a_malloc(sizeof(A_NODOLITERALREAL));
	nodo->tipo=A_LITERALREAL;
	nodo->f=f;
	e_copiaPosicion(&nodo->posicion,posicion);
	return (A_NODO *)nodo;
}
A_NODO *a_id(char *id,E_POSICION *posicion){
	A_NODOID *nodo=a_malloc(sizeof(A_NODOID));
	nodo->tipo=A_ID;
	nodo->id=id;
	e_copiaPosicion(&nodo->posicion,posicion);
	return (A_NODO *)nodo;
}

A_NODO *a_nodo0(A_TIPO tipo,E_POSICION *posicion){
	A_NODO0 *nodo=a_malloc(sizeof(A_NODO0));
	nodo->tipo=tipo;
	e_copiaPosicion(&nodo->posicion,posicion);
	return (A_NODO *)nodo;
}
A_NODO *a_nodo1(A_TIPO tipo,A_NODO *h1,E_POSICION *posicion){
	A_NODO1 *nodo=a_malloc(sizeof(A_NODO1));
	nodo->tipo=tipo;
	nodo->h1=h1;
	e_copiaPosicion(&nodo->posicion,posicion);
	return (A_NODO *)nodo;
}
A_NODO *a_nodo2(A_TIPO tipo,A_NODO *h1,A_NODO *h2,E_POSICION *posicion){
	A_NODO2 *nodo=a_malloc(sizeof(A_NODO2));
	nodo->tipo=tipo;
	nodo->h1=h1;
	nodo->h2=h2;
	e_copiaPosicion(&nodo->posicion,posicion);
	return (A_NODO *)nodo;
}
A_NODO *a_nodo3(A_TIPO tipo,A_NODO *h1,A_NODO *h2,A_NODO *h3,E_POSICION *posicion){
	A_NODO3 *nodo=a_malloc(sizeof(A_NODO3));
	nodo->tipo=tipo;
	nodo->h1=h1;
	nodo->h2=h2;
	nodo->h3=h3;
	e_copiaPosicion(&nodo->posicion,posicion);
	return (A_NODO *)nodo;
}
A_NODO *a_nodo4(A_TIPO tipo,A_NODO *h1,A_NODO *h2,A_NODO *h3,A_NODO *h4,E_POSICION *posicion){
	A_NODO4 *nodo=a_malloc(sizeof(A_NODO4));
	nodo->tipo=tipo;
	nodo->h1=h1;
	nodo->h2=h2;
	nodo->h3=h3;
	nodo->h4=h4;
	e_copiaPosicion(&nodo->posicion,posicion);
	return (A_NODO *)nodo;
}
A_NODO *a_objeto(A_NODO *h1,A_NODO *h2,A_NODO *h3,A_NODO *h4,E_POSICION *posicion){
	A_NODOOBJETO *nodo=a_malloc(sizeof(A_NODOOBJETO));
	nodo->tipo=A_OBJETO;
	nodo->h1=h1;
	nodo->h2=h2;
	nodo->h3=h3;
	nodo->h4=h4;
	e_copiaPosicion(&nodo->posicion,posicion);
	return (A_NODO *)nodo;
}
A_NODO *a_miembro(A_NODO *h1,A_NODO *h2,A_NODO *h3,A_NODO *h4,E_POSICION *posicion){
	A_NODOMIEMBRO *nodo=a_malloc(sizeof(A_NODOMIEMBRO));
	nodo->tipo=A_MIEMBRO;
	nodo->h1=h1;
	nodo->h2=h2;
	nodo->h3=h3;
	nodo->h4=h4;
	e_copiaPosicion(&nodo->posicion,posicion);
	return (A_NODO *)nodo;
}
A_NODO *a_programa(A_NODO *h1,E_POSICION *posicion){
	A_NODOPROGRAMA *nodo=a_malloc(sizeof(A_NODOPROGRAMA));
	nodo->tipo=A_PROGRAMA;
	nodo->h1=h1;
	e_copiaPosicion(&nodo->posicion,posicion);
	return (A_NODO *)nodo;
}
A_NODO *a_let(A_NODO *h1,A_NODO *h2,E_POSICION *posicion){
	A_NODOLET *nodo=a_malloc(sizeof(A_NODOLET));
	nodo->tipo=A_LET;
	nodo->h1=h1;
	nodo->h2=h2;
	e_copiaPosicion(&nodo->posicion,posicion);
	return (A_NODO *)nodo;
}

#if 0
/*************************************************************************************/
/* Plantilla para patron visitante de recorrido de arbol sintactico abstracto        */
/* (versión minima)                                                                  */
/*************************************************************************************/

#include <stdio.h>
#include <string.h>
#include "error.h"
#include "ast.h"
#include "lexer.h"

static void visitar(A_NODO *nodo);

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

static void visitarPrograma(A_NODOPROGRAMA *nodo){
	if (nodo->h1!=NULL) visitar(nodo->h1);
}
static void visitarObjeto(A_NODOOBJETO *nodo){
	if (nodo->h1!=NULL) visitar(nodo->h1);
	if (nodo->h2!=NULL) visitar(nodo->h2);
	if (nodo->h3!=NULL) visitar(nodo->h3);
	if (nodo->h4!=NULL) visitar(nodo->h4);
}
static void visitarMiembro(A_NODOMIEMBRO *nodo){
	if (nodo->h1!=NULL) visitar(nodo->h1);
	if (nodo->h2!=NULL) visitar(nodo->h2);
	if (nodo->h3!=NULL) visitar(nodo->h3);
	if (nodo->h4!=NULL) visitar(nodo->h4);
}
static void visitarLet(A_NODOLET *nodo){
	if (nodo->h1!=NULL) visitar(nodo->h1);
	if (nodo->h2!=NULL) visitar(nodo->h2);
}
static void visitarNodo0(A_NODO0 *nodo){
}
static void visitarNodo1(A_NODO1 *nodo){
	if (nodo->h1!=NULL) visitar(nodo->h1);
}
static void visitarNodo2(A_NODO2 *nodo){
	if (nodo->h1!=NULL) visitar(nodo->h1);
	if (nodo->h2!=NULL) visitar(nodo->h2);
}
static void visitarNodo3(A_NODO3 *nodo){
	if (nodo->h1!=NULL) visitar(nodo->h1);
	if (nodo->h2!=NULL) visitar(nodo->h2);
	if (nodo->h3!=NULL) visitar(nodo->h3);
}
static void visitarNodo4(A_NODO4 *nodo){
	if (nodo->h1!=NULL) visitar(nodo->h1);
	if (nodo->h2!=NULL) visitar(nodo->h2);
	if (nodo->h3!=NULL) visitar(nodo->h3);
	if (nodo->h4!=NULL) visitar(nodo->h4);
}
static void visitarLiteralCadena(A_NODOLITERALCADENA *nodo){
}
static void visitarLiteralEntero(A_NODOLITERALENTERO *nodo){
}
static void visitarLiteralReal(A_NODOLITERALREAL *nodo){
}
static void visitarId(A_NODOID *nodo){
}

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

static void *tablaVisitante[A_TIPO_SIZE];

static void visitarError(A_NODO *nodo){
	e_fatal(NULL,"Error interno: Patron visitante");
}	

static void inicializarTablaVisitante(void){
int i;	
	for(i=0;i<A_TIPO_SIZE;i++) tablaVisitante[i]=&visitarError;
	tablaVisitante[A_PROGRAMA]=&visitarPrograma;	
	tablaVisitante[A_OBJETO]=&visitarObjeto;	
	tablaVisitante[A_MIEMBRO]=&visitarMiembro;
	tablaVisitante[A_LET]=&visitarLet;
	tablaVisitante[A_ERROR]=&visitarNodo0;
	tablaVisitante[A_ABSTRACT]=&visitarNodo0;
	tablaVisitante[A_SHARED]=&visitarNodo0;
	tablaVisitante[A_NATIVE]=&visitarNodo0;
	tablaVisitante[A_VAR]=&visitarNodo0;
	tablaVisitante[A_BREAK]=&visitarNodo0;
	tablaVisitante[A_CONTINUE]=&visitarNodo0;
	tablaVisitante[A_LITERALTRUE]=&visitarNodo0;
	tablaVisitante[A_LITERALFALSE]=&visitarNodo0;
	tablaVisitante[A_HIDDEN]=&visitarNodo0;
	tablaVisitante[A_RETURN]=&visitarNodo1;
	tablaVisitante[A_STATIC]=&visitarNodo1;
	tablaVisitante[A_MAS]=&visitarNodo1;
	tablaVisitante[A_MENOS]=&visitarNodo1;
	tablaVisitante[A_NOT]=&visitarNodo1;
	tablaVisitante[A_LITERALSECUENCIA]=&visitarNodo1;
	tablaVisitante[A_OR]=&visitarNodo2;
	tablaVisitante[A_AND]=&visitarNodo2;
	tablaVisitante[A_IGUAL]=&visitarNodo2;
	tablaVisitante[A_NOIGUAL]=&visitarNodo2;
	tablaVisitante[A_IDENTICO]=&visitarNodo2;
	tablaVisitante[A_NOIDENTICO]=&visitarNodo2;
	tablaVisitante[A_MAYOR]=&visitarNodo2;
	tablaVisitante[A_MENOR]=&visitarNodo2;
	tablaVisitante[A_MAYORIGUAL]=&visitarNodo2;
	tablaVisitante[A_MENORIGUAL]=&visitarNodo2;
	tablaVisitante[A_UNION]=&visitarNodo2;
	tablaVisitante[A_CONCATENACION]=&visitarNodo2;
	tablaVisitante[A_SUMA]=&visitarNodo2;
	tablaVisitante[A_RESTA]=&visitarNodo2;
	tablaVisitante[A_MULTIPLICACION]=&visitarNodo2;
	tablaVisitante[A_DIVISION]=&visitarNodo2;
	tablaVisitante[A_MODULO]=&visitarNodo2;
	tablaVisitante[A_IS]=&visitarNodo2;
	tablaVisitante[A_ISNOT]=&visitarNodo2;
	tablaVisitante[A_HAS]=&visitarNodo2;
	tablaVisitante[A_HASNOT]=&visitarNodo2;
	tablaVisitante[A_ACCESOARRAY]=&visitarNodo2;
	tablaVisitante[A_IDATOMICO]=&visitarNodo2;
	tablaVisitante[A_LITERALSECUENCIALISTA]=&visitarNodo2;
	tablaVisitante[A_MODOBJETOLISTA]=&visitarNodo2;
	tablaVisitante[A_IDLISTA]=&visitarNodo2;
	tablaVisitante[A_CUERPOOBJETOLISTA]=&visitarNodo2;
	tablaVisitante[A_DOWHILE]=&visitarNodo2;
	tablaVisitante[A_MODMIEMBROLISTA]=&visitarNodo2;
	tablaVisitante[A_WHILE]=&visitarNodo2;
	tablaVisitante[A_ARGUMENTOSLISTA]=&visitarNodo2;
	tablaVisitante[A_ASIGNACION]=&visitarNodo2;
	tablaVisitante[A_PARAMETROSLISTA]=&visitarNodo2;
	tablaVisitante[A_SECUENCIA]=&visitarNodo2;
	tablaVisitante[A_BLOQUE]=&visitarNodo2;
	tablaVisitante[A_RESEND]=&visitarNodo3;
	tablaVisitante[A_DECLARACIONLISTA]=&visitarNodo3;
	tablaVisitante[A_IF]=&visitarNodo3;
	tablaVisitante[A_ACCESOMIEMBRO]=&visitarNodo3;
	tablaVisitante[A_MIEMBROEXTERNO]=&visitarNodo3;
	tablaVisitante[A_FOR]=&visitarNodo4;	
	tablaVisitante[A_LITERALCADENA]=&visitarLiteralCadena;
	tablaVisitante[A_LITERALENTERO]=&visitarLiteralEntero;
	tablaVisitante[A_LITERALREAL]=&visitarLiteralReal;
	tablaVisitante[A_ID]=&visitarId;
}

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

	if (nodo!=NULL){
		ptr=tablaVisitante[nodo->tipo];
		if (ptr!=NULL) ptr(nodo);
	}
}

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

...
	inicializarTablaVisitante();	
	visitar(ast);
...
#endif
