using System.Collections;

using System;

namespace Liss {



public class Parser {
	const int _EOF = 0;
	const int _ident = 1;
	const int _number = 2;
	const int maxT = 72;
	const int _comment = 73;

	const bool T = true;
	const bool x = false;
	const int minErrDist = 2;
	
	public Scanner scanner;
	public Errors  errors;

	public Token t;    // last recognized token
	public Token la;   // lookahead token
	int errDist = minErrDist;

const int undef = 0, boolean = 1, integer = 2, array = 3, sets = 4, sequence = 5;

public int elseT = 1, whileT = 1, forT = 1;	// tells how many IfThenElse/while/for exists
public int arrayNum = 1, open=1, level = 0;
public SymbolTable SymTab;
public VM_Code genCode;
public Resolver Resolver;
public string output = "";
public string functions = "";
public string varDeclCode = "";




	public Parser(Scanner scanner) {
		this.scanner = scanner;
		errors = new Errors();
	}

	void SynErr (int n) {
		if (errDist >= minErrDist) errors.SynErr(la.line, la.col, n);
		errDist = 0;
	}

	public void SemErr (string msg) {
		if (errDist >= minErrDist) errors.Error(t.line, t.col, msg);
		errDist = 0;
	}
	
	void Get () {
		for (;;) {
			t = la;
			la = scanner.Scan();
			if (la.kind <= maxT) { ++errDist; break; }
				if (la.kind == 73) {
				SymTab.AddComments(la.val); 
				}

			la = t;
		}
	}
	
	void Expect (int n) {
		if (la.kind==n) Get(); else { SynErr(n); }
	}
	
	bool StartOf (int s) {
		return set[s, la.kind];
	}
	
	void ExpectWeak (int n, int follow) {
		if (la.kind == n) Get();
		else {
			SynErr(n);
			while (!StartOf(follow)) Get();
		}
	}
	
	bool WeakSeparator (int n, int syFol, int repFol) {
		bool[] s = new bool[maxT+1];
		if (la.kind == n) { Get(); return true; }
		else if (StartOf(repFol)) return false;
		else {
			for (int i=0; i <= maxT; i++) {
				s[i] = set[syFol, i] || set[repFol, i] || set[0, i];
			}
			SynErr(n);
			while (!s[la.kind]) Get();
			return StartOf(syFol);
		}
	}
	
	void Liss() {
		string varDeclCode1 = "", libs = "",
		statCode1 = "", statCode = "";
		genCode.writeLiss();	
		Expect(3);
		Expect(1);
		output += SymTab.GetComments() + genCode.WriteMain();	
		Expect(4);
		output += "{\n";
		SymTab.IncIdent();
		output += SymTab.GetComments();	
		if (la.kind == 5) {
			Get();
			SymTab.InicEnv();	
			while (la.kind == 1 || la.kind == 69) {
				Decls(out varDeclCode1);
				varDeclCode += varDeclCode1;	
			}
		}
		Expect(6);
		while (StartOf(1)) {
			Statement(out statCode1);
			statCode += statCode1 + "\n";	
		}
		Expect(7);
		if (SymTab.checkCaduceus())
		libs = genCode.WriteCaduceusLib() + "\n";
		else
			libs = genCode.WriteLib() + "\n";
		
		output = libs 
				+ functions
				+ output
				+ varDeclCode + "\n"
				+ statCode
			/*	+ SymTab.PrintIdent() + genCode.WriteEnd()  TODO */
				+ SymTab.GetComments() + "}\n";
		
		SymTab.DecIdent();	
	}

	void Decls(out string code) {
		code = "";
		string fun = "", com = SymTab.GetComments();	
		if (la.kind == 1) {
			VarDecl(out code);
			code = com + code + ";\n";	
		} else if (la.kind == 69) {
			SubProgDef(out fun);
			functions += com + fun + "\n";	
		} else SynErr(73);
	}

	void Statement(out string code) {
		code = ""; string com = SymTab.GetComments();
		int type = undef;	
		if (Resolver.IsVarDecl()) {
			VarDecl(out code);
			if (level == 0)
			SemErr("Invalid global variable declaration!");	
		} else if (StartOf(2)) {
			Assignment(out code);
			code += ";\n";	
		} else if (la.kind == 31 || la.kind == 32) {
			WriteStatement(out code);
		} else if (la.kind == 55 || la.kind == 58 || la.kind == 67) {
			Conditional(out code);
		} else if (la.kind == 68) {
			Read(out code);
			code = SymTab.PrintIdent() + code + ";\n";
			if (SymTab.checkCaduceus())
				code = SymTab.genCaduceusCom() +
						code + SymTab.PrintIdent() + "*/\n";	
		} else if (la.kind == 27 || la.kind == 28) {
			SucOrPred(out code);
			code = SymTab.PrintIdent() + code + ";\n";	
		} else if (la.kind == 39) {
			Copy(out type,out code);
			code = SymTab.PrintIdent() + code + ";\n";	
		} else SynErr(74);
		code = com + code;	
	}

	void VarDecl(out string code) {
		int type = undef, init, endT; code = ""; 
		string tpname = "", name = "";
		Object obj = null;	
		init = SymTab.getSizeTable();
		ArrayList VarDecls = new ArrayList();	
		OneDecl(out type, out name);
		VarDecls.Add(name);	
		while (la.kind == 8) {
			Get();
			OneDecl(out type, out name);
			VarDecls.Add(name);	
		}
		Expect(9);
		Type(out type,out tpname,out obj);
		endT = SymTab.getSizeTable();
		SymTab.errorsType(type,init,endT);	  
			   		if (type == array)
			SymTab.validateArray(obj);
		SymTab.UpdateEntry(type,tpname,init,endT);
		code = SymTab.declLineArray(VarDecls, type, level);
		
		Expect(10);
	}

