/* generar.c
 *
 * En este archivo se trata todo lo
 * relacionado con la generación de
 * código.
 */

#include <errno.h>
#include <malloc.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include "comun.h"
#include "generar.h"
#include "vocabula.h"
#include "textos.h"
#include "salidas.h"
#include "objetos.h"
#include "procesos.h"
#include "condacto.h"
#include "lexico.h"

FILE *fichUla,
     *fichLib;

char libFile[80];

TipoCondacto elCondacto;

void VolcarProcesos(void);
void VolcarPalabras(void);
void VolcarMensajesSistema(void);
void VolcarMensajesUsuario(void);
void VolcarDescripcionesDeObjetos(void);
void VolcarDescripcionesDeLugares(void);
void VolcarConexiones(void);
void VolcarObjetos(void);

void GenerarEnsamblador(char * nombreFuente){
  char nombreDestino[256];
  char *finNombre;
  char linea[256];
  /* Generar el nombre del fichero destino
     basado en el nombre del fichero de fuente. */
  strcpy(nombreDestino, nombreFuente);
  /*finNombre = strpbrk(nombreDestino, ".");*/
  finNombre = strrchr(nombreDestino, '.');
  if(finNombre)
    *finNombre='\0';
  strcat(nombreDestino, ".ula");
  /* Abrir el fichero de destino */
  if((fichUla=fopen(nombreDestino, "wt")) == NULL){
    printf("No se puede crear el fichero de destino.\n");
    exit(-1);
  }
  /* Copiar en el el codigo de inicio */
  /*perror("ERROR");*/
  /*printf("Memoria libre: %dbytes.\n", coreleft());*/
  strcpy(libFile, wd);
  strcat(libFile,"/pgl/inicio.pgl");
  printf("%s\n", libFile);
  if((fichLib=fopen(libFile, "rt")) != NULL){
    while(!feof(fichLib)){
	  fgets(linea,255,fichLib);
      fputs(linea,fichUla);
    }
    fclose(fichLib);
  }else perror("ERROR");
  /* Volcar los procesos */
  VolcarProcesos();
  /* Copiar en el el codigo de los condactos */
  strcpy(libFile, wd);
  strcat(libFile,"/pgl/condacto.pgl");
  printf("%s\n", libFile);
  if((fichLib=fopen(libFile, "rt")) != NULL){
    while(fgets(linea,255,fichLib)){
        fputs(linea,fichUla);
    }
    fclose(fichLib);
  }
  /* Copiar en el el codigo del interprete */
  strcpy(libFile, wd);
  strcat(libFile,"/pgl/interpre.pgl");
  printf("%s\n", libFile);
  if((fichLib=fopen(libFile, "rt")) != NULL){
    while(fgets(linea,255,fichLib)){
      fputs(linea,fichUla);
    }
    fclose(fichLib);
  }
  /* Volcar el vocabulario */
  VolcarPalabras();
  /* Volcar los mensajes */
  VolcarMensajesSistema();
  VolcarMensajesUsuario();
  VolcarDescripcionesDeObjetos();
  VolcarDescripcionesDeLugares();
  VolcarConexiones();
  /* Copiar en el el codigo de las variables */
  strcpy(libFile, wd);
  strcat(libFile,"/pgl/vriables.pgl");
  printf("%s\n", libFile);
  if((fichLib=fopen(libFile, "rt")) != NULL){
    while(fgets(linea,255,fichLib)){
      fputs(linea,fichUla);
    }
    fclose(fichLib);
  }
  /* Volcar los objetos */
  VolcarObjetos();
  /* Copiar en el el codigo de finalizacion */
  strcpy(libFile, wd);
  strcat(libFile,"/pgl/final.pgl");
  printf("%s\n", libFile);
  if((fichLib=fopen(libFile, "rt")) != NULL){
    while(fgets(linea,255,fichLib)){
      fputs(linea,fichUla);
    }
    fclose(fichLib);
  }
};

