JAssignment.java |
1 // Copyright 2013 Bill Campbell, Swami Iyer and Bahar Akbal-Delibas 2 3 package jminusminus; 4 5 import static jminusminus.CLConstants.*; 6 7 /** 8 * The AST node for an assignment statement. This is an abtract class into which 9 * we factor behavior common to all assignment operations. 10 */ 11 12 abstract class JAssignment extends JBinaryExpression { 13 14 /** 15 * Construct an AST node for an assignment operation. 16 * 17 * @param line 18 * line in which the assignment operation occurs in the source 19 * file. 20 * @param operator 21 * the actual assignment operator. 22 * @param lhs 23 * the lhs operand. 24 * @param rhs 25 * the rhs operand. 26 */ 27 28 public JAssignment(int line, String operator, JExpression lhs, 29 JExpression rhs) { 30 super(line, operator, lhs, rhs); 31 } 32 33 } 34 35 /** 36 * The AST node for an assignment (=) expression. The = operator has two 37 * operands: a lhs and a rhs. 38 */ 39 40 class JAssignOp extends JAssignment { 41 42 /** 43 * Construct the AST node for an assignment (=) expression given the lhs and 44 * rhs operands. 45 * 46 * @param line 47 * line in which the assignment expression occurs in the source 48 * file. 49 * @param lhs 50 * lhs operand. 51 * @param rhs 52 * rhs operand. 53 */ 54 55 public JAssignOp(int line, JExpression lhs, JExpression rhs) { 56 super(line, "=", lhs, rhs); 57 } 58 59 /** 60 * Analyze the lhs and rhs, checking that types match, and set the result 61 * type. 62 * 63 * @param context 64 * context in which names are resolved. 65 * @return the analyzed (and possibly rewritten) AST subtree. 66 */ 67 68 public JExpression analyze(Context context) { 69 if (!(lhs instanceof JLhs)) { 70 JAST.compilationUnit.reportSemanticError(line(), 71 "Illegal lhs for assignment"); 72 } else { 73 lhs = (JExpression) ((JLhs) lhs).analyzeLhs(context); 74 } 75 rhs = (JExpression) rhs.analyze(context); 76 rhs.type().mustMatchExpected(line(), lhs.type()); 77 type = rhs.type(); 78 if (lhs instanceof JVariable) { 79 IDefn defn = ((JVariable) lhs).iDefn(); 80 if (defn != null) { 81 // Local variable; consider it to be initialized now. 82 ((LocalVariableDefn) defn).initialize(); 83 } 84 } 85 return this; 86 } 87 88 /** 89 * Code generation for an assignment involves, generating code for loading 90 * any necessary Lvalue onto the stack, for loading the Rvalue, for (unless 91 * a statement) copying the Rvalue to its proper place on the stack, and for 92 * doing the store. 93 * 94 * @param output 95 * the code emitter (basically an abstraction for producing the 96 * .class file). 97 */ 98 99 public void codegen(CLEmitter output) { 100 ((JLhs) lhs).codegenLoadLhsLvalue(output); 101 rhs.codegen(output); 102 if (!isStatementExpression) { 103 // Generate code to leave the Rvalue atop stack 104 ((JLhs) lhs).codegenDuplicateRvalue(output); 105 } 106 ((JLhs) lhs).codegenStore(output); 107 } 108 109 } 110 111 /** 112 * The AST node for a += expression. A += expression has two operands: a lhs and 113 * a rhs. 114 */ 115 116 class JPlusAssignOp extends JAssignment { 117 118 /** 119 * Construct the AST node for a += expression given its lhs and rhs 120 * operands. 121 * 122 * @param line 123 * line in which the assignment expression occurs in the source 124 * file. 125 * @param lhs 126 * the lhs operand. 127 * @param rhs 128 * the rhs operand. 129 */ 130 131 public JPlusAssignOp(int line, JExpression lhs, JExpression rhs) { 132 super(line, "+=", lhs, rhs); 133 } 134 135 /** 136 * Analyze the lhs and rhs, rewrite rhs as lhs + rhs (string concatenation) 137 * if lhs is a String, and set the result type. 138 * 139 * @param context 140 * context in which names are resolved. 141 * @return the analyzed (and possibly rewritten) AST subtree. 142 */ 143 144 public JExpression analyze(Context context) { 145 if (!(lhs instanceof JLhs)) { 146 JAST.compilationUnit.reportSemanticError(line(), 147 "Illegal lhs for assignment"); 148 } else { 149 lhs = (JExpression) ((JLhs) lhs).analyzeLhs(context); 150 } 151 rhs = (JExpression) rhs.analyze(context); 152 if (lhs.type().equals(Type.INT)) { 153 rhs.type().mustMatchExpected(line(), Type.INT); 154 type = Type.INT; 155 } else if (lhs.type().equals(Type.STRING)) { 156 rhs = (new JStringConcatenationOp(line, lhs, rhs)).analyze(context); 157 type = Type.STRING; 158 } else { 159 JAST.compilationUnit.reportSemanticError(line(), 160 "Invalid lhs type for +=: " + lhs.type()); 161 } 162 return this; 163 } 164 165 /** 166 * Code generation for += involves, generating code for loading any 167 * necessary l-value onto the stack, for (unless a string concatenation) 168 * loading the r-value, for (unless a statement) copying the r-value to its 169 * proper place on the stack, and for doing the store. 170 * 171 * @param output 172 * the code emitter (basically an abstraction for producing the 173 * .class file). 174 */ 175 176 public void codegen(CLEmitter output) { 177 ((JLhs) lhs).codegenLoadLhsLvalue(output); 178 if (lhs.type().equals(Type.STRING)) { 179 rhs.codegen(output); 180 } else { 181 ((JLhs) lhs).codegenLoadLhsRvalue(output); 182 rhs.codegen(output); 183 output.addNoArgInstruction(IADD); 184 } 185 if (!isStatementExpression) { 186 // Generate code to leave the r-value atop stack 187 ((JLhs) lhs).codegenDuplicateRvalue(output); 188 } 189 ((JLhs) lhs).codegenStore(output); 190 } 191 192 } 193