	void SubProgDef(out string code) {
		string codearg = "", code2 = "", code4 = "", codeInit = "",
		typeStr = "", name="", stat_code = "",
		name_res = "", fun_type = "void "; 
		int type = undef, type1 = undef, init, endT; 
		code = "";
		object obj = new object();
					string varDeclCodeTMP = varDeclCode; varDeclCode = "";
					string actualFunTMP = SymTab.GetActFun();
					int identationTMP = SymTab.GetCurIdent();
					SymTab.SetCurIdent(0);	
		Expect(69);
		Expect(1);
		SymTab.SetActFun(t.val);
		SymTab.OpenScope();
		level++;
					name = t.val;	
		Expect(29);
		SymTab.initDimensions2();	
		FormalArgs(out codearg);
		Expect(30);
		if (la.kind == 70) {
			Get();
			Type(out type,out typeStr, out obj);
			switch (type)
			{
			case(1): fun_type = "int ";
					 break;
			case(2): fun_type = "int ";
					 break;
			case(3): fun_type = "int * ";
						
						init = SymTab.getSizeTable();
						name_res = SymTab.genVar();
						SymTab.AddEntry(name_res,type,typeStr,level,obj);
						endT = SymTab.getSizeTable();
						SymTab.errorsType(type,init,endT);
						SymTab.validateArray(obj);
						SymTab.UpdateEntry(type,name,init,endT);
			
														ArrayList dim = SymTab.returnDim(name_res);
														int array_size = 0;
			
														foreach(int el in dim)
															array_size += el;
			
														SymTab.IncIdent();
														varDeclCode += SymTab.PrintIdent() + "int * " + name_res +
																		" = malloc(sizeof(int) * " +
																		array_size + ");\n";
														SymTab.DecIdent();
			
													 break;
											case(4): fun_type = "set ";
													 break;
											case(5): fun_type = "list ";
													 break; 
											default: break;
										}
			           				
			           				
		}
		SymTab.AddEntryFun(name,SymTab.findSize(typeStr),level,typeStr, obj);
		SymTab.UpdateEntry(name);
		
		SymTab.offset = SymTab.findSize(name) + SymTab.sizeDimensions(name); 
		 				
		codeInit += SymTab.PrintIdent() + fun_type + name;
		codeInit += SymTab.GetComments();	
		Expect(4);
		code += SymTab.PrintIdent() + "{\n";
		SymTab.IncIdent();
		code += SymTab.GetComments();	
		if (la.kind == 5) {
			Get();
			while (la.kind == 1 || la.kind == 69) {
				Decls(out code2);
				varDeclCode += code2;	
			}
		}
		Expect(6);
		while (StartOf(1)) {
			Statement(out code2);
			stat_code += code2 + "\n";	
		}
		SymTab.localF++;	
		if (la.kind == 71) {
			ReturnStatement(name, out type1,out code4);
			if (typeStr.Length == 0)
			SemErr("Invalid return!");		
			 	if (type != type1)
			SemErr("Invalid return!");		
			else
			if (type == array)
			  	{
				init = SymTab.getSizeTable();
				stat_code += SymTab.AssignArray(name_res, code4, level) + ";\n";
				endT = SymTab.getSizeTable();
				if (init != endT)
					varDeclCode += SymTab.declLine(init, endT, level) + ";\n";
			  		
			  		stat_code += SymTab.PrintIdent() + "return " + name_res + ";\n";
			  	}
			  	else
			  		stat_code += SymTab.PrintIdent() + "return " + code4 + ";\n";
			  		
			  		
		}
		stat_code += SymTab.GetComments();	
		Expect(7);
		SymTab.offset = 0;
		if (typeStr.Length == 0 && code4.Length != 0)
		SemErr("Invalid Return!");
		 	else if (typeStr.Length != 0 && code4.Length == 0)
		SemErr("Missing Return!");
		 	
		 	SymTab.DecIdent();
		 	
		 	code = codeInit + "(" + SymTab.getArgDecl(name, codearg) + ")" + "\n"
		 					+ code;
		 	
		 	code += varDeclCode + "\n" + stat_code + SymTab.PrintIdent();
		code += "}\n";
					varDeclCode = varDeclCodeTMP;
					SymTab.SetActFun(actualFunTMP);
		code = SymTab.substArg(code, name, level);
		  	SymTab.SetCurIdent(identationTMP);
		  	SymTab.CloseScope(level);
		  	level--;				  	
	}

	void OneDecl(out int type, out string name) {
		type = undef;
		string code1 = "";
		Object obj = null;	
		Expect(1);
		name = t.val;
		SymTab.AddEntry(name,level);	
		if (la.kind == 11) {
			Get();
			InicVar(out type, out obj, out code1);
			SymTab.UpdateEntry(name, type, obj);	
		}
		SymTab.UpdateEntry(name, code1);	
	}

	void Type(out int type,out string name,out object obj) {
		name = "";
		obj = new object();	
		type = undef;	
		if (la.kind == 12) {
			Get();
			name = "Integer";
			type = integer;	
		} else if (la.kind == 13) {
			Get();
			name = "Boolean";
			type = boolean;	
		} else if (la.kind == 16) {
			Array(out name,out obj);
			type = array;	
		} else if (la.kind == 14) {
			Get();
			name = "Set";
			type = sets;	
		} else if (la.kind == 15) {
			Get();
			name = "Sequence";
			type = sequence;	
		} else SynErr(75);
	}

	void InicVar(out int type, out Object obj,out string code) {
		obj = new Object(); code = "";
		string sign = ""; type = undef; 
		int num;	
		if (StartOf(3)) {
			Constant(out sign,out num, out type, out code);
			if (sign.Equals("-"))
			obj = -num;
			else
				obj = num;	
		} else if (la.kind == 20) {
			ArrayDef(out obj, out code);
			obj = SymTab.isVector(); 
			type = array;	
		} else if (la.kind == 4) {
			SetDef(out obj);
			type = sets;	
		} else if (la.kind == 22) {
			SequenceDef(out obj);
			type = sequence;	
		} else SynErr(76);
	}

