import java_cup.runtime.*;
import java.util.Vector;

scan with {: return getScanner().next_token(); :};
parser code {:
			Atributos funcion = new Atributos();
			Vector lista = new Vector();
			Quads quads = new Quads();
			int tope = 0;
			int param = 0;
			int actual = 0; //tabla que se esta utilizando actualmente
			TablaHash hash[] = {new TablaHash(),new TablaHash()} ; // Lista de tablas hash
			public boolean temporales[] = 	{false
											,false
											,false
											,false
											,false
											,false
											,false
											,false
											,false
											,false
											};
			
			String newtemp()
			{
				for (int i = 0;i<10;i++)
					if (!temporales[i])
						{
						temporales[i] = true;
						return new String("$t"+i);
						}
				return null;
			}
			
			void freetemp(String llave)
			{
				System.out.println("free "+llave);
				if (llave.charAt(0)=='$')
					{
					temporales[Integer.valueOf(String.valueOf(llave.charAt(2))).intValue()] = false;
					}
			}
			
			void backpatch(Vector l,int q)
			{
				if (l != null)
					{
					for (int i=0;i<l.size();i++)
						{
						int tq = ((Integer)(l.get(i))).intValue();
						((Quad)(quads.get(tq))).result = String.valueOf(q);
						}
					}
			}
			
			Vector merge(Vector l1,Vector l2)
			{
				if (l1 == null && l2 == null) 
					return new Vector();
				if (l1 == null) 
					return new Vector(l2);
				if (l2 == null)
					return new Vector(l1);
				Vector l3 = new Vector(l1);
				for (int i = 0;i<l2.size();i++)
					l3.add(l2.get(i));
				return l3;
			}
			
			:};
	
terminal PACKAGE, IS, BEGIN, END, SEMI;
terminal VPOINTS;
terminal COMMA;
terminal ARRAY, LPAR, RPAR, OF; 
terminal INTEGER, CHARACTER, BOOLEAN;
terminal PROCEDURE;
terminal IN, OUT;
terminal ASSIGN; 
terminal IF, THEN, ELSEIF, ELSE;
terminal LOOP, WHILE, FOR, REVERSE;
terminal EXIT, WHEN;
terminal RETURN;
terminal NULL;
terminal READ;
terminal READLN;
terminal WRITE;
terminal WRITELN;
terminal HPOINTS;
terminal AP, VAL, CHAR, FIRST, LAST;
terminal AND, OR;
terminal NOT, ABS;
terminal TRUE, FALSE;
terminal LT, LE, EQ, NEQ, GT, GE;
terminal PLUS, MINUS;
terminal TIMES, DIV, MOD;
terminal UMINUS;

terminal String NCHAR;
terminal String ID;
terminal Integer NUMBER;

non terminal MicroAda;
non terminal Declarations, Declaration , ObjDeclaration;
non terminal Atributos IDList, SimpleType, Type;
non terminal ProcDeclaration;
non terminal ProcBody;
non terminal ProcDeclarations;
non terminal Parameters, Params, ParamsList;
non terminal Atributos IDParamsList, ParamMode, ParamType;
non terminal Atributos Statements, Statement, ProcCall;
non terminal Atributos ParamCallList;
non terminal Atributos Expression;
non terminal AssignStatement;
non terminal Atributos PossibleAssign;
non terminal Atributos PossibleReverse;
non terminal Atributos M,N;

precedence left OR;
precedence left AND;
precedence right NOT;
precedence nonassoc GT,GE,LT,LE,EQ,NEQ;
precedence left PLUS, MINUS; 
precedence left TIMES,DIV,MOD;
precedence right ABS, UMINUS;

start with MicroAda;

MicroAda::= PACKAGE ID IS Declarations BEGIN 
	{:
	parser.quads.emit("label","main","null","null");
	parser.quads.emit("sinit",String.valueOf(parser.hash[parser.actual].size),"null","null");
	parser.quads.emit("mov","$sp","null","$s2");
	:}
	Statements:s1 END  SEMI 	
	{:
	int tq = parser.quads.nextQuad();
	parser.backpatch(s1.exitlist,tq); //fix
	//t1.nextlist = null;
	parser.quads.emit("label","$L"+tq,"null","null");
	parser.quads.emit("send",String.valueOf(parser.hash[parser.actual].size),"null","null");
	parser.quads.emit("halt","null","null","null");
	:}
;



Declarations::= Declarations Declaration {::}
	| {::}
;

Declaration::= ObjDeclaration {::}
	| ProcDeclaration {::}
;

ObjDeclaration::= 	ID:id1 IDList:l1 
					{:
					if (parser.hash[parser.actual].Existe(id1))
					{
						System.out.println("El id ya existe "+id1);
						System.exit(1);
					}
					Atributos  t1 = new Atributos();
					t1.tipo = l1.tipo;
					t1.arreglo = l1.arreglo;
					t1.modo = l1.modo;
					t1.width = l1.width;
					t1.min=l1.min;
					t1.max=l1.max;
					t1.k = l1.k;
					t1.offset = parser.hash[parser.actual].offset;
					parser.hash[parser.actual].offset+=t1.width;
					parser.hash[parser.actual].size+=t1.width;
					
					t1.place = new String(id1);
					parser.hash[parser.actual].Mete(t1);
					RESULT = l1;
					:}
;

IDList::= COMMA ID:id1 IDList:l1 
					{:
					if (parser.hash[parser.actual].Existe(id1))
					{
						System.out.println("El id ya existe "+id1);
						System.exit(1);
					}
					Atributos  t1 = new Atributos();
					t1.tipo = l1.tipo;
					t1.arreglo = l1.arreglo;
					t1.modo = l1.modo;
					t1.width = l1.width;
					t1.min=l1.min;
					t1.max=l1.max;
					t1.k=l1.k;
					t1.offset = parser.hash[parser.actual].offset;
					parser.hash[parser.actual].offset+=t1.width;
					parser.hash[parser.actual].size+=t1.width;
					
					t1.place = new String(id1);
					parser.hash[parser.actual].Mete(t1);
					RESULT = l1;
					:}
	| VPOINTS Type:t1 SEMI 
	{:
	RESULT = t1;
	:}
;

Type::= SimpleType:t1 
	{:RESULT = t1;:}
	
	| ARRAY LPAR NUMBER:n1 HPOINTS NUMBER:n2 RPAR OF SimpleType:s1 
	{:
	if (n1.intValue()>n2.intValue()||n2.intValue()-n1.intValue()>=32)
		{
		System.out.println("Error de Rango en arreglo");
		System.exit(1);
		}
	Atributos t1 = new Atributos();
	t1.tipo = s1.tipo;
	t1.min = n1.intValue();
	t1.max = n2.intValue();
	t1.arreglo = true;
	t1.width = (t1.max - t1.min +1)*s1.width;
	t1.k = s1.k;
	RESULT = t1;
	:}
;

SimpleType::= 	INTEGER 
				{:
				Atributos t1 = new Atributos();
				t1.tipo = 0;
				t1.width = 4;
				t1.k = 4;
				RESULT = t1;
				:}
| CHARACTER 	{:
				Atributos t1 = new Atributos();
				t1.tipo = 1;
				t1.width = 4;
				t1. k = 4;
				RESULT = t1;
				:}
| BOOLEAN 		{:
				Atributos t1 = new Atributos();
				t1.tipo = 2;
				t1.width = 1;
				t1. k = 1;
				RESULT = t1;
				:}
;



