1 /* 2 * Licensed to the Apache Software Foundation (ASF) under one or more 3 * contributor license agreements. See the NOTICE file distributed with 4 * this work for additional information regarding copyright ownership. 5 * The ASF licenses this file to You under the Apache License, Version 2.0 6 * (the "License"); you may not use this file except in compliance with 7 * the License. You may obtain a copy of the License at 8 * 9 * http://www.apache.org/licenses/LICENSE-2.0 10 * 11 * Unless required by applicable law or agreed to in writing, software 12 * distributed under the License is distributed on an "AS IS" BASIS, 13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 * See the License for the specific language governing permissions and 15 * limitations under the License. 16 * 17 */ 18 /* Generated By:JJTree: Do not edit this line. ASTExpr.java */ 19 /* JJT: 0.3pre1 */ 20 21 package Mini; 22 import org.apache.bcel.generic.BranchHandle; 23 import org.apache.bcel.generic.ConstantPoolGen; 24 import org.apache.bcel.generic.GOTO; 25 import org.apache.bcel.generic.IF_ICMPEQ; 26 import org.apache.bcel.generic.IF_ICMPGE; 27 import org.apache.bcel.generic.IF_ICMPGT; 28 import org.apache.bcel.generic.IF_ICMPLE; 29 import org.apache.bcel.generic.IF_ICMPLT; 30 import org.apache.bcel.generic.IF_ICMPNE; 31 import org.apache.bcel.generic.InstructionConstants; 32 import org.apache.bcel.generic.InstructionList; 33 import org.apache.bcel.generic.MethodGen; 34 import org.apache.bcel.generic.PUSH; 35 36 /** 37 * Represents arithmetic expressions such as `(a + 12 == b) OR c'. 38 * The parse tree is built initially by the parser and modified, i.e. 39 * compacted with `traverse()'. Each (Expr, Term, Factor) node 40 * with kind == -1 is replaced which its successor node, which is 41 * converted to type `Expr' 42 * 43 * A node with kind == -1 denotes the fact that this expression 44 * node has just one child branch and thus may be replaced by this 45 * branch (or leaf) directly without altering the expression 46 * semantics. Term and Factor nodes are used only to build the parse tree 47 * obeying the aritmetical precedences (* stronger than +, etc.) and 48 * are discarded in the first pass. 49 */ 50 public class ASTExpr extends SimpleNode 51 implements MiniParserConstants, MiniParserTreeConstants, org.apache.bcel.Constants { 52 protected int kind=-1; // Single twig to leaf? 53 private int unop=-1; // Special case: Unary operand applied 54 protected ASTExpr[] exprs; // Sub expressions 55 protected Environment env; // Needed in all passes 56 protected int line, column; 57 protected boolean is_simple; // true, if simple expression like `12 + f(a)' 58 59 /* Not all children shall inherit this, exceptions are ASTIdent and ASTFunAppl, which 60 * look up the type in the corresponding environment entry. 61 */ 62 protected int type = T_UNKNOWN; 63 64 // Generated methods 65 ASTExpr(int id) { 66 super(id); 67 } 68 69 ASTExpr(MiniParser p, int id) { 70 super(p, id); 71 } 72 73 public static Node jjtCreate(MiniParser p, int id) { 74 return new ASTExpr(p, id); 75 } 76 77 ASTExpr(int line, int column, int id) { 78 super(id); 79 this.line = line; 80 this.column = column; 81 } 82 83 ASTExpr(int line, int column, int kind, int id) { 84 this(line, column, id); 85 this.kind = kind; 86 } 87 88 /* Special constructor, called from ASTTerm.traverse() and 89 * ASTFactor.traverse(), when traverse()ing the parse tree replace 90 * themselves with Expr nodes. 91 */ 92 ASTExpr(ASTExpr[] children, int kind, int line, int column) { 93 this(line, column, kind, JJTEXPR); 94 exprs = children; 95 } 96 97 /** 98 * @return name of node, its kind and the number of children. 99 */ 100 @Override 101 public String toString() { 102 String op=""; 103 int len = (children != null)? children.length : 0; 104 if(unop != -1) { 105 op = tokenImage[unop]; 106 } else if(kind != -1) { 107 op = tokenImage[kind]; 108 } 109 110 return jjtNodeName[id] + "(" + op + ")[" + len + "]<" + 111 TYPE_NAMES[type] + "> @" + line + ", " + column; 112 } 113 114 /** 115 * Overrides SimpleNode.closeNode(). Overridden by some subclasses. 116 * 117 * Called by the parser when the construction of this node is finished. 118 * Casts children Node[] to precise ASTExpr[] type. 119 */ 120 @Override 121 public void closeNode() { 122 if(children != null) { 123 exprs = new ASTExpr[children.length]; 124 System.arraycopy(children, 0, exprs, 0, children.length); 125 children=null; // Throw away old reference 126 } 127 } 128 129 /** 130 * First pass 131 * Overridden by subclasses. Traverse the whole parse tree recursively and 132 * drop redundant nodes. 133 */ 134 public ASTExpr traverse(Environment env) { 135 this.env = env; 136 137 if((kind == -1) && (unop == -1)) { 138 return exprs[0].traverse(env); // --> Replaced by successor 139 } else { 140 for(int i=0; i < exprs.length; i++) { 141 exprs[i] = exprs[i].traverse(env); // References may change 142 } 143 144 return this; 145 } 146 } 147 148 /** 149 * Second and third pass 150 * @return type of expression 151 * @param expected type 152 */ 153 public int eval(int expected) { 154 int child_type = T_UNKNOWN, t; 155 156 is_simple = true; 157 158 // Determine expected node type depending on used operator. 159 if(unop != -1) { 160 if(unop == MINUS) { 161 child_type = type = T_INT; // - 162 } else { 163 child_type = type = T_BOOLEAN; // ! 164 } 165 } 166 else { 167 // Compute expected type 168 if((kind == PLUS) || (kind == MINUS) || (kind == MULT) || 169 (kind == MOD) || (kind == DIV)) { 170 child_type = type = T_INT; 171 } else if((kind == AND) || (kind == OR)) { 172 child_type = type = T_BOOLEAN; 173 } else { // LEQ, GT, etc. 174 child_type = T_INT; 175 type = T_BOOLEAN; 176 } 177 } 178 179 // Get type of subexpressions 180 for(int i=0; i < exprs.length; i++) { 181 t = exprs[i].eval(child_type); 182 183 if(t != child_type) { 184 MiniC.addError(exprs[i].getLine(), exprs[i].getColumn(), 185 "Expression has not expected type " + TYPE_NAMES[child_type] + 186 " but " + TYPE_NAMES[t] + "."); 187 } 188 189 is_simple = is_simple && exprs[i].isSimple(); 190 } 191 192 return type; 193 } 194 195 private static String toBool(String i) { 196 return "(" + i + " != 0)"; 197 } 198 199 private static String toInt(String i) { 200 return "((" + i + ")? 1 : 0)"; 201 } 202 203 /** 204 * Fourth pass, produce Java code. 205 */ 206 public void code(StringBuffer buf) { 207 if(unop != -1) { 208 exprs[0].code(buf); 209 String top = ASTFunDecl.pop(); 210 if(unop == MINUS) { 211 ASTFunDecl.push(buf, "-" + top); 212 } else { 213 ASTFunDecl.push(buf, "(" + top + " == 1)? 0 : 1)"); 214 } 215 } 216 else { 217 exprs[0].code(buf); 218 exprs[1].code(buf); 219 String _body_int2 = ASTFunDecl.pop(); 220 String _body_int = ASTFunDecl.pop(); 221 222 switch(kind) { 223 case PLUS: ASTFunDecl.push(buf, _body_int + " + " + _body_int2); break; 224 case MINUS: ASTFunDecl.push(buf, _body_int + " - " + _body_int2); break; 225 case MULT: ASTFunDecl.push(buf, _body_int + " * " + _body_int2); break; 226 case DIV: ASTFunDecl.push(buf, _body_int + " / " + _body_int2); break; 227 228 case AND: ASTFunDecl.push(buf, toInt(toBool(_body_int) + " && " + 229 toBool(_body_int2))); break; 230 case OR: ASTFunDecl.push(buf, toInt(toBool(_body_int) + " || " + 231 toBool(_body_int2))); break; 232 233 case EQ: ASTFunDecl.push(buf, toInt(_body_int + " == " + _body_int2)); 234 break; 235 case LEQ: ASTFunDecl.push(buf, toInt(_body_int + " <= " + _body_int2)); 236 break; 237 case GEQ: ASTFunDecl.push(buf, toInt(_body_int + " >= " + _body_int2)); 238 break; 239 case NEQ: ASTFunDecl.push(buf, toInt(_body_int + " != " + _body_int2)); 240 break; 241 case LT: ASTFunDecl.push(buf, toInt(_body_int + " < " + _body_int2)); 242 break; 243 case GT: ASTFunDecl.push(buf, toInt(_body_int + " > " + _body_int2)); 244 break; 245 246 default: System.err.println("Ooops"); 247 } 248 } 249 } 250 251 /** 252 * Fifth pass, produce Java byte code. 253 */ 254 public void byte_code(InstructionList il, MethodGen method, ConstantPoolGen cp) { 255 exprs[0].byte_code(il, method, cp); 256 257 if(unop != -1) { // Apply unary operand 258 if(unop == MINUS) { 259 il.append(InstructionConstants.INEG); 260 } else { // == NOT 261 il.append(new PUSH(cp, 1)); ASTFunDecl.push(); // Push TRUE 262 il.append(InstructionConstants.IXOR); ASTFunDecl.pop(); 263 } 264 } 265 else { // Apply binary operand 266 BranchHandle bh=null; 267 268 exprs[1].byte_code(il, method, cp); 269 270 switch(kind) { 271 case PLUS: il.append(InstructionConstants.IADD); ASTFunDecl.pop(); break; 272 case MINUS: il.append(InstructionConstants.ISUB); ASTFunDecl.pop(); break; 273 case MULT: il.append(InstructionConstants.IMUL); ASTFunDecl.pop(); break; 274 case DIV: il.append(InstructionConstants.IDIV); ASTFunDecl.pop(); break; 275 case AND: il.append(InstructionConstants.IAND); ASTFunDecl.pop(); break; 276 case OR: il.append(InstructionConstants.IOR); ASTFunDecl.pop(); break; 277 278 /* Use negated operands */ 279 case EQ: bh = il.append(new IF_ICMPNE(null)); ASTFunDecl.pop(2); break; 280 case LEQ: bh = il.append(new IF_ICMPGT(null)); ASTFunDecl.pop(2); break; 281 case GEQ: bh = il.append(new IF_ICMPLT(null)); ASTFunDecl.pop(2); break; 282 case NEQ: bh = il.append(new IF_ICMPEQ(null)); ASTFunDecl.pop(2); break; 283 case LT: bh = il.append(new IF_ICMPGE(null)); ASTFunDecl.pop(2); break; 284 case GT: bh = il.append(new IF_ICMPLE(null)); ASTFunDecl.pop(2); break; 285 default: System.err.println("Ooops"); 286 } 287 288 switch(kind) { 289 case EQ: case LEQ: case GEQ: case NEQ: case LT: case GT: 290 BranchHandle g; 291 292 il.append(new PUSH(cp, 1)); 293 g = il.append(new GOTO(null)); 294 bh.setTarget(il.append(new PUSH(cp, 0))); 295 g.setTarget(il.append(InstructionConstants.NOP)); // May be optimized away later 296 ASTFunDecl.push(); 297 break; 298 299 default: break; 300 } 301 } 302 } 303 304 public boolean isSimple() { return is_simple; } 305 public void setType(int type) { this.type = type; } 306 public int getType() { return type; } 307 public void setKind(int kind) { this.kind = kind; } 308 public int getKind() { return kind; } 309 public void setUnOp(int unop) { this.unop = unop; } 310 public int getUnOp() { return unop; } 311 public void setLine(int line) { this.line = line; } 312 public int getLine() { return line; } 313 public void setColumn(int column) { this.column = column; } 314 public int getColumn() { return column; } 315 public void setPosition(int line, int column) { 316 this.line = line; 317 this.column = column; 318 } 319 320 @Override 321 public void dump(String prefix) { 322 System.out.println(toString(prefix)); 323 324 if(exprs != null) { 325 for(int i=0; i < exprs.length; ++i) { 326 exprs[i].dump(prefix + " "); 327 } 328 } 329 } 330 } 331