	void Array(out string name,out object dim) {
		int num, size = 0; 			
		Expect(16);
		Expect(17);
		Expect(2);
		SymTab.initDimensions();
		size = Convert.ToInt32(t.val);
		SymTab.AddDimension(size);
		name = "Array_" + arrayNum;	 
		while (la.kind == 8) {
			Get();
			Expect(2);
			num = Convert.ToInt32(t.val); 
			size = size * num; 
						SymTab.AddDimension(num);		
		}
		dim = SymTab.returnDimensions();
		if (SymTab.validateBraces(dim))
		{
			SymTab.AddLineTable(arrayNum,size,dim);
					arrayNum++;				
		}	
	}

	void Constant(out string sign,out int num,out int type, out string code) {
		num = 0; type = undef; code = "";
		sign = "";	
		if (la.kind == 2 || la.kind == 43 || la.kind == 44) {
			if (la.kind == 43 || la.kind == 44) {
				Sign(out sign);
			}
			Expect(2);
			type = integer;
			num = Convert.ToInt32(t.val);
			code = sign + t.val;	
		} else if (la.kind == 18) {
			Get();
			type = boolean;
			num = 1;	
			code = "1";	
		} else if (la.kind == 19) {
			Get();
			type = boolean;
			num = 0;
			code = "0";	
		} else SynErr(77);
	}

	void ArrayDef(out object obj, out string code) {
		string code1 = "";
		obj = new object();
		SymTab.newLine();
		SymTab.newBraces();
		SymTab.newInitArray();	
		SymTab.newOneDim();		
		Expect(20);
		OneOrMoreList(out obj, out code1);
		Expect(21);
		code = "{" + code1 + "}";	
	}

	void SetDef(out Object code) {
		ArrayList tree = new ArrayList(), 
		treeL = new ArrayList(),
		treeR = new ArrayList();
		code = new Object();	
		Expect(4);
		if (la.kind == 1) {
			Get();
			Expect(24);
			Tree(out treeL);
			tree.AddRange(treeL);	
			while (la.kind == 25) {
				Get();
				Tree(out treeR);
				tree.Insert(0, "||");
				tree.AddRange(treeR);	
			}
		}
		Expect(7);
		code = tree;	
	}

	void SequenceDef(out Object code) {
		ArrayList valinit = new ArrayList();
		code = new Object();	
		Expect(22);
		Expect(2);
		valinit.Add(Convert.ToInt32(t.val));	
		while (la.kind == 8) {
			Get();
			Expect(2);
			valinit.Add(Convert.ToInt32(t.val));	
		}
		Expect(23);
		code = valinit;	
	}

	void Sign(out string sign) {
		sign = "";		
		if (la.kind == 43) {
			Get();
			sign = t.val;	
		} else if (la.kind == 44) {
			Get();
			sign = t.val;	
		} else SynErr(78);
	}

	void OneOrMoreList(out object obj, out string code) {
		obj = new object(); string code1 = "", code2 = ""; code = "";	
		if (la.kind == 20) {
			Get();
			open++; 				
			OneOrMoreList(out obj, out code1);
			Expect(21);
			open--; 
			if (open == 1) 
			{
			obj = SymTab.returnInitArray();
			SymTab.AddLine(obj);      
			SymTab.newInitArray();
			}
			code = "{" + code1 + "}";	
			while (la.kind == 8) {
				Get();
				Expect(20);
				open++; 				
				OneOrMoreList(out obj, out code2);
				Expect(21);
				open--; 
				if (open == 1) 
				{
				obj = SymTab.returnInitArray();
				SymTab.AddLine(obj);
				SymTab.newInitArray();	
				}
				code += ", {" + code2 + "}";
								
			}
		} else if (la.kind == 2) {
			OneOrMoreNum(out obj, out code);
			SymTab.AddNumBraces(open);
			SymTab.AddArray(obj);
			SymTab.AddOneDim(obj);		
		} else SynErr(79);
	}

	void OneOrMoreNum(out object obj, out string code) {
		int num; code = "";
		obj = new Object();		
		SymTab.initList();  	 	
		Expect(2);
		num = Convert.ToInt32(t.val); 
		SymTab.addList(num);
		code += t.val;	
		while (la.kind == 8) {
			Get();
			Expect(2);
			num = Convert.ToInt32(t.val);
			 	       SymTab.addList(num);
			 	       code += "," + t.val;	
		}
		obj = SymTab.returnList();	
	}

	void Tree(out ArrayList tree) {
		ArrayList treeL = new ArrayList(),
		treeR = new ArrayList();
		tree = new ArrayList();	
		Tree2(out treeL);
		tree.AddRange(treeL);	
		while (la.kind == 26) {
			Get();
			Tree2(out treeR);
			tree.Insert(0, "&&");
			tree.AddRange(treeR);	
		}
	}

	void Tree2(out ArrayList tree) {
		string op;
		int type;
		tree = new ArrayList();	
		Expect(1);
		RelOp(out op, out type);
		Expect(2);
		tree.Add(SymTab.Operator(op));
		tree.Add("x");
		tree.Add(t.val);	
	}

	void RelOp(out string op,out int type) {
		op = ""; 		type = undef;	
		switch (la.kind) {
		case 49: {
			Get();
			op = "EQUAL";	type = boolean;	
			break;
		}
		case 50: {
			Get();
			op = "NOT";		type = boolean; 
			break;
		}
		case 51: {
			Get();
			op = "INF";		type = boolean; 
			break;
		}
		case 52: {
			Get();
			op = "INFEQ";	type = boolean;	
			break;
		}
		case 53: {
			Get();
			op = "SUPEQ";	type = boolean;	
			break;
		}
		case 54: {
			Get();
			op = "SUP"; 		type = boolean; 
			break;
		}
		case 22: {
			Get();
			op = "<<"; 		type = sets;	
			break;
		}
		default: SynErr(80); break;
		}
	}

