#!/usr/bin/env python
# -*- coding: UTF-8 -*-

# ------------------------------------------------------------
# RangeX
#
# Interprete del lenguaje RangeX
# Entrega 3, Tabla de simbolos con arbol sintactico abstracto.
# CI-3725
# (Abril-Julio 2013)
#
#
# Hecho por:
#	@author: Stefano De Colli	09-10203
#	@author: Karen Troiano		09-10855
# ------------------------------------------------------------



import ply.lex as lex
import ply.yacc as yacc
import sys
import re
from SymTable import *

global impresion 
impresion = '\n'
global Error
Error = False
global ErrorEst
ErrorEst = False
global TS
TS = None

#---------------------------------------------------#
#		PRIMERA ENTREGA								#
#---------------------------------------------------#

# Lista de palabras reservadas.

reserved = {
	# Bloques
	'program'	:	'TkProgram',
	'begin'		:	'TkBegin',
	'end'		:	'TkEnd',
	'declare'	:	'TkDeclare',
	'as'		:	'TkAs',

	# Secuenciadores
	'if'		:	'TkIf',
	'do' 		: 	'TkDo',
	'then'		:	'TkThen',
	'else'		:	'TkElse',
	'for'		:	'TkFor',
	'while'		:	'TkWhile',
	'in'		:	'TkIn',
	'case'		:	'TkCase',
	'of'		:	'TkOf',

	# I/O
	'read'		: 	'TkRead',
	'write'		:	'TkWrite',
	'writeln'	:	'TkWriteLn',

	# Funciones
	'rtoi'		:	'TkRtoi',
	'length'	:	'TkLength',
	'top'		:	'TkTop',
	'bottom'	:	'TkBottom',

	# Tipos
	'bool'	 	: 	'TkBool',
	'int'		:	'TkInt',
	'range'		:	'TkRange',
	
	 # Booleans
	'true'		:	'TkTrue',
	'false'		:	'TkFalse',
	'and'		:	'TkAnd',
	'or'		:	'TkOr',
	'not'		:	'TkNot'
}

# Lista de Tokens.
tokens = [
	# Simples
	'TkPuntoYComa',
	'TkParAbre',
	'TkParCierra',
	'TkSuma',
	'TkResta',
	'TkAsterisco',
	'TkInterseccion',
	'TkPertenece',
	'TkMenor',
	'TkMenorIgual',
	'TkMayor',
	'TkMayorIgual',
	'TkIgual',
	'TkDesIgual',
	'TkAsignacion',
	'TkFlechaCase',
	'TkComma',
	'TkConstruccion',
	'TkModulo',
	'TkDiv',

	# Funcionales
	'TkId',
	'TkComent',
	'TkString',
	'TkNum'
	] + list(reserved.values())

# Expresiones regulares para tokens simples.
t_TkPuntoYComa 		= r';'
t_TkParAbre			= r'\('
t_TkParCierra		= r'\)'
t_TkSuma			= r'\+'
t_TkResta 			= r'-'
t_TkAsterisco		= r'\*'
t_TkInterseccion	= r'<>'
t_TkPertenece		= r'>>'
t_TkMenor			= r'<'
t_TkMenorIgual 		= r'<='
t_TkMayor 			= r'>'
t_TkMayorIgual 		= r'>='
t_TkIgual			= r'=='
t_TkDesIgual		= r'/='
t_TkAsignacion 		= r'='
t_TkFlechaCase		= r'->'
t_TkComma			= r'\,'
t_TkConstruccion	= r'\.\.'
t_TkModulo			= r'%'
t_TkDiv				= r'/'

# Expresiones regulares para tokens complejos.
# (que requieren instrucciones adicionales)

def t_TkId(t):
	r'[a-zA-Z_][a-zA-Z0-9_]*'
	if t.value in reserved:
		t.type = reserved[t.value]
	return t

def t_ignore_TkComent(t):
	r'\/\/[^\n]*'

def t_TkString(t):
	r'"([^"\\]|\\"|\\\\|\\n|\\t|\\r|\\f|\\v)*"'
	t.value = (t.value)[1:-1]
	return t

def t_TkNum(t):
	r'\d+'
	t.value = int(t.value)
	if (t.value > 2147483647 or t.value < -2147483648):
		t_error(t)
	return t

# Se calcula la columna en la que comienza la palabra que
# contiene el error.
# lineno - Numero de linea actual.
# lexpos - Posicion actual en el archivo de entrada.

def find_column(input, token):
	i = token.lexpos
	j = 0
	k = 0  
	while i > 0:
		if input[i] == '\n':			break
		if input[i] == '\t': 
			k += 1
		i -=1
	if (token.lineno == 1):
		k += 0
		j = 0
	else:
		j = 1
	column = ((((token.lexpos - i) + (k*4)) - k) - j) + 1
	return column

	
def find_column_parser(input, num, linea):
	i = num
	j = 0
	k = 0  
	while i > 0:
		if input[i] == '\n':			break
		if input[i] == '\t': 
			k += 1
		i -=1
	if (linea == 1):
		k += 0
		j = 0
	else:
		j = 1
	column = ((((num - i) + (k*4)) - k) - j) + 1
	return column

# Aqui se toman en cuenta los caracteres en blanco.
# (espacios, tab)
t_ignore = ' \t'

# Se utiliza para que la linea en la que se encuentra
# el lexer leyendo vaya aumentando cada vez que encuentra
# un '\n'.
def t_newline(t):
	r'\n+'
	t.lexer.lineno += len(t.value)

# Se define accion a tomar cuando ocurre un error.
def t_error(t):
	global Error
	Error = True
	if (t.type == 'TkNum'):
		print "Entero fuera de rango 32b \"%d\"en linea %s, columna %s."%(t.value, t.lineno, find_column(text, t))
	else:
		print "Error: caracter inesperado \"%s\"en linea %s, columna %s."%(t.value[0], t.lineno, find_column(text, t))
	t.lexer.skip(1)
	return t


#-------------------------------------------------------#
#			FIN DE PRIMERA ENTREGA						#
#-------------------------------------------------------#

#-----------------------#
#	Clases				#
#-----------------------#

#def verificarValor(value, clase):
	#if (t.value > 2147483647 or t.value < -2147483648):
		# Imprimir error dinamico

class Declaracion:
	def __init__(self, variables ,tipo ,linea, columna):
		self.variables = variables
		self.tipo = tipo
		self.linea = linea
		self.columna = columna

	def getVariables(self):
		return self.variables

	def getLinea(self):
		return self.linea
	
	def getTipo(self,flag = False):
		return self.tipo
	
	def getColumna(self):
		return self.columna

