context: 
  using System;
  
  namespace DCasm {
  
  
  
  public class Parser {
  	public const int _EOF = 0;
  	public const int _ident = 1;
  	public const int _number = 2;
  	public const int _registerNum = 3;
  	public const int maxT = 32;
  
  	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;
  
  public CodeGenerator gen;
    
  /*--------------------------------------------------------------------------*/
  
  
  	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.SemErr(t.line, t.col, msg);
  		errDist = 0;
  	}
  	
  	void Get () {
  		for (;;) {
  			t = la;
  			la = scanner.Scan();
  			if (la.kind <= maxT) { ++errDist; break; }
  
  			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) {
  		int kind = la.kind;
  		if (kind == n) {Get(); return true;}
  		else if (StartOf(repFol)) {return false;}
  		else {
  			SynErr(n);
  			while (!(set[syFol, kind] || set[repFol, kind] || set[0, kind])) {
  				Get();
  				kind = la.kind;
  			}
  			return StartOf(syFol);
  		}
  	}
  
  	
  	void DCasm() {
  		if (la.kind == 4) {
  			Get();
  			gen.Type = FileTypeEnum.Program; 
  		} else if (la.kind == 5) {
  			Get();
  			gen.Type = FileTypeEnum.Module; 
  		} else SynErr(33);
  		while (la.kind == 6) {
  			Get();
  			moduleName(out string name);
  			if(gen.Type == FileTypeEnum.Program) gen.ImportModule(name); else throw new ArgumentException("you cannot import a module into another"); 
  		}
  		Block(out INode node);
  		node.Children.ForEach(c => gen.RootNodes.Add(c)); 
  		Expect(0);
  	}
  
  	void moduleName(out string name) {
  		Expect(1);
  		name = t.val; 
  	}
  
  	void Block(out INode node) {
  		node = new Block(); 
  		Expect(7);
  		BlockUnit(out INode exp);
  		node.Children.Add(exp); 
  		while (StartOf(1)) {
  			BlockUnit(out INode exp2);
  			node.Children.Add(exp2); 
  		}
  		Expect(8);
  	}
  
  	void BlockUnit(out INode exp) {
  		exp = new Error(); 
  		switch (la.kind) {
  		case 11: case 12: case 13: case 14: {
  			arithm(out exp);
  			break;
  		}
  		case 9: case 10: {
  			immediateLoad(out exp);
  			break;
  		}
  		case 15: case 16: case 17: case 18: case 19: {
  			data(out exp);
  			break;
  		}
  		case 20: {
  			function(out exp);
  			break;
  		}
  		case 22: {
  			Call(out exp);
  			break;
  		}
  		case 23: {
  			Condition(out exp);
  			break;
  		}
  		case 31: {
  			While(out exp);
  			break;
  		}
  		default: SynErr(34); break;
  		}
  	}
  
  	void arithm(out INode exp) {
  		exp = new Error();
  		arithmOp(out string op);
  		register(out INode dest);
  		register(out INode src1);
  		if (la.kind == 3) {
  			register(out INode src2);
  			exp = ArithmFactory.Create(op, dest, src1, src2); 
  		} else if (la.kind == 2) {
  			constant(out INode src2);
  			exp = ArithmFactory.Create(op, dest, src1, src2); 
  		} else SynErr(35);
  	}
  
  	void immediateLoad(out INode exp) {
  		exp = new Error(); 
  		if (la.kind == 9) {
  			Get();
  			exp = new ImmediateLoad(false); 
  		} else if (la.kind == 10) {
  			Get();
  			exp = new ImmediateLoad(true); 
  		} else SynErr(36);
  		register(out INode dest);
  		constant(out INode val);
  		exp.Children.Add(dest); exp.Children.Add(val); 
  	}
  
  	void data(out INode exp) {
  		exp = new Error(); 
  		if (la.kind == 15) {
  			Get();
  			register(out INode dest);
  			register(out INode source);
  			exp = new Move(source, dest); 
  		} else if (la.kind == 16) {
  			Get();
  			register(out INode OutputSelection);
  			if (la.kind == 3) {
  				register(out INode val);
  				exp = new Write(OutputSelection, val); 
  			} else if (la.kind == 2) {
  				constant(out INode val);
  				exp = new Write(OutputSelection, val); 
  			} else SynErr(37);
  		} else if (la.kind == 17) {
  			Get();
  			register(out INode inputSelection);
  			register(out INode dest);
  			exp = new Read(inputSelection, dest); 
  		} else if (la.kind == 18) {
  			Get();
  			register(out INode dest);
  			register(out INode baseReg);
  			register(out INode offset);
  			exp = new Load(dest, baseReg, offset); 
  		} else if (la.kind == 19) {
  			Get();
  			register(out INode value);
  			register(out INode baseReg);
  			register(out INode offset);
  			exp = new Store(baseReg, offset, value); 
  		} else SynErr(38);
  	}
  
  	void function(out INode function) {
  		Expect(20);
  		functionName(out string name);
  		function = new Function(name); 
  		while (StartOf(2)) {
  			if (StartOf(3)) {
  				arithm(out INode exp);
  				function.Children.Add(exp); 
  			} else if (la.kind == 9 || la.kind == 10) {
  				immediateLoad(out INode exp);
  				function.Children.Add(exp); 
  			} else if (StartOf(4)) {
  				data(out INode exp);
  				function.Children.Add(exp); 
  			} else if (la.kind == 22) {
  				Call(out INode exp);
  				function.Children.Add(exp); 
  			} else {
  				Condition(out INode exp);
  				function.Children.Add(exp); 
  			}
  		}
  		Expect(21);
  		function.Value = name; function.Children.Add(new Return(name)); gen.Functions.Add(name, function); 
  	}
  
  	void Call(out INode exp) {
  		Expect(22);
  		functionName(out string name);
  		exp = new Call(name); 
  	}
  
  	void Condition(out INode node) {
  		Expect(23);
  		Comparaison(out INode reg1, out string op, out INode reg2);
  		Expect(24);
  		Block(out INode thenblock);
  		node = new Condition(new Comparaison(op, reg1, reg2), thenblock); 
  		if (la.kind == 25) {
  			Get();
  			Block(out INode elseBlock);
  			node = new Condition(new Comparaison(op, reg1, reg2), thenblock, elseBlock); 
  		}
  	}
  
  	void While(out INode Node) {
  		Expect(31);
  		Comparaison(out INode reg1, out string op, out INode reg2);
  		Block(out INode exp);
  		Node = new While(exp, new Comparaison(op, reg1, reg2)); 
  	}
  
  	void register(out INode node) {
  		Expect(3);
  		node = new Register(); node.Value = t.val; 
  	}
  
  	void constant(out INode val) {
  		val = null; 
  		Expect(2);
  		val = new Const(t.val); 
  	}
  
  	void arithmOp(out string op) {
  		op = "";
  		if (la.kind == 11) {
  			Get();
  		} else if (la.kind == 12) {
  			Get();
  		} else if (la.kind == 13) {
  			Get();
  		} else if (la.kind == 14) {
  			Get();
  		} else SynErr(39);
  		op = t.val; 
  	}
  
  	void functionName(out string name) {
  		Expect(1);
  		name = t.val; 
  	}
  
  	void Comparaison(out INode reg1, out string op, out INode reg2) {
  		reg1 = new Const("-1"); reg2 = new Const("-1"); 
  		if (la.kind == 3) {
  			register(out reg1);
  		} else if (la.kind == 2) {
  			constant(out reg1);
  		} else SynErr(40);
  		ConditionOp(out op);
  		if (la.kind == 3) {
  			register(out reg2);
  		} else if (la.kind == 2) {
  			constant(out reg2);
  		} else SynErr(41);
  	}
  
  	void ConditionOp(out string op) {
  
gt: 		if (la.kind == 26) {