	void Assignment(out string code) {
		code = "";
		int type = undef, type1=undef, type2, init, endT; 
		string name="", code2 = "", code_array = "";	
		if (la.kind == 1) {
			Designator(out type1, out type2, out code, out name);
			if (la.kind == 33) {
				Get();
				Expression(out type, out code2);
				if (type1 != type)
				SemErr("Bad attribution! Wrong types!");
				
											if (type == array)
											{
												init = SymTab.getSizeTable();
												code_array = SymTab.AssignArray(code, code2, level);
												endT = SymTab.getSizeTable();
												if (init != endT)
													varDeclCode += SymTab.declLine(init, endT, level) + ";\n";
												if (code_array == "")
													SemErr("Bad attribution! Arrays with different dimensions!");
												code = code_array;
											}
											else if (type != sets)
											{ 
												code = SymTab.PrintIdent() + code + " = " + code2;
											}								
											else
												code = SymTab.PrintIdent() + genCode.AssignSet(code2, code);
										
			} else if (la.kind == 29) {
				Get();
				SymTab.ValidCall(name,level,1); 	
				Arguments(name, out code2);
				code = SymTab.PrintIdent() + code + "(" + code2 + ")";			
				Expect(30);
			} else SynErr(81);
		} else if (la.kind == 35 || la.kind == 37 || la.kind == 38) {
			if (la.kind == 37) {
				Cons(out type, out code);
			} else if (la.kind == 35) {
				Tail(out type, out code);
			} else {
				Delete(out type, out code);
			}
			code = SymTab.PrintIdent() + code;	
		} else SynErr(82);
		Expect(10);
	}

	void WriteStatement(out string code) {
		int type=undef, init, endT; 
		string code2 = "", code_ln = "", com = "";
		code = "";	
		if (la.kind == 31) {
			Get();
		} else if (la.kind == 32) {
			Get();
			code_ln += SymTab.PrintIdent() + genCode.printLn();	
		} else SynErr(83);
		Expect(29);
		if (StartOf(4)) {
			Expression(out type, out code2);
			init = SymTab.getSizeTable();
			code += SymTab.print(code2, level) + code_ln;
			endT = SymTab.getSizeTable();
			if (init != endT)
				varDeclCode += SymTab.declLine(init, endT, level) + ";\n";	
		}
		Expect(30);
		com = SymTab.GetComments();	
		Expect(10);
		if (code2 == "")
		code = code_ln;
		
		if (SymTab.checkCaduceus())
			code = SymTab.genCaduceusCom() +
					code + SymTab.PrintIdent() + "*/\n";
		code = com + code;	
	}

	void Conditional(out string code) {
		code = "";	
		if (la.kind == 55) {
			IfThenElse(out code);
		} else if (la.kind == 58) {
			ForStatement(out code);
		} else if (la.kind == 67) {
			WhileStatement(out code);
		} else SynErr(84);
	}

	void Read(out string code) {
		string name="";			
		Expect(68);
		Expect(29);
		Expect(1);
		name = t.val;
		SymTab.CheckVar(name, level);
		code = genCode.Read(SymTab.GetCorrectName(name));	
		Expect(30);
		Expect(10);
	}

	void SucOrPred(out string code) {
		code = "";	
		int type; 
		string name="", op = ""; 	
		if (la.kind == 27) {
			Get();
			op += "++";		
		} else if (la.kind == 28) {
			Get();
			op += "--";		
		} else SynErr(85);
		Expect(29);
		Expect(1);
		name = t.val;
		type = SymTab.findType(t.val);
		SymTab.Expect(type,integer);
		SymTab.CheckVar(name, level);
		code = op + SymTab.GetCorrectName(name);				
		Expect(30);
		Expect(10);
	}

	void Copy(out int type, out string code) {
		type = undef;
		code = "";
		int type1 = undef, type2 = undef;	
		string src = "", dest = "";	
		Expect(39);
		Expect(29);
		Expect(1);
		src = t.val;		
		type1 = SymTab.findType(src);
		SymTab.Expect(sequence,type1);
		if (type1 == undef)
			SemErr("Variable '" + src + "' isn't defined!");
		SymTab.CheckVar(src, level);	
		Expect(8);
		Expect(1);
		dest = t.val; 
		type2 = SymTab.findType(dest);
		
									SymTab.Expect(sequence,type2);
		
									if (type2 == undef)
										SemErr("Variable '" + dest + "' isn't defined!");  
									type = sequence;
									
									SymTab.CheckVar(dest, level);
									
									code = genCode.Copy(SymTab.GetCorrectName(src), SymTab.GetCorrectName(dest));	
		Expect(30);
		Expect(10);
	}

	void Expression(out int type, out string code) {
		string op = "",code2; 
		int type1=undef,type2=undef;	
		SimpleExpression(out type, out code);
		if (StartOf(5)) {
			RelOp(out op,out type1);
			SimpleExpression(out type2, out code2);
			if (type1 != sets)
			{
			if (type != type2)
				SemErr("Bad attribution! Wrong types!"); 
			  	code  += SymTab.Operator(op) + code2;	     
			}
			else
			{
							    if (type1 != type2)
					SemErr("Bad attribution! Wrong types!");
				else
					code = genCode.IsInSet(code, code2);
			}	
			type = boolean;	// to indicate that the result is boolean
			
		}
	}

	void Designator(out int type, out int type2, out string code, out string name) {
		code =""; 
		string code2 = "";	
		Expect(1);
		name = t.val;	
		type = SymTab.findType(name); 
		type2 = SymTab.findType(name);
		if (type == undef && ! SymTab.getClass(name).Equals("subProgram"))
			SemErr("Variable " + name + " isn't defined!");
		SymTab.CheckVar(name, level);
		code += SymTab.GetCorrectName(name); 
		if (la.kind == 20) {
			Get();
			if ( (type != array) && (type != sequence) )
			SemErr("Wrong type!");		
			Elem(name, out code2, out type);
			if ( SymTab.findType(name) == sequence )
			code = genCode.IndexSequence(code2, SymTab.GetCorrectName(name));
			else
				code += code2;	
			Expect(21);
		}
	}

