//-------------------------------------------------------------------//
//                                                                   //
//	                     Parser                                  //
//                                                                   //
//-------------------------------------------------------------------//

/***********************************************************************/
/* Gramatica                                                           */
/***********************************************************************/

// La presente gramatica se compone de un conjunto de verbos en infinitivo con 
// acciones asociadas: al coincidir el formato de la gramatica con el de la entrada,
// se ejecuta la accion correspondiente

	/***********************/
	/* Abstraccion 'verbo' */
	/***********************/

abstract verbo::object{
	verbo:	abstract	// Secuencia de objetos que representa los tokens a emparejar
				// para ejecutar la accion asociada. Cada elemento de la secuencia
				// puede ser una cadena de caracteres (emparejamiento literal),
				// un array de cadenas de caracteres (emparejamiento literal con
				// alguno de los elementos del array) o el valor nulo (cualquier
				// nombre de objeto del mundo virtual)
				
	accion(x): abstract	// Accion asociada, donde x es la secuencia de tokens emparejada
}

	/*************/
	/* Gramatica */
	/*************/
	
gramatica::object{

	/* AYUDA */

	ayuda::verbo{
		verbo:	[["ayuda","socorro","help"]]
		accion(x):	
			print(" Eres un cachito de basura que se quiere comer el mundo usando
	     			ordenes como 'mirar','examinar cubo', 'asimilar excrementos',
	     			'ir a cocina', etc... entre otras. Descubrirlas es parte del
	     			juego, aunque son bastante sencillas. \n\n Adelante, basura!\n")
	}
	
	/* MIRAR */
	
	mirar::verbo{
		verbo:	[["examinar","ex","x","mirar","m"]]
		accion(x): 
			let sitio=protagonista.dentroDe in
			  let l=sitio.contiene in

					// Descripcion
							
				print(sitio.descripcion)
				
					// Mensajes
				
				let i,m in
					for i=m=0,i<l.length,i=i+1 do
						if l[i].mensaje!=null then
							if m==0 then print("\n")
							else m=1
							print(l[i].mensaje)
				
				print("\n")
				
					// Inventario
								
				let k=0 in
					let i in for i=0,i<l.length,i=i+1 do
						if l[i].inventario!=null then k=k+1
					if k!=0 then let i,m in
						for i=m=0,i<l.length,i=i+1 do
						    if l[i].inventario!=null then
							if m==0 then 
								print(" Ves ");m=1;k=k-1
							else if k>1 then 
								print(", ");k=k-1
							else print(" y ")
							print(l[i].inventario)
						if m!=0 then print (".\n")
	}
	
	/* EXAMINAR */
	
	examinar::verbo{
		verbo:	[["examinar","ex","x","mirar","m"],null]
		accion(x):
			print(x[1].descripcion:"\n")
	}

	/* COMER */
	
	comer::verbo{
		verbo:	[["comer","absorver","asimilar","succionar"],null]
		accion(x):
			let objeto=x[1] in
				if (objeto is decorado) then
					print(" A eso no se le puede extraer jugo\n")
				else if (objeto.calorias>protagonista.calorias) then
					print(" Tus jugos se revuelven de emocion, pero 
					no puedes asimilar algo tan grande todavia\n")
				else
					print(objeto.alcomer:"\n")
					protagonista.calorias=protagonista.calorias+objeto.calorias
					if objeto.calorias!=0 then
						objeto.calorias=0
						objeto.borrar
	}
	
	verbo{
		verbo:	[["comer","absorver","asimilar","succionar"]]
		accion(x):
			print(" Tendras que explicarte mejor. Que quieres ":x[0]:"?\n")
			
	}
	
	/* SUR,NORTE,ESTE,OESTE */
	
	sur::verbo{
		verbo:	[["s","sur"]]
		accion(x):	
			ir.accion([null,null,protagonista.dentroDe.salidaSur])
	}

	norte::verbo{
		verbo:	[["n","norte"]]
		accion(x):	
			ir.accion([null,null,protagonista.dentroDe.salidaNorte])
	}

	este::verbo{
		verbo:	[["e","este"]]
		accion(x):	
			ir.accion([null,null,protagonista.dentroDe.salidaEste])
	}

	oeste::verbo{
		verbo:	[["o","oeste"]]
		accion(x):	
			ir.accion([null,null,protagonista.dentroDe.salidaOeste])
	}
	
	/* ENTRAR, SALIR */
	
	entrar::verbo{
		verbo:	[["entrar"]]
		accion(x):	
			if protagonista.dentroDe.salidaEntrar==null then print(" Entrar... donde?\n")
			else ir.accion([null,null,protagonista.dentroDe.salidaEntrar])
	}
	
	salir::verbo{
		verbo:	[["salir"]]
		accion(x):	
			if protagonista.dentroDe.salidaSalir==null then print(" Salir... donde?\n")
			else ir.accion([null,null,protagonista.dentroDe.salidaSalir])
	}
					
	entrarEn::verbo{
		verbo:	[["entrar"],["en","a"],null]
		accion(x):	
			if x[2]==protagonista.dentroDe.salidaEntrar then ir.accion([null,null,x[2]])
			else print(" No puedes entrar ahi.\n")
	}
	
	salirA::verbo{
		verbo:	[["salir"],["a","hacia"],null]
		accion(x):	
			if x[2]==protagonista.dentroDe.salidaSalir then ir.accion([null,null,x[2]])
			else print(" No puedes salir hacia ahi.\n")
	}

	/* IR */
	
	verbo{
		verbo:	[["ir"]]
		accion(x):
			print(" Ir... hacia donde?\n")
	}
	
	ir::verbo{
		verbo:	[["ir"],["a","hacia"],null]
		accion(x): 
			if x[2]==null then 
				print(" No puedes ir por ahi.\n")
			else if let z=protagonista.dentroDe in \
				(z.salidaSur!=null and x[2].nombre==z.salidaSur.nombre) or\
				(z.salidaNorte!=null and x[2].nombre==z.salidaNorte.nombre) or\
				(z.salidaEste!=null and x[2].nombre==z.salidaEste.nombre) or\
				(z.salidaOeste!=null and x[2].nombre==z.salidaOeste.nombre) or\
				(z.salidaEntrar!=null and x[2].nombre==z.salidaEntrar.nombre) or\
				(z.salidaSalir!=null and x[2].nombre==z.salidaSalir.nombre) then
			     		protagonista.moverA(x[2])
					mirar.accion(null)
			else 
				print(" No puedes ir por ahi.\n")
	}

	/* SALIDAS */
	
	salidas::verbo{
		verbo:	[["salidas"]]
		accion(x):
		    let x=" Salidas:" in
			if (protagonista.dentroDe.salidaNorte!=null) then
				x=x:"\n    Norte: (":protagonista.dentroDe.salidaNorte.nombre:")"
			if (protagonista.dentroDe.salidaSur!=null) then 
				x=x:"\n    Sur: (":protagonista.dentroDe.salidaSur.nombre:")"
			if (protagonista.dentroDe.salidaEste!=null) then
				x=x:"\n    Este: (":protagonista.dentroDe.salidaEste.nombre:")"
			if (protagonista.dentroDe.salidaOeste!=null) then
				x=x:"\n    Oeste: (":protagonista.dentroDe.salidaOeste.nombre:")"
			if (protagonista.dentroDe.salidaEntrar!=null) then 
				x=x:"\n    Entrar: (":protagonista.dentroDe.salidaEntrar.nombre:")"
			if (protagonista.dentroDe.salidaSalir!=null) then 
				x=x:"\n    Salir: (":protagonista.dentroDe.salidaSalir.nombre:")"
			if (x==" Salidas:") then
				x=x:"\n    Ninguna"
			print(x:"\n")
	}

	/* parser.fin */
	
	fin::verbo{
		verbo:	[["fin","exit","quit","bye","adios"]]
		accion(x):	
			print(" Terminar? [s/N] ")
			parser.fin=(system.readln.toLower=="s")
	}
	
	/* ESPERAR */
	
	esperar::verbo{
		verbo:	[["pensar","esperar","descansar","relax"]]
		accion(x):	
			print(" El tiempo pasa...\n")
	}
	
	verbo{
		verbo:	[esperar.verbo[0],["en","sobre"],null]
		accion(x): 
			esperar.accion(x)
	}

	/* OTROS */
	
	otros::verbo{
		verbo:	[["mover","usar","abrir","empujar","forzar",\
			  "romper","matar","coger","buscar","registrar","golpear"]]
      		accion(x): print(" Te das cuenta de que eres una masa informe y viscosa, y de
				que no tienes manos para manejar objetos.\n\n Te sientes un
				poco torpe.\n")
	}
	
	verbo{
		verbo:	[otros.verbo[0],null]
      		accion(x): otros.accion(x)
	}

	verbo{
		verbo:	[otros.verbo[0],null,["usando","con","en","utilizando","hacia"],null]
      		accion(x): otros.accion(x)
	}
}

/***********************************************************************/
/* Leer entrada y ejecutar accion gramatical asociada                  */
/***********************************************************************/

parser::object{	

	var turno:	1	// autoincremento cada vez que se ejecuta una accion
				// de la gramatica
	
	var fin: 	false	// fin del juego
	
	/**********************************/
	/* Leer entrada y ejecutar accion */
	/**********************************/

	parse:	
	
		/* LEER ENTRADA */
				
		let tokens,verbos,i in
				
				/* Leer entrada */
		
			print("\n> ")						
			tokens=system.readln.tokens
			print("\n")
			
				/* Emparejar con verbos de la gramatica */
			
			verbos=gramatica.lexicalSons
			for i=0,i<verbos.length,i=i+1 do
				if verbos[i].verbo.length==tokens.length then
					if compararEntrada(verbos[i].verbo,tokens) then break
			
				/* Ejecutar accion o mostrar error */
			
			if i!=verbos.length then
				verbos[i].accion(tokens)
		
				if (not parser.fin) then
				
					/* Ejecutar demonios asociados a los objetos */
					
					protagonista.dentroDe.accion
					
					let i,x=protagonista.dentroDe.contiene in
						if x!==null then
						    for i=0,i<x.length,i=i+1 do 
							let z=x[i].accion in
								if z is string and z.length>0 then
									print("\n":z:"\n")
					
					protagonista.accion
					
					/* Actualizar turno */
						
					parser.turno=parser.turno+1
			else
				print(staticMsg[staticIter])
				staticIter=(staticIter+1)%staticMsg.length

	/**********************************/
	/* Emparejar una entrada concreta */
	/**********************************/
		
	compararEntrada(verbo,tokens):
		let i,j,k,x,y in
			for j=0,j<tokens.length,j=j+1 do
				
					/* Emparejar con objeto */
			
				if verbo[j] is null then
					x=protagonista.dentroDe.contiene
					for y=0,y<x.length,y=y+1 do
					
							/* objeto con un solo nombre */
					
						if x[y].nombre is string then
							if x[y].nombre.tolower==tokens[j].tolower then
								break
						
							/* objeto con varios nombres */
						
						else if x[y].nombre is array then
							let z in for z=0,z<x[y].nombre.length,z=z+1 do
								if x[y].nombre[z].tolower==tokens[j].tolower then
									break		
							if z!=x[y].nombre.length then break
					
					if y==x.length then break
					else tokens[j]=x[y]
				
					/* Emparejar con cadena */
				
				else if verbo[j] is string then
					if tokens[j].tolower!=verbo[j].tolower then break
				
					/* Emparejar con una o mas cadenas de entre varias */
				
				else if verbo[j] is array then
					let t=false,z in 
   				            for z=0,z<verbo[j].length,z=z+1 do
						if (tokens[j].tolower==verbo[j][z].tolower) then
							t=true
					    if t==false then break	
			
			j==tokens.length
	
	/*****************************/
	/* Mensajes en caso de error */
	/*****************************/
			
	var staticIter: 1
	var staticIter2: 1
	staticMsg:  ["Como?\n","Perdon?\n","No entiendo.\n","Tendras que explicarte mejor.\n"]
	staticMsg2: ["Cual?\n","No es algo que necesites en esta aventura.\n"]
}