
/* sintacti.c */

#include "lexico.h"
#include "sintacti.h"
#include "errores.h"
#include "vocabula.h"
#include "salidas.h"
#include "textos.h"
#include "objetos.h"
#include "comun.h"
#include "condacto.h"
#include "procesos.h"
#include <string.h>
#include <stdio.h>
#include <stdlib.h>

TipoPalabra palabra;
TipoObjeto objeto;
TipoEntrada *entrada;
TipoCondacto condacto;

/*int ultConexion=-1;*/
/*int ultProceso=2;*/

/* cabeceras de funciones del analizador sintactico */

void anFichPaw(void);
void anSeccionCtl(void);
void anSeccionVoc(void);
void anSeccionOtx(void);
void anSeccionLtx(void);
void anSeccionCon(void);
void anSeccionStx(void);
void anSeccionMtx(void);
void anSeccionObj(void);
void anProcesos(void);

void anEntradasVoc(void);
void anEntradaVoc(void);
void anTextosObjetos(void);
void anTextosLugares(void);
void anConexiones(void);
void anSalidas(int);
void anTextosSistema(void);
void anTextosMensajes(void);
void anDefinicionesObjetos(void);
void anDefObjeto(int);
void anLugar(TipoObjeto*);
void anAdjetivo(TipoObjeto*);
void anProceso(int);
void anEntradas(int);
void anEntrada(int);
void anVerbo(TipoEntrada*);
void anNombre(TipoEntrada*);
void anCondactos(int);
void anCondacto(int);
void anMasCondactos(int);
void anArgs(int*a1,int*a2);
void anSiNo(int*);

int Val(const char *numero) {
  int res;
  sscanf(numero,"%d",&res);
  return res;
}

/* Analizador sintactico */

void checkArg(int*a1,tipoArg tipo){
  switch(tipo){
    case nada:
      break;
    case value:
    case flagno:
      if(simbolo==pNumero){
        *a1=Val(lexema);
        if((*a1>255)||(*a1<0))
          error(errSem,15);
      }
      casarLex(pNumero);
      break;
    case percent:
      if(simbolo==pNumero){
        *a1=Val(lexema);
        if((*a1>99)||(*a1<1))
          error(errSem,16);
      }
      casarLex(pNumero);
      break;
    case objno:
      if(simbolo==pNumero){
        *a1=Val(lexema);
        if((*a1>ultTextoObjeto)||(*a1<0))
          error(errSem,17);
      }
      casarLex(pNumero);
      break;
    case mesno:
      if(simbolo==pNumero){
        *a1=Val(lexema);
        if((*a1>ultTextoMensaje)||(*a1<0))
          error(errSem,18);
      }
      casarLex(pNumero);
      break;
    case smesno:
      if(simbolo==pNumero){
        *a1=Val(lexema);
        if((*a1>ultTextoSistema)||(*a1<0))
          error(errSem,19);
      }
      casarLex(pNumero);
      break;
    case prono:
      if(simbolo==pNumero){
        *a1=Val(lexema);
        if((*a1>255)||(*a1<0))
          error(errSem,20);
        if(*a1>ultProceso)ultProceso=*a1;
      }
      casarLex(pNumero);
      break;
    case locno:
      if(simbolo==pNumero){
        *a1=Val(lexema);
        if((*a1>ultTextoLugar)||(*a1<0))
          error(errSem,21);
      }
      casarLex(pNumero);
      break;
    case locno_:
      if(simbolo==pNumero){
        *a1=Val(lexema);
        if(((*a1>ultTextoLugar)||(*a1<0))&&!((*a1>251)&&(*a1<=255)))
          error(errSem,21);
        if (*a1==255)*a1=-2;
        casarLex(pNumero);
      }
      else if(simbolo==pSubrayado){
        *a1=-1;
        casarLex(pSubrayado);
      }
      else if(simbolo==pPalabra){
        if(!strcmp(lexema,"WORN"))
          *a1=253;
        else if(!strcmp(lexema,"CARRIED"))
          *a1=254;
        else if(!strcmp(lexema,"HERE"))
          *a1=-2;
        else
          error(errSem,21);
        casarLex(pPalabra);
      }
      else
        casarLex(pNumero);
      break;
    case adjective:
      if(simbolo==pPalabra){
        if(!BuscarPalabra(lexema,&palabra)||(palabra.tipo!=adjetivo))
          error(errSem, 10);
        *a1=palabra.num;
        casarLex(pPalabra);
      }
      else if(simbolo==pSubrayado){
        *a1=-1;
        casarLex(pSubrayado);
      }
      else if(simbolo==pNumero){
      	*a1=Val(lexema);
      	casarLex(pNumero);
      }
      else
        casarLex(pPalabra);
      break;
    case adverb:
      if(simbolo==pPalabra){
        if(!BuscarPalabra(lexema,&palabra)||(palabra.tipo!=adverbio))
          error(errSem, 10);
        *a1=palabra.num;
        casarLex(pPalabra);
      }
      else if(simbolo==pSubrayado){
        *a1=-1;
        casarLex(pSubrayado);
      }
      else if(simbolo==pNumero){
      	*a1=Val(lexema);
      	casarLex(pNumero);
      }
      else
        casarLex(pPalabra);
      break;
    case preposition:
      if(simbolo==pPalabra){
        if(!BuscarPalabra(lexema,&palabra)||(palabra.tipo!=preposicion))
          error(errSem, 10);
        *a1=palabra.num;
        casarLex(pPalabra);
      }
      else if(simbolo==pSubrayado){
        *a1=-1;
        casarLex(pSubrayado);
      }
      else if(simbolo==pNumero){
      	*a1=Val(lexema);
      	casarLex(pNumero);
      }
      else
        casarLex(pPalabra);
      break;
    case noun:
      if(simbolo==pPalabra){
        if(!BuscarPalabra(lexema,&palabra)||(palabra.tipo!=nombre))
          error(errSem, 10);
        *a1=palabra.num;
        casarLex(pPalabra);
      }
      else if(simbolo==pSubrayado){
        *a1=-1;
        casarLex(pSubrayado);
      }
      else if(simbolo==pNumero){
      	*a1=Val(lexema);
      	casarLex(pNumero);
      }
      else
        casarLex(pPalabra);
      break;
  }
}