ProcDeclaration::= 	PROCEDURE ID:id1
					{:
					if (parser.hash[parser.actual].Existe(id1))
					{
						System.out.println("El id ya existe "+id1);
						System.exit(1);
					}
					Atributos t1 = new Atributos();
					t1.proc = true;
					t1.place = new String(id1);
					parser.hash[parser.actual].Mete(t1);
					parser.actual = parser.actual +1;
					t1 = new Atributos();
					t1.proc = true;
					t1.place = new String(id1);
					parser.hash[parser.actual].Mete(t1);
					parser.tope = 0;
					parser.funcion.parametros = new Vector();
					parser.funcion.parametros.clear();
					parser.quads.emit("label",id1,"null","null");
					:} 
					Parameters
					{:
					Atributos t1 = parser.hash[parser.actual].Recupera(id1);
					t1.parametros = new Vector(parser.funcion.parametros);
					t1 = parser.hash[parser.actual-1].Recupera(id1);
					t1.parametros = new Vector(parser.funcion.parametros);
					
					for (int i =0;i<parser.funcion.parametros.size();i++)
						{
						Atributos t2 =  (Atributos)(parser.funcion.parametros.elementAt(i));
						t1 = parser.hash[parser.actual].Recupera(t2.place);
						t1.numerop = i;
						}
					:} 
					ProcBody SEMI 
					{:
					parser.hash[parser.actual].clear();
					parser.actual = parser.actual -1;
					parser.quads.emit("return","null","null","null");
					:}
;

ProcBody::= IS ProcDeclarations 
	{:
	parser.quads.emit("sinit",String.valueOf(parser.hash[parser.actual].size),"null","null");
	:}
	BEGIN Statements END 
	{:
	parser.quads.emit("send",String.valueOf(parser.hash[parser.actual].size),"null","null");
	parser.hash[parser.actual].size = 24;
	parser.hash[parser.actual].offset = 24;
	:}
	| {::}
;


ProcDeclarations::= ProcDeclarations ObjDeclaration {::}
	| {::}
;


Parameters::= LPAR Params ParamsList RPAR {::}
	| {::}
;

ParamsList::= SEMI Params ParamsList {::}
	| {::}
;

Params::= ID:id1 IDParamsList:l1 
	{:
	if (parser.funcion.parametros.size()==4)
		{
		System.out.println("Se excedio en el numero de parametros "+id1);
		System.exit(1);
		}
	
	if (parser.hash[parser.actual].Existe(id1))
		{
		System.out.println("El id ya existe "+id1);
		System.exit(1);
		}
	Atributos t1 = new Atributos();
	t1.tipo = l1.tipo;
	t1.arreglo = l1.arreglo;
	t1.modo = l1.modo;
	t1.place = id1;
	t1.parametro = true;
	t1.numerop = parser.tope; 
	parser.hash[parser.actual].Mete(t1);
	System.out.println(parser.funcion.parametros.size());
	parser.funcion.parametros.add(parser.tope,t1);
	parser.tope = parser.funcion.parametros.size();
	RESULT = l1;
	:}
;

IDParamsList::= COMMA ID:id1 IDParamsList:l1 
	{:
	if (parser.funcion.parametros.size()==4)
		{
		System.out.println("Se excedio en el numero de parametros "+id1);
		System.exit(1);
		}
	if (parser.hash[parser.actual].Existe(id1))
		{
		System.out.println("El id ya existe "+id1);
		System.exit(1);
		}
	Atributos t1 = new Atributos();
	t1.tipo = l1.tipo;
	t1.arreglo = l1.arreglo;
	t1.modo = l1.modo;
	t1.place = id1;
	t1.parametro = true;
	t1.numerop = parser.tope;
	parser.hash[parser.actual].Mete(t1);
	parser.funcion.parametros.add(parser.tope,t1);
	RESULT = l1;
	:}
	
	| VPOINTS ParamMode:m1 ParamType:l1 
	{:
	Atributos t1 = l1;
	t1.modo = m1.modo;
	RESULT = t1;
	:}
;

ParamMode::= IN 
	{:
	Atributos t1 = new Atributos();
	t1.modo = 1;
	RESULT = t1;
	:}
	| OUT 
	{:
	Atributos t1 = new Atributos();
	t1.modo = 2;
	RESULT = t1;
	:}
	| IN OUT 
	{:
	Atributos t1 = new Atributos();
	t1.modo = 0;
	RESULT = t1;
	:}
	| 
	{:
	Atributos t1 = new Atributos();
	t1.modo = 1;
	RESULT = t1;
	:}
;

ParamType::= SimpleType:s1
	{:
	RESULT = s1;
	:}
	| ARRAY OF SimpleType:s1 
	{:
	Atributos t1 = s1;
	t1.arreglo = true;
	RESULT = t1;
	:}
;

Statements::= Statement:s1 {:RESULT = s1;:}
	| Statement:s1 Statements:s2 
	{:
	
	if (s2==null)
		System.out.println("PUTA MADRE");
	s2.truelist = parser.merge(s1.truelist,s2.truelist);
	
	s2.falselist = parser.merge(s1.falselist,s2.falselist);
	
	s2.nextlist = parser.merge(s1.nextlist,s2.nextlist);
	
	s2.exitlist = parser.merge(s1.exitlist,s2.exitlist);
	
	
	RESULT = s2;
	:}
;