class Asignacion:
	def __init__(self, var, val):
		self.var = var
		self.val = val

	def toString(self, tab, booleano):
		tab = tab + "\t"
		palabra = "ASIGNACION\n"
		palabra += tab + "var: " + str(self.var.toString(tab, True, False)) + "\n"
		palabra += tab + "val: " + str(self.val.toString(tab, False))
		return palabra

	def verificar(self):
		global TS
		global ErrorEst
		a = TS.find(self.var.getVariable(), False)
		if (a != None):
			if (a.getReservado()):
				ErrorEst = True
				print("Error en la linea %s, columna %s: se intenta modificar la variable \"%s\" la cual pertenece a una iteracion." %(self.var.getLinea() , self.var.getColumna(), self.var.getVariable()))
			else: 
				if (self.val.getTipo() != "TypeError" and self.var.getTipo() != self.val.getTipo()): 
					ErrorEst = True
					print("Error en la linea %s, columna %s: intento de asignar a la variable \"%s\" de tipo \"%s\" una expresion del tipo \"%s\"." %(self.var.getLinea() , self.var.getColumna(), self.var.getVariable(), TS.find(self.var.getVariable(), False).getTipo(), self.val.getTipo()))
		else:
			ErrorEst = True
			print("Error en linea %s, columna %s: no puede usar la variable \"%s\" pues no ha sido declarada." %(self.var.getLinea() , self.var.getColumna(), self.var.getVariable()))
			
		self.val.verificar()

	# Revisado
	def ejecutar(self):
		expresion = self.val
		variable = TS.find(self.var.getVariable(), False)
		val, val1 = expresion.evaluar()

		variable.update(val, val1)

class Condicional:
	def __init__(self, guardia, then, elsse):
		self.guardia = guardia
		self.then = then
		self.elsse = elsse
		
	def toString(self, tab, booleano):
		tab = tab + "\t"
		palabra = "CONDICIONAL\n"
		palabra += tab + "condicion: " + self.guardia.toString(tab, False) + "\n"
		palabra += tab + "verdadero: " + self.then.toString(tab, False)
		if (self.elsse != 'vacio'):
			palabra += "\n"+ tab + "falso: " +  self.elsse.toString(tab, False)
		return palabra

	def verificar(self):
		self.then.verificar()
		if (self.elsse != "vacio"):
			self.elsse.verificar()

		if (self.guardia.getTipo() != "TypeError" and self.guardia.getTipo() != "bool"):
			global ErrorEst
			ErrorEst = True
			print("Error en la linea %s, columna %s: la condicion no es del tipo \"bool\"." %(self.guardia.getLinea() , self.guardia.getColumna()))

	# Revisado
	def ejecutar(self):
		res, res1 = self.guardia.evaluar()
		if (res):
			self.then.ejecutar()
		else:
			if (self.elsse != "vacio"):
				self.elsse.ejecutar()

class Case:
	def __init__(self, exp, casos):
		self.exp = exp
		self.casos = casos

	def toString(self, tab, booleano):
		palabra = "CASE\n"
		if (type(self.exp) is str):
			palabra += tab + "exp: "  + self.exp
		else:
			palabra += tab + "exp: " + self.exp.toString(tab, False) + "\n"
		palabra += tab + "caso: \n" + tab + self.casos.toString(tab, False) 
		return palabra

	def verificar(self):
		self.exp.verificar()

		if (self.exp.getTipo() != "TypeError" and self.exp.getTipo() != "int"):
			global ErrorEst
			ErrorEst = True
			print("Error en la linea %s, columna %s: la condicion no es del tipo \"int\"." %(self.exp.getLinea() , self.exp.getColumna()))

		self.casos.verificar()

	# Revisado
	def ejecutar(self):
		exp, exp1 = self.exp.evaluar()
		self.casos.ejecutar(exp)

class CaseCond:
	def __init__(self, rango, instruccion, casos):
		self.rango = rango
		self.instruccion = instruccion
		self.casos = casos

	def toString(self, tab, booleano):
		palabra = "\t" + "ran: " + self.rango.toString(tab + "\t", False) + "\n"
		palabra += tab + "\t" +  "ins: " + self.instruccion.toString(tab + "\t", False) + "\n"
		if (self.casos != 'vacio'):
			palabra += tab + "caso: \n" + tab + self.casos.toString(tab, False)
		return palabra

	def verificar(self):
		self.rango.verificar()

		if (self.rango.getTipo() == "TypeError" and self.rango.getTipo() != "range"):
			global ErrorEst
			ErrorEst = True
			print("Error en la linea %s, columna %s: la condicion no es del tipo \"range\"." %(self.rango.getLinea() , self.rango.getColumna()))

		self.instruccion.verificar()
		if (self.casos != "vacio"):
			self.casos.verificar()

	# Revisado
	def ejecutar(self, exp = 2147483647):
		inf, sup = self.rango.evaluar()
		if ((exp) in range(inf, sup + 1)):
			self.instruccion.ejecutar()

		if (self.casos != "vacio"):
			self.casos.ejecutar(exp)

class RepeticionDet:
	def __init__(self, variable, rango, instruccion):
		self.variable = variable
		self.rango = rango
		self.instruccion = instruccion

	def toString(self, tab, booleano):
		tab = tab + "\t"
		palabra = "ITERACION_DET\n"
		palabra += tab + "variable: " + self.variable.toString(tab, True, False) + "\n"
		palabra += tab + "rango: "  + self.rango.toString(tab, False) + "\n"
		palabra += tab + "instruccion: " + self.instruccion.toString(tab, False)
		return palabra

	def verificar(self):
		global ErrorEst
		global TS
		TS = SymTable(TS, False)
		if (self.variable.getTipo(True) == "variable" or self.variable.getTipo() == "TypeError"):
			if not(TS.insert(self.variable.getVariable(), "int", True)):
				ErrorEst = True
				x = self.variable
				print("Error en linea %s, columna %s: la variable '%s' ya ha sido declarada." %(x.getLinea() , x.getColumna(), x.getVariable()))
		if (self.rango.getTipo() != "TypeError" and self.rango.getTipo() != "range"):
			ErrorEst = True
			print("Error en la linea %s, columna %s: el rango no es del tipo \"range\"." %(self.rango.getLinea() , self.rango.getColumna()))
		self.instruccion.verificar()
		TS = TS.getPadre()

	# Revisado?
	def ejecutar(self):
		# Creamos la TS
		global TS
		TS = SymTable(TS, False)
		TS.insert(self.variable.getVariable(), "int", True)

		# Ejecutamos la instrucion
		var = TS.find(self.variable.getVariable(), False)
		inf, sub = self.rango.evaluar()
		for i in range(inf, sub + 1):
			var.update(i)
			self.instruccion.ejecutar()

		# Cambiamos la TS
		TS = TS.getPadre()

