|
|
|
@ -439,7 +439,70 @@ public class CodeGenImpl extends CodeGenBase
|
|
|
|
|
backend.emitLocalLabel(ln, "End of if statement");
|
|
|
|
|
return null;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public void copyList(Register dest, Register src, Register size) {
|
|
|
|
|
Label begin = generateLocalLabel();
|
|
|
|
|
Label exit = generateLocalLabel();
|
|
|
|
|
backend.emitLocalLabel(begin, "Start loop for copying");
|
|
|
|
|
backend.emitBEQ(size, Register.ZERO, exit, "Exit when copy completes");
|
|
|
|
|
backend.emitLW(Register.A2, src, 0, "Load Word from Source");
|
|
|
|
|
backend.emitSW(Register.A2, dest, 0, "Store Word in Destination");
|
|
|
|
|
backend.emitADDI(src, src, wordSize, "Increment Source Address");
|
|
|
|
|
backend.emitADDI(dest, dest, wordSize, "Increment Destination Address");
|
|
|
|
|
backend.emitADDI(size, size, -1, "Decrement size left to copy");
|
|
|
|
|
backend.emitJ(begin, "Jump to beginning of loop");
|
|
|
|
|
backend.emitLocalLabel(exit,"Exit loop for copying");
|
|
|
|
|
}
|
|
|
|
|
private Register addLists() {
|
|
|
|
|
// Check for Null operands
|
|
|
|
|
Label label = generateLocalLabel();
|
|
|
|
|
backend.emitBNEZ(Register.A0, label, "Left operand is NULL");
|
|
|
|
|
backend.emitBNEZ(Register.T0, label, "Right operand is NULL");
|
|
|
|
|
backend.emitJAL(errorNone, "Operand is Null");
|
|
|
|
|
backend.emitLocalLabel(label, "List Addition");
|
|
|
|
|
|
|
|
|
|
//Get lengths of the two lists
|
|
|
|
|
backend.emitLW(Register.T1, Register.A0,0,"Load length of first list");
|
|
|
|
|
backend.emitLW(Register.T2, Register.T0,0,"Load length of second list");
|
|
|
|
|
backend.emitADD(Register.A1, Register.T2,Register.T1,"Add lengths of lists");
|
|
|
|
|
backend.emitMV(Register.T3,Register.A1,"Store total length combined list");
|
|
|
|
|
backend.emitADDI(Register.A1, Register.A1,1,"Add 1 to store length of new list");
|
|
|
|
|
|
|
|
|
|
//Store address and length of lists on stack
|
|
|
|
|
backend.emitSW(Register.A0, Register.FP, -sp_off*wordSize, "Store address of first list");
|
|
|
|
|
sp_off++;
|
|
|
|
|
backend.emitSW(Register.T0, Register.FP, -sp_off*wordSize, "Store address of second list");
|
|
|
|
|
sp_off++;
|
|
|
|
|
backend.emitSW(Register.T3, Register.FP, -sp_off*wordSize, "Store length of combined list");
|
|
|
|
|
sp_off++;
|
|
|
|
|
|
|
|
|
|
//Allocate space on heap
|
|
|
|
|
backend.emitLA(Register.A0, listClass.getPrototypeLabel(), "Load empty list");
|
|
|
|
|
backend.emitJAL(objectAllocResizeLabel, "Allocate list");
|
|
|
|
|
backend.emitMV(Register.A1, Register.A0, "Store address of allocated space");
|
|
|
|
|
backend.emitMV(Register.T5, Register.A1, "Make a copy of address of allocated space");
|
|
|
|
|
|
|
|
|
|
//Pop length and address from stack
|
|
|
|
|
sp_off--;
|
|
|
|
|
backend.emitLW(Register.T3, Register.FP, -sp_off*wordSize, "Load length of combined list");
|
|
|
|
|
sp_off--;
|
|
|
|
|
backend.emitLW(Register.T0, Register.FP, -sp_off*wordSize, "Load address of second list");
|
|
|
|
|
sp_off--;
|
|
|
|
|
backend.emitLW(Register.A0, Register.FP, -sp_off*wordSize, "Load address of first list");
|
|
|
|
|
|
|
|
|
|
backend.emitLW(Register.T1, Register.A0,0,"Load length of first list");
|
|
|
|
|
backend.emitLW(Register.T2, Register.T0,0,"Load length of second list");
|
|
|
|
|
|
|
|
|
|
//Copy each list in newly allocated space
|
|
|
|
|
backend.emitSW(Register.T3,Register.T5,0,"Store length of combined list ");
|
|
|
|
|
backend.emitADDI(Register.T5,Register.T5,wordSize,"Increment address");
|
|
|
|
|
backend.emitADDI(Register.A0,Register.A0,wordSize,"Increment address");
|
|
|
|
|
copyList(Register.T5, Register.A0, Register.T1);
|
|
|
|
|
backend.emitADDI(Register.T0,Register.T0,wordSize,"Increment address");
|
|
|
|
|
copyList(Register.T5, Register.T0, Register.T2);
|
|
|
|
|
|
|
|
|
|
backend.emitMV(Register.A0,Register.A1,"Load address of combined list");
|
|
|
|
|
return Register.A0;
|
|
|
|
|
}
|
|
|
|
|
@Override
|
|
|
|
|
public Register analyze(BinaryExpr node)
|
|
|
|
|
{
|
|
|
|
@ -448,10 +511,10 @@ public class CodeGenImpl extends CodeGenBase
|
|
|
|
|
|
|
|
|
|
if(node.left.getInferredType().equals(Type.INT_TYPE) && node.right.getInferredType().equals(Type.INT_TYPE))
|
|
|
|
|
{
|
|
|
|
|
node.left.dispatch(this);
|
|
|
|
|
node.right.dispatch(this);
|
|
|
|
|
backend.emitSW(Register.A0, Register.FP, -sp_off*wordSize, "Push on stack slot "+sp_off);
|
|
|
|
|
sp_off++;
|
|
|
|
|
node.right.dispatch(this);
|
|
|
|
|
node.left.dispatch(this);
|
|
|
|
|
sp_off--;
|
|
|
|
|
backend.emitLW(Register.T0, Register.FP, -sp_off*wordSize, "Pop stack slot "+sp_off);
|
|
|
|
|
|
|
|
|
@ -480,7 +543,6 @@ public class CodeGenImpl extends CodeGenBase
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{ // Comparison operators
|
|
|
|
|
//elseBlock = generateLocalLabel();
|
|
|
|
|
String comment="Operator: "+operator;
|
|
|
|
|
if(operator.equals("=="))
|
|
|
|
|
{
|
|
|
|
@ -508,16 +570,96 @@ public class CodeGenImpl extends CodeGenBase
|
|
|
|
|
}
|
|
|
|
|
else if(operator.equals("is"))
|
|
|
|
|
{
|
|
|
|
|
backend.emitXOR(Register.A0, Register.A0, Register.T0, "is operation");
|
|
|
|
|
backend.emitXOR(Register.A0, Register.A0, Register.T0, comment);
|
|
|
|
|
backend.emitSEQZ(Register.A0, Register.A0, "Result is True if XOR equals 0");
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{}
|
|
|
|
|
{
|
|
|
|
|
backend.emitJAL(errorNI, "Operator not implemented for integer operands");
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
else if(node.left.getInferredType().equals(Type.BOOL_TYPE) && node.right.getInferredType().equals(Type.BOOL_TYPE))
|
|
|
|
|
{
|
|
|
|
|
|
|
|
|
|
// Comparison operators
|
|
|
|
|
String comment="Operator: "+operator;
|
|
|
|
|
if(operator.equals("=="))
|
|
|
|
|
{
|
|
|
|
|
node.right.dispatch(this);
|
|
|
|
|
backend.emitSW(Register.A0, Register.FP, -sp_off*wordSize, "Push on stack slot "+sp_off);
|
|
|
|
|
sp_off++;
|
|
|
|
|
node.left.dispatch(this);
|
|
|
|
|
sp_off--;
|
|
|
|
|
backend.emitLW(Register.T0, Register.FP, -sp_off*wordSize, "Pop stack slot "+sp_off);
|
|
|
|
|
backend.emitXOR(Register.A0, Register.A0, Register.T0, "Check for equality");
|
|
|
|
|
backend.emitSEQZ(Register.A0, Register.A0, "Result is True if XOR equals 0");
|
|
|
|
|
}
|
|
|
|
|
else if(operator.equals("!="))
|
|
|
|
|
{
|
|
|
|
|
node.right.dispatch(this);
|
|
|
|
|
backend.emitSW(Register.A0, Register.FP, -sp_off*wordSize, "Push on stack slot "+sp_off);
|
|
|
|
|
sp_off++;
|
|
|
|
|
node.left.dispatch(this);
|
|
|
|
|
sp_off--;
|
|
|
|
|
backend.emitLW(Register.T0, Register.FP, -sp_off*wordSize, "Pop stack slot "+sp_off);
|
|
|
|
|
backend.emitXOR(Register.A0, Register.A0, Register.T0, "Check for inequality");
|
|
|
|
|
backend.emitSNEZ(Register.A0, Register.A0, "Result is True if XOR does not equal 0");
|
|
|
|
|
}
|
|
|
|
|
else if(operator.equals("and"))
|
|
|
|
|
{
|
|
|
|
|
Label label = generateLocalLabel();
|
|
|
|
|
node.left.dispatch(this);
|
|
|
|
|
backend.emitSW(Register.A0, Register.FP, -sp_off*wordSize, "Push on stack slot "+sp_off);
|
|
|
|
|
sp_off++;
|
|
|
|
|
backend.emitBEQZ(Register.A0, label, "If first operand is false, don't check second");
|
|
|
|
|
node.right.dispatch(this);
|
|
|
|
|
sp_off--;
|
|
|
|
|
backend.emitLW(Register.T0, Register.FP, -sp_off*wordSize, "Pop stack slot "+sp_off);
|
|
|
|
|
backend.emitAND(Register.A0, Register.A0, Register.T0, "AND operation");
|
|
|
|
|
backend.emitLocalLabel(label, "Next step after AND");
|
|
|
|
|
}
|
|
|
|
|
else if(operator.equals("or"))
|
|
|
|
|
{
|
|
|
|
|
Label label = generateLocalLabel();
|
|
|
|
|
node.left.dispatch(this);
|
|
|
|
|
backend.emitSW(Register.A0, Register.FP, -sp_off*wordSize, "Push on stack slot "+sp_off);
|
|
|
|
|
sp_off++;
|
|
|
|
|
backend.emitBNEZ(Register.A0, label, "If first operand is true, don't check second");
|
|
|
|
|
node.right.dispatch(this);
|
|
|
|
|
sp_off--;
|
|
|
|
|
backend.emitLW(Register.T0, Register.FP, -sp_off*wordSize, "Pop stack slot "+sp_off);
|
|
|
|
|
backend.emitOR(Register.A0, Register.A0, Register.T0, "OR operation");
|
|
|
|
|
backend.emitLocalLabel(label, "Next step after OR");
|
|
|
|
|
}
|
|
|
|
|
else if(operator.equals("is"))
|
|
|
|
|
{
|
|
|
|
|
backend.emitXOR(Register.A0, Register.A0, Register.T0, comment);
|
|
|
|
|
backend.emitSEQZ(Register.A0, Register.A0, "Result is True if XOR equals 0");
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
backend.emitJAL(errorNI, "Operator not implemented for boolean operands");
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
else if(node.left.getInferredType().isListType() && node.right.getInferredType().isListType())
|
|
|
|
|
{
|
|
|
|
|
node.right.dispatch(this);
|
|
|
|
|
backend.emitSW(Register.A0, Register.FP, -sp_off*wordSize, "Push on stack slot "+sp_off);
|
|
|
|
|
sp_off++;
|
|
|
|
|
node.left.dispatch(this);
|
|
|
|
|
sp_off--;
|
|
|
|
|
backend.emitLW(Register.T0, Register.FP, -sp_off*wordSize, "Pop stack slot "+sp_off);
|
|
|
|
|
if(operator.equals("+"))
|
|
|
|
|
addLists();
|
|
|
|
|
}
|
|
|
|
|
else if(node.left.getInferredType().equals(Type.STR_TYPE) && node.right.getInferredType().equals(Type.STR_TYPE))
|
|
|
|
|
{
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
backend.emitJAL(errorNI, "Operator not implemented");
|
|
|
|
|
}
|
|
|
|
|
return A0;
|
|
|
|
|
}
|
|
|
|
@ -589,19 +731,25 @@ public class CodeGenImpl extends CodeGenBase
|
|
|
|
|
@Override
|
|
|
|
|
public Register analyze(ListExpr node) {
|
|
|
|
|
int l = node.elements.size();
|
|
|
|
|
backend.emitLI(Register.A1, l+1, "Load length of list+1 in words");
|
|
|
|
|
backend.emitLA(Register.A0, listClass.getPrototypeLabel(), "Load empty list");
|
|
|
|
|
backend.emitJAL(objectAllocResizeLabel, "Allocate list");
|
|
|
|
|
backend.emitMV(Register.A1, Register.A0, "Store address of allocated space");
|
|
|
|
|
backend.emitMV(Register.T0, Register.A1, "Make a copy of address of allocated space");
|
|
|
|
|
|
|
|
|
|
int i = l;
|
|
|
|
|
backend.emitLI(Register.A0,l,"Load length of list in words");
|
|
|
|
|
backend.emitSW(Register.A0,Register.T0,0,"Store length of list: "+i);
|
|
|
|
|
backend.emitADDI(Register.T0,Register.T0,wordSize,"Increment address");
|
|
|
|
|
|
|
|
|
|
for(Expr exp:node.elements)
|
|
|
|
|
{
|
|
|
|
|
Register r = exp.dispatch(this);
|
|
|
|
|
backend.emitSW(r,Register.FP,-sp_off*wordSize,"Push argument "+i+" from last.");
|
|
|
|
|
sp_off++;
|
|
|
|
|
backend.emitSW(r,Register.T0,0,"Store element "+i+" from last.");
|
|
|
|
|
backend.emitADDI(Register.T0,Register.T0,wordSize,"Increment address");
|
|
|
|
|
i--;
|
|
|
|
|
}
|
|
|
|
|
backend.emitLI(Register.A0, l, "Pass list length");
|
|
|
|
|
backend.emitSW(Register.A0, Register.FP, -sp_off*wordSize, "Push argument "+i+" from last.");
|
|
|
|
|
sp_off++;
|
|
|
|
|
backend.emitADDI(Register.SP, Register.SP, -sp_off*wordSize, "Set SP to last argument.");
|
|
|
|
|
//TODO: Store reference to variable
|
|
|
|
|
backend.emitMV(Register.A0,Register.A1,"Load address of list");
|
|
|
|
|
return Register.A0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|