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

/***********************************************************************/
/* Compilador                                                          */
/***********************************************************************/

#include "stdio.h"
#include "error.h"
#include "lexer.h"
#include "parser.h"
#include "sem.h"
#include "opt.h"
#include "tradJava.h"

/***********************************************************************/
/* Linea de comandos                                                   */
/***********************************************************************/
	
	/********************************/
	/* Constantes para esta version */
	/********************************/

		/* Salida por pantalla */
		
#define M_VERSION	"Alfa"
#define M_TITULO	"OrbC, version " M_VERSION " ("__DATE__")"
#define M_TAB		"   "

		/* Linea de comandos */

#define M_MOSTRAR_OPCIONES_PRUEBA	(0==1)	/* Indica si mostrar las opciones --prueba* (uso interno) en la linea de comandos */

	/**********************/
	/* Variables globales */
	/**********************/

		/* Variables a rellenar por la linea de comandos */	
	
static char *ficheroEntrada=NULL;	/* Nombre del fichero de entrada */
static char *ficheroSalida="Main.java"; /* Nombre del fichero de salida */
static char *raizPrueba1=NULL;		/* (CMD_PRUEBA1) */
static char *raizPrueba2=NULL;		/* (CMD_PRUEBA2) */
static char *raizPrueba3=NULL;		/* (CMD_PRUEBA3) */
static char *raizPrueba4=NULL;		/* (CMD_PRUEBA3) */

/***********************************************************************/
/* Linea de comandos                                                   */
/***********************************************************************/

	/********************/
	/* Tipos de comando */
	/********************/

typedef enum {
	CMD_SECCION,
	
	CMD_AYUDA, 
	CMD_JOUTPUT,
	CMD_PRUEBA1, CMD_PRUEBA2, CMD_PRUEBA3, CMD_PRUEBA4,
	
	CMD_FIN	/* Marca de fin de enumeracion */
		/* (mantener como ultimo elemento de la enumeracion) */
} OPCIONESLINEACOMANDOS;

	/**************************/
	/* Definicion de comandos */
	/**************************/

static struct 
	{	
		OPCIONESLINEACOMANDOS tipo;	
		char *prefijo;	
		char *sintaxis;
		char *descripcion;
	}
opcionesLineaComandos[]={
	/*----------------------------------------------------------------------------------*/
	{CMD_SECCION,	"<Opciones generales>",NULL,NULL},
	
	{CMD_AYUDA,	"--help",
			"--help",
			"Mostrar esta pantalla de ayuda"
			},
			
	/*----------------------------------------------------------------------------------*/
	{CMD_SECCION,	"<Traduccion a lenguaje Java>",NULL,NULL},	
	{CMD_JOUTPUT,	"-o=",
		    	"-o=<fichero>",
		    	"Especificar el fichero de salida (por defecto: 'Main.java')"
			},
	
	/*----------------------------------------------------------------------------------*/
	#if M_MOSTRAR_OPCIONES_PRUEBA
	{CMD_SECCION,	"<Pruebas>",NULL,NULL},	
	#endif
	{CMD_PRUEBA1,	"--prueba1=",
			#if M_MOSTRAR_OPCIONES_PRUEBA
				"--prueba1=<raiz>",
				"Obtener una salida en formato texto (<raiz>.txt) con un listado de\n"
				"los tokens obtenidos al aplicar el analizador lexico."
			#else
				NULL,
				NULL
			#endif
			},
						
	{CMD_PRUEBA2,	"--prueba2=",
			#if M_MOSTRAR_OPCIONES_PRUEBA
				"--prueba2=<raiz>",
				"Obtener una salida en formato texto (<raiz>.txt) y grafico (<raiz>.dot)\n"
				"del arbol sintactico tras realizar el analisis sintactico."
			#else
				NULL,
				NULL
			#endif
			},

	
	{CMD_PRUEBA3,	"--prueba3=",
			#if M_MOSTRAR_OPCIONES_PRUEBA
				"--prueba3=<raiz>",
				"Obtener una salida en formato texto (<raiz>.txt) y grafico (<raiz>.dot)\n"
				"del arbol sintactico tras realizar el analisis semantico."
			#else
				NULL,
				NULL
			#endif
			},
			
	{CMD_PRUEBA4,	"--prueba4=",
			#if M_MOSTRAR_OPCIONES_PRUEBA
				"--prueba4=<raiz>",
				"Obtener una salida en formato texto (<raiz>.txt) y grafico (<raiz>.dot)\n"
				"del arbol sintactico tras realizar la optimización de código intermedio."
			#else
				NULL,
				NULL
			#endif
			},
			
			/* Marca de fin de estructura (mantener al final de la estructura) */
	{CMD_FIN,NULL,NULL,NULL}
};

	/****************************/
	/* Mostrar mensaje de ayuda */
	/****************************/

