/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * */ /* Generated By:JJTree: Do not edit this line. ASTExpr.java */ /* JJT: 0.3pre1 */ package Mini; import org.apache.bcel.generic.BranchHandle; import org.apache.bcel.generic.ConstantPoolGen; import org.apache.bcel.generic.GOTO; import org.apache.bcel.generic.IF_ICMPEQ; import org.apache.bcel.generic.IF_ICMPGE; import org.apache.bcel.generic.IF_ICMPGT; import org.apache.bcel.generic.IF_ICMPLE; import org.apache.bcel.generic.IF_ICMPLT; import org.apache.bcel.generic.IF_ICMPNE; import org.apache.bcel.generic.InstructionConstants; import org.apache.bcel.generic.InstructionList; import org.apache.bcel.generic.MethodGen; import org.apache.bcel.generic.PUSH; /** * Represents arithmetic expressions such as `(a + 12 == b) OR c'. * The parse tree is built initially by the parser and modified, i.e. * compacted with `traverse()'. Each (Expr, Term, Factor) node * with kind == -1 is replaced which its successor node, which is * converted to type `Expr' * * A node with kind == -1 denotes the fact that this expression * node has just one child branch and thus may be replaced by this * branch (or leaf) directly without altering the expression * semantics. Term and Factor nodes are used only to build the parse tree * obeying the aritmetical precedences (* stronger than +, etc.) and * are discarded in the first pass. */ public class ASTExpr extends SimpleNode implements MiniParserConstants, MiniParserTreeConstants, org.apache.bcel.Constants { protected int kind=-1; // Single twig to leaf? private int unop=-1; // Special case: Unary operand applied protected ASTExpr[] exprs; // Sub expressions protected Environment env; // Needed in all passes protected int line, column; protected boolean is_simple; // true, if simple expression like `12 + f(a)' /* Not all children shall inherit this, exceptions are ASTIdent and ASTFunAppl, which * look up the type in the corresponding environment entry. */ protected int type = T_UNKNOWN; // Generated methods ASTExpr(int id) { super(id); } ASTExpr(MiniParser p, int id) { super(p, id); } public static Node jjtCreate(MiniParser p, int id) { return new ASTExpr(p, id); } ASTExpr(int line, int column, int id) { super(id); this.line = line; this.column = column; } ASTExpr(int line, int column, int kind, int id) { this(line, column, id); this.kind = kind; } /* Special constructor, called from ASTTerm.traverse() and * ASTFactor.traverse(), when traverse()ing the parse tree replace * themselves with Expr nodes. */ ASTExpr(ASTExpr[] children, int kind, int line, int column) { this(line, column, kind, JJTEXPR); exprs = children; } /** * @return name of node, its kind and the number of children. */ @Override public String toString() { String op=""; int len = (children != null)? children.length : 0; if(unop != -1) { op = tokenImage[unop]; } else if(kind != -1) { op = tokenImage[kind]; } return jjtNodeName[id] + "(" + op + ")[" + len + "]<" + TYPE_NAMES[type] + "> @" + line + ", " + column; } /** * Overrides SimpleNode.closeNode(). Overridden by some subclasses. * * Called by the parser when the construction of this node is finished. * Casts children Node[] to precise ASTExpr[] type. */ @Override public void closeNode() { if(children != null) { exprs = new ASTExpr[children.length]; System.arraycopy(children, 0, exprs, 0, children.length); children=null; // Throw away old reference } } /** * First pass * Overridden by subclasses. Traverse the whole parse tree recursively and * drop redundant nodes. */ public ASTExpr traverse(Environment env) { this.env = env; if((kind == -1) && (unop == -1)) { return exprs[0].traverse(env); // --> Replaced by successor } else { for(int i=0; i < exprs.length; i++) { exprs[i] = exprs[i].traverse(env); // References may change } return this; } } /** * Second and third pass * @return type of expression * @param expected type */ public int eval(int expected) { int child_type = T_UNKNOWN, t; is_simple = true; // Determine expected node type depending on used operator. if(unop != -1) { if(unop == MINUS) { child_type = type = T_INT; // - } else { child_type = type = T_BOOLEAN; // ! } } else { // Compute expected type if((kind == PLUS) || (kind == MINUS) || (kind == MULT) || (kind == MOD) || (kind == DIV)) { child_type = type = T_INT; } else if((kind == AND) || (kind == OR)) { child_type = type = T_BOOLEAN; } else { // LEQ, GT, etc. child_type = T_INT; type = T_BOOLEAN; } } // Get type of subexpressions for(int i=0; i < exprs.length; i++) { t = exprs[i].eval(child_type); if(t != child_type) { MiniC.addError(exprs[i].getLine(), exprs[i].getColumn(), "Expression has not expected type " + TYPE_NAMES[child_type] + " but " + TYPE_NAMES[t] + "."); } is_simple = is_simple && exprs[i].isSimple(); } return type; } private static String toBool(String i) { return "(" + i + " != 0)"; } private static String toInt(String i) { return "((" + i + ")? 1 : 0)"; } /** * Fourth pass, produce Java code. */ public void code(StringBuffer buf) { if(unop != -1) { exprs[0].code(buf); String top = ASTFunDecl.pop(); if(unop == MINUS) { ASTFunDecl.push(buf, "-" + top); } else { ASTFunDecl.push(buf, "(" + top + " == 1)? 0 : 1)"); } } else { exprs[0].code(buf); exprs[1].code(buf); String _body_int2 = ASTFunDecl.pop(); String _body_int = ASTFunDecl.pop(); switch(kind) { case PLUS: ASTFunDecl.push(buf, _body_int + " + " + _body_int2); break; case MINUS: ASTFunDecl.push(buf, _body_int + " - " + _body_int2); break; case MULT: ASTFunDecl.push(buf, _body_int + " * " + _body_int2); break; case DIV: ASTFunDecl.push(buf, _body_int + " / " + _body_int2); break; case AND: ASTFunDecl.push(buf, toInt(toBool(_body_int) + " && " + toBool(_body_int2))); break; case OR: ASTFunDecl.push(buf, toInt(toBool(_body_int) + " || " + toBool(_body_int2))); break; case EQ: ASTFunDecl.push(buf, toInt(_body_int + " == " + _body_int2)); break; case LEQ: ASTFunDecl.push(buf, toInt(_body_int + " <= " + _body_int2)); break; case GEQ: ASTFunDecl.push(buf, toInt(_body_int + " >= " + _body_int2)); break; case NEQ: ASTFunDecl.push(buf, toInt(_body_int + " != " + _body_int2)); break; case LT: ASTFunDecl.push(buf, toInt(_body_int + " < " + _body_int2)); break; case GT: ASTFunDecl.push(buf, toInt(_body_int + " > " + _body_int2)); break; default: System.err.println("Ooops"); } } } /** * Fifth pass, produce Java byte code. */ public void byte_code(InstructionList il, MethodGen method, ConstantPoolGen cp) { exprs[0].byte_code(il, method, cp); if(unop != -1) { // Apply unary operand if(unop == MINUS) { il.append(InstructionConstants.INEG); } else { // == NOT il.append(new PUSH(cp, 1)); ASTFunDecl.push(); // Push TRUE il.append(InstructionConstants.IXOR); ASTFunDecl.pop(); } } else { // Apply binary operand BranchHandle bh=null; exprs[1].byte_code(il, method, cp); switch(kind) { case PLUS: il.append(InstructionConstants.IADD); ASTFunDecl.pop(); break; case MINUS: il.append(InstructionConstants.ISUB); ASTFunDecl.pop(); break; case MULT: il.append(InstructionConstants.IMUL); ASTFunDecl.pop(); break; case DIV: il.append(InstructionConstants.IDIV); ASTFunDecl.pop(); break; case AND: il.append(InstructionConstants.IAND); ASTFunDecl.pop(); break; case OR: il.append(InstructionConstants.IOR); ASTFunDecl.pop(); break; /* Use negated operands */ case EQ: bh = il.append(new IF_ICMPNE(null)); ASTFunDecl.pop(2); break; case LEQ: bh = il.append(new IF_ICMPGT(null)); ASTFunDecl.pop(2); break; case GEQ: bh = il.append(new IF_ICMPLT(null)); ASTFunDecl.pop(2); break; case NEQ: bh = il.append(new IF_ICMPEQ(null)); ASTFunDecl.pop(2); break; case LT: bh = il.append(new IF_ICMPGE(null)); ASTFunDecl.pop(2); break; case GT: bh = il.append(new IF_ICMPLE(null)); ASTFunDecl.pop(2); break; default: System.err.println("Ooops"); } switch(kind) { case EQ: case LEQ: case GEQ: case NEQ: case LT: case GT: BranchHandle g; il.append(new PUSH(cp, 1)); g = il.append(new GOTO(null)); bh.setTarget(il.append(new PUSH(cp, 0))); g.setTarget(il.append(InstructionConstants.NOP)); // May be optimized away later ASTFunDecl.push(); break; default: break; } } } public boolean isSimple() { return is_simple; } public void setType(int type) { this.type = type; } public int getType() { return type; } public void setKind(int kind) { this.kind = kind; } public int getKind() { return kind; } public void setUnOp(int unop) { this.unop = unop; } public int getUnOp() { return unop; } public void setLine(int line) { this.line = line; } public int getLine() { return line; } public void setColumn(int column) { this.column = column; } public int getColumn() { return column; } public void setPosition(int line, int column) { this.line = line; this.column = column; } @Override public void dump(String prefix) { System.out.println(toString(prefix)); if(exprs != null) { for(int i=0; i < exprs.length; ++i) { exprs[i].dump(prefix + " "); } } } }