JBinaryExpression.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 a binary expression. A binary expression has an operator and 9 * two operands: a lhs and a rhs. 10 */ 11 12 abstract class JBinaryExpression extends JExpression { 13 14 /** The binary operator. */ 15 protected String operator; 16 17 /** The lhs operand. */ 18 protected JExpression lhs; 19 20 /** The rhs operand. */ 21 protected JExpression rhs; 22 23 /** 24 * Construct an AST node for a binary expression given its line number, the 25 * binary operator, and lhs and rhs operands. 26 * 27 * @param line 28 * line in which the binary expression occurs in the source file. 29 * @param operator 30 * the binary operator. 31 * @param lhs 32 * the lhs operand. 33 * @param rhs 34 * the rhs operand. 35 */ 36 37 protected JBinaryExpression(int line, String operator, JExpression lhs, 38 JExpression rhs) { 39 super(line); 40 this.operator = operator; 41 this.lhs = lhs; 42 this.rhs = rhs; 43 } 44 45 /** 46 * @inheritDoc 47 */ 48 49 public void writeToStdOut(PrettyPrinter p) { 50 p.printf("<JBinaryExpression line=\"%d\" type=\"%s\" " 51 + "operator=\"%s\">\n", line(), ((type == null) ? "" : type 52 .toString()), Util.escapeSpecialXMLChars(operator)); 53 p.indentRight(); 54 p.printf("<Lhs>\n"); 55 p.indentRight(); 56 lhs.writeToStdOut(p); 57 p.indentLeft(); 58 p.printf("</Lhs>\n"); 59 p.printf("<Rhs>\n"); 60 p.indentRight(); 61 rhs.writeToStdOut(p); 62 p.indentLeft(); 63 p.printf("</Rhs>\n"); 64 p.indentLeft(); 65 p.printf("</JBinaryExpression>\n"); 66 } 67 68 } 69 70 /** 71 * The AST node for a plus (+) expression. In j--, as in Java, + is overloaded 72 * to denote addition for numbers and concatenation for Strings. 73 */ 74 75 class JPlusOp extends JBinaryExpression { 76 77 /** 78 * Construct an AST node for an addition expression given its line number, 79 * and the lhs and rhs operands. 80 * 81 * @param line 82 * line in which the addition expression occurs in the source 83 * file. 84 * @param lhs 85 * the lhs operand. 86 * @param rhs 87 * the rhs operand. 88 */ 89 90 public JPlusOp(int line, JExpression lhs, JExpression rhs) { 91 super(line, "+", lhs, rhs); 92 } 93 94 /** 95 * Analysis involves first analyzing the operands. If this is a string 96 * concatenation, we rewrite the subtree to make that explicit (and analyze 97 * that). Otherwise we check the types of the addition operands and compute 98 * the result type. 99 * 100 * @param context 101 * context in which names are resolved. 102 * @return the analyzed (and possibly rewritten) AST subtree. 103 */ 104 105 public JExpression analyze(Context context) { 106 lhs = (JExpression) lhs.analyze(context); 107 rhs = (JExpression) rhs.analyze(context); 108 if (lhs.type() == Type.STRING || rhs.type() == Type.STRING) { 109 return (new JStringConcatenationOp(line, lhs, rhs)) 110 .analyze(context); 111 } else if (lhs.type() == Type.INT && rhs.type() == Type.INT) { 112 type = Type.INT; 113 } else { 114 type = Type.ANY; 115 JAST.compilationUnit.reportSemanticError(line(), 116 "Invalid operand types for +"); 117 } 118 return this; 119 } 120 121 /** 122 * Any string concatenation has been rewritten as a JStringConcatenationOp 123 * (in analyze()), so code generation here involves simply generating code 124 * for loading the operands onto the stack and then generating the 125 * appropriate add instruction. 126 * 127 * @param output 128 * the code emitter (basically an abstraction for producing the 129 * .class file). 130 */ 131 132 public void codegen(CLEmitter output) { 133 if (type == Type.INT) { 134 lhs.codegen(output); 135 rhs.codegen(output); 136 output.addNoArgInstruction(IADD); 137 } 138 } 139 140 } 141 142 /** 143 * The AST node for a subtraction (-) expression. 144 */ 145 146 class JSubtractOp extends JBinaryExpression { 147 148 /** 149 * Construct an AST node for a subtraction expression given its line number, 150 * and lhs and rhs operands. 151 * 152 * @param line 153 * line in which the subtraction expression occurs in the source 154 * file. 155 * @param lhs 156 * the lhs operand. 157 * @param rhs 158 * the rhs operand. 159 */ 160 161 public JSubtractOp(int line, JExpression lhs, JExpression rhs) { 162 super(line, "-", lhs, rhs); 163 } 164 165 /** 166 * Analyzing the - operation involves analyzing its operands, checking 167 * types, and determining the result type. 168 * 169 * @param context 170 * context in which names are resolved. 171 * @return the analyzed (and possibly rewritten) AST subtree. 172 */ 173 174 public JExpression analyze(Context context) { 175 lhs = (JExpression) lhs.analyze(context); 176 rhs = (JExpression) rhs.analyze(context); 177 lhs.type().mustMatchExpected(line(), Type.INT); 178 rhs.type().mustMatchExpected(line(), Type.INT); 179 type = Type.INT; 180 return this; 181 } 182 183 /** 184 * Generating code for the - operation involves generating code for the two 185 * operands, and then the subtraction instruction. 186 * 187 * @param output 188 * the code emitter (basically an abstraction for producing the 189 * .class file). 190 */ 191 192 public void codegen(CLEmitter output) { 193 lhs.codegen(output); 194 rhs.codegen(output); 195 output.addNoArgInstruction(ISUB); 196 } 197 198 } 199 200 /** 201 * The AST node for a multiplication (*) expression. 202 */ 203 204 class JMultiplyOp extends JBinaryExpression { 205 206 /** 207 * Construct an AST for a multiplication expression given its line number, 208 * and the lhs and rhs operands. 209 * 210 * @param line 211 * line in which the multiplication expression occurs in the 212 * source file. 213 * @param lhs 214 * the lhs operand. 215 * @param rhs 216 * the rhs operand. 217 */ 218 219 public JMultiplyOp(int line, JExpression lhs, JExpression rhs) { 220 super(line, "*", lhs, rhs); 221 } 222 223 /** 224 * Analyzing the * operation involves analyzing its operands, checking 225 * types, and determining the result type. 226 * 227 * @param context 228 * context in which names are resolved. 229 * @return the analyzed (and possibly rewritten) AST subtree. 230 */ 231 232 public JExpression analyze(Context context) { 233 lhs = (JExpression) lhs.analyze(context); 234 rhs = (JExpression) rhs.analyze(context); 235 lhs.type().mustMatchExpected(line(), Type.INT); 236 rhs.type().mustMatchExpected(line(), Type.INT); 237 type = Type.INT; 238 return this; 239 } 240 241 /** 242 * Generating code for the * operation involves generating code for the two 243 * operands, and then the multiplication instruction. 244 * 245 * @param output 246 * the code emitter (basically an abstraction for producing the 247 * .class file). 248 */ 249 250 public void codegen(CLEmitter output) { 251 lhs.codegen(output); 252 rhs.codegen(output); 253 output.addNoArgInstruction(IMUL); 254 } 255 256 } 257