static void mostrarAyuda(char *ficheroEjecutable){
int i,j,k;
int margen=0;
char *s;

	printf("\n"M_TITULO"\n\n");
	printf("Uso:\n\n"M_TAB"%s [opciones] ficheroEntrada\n\nOpciones:\n",ficheroEjecutable);
	
		/* Obtener longitud mas larga de cadena de sintaxis para tabular opciones */
	
	for(i=0;opcionesLineaComandos[i].tipo!=CMD_FIN;i++)
		if (opcionesLineaComandos[i].tipo!=CMD_SECCION)
			if (opcionesLineaComandos[i].sintaxis!=NULL && strlen(opcionesLineaComandos[i].sintaxis)>margen) 
				margen=strlen(opcionesLineaComandos[i].sintaxis)+1;
	
		/* Imprimir opciones */
	
	for(i=0;opcionesLineaComandos[i].tipo!=CMD_FIN;i++){
	
		if (opcionesLineaComandos[i].tipo==CMD_SECCION){
			printf("\n"M_TAB"%s\n\n",opcionesLineaComandos[i].prefijo);
			continue;
		}
	
		if (opcionesLineaComandos[i].sintaxis==NULL ||
		    opcionesLineaComandos[i].descripcion==NULL)
		    	continue;
			
			/* Imprimir sintaxis */
	
		printf(M_TAB"%s ",opcionesLineaComandos[i].sintaxis);
		
			/* Ajustar margen */
		
		j=strlen(opcionesLineaComandos[i].sintaxis)+1;
		for (;j<margen;j++) printf(" ");
	
			/* Imprimir descripcion (si hay salto de linea, ajustar margen) */
		
		s=opcionesLineaComandos[i].descripcion;	
		for(k=0;s[k]!=0;k++){
			if (s[k]!='\n') 
				printf("%c",s[k]);
			else{
				printf("\n"M_TAB);
				for(j=0;j<margen;j++) printf(" ");
			}
		}
		
		printf("\n");
	}
	printf("\n");
}
	
	/******************************/
	/* Procesar linea de comandos */
	/******************************/

static void lineaComandos(int argc,char **argv){
int contador,i,j,k;
char *token;

	if (argc<=1){
		printf("%s: --help para obtener ayuda\n",argv[0]);
		exit(1);
	}
	
	for(contador=1;contador<argc;contador++){
		for(i=0;opcionesLineaComandos[i].tipo!=CMD_FIN;i++)
			if (opcionesLineaComandos[i].tipo!=CMD_SECCION)
				if (!strncmp(opcionesLineaComandos[i].prefijo,
					argv[contador],
					strlen(opcionesLineaComandos[i].prefijo)))
						break;
		
		if (opcionesLineaComandos[i].tipo==CMD_FIN)
			if (contador==argc-1){
				ficheroEntrada=argv[contador];
				return;
			}
			else
				e_fatal(NULL,"Comando \"%s\" desconocido",argv[contador]);
		
		token=argv[contador]+strlen(opcionesLineaComandos[i].prefijo);
		switch(opcionesLineaComandos[i].tipo){
			case CMD_PRUEBA1:
				raizPrueba1=token;
				break;
			case CMD_PRUEBA2:
				raizPrueba2=token;
				break;
			case CMD_PRUEBA3:
				raizPrueba3=token;
				break;
			case CMD_PRUEBA4:
				raizPrueba4=token;
				break;
			case CMD_JOUTPUT:
				ficheroSalida=token;
				break;
			case CMD_AYUDA:
				mostrarAyuda(argv[0]);
				exit(0);
				break;
		}
		
	}
	
	if (ficheroEntrada==NULL) 
		e_fatal(NULL,"No se ha especificado un fichero de entrada");	
		
}
	
/***********************************************************************/
/* Main                                                                */
/***********************************************************************/

int main(int argc,char **argv){
FILE *fp;
A_NODO *ast;

		/******************/
		/* Inicializacion */
		/******************/

	e_init(stderr);				/* Control de errores */	
	lineaComandos(argc,argv);		/* Linea de comandos */

		/***********/
		/* Pruebas */
		/***********/
	
	if (raizPrueba1!=NULL){			/* CMD_PRUEBA1 */
		prueba1_write(raizPrueba1,ficheroEntrada);	
		e_close();
		return 0;
	}
	else if (raizPrueba2!=NULL){		/* CMD_PRUEBA2 */
		ast=p_parse(ficheroEntrada);
		prueba2_write(raizPrueba2,ast);	
		e_close();
		return 0;
	}
	else if (raizPrueba3!=NULL){		/* CMD_PRUEBA3 */
		ast=p_parse(ficheroEntrada);
		if (e_errores()==0) {ast=s_sem(ast);prueba3_write(raizPrueba3,ast);}
		e_close();
		return 0;
	}
	else if (raizPrueba4!=NULL){		/* CMD_PRUEBA4 */
		ast=p_parse(ficheroEntrada);
		if (e_errores()==0) ast=s_sem(ast);
		if (e_errores()==0) {ast=s_opt(ast);prueba4_write(raizPrueba4,ast);}
		e_close();
		return 0;
	}
		
		/**************/
		/* Traduccion */
		/**************/

	ast=p_parse(ficheroEntrada);		/* Analisis sintactico */
	if (e_errores()==0) ast=s_sem(ast);	/* Analisis semántico */
	if (e_errores()==0) ast=s_opt(ast);	/* Optimización de código intermedio */
	if (e_errores()==0){
		j_trad(ast,ficheroSalida);	/* Traduccion */
		if (e_errores()!=0) remove(ficheroSalida);
	}
	
		/*******/
		/* Fin */
		/*******/
	
	e_close();
	return e_errores()!=0;
}