void anArgs(int*a1,int*a2){
  checkArg(a1,condacto.tipoArg1);
  checkArg(a2,condacto.tipoArg2);
};

void anCondacto(int numPro) {
  int cond,arg1, arg2;
  /*cond=*/arg1=arg2=-1;
  if(simbolo==pPalabra){
    if((cond=BuscarCondacto(lexema,&condacto))==FALSE)
      error(errSem,12);
    else {
      casarLex(pPalabra);
      anArgs(&arg1,&arg2);
      agregarCondacto(numPro,cond,arg1,arg2);
    }
  }else{
  casarLex(pPalabra);}
/*  anArgs();*/
}

void anMasCondactos(int numPro){
  while((simbolo==pPalabra)&&(!BOL))
    anCondacto(numPro);
}

void anCondactos(int numPro){
  anCondacto(numPro);
  anMasCondactos(numPro);
}

void anNombre(TipoEntrada*entrada){
  if((simbolo==pPalabra)||(simbolo==pNumero)){
    if(BuscarPalabra(lexema,&palabra))
      if(palabra.tipo==nombre)
        entrada->nombre=palabra.num;
      else
        error(errSem,9);
    else
      error(errSem, 8);
  if(simbolo==pPalabra)
    casarLex(pPalabra);
  else casarLex(pNumero);
  }
  else if(simbolo==pSubrayado){
    entrada->nombre=-1;
    casarLex(pSubrayado);
  }
  else
    error(errLexSint, pPalabra);
}

void anVerbo(TipoEntrada*entrada){
  if((simbolo==pPalabra)||(simbolo==pNumero)){
    if(BuscarPalabra(lexema,&palabra))
      if((palabra.tipo==verbo)||((palabra.tipo==nombre)&&(palabra.num<20)))
        entrada->verbo=palabra.num;
      else
        error(errSem,14);
    else
      error(errSem, 8);
    if(simbolo==pPalabra)
    casarLex(pPalabra);
    else casarLex(pNumero);
  }
  else if(simbolo==pSubrayado){
    entrada->verbo=-1;
    casarLex(pSubrayado);
  }
  else
    error(errLexSint, pPalabra);
}

void anEntrada(int numPro){
  entrada=(TipoEntrada*)malloc(sizeof(TipoEntrada));
  entrada->posicion=0;
  entrada->sig=NULL;
  anVerbo(entrada);
  anNombre(entrada);
  agregarEntrada(numPro, entrada);
  anCondactos(numPro);
}

void anEntradas(int numPro){
  while((simbolo==pPalabra)||(simbolo==pSubrayado))
    anEntrada(numPro);
}

void anProceso(int numPro){
  NuevoProceso(numPro);
  anEntradas(numPro);
}

