diff --git a/src/main/java/chocopy/pa3/CodeGenImpl.java b/src/main/java/chocopy/pa3/CodeGenImpl.java index 6e11970..d2b7b33 100644 --- a/src/main/java/chocopy/pa3/CodeGenImpl.java +++ b/src/main/java/chocopy/pa3/CodeGenImpl.java @@ -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; }