/* PL0Interpret.java - interpretace generovanych kodu jazyka PL0
 *
 * Michal Beran, berny@students.zcu.cz
 * 4.1.2001  
 */
package pl0prog;

import java.io.*;


public class PL0Interpret {

	/** Maximalni velikost zasobniku */
	private static final int STACKSIZE = 500;
	/** Pouzivana tabulka instrukci */
	private CodeGen Code;
	/** Pouzivana tabulka symbolu */
	private SymbolT Symbol;
	/** Zasobnik */
	private int[] Stack = new int[STACKSIZE];
	/** Aktualni uroven zanoreni */
	private int CurrentLevel;

	/** Vytvari novy interpret PL0.
	  * @param sym vygenerovana tabulka symbolu,
	  * @param code vygenerovana tabulka instrukci/
	  */
	public PL0Interpret(SymbolT sym, CodeGen code) {
		Code = code;
		Symbol = sym;
	}

	/** Metoda pro zjisteni pocatecni adresy na urovni, ktera je 
	  * o l vyssi nez soucasna uroven, ve ktere je prave vykonan program.
	  * @param l rozdil pozadovane a aktualni urovne,
	  * @return adresa pocatecni urovne.
	  */
	private int base(int l) {
		int BaseLevel;

		BaseLevel= CurrentLevel;
		while (l>0) {
			BaseLevel=Stack[BaseLevel];
			l--;
		}
		return BaseLevel;
	}

	/** Metoda spusteni interpretu.
	  */
	public void run() {
		int p,t;
		GenInstruction i;


		System.out.println("START PL/0\n");
		t=p=Stack[1]=Stack[2]=Stack[3]=0;CurrentLevel=1;
		do 
		{
			i=Code.getInstruction(p++);
			switch (i.functionCode) {
				case Fct.LIT:Stack[++t]=i.operand;break;
				case Fct.OPR:switch (i.operand) {
	      			case OOperation.NEG : Stack[t]=-Stack[t];
						break;
					case OOperation.ADD : t--;
						Stack[t]+=Stack[t+1]; break;
					case OOperation.SUB : t--;
						Stack[t]-=Stack[t+1];
						break;
					case OOperation.MUL : t--;
						Stack[t]*=Stack[t+1];
						break;
					case OOperation.DI :  t--;
						Stack[t]/=Stack[t+1];
						break;
					case OOperation.MOD : t--;
						Stack[t]=Stack[t]%Stack[t+1];
						break;
					case OOperation.ODD : Stack[t]=Stack[t]%2;
						break;
					case OOperation.EQ : t--;
			       		Stack[t]=(Stack[t]==Stack[t+1])? 1:0;
			       		break;
					case OOperation.NE : t--;
		       			Stack[t]=(Stack[t]!=Stack[t+1]) ? 1:0;
		       			break;
					case OOperation.LT : t--;
				       Stack[t]=(Stack[t]<Stack[t+1]) ? 1:0;
		    		    break;
					case OOperation.GE : t--;
				       Stack[t]=(Stack[t]>=Stack[t+1])? 1:0;
				       break;
					case OOperation.GT : t--;
				       Stack[t]=(Stack[t]>Stack[t+1])? 1:0;
				       break;
					case OOperation.LE : t--;
				       Stack[t]=(Stack[t]<=Stack[t+1])? 1:0;
				       break;
				    }
				    break;
			   	case Fct.LOD:t++;
				    Stack[t]=Stack[base(i.level)+i.operand];
			    	break;
			    case Fct.STO:Stack[base(i.level)+i.operand]=Stack[t];
				    System.out.println(Stack[t--]);
				    break;
				case Fct.CAL:Stack[t+1]=base(i.level);
				    Stack[t+2]=CurrentLevel;
				    Stack[t+3]=p;
				    CurrentLevel=t+1;
				    p=i.operand;
				    break;
			    case Fct.RET:t=CurrentLevel-1;
				    p=Stack[t+3];
				    CurrentLevel=Stack[t+2];
				    break;
			    case Fct.ING:t+=i.operand;break;
			    case Fct.JMP:p=i.operand;break;
			    case Fct.JPC:if (Stack[t]==0) p=i.operand;
	    			t--;
	    			break;
  			}
		System.out.println(p);
		} while (p != 0);
 
		try {

			Code.list("LIST.TAB");
			Symbol.list("SYMBOL.TAB");
		}
		catch (IOException e) {
			System.out.println("Chyba pri zapisu do pomocnych souboru\n");
		}
		System.out.println(" END PL/0\n");
	}

}