	void Arguments(string name, out string code) {
		code = "";
		int argCount = 0;
		string code2;						
		if (StartOf(4)) {
			OneArg(name,argCount, out code);
			argCount++;  							
			while (la.kind == 8) {
				Get();
				OneArg(name,argCount, out code2);
				argCount++; 		
				code += "," + code2; 					
			}
		}
		if (argCount != SymTab.nParam(name))
		                   SemErr("Wrong number of parameters in '" + name + "'");
		code = SymTab.GetCorrectArg(name, code, level);	
	}

	void Cons(out int type, out string code) {
		type = undef;
		code = "";
		int type2 = undef;
		string name = "";	
		Expect(37);
		Expect(29);
		Expression(out type, out code);
		Expect(8);
		Expect(1);
		name = t.val;
		type2 = SymTab.findType(name);
		if (type2 == undef)
			SemErr("Variable '" + name + "' isn't defined!");  
		SymTab.CheckVar(name, level);
		code = genCode.Cons(code, SymTab.GetCorrectName(name));	
		Expect(30);
	}

	void Tail(out int type, out string code) {
		type = undef;
		code = "";				
		int type2 = undef;	
		Expect(35);
		Expect(29);
		Expression(out type2, out code);
		type = sequence;
		SymTab.Expect(sequence,type2);
		code = genCode.Tail(code);				
		
		Expect(30);
	}

	void Delete(out int type, out string code) {
		type = undef;
		code = "";
		int type2 = undef;	
		string name = "";				
		Expect(38);
		Expect(29);
		Expression(out type, out code);
		Expect(8);
		Expect(1);
		name = t.val; 
		type2 = SymTab.findType(name);
		SymTab.Expect(integer,type);
		if (type2 == undef)
			SemErr("Variable '" + name + "' isn't defined!");  
		type = sequence;
		SymTab.CheckVar(name, level);
		code = genCode.Delete(code,SymTab.GetCorrectName(name));	
		Expect(30);
	}

	void OneArg(string name, int argCount, out string code) {
		int argType;	
		Expression(out argType, out code);
		SymTab.Compatible(argCount, argType, name);	
	}

	void Elem(string name, out string code,out int type2) {
		code = ""; type2 = undef;
		string code1 = "", code2 = "";
		int num = 0, type, type3;
		SymTab.initIndexes();
		type3 = SymTab.findType(name);				
		Expression(out type, out code1);
		if (type3 == sequence)
		code = code1;
		else
			code = "[" + code1 + "]";
		SymTab.Expect(integer, type);
		   num++;			
		while (la.kind == 8) {
			Get();
			Expression(out type, out code2);
			SymTab.Expect(integer, type);
			num++;
			if (type3 == array)
			  code += "[" + code2 + "]";			   		
			else
			  SemErr("Invalid Expression");				
		}
		SymTab.validateIndex(name,num);
		type2 = integer;				
	}

	void SimpleExpression(out int type, out string code) {
		code=""; 
		string sign="", op="", oper="", code2 = "", code1 = "";
		int type1;	
		Term(sign,op,out type, out code1);
		code += code1;	
		while (StartOf(6)) {
			AddOp(out op,out type1);
			if (type != type1)
			SemErr("Bad Attribution! Wrong Types!"); 
			  else
			  		    	  oper   = op;
								
			Term(sign,op,out type, out code2);
			if (type != type1)
			SemErr("Wrong Types!"); 
			  else 
			    	if (type != sets) 
			 			    	code += SymTab.Operator(oper) + code2;
			    	else
			{
			 	 		code = genCode.UnionSet(code, code2);
			}
			  			     		
		}
	}

	void Term(string sign,string op,out int type, out string code) {
		int type1 = undef; code = "";
		string code1 = "", code2 = "";	
		type = undef;	
		Factor(sign,out type, out code1);
		code += code1;	
		while (StartOf(7)) {
			MulOp(out op,out type1);
			if (type != type1)	
			SemErr("Wrong Types!");	
			Factor(sign,out type, out code2);
			if (type != type1)
			SemErr("Wrong Types!"); 
			else
				if (type != sets) 
			   			code += SymTab.Operator(op) + code2;
			 			else
			 		{
			  			code = genCode.InterceptionSet(code, code2);
			 		}	 
			 
		}
	}

	void AddOp(out string op, out int type) {
		op = ""; 	type = undef;	
		if (la.kind == 43) {
			Get();
			op = "ADD";	type = integer; 
		} else if (la.kind == 44) {
			Get();
			op = "SUB";	type = integer; 
		} else if (la.kind == 25) {
			Get();
			op = "OR";	type = boolean; 
		} else if (la.kind == 45) {
			Get();
			op = "++";   type = sets; 	
		} else SynErr(86);
	}

	void Factor(string sign,out int type, out string code) {
		type = undef; int num, type2, init, endT; 
		string name = "", code1 = "";
		code = ""; Object obj = new Object();	
		switch (la.kind) {
		case 2: case 18: case 19: case 43: case 44: {
			Constant(out sign,out num,out type,out code);
			break;
		}
		case 1: {
			Designator(out type, out type2, out code, out name);
			if (la.kind == 29) {
				Get();
				SymTab.ValidCall(name,level,0);	
				Arguments(name, out code1);
				Expect(30);
				code += "(" + code1 + ")";	
			}
			break;
		}
		case 29: {
			Get();
			Expression(out type, out code1);
			code += "(" + code1 + ")";	
			Expect(30);
			break;
		}
		case 34: {
			Get();
			Factor(sign,out type, out code1);
			code = "!" + code1;	
			break;
		}
		case 4: {
			SetDef(out obj);
			init = SymTab.getSizeTable();
			name = SymTab.genVar();
			SymTab.AddEntry(name,level);
			SymTab.UpdateEntry(name, sets, obj);
			SymTab.UpdateEntry(name, "");
				endT = SymTab.getSizeTable();
			varDeclCode += SymTab.declLine(init, endT, level) + ";\n";
			type = sets;
			code = name;	
			break;
		}
		case 35: {
			Tail(out type,out code);
			break;
		}
		case 36: {
			Head(out type,out code);
			break;
		}
		case 40: {
			Member(out type,out code);
			break;
		}
		case 41: {
			IsEmpty(out type,out code);
			break;
		}
		case 42: {
			Length(out code);
			type = integer;	
			break;
		}
		default: SynErr(87); break;
		}
	}