class RepeticionIndet:
	def __init__(self, guardia, instruccion):
		self.guardia = guardia
		self.instruccion = instruccion

	def toString(self, tab, booleano):
		tab = tab + "\t"
		palabra = "ITERACION_INDET\n"
		palabra += tab + "condicion: "  + self.guardia.toString(tab, False) + "\n"
		palabra += tab + "instruccion: "  + self.instruccion.toString(tab, False)
		return palabra

	def verificar(self):
		if (self.guardia.getTipo() != "TypeError"):
			if (self.guardia.getTipo() != "bool"):
				global ErrorEst
				ErrorEst = True
				print("Error en la linea %s, columna %s: la condicion no es del tipo \"bool\"." %(self.guardia.getLinea() , self.guardia.getColumna()))

		self.instruccion.verificar()

	# Revisado
	def ejecutar(self):
		res, we = self.guardia.evaluar()
		while res:
			self.instruccion.ejecutar()
			res, we = self.guardia.evaluar()

class Bloque:
	def __init__(self, declaraciones, instrucciones, end):
		self.declaraciones = declaraciones
		self.instrucciones = instrucciones
		self.end = end

	def toString(self, tab, booleano):
		palabra = "BLOQUE\n"
		tab = tab + "\t"
		if (not (self.declaraciones == 'vacio')):
			palabra += tab + "TABLA DE SIMBOLOS\n"
			for x in self.declaraciones.getLista():
				for y in x.getVariables():
					palabra += tab + "variable: " + y + " | tipo: " + x.getTipo() + "\n"
			palabra += "\n"
				
		palabra += tab + self.instrucciones.toString(tab, False) + "\n"
		return palabra

	def verificar(self):
		global TS
		TS = SymTable(TS)
		if (not (self.declaraciones == 'vacio')):
			for x in self.declaraciones.getLista():
				for y in x.getVariables():
					if (not (TS.insert(y, x.getTipo()))):
						global ErrorEst
						ErrorEst = True
						print("Error en linea %s, columna %s: la variable '%s' ya ha sido declarada." %(x.getLinea() , x.getColumna(), y))

		self.instrucciones.verificar()
		TS = TS.getPadre()

	# Revisado?
	def ejecutar(self):
		# Agregamos las variables a la TS
		global TS
		TS = SymTable(TS)
		if (not (self.declaraciones == 'vacio')):
			for x in self.declaraciones.getLista():
				for y in x.getVariables():
					TS.insert(y, x.getTipo())

		# Ejecutamos las instrucciones
		self.instrucciones.ejecutar()

		# Cambiamos la TS
		TS = TS.getPadre()

class Simple:
	def __init__(self, tipo, valor, linea = 0, columna = 0):
		self.tipo = tipo
		self.valor = valor
		self.linea = linea
		self.columna = columna

	def getColumna(self):
		return self.columna
		
	def getLinea(self):
		return self.linea
		
	def getVariable(self):
		return self.valor

	def Conjunto(self):
		ls = []
		ls.append(self.valor)
		return ls

	def toString(self, tab, booleano, bool2 = True):
		tab = tab + "\t"
		if (self.tipo == 'VARIABLE' or self.tipo == 'CADENA'):
			if (booleano == True and bool2 == True):
				palabra = "elemento: " + str(self.tipo) + "\n"
				if (self.tipo == 'VARIABLE'):
					palabra += tab + "nombre: " + str(self.valor)
				else:
					cadena = str(self.valor)
					cadena = cadena.replace("\\n", " ")
					cadena = cadena.replace("\\t", "	")
					cadena = cadena.replace("\\", "")
					palabra += tab + "valor: " + cadena
			elif (booleano == True and bool2 == False):
				palabra = str(self.valor)
			elif (self.tipo == 'VARIABLE'):
				palabra = str(self.tipo) + "\n"
				palabra += tab + "nombre: " + str(self.valor)
			elif (self.tipo == 'CADENA'):
				palabra = str(self.tipo) + "\n"
				cadena = str(self.valor)
				cadena = cadena.replace("\\n", " ")
				cadena = cadena.replace("\\t", "	")
				cadena = cadena.replace("\\", "")
				palabra += tab + "valor: " + cadena 
		else:
			if (booleano == True):
				palabra = "elemento: " + str(self.tipo) + "\n"
			else:
				palabra = str(self.tipo) + "\n"
			palabra += tab + "valor: " + str(self.valor)
		return palabra

	def getTipo(self, flag = False):
		if (self.tipo == "CONSTANTE_ENT"):
			return "int"
		elif (self.tipo == "VARIABLE"):
			global TS
			if (TS.find(self.valor, False) == None):
				return "TypeError" # No encontrado
			else:
				if (not flag):
					return TS.find(self.valor, False).getTipo()
				else:
					return "variable"
		elif (self.tipo == "BOOLEANO"):
			return "bool"
		else:
			return "string"

	def verificar(self):
		global TS
		if (self.tipo == "VARIABLE"):
			if (TS.find(self.valor, False) == None):
				global ErrorEst
				ErrorEst = True
				print("Error en línea %s, columna %s: no puede usar la variable \"%s\" pues no ha sido declara." %(self.linea, self.columna, self.valor))

	def getExpresion(self):
		return str(self.valor)

	def evaluar(self):
		res = None
		# Ok
		if (self.tipo == "BOOLEANO"):
			res = (self.valor == "true")
		elif (self.tipo == "CADENA"):
			cadena = str(self.valor)
			cadena = cadena.replace("\\t", "	")
			i = cadena.count("\\n", 0, len(cadena))
			prueba = cadena.split("\\n")
			if (len(prueba) == 1):
				prueba[0] = prueba[0].replace("\\", "")
				res = prueba[0]
			else:
				x = 0
				res = ""
				while x < i:
					prueba[x] = prueba[x].replace("\\", "")
					res += prueba[x] + "\n"
					x = x + 1
				else: 
					prueba[x] = prueba[x].replace("\\", "")
					res += prueba[x]
		# Ok
		elif (self.tipo == "CONSTANTE_ENT"):
			res = self.valor
		# Ok
		else:
			a = TS.find(self.valor, False)
			if (a.getDefinida() != True):
				sys.exit("Error: La variable \"%s\" no ha sido inicializada." %(self.valor))
			if (a.getTipo() == "bool"):
				res = a.getValor()
			else:
				if (a.getTipo() == "range"):
					return a.getValor(), a.getValor2()
				else:
					res = a.getValor()

		return res, None

class Secuenciacion:
	def __init__(self, instruccion1, instruccion2):
		self.instruccion1 = instruccion1
		self.instruccion2 = instruccion2

	def toString(self, tab, booleano):
		palabra = self.instruccion1.toString(tab, False) + "\n"
		palabra += tab + "SEPARADOR\n"
		palabra += tab + self.instruccion2.toString(tab, False)
		return palabra

	def verificar(self):
		self.instruccion1.verificar()
		self.instruccion2.verificar()

	# Revisado
	def ejecutar(self):
		self.instruccion1.ejecutar()
		self.instruccion2.ejecutar()