void anProcesos(){
  int ultimo=-1;
  int numero;
  while(simbolo==pcPro){
    casarLex(pcPro);
    if(simbolo==pNumero){
      sscanf(lexema,"%d",&numero);
      if((numero!=ultimo+1)||(numero>ultProceso))
        error(errSem,13);
    };
    casarLex(pNumero);
    anProceso(numero);
    ultimo=numero;
    if(numero>ultProceso)
      ultProceso++;
  }
}

void anSiNo(int*valor) {
  if(simbolo==pPalabra){
    if(!strcmp(lexema,"Y")){
      *valor=TRUE;
      casarLex(pPalabra);
    }
    else
      error(errSem,7);
  }
  else if(simbolo==pSubrayado){
    *valor=FALSE;
    casarLex(pSubrayado);
  }
  else
    error(errLexSint, pPalabra);
}

void anAdjetivo(TipoObjeto *obj){
  if((simbolo==pPalabra)||(simbolo==pNumero)){
    if(!BuscarPalabra(lexema,&palabra))
      error(errSem, 8);
    if(palabra.tipo!=adjetivo)
      error(errSem,10);
    obj->adjetivo=palabra.num;
    if(simbolo==pPalabra)
    casarLex(pPalabra); /* El adjetivo */
    else casarLex(pNumero);
  }
  else if (simbolo==pSubrayado){
    obj->adjetivo=255;
    casarLex(pSubrayado);
  }
  else
    error(errLexSint, pPalabra);
}

void anLugar(TipoObjeto*obj) {
  if(simbolo==pNumero){
    obj->lugar=Val(lexema);
    casarLex(pNumero);
  }
  else if(simbolo==pPalabra){
    if(!strcmp(lexema,"WORN"))
      obj->lugar=253;
    else if(!strcmp(lexema,"CARRIED"))
      obj->lugar=254;
    else
      error(errSem,6);
    casarLex(pPalabra);
  }
  else if(simbolo==pSubrayado){
    obj->lugar=252;
    casarLex(pSubrayado);
  }
  else
    error(errLexSint, pNumero);
}

void anDefObjeto(int numObj){
  anLugar(&objeto);
  if(simbolo==pNumero){
    objeto.peso = Val(lexema);
    casarLex(pNumero);
  }
  else
    error(errLexSint, pNumero);
  anSiNo(&objeto.contenedor);
  anSiNo(&objeto.prenda);
  if((simbolo==pPalabra)||(simbolo==pNumero)){
    if(!BuscarPalabra(lexema,&palabra))
      error(errSem,8);
    if(palabra.tipo!=nombre)
      error(errSem,9);
    else
      objeto.nombre=palabra.num;
    if(simbolo==pPalabra)
    casarLex(pPalabra); /* El propio nombre */
    else casarLex(pNumero);
  }
  else if(simbolo==pSubrayado){
  	objeto.nombre=255;
  	casarLex(pSubrayado);
  }
  anAdjetivo(&objeto);
  PonerObjeto(numObj, objeto);
}

void anDefinicionesObjetos(){
  int anterior,numero;
  anterior=-1;
  while(simbolo==pIdNumerico){
    sscanf(lexema,"/%d",&numero);
    if((numero!=anterior+1)||(numero>ultTextoObjeto))
      error(errSem,11);
    casarLex(pIdNumerico);
    anDefObjeto(numero);
    anterior=numero;
  }
}

void anSeccionObj() {
  casarLex(pcObj);
  anDefinicionesObjetos();
}

void anTextosMensajes() {
  int numero;
  while(simbolo==pIdNumerico){
    ultTextoMensaje++;
    sscanf(lexema,"/%d",&numero);
    if(numero!=ultTextoMensaje)
      error(errSem, 1);
    if(numero>255)
      error(errSem, 2);
    casarLexSinLeer(pIdNumerico);
    agregarTexto(txtMensajes, numero, extraerTexto());
  }
}

void anSeccionMtx() {
  casarLex(pcMtx);
  anTextosMensajes();
}

void anTextosSistema() {
  int numero;
  while(simbolo==pIdNumerico){
    ultTextoSistema++;
    sscanf(lexema,"/%d",&numero);
    if(numero!=ultTextoSistema)
      error(errSem, 1);
    if(numero>255)
      error(errSem, 2);
    casarLexSinLeer(pIdNumerico);
    /* leerLineaDeTexto(); */ 
    agregarTexto(txtSistema, numero, extraerTexto());
  }
}