	void MulOp(out string op, out int type) {
		op = ""; 	type = undef;	
		if (la.kind == 46) {
			Get();
			op = "MUL";	type = integer; 
		} else if (la.kind == 47) {
			Get();
			op = "DIV";	type = integer; 
		} else if (la.kind == 26) {
			Get();
			op = "AND";	type = boolean; 
		} else if (la.kind == 48) {
			Get();
			op = "**";   type = sets;	
		} else SynErr(88);
	}

	void Head(out int type, out string code) {
		type = undef;
		code = "";
		int type2 = undef;	
		Expect(36);
		Expect(29);
		Expression(out type2, out code);
		type = integer;
		SymTab.Expect(sequence,type2);
		code = genCode.Head(code);		
		Expect(30);
	}

	void Member(out int type, out string code) {
		type = undef;
		code = "";
		int type2 = undef;	
		string name = "";	
		Expect(40);
		Expect(29);
		Expression(out type, out code);
		Expect(8);
		Expect(1);
		name = t.val; 
		type2 = SymTab.findType(name);
		SymTab.Expect(integer,type);
		if (type2 == undef)
			SemErr("Variable '" + name + "' isn't defined!");  
		type = boolean;
		SymTab.CheckVar(name, level);
		code = genCode.IsMember(code, SymTab.GetCorrectName(name));		
		Expect(30);
	}

	void IsEmpty(out int type, out string code) {
		type = undef;
		code = "";	
		Expect(41);
		Expect(29);
		Expression(out type, out code);
		SymTab.Expect(sequence,type);
		type = boolean;
		code += genCode.IsEmpty(code);	
		Expect(30);
	}

	void Length(out string code) {
		code = "";
		string name = "";				
		int type = undef;				
		Expect(42);
		Expect(29);
		Expect(1);
		name = t.val;				
		type = SymTab.findType(name);
		if ((type != array) && (type != sequence))
			SemErr("Invalid type!"); 
		SymTab.CheckVar(name, level);
		code = SymTab.Length(SymTab.GetCorrectName(name));	
		Expect(30);
	}

	void IfThenElse(out string code) {
		int type; code = "";
		string code1, code3="", code2="";	
		Expect(55);
		Expression(out type, out code1);
		SymTab.Expect(boolean, type);
		code = SymTab.PrintIdent() + "if (" + code1 + ")\n"; 
		code += SymTab.GetComments();
		elseT++;	
		Expect(56);
		Expect(4);
		code += SymTab.PrintIdent() + "{\n";
		SymTab.IncIdent();	
		BlockStat(out code2);
		code += code2;
		code += SymTab.GetComments();	
		Expect(7);
		SymTab.DecIdent();
		code += SymTab.PrintIdent() + "}\n";	
		Else(out code3);
		code += code3;	
	}

	void ForStatement(out string code) {
		string	code1 = "", lim1 = "", lim2 = "", inc = "",
		name, var, step = "", sat = ""; 
				code = ""; 
				int type;
				int actual_identation = SymTab.GetCurIdent();	
		Expect(58);
		Expect(29);
		Interval(out code, out lim1, out lim2, out name, out var);
		Expect(30);
		Step(name, out step, out inc);
		name = SymTab.GetCorrectName(name);
		type = SymTab.findType(var);
		if (type != array)
		{
			code = SymTab.PrintIdent();
			if ( (step == "stepUp") || (step == "") )
			{
				if (inc == "")
					inc = "1";
				code += "for(" + name + "=" + lim1 + "; "
						+ name + "<=" + lim2 + "; " 
						+ name + "+=" + inc + ")\n";
			}
		else
							code += "for(" + name + "=" + lim2 + "; "
						+ name + ">=" + lim1 + "; " 
						+ name + "-=" + inc + ")\n";
			code += SymTab.GetComments();
		}	
		Satisfy(out sat);
		if( sat != "" )
		{
			SymTab.IncIdent();
			code += SymTab.GetComments();
		code += SymTab.PrintIdent() + sat;
				}	
		Expect(4);
		if ( ! ((sat == "") && (type == array)) )
		code += SymTab.PrintIdent() + "{\n";
		
		SymTab.IncIdent();	
		BlockStat(out code1);
		code += code1;
		code += SymTab.GetComments();	
		Expect(7);
		SymTab.DecIdent();
		code += SymTab.PrintIdent() + "}\n";	
		if ( (sat != "") && (type == array) )
		{
			SymTab.DecIdent();
			code += SymTab.PrintIdent() + "}\n";
			
		}
		
		SymTab.DecIdent(SymTab.GetCurIdent() - actual_identation);
		
	}

	void WhileStatement(out string code) {
		int type; code = "";
		string code1, code2;	
		Expect(67);
		code = SymTab.PrintIdent() + "while ";  
		whileT++;					
		Expect(29);
		Expression(out type, out code1);
		if (type != 1)
		SemErr("Invalid type! Expected type is boolean!"); 	   
		Expect(30);
		code += "(" + code1 + ")\n";
		code += SymTab.GetComments();	
		Expect(4);
		code += SymTab.PrintIdent() + "{\n"; 
		SymTab.IncIdent();	
		BlockStat(out code2);
		code += code2;
		code += SymTab.GetComments();	
		Expect(7);
		SymTab.DecIdent();
		code += SymTab.PrintIdent() + "}\n";	
	}