class LineaDeclaracion:
	def __init__(self, variable, tipo, declaraciones, linea, columna):
		self.declaraciones = []
		self.linea = linea
		self.columna = columna
		self.declaraciones.append(Declaracion(variable.Conjunto(), tipo, self.linea, self.columna))
		if (not declaraciones == "vacio"):
			self.declaraciones = declaraciones.getLista() + self.declaraciones

	def getLinea(self):
		return self.linea

	def getColumna(self):
		return self.columna

	def getLista(self):
		return self.declaraciones

class Variables:
	def __init__(self, variable1, variable2, linea, columna):
		self.variable1 = variable1.Conjunto()
		self.variable2 = variable2.Conjunto()
		self.linea = linea
		self.columna = columna
		
	def getLinea(self):
		return self.linea
		
	def getColumna(self):
		return self.linea
		
	def Conjunto(self):
		return self.variable1 + self.variable2

class IO:
	def __init__(self, nombre, expresion):
		self.nombre = nombre
		self.expresion = expresion

	def toString(self, tab, booleano):
		palabra = self.nombre + "\n"
		if (self.nombre == 'READ'):
			palabra += tab + "\t" + "variable: " + self.expresion.toString(tab, True, False)
		else:
			tab = tab + "\t"
			palabra += tab + self.expresion.toString(tab, True)
		return palabra

	def verificar(self):
		if (self.nombre == 'READ'):
			global TS
			a = TS.find(self.expresion.getVariable(), False)
			if (a != None):
				if (a.getReservado()):
					global ErrorEst
					ErrorEst = True
					print("Error en la linea %s, columna %s: se intenta modificar la variable \"%s\" la cual pertenece a una iteracion." %(self.expresion.getLinea() , self.expresion.getColumna(), self.expresion.getVariable()))
		self.expresion.verificar()

	def ejecutar(self):
		tipo = self.expresion.getTipo()
		if (self.nombre == 'READ'):
			# Buscamos la variable
			global TS
			variable = TS.find(self.expresion.getVariable(), False)
			valor = raw_input()
			valor = Depurar(valor)
			if (tipo == 'range'):
				self.Range(valor)
			elif (tipo == 'int'):
				self.Int(valor)
			elif (tipo == 'bool'):
				while (valor != "true" and valor != "false"):
					print("Error: La variable \"" + self.expresion.getVariable() + "\" es de tipo bool. Formatos validos: true, false")
					valor = raw_input()
					valor = Depurar(valor)
				# Asignamos a la varible el valor
				variable.update(valor == "true")
		elif (self.nombre == 'WRITE'):
			palabra = imprimir(self.expresion)
			print palabra,

		elif (self.nombre == 'WRITELN'):
			palabra = imprimir(self.expresion)
			print(palabra)

	def Int(self,valor):
		while (not IsInt(valor)):
			print("Error: La variable \"" + self.expresion.getVariable() + "\" es de tipo int. Introduzca un numero.")
			valor = raw_input()
			valor = Depurar(valor) 
		else:
			valor = int(valor)
			if ((valor > 2147483647) or (valor < -2147483648)):
				print("Error: El numero no se puede representarse en 32B.")
				valor = raw_input()
				valor = Depurar(valor)
				self.Int(valor)
			else:
				global TS
				variable = TS.find(self.expresion.getVariable(), False)
				variable.update(valor)
			
		
		
	def Range(self, valor):
		global TS
		variable = TS.find(self.expresion.getVariable(), False)
		while (not re.match("([+-]?)[0-9]+(,|(\.\.))([+-]?)[0-9]+", valor)):
			print("Error: La variable " + self.expresion.getVariable() + " es de tipo range. Formatos validos: 1..2 o 1,2")
			valor = raw_input()
			valor = Depurar(valor)
		else:
			prueba = valor.split(",")
			if (len(prueba) < 2):
				prueba = valor.split("..")
			if (not (IsInt(prueba[0]) and IsInt(prueba[1]))):
				print("Error: Las cotas no son del tipo int. Formatos validos: 1..2 o 1,2")
				valor = raw_input()
				valor = Depurar(valor)
				self.Range(valor)
			elif (not IsInt(prueba[0])):
				print("Error: La cota inferior no es del tipo int. Formatos validos: 1..2 o 1,2")
				valor = raw_input()
				valor = Depurar(valor)
				self.Range(valor)
			elif (not IsInt(prueba[1])):
				print("Error: La cota superior no es del tipo int. Formatos validos: 1..2 o 1,2")
				valor = raw_input()
				valor = Depurar(valor)
				self.Range(valor)
			else:
				inf = int(prueba[0])
				sup = int(prueba[1])
				if (inf > 2147483647 or inf < -2147483648 or sup > 2147483647 or sup < -2147483648):
					print("Error: El numero no se puede representarse en 32B.")
					valor = raw_input()
					valor = Depurar(valor)
					self.Range(valor)
				else:
					if (inf <= sup):
						variable.update(inf, sup)
					else:
						print("Error: La cota inferior es mayor que la superior. Formatos validos: 1..2 o 1,2")
						valor = raw_input()
						valor = Depurar(valor)
						self.Range(valor)

def IsInt(s):
	try: 
		int(s)
		return True
	except ValueError:
		return False

def imprimir(a):
	palabra = ""
	if (a.getTipo() == 'impresion'):
		palabra += a.ejecutar()
	else:
		res1, res2 = a.evaluar() 
		if (res2 == None):
			if (a.getTipo() == "bool"):
				res1, res2 = a.evaluar()
				if (res1):
					palabra = palabra + "true"
				else:
					palabra = palabra + "false"
			else:
				palabra = palabra + str(res1)
		else:
			palabra = palabra + str(res1) + ".." + str(res2)
	return palabra

def Depurar(valor):
	valor = valor.replace('\n', "")
	valor = valor.replace(' ', "")
	valor = valor.replace('\t', "")
	valor = valor.replace('\\t', "")
	valor = valor.replace('\\n', "")
	return valor

class Impresion:
	def __init__(self, expresion1, expresion2):
		self.expresion1 = expresion1
		self.expresion2 = expresion2
		
	def toString(self, tab, booleano):
		palabra = self.expresion1.toString(tab, True) + "\n"
		palabra += tab + "elemento: " + self.expresion2.toString(tab, False)
		return palabra

	def verificar(self, reserved = None):
		self.expresion1.verificar()
		self.expresion2.verificar()

	def getTipo(self):
		return "impresion"

	# Revisado
	def ejecutar(self):
		palabra = imprimir(self.expresion1)

		res1, res2 = self.expresion2.evaluar() 
		if (res2 == None):
			if (self.expresion2.getTipo() == "bool"):
				res1, res2 = self.expresion2.evaluar()
				if (res1):
					palabra = palabra + "true"
				else:
					palabra = palabra + "false"
			else:
				palabra = palabra + str(res1)
		else:
			palabra = palabra + str(res1) + ".." + str(res2)

		return palabra