Statement::= ProcCall 
	{:
	Atributos t1 = new Atributos();
	//t1.nextlist = null;
	RESULT = t1;
	:}
	| AssignStatement 
	{:
	Atributos t1 = new Atributos();
	//t1.nextlist = null;
	RESULT = t1;
	:}
	| NULL SEMI 
	{:
	Atributos t1 = new Atributos();
	//t1.nextlist = null;
	RESULT = t1;
	:}
	| RETURN SEMI 
	{:
	Atributos t1 = new Atributos();
	//t1.nextlist = null;
	parser.quads.emit("return","null","null","null");
	RESULT = t1;
	:}
	| WHILE M:m1 Expression:e1
	{:
	if (e1.tipo!=2)
		{
		System.out.println("While expression debe ser boolean");
		System.exit(1);
		}
	parser.freetemp(e1.place);
	
	:} LOOP M:m2 Statements:s1 END LOOP SEMI
	{:
	parser.backpatch(e1.truelist,m2.quad);
	//parser.backpatch(s1.nextlist,m1.quad);
	Atributos t1 = new Atributos();
	t1.nextlist = e1.falselist;
	parser.quads.emit("goto","null","null",String.valueOf(m1.quad));
	parser.backpatch(e1.falselist,parser.quads.nextQuad()); //fix
	parser.backpatch(s1.exitlist,parser.quads.nextQuad()); //fix
	int quad = parser.quads.nextQuad();
	parser.quads.emit("label","$L"+quad,"null","null");
	RESULT = t1;
	:}
	| FOR ID:id1
	{:
	boolean encontro = false;
	Atributos t1 = new Atributos();
	for (int i =parser.actual;i>=0&&!encontro;i--)
		{
		if (parser.hash[i].Existe(id1))
			{
			t1 = parser.hash[i].Recupera(id1);
			encontro = true;
			}
		}
	if (!encontro )
		{
		System.out.println("El id no existe "+id1);
		System.exit(1);
		}
	if (t1.tipo!=0)
		{
		System.out.println("El iterador del for no entero "+id1);
		System.exit(1);
		}
		
	if (t1.modo!=0 && t1.modo!=2)
		{
		System.out.println("El iterador del for no es out "+id1);
		System.exit(1);
		}
		
	if (t1.arreglo)
		{
		System.out.println("El iterador del for es un arreglo "+id1);
		System.exit(1);
		}
		
	:}
	IN PossibleReverse:r1 NUMBER:n1 HPOINTS NUMBER:n2
	{:
	
	if (n1.intValue()>n2.intValue())
		{
		System.out.println("Rango erroneo en el for");
		System.exit(1);
		}
	:}
	LOOP 
	{:
	
	boolean encontro = false;
	Atributos t1 = new Atributos();
	int tabla = 0;
	for (int i =parser.actual;i>=0&&!encontro;i--)
		{
		if (parser.hash[i].Existe(id1))
			{
			t1 = parser.hash[i].Recupera(id1);
			encontro = true;
			tabla = i;
			}
		}
	String temp = parser.newtemp();
	
	if (r1==null)
		{
		if (t1.parametro)
			{
			parser.quads.emit(":=i",String.valueOf(n1.intValue()),"null","$a"+t1.numerop);
			}
		else
			{
			parser.quads.emit(":=i",String.valueOf(n1.intValue()),"null",temp);
			if (tabla!=parser.actual)
				parser.quads.emit(":=",temp,"null",t1.offset+"($s2)");
			else
				parser.quads.emit(":=",temp,"null",t1.offset+"($sp)");
			}
		}
	else
		{
		if (t1.parametro)
			{
			parser.quads.emit(":=i",String.valueOf(n2.intValue()),"null","$a"+t1.numerop);
			}
		else
			{
			parser.quads.emit(":=i",String.valueOf(n2.intValue()),"null",temp);
			if (tabla!=parser.actual)
				parser.quads.emit(":=",temp,"null",t1.offset+"($s2)");
			else
				parser.quads.emit(":=",temp,"null",t1.offset+"($sp)");
			}
		}
	parser.freetemp(temp);
	
	:}
	M:m1 
	{:
	boolean encontro = false;
	Atributos t1 = new Atributos();
	int tabla = 0;
	for (int i =parser.actual;i>=0&&!encontro;i--)
		{
		if (parser.hash[i].Existe(id1))
			{
			t1 = parser.hash[i].Recupera(id1);
			encontro = true;
			tabla = i;
			}
		}
	String temp = parser.newtemp();
	
	if (t1.parametro)
		{
		parser.quads.emit("mov","$a"+t1.numerop,"null",temp);
		}
	else
		{
		if (tabla!=parser.actual)
			parser.quads.emit(":=w",t1.offset+"($s2)","null",temp);
		else
			parser.quads.emit(":=w",t1.offset+"($sp)","null",temp);
		}
	
	if (r1 == null)
		parser.quads.emit(">",temp,String.valueOf(n2.intValue()),"null");
	else
		parser.quads.emit("<",temp,String.valueOf(n1.intValue()),"null");
	parser.freetemp(temp);
	:}
	Statements:s1 
	{:
	
	int quad = parser.quads.nextQuad();
	parser.backpatch(s1.nextlist,quad);
	parser.quads.emit("label","$L"+quad,"null","null");
	
	boolean encontro = false;
	Atributos t1 = new Atributos();
	int tabla = 0;
	for (int i =parser.actual;i>=0&&!encontro;i--)
		{
		if (parser.hash[i].Existe(id1))
			{
			t1 = parser.hash[i].Recupera(id1);
			encontro = true;
			tabla = i;
			}
		}
	String temp = parser.newtemp();
	
	if (t1.parametro)
		{
		parser.quads.emit("mov","$a"+t1.numerop,"null",temp);
		}
	else
		{
		if (tabla!=parser.actual)
			parser.quads.emit(":=w",t1.offset+"($s2)","null",temp);
		else
			parser.quads.emit(":=w",t1.offset+"($sp)","null",temp);
		}
		
	if (r1==null)
		{
		parser.quads.emit("+",temp,"1",temp);
		}
	else
		{
		parser.quads.emit("-",temp,"1",temp);
		}
		
	if (t1.parametro)
		{
		parser.quads.emit("mov",temp,"null","$a"+t1.numerop);
		}
	else
		{
		if (tabla!=parser.actual)
			parser.quads.emit(":=",temp,"null",t1.offset+"($s2)");
		else
			parser.quads.emit(":=",temp,"null",t1.offset+"($sp)");
		}
	
	parser.freetemp(temp);
	:}
	END LOOP SEMI 
	{:
	Vector tempv = new Vector();
	tempv.add(new Integer(m1.quad+2));
	//parser.backpatch(s1.nextlist,m1.quad);
	parser.quads.emit("goto","null","null",String.valueOf(m1.quad));
	parser.backpatch(tempv,parser.quads.nextQuad());
	parser.backpatch(s1.exitlist,parser.quads.nextQuad()); //fix
	int quad = parser.quads.nextQuad();
	parser.quads.emit("label","$L"+quad,"null","null");
	Atributos t1 = new Atributos();
	//t1.nextlist = null;
	RESULT = t1;
	:}
	| LOOP M:m1 Statements:s1 END LOOP SEMI 
	{:
	parser.backpatch(s1.nextlist,m1.quad);
	parser.quads.emit("goto","null","null",String.valueOf(m1.quad));
	parser.backpatch(s1.exitlist,parser.quads.nextQuad()); //fix
	int quad = parser.quads.nextQuad();
	parser.quads.emit("label","$L"+quad,"null","null");
	Atributos t1 = new Atributos();
	//t1.nextlist = null;
	RESULT = t1;
	:}
	| EXIT WHEN Expression:e1 SEMI 
	{:
	if (e1.tipo!=2)
		{
		System.out.println("When expresion debe ser boolean");
		System.exit(1);
		}
	Atributos t1 = new Atributos();
	t1.exitlist = new Vector(e1.truelist);
	parser.backpatch(e1.falselist,parser.quads.nextQuad());
	int quad = parser.quads.nextQuad();
	parser.quads.emit("label","$L"+quad,"null","null");
	RESULT = t1;
	:}
	| EXIT SEMI 
	{:
	Atributos t1 = new Atributos();
	t1.exitlist = new Vector();
	t1.exitlist.add(new Integer(parser.quads.nextQuad()));
	parser.quads.emit("goto","null","null","null");
	RESULT = t1;
	:}
	| IF Expression:e1 
	THEN M:m1 Statements:s1 N:n1
	ELSE M:m2 Statements:s2 
	END IF SEMI 
	{:
	if (e1.tipo!=2)
		{
		System.out.println("if expresion debe ser boolean");
		System.exit(1);
		}
	parser.backpatch(e1.truelist,m1.quad);
	parser.backpatch(e1.falselist,m2.quad);
	Atributos t1 = new Atributos();
	int quad = parser.quads.nextQuad();
	parser.backpatch(s1.nextlist,quad);
	parser.backpatch(s2.nextlist,quad);
	parser.backpatch(n1.nextlist,quad);
	parser.quads.emit("label","$L"+quad,"null","null");
	//t1.nextlist = parser.merge(s1.nextlist,parser.merge(s2.nextlist,n1.nextlist));
	RESULT = t1;
	:}
	| 	IF Expression:e1 
	THEN M:m1 Statements:s1 END IF SEMI 
	{:
	if (e1.tipo!=2)
		{
		System.out.println("if expresion debe ser boolean");
		System.exit(1);
		}
	parser.backpatch(e1.truelist,m1.quad);
	parser.backpatch(e1.falselist,parser.quads.nextQuad()); //fix
	int quad = parser.quads.nextQuad();
	parser.quads.emit("label","$L"+quad,"null","null");
	Atributos t1 = new Atributos();
	t1.nextlist = parser.merge(e1.falselist,s1.nextlist);
	RESULT = t1;
	:}
	| IF Expression:e1 
	THEN M:m1 Statements:s1 N:n1
	ELSEIF M:m2 Expression:e2 
	THEN M:m3 Statements:s2 
	END IF SEMI 
	{:
	if (e1.tipo!=2)
		{
		System.out.println("if expresion debe ser boolean");
		System.exit(1);
		}
	parser.backpatch(e1.truelist,m1.quad);
	parser.backpatch(e1.falselist,m2.quad);
	parser.backpatch(e2.truelist,m3.quad);
	parser.backpatch(e2.falselist,parser.quads.nextQuad()); //fix
	int quad = parser.quads.nextQuad();
	parser.backpatch(s1.nextlist,quad);
	parser.backpatch(s2.nextlist,quad);
	parser.backpatch(n1.nextlist,quad);
	
	parser.quads.emit("label","$L"+quad,"null","null");
	Atributos t1 = new Atributos();
	RESULT = t1;
	:}
	| IF Expression:e1 
	THEN M:m1 Statements:s1 N:n1
	ELSEIF M:m2 Expression:e2 
	THEN M:m3 Statements:s2 N:n2
	ELSE M:m4 Statements:s3
	END IF SEMI 
	{:
	if (e1.tipo!=2)
		{
		System.out.println("if expresion debe ser boolean");
		System.exit(1);
		}
	parser.backpatch(e1.truelist,m1.quad);
	parser.backpatch(e1.falselist,m2.quad);
	parser.backpatch(e2.truelist,m3.quad);
	parser.backpatch(e2.falselist,m4.quad);
	
	Atributos t1 = new Atributos();
	int quad = parser.quads.nextQuad();
	parser.backpatch(s1.nextlist,quad);
	parser.backpatch(s2.nextlist,quad);
	parser.backpatch(n1.nextlist,quad);
	parser.backpatch(s3.nextlist,quad);
	parser.backpatch(n2.nextlist,quad);
	parser.quads.emit("label","$L"+quad,"null","null");
	RESULT = t1;
	:}