	void BlockStat(out string code) {
		string code1 = "";
		code = "";	
		while (StartOf(1)) {
			Statement(out code1);
			code += code1;	
		}
	}

	void Else(out string code) {
		code = ""; string code1 = "";	
		if (la.kind == 57) {
			Get();
			code += SymTab.GetComments()
			+ SymTab.PrintIdent() + "else\n";	
			Expect(4);
			code += SymTab.PrintIdent() + "{\n";
			SymTab.IncIdent();	
			BlockStat(out code1);
			code += code1 + SymTab.GetComments();
			SymTab.DecIdent();	
			Expect(7);
			code += SymTab.PrintIdent() + "}\n";	
		} else if (StartOf(8)) {
		} else SynErr(89);
	}

	void Interval(out string code, out string lim1, out string lim2, out string name, out string var) {
		int type, type2 = undef, init, endT; code = ""; var = "";
		lim1 = ""; lim2 = "";	
		Expect(1);
		name = t.val;
		SymTab.CheckVar(name, level);	
		if (la.kind == 59) {
			Get();
			Range(out lim1, out lim2);
		} else if (la.kind == 60) {
			Get();
			Expect(1);
			init = SymTab.getSizeTable();
			type = SymTab.findType(t.val);
			SymTab.Expect(array, type);
			var = t.val;
			SymTab.CheckVar(var, level);
			code = SymTab.ForEach(name, var, level);
			endT = SymTab.getSizeTable();
			if (init != endT)
				varDeclCode += SymTab.declLine(init, endT, level) + ";\n";	
		} else if (la.kind == 61) {
			Get();
			Expect(1);
			var = t.val;
			      if (! (SymTab.getClass(var)).Equals("subProgram"))
			SemErr("Expected subProgram!");	
			Expect(29);
			type = SymTab.findType(name);
			type2 = SymTab.findType(var);
			if (type2 != type) 
			SemErr("Types mismatch! ");	
			Arguments(var, out code);
			Expect(30);
			if (la.kind == 62) {
				Get();
			}
		} else SynErr(90);
	}

	void Step(string name, out string step, out string val) {
		step = "";	val = "";
		if (la.kind == 64 || la.kind == 65) {
			if (la.kind == 64) {
				Get();
				step += "stepUp";	
			} else {
				Get();
				step += "stepDown";	
			}
			Expect(2);
			val += t.val;			
		} else if (la.kind == 4 || la.kind == 66) {
		} else SynErr(91);
	}

	void Satisfy(out string code) {
		string code1 = "";
		code=""; int type=undef;	
		if (la.kind == 66) {
			Get();
			Expression(out type, out code1);
			SymTab.Expect(boolean,type);
			code = "if (" + code1 + ")\n";		
		} else if (la.kind == 4) {
		} else SynErr(92);
	}

	void Range(out string lim1, out string lim2) {
		int type;
		lim1 = ""; lim2 = "";	
		if (la.kind == 2) {
			Get();
			lim1 = t.val;				
		} else if (la.kind == 1) {
			Get();
			type = SymTab.findType(t.val);
			SymTab.Expect(integer,type);
			lim1 = t.val;
			SymTab.CheckVar(lim1, level);
			lim1 = SymTab.GetCorrectName(lim1);		
		} else SynErr(93);
		Expect(63);
		if (la.kind == 2) {
			Get();
			lim2 = t.val;	 			
		} else if (la.kind == 1) {
			Get();
			type = SymTab.findType(t.val);
			SymTab.Expect(integer,type);
			lim2 = t.val;
			SymTab.CheckVar(lim2, level);
			lim2 = SymTab.GetCorrectName(lim2);	
		} else SynErr(94);
	}

	void FormalArgs(out string code) {
		string code2 = ""; code = "";
		SymTab.initDimensions();
		SymTab.initArgs();				
		if (la.kind == 1) {
			OneParam(out code);
			while (la.kind == 10) {
				Get();
				OneParam(out code2);
				code += ", " + code2;	
			}
		}
	}

	void ReturnStatement(string name, out int type, out string code) {
		type = undef; code = SymTab.GetComments();
		string code1 = "";	
		Expect(71);
		Expression(out type, out code1);
		code += code1 + SymTab.GetComments();	
		Expect(10);
	}

	void OneParam(out string code) {
		int type; code = "";
		string name, typeStr; 
		object dim;	
		Expect(1);
		name = t.val;	
		SymTab.AddArg(name);	
		Expect(9);
		Type(out type,out typeStr,out dim);
		SymTab.AddDimension2(typeStr);
		SymTab.AddEntry(name,type,typeStr,-level,dim);
		if (type == array)
		{
			string array_dim = "";
			foreach(int el in (ArrayList) dim)
				array_dim += "[" + el + "]";
			code += "int " + name + array_dim;
		}
		else if (type == sequence)
			code += "list " + name;
		else if (type == sets)
			code += "set " + name;
		else 
			code += "int " + name;
			
	}



	public void Parse() {
		la = new Token();
		la.val = "";		
		Get();
		Liss();

    Expect(0);
	}
	
	bool[,] set = {
		{T,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x},
		{x,T,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,T, T,x,x,T, T,x,x,T, x,T,T,T, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,T, x,x,T,x, x,x,x,x, x,x,x,T, T,x,x,x, x,x},
		{x,T,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,T, x,T,T,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x},
		{x,x,T,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,T,T, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,T, T,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x},
		{x,T,T,x, T,x,x,x, x,x,x,x, x,x,x,x, x,x,T,T, x,x,x,x, x,x,x,x, x,T,x,x, x,x,T,T, T,x,x,x, T,T,T,T, T,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x},
		{x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,T,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,T,T,T, T,T,T,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x},
		{x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,T,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,T, T,T,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x},
		{x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,T,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,T,T, T,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x},
		{x,T,x,x, x,x,x,T, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,T, T,x,x,T, T,x,x,T, x,T,T,T, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,T, x,x,T,x, x,x,x,x, x,x,x,T, T,x,x,T, x,x}

	};
} // end Parser


public class Errors {
	public int count = 0;                                    // number of errors detected
  public string errMsgFormat = "-- line {0} col {1}: {2}"; // 0=line, 1=column, 2=text
	
