package compiler.lincode;
import java.util.HashMap;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.Scanner;
import compiler.frames.Frame;
import compiler.frames.Label;
import compiler.frames.Temp;
import compiler.imcode.ImcBINOP;
import compiler.imcode.ImcCALL;
import compiler.imcode.ImcCJUMP;
import compiler.imcode.ImcCONST;
import compiler.imcode.ImcChunk;
import compiler.imcode.ImcCodeChunk;
import compiler.imcode.ImcConstChunk;
import compiler.imcode.ImcDataChunk;
import compiler.imcode.ImcEXP;
import compiler.imcode.ImcExpr;
import compiler.imcode.ImcJUMP;
import compiler.imcode.ImcLABEL;
import compiler.imcode.ImcMEM;
import compiler.imcode.ImcMOVE;
import compiler.imcode.ImcNAME;
import compiler.imcode.ImcSEQ;
import compiler.imcode.ImcStmt;
import compiler.imcode.ImcTEMP;
import compiler.report.Report;
public class Interpreter {
int debug = 0;
/** Pomnilnik. */
public HashMap<Integer,Integer> memory = new HashMap<Integer,Integer>();
/** Preslikava label globalnih spremenljivk in konstant v naslove. */
public HashMap<String,Integer> labels = new HashMap<String,Integer>();
/** Preslikava label funkcij v kodo. */
public HashMap<String,ImcCodeChunk> chunks = new HashMap<String,ImcCodeChunk>();
/** Lokalne spremenljivke. */
public HashMap<String,Integer> temps = new HashMap<String,Integer>();
/** Kazalec na sklad. */
public Integer SP;
/** Kazalec na klicni zapis. */
public Integer FP;
/** Kazalec na kopico. */
public Integer HP;
public Interpreter(LinkedList<ImcChunk> progChunks) {
SP = 65536;
FP = 65536;
HP = 1024;
Iterator<ImcChunk> chunks = progChunks.iterator();
while (chunks.hasNext()) {
ImcChunk chunk = chunks.next();
if (chunk instanceof ImcCodeChunk) {
ImcCodeChunk codeChunk = (ImcCodeChunk)chunk;
this.chunks.put(codeChunk.frame.label.name(), codeChunk);
}
if (chunk instanceof ImcDataChunk) {
ImcDataChunk dataChunk = (ImcDataChunk)chunk;
this.labels.put(dataChunk.label.name(), HP);
HP = HP + dataChunk.size;
}
if (chunk instanceof ImcConstChunk) {
ImcConstChunk constChunk = (ImcConstChunk)chunk;
this.labels.put(constChunk.label.name(), HP);
for (int i = 0; i < constChunk.value.length(); i++) {
ST(HP + i * 4, new Integer(constChunk.value.charAt(i)));
}
ST(HP + constChunk.size, 0);
HP = HP + constChunk.size + 4;
}
}
execFun("_main");
}
public static String prefix = "";
public Integer execFun(String label) {
if (label.equals("_new")) {
Integer addr = HP;
HP = HP + LD(SP + 4);
return addr;
}
if (label.equals("_free")) {
return 0;
}
if (label.equals("_read_int")) {
return (new Scanner(System.in)).nextInt();
}
if (label.equals("_print_char")) {
System.out.print((char)(LD(SP + 4)).byteValue());
return 0;
}
if (label.equals("_print_int")) {
System.out.print(LD(SP + 4));
return 0;
}
if (debug == 1) System.err.println(prefix + "=> " + label + " SP:" + SP + " FP:" + FP);
ImcCodeChunk chunk = chunks.get(label);
Frame frame = chunk.frame;
HashMap<String,Integer> outerTemps = temps;
temps = new HashMap<String,Integer>();
// Prolog:
ST(SP - frame.sizeLocs - 4, FP);
FP = SP;
SP = SP - frame.size();
ST(frame.FP, FP);
if (debug == 1) System.err.println(prefix + "in " + label + " SP:" + SP + " FP:" + FP);
// jedro:
LinkedList<ImcStmt> stmts = ((ImcSEQ)(chunk.lincode)).stmts;
int PC = 0;
while (PC < stmts.size()) {
Label newLabel = execStmt(stmts.get(PC));
if (newLabel != null) {
// Razveljavimo cevovod:
PC = stmts.indexOf(new ImcLABEL(newLabel));
}
else PC++;
}
// Epilog:
SP = SP + frame.size();
FP = LD(SP - frame.sizeLocs - 4);
Integer retValue = LD(frame.RV);
if (debug == 1) System.err.println(prefix + "<= " + label + " SP:" + SP + " FP:" + FP);
temps = outerTemps;
return retValue;
}
public Label execStmt(ImcStmt stmt) {
if (debug == 1) System.err.println(prefix + stmt);
if (stmt instanceof ImcCJUMP) {
ImcCJUMP cjump = (ImcCJUMP)stmt;
Integer cond = execExpr(cjump.cond);
return cond != 0 ? cjump.trueLabel : cjump.falseLabel;
}
if (stmt instanceof ImcEXP) {
ImcEXP expr = (ImcEXP)stmt;
execExpr(expr.expr);
return null;
}
if (stmt instanceof ImcJUMP) {
return ((ImcJUMP)stmt).label;
}
if (stmt instanceof ImcLABEL) {
return null;
}
if (stmt instanceof ImcMOVE) {
ImcMOVE move = (ImcMOVE)stmt;
if (move.dst instanceof ImcTEMP) {
ImcTEMP dst = (ImcTEMP)move.dst;
Integer src = execExpr(move.src);
ST(dst.temp, src);
return null;
}
if (move.dst instanceof ImcMEM) {
Integer dst = execExpr(((ImcMEM)move.dst).expr);
Integer src = execExpr(move.src);
ST(dst, src);
return null;
}
Report.error("Illegal MOVE statement.", 0);
}
Report.error("Unknown statement: " + stmt, 0);
return null;
}
public Integer execExpr(ImcExpr expr) {
// if (debug == 1) System.err.println(prefix + expr);
if (expr instanceof ImcBINOP) {
ImcBINOP binop = (ImcBINOP)expr;
Integer lval = execExpr(binop.limc);
Integer rval = execExpr(binop.rimc);
switch (binop.op) {
case ImcBINOP.ADD: return lval + rval;
case ImcBINOP.SUB: return lval - rval;
case ImcBINOP.MUL: return lval * rval;
case ImcBINOP.DIV: return lval / rval;
case ImcBINOP.EQU: return (lval == rval ? 1 : 0);
case ImcBINOP.NEQ: return (lval != rval ? 1 : 0);
case ImcBINOP.LTH: return (lval < rval ? 1 : 0);
case ImcBINOP.GTH: return (lval > rval ? 1 : 0);
case ImcBINOP.LEQ: return (lval <= rval ? 1 : 0);
case ImcBINOP.GEQ: return (lval >= rval ? 1 : 0);
case ImcBINOP.AND: return lval * rval;
case ImcBINOP.OR : return (lval + rval) % 2;
}
}
if (expr instanceof ImcCALL) {
ImcCALL call = (ImcCALL)expr;
for (int a = 0; a < call.args.size(); a++) {
Integer v = execExpr(call.args.get(a));
ST(SP + 4 * a, v);
}
prefix = prefix + " ";
Integer result = execFun(call.label.name());
prefix = prefix.substring(2);
return result;
}
if (expr instanceof ImcCONST) {
return ((ImcCONST)expr).value;
}
if (expr instanceof ImcMEM) {
return LD(execExpr(((ImcMEM)expr).expr));
}
if (expr instanceof ImcNAME) {
return labels.get(((ImcNAME)expr).label.name());
}
if (expr instanceof ImcTEMP) {
return LD(((ImcTEMP)expr).temp);
}
Report.error("Unknown expression: " + expr, 0);
return null;
}
public Integer LD(Integer addr) {
Integer data = memory.get(addr / 4);
if (debug == 1) System.err.println(prefix + "[" + addr + "]" + "->" + (data == null ? 0 : data));
if (data == null) return 0; else return data;
}
public Integer LD(Temp temp) {
Integer value = temps.get(temp.name());
if (debug == 1) System.err.println(prefix + temp.name() + "->" + (value == null ? 0 : value));
if (value == null) return 0; else return value;
}
public void ST(Integer addr, Integer data) {
if (debug == 1) System.err.println(prefix + "[" + addr + "]" + "<-" + data);
memory.put(addr / 4, data);
}
public void ST(Temp temp, Integer value) {
if (debug == 1) System.err.println(prefix + temp.name() + "<-" + value);
temps.put(temp.name(), value);
}
}