void anSeccionStx(){
  casarLex(pcStx);
  anTextosSistema();
  if(ultTextoSistema<60)
    error(errSem,3);

}

void anSalidas(int origen){
  while(simbolo==pPalabra){
    if(!BuscarPalabra(lexema,&palabra)||((palabra.num > 13)&&(palabra.tipo!=verbo)))
      error(errSem,5);
    casarLex(pPalabra);
    if(simbolo==pNumero) {
      PonerSalida(origen,palabra.num,Val(lexema));
      casarLex(pNumero);
    }
    else {
      error(errLexSint, pNumero);
    }
  }
}

void anConexiones() {
  int numero;
  while(simbolo==pIdNumerico){
    ultConexion++;
    sscanf(lexema,"/%d",&numero);
    if(numero!=ultConexion)
      error(errSem,4);
    casarLex(pIdNumerico);
    anSalidas(numero);
  }
}

void anSeccionCon() {
  casarLex(pcCon);
  anConexiones();
}

void anTextosLugares(){
  int numero;
  while(simbolo==pIdNumerico){
    ultTextoLugar++;
    sscanf(lexema,"/%d",&numero);
    if(numero!=ultTextoLugar)
      error(errSem, 1);
    if(numero>255)
      error(errSem, 2);
    casarLexSinLeer(pIdNumerico);
    agregarTexto(txtLugares, numero, extraerTexto());
  }
}

void anSeccionLtx() {
  casarLex(pcLtx);
  anTextosLugares();
}

void anTextosObjetos() {
  int numero;
  while(simbolo==pIdNumerico){
    ultTextoObjeto++;
    sscanf(lexema,"/%d",&numero);
    if(numero!=ultTextoObjeto)
      error(errSem, 1);
    if(numero>255)
      error(errSem, 2);
    casarLexSinLeer(pIdNumerico);
    agregarTexto(txtObjetos, numero, extraerTexto());
  }
}

void anSeccionOtx() {
  casarLex(pcOtx);
  anTextosObjetos();
}

void anEntradaVoc(){
  char pal[6];
  int numero;
  TiposDePalabra tipo;

  if(simbolo==pPalabra){
    strncpy(pal,lexema,5);
    casarLex(pPalabra);
  } else if (simbolo==pNumero){
    strncpy(pal,lexema,5);
    casarLex(pNumero);
  } else error(errLexSint,pPalabra);
  if(simbolo==pNumero) {
    sscanf(lexema,"%d",&numero);
    casarLex(pNumero);
  } else error(errLexSint,pNumero);
  if(simbolo==pPalabra) {
    if(!strcmp(lexema,"VERB"))
      tipo=verbo;
    else if(!strcmp(lexema,"NOUN"))
      tipo=nombre;
    else if(!strcmp(lexema,"ADJECTIVE"))
      tipo=adjetivo;
    else if(!strcmp(lexema,"ADVERB"))
      tipo=adverbio;
    else if(!strcmp(lexema,"PRONOUN"))
      tipo=pronombre;
    else if(!strcmp(lexema,"CONJUGATION"))
      tipo=conjuncion;
    else if(!strcmp(lexema,"PREPOSITION"))
      tipo=preposicion;
    else error(errSem, 0);
  }
  else
    error(errLexSint,pPalabra);
  NuevaPalabra(pal, tipo, numero);
  casarLex(pPalabra);
}

void anEntradasVoc() {
  while((simbolo==pPalabra)||(simbolo==pNumero))
    anEntradaVoc();
}

void anSeccionVoc() {
  casarLex(pcVoc);
  anEntradasVoc();
}

void anSeccionCtl(){
  casarLex(pcCtl);
  casarLex(pSubrayado);
}

void anFichPaw() {
  puts("Analizando sección /CTL...\n");
  anSeccionCtl();
  puts("Analizando sección /VOC...\n");
  anSeccionVoc();
  puts("Analizando sección /STX...\n");
  anSeccionStx();
  puts("Analizando sección /MTX...\n");
  anSeccionMtx();
  puts("Analizando sección /OTX...\n");
  anSeccionOtx();
  puts("Analizando sección /LTX...\n");
  anSeccionLtx();
  puts("Analizando sección /CON...\n");
  anSeccionCon();
  puts("Analizando sección /OBJ...\n");
  anSeccionObj();
  puts("Analizando secciones /PRO...\n");
  anProcesos();
}

void analizar(void) {
  InicializarVocabulario();
  PrepararSalidas();
  anFichPaw();
  casarLex(pFinal);
/*  error(sinError,0);*/
}