void VolcarProcesos(){

  TipoEntrada * laEntrada;
  int npro, nent, posicion;
  int * pCondacto, i;
  char verboDeLaEntrada[20], nombreDeLaEntrada[20];

  /* Primero, volcar la tabla de procesos */

  fputs(":tabla_procesos\n",fichUla);
  for(i=0;i<ultProceso+1;i++){
    if(!(i%8))
      fputs("\n dc.l", fichUla);
    fprintf(fichUla, " :pro%03d", i);
  }
  fputs("\n\n", fichUla);

  for(npro = 0; npro < ultProceso+1; npro++){
    fprintf(fichUla, ":pro%03d\n", npro);
    fputs(" dc.b 0xc0 0x00 0x00\n", fichUla);
    nent=0;
    laEntrada = SiguienteEntrada(npro, NULL);
    while(laEntrada != NULL){
      pCondacto = laEntrada->condactos;
      posicion=0;
      fprintf(fichUla, ":p%03de%03d\n", npro, nent);
      strcpy(verboDeLaEntrada, BuscarPalabraPorNumero(laEntrada->verbo,verbo));
      strcpy(nombreDeLaEntrada, BuscarPalabraPorNumero(laEntrada->nombre,nombre));
      fprintf(fichUla, "; %s %s\n", verboDeLaEntrada, nombreDeLaEntrada);
      /* generar el codigo de entrada a la entrada */
      fprintf(fichUla," jz (:bandera_en_response).l :p%03de%03d_condactos.l\n",npro, nent);
      if(laEntrada->verbo != -1)
        fprintf(fichUla, " jne (:flag033).l 0x%x :p%03de%03d.l\n",laEntrada->verbo,npro,nent+1);
      if(laEntrada->nombre != -1)
        fprintf(fichUla, " jne (:flag034).l 0x%x :p%03de%03d.l\n",laEntrada->nombre,npro,nent+1);
      /* generar codigo de condactos */
      fprintf(fichUla, ":p%03de%03d_condactos\n",npro, nent);
      while(posicion<(laEntrada->posicion)){
        elCondacto = condactos[pCondacto[posicion]];
        /* generar el codigo del condacto */
        if(!strcmp(elCondacto.nombre,"doall")){
          fprintf(fichUla, " jnz (:bandera_en_doall).l :p%03de%03d.l\n",npro,nent+1);
          fprintf(fichUla, " copy %d.l (:proceso_en_doall).l\n", npro);
        }
        if(elCondacto.tipoArg2!=nada)
          fprintf(fichUla," copy 0x%x.l (sp)\n", pCondacto[posicion+2]);
        if(elCondacto.tipoArg1!=nada)
          fprintf(fichUla," copy 0x%x.l (sp)\n", pCondacto[posicion+1]);
        switch(elCondacto.tipo){
          case condicion:
          case mixto:
            fprintf(fichUla," call :cnd_%s.l 0x%x.b (sp)\n", aMinusculas(elCondacto.nombre), 0+((elCondacto.tipoArg1!=nada)?1:0)+((elCondacto.tipoArg2!=nada)?1:0));
            fprintf(fichUla," jz (sp) :p%03de%03d.l\n", npro, nent+1);
            break;
          case accion:
            fprintf(fichUla," call :acc_%s.l %x.b ~\n", aMinusculas(elCondacto.nombre), 0+((elCondacto.tipoArg1!=nada)?1:0)+((elCondacto.tipoArg2!=nada)?1:0));
            if(!strcmp(elCondacto.nombre,"process")){
              fprintf(fichUla, " jnz (:bandera_describir_localidad).l :p%03de999.l\n", npro);
            	fprintf(fichUla, " jnz (:bandera_salir).l 0 ; por si se ha ejecutado END\n");
            }
            break;
          default:
            printf("ERROR: tipo de condacto no reconocido\n");
        }
        /* y ahora, las operaciones de limpieza del condacto según el tipo del mismo */
        switch(elCondacto.limpieza){
        	case aDescribir:
        	case aEnd:
        	case aFinDeTabla:
        		fprintf(fichUla, " return 0 ; debemos salir de todas las funciones\n");
        		break;
        	case aCondicional:
        		fprintf(fichUla, " jz (:exito).l :p%03de999.l ; debemos salir de la tabla\n", npro);
        		break;
        }
        posicion+=3;
      }
      laEntrada = SiguienteEntrada(npro, laEntrada);
      nent++;
    }
  fprintf(fichUla, ":p%03de%03d\n:p%03de999\nreturn 0\n", npro,nent,npro);
  }
}

void VolcarPalabras(){

  PPalabra palabra;
  int np, i;

  np = 0;
  palabra = SiguientePalabra(NULL);
  while(palabra != NULL){
    fprintf(fichUla, ":pal%04d\n", np);
    fprintf(fichUla, " dc.b \"%s\"\n", palabra->pal);
    for (i = strlen(palabra->pal); i < 6; i++)
      fprintf(fichUla, " dc.b 0x00.b\n");
    fprintf(fichUla, " dc.l %d.l\n", palabra->tipo);
    fprintf(fichUla, " dc.l %d.l\n", palabra->num);
    palabra = SiguientePalabra(palabra);
    np++;
  }
  fputs(":pal9999 ; ultima palabra\n",fichUla);
  fputs(" dc.b 0x00.b 0x00.b 0x00.b 0x00.b 0x00.b 0x00.b 0x00.b 0x00.b\n",fichUla);
  fputs(" dc.l 0.l\n",fichUla);
  fputs(" dc.l 0.l\n",fichUla);
}

void VolcarMensajesSistema(){
  int i;
  fputs(";;;;;;;;;;;;\n",fichUla);
  fputs("; MENSAJES ;\n",fichUla);
  fputs(";;;;;;;;;;;;\n",fichUla);
  fputs("\n",fichUla);
  fputs("; MENSAJES DEL SISTEMA\n",fichUla);
  fputs("\n",fichUla);
  fputs(":tabla_mensajes_sistema\n",fichUla);
  for(i=0;i<ultTextoSistema+1;i++){
    if(!(i%8))
      fputs("\n dc.l", fichUla);
    fprintf(fichUla, " :ms%03d", i);
  }
  fputs("\n", fichUla);
  for(i=0;i<ultTextoSistema+1;i++)
    fprintf(fichUla, ":ms%03d\n dc.b \"%s\"\n", i, txtSistema[i]);
}