class Funcion:
	def __init__(self, valor, expresion, linea, columna):
		self.valor = valor
		self.expresion = expresion
		self.linea = linea
		self.columna = columna

	def getLinea(self):
		return self.linea

	def getColumna(self):
		return self.columna

	def toString(self, tab, booleano):
		if (booleano == True):
			palabra = "elemento: "
		else:
			palabra = ""
		palabra += "FUNCION_EMB\n"
		tab = tab + "\t"
		palabra += tab + "nombre: " + str(self.valor) + "\n"
		palabra += tab + "argumento: " + self.expresion.toString(tab, False)
		return palabra

	def getTipo(self, flag = False):
		if (self.expresion.getTipo != "TypeError"):
			return "int"
		else:
			return "TypeError"

	def verificar(self):
		self.expresion.verificar()
		global ErrorEst
		if (self.expresion.getTipo() != "TypeError"):
			if (self.expresion.getTipo() != "range"):
				ErrorEst = True
				print("Error en línea %s, columna %s: el parametro de la funcion \"%s\" es del tipo \"%s\" y debe ser del tipo \"range\"." %(self.expresion.getLinea(), self.expresion.getColumna(), self.valor, self.expresion.getTipo()))

	# Revisado
	def evaluar(self):
		val, val2 = self.expresion.evaluar()
		res = None
		if (self.valor == "rtoi"):
			if (val == val2):
				res = val
			else:
				sys.exit("Error: El argumento de la funcion rtoi no posee las mismas cotas.")
		elif (self.valor == "top"):
			res = val
		elif (self.valor == "bottom"):
			res = val2
		else:
			res = val - val2 + 1

		return res, None

class ExpresionUnaria:
	def __init__(self, tipo, operador, operando, linea, columna, simbolo):
		self.tipo = tipo
		self.operador = operador
		self.operando = operando
		self.linea = linea
		self.columna = columna
		self.simbolo = simbolo

	def getLinea(self):
		return self.linea
	
	def getColumna(self):
		return self.columna
		
	def toString(self, tab, booleano):
		if (booleano == True):
			palabra = "elemento: "
		else:
			palabra = "EXPRESION_UN\n"
		tab = tab + "\t"
		if (type(self.operador) is str):
			palabra += tab + "operador: "+ str(self.tipo) + "\n"
		else:
			palabra += tab + "operador: "  + self.operador.toString(tab, False) + "\n"
		palabra += tab + "operando:  "  + self.operando.toString(tab, False)
		return palabra

	def getTipo(self, flag = False):
		# Tenemos un error interno, entonces el tipo de la expresion sigue tienendo errores
		if (self.operando.getTipo() == "TypeError"):
			return "TypeError"

		# El operador es el TkNot, la expresion tiene que ser bool
		if (self.tipo == "NEGACION" and self.operando.getTipo() == "bool"):
			return "bool"

		# El operador es un + o -, la expresion tiene que ser int
		if ((self.tipo == "MAS_UNARIO" or self.tipo == "MENOS_UNARIO")
			and self.operando.getTipo() == "int"):
			return "int"

		# No encontramos nada... Devolvemos TypeError
		return "TypeError"

	def verificar(self):
		self.operando.verificar()
		a = self.operando

		if (self.getTipo() == "TypeError" and a.getTipo() != "TypeError"):
			global ErrorEst
			ErrorEst = True
			impr = "Error en línea " + str(self.linea) + ", columna " + str(self.columna) + ": Intento de uso del operador unario \"" + str(self.operador) + "\" con la "
			if (a.getTipo(True) == "variable"):
				impr = impr + "variable \"" + str(a.getVariable()) + "\""
			else:
				impr = impr + "expresion \"" + str(a.getExpresion()) + "\""

			impr = impr + " del tipo \"" + str(a.getTipo()) + "\"."
			print(impr)

	def getExpresion(self):
		return self.simbolo + " " + self.operando.getExpresion()

	# Revisado
	def evaluar(self):
		val, val2 = self.operando.evaluar()
		res = None
		if (self.tipo == "NEGACION"):
			res = not val
		else:
			if (self.tipo == "MAS_UNARIO"):
				res = val
			else:
				res = -val
		return res, None

