package compiler.imcode;
import java.util.LinkedList;
import compiler.abstree.AbsArrTyp;
import compiler.abstree.AbsAtomExpr;
import compiler.abstree.AbsAtomTyp;
import compiler.abstree.AbsBinExpr;
import compiler.abstree.AbsDecl;
import compiler.abstree.AbsDecls;
import compiler.abstree.AbsForStmt;
import compiler.abstree.AbsFunDecl;
import compiler.abstree.AbsFunName;
import compiler.abstree.AbsIfStmt;
import compiler.abstree.AbsLetExpr;
import compiler.abstree.AbsPtrTyp;
import compiler.abstree.AbsRecTyp;
import compiler.abstree.AbsStmt;
import compiler.abstree.AbsStmts;
import compiler.abstree.AbsTypDecl;
import compiler.abstree.AbsTypName;
import compiler.abstree.AbsUnExpr;
import compiler.abstree.AbsValExpr;
import compiler.abstree.AbsValStmt;
import compiler.abstree.AbsVarDecl;
import compiler.abstree.AbsVarName;
import compiler.abstree.AbsWhileStmt;
import compiler.abstree.Visitor;
import compiler.frames.ArgAccess;
import compiler.frames.CmpAccess;
import compiler.frames.Frame;
import compiler.frames.Label;
import compiler.frames.LocAccess;
import compiler.frames.VarAccess;
import compiler.report.Report;
import compiler.semanal.SemAtomTyp;
import compiler.semanal.SemFunTyp;
import compiler.semanal.SemPtrTyp;
import compiler.semanal.SemRecTyp;
public class IMCodeGenerator implements Visitor
{
public LinkedList<ImcChunk> chunks = new LinkedList<ImcChunk>();
private int scopeLevel = 0;
private Frame currentFrame = null;
@Override
public Object visit(AbsArrTyp node)
{
// Nothing TBD
return null;
}
@Override
public Object visit(AbsAtomExpr node)
{
switch(node.typ_desc)
{
case AbsAtomExpr.STRING:
ImcConstChunk stringConst = new ImcConstChunk(Label.newLabel(), node.value);
chunks.add(stringConst);
return new ImcNAME(stringConst.label);
case AbsAtomExpr.BOOL:
int boolvalue = 0;
if (node.value.equals("true"))
boolvalue = 1;
else
boolvalue = 0;
return new ImcCONST(boolvalue);
case AbsAtomExpr.INT:
return new ImcCONST(Integer.parseInt(node.value));
case AbsAtomExpr.PTR:
case AbsAtomExpr.VOID:
return new ImcCONST(0);
case AbsAtomExpr.CHAR:
// Check for escaped chars
int charValue = 0;
if (node.value.length() > 3)
{
if (node.value.equals("'\\n'"))
charValue = Character.valueOf('\n').charValue();
else if (node.value.equals("'\\''"))
charValue = Character.valueOf('\'').charValue();
else if (node.value.equals("'\\\\'"))
charValue = Character.valueOf('\\').charValue();
}
else
{
charValue = (int)node.value.charAt(1);
}
return new ImcCONST(charValue);
default:
return null;
}
}
@Override
public Object visit(AbsAtomTyp node)
{
// Nothing TBD
return null;
}
@Override
public Object visit(AbsBinExpr node)
{
switch(node.op)
{
case AbsBinExpr.ADD:
return new ImcBINOP(ImcBINOP.ADD, (ImcExpr)node.lsub.accept(this), (ImcExpr)node.rsub.accept(this));
case AbsBinExpr.SUB:
return new ImcBINOP(ImcBINOP.SUB, (ImcExpr)node.lsub.accept(this), (ImcExpr)node.rsub.accept(this));
case AbsBinExpr.MUL:
return new ImcBINOP(ImcBINOP.MUL, (ImcExpr)node.lsub.accept(this), (ImcExpr)node.rsub.accept(this));
case AbsBinExpr.DIV:
return new ImcBINOP(ImcBINOP.DIV, (ImcExpr)node.lsub.accept(this), (ImcExpr)node.rsub.accept(this));
case AbsBinExpr.EQU:
return new ImcBINOP(ImcBINOP.EQU, (ImcExpr)node.lsub.accept(this), (ImcExpr)node.rsub.accept(this));
case AbsBinExpr.GTH:
return new ImcBINOP(ImcBINOP.GTH, (ImcExpr)node.lsub.accept(this), (ImcExpr)node.rsub.accept(this));
case AbsBinExpr.GEQ:
return new ImcBINOP(ImcBINOP.GEQ, (ImcExpr)node.lsub.accept(this), (ImcExpr)node.rsub.accept(this));
case AbsBinExpr.LTH:
return new ImcBINOP(ImcBINOP.LTH, (ImcExpr)node.lsub.accept(this), (ImcExpr)node.rsub.accept(this));
case AbsBinExpr.LEQ:
return new ImcBINOP(ImcBINOP.LEQ, (ImcExpr)node.lsub.accept(this), (ImcExpr)node.rsub.accept(this));
case AbsBinExpr.NEQ:
return new ImcBINOP(ImcBINOP.NEQ, (ImcExpr)node.lsub.accept(this), (ImcExpr)node.rsub.accept(this));
case AbsBinExpr.AND:
return new ImcBINOP(ImcBINOP.AND, (ImcExpr)node.lsub.accept(this), (ImcExpr)node.rsub.accept(this));
case AbsBinExpr.OR:
return new ImcBINOP(ImcBINOP.OR, (ImcExpr)node.lsub.accept(this), (ImcExpr)node.rsub.accept(this));
case AbsBinExpr.IS:
return new ImcMOVE((ImcExpr)node.lsub.accept(this), (ImcExpr)node.rsub.accept(this));
case AbsBinExpr.DOT:
// Get record var access tree
ImcExpr expr = (ImcExpr) node.lsub.accept(this);
// Right hand component
AbsVarName comp = (AbsVarName)node.rsub;
CmpAccess access = null;
// Get access from component list
for (AbsVarDecl cmp : ((SemRecTyp)node.lsub.semTyp.actual()).comps)
{
if (cmp.name.equals(comp.name))
{
// Found component, assign access
access = (CmpAccess) cmp.access;
break;
}
}
// Create result
return new ImcMEM(new ImcBINOP(ImcBINOP.ADD, expr, new ImcCONST(access.offset)));
case AbsBinExpr.ARR:
// Get basic array access data
ImcMEM arrayAccess = (ImcMEM) node.lsub.accept(this);
// Create addition operation meaning rsub * CONST type_size
ImcExpr add = new ImcBINOP(ImcBINOP.ADD, arrayAccess, new ImcBINOP(ImcBINOP.MUL, (ImcExpr)node.rsub.accept(this), new ImcCONST(node.semTyp.size())));
return new ImcMEM(add);
default:
Report.error("Switch value not implemented!", 100);
}
return null;
}
@Override
public Object visit(AbsDecls node)
{
// Iterate over declarations and add their chunks to list
for (AbsDecl decl : node.decls)
{
decl.accept(this);
}
return chunks;
}
@Override
public Object visit(AbsForStmt node)
{
// For sequence
ImcSEQ forSequence = new ImcSEQ();
ImcExpr var = (ImcExpr)node.expr.accept(this);
ImcExpr lo = (ImcExpr)node.lo.accept(this);
ImcExpr hi = (ImcExpr)node.hi.accept(this);
// Initialize variable with starting value with MOVE
ImcMOVE init = new ImcMOVE(var, lo);
ImcLABEL lblCondition = new ImcLABEL(Label.newLabel());
ImcLABEL lblStatements = new ImcLABEL(Label.newLabel());
ImcLABEL lblEnd = new ImcLABEL(Label.newLabel());
// Condition value check
ImcCJUMP condition = new ImcCJUMP(new ImcBINOP(ImcBINOP.GTH, var, hi), lblEnd.label, lblStatements.label);
// Collect sequence together
forSequence.stmts.add(init);
forSequence.stmts.add(lblCondition);
forSequence.stmts.add(condition);
forSequence.stmts.add(lblStatements);
forSequence.stmts.add((ImcStmt) node.stmts.accept(this));
// Increment loop counter
forSequence.stmts.add(new ImcMOVE(var, new ImcBINOP(ImcBINOP.ADD, var, new ImcCONST(1))));
// Jump back to condition
forSequence.stmts.add(new ImcJUMP(lblCondition.label));
// End label
forSequence.stmts.add(lblEnd);
return forSequence;
}
@Override
public Object visit(AbsFunDecl node)
{
// Change valid scope level
scopeLevel++;
Frame oldFrame = currentFrame;
currentFrame = node.frame;
// Evaluate function code, then check if the result is an expression
// Because void functions can have non-expressions as code we need to check that and wrap them into
// ESEQ call with 0 result
ImcExpr functionCode = null;
Object code = node.val.accept(this);
if (code instanceof ImcExpr)
{
functionCode = (ImcExpr) code;
}
else
{
ImcESEQ eseq = new ImcESEQ((ImcStmt) code, new ImcCONST(0));
functionCode = eseq;
}
// Restore valid scope level
scopeLevel--;
// Restore currentframe
currentFrame = oldFrame;
ImcCodeChunk codeChunk = null;
// Void function
if (((SemFunTyp)node.semTyp).result instanceof SemAtomTyp &&
((SemAtomTyp)((SemFunTyp)node.semTyp).result).typ_desc == SemAtomTyp.VOID)
{
ImcESEQ eseq = (ImcESEQ)functionCode;
codeChunk = new ImcCodeChunk(node.frame, eseq.stmt);
}
else
{
ImcMOVE moveResult = new ImcMOVE(new ImcTEMP(node.frame.RV), functionCode);
// Add data chunk
codeChunk = new ImcCodeChunk(node.frame, moveResult);
}
chunks.add(codeChunk);
return codeChunk;
}
@Override
public Object visit(AbsFunName node)
{
ImcCALL functionCall = new ImcCALL(node.decl.frame.label);
functionCall.args.add(new ImcTEMP(currentFrame.FP));
// Intercept new call and replace argument with size of the datatype
if (node.decl.frame.label.name().equals("_new"))
{
// Intercept new function call and turn it into a pointer assignment sequence
functionCall.args.add(new ImcCONST(((SemPtrTyp)node.args.get(0).semTyp.actual()).base.size()));
// Pointer assignment
ImcMOVE ptr = new ImcMOVE((ImcExpr) node.args.get(0).accept(this), functionCall);
return ptr;
}
// Evaulate arguments
if (node.args != null)
{
for (AbsValExpr args : node.args)
{
functionCall.args.add((ImcExpr) args.accept(this));
}
}
// Void functions require expression node above
if (((SemFunTyp)node.decl.semTyp).result.actual() instanceof SemAtomTyp &&
((SemAtomTyp)((SemFunTyp)node.decl.semTyp).result.actual()).typ_desc == SemAtomTyp.VOID)
{
return new ImcEXP(functionCall);
}
else
{
return functionCall;
}
}
@Override
public Object visit(AbsIfStmt node)
{
// IF is a sequence of commands depending on the expression
ImcSEQ ifSequence = new ImcSEQ();
ImcLABEL thenLabel = new ImcLABEL(Label.newLabel());
ImcLABEL endThenLabel = new ImcLABEL(Label.newLabel());
ImcCJUMP condition = new ImcCJUMP((ImcExpr)node.cond.accept(this), thenLabel.label, endThenLabel.label);
// No else statement
if (node.else_stmts == null)
{
ifSequence.stmts.add(condition);
ifSequence.stmts.add(thenLabel);
ifSequence.stmts.add((ImcStmt) node.then_stmts.accept(this));
ifSequence.stmts.add(endThenLabel);
}
else
{
ImcLABEL endElseLabel = new ImcLABEL(Label.newLabel());
ifSequence.stmts.add(condition);
ifSequence.stmts.add(thenLabel);
ifSequence.stmts.add((ImcStmt) node.then_stmts.accept(this));
ifSequence.stmts.add(new ImcJUMP(endElseLabel.label));
ifSequence.stmts.add(endThenLabel);
ifSequence.stmts.add((ImcStmt) node.else_stmts.accept(this));
ifSequence.stmts.add(endElseLabel);
}
return ifSequence;
}
@Override
public Object visit(AbsLetExpr node)
{
ImcSEQ stmts = new ImcSEQ();
// Get command sequence and finishing expression
if (node.stmts != null)
{
stmts = (ImcSEQ) node.stmts.accept(this);
}
if (node.defs != null)
{
node.defs.accept(this);
}
ImcExpr expr = (ImcExpr)node.expr.accept(this);
// Is this a void statement?
/*if (node.semTyp.actual() instanceof SemAtomTyp &&
((SemAtomTyp)node.semTyp.actual()).typ_desc == SemAtomTyp.VOID)
{
return stmts;
}*/
// Let statement is just an expreesion sequence
ImcESEQ letStmt = new ImcESEQ(stmts, expr);
return letStmt;
}
@Override
public Object visit(AbsPtrTyp node)
{
// Nothing TBD
return null;
}
@Override
public Object visit(AbsRecTyp node)
{
// Nothing TBD
return null;
}
@Override
public Object visit(AbsStmts node)
{
// Create sequence
ImcSEQ statements = new ImcSEQ();
for (AbsStmt statement : node.stmts)
{
Object stmtCode = statement.accept(this);
ImcStmt stmt = null;
if (stmtCode instanceof ImcStmt)
{
stmt = (ImcStmt)stmtCode;
}
else
{
stmt = ((ImcESEQ)stmtCode).stmt;
}
// DEBUG
assert(stmt != null);
statements.stmts.addFirst(stmt);
}
return statements;
}
@Override
public Object visit(AbsTypDecl node)
{
// Nothing TBD
return null;
}
@Override
public Object visit(AbsTypName node)
{
// Nothing TBD
return null;
}
@Override
public Object visit(AbsUnExpr node)
{
switch(node.op)
{
case AbsUnExpr.ADD:
return node.sub.accept(this);
case AbsUnExpr.SUB:
return new ImcBINOP(ImcBINOP.SUB, new ImcCONST(0), (ImcExpr) node.sub.accept(this));
case AbsUnExpr.NOT:
ImcExpr var = (ImcExpr) node.sub.accept(this);
ImcSEQ flipSeq = new ImcSEQ();
// Comparison expression
ImcExpr cmpExpr = new ImcBINOP(ImcBINOP.EQU, var, new ImcCONST(0));
// True
ImcMOVE trueStmt = new ImcMOVE(var, new ImcCONST(1));
// False
ImcMOVE falseStmt = new ImcMOVE(var, new ImcCONST(0));
ImcLABEL trueLbl = new ImcLABEL(Label.newLabel());
ImcLABEL falseLbl = new ImcLABEL(Label.newLabel());
ImcLABEL endLbl = new ImcLABEL(Label.newLabel());
// Create comparison and flip sequence
flipSeq.stmts.add(new ImcCJUMP(cmpExpr, trueLbl.label, falseLbl.label));
flipSeq.stmts.add(trueLbl);
flipSeq.stmts.add(trueStmt);
flipSeq.stmts.add(new ImcJUMP(endLbl.label));
flipSeq.stmts.add(falseLbl);
flipSeq.stmts.add(falseStmt);
flipSeq.stmts.add(endLbl);
ImcESEQ notSeq = new ImcESEQ(flipSeq, var);
return notSeq;
case AbsUnExpr.VAL:
ImcMEM varAccess = (ImcMEM) node.sub.accept(this);
return new ImcMEM(varAccess.expr);
case AbsUnExpr.REF:
ImcMEM variableAccess = (ImcMEM) node.sub.accept(this);
return variableAccess.expr;
}
return null;
}
@Override
public Object visit(AbsValStmt node)
{
return node.expr.accept(this);
}
@Override
public Object visit(AbsVarDecl node)
{
// Global variable
if (node.access instanceof VarAccess)
{
chunks.add(new ImcDataChunk(((VarAccess)node.access).label, node.semTyp.size()));
}
return null;
}
@Override
public Object visit(AbsVarName node)
{
// Check variable access
if (node.decl.access instanceof VarAccess)
{
// Global variable
VarAccess access = (VarAccess)node.decl.access;
return new ImcMEM(new ImcNAME(access.label));
}
else if (node.decl.access instanceof ArgAccess)
{
ArgAccess access = (ArgAccess)node.decl.access;
ImcExpr fpAccess = new ImcTEMP(access.frame.FP);
// Count scope delta and add required amount of memory accesses
for (int i = 0; i < (scopeLevel - 1) - access.frame.level; i++)
{
fpAccess = new ImcMEM(fpAccess);
}
return new ImcMEM(new ImcBINOP(ImcBINOP.ADD, fpAccess, new ImcCONST(access.offset)));
}
else
{
LocAccess access = (LocAccess)node.decl.access;
ImcExpr fpAccess = new ImcTEMP(currentFrame.FP);
// Count scope delta and add required amount of memory accesses
for (int i = 0; i < (scopeLevel - 1) - access.frame.level; i++)
{
fpAccess = new ImcMEM(fpAccess);
}
// Add offset of varibale in frame to the frame pointer address
return new ImcMEM(new ImcBINOP(ImcBINOP.ADD, fpAccess, new ImcCONST(access.offset)));
}
}
@Override
public Object visit(AbsWhileStmt node)
{
ImcLABEL startLabel = new ImcLABEL(Label.newLabel());
ImcLABEL stmtsLabel = new ImcLABEL(Label.newLabel());
ImcLABEL endLabel = new ImcLABEL(Label.newLabel());
// Jump to end of code on false
ImcCJUMP cJump = new ImcCJUMP((ImcExpr) node.cond.accept(this), stmtsLabel.label, endLabel.label);
ImcSEQ whileSeq = new ImcSEQ();
whileSeq.stmts.add(startLabel);
whileSeq.stmts.add(cJump);
whileSeq.stmts.add(stmtsLabel);
whileSeq.stmts.add((ImcStmt) node.stmts.accept(this));
// Jummp to condition
whileSeq.stmts.add(new ImcJUMP(startLabel.label));
whileSeq.stmts.add(endLabel);
return whileSeq;
}
}