| /* Generated By:JJTree: Do not edit this line. ASTExpr.java */ |
| /* JJT: 0.3pre1 */ |
| |
| package Mini; |
| import org.apache.bcel.classfile.*; |
| import org.apache.bcel.generic.*; |
| |
| /** |
| * 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. |
| */ |
| 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. |
| */ |
| 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)) // Redundant node (built thru op precedence) ? |
| return exprs[0].traverse(env); // --> Replaced by successor |
| else { |
| for(int i=0; i < exprs.length; i++) // Traverse children |
| 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 final String toBool(String i) { |
| return "(" + i + " != 0)"; |
| } |
| |
| private static final 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; |
| } |
| |
| public void dump(String prefix) { |
| System.out.println(toString(prefix)); |
| |
| if(exprs != null) // Children may have no subchildren |
| for(int i=0; i < exprs.length; ++i) |
| exprs[i].dump(prefix + " "); |
| } |
| } |