class ExprBinaria:
	def __init__(self, operacion, tipo, operando1, operando2, relacional, linea, columna, simbolo):
		self.operacion = operacion
		self.tipo = tipo
		self.operando1 = operando1
		self.operando2 = operando2
		self.relacional = relacional
		self.linea = linea
		self.columna = columna
		self.simbolo = simbolo
		self.valor = None
		self.valor2 = None

		self.opBool = set(['And', 'Or'])
		self.opInt = set(['Construccion','Modulo', 'Div', 'Resta', 'Igual que', 'No igual a', 'Menor que', 'Menor Igual que', 'Mayor que', 'Mayor Igual que'])
		self.opRango = set(['Interseccion'])

		self.devuelveBool = set(['Igual que', 'No igual a', 'Menor que', 'Menor Igual que', 'Mayor que', 'Mayor Igual que'])
		self.devuelveInt = set(['Modulo', 'Div', 'Resta', 'Mas', 'Por'])

	def getLinea(self):
		return self.linea
	
	def getColumna(self):
		return self.columna

	def toString(self, tab, booleano):
		if (booleano == True):
			palabra = "elemento: "
		else:
			palabra = ""
		tab = tab + "\t"
		palabra += "EXPRESION_BIN\n"
		palabra += tab + "operador: " + str(self.operacion) + "\n"
		if ( type(self.operando1) is str):
			palabra += tab + "operando izq: " + self.expresion
		else:
			palabra += tab + "operando izq: " + self.operando1.toString(tab, False) + "\n"
		if (type(self.operando2) is str):
			palabra += tab + "operando der: " + self.expresion
		else:
			palabra += tab + "operando der: " + self.operando2.toString(tab, False)
		return palabra

	def getTipo(self, flag = False):
		#print "Intentando comparar un operador de tipo " + str(self.operando1.getTipo()) + " operando 2 con" + str(self.operando2.getTipo()) + "OPERADOR " + str(self.operacion)
		# Tenemos un error interno, entonces el tipo de la expresion sigue tienendo errores
		if (self.operando1.getTipo() == "TypeError" or self.operando1.getTipo() == "TypeError"):
			return "TypeError"

		# No tenemos errores, verificamos los tipos
		# El operador es un operador que devuelve booleanos
		if (self.operacion == "Or" or self.operacion == "And"
			and (self.operando1.getTipo() == "bool" and self.operando2.getTipo() == "bool")):
			return "bool"

		if (self.operacion in self.devuelveBool 
		and ((self.operando1.getTipo() == "int" and self.operando2.getTipo() == "int") or (self.operando1.getTipo() == "range"  and self.operando2.getTipo() == "range"))):
			return "bool"

		if (self.operacion == 'Pertenece'
			and (self.operando1.getTipo() == "int" and self.operando2.getTipo() == "range")):
			return "bool"

		# El operador devuelve int
		if (self.operacion in self.devuelveInt
			and (self.operando1.getTipo() == "int" and self.operando2.getTipo() == "int")):
			return "int"

		# El operador devuelve range
		if (self.operacion == 'Construccion'
			and (self.operando1.getTipo() == "int" and self.operando2.getTipo() == "int")):
				return "range"

		if (self.operacion == 'Interseccion' or self.operacion == 'Mas'
			and (self.operando1.getTipo() == "range" and self.operando2.getTipo() == "range")):
			return "range"

		if (self.operacion == 'Por'
			and (self.operando1.getTipo() == "range" and self.operando2.getTipo() == "int")):
			return "range"

		# No encontramos nada... Devolvemos TypeError
		return "TypeError"

	def verificar(self):
		self.operando1.verificar()
		self.operando2.verificar()
		a = self.operando1
		b = self.operando2
		if (self.getTipo() == "TypeError" and a.getTipo() != "TypeError" and b.getTipo() != "TypeError"):
			global ErrorEst
			ErrorEst = True
			impr = "Error en línea " + str(self.linea) + ", columna " + str(self.columna) + ": Intento de utilizar el operador \"" + str(self.operacion) + "\" con la "
			if (a.getTipo(True) == "variable"):
				impr = impr + "variable \"" + str(a.getVariable()) + "\""
			else:
				impr = impr + "expresion \"" + str(a.getExpresion()) + "\""

			impr = impr + " del tipo \"" + a.getTipo() + "\" y una "

			if (b.getTipo(True) == "variable"):
				impr = impr + "variable \"" + str(b.getVariable()) + "\""
			else:
				impr = impr + "expresion \"" + str(b.getExpresion()) + "\""

			impr = impr + " del tipo \"" + str(b.getTipo()) + "\"."
			print(impr)

	def getExpresion(self):
		return str(self.operando1.getExpresion()) + " " + str(self.simbolo) + " " + str(self.operando2.getExpresion())

	# Revisado?
	def evaluar(self):
		resultado11, resultado12 = self.operando1.evaluar()
		resultado21, resultado22 = self.operando2.evaluar()

		Operaciones = {
			# Aritmeticas:
			'Mas' : Suma,
			'Resta' : Resta,
			'Por' : Mult,
			'Div' : Div,
			'Mod' : Mod,
			# Booleanos:
			'And' : And,
			'Or' : Or,
			# Relacionales:
			'Igual que' : Igualque,
			'No igual a' : Desigualque,
			'Mayor que' : Mayorque,
			'Mayor Igual que' : MayorIgualque,
			'Menor que' : Menorque,
			'Menor Igual que' : MenorIgualque,
			# Rangos:
			'Construccion' : Construccion,
			'Interseccion' : Interseccion,
			'Pertenece' : Pertenece,
		}

		return Operaciones[self.operacion](resultado11, resultado12, resultado21, resultado22)

	def getValor(self):
		return self.valor

	def getValor2(self):
		return self.valor2

# Aritmeticos:

def Suma(op11, op12, op21, op22):
	# Son enteros
	if (op12 == None and op22 == None):
		resultado = op11 + op21
		if (resultado > 2147483647 or resultado < -2147483648):
			sys.exit("Error: Resultado no puede representarse en 32 bits.")
		else:
			return resultado, None
	# Es union de rangos
	else:
		if (op11 <= op21 and op12 <= op22):
			return op11, op22
		elif (op11 > op21 and op12 <= op22):
			return op21, op22
		elif (op11 <= op21 and op12 > op22):
			return op11, op12
		elif (op11 > op21 and op12 > op22):
			return op21, op12
		else:
			sys.exit("Error: Que no deberia pasar.")

def Resta(op11, op12, op21, op22):
	resultado = op11 - op21
	if (resultado > 2147483647 or resultado < -2147483648):
		sys.exit("Error: Resultado no puede representarse en 32 bits.")
	else:
		return resultado, None

def Mult(op11, op12, op21, op22):
	# Multiplicacion entera
	if (op12 == None and op22 == None):
		resultado = op11 * op21
		if (resultado > 2147483647 or resultado < -2147483648):
			sys.exit("Error: Resultado no puede representarse en 32 bits.")
		else:
			return resultado, None
	# Es escala de rangos
	else:
		if (op21 >= 0):
			return (op11 * op21), (op12 * op21)
		else:
			return (op12 * op21), (op11 * op21)

def Div(op11, op12, op21, op22):
	if (op21 == 0):
		sys.exit("Error: Intento de división por cero.")

	resultado = op11 / op21
	if (resultado > 2147483647 or resultado < -2147483648):
		sys.exit("Error: Resultado no puede representarse en 32 bits.")
	else:
		return resultado, None

def Mod(op11, op12, op21, op22):
	resultado = op11 % op22
	if (resultado > 2147483647 or resultado < -2147483648):
		sys.exit("Error: Resultado no puede representarse en 32 bits.")
	else:
		return resultado, None

# Booleanos:
def And(op11, op12, op21, op22):
	return (op11 and op21), None

def Or(op11, op12, op21, op22):
	return (op11 or op21), None

# Relacionales:
def Igualque(op11, op12, op21, op22):
	if (op12 == None and op22 == None):
		return (op11 == op21), None
	else:
		return (op11 == op21 and op12 == op22), None

def Desigualque(op11, op12, op21, op22):
	if (op12 == None and op22 == None):	
		return (op11 != op21), None
	else:
		return (op11 != op21 and op12 != op22), None

def Mayorque(op11, op12, op21, op22):
	if (op12 == None and op22 == None):
		return (op11 > op21), None
	else:
		return (op11 > op22), None
	
def MayorIgualque(op11, op12, op21, op22):
	if (op12 == None and op22 == None):
		return (op11 >= op21), None
	else:
		return (op11 >= op22), None

def Menorque(op11, op12, op21, op22):
	if (op12 == None and op22 == None):
		return (op11 < op21), None
	else:
		return (op12 < op21), None

def MenorIgualque(op11, op12, op21, op22):
	if (op12 == None and op22 == None):
		return (op11 <= op21), None
	else:
		return (op12 <= op21), None

# Rangos:
def Construccion(op11, op12, op21, op22):
	if (op11 > op21):
		sys.exit("Error: Rango donde la cota inferior es mayor que la superior.")
	else:
		return op11, op21

# Deberia funcionar... Super ineficiente
def Interseccion(op11, op12, op21, op22):
	op1 = range(op11, op12 + 1)
	op2 = range(op21, op22 + 1)
	k = 1
	l = []
	for i in op1:
		for j in op2:
			if (i == j):
				l.insert(k,i)
				k = k + 1

	if (len(l) == 0):
		sys.exit("Error: La interseccion de rangos es vacia.")
	else:
		return l[0], l[len(l) - 1]