void VolcarMensajesUsuario(){
  int i;

  fputs("; MENSAJES DE USUARIO\n",fichUla);
  fputs("\n",fichUla);
  fputs(":tabla_mensajes_usuario\n",fichUla);
  for(i=0;i<ultTextoMensaje+1;i++){
    if(!(i%8))
      fputs("\n dc.l", fichUla);
    fprintf(fichUla, " :mu%03d", i);
  }
  fputs("\n", fichUla);
  for(i=0;i<ultTextoMensaje+1;i++)
    fprintf(fichUla, ":mu%03d\n dc.b \"%s\"\n", i, txtMensajes[i]);
}

void VolcarDescripcionesDeObjetos(){
  int i;

  fputs("\n",fichUla);
  fputs("; DESCRIPCIONES DE OBJETOS\n",fichUla);
  fputs("\n",fichUla);
  fputs(":tabla_desc_objetos\n",fichUla);
  for(i=0;i<ultTextoObjeto+1;i++){
    if(!(i%8))
      fputs("\n dc.l", fichUla);
    fprintf(fichUla, " :do%03d", i);
  }
  fputs("\n", fichUla);
  for(i=0;i<ultTextoObjeto+1;i++)
    fprintf(fichUla, ":do%03d\n dc.b \"%s\"\n", i, txtObjetos[i]);
}

void VolcarDescripcionesDeLugares(){
  int i;

  fputs("\n",fichUla);
  fputs("; DESCRIPCIONES DE LUGARES\n",fichUla);
  fputs("\n",fichUla);
  fputs(":tabla_desc_lugares\n",fichUla);
  for(i=0;i<ultTextoLugar+1;i++){
    if(!(i%8))
      fputs("\n dc.l", fichUla);
    fprintf(fichUla, " :dl%03d", i);
  }
  fputs("\n", fichUla);
  for(i=0;i<ultTextoLugar+1;i++)
    fprintf(fichUla, ":dl%03d\n dc.b \"%s\"\n", i, txtLugares[i]);
}

void VolcarConexiones(){
  int i,j;
  fputs("\n", fichUla);
  fputs(";;;;;;;;;;;;;;\n", fichUla);
  fputs("; CONEXIONES ;\n", fichUla);
  fputs(";;;;;;;;;;;;;;\n", fichUla);
  fputs("\n", fichUla);
  fputs(":conexiones\n", fichUla);
  for(i=0;i<ultTextoLugar+1;i++)
    fprintf(fichUla, "dc.l :cx%03d\n",i);
  for(i=0;i<ultTextoLugar+1;i++){
    fprintf(fichUla, ":cx%03d\n", i);
    for(j=0;j<254;j++){
      if(Salida(i,j)!=0)
      fprintf(fichUla, "dc.l %d.l %d.l\n",j, Salida(i,j));
    }
    fprintf(fichUla, "dc.l -1.l -1.l\n");
    fputs("\n", fichUla);
  }
}

void VolcarObjetos(void){
  int i, objetosLlevados;
  fputs("\n", fichUla);
  fputs(";;;;;;;;;;;;;;;;;;;;\n", fichUla);
  fputs("; TABLA DE OBJETOS ;\n", fichUla);
  fputs(";;;;;;;;;;;;;;;;;;;;\n", fichUla);
  fputs("\n", fichUla);
  fputs(":objetos\n", fichUla);
  objetosLlevados=0;
  for(i=0;i<ultTextoObjeto+1;i++){
    fprintf(fichUla, ":obj%03d\n", i);
    fprintf(fichUla, " dc.l %d.l\n", objetos[i].nombre);
    fprintf(fichUla, " dc.l %d.l\n", objetos[i].adjetivo);
    fprintf(fichUla, " dc.l %d.l\n", objetos[i].lugar);
    fprintf(fichUla, " dc.l %d.l\n", objetos[i].peso);
    fprintf(fichUla, " dc.l %d.l\n", objetos[i].contenedor);
    fprintf(fichUla, " dc.l %d.l\n", objetos[i].prenda);
    fprintf(fichUla, " dc.l :do%03d\n", i);
    if (objetos[i].lugar==254) objetosLlevados++;
  }
  fprintf(fichUla, ":fin_de_objetos\n ds.l 1\n");
  fprintf(fichUla, ":numero_ultimo_objeto dc.l %d.l\n", ultTextoObjeto);
  fprintf(fichUla, ":numero_inicial_de_objetos_llevados dc.l %d\n", objetosLlevados);
  fprintf(fichUla, ":tamaño_buffer_ramsave dc.l %d\n",1024+(ultTextoObjeto+1)*28);
  fprintf(fichUla, ":ramsave_buffer ds.l %d\n", 1024+(ultTextoObjeto+1)*28);
  fprintf(fichUla, ":localidad_inicial\n");
  for(i=0;i<ultTextoObjeto+1;i++){
    fprintf(fichUla, " dc.l %d.l\n", objetos[i].lugar);
  }
}