;





ProcCall::= ID:id1 SEMI 
	{:
	boolean encontro = false;
	Atributos t1 = new Atributos();
	for (int i =parser.actual;i>=0&&!encontro;i--)
		{
		if (parser.hash[i].Existe(id1))
			{
			t1 = parser.hash[i].Recupera(id1);
			encontro = true;
			}
		}
	if (!encontro )
		{
		System.out.println("El id no existe "+id1);
		System.exit(1);
		}
	if (!t1.proc)
		{
		System.out.println("La variable no es una funcion"+id1);
		System.exit(1);
		}
	if (t1.parametros.size()!=0)
		{
		System.out.println("Error en el numero de parametros"+id1);
		System.exit(1);
		}
	parser.quads.emit(":=","$a0","null","8($sp)");
	parser.quads.emit(":=","$a1","null","12($sp)");
	parser.quads.emit(":=","$a2","null","16($sp)");
	parser.quads.emit(":=","$a3","null","20($sp)");
	
	parser.quads.emit("call",id1,"null","null");
	
	parser.quads.emit(":=w","8($sp)","null","$a0");
	parser.quads.emit(":=w","12($sp)","null","$a1");
	parser.quads.emit(":=w","16($sp)","null","$a2");
	parser.quads.emit(":=w","20($sp)","null","$a3");
	
	:}
	| ID:id1 LPAR 
	{:
	parser.lista.clear();
	:}
	ParamCallList:l1 RPAR PossibleAssign:e1 SEMI 
	{:
	
	boolean encontro = false;
	Atributos t1 = new Atributos();
	int tabla = 0;
	for (int i =parser.actual;i>=0&&!encontro;i--)
		{
		if (parser.hash[i].Existe(id1))
			{
			t1 = parser.hash[i].Recupera(id1);
			encontro = true;
			tabla = i;
			}
		}
	if (!encontro )
		{
		System.out.println("El id no existe "+id1);
		System.exit(1);
		}
	if (e1!=null)
	{
	if (t1.proc)
		{
		System.out.println("La variable  es proc "+id1);
		System.exit(1);
		}
	if (t1.modo!=0 && t1.modo!=2)
		{
		System.out.println("La variable nos es modo out "+id1);
		System.exit(1);
		}
	if (!t1.arreglo)
		{
		System.out.println("La variable nos es array "+id1);
		System.exit(1);
		}
	if (t1.tipo!=e1.tipo)
		{
		System.out.println("La variable nos es del tipo de la expresion "+id1);
		System.exit(1);
		}
	
	Atributos temp = (Atributos)(parser.lista.get(0));
	
	if (temp.estatico&&(temp.valor<t1.min||temp.valor>t1.max))
		{
		System.out.println("El indice no se encuentra en el rango del arreglo "+id1);
		System.exit(1);
		}
	parser.quads.emit("-",temp.place,String.valueOf(t1.min),temp.place);
	parser.quads.emit("*",temp.place,String.valueOf(t1.k),temp.place);
	parser.quads.emit("+",temp.place,String.valueOf(t1.offset),temp.place);
	
	if (tabla!=parser.actual)
		parser.quads.emit("+",temp.place,"$s2",temp.place);
	else
		parser.quads.emit("+",temp.place,"$sp",temp.place);
		
	parser.quads.emit(":=",e1.place,"null","0("+temp.place+")");
	
	parser.freetemp(temp.place);
	parser.freetemp(e1.place);
	}
	else
		{
		if (!t1.proc)
			{
			System.out.println("La variable no es una funcion"+id1);
			System.exit(1);
			}
		if (parser.lista.size()!=t1.parametros.size())
			{
			System.out.println("Numero de parametros erroneos"+id1);
			System.exit(1);
			}
		parser.quads.emit(":=","$a0","null","8($sp)");
		parser.quads.emit(":=","$a1","null","12($sp)");
		parser.quads.emit(":=","$a2","null","16($sp)");
		parser.quads.emit(":=","$a3","null","20($sp)");
		
		for (int i =0;i<parser.lista.size();i++)
			{
			Atributos temp = (Atributos)(parser.lista.get(i));
			if (temp.tipo!=((Atributos)(t1.parametros.elementAt(i))).tipo||temp.arreglo!=((Atributos)(t1.parametros.elementAt(i))).arreglo)
				{
				System.out.println("Parametros erroneos"+id1);
				System.exit(1);
				}
			else
				{
				if ((temp.modo !=((Atributos)(t1.parametros.elementAt(i))).modo)&&(temp.modo!=0))
					{
					System.out.println("Modo en parametros de llamada no coinciden "+id1);
					System.exit(1);
					}
				else
				{
				parser.quads.emit("mov",temp.place,"null","$a"+i);
				parser.freetemp(temp.place);
				}
				}
			
			}
		parser.quads.emit("call",id1,"null","null");
		
		parser.quads.emit(":=w","8($sp)","null","$a0");
		parser.quads.emit(":=w","12($sp)","null","$a1");
		parser.quads.emit(":=w","16($sp)","null","$a2");
		parser.quads.emit(":=w","20($sp)","null","$a3");
		}
		t1 = new Atributos();
		RESULT = t1;
	:}
	| READ LPAR ID:id1 RPAR SEMI 
	{:
	boolean encontro = false;
	Atributos t1 = new Atributos();
	int tabla = 0;
	for (int i =parser.actual;i>=0&&!encontro;i--)
		{
		if (parser.hash[i].Existe(id1))
			{
			t1 = parser.hash[i].Recupera(id1);
			encontro = true;
			tabla = i;
			}
		}
	if (!encontro )
		{
		System.out.println("El id no existe "+id1);
		System.exit(1);
		}
	if (t1.modo!=0 && t1.modo!=2)
		{
		System.out.println("Modo no es out "+id1);
		System.exit(1);
		}
	if (t1.proc)
		{
		System.out.println("La variable  es proc "+id1);
		System.exit(1);
		}
	
	if (t1.tipo==0)
		{
		parser.quads.emit(":=i","5","null","$v0");
		parser.quads.emit("syscall","null","null","null");
		
		if (!t1.parametro)
		{
		if (tabla!=parser.actual)
			parser.quads.emit(":=","$v0","null",t1.offset+"($s2)");
		else
			parser.quads.emit(":=","$v0","null",t1.offset+"($sp)");
		}
		else
			{
			parser.quads.emit("mov","$v0","null","$a"+t1.numerop);
			}
		}
	else
		{
		parser.quads.emit("mov","$a0","null","$s0");
		parser.quads.emit("mov","$a1","null","$s1");
		parser.quads.emit(":=i","8","null","$v0");
		parser.quads.emit(":=a","$CHAR","null","$a0");
		parser.quads.emit(":=i","2","null","$a1");
		parser.quads.emit("syscall","null","null","null");
		parser.quads.emit("mov","$s0","null","$a0");
		parser.quads.emit("mov","$s1","null","$a1");
		
		String temp = parser.newtemp();
		parser.quads.emit(":=w","$CHAR","null",temp);
		if (!t1.parametro)
		{
		if (tabla!=parser.actual)
			parser.quads.emit(":=",temp,"null",t1.offset+"($s2)");
		else
			parser.quads.emit(":=",temp,"null",t1.offset+"($sp)");
		}
		else
			{
			parser.quads.emit(":=w","$CHAR","null","$a"+t1.numerop);
			}
		parser.freetemp(temp);
		}
	t1 = new Atributos();
	RESULT = t1;
	:}
	| READLN LPAR ID:id1 RPAR SEMI 
	{:
	boolean encontro = false;
	Atributos t1 = new Atributos();
	int tabla = 0;
	for (int i =parser.actual;i>=0&&!encontro;i--)
		{
		if (parser.hash[i].Existe(id1))
			{
			t1 = parser.hash[i].Recupera(id1);
			encontro = true;
			tabla = i;
			}
		}
	if (!encontro )
		{
		System.out.println("El id no existe "+id1);
		System.exit(1);
		}
	if (t1.modo!=0 && t1.modo!=2)
		{
		System.out.println("Modo no es out "+id1);
		System.exit(1);
		}
	if (t1.proc)
		{
		System.out.println("La variable  es proc "+id1);
		System.exit(1);
		}
	if (t1.tipo==0)
		{
		parser.quads.emit(":=i","5","null","$v0");
		parser.quads.emit("syscall","null","null","null");
		
		if (!t1.parametro)
		{
		if (tabla!=parser.actual)
			parser.quads.emit(":=","$v0","null",t1.offset+"($s2)");
		else
			parser.quads.emit(":=","$v0","null",t1.offset+"($sp)");
		}
		else
			{
			parser.quads.emit("mov","$v0","null","$a"+t1.numerop);
			}
		}
	else
		{
		parser.quads.emit("mov","$a0","null","$s0");
		parser.quads.emit("mov","$a1","null","$s1");
		parser.quads.emit(":=i","8","null","$v0");
		parser.quads.emit(":=a","$CHAR","null","$a0");
		parser.quads.emit(":=i","2","null","$a1");
		parser.quads.emit("syscall","null","null","null");
		parser.quads.emit("mov","$s0","null","$a0");
		parser.quads.emit("mov","$s1","null","$a1");
		String temp = parser.newtemp();
		parser.quads.emit(":=w","$CHAR","null",temp);
		if (!t1.parametro)
		{
		if (tabla!=parser.actual)
			parser.quads.emit(":=",temp,"null",t1.offset+"($s2)");
		else
			parser.quads.emit(":=",temp,"null",t1.offset+"($sp)");
		}
		else
			{
			parser.quads.emit(":=w","$CHAR","null","$a"+t1.numerop);
			}
		parser.freetemp(temp);
		}
	parser.quads.emit(":=i","4","null","$v0");
	parser.quads.emit("mov","$a0","null","$s0");
	parser.quads.emit(":=a","$ENTER","null","$a0");
	parser.quads.emit("mov","$a1","null","$s1");
	parser.quads.emit(":=i","1","null","$a1");
	parser.quads.emit("syscall","null","null","null");
	parser.quads.emit("mov","$s0","null","$a0");
	parser.quads.emit("mov","$s1","null","$a1");
	t1 = new Atributos();
	RESULT = t1;
	:}
	| WRITE LPAR Expression:e1 RPAR SEMI 
	{:
	if (e1.modo!=0&&e1.modo!=1)
		{
		System.out.println("El modo del parametro no es in");
		System.exit(1);
		}
	if (e1.tipo == 2)
		{
		System.out.println("No se permiten Expresiones booleanas en Writes");
		System.exit(1);
		}
	parser.quads.emit("func","write","null","null");
	
	if (e1.tipo==0)
		{
		parser.quads.emit(":=i","1","null","$v0");
		parser.quads.emit("mov","$a0","null","$s0");
		parser.quads.emit("mov",e1.place,"null","$a0");
		parser.quads.emit("syscall","null","null","null");
		parser.quads.emit("mov","$s0","null","$a0");
		}
	else
		{
		parser.quads.emit(":=i","4","null","$v0");
		parser.quads.emit("mov","$a0","null","$s0");
		parser.quads.emit(":=",e1.place,"null","$CHAR");
		parser.quads.emit(":=a","$CHAR","null","$a0");
		parser.quads.emit("syscall","null","null","null");
		parser.quads.emit("mov","$s0","null","$a0");
		}
	parser.freetemp(e1.place);
	Atributos t1 = new Atributos();
	RESULT = t1;
	:}
	| WRITELN SEMI 
	{:
	parser.quads.emit(":=i","4","null","$v0");
	parser.quads.emit("mov","$a0","null","$s0");
	parser.quads.emit(":=a","$ENTER","null","$a0");
	parser.quads.emit("mov","$a1","null","$s1");
	parser.quads.emit(":=i","1","null","$a1");
	parser.quads.emit("syscall","null","null","null");
	parser.quads.emit("mov","$s0","null","$a0");
	parser.quads.emit("mov","$s1","null","$a1");
	
	Atributos t1 = new Atributos();
	RESULT = t1;
	:}