	public void SynErr (int line, int col, int n) {
		string s;
		switch (n) {
			case 0: s = "EOF expected"; break;
			case 1: s = "ident expected"; break;
			case 2: s = "number expected"; break;
			case 3: s = "\"program\" expected"; break;
			case 4: s = "\"{\" expected"; break;
			case 5: s = "\"declarations\" expected"; break;
			case 6: s = "\"statements\" expected"; break;
			case 7: s = "\"}\" expected"; break;
			case 8: s = "\",\" expected"; break;
			case 9: s = "\"->\" expected"; break;
			case 10: s = "\";\" expected"; break;
			case 11: s = "\":=\" expected"; break;
			case 12: s = "\"integer\" expected"; break;
			case 13: s = "\"boolean\" expected"; break;
			case 14: s = "\"set\" expected"; break;
			case 15: s = "\"sequence\" expected"; break;
			case 16: s = "\"array\" expected"; break;
			case 17: s = "\"size\" expected"; break;
			case 18: s = "\"true\" expected"; break;
			case 19: s = "\"false\" expected"; break;
			case 20: s = "\"[\" expected"; break;
			case 21: s = "\"]\" expected"; break;
			case 22: s = "\"<<\" expected"; break;
			case 23: s = "\">>\" expected"; break;
			case 24: s = "\"|\" expected"; break;
			case 25: s = "\"||\" expected"; break;
			case 26: s = "\"&&\" expected"; break;
			case 27: s = "\"succ\" expected"; break;
			case 28: s = "\"pred\" expected"; break;
			case 29: s = "\"(\" expected"; break;
			case 30: s = "\")\" expected"; break;
			case 31: s = "\"write\" expected"; break;
			case 32: s = "\"writeln\" expected"; break;
			case 33: s = "\"=\" expected"; break;
			case 34: s = "\"!\" expected"; break;
			case 35: s = "\"tail\" expected"; break;
			case 36: s = "\"head\" expected"; break;
			case 37: s = "\"cons\" expected"; break;
			case 38: s = "\"del\" expected"; break;
			case 39: s = "\"copy\" expected"; break;
			case 40: s = "\"ismember\" expected"; break;
			case 41: s = "\"isempty\" expected"; break;
			case 42: s = "\"length\" expected"; break;
			case 43: s = "\"+\" expected"; break;
			case 44: s = "\"-\" expected"; break;
			case 45: s = "\"++\" expected"; break;
			case 46: s = "\"*\" expected"; break;
			case 47: s = "\"/\" expected"; break;
			case 48: s = "\"**\" expected"; break;
			case 49: s = "\"==\" expected"; break;
			case 50: s = "\"!=\" expected"; break;
			case 51: s = "\"<\" expected"; break;
			case 52: s = "\"<=\" expected"; break;
			case 53: s = "\">=\" expected"; break;
			case 54: s = "\">\" expected"; break;
			case 55: s = "\"if\" expected"; break;
			case 56: s = "\"then\" expected"; break;
			case 57: s = "\"else\" expected"; break;
			case 58: s = "\"for\" expected"; break;
			case 59: s = "\"in\" expected"; break;
			case 60: s = "\"inarray\" expected"; break;
			case 61: s = "\"infunction\" expected"; break;
			case 62: s = "\"with\" expected"; break;
			case 63: s = "\"..\" expected"; break;
			case 64: s = "\"stepup\" expected"; break;
			case 65: s = "\"stepdown\" expected"; break;
			case 66: s = "\"satisfying\" expected"; break;
			case 67: s = "\"while\" expected"; break;
			case 68: s = "\"read\" expected"; break;
			case 69: s = "\"subprogram\" expected"; break;
			case 70: s = "\"::\" expected"; break;
			case 71: s = "\"return\" expected"; break;
			case 72: s = "??? expected"; break;
			case 73: s = "invalid Decls"; break;
			case 74: s = "invalid Statement"; break;
			case 75: s = "invalid Type"; break;
			case 76: s = "invalid InicVar"; break;
			case 77: s = "invalid Constant"; break;
			case 78: s = "invalid Sign"; break;
			case 79: s = "invalid OneOrMoreList"; break;
			case 80: s = "invalid RelOp"; break;
			case 81: s = "invalid Assignment"; break;
			case 82: s = "invalid Assignment"; break;
			case 83: s = "invalid WriteStatement"; break;
			case 84: s = "invalid Conditional"; break;
			case 85: s = "invalid SucOrPred"; break;
			case 86: s = "invalid AddOp"; break;
			case 87: s = "invalid Factor"; break;
			case 88: s = "invalid MulOp"; break;
			case 89: s = "invalid Else"; break;
			case 90: s = "invalid Interval"; break;
			case 91: s = "invalid Step"; break;
			case 92: s = "invalid Satisfy"; break;
			case 93: s = "invalid Range"; break;
			case 94: s = "invalid Range"; break;

			default: s = "error " + n; break;
		}
		Console.WriteLine(errMsgFormat, line, col, s);
		count++;
	}

	public void SemErr (int line, int col, int n) {
		Console.WriteLine(errMsgFormat, line, col, ("error " + n));
		count++;
	}

	public void Error (int line, int col, string s) {
		Console.WriteLine(errMsgFormat, line, col, s);
		count++;
	}

	public void Exception (string s) {
		Console.WriteLine(s); 
		System.Environment.Exit(1);
	}
} // Errors

}