def Pertenece(op11, op12, op21, op22):
	# Rehacer a <= b <= c asi
	return (op11 >= op21 and op11 <= op22), None

#---------------------------#
#	Fin de clases			#
#---------------------------#

#-------------------#
# Precedencia		#
#-------------------#

#Se define la precedencia de los operadores.

precedence = (
	#('left','Impresion'),
	('nonassoc','Then'),
	('nonassoc', 'Else'),
	# Expresiones logicos.
	('left','TkOr'),
	('left','TkAnd'),
	('right', 'TkNot'),
	# De menor a mayor
	('nonassoc', 'TkPertenece'),
	# Operadores relacionales.
	('nonassoc' ,'TkIgual','TkDesIgual'),
	('nonassoc', 'TkMayor', 'TkMayorIgual', 'TkMenor', 'TkMenorIgual'),
	# Expresiones aritmeticas.
	('left','TkInterseccion'),
	('left', 'TkSuma', 'TkResta'),
	('left', 'TkAsterisco','TkDiv','TkModulo'),
	('left', 'TkConstruccion'),
	('right','RestaU', 'SumaU')
)

#------------------#
# Fin Precedencia  #
#------------------#

#---------------------------------------------------#
#	Producciones de la gramática					#
#---------------------------------------------------#

def p_PROGRAMA(p):
	"""
	PROGRAMA : TkProgram INSTRUCCION
	"""
	p[0] = p[2]
	if (not (Error)):
		global TS
		TS = SymTable(None)
		p[0].verificar()
		if (not (ErrorEst)):
			TS = SymTable(None)
			p[0].ejecutar()

			#global impresion
			#impresion += p[0].toString('', False)
			#print impresion

def p_INSTRUCCION(p):
	"""
	INSTRUCCION : ASIGNACION
		| CONDICIONAL
		| CASE
		| REPETICION_DET
		| REPETICION_INDET
		| BLOQUE
		| INPUT
		| OUTPUT
	"""
	p[0] = p[1]

def p_ASIGNACION(p):
	"""
	ASIGNACION : VARIABLE TkAsignacion EXPRESION
	"""
	p[0] = Asignacion(p[1], p[3])

def p_CONDICIONAL(p):
	"""
	CONDICIONAL : TkIf EXPRESION TkThen INSTRUCCION ELSE 
	"""
	p[0] = Condicional(p[2], p[4], p[5])

def p_ELSE(p):
	"""
	ELSE : TkElse INSTRUCCION %prec Else
		| %prec Then
	"""
	if (len(p) > 1): p[0] = p[2]
	else: p[0] = "vacio"

def p_CASE(p):
	"""
	CASE : TkCase EXPRESION TkOf CASECOND TkEnd
	"""
	p[0] = Case(p[2], p[4])

def p_CASECOND(p):
	"""
	CASECOND : EXPRESION TkFlechaCase INSTRUCCION TkPuntoYComa CASECONDDOS
	"""
	p[0] = CaseCond(p[1], p[3], p[5])

def p_CASECONDDOS(p):
	"""
	CASECONDDOS : EXPRESION TkFlechaCase INSTRUCCION TkPuntoYComa CASECONDDOS
		| 
	"""
	if (len(p) > 1):
		p[0] = CaseCond(p[1], p[3], p[5])
	else:
		p[0] = "vacio"

def p_REPETICION_DET(p):
	"""
	REPETICION_DET : TkFor VARIABLE TkIn EXPRESION TkDo INSTRUCCION
	"""
	p[0] = RepeticionDet(p[2], p[4], p[6])

def p_REPETICION_INDET(p):
	"""
	REPETICION_INDET : TkWhile EXPRESION TkDo INSTRUCCION
	"""
	p[0] = RepeticionIndet(p[2], p[4])

def p_BLOQUE(p):
	"""
	BLOQUE : TkBegin DECLARE SECUENCIACION TkEnd
	"""
	p[0] = Bloque(p[2], p[3], p[4])

def p_DECLARE(p):
	"""
	DECLARE : TkDeclare LINEADECLARACION
		| 
	"""
	if (len(p) > 1):
		p[0] = p[2]
	else: 
		p[0] = "vacio"

def p_SECUENCIACION(p):
	"""
	SECUENCIACION : SECUENCIACION TkPuntoYComa INSTRUCCION
		| INSTRUCCION 
	"""
	if (len(p) <= 2): p[0] = p[1]
	else: p[0] = Secuenciacion(p[1], p[3])
	

def p_LINEADECLARACION(p):
	"""
	LINEADECLARACION : LINEADECLARACION TkPuntoYComa VARIABLES TkAs TYPE
		| VARIABLES TkAs TYPE
	"""
	if (len(p) <= 4):
		k = p.lineno(2)
		s = p.lexpos(2)
		p[0] = LineaDeclaracion(p[1], p[3], 'vacio', k, find_column_parser(text, s, k) - 2)
	else:
		k = p.lineno(4)
		s = p.lexpos(4)
		p[0] = LineaDeclaracion(p[3], p[5], p[1], k, find_column_parser(text, s, k) - 2)

def p_TYPE(p):
	"""
	TYPE : TkInt
		| TkBool
		| TkRange
	"""
	p[0] = p[1]

def p_VARIABLES(p):
	"""
	VARIABLES : VARIABLES TkComma VARIABLE
		| VARIABLE
	"""
	if (len(p) <= 2):
		p[0] = p[1]
	else:
		k = p.lineno(2)
		s = p.lexpos(2)
		p[0] = Variables(p[1], p[3], k, find_column_parser(text, s, k))

def p_INPUT(p):
	"""
	INPUT : TkRead VARIABLE
	"""
	p[0] = IO('READ', p[2])

def p_OUTPUT(p):
	"""
	OUTPUT : TkWrite IMPRESION
		| TkWriteLn IMPRESION
	"""
	if (p[1] == 'write'): p[0] = IO('WRITE', p[2])
	else: p[0] = IO('WRITELN', p[2]) 

def p_IMPRESION(p):
	"""
	IMPRESION : IMPRESION TkComma STRINEXP
		| STRINEXP
	"""
	if (len(p) > 2): p[0] = Impresion(p[1], p[3])
	else: p[0] = p[1]
	
def p_STRINEXP(p):
	"""
	STRINEXP : TkString
		| EXPRESION
	"""
	if (type(p[1]) is str): 
		p[0] = Simple('CADENA', p[1])
	else: 
		p[0] = p[1]

def p_EXPRESION(p):
	"""
	EXPRESION : EXPRBOOL
		| EXPREARITME
		| VARIABLE
		| EXPRANGO
		| TkParAbre EXPRESION TkParCierra
		| FUNCION
	"""
	if (len(p) > 2): p[0] = p[2]
	else: p[0] = p[1]

def p_FUNCION(p):
	"""
	FUNCION : FUNCIONES TkParAbre EXPRESION TkParCierra
	"""
	p[0] = Funcion(p[1], p[3],p.lineno(2),find_column_parser(text,p.lexpos(2) ,p.lineno(2)))

def p_FUNCIONES(p):
	"""
	FUNCIONES : TkBottom
		| TkRtoi
		| TkLength
		| TkTop
	"""
	p[0] = p[1]

def p_EXPRANGO(p):
	"""
	EXPRANGO : EXPRESION TkConstruccion EXPRESION
		| EXPRESION TkInterseccion EXPRESION
		| EXPRESION TkPertenece EXPRESION
	"""
	k = p.lineno(2)
	s = find_column_parser(text, p.lexpos(2), k) - 2
	if (p[2] == '..'): p[0] = ExprBinaria('Construccion', 'range', p[1], p[3], False, k, s, p[2])
	elif (p[2] == '<>'):  p[0] = ExprBinaria('Interseccion','range', p[1], p[3], False, k, s, p[2])
	elif (p[2] == '>>'):  p[0] = ExprBinaria('Pertenece','range', p[1], p[3], False, k, s, p[2])

def p_VARIABLE(p):
	"""
	VARIABLE : TkId
	"""
	k= p.lineno(1)
	s= p.lexpos(1)
	p[0] = Simple('VARIABLE', p[1], k, find_column_parser(text, s, k))


def p_NUMERO(p):
	"""
	NUMERO : TkNum
	"""
	k= p.lineno(1)
	s= p.lexpos(1)
	p[0] = Simple('CONSTANTE_ENT', p[1], k, find_column_parser(text, s, k))

def p_EXPRELACIONAL(p):
	"""
	EXPRELACIONAL : EXPRESION TkIgual EXPRESION
		| EXPRESION TkDesIgual EXPRESION
		| EXPRESION TkMenor EXPRESION
		| EXPRESION TkMenorIgual EXPRESION
		| EXPRESION TkMayor EXPRESION
		| EXPRESION TkMayorIgual EXPRESION
	"""
	k = p.lineno(2)
	s = find_column_parser(text, p.lexpos(2), k) - 2
	if (p[2] == '=='): p[0] = ExprBinaria('Igual que', 'boolean', p[1], p[3], True, k, s, p[2])
	elif (p[2] == '/='): p[0] = ExprBinaria('No igual a', 'boolean', p[1], p[3], True, k, s, p[2])
	elif (p[2] == '<'): p[0] = ExprBinaria('Menor que', 'boolean', p[1], p[3], True, k, s, p[2])
	elif (p[2] == '<='): p[0] = ExprBinaria('Menor Igual que', 'boolean', p[1], p[3], True, k, s, p[2])
	elif (p[2] == '>'): p[0] = ExprBinaria('Mayor que', 'boolean', p[1], p[3], True, k, s, p[2])
	elif (p[2] == '>='): p[0] = ExprBinaria('Mayor Igual que', 'boolean', p[1], p[3], True, k, s, p[2])

def p_EXPREARITME(p):
	"""
	EXPREARITME : BINEXPRARITM
		| UNEXPRARITME
		| NUMERO
	"""
	p[0] = p[1]

def p_BINEXPRARITM(p):
	"""
	BINEXPRARITM : EXPRESION TkSuma EXPRESION
		| EXPRESION TkResta EXPRESION
		| EXPRESION TkAsterisco EXPRESION
		| EXPRESION TkDiv EXPRESION
		| EXPRESION TkModulo EXPRESION
	"""
	k = p.lineno(2)
	s = find_column_parser(text, p.lexpos(2), k)
	if (p[2] == '+'): p[0] = ExprBinaria('Mas', 'integer', p[1], p[3], False, k, s, p[2])
	elif (p[2] == '-'): p[0] = ExprBinaria('Resta', 'integer', p[1], p[3], False, k, s, p[2])
	elif (p[2] == '*'): p[0] = ExprBinaria('Por', 'integer', p[1], p[3], False, k, s, p[2])
	elif (p[2] == '/'): p[0] = ExprBinaria('Div', 'integer', p[1], p[3], False, k, s, p[2])
	elif (p[2] == '%'): p[0] = ExprBinaria('Modulo', 'integer', p[1], p[3], False, k, s, p[2])

def p_UNEXPRARITME(p):
	"""
	UNEXPRARITME : TkResta EXPRESION %prec RestaU
		| TkSuma EXPRESION %prec SumaU
	"""
	k = p.lineno(1)
	s = find_column_parser(text, p.lexpos(1), k) + 1
	if (p[1] == '-'):
		p[0] = ExpresionUnaria('MENOS_UNARIO', p[1], p[2], k, s, p[1])
	else: 
		p[0] = ExpresionUnaria('MAS_UNARIO', p[1], p[2], k, s, p[1])
	
def p_EXPRBOOL(p):
	"""
	EXPRBOOL : EXPRBINBOOL
		| BOOL
		| EXPRELACIONAL
		| UNEXPRBOOL
	"""
	p[0] = p[1]

def p_EXPRBINBOOL(p):
	"""
	EXPRBINBOOL : EXPRESION TkOr EXPRESION
		| EXPRESION TkAnd EXPRESION
	"""
	k = p.lineno(2)
	s = find_column_parser(text, p.lexpos(2), k)
	if (p[2] == "or"): p[0] = ExprBinaria('Or', 'boolean', p[1], p[3], False, k, s, p[2])
	else: p[0] = ExprBinaria('And', 'boolean', p[1], p[3], False, k, s, p[2])

def p_UNEXPRBOOL(p):
	"""
	UNEXPRBOOL : TkNot EXPRESION
	"""
	k = p.lineno(1)
	s = find_column_parser(text, p.lexpos(1), k)
	p[0] = ExpresionUnaria('NEGACION', p[1], p[2], k, s, p[1])

def p_BOOL(p):
	"""
	BOOL : TkTrue
		| TkFalse
	"""
	k = p.lineno(1)
	s = find_column_parser(text, p.lexpos(1), k)
	p[0] = Simple('BOOLEANO', p[1], k, s)

def p_error(p):
	global Error
	if (Error != True and p != None):
		Error = True
		sys.exit("Error de sintaxis en la linea %s, columna %s: token '%s' inesperado." %(p.lineno , find_column(text, p), p.value));

#---------------------------------------------------#
#	Fin de producciones de la gramática				#
#---------------------------------------------------#

####################################################
####################################################

#---------------------------------------------------#
#			MAIN									#
#---------------------------------------------------#

# Se construye el lexer.
lexer = lex.lex()

# Se toma el archivo por entrada estandar.
archivo = sys.argv[1]
f = open(archivo, "r")
text = f.read()

# Se pasa al lexer.
lexer.input(text)
# Se construye el parser
parser = yacc.yacc()
# Se pasa al parser.
result = parser.parse(text)


#---------------------------------------------------#
#		FIN MAIN									#
#---------------------------------------------------#