;

PossibleAssign::= ASSIGN Expression:e1 
	{:
	RESULT = e1;
	:}
	| {:RESULT = null;:}
;

ParamCallList::= Expression:e1 
	{:
	parser.lista.add(0,e1);
	:}
	| Expression:e1 COMMA ParamCallList 
	{:
	parser.lista.add(0,e1);
	:}
;


M::= 	{:
		Atributos t1 = new Atributos();
		t1.quad = parser.quads.nextQuad();
		parser.quads.emit("label","$L"+t1.quad,"null","null");
		RESULT = t1;
		:}
;
N::= 	{:
		Atributos t1 = new Atributos();
		t1.nextlist = new Vector();
		t1.nextlist.add(new Integer(parser.quads.nextQuad()));
		parser.quads.emit("goto","null","null","null");
		RESULT = t1;
		:}
;




Expression::= Expression:e1 PLUS Expression:e2 
	{:
	if (e1.tipo!=e2.tipo || e1.tipo!=0)
		{
		System.out.println("No se permiten sumas que no sean enteras");
		System.exit(1);
		}
	Atributos t1 = new Atributos();
	t1.tipo = 0;
	t1.modo = 1;
	System.out.println(e1.place);
	System.out.println(e2.place);
	String temp = parser.newtemp();
	System.out.println(temp);
	parser.quads.emit("+",e1.place,e2.place,temp);
	parser.freetemp(e1.place);
	parser.freetemp(e2.place);
	t1.place = new String(temp);
	
	RESULT = t1;
	:}
	| Expression:e1 MINUS Expression:e2
	{:
	if (e1.tipo!=e2.tipo || e1.tipo!=0)
		{
		System.out.println("No se permiten restas que no sean enteras");
		System.exit(1);
		}
	Atributos t1 = new Atributos();
	t1.tipo = 0;
	t1.modo = 1;
	String temp = parser.newtemp();
	parser.quads.emit("-",e1.place,e2.place,temp);
	parser.freetemp(e1.place);
	parser.freetemp(e2.place);
	t1.place = new String(temp);
	
	RESULT = t1;
	:}
	| Expression:e1 TIMES Expression:e2 
	{:
	if (e1.tipo!=e2.tipo || e1.tipo!=0)
		{
		System.out.println("No se permiten multiplicaciones que no sean enteras");
		System.exit(1);
		}
	Atributos t1 = new Atributos();
	t1.tipo = 0;
	t1.modo = 1;
	String temp = parser.newtemp();
	parser.quads.emit("*",e1.place,e2.place,temp);
	parser.freetemp(e1.place);
	parser.freetemp(e2.place);
	t1.place = new String(temp);
	
	RESULT = t1;
	:}
	| Expression:e1 DIV Expression:e2
	{:
	if (e1.tipo!=e2.tipo || e1.tipo!=0)
		{
		System.out.println("No se permiten diversiones que no sean enteras");
		System.exit(1);
		}
	Atributos t1 = new Atributos();
	t1.tipo = 0;
	t1.modo = 1;
	String temp = parser.newtemp();
	parser.quads.emit("/",e1.place,e2.place,temp);
	parser.freetemp(e1.place);
	parser.freetemp(e2.place);
	t1.place = new String(temp);
	
	RESULT = t1;
	:}
	| Expression:e1 MOD Expression:e2 
	{:
	if (e1.tipo!=e2.tipo || e1.tipo!=0)
		{
		System.out.println("No se permiten modulos que no sean enteras");
		System.exit(1);
		}
	Atributos t1 = new Atributos();
	t1.tipo = 0;
	t1.modo = 1;
	String temp = parser.newtemp();
	parser.quads.emit("%",e1.place,e2.place,temp);
	parser.freetemp(e1.place);
	parser.freetemp(e2.place);
	t1.place = new String(temp);
	
	RESULT = t1;
	:}
	| ABS Expression:e1 
	{:
	if (e1.tipo!=0)
		{
		System.out.println("No se permiten absolutos que no sean enteras");
		System.exit(1);
		}
	Atributos t1 = new Atributos();
	t1.tipo = 0;
	t1.modo = 1;
	String temp = parser.newtemp();
	parser.quads.emit("|",e1.place,"null",temp);
	parser.freetemp(e1.place);
	t1.place = new String(temp);
	
	RESULT = t1;
	:}
	| MINUS Expression:e1 
	{:
	if (e1.tipo!=0)
		{
		System.out.println("No se permiten uminus que no sean enteras");
		System.exit(1);
		}
	Atributos t1 = new Atributos();
	t1.tipo = 0;
	t1.modo = 1;
	String temp = parser.newtemp();
	parser.quads.emit("-","1",e1.place,temp);
	parser.freetemp(e1.place);
	t1.place = new String(temp);
	
	RESULT = t1;
	:} %prec UMINUS
	
	
	| NOT Expression:e1 
	{:
	if (e1.tipo!=2)
		{
		System.out.println("No se permiten negaciones que no sean booleanas");
		System.exit(1);
		}
	Atributos t1 = new Atributos();
	t1.tipo = 2;
	t1.modo = 1;
	t1.truelist = new Vector(e1.falselist);
	t1.falselist = new Vector(e1.truelist);
	t1.place="null";
	RESULT = t1;
	:}
	| Expression:e1 GT Expression:e2 
	{:
	if (e1.tipo!=e2.tipo || e1.tipo!=0)
		{
		System.out.println("No se permiten GT que no sean enteras");
		System.exit(1);
		}
	Atributos t1 = new Atributos();
	t1.tipo = 2;
	t1.modo = 1;
	t1.truelist = new Vector();
	t1.falselist = new Vector();
	t1.truelist.add(new Integer(parser.quads.nextQuad()));
	t1.falselist.add(new Integer(parser.quads.nextQuad()+1));
	parser.quads.emit(">",e1.place,e2.place,"null");
	parser.quads.emit("goto","null","null","null");
	parser.freetemp(e1.place);
	parser.freetemp(e2.place);
	t1.place="null";
	RESULT = t1;
	:}
	| Expression:e1 LT Expression:e2 
	{:
	if (e1.tipo!=e2.tipo || e1.tipo!=0)
		{
		System.out.println("No se permiten LT que no sean enteras");
		System.exit(1);
		}
	Atributos t1 = new Atributos();
	t1.tipo = 2;
	t1.modo = 1;
	t1.truelist = new Vector();
	t1.falselist = new Vector();
	t1.truelist.add(new Integer(parser.quads.nextQuad()));
	t1.falselist.add(new Integer(parser.quads.nextQuad()+1));
	parser.quads.emit("<",e1.place,e2.place,"null");
	parser.quads.emit("goto","null","null","null");
	parser.freetemp(e1.place);
	parser.freetemp(e2.place);
	t1.place="null";
	RESULT = t1;
	:}
	| Expression:e1 GE Expression:e2 
	{:
	if (e1.tipo!=e2.tipo || e1.tipo!=0)
		{
		System.out.println("No se permiten GE que no sean enteras");
		System.exit(1);
		}
	Atributos t1 = new Atributos();
	t1.tipo = 2;
	t1.modo = 1;
	t1.truelist = new Vector();
	t1.falselist = new Vector();
	t1.truelist.add(new Integer(parser.quads.nextQuad()));
	t1.falselist.add(new Integer(parser.quads.nextQuad()+1));
	parser.quads.emit(">=",e1.place,e2.place,"null");
	parser.quads.emit("goto","null","null","null");
	parser.freetemp(e1.place);
	parser.freetemp(e2.place);
	t1.place="null";
	RESULT = t1;
	:}
	| Expression:e1 LE Expression:e2
	{:
	if (e1.tipo!=e2.tipo || e1.tipo!=0)
		{
		System.out.println("No se permiten LE que no sean enteras");
		System.exit(1);
		}
	Atributos t1 = new Atributos();
	t1.tipo = 2;
	t1.modo = 1;
	t1.truelist = new Vector();
	t1.falselist = new Vector();
	t1.truelist.add(new Integer(parser.quads.nextQuad()));
	t1.falselist.add(new Integer(parser.quads.nextQuad()+1));
	parser.quads.emit("<=",e1.place,e2.place,"null");
	parser.quads.emit("goto","null","null","null");
	parser.freetemp(e1.place);
	parser.freetemp(e2.place);
	t1.place="null";
	RESULT = t1;
	:}
	| Expression:e1 EQ Expression:e2 
	{:
	if (e1.tipo!=e2.tipo )
		{
		System.out.println("No se permiten comparaciones de tipos distintos");
		System.exit(1);
		}
	Atributos t1 = new Atributos();
	t1.tipo = 2;
	t1.modo = 1;
	t1.truelist = new Vector();
	t1.falselist = new Vector();
	t1.truelist.add(new Integer(parser.quads.nextQuad()));
	t1.falselist.add(new Integer(parser.quads.nextQuad()+1));
	parser.quads.emit("=",e1.place,e2.place,"null");
	parser.quads.emit("goto","null","null","null");
	parser.freetemp(e1.place);
	parser.freetemp(e2.place);
	t1.place="null";
	RESULT = t1;
	:}
	| Expression:e1 NEQ Expression:e2 
	{:
	if (e1.tipo!=e2.tipo )
		{
		System.out.println("No se permiten comparaciones de tipos distintos");
		System.exit(1);
		}
	Atributos t1 = new Atributos();
	t1.tipo = 2;
	t1.modo = 1;
	t1.truelist = new Vector();
	t1.falselist = new Vector();
	t1.truelist.add(new Integer(parser.quads.nextQuad()));
	t1.falselist.add(new Integer(parser.quads.nextQuad()+1));
	parser.quads.emit("/=",e1.place,e2.place,"null");
	parser.quads.emit("goto","null","null","null");
	parser.freetemp(e1.place);
	parser.freetemp(e2.place);
	t1.place="null";
	RESULT = t1;
	:}
	| Expression:e1 AND M:m1 Expression:e2 
	{:
	if (e1.tipo!=e2.tipo || e1.tipo!=2)
		{
		System.out.println("No se permiten AND que no sean boolean");
		System.exit(1);
		}
	Atributos t1 = new Atributos();
	t1.tipo = 2;
	t1.modo = 1;
	parser.backpatch(e1.truelist,m1.quad);
	t1.truelist = new Vector(e2.truelist);
	t1.falselist = parser.merge(e1.falselist,e2.falselist);
	parser.freetemp(e1.place);
	parser.freetemp(e2.place);
	t1.place="null";
	RESULT = t1;
	:}
	| Expression:e1 OR M:m1 Expression:e2
	{:
	if (e1.tipo!=e2.tipo || e1.tipo!=2)
		{
		System.out.println("No se permiten OR que no sean boolean");
		System.exit(1);
		}
	Atributos t1 = new Atributos();
	t1.tipo = 2;
	t1.modo = 1;
	parser.backpatch(e1.falselist,m1.quad);
	t1.falselist = new Vector(e2.falselist);
	t1.truelist = parser.merge(e1.truelist,e2.truelist);
	parser.freetemp(e1.place);
	parser.freetemp(e2.place);
	t1.place="null";
	RESULT = t1;
	:}
	| LPAR Expression:e1 RPAR 
	{:
	RESULT = e1;
	:}
	| TRUE 
	{:
	Atributos t1 = new Atributos();
	t1.tipo = 2;
	t1.modo = 1;
	t1.truelist = new Vector();
	t1.truelist.add(new Integer(parser.quads.nextQuad()));
	parser.quads.emit("goto","null","null","null");
	t1.place="true";
	RESULT = t1;
	:}
	| FALSE 
	{:
	Atributos t1 = new Atributos();
	t1.tipo = 2;
	t1.modo = 1;
	t1.falselist = new Vector();
	t1.falselist.add(new Integer(parser.quads.nextQuad()));
	parser.quads.emit("goto","null","null","null");
	t1.place="false";
	RESULT = t1;
	:}
	| ID:id1 AP FIRST 
	{:
	boolean encontro = false;
	Atributos t1 = new Atributos();
	int tabla = 0;
	for (int i =parser.actual;i>=0&&!encontro;i--)
		{
		if (parser.hash[i].Existe(id1))
			{
			t1 = parser.hash[i].Recupera(id1);
			tabla = i;
			encontro = true;
			}
		}
	if (!encontro )
		{
		System.out.println("El id no existe "+id1);
		System.exit(1);
		}
	if (t1.modo!=0 && t1.modo!=1)
		{
		System.out.println("Modo no es in "+id1);
		System.exit(1);
		}
	if (!t1.arreglo)
		{
		System.out.println("Tipo no es arreglo "+id1);
		System.exit(1);
		}
	if (t1.proc)
		{
		System.out.println("La variable  es proc "+id1);
		System.exit(1);
		}
	Atributos t2 = new Atributos();
	t2.tipo = t1.tipo;
	t2.modo = t1.modo;
	/*String temp = parser.newtemp();
	parser.quads.emit(":=a",id1,"null",temp);
	String temp2 = parser.newtemp();
	parser.quads.emit(":=[]",temp,"0",temp2);
	t2.place = temp2;
	parser.freetemp(temp);*/
	
	String temp = parser.newtemp();
	if (tabla==parser.actual)
		parser.quads.emit(":=w",t1.offset+"($sp)","null",temp);
	else
		parser.quads.emit(":=w",t1.offset+"($s2)","null",temp);
	t2.place = temp;
	
	RESULT = t2;
	:}
	| ID:id1 AP LAST 
	{:
	boolean encontro = false;
	Atributos t1 = new Atributos();
	int tabla = 0;
	for (int i =parser.actual;i>=0&&!encontro;i--)
		{
		if (parser.hash[i].Existe(id1))
			{
			t1 = parser.hash[i].Recupera(id1);
			tabla = i;
			encontro = true;
			}
		}
	if (!encontro )
		{
		System.out.println("El id no existe "+id1);
		System.exit(1);
		}
	if (t1.modo!=0 && t1.modo!=1)
		{
		System.out.println("Modo no es in "+id1);
		System.exit(1);
		}
	if (!t1.arreglo)
		{
		System.out.println("Tipo no es arreglo "+id1);
		System.exit(1);
		}
	if (t1.proc)
		{
		System.out.println("La variable  es proc "+id1);
		System.exit(1);
		}
	Atributos t2 = new Atributos();
	t2.tipo = t1.tipo;
	t2.modo = t1.modo;
	/*String temp = parser.newtemp();
	parser.quads.emit(":=a",id1,"null",temp);
	String temp2 = parser.newtemp();
	parser.quads.emit(":=[]",temp,"MAX",temp2);
	t2.place = temp2;
	parser.freetemp(temp);*/
	
	int offset = t1.offset + (t1.max-t1.min)*t1.k;
	
	String temp = parser.newtemp();
	
	if (tabla==parser.actual)
		parser.quads.emit(":=w",offset+"($sp)","null",temp);
	else
		parser.quads.emit(":=w",offset+"($s2)","null",temp);
		
	t2.place = temp;
	
	RESULT = t2;
	:}
	| ID:id1 AP CHAR 
	{:
	boolean encontro = false;
	Atributos t1 = new Atributos();
	int tabla = 0;
	for (int i =parser.actual;i>=0&&!encontro;i--)
		{
		if (parser.hash[i].Existe(id1))
			{
			t1 = parser.hash[i].Recupera(id1);
			tabla=i;
			encontro = true;
			}
		}
	if (!encontro )
		{
		System.out.println("El id no existe "+id1);
		System.exit(1);
		}
	if (t1.modo!=0 && t1.modo!=1)
		{
		System.out.println("Modo no es in "+id1);
		System.exit(1);
		}
	if (t1.tipo!=0)
		{
		System.out.println("Tipo no es integer "+id1);
		System.exit(1);
		}
	if (t1.proc)
		{
		System.out.println("La variable  es proc "+id1);
		System.exit(1);
		}
	Atributos t2 = new Atributos();
	t2.tipo = 1;
	t2.modo = 1;
	String temp = parser.newtemp();
	if (t1.parametro)
		{
		parser.quads.emit("mov","$a"+t1.numerop,"null",temp);
		}
	else
	{
	if (tabla == parser.actual)
		parser.quads.emit(":=w",t1.offset+"($sp)","null",temp);
	else
		parser.quads.emit(":=w",t1.offset+"($s2)","null",temp);
	}
	t2.place = temp;
	
	RESULT = t2;
	:}
	| ID:id1 LPAR Expression:e1 RPAR 
	{:
	boolean encontro = false;
	Atributos t1 = new Atributos();
	int tabla = 0;
	for (int i =parser.actual;i>=0&&!encontro;i--)
		{
		if (parser.hash[i].Existe(id1))
			{
			t1 = parser.hash[i].Recupera(id1);
			tabla = i;
			encontro = true;
			}
		}
	if (!encontro )
		{
		System.out.println("El id no existe "+id1);
		System.exit(1);
		}
	if (t1.modo!=0 && t1.modo!=1)
		{
		System.out.println("Modo no es in "+id1);
		System.exit(1);
		}
	if (!t1.arreglo)
		{
		System.out.println("Tipo no es arreglo "+id1);
		System.exit(1);
		}
	if (e1.tipo!=0)
		{
		System.out.println("Tipo de expresion no es int");
		System.exit(1);
		}
	if (t1.proc)
		{
		System.out.println("La variable  es proc "+id1);
		System.exit(1);
		}
	Atributos t2 = new Atributos();
	t2.tipo = t1.tipo;
	t2.modo = t1.modo;
	
	String temp = parser.newtemp();
	
	parser.quads.emit("-",e1.place,String.valueOf(t1.min),e1.place);
	parser.quads.emit("*",e1.place,String.valueOf(t1.k),e1.place);
	parser.quads.emit("+",e1.place,String.valueOf(t1.offset),e1.place);
	
	if (tabla==parser.actual)
		parser.quads.emit("+",e1.place,"$sp",e1.place);
	else
		parser.quads.emit("+",e1.place,"$s2",e1.place);
		
	parser.quads.emit(":=w","0("+e1.place+")","null",temp);
	
	
	parser.freetemp(e1.place);
	t2.place = temp;
	
	/*String temp = parser.newtemp();
	parser.quads.emit(":=a",id1,"null",temp);
	String temp2 = parser.newtemp();
	parser.quads.emit(":=[]",temp,e1.place,temp2);
	t2.place = temp2;
	parser.freetemp(e1.place);
	parser.freetemp(temp);*/
	
	RESULT = t2;
	:}
	| ID:id1 AP VAL 
	{:
	boolean encontro = false;
	Atributos t1 = new Atributos();
	int tabla = 0;
	for (int i =parser.actual;i>=0&&!encontro;i--)
		{
		if (parser.hash[i].Existe(id1))
			{
			t1 = parser.hash[i].Recupera(id1);
			tabla = i;
			encontro = true;
			}
		}
	if (!encontro )
		{
		System.out.println("El id no existe "+id1);
		System.exit(1);
		}
	if (t1.modo!=0 && t1.modo!=1)
		{
		System.out.println("Modo no es in "+id1);
		System.exit(1);
		}
	if (t1.tipo!=1)
		{
		System.out.println("Tipo no es char "+id1);
		System.exit(1);
		}
	if (t1.proc)
		{
		System.out.println("La variable  es proc "+id1);
		System.exit(1);
		}
	Atributos t2 = new Atributos();
	t2.tipo = 0;
	t2.modo = 1;
	String temp = parser.newtemp();
	
	if (t1.parametro)
		{
		parser.quads.emit("mov","$a"+t1.numerop,"null",temp);
		}
	else
	{
	if (tabla==parser.actual)
		parser.quads.emit(":=w",t1.offset+"($sp)","null",temp);
	else
		parser.quads.emit(":=w",t1.offset+"($s2)","null",temp);
	}
	t2.place = temp;
	
	RESULT = t2;
	:}
	| ID:id1 
	{:
	boolean encontro = false;
	Atributos t1 = new Atributos();
	int tabla = 0;
	for (int i =parser.actual;i>=0&&!encontro;i--)
		{
		if (parser.hash[i].Existe(id1))
			{
			t1 = parser.hash[i].Recupera(id1);
			tabla = i;
			encontro = true;
			}
		}
	if (!encontro )
		{
		System.out.println("El id no existe "+id1);
		System.exit(1);
		}
	if (t1.modo!=0 && t1.modo!=1)
		{
		System.out.println("Modo no es in "+id1);
		System.exit(1);
		}
	if (t1.proc)
		{
		System.out.println("La variable  es proc "+id1);
		System.exit(1);
		}
	Atributos t2 = new Atributos();
	t2.tipo = t1.tipo;
	t2.arreglo = t1.arreglo;
	t2.modo = t1.modo;
	String temp = parser.newtemp();
	
	if (t1.parametro)
		{
		parser.quads.emit("mov","$a"+t1.numerop,"null",temp);
		}
	else
	{
	if (tabla==parser.actual)
		parser.quads.emit(":=w",t1.offset+"($sp)","null",temp);
	else
		parser.quads.emit(":=w",t1.offset+"($s2)","null",temp);
	}
	t2.place = temp;
	
	RESULT = t2;
	:}
	| NUMBER:n1 
	{:
	Atributos t1 = new Atributos();
	t1.tipo = 0;
	t1.modo = 1;
	t1.estatico = true;
	t1.valor = n1.intValue();
	String temp = parser.newtemp();
	String temp2 = String.valueOf(n1);
	parser.quads.emit(":=i",temp2,"null",temp);
	t1.place = new String(temp);
	RESULT = t1;
	:}
	| NCHAR:nc
	{:
	Atributos t1 = new Atributos();
	t1.tipo = 1;
	t1.modo = 1;
	String temp = parser.newtemp();
	parser.quads.emit(":=i",String.valueOf(nc.getBytes()[1]),"null",temp);
	t1.place = new String(temp);
	RESULT = t1;
	:}

;



AssignStatement::= ID:id1 ASSIGN Expression:e1 SEMI 
	{:
	boolean encontro = false;
	Atributos t1 = new Atributos();
	int tabla = 0;
	for (int i =parser.actual;i>=0&&!encontro;i--)
		{
		if (parser.hash[i].Existe(id1))
			{
			t1 = parser.hash[i].Recupera(id1);
			tabla = i;
			encontro = true;
			}
		}
	if (!encontro )
		{
		System.out.println("El id no existe "+id1);
		System.exit(1);
		}
	if (t1.proc)
		{
		System.out.println("La variable  es proc "+id1);
		System.exit(1);
		}
	if (t1.modo!=0 && t1.modo!=2)
		{
		System.out.println("La variable nos es modo out "+id1);
		System.exit(1);
		}
	if (t1.tipo!=e1.tipo)
		{
		System.out.println("La variable nos es del tipo de la expresion "+id1);
		System.exit(1);
		}
	System.out.println(e1.place);	
	if (t1.parametro)
		{
		parser.quads.emit("mov",e1.place,"null","$a"+t1.numerop);
		}
	else
	{
	if (tabla == parser.actual)
		parser.quads.emit(":=",e1.place,"null",t1.offset+"($sp)");
	else
		parser.quads.emit(":=",e1.place,"null",t1.offset+"($s2)");
	}
	
	parser.freetemp(e1.place);
	:}
	| ID:id1 AP FIRST ASSIGN Expression:e1 SEMI 
	{:
	boolean encontro = false;
	Atributos t1 = new Atributos();
	int tabla = 0;
	for (int i =parser.actual;i>=0&&!encontro;i--)
		{
		if (parser.hash[i].Existe(id1))
			{
			t1 = parser.hash[i].Recupera(id1);
			encontro = true;
			tabla = i;
			}
		}
	if (!encontro )
		{
		System.out.println("El id no existe "+id1);
		System.exit(1);
		}
	if (t1.modo!=0 && t1.modo!=2)
		{
		System.out.println("La variable nos es modo out "+id1);
		System.exit(1);
		}
	if (t1.proc)
		{
		System.out.println("La variable  es proc "+id1);
		System.exit(1);
		}
	if (!t1.arreglo)
		{
		System.out.println("La variable nos es array "+id1);
		System.exit(1);
		}
	if (t1.tipo!=e1.tipo)
		{
		System.out.println("La variable nos es del tipo de la expresion "+id1);
		System.exit(1);
		}
	if (tabla!=parser.actual)
		parser.quads.emit(":=",e1.place,"null",t1.offset+"($s2)");
	else
		parser.quads.emit(":=",e1.place,"null",t1.offset+"($sp)");
	parser.freetemp(e1.place);
	:}
	| ID:id1 AP LAST ASSIGN Expression:e1 SEMI 
	{:
	boolean encontro = false;
	Atributos t1 = new Atributos();
	int tabla = 0;
	for (int i =parser.actual;i>=0&&!encontro;i--)
		{
		if (parser.hash[i].Existe(id1))
			{
			t1 = parser.hash[i].Recupera(id1);
			encontro = true;
			tabla = i;
			}
		}
	if (!encontro )
		{
		System.out.println("El id no existe "+id1);
		System.exit(1);
		}
	if (t1.proc)
		{
		System.out.println("La variable  es proc "+id1);
		System.exit(1);
		}
	if (t1.modo!=0 && t1.modo!=2)
		{
		System.out.println("La variable nos es modo out "+id1);
		System.exit(1);
		}
	if (!t1.arreglo)
		{
		System.out.println("La variable nos es array "+id1);
		System.exit(1);
		}
	if (t1.tipo!=e1.tipo)
		{
		System.out.println("La variable nos es del tipo de la expresion "+id1);
		System.exit(1);
		}
	int offset = t1.offset+t1.k*(t1.max-t1.min);
	
	if (tabla!=parser.actual)
		parser.quads.emit(":=",e1.place,"null",offset+"($s2)");
	else
		parser.quads.emit(":=",e1.place,"null",offset+"($sp)");
	parser.freetemp(e1.place);
	:}
	
;



PossibleReverse::= REVERSE 
	{: 
	Atributos t1 = new Atributos();
	RESULT = t1;
	:}
	| {:RESULT = null;:}
;