| /* |
| * 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 |
| * |
| * https://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.Const; |
| 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.InstructionConst; |
| 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 arithmetical precedences (* stronger than +, etc.) and are discarded in the first |
| * pass. |
| */ |
| public class ASTExpr extends SimpleNode implements MiniParserConstants, MiniParserTreeConstants { |
| public static Node jjtCreate(final MiniParser p, final int id) { |
| return new ASTExpr(p, id); |
| } |
| |
| private static String toBool(final String i) { |
| return "(" + i + " != 0)"; |
| } |
| |
| private static String toInt(final String i) { |
| return "((" + i + ")? 1 : 0)"; |
| } |
| |
| 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 = Const.T_UNKNOWN; |
| |
| /* |
| * Special constructor, called from ASTTerm.traverse() and ASTFactor.traverse(), when traverse()ing the parse tree |
| * replace themselves with Expr nodes. |
| */ |
| ASTExpr(final ASTExpr[] children, final int kind, final int line, final int column) { |
| this(line, column, kind, JJTEXPR); |
| exprs = children; |
| } |
| |
| // Generated methods |
| ASTExpr(final int id) { |
| super(id); |
| } |
| |
| ASTExpr(final int line, final int column, final int id) { |
| super(id); |
| this.line = line; |
| this.column = column; |
| } |
| |
| ASTExpr(final int line, final int column, final int kind, final int id) { |
| this(line, column, id); |
| this.kind = kind; |
| } |
| |
| ASTExpr(final MiniParser p, final int id) { |
| super(p, id); |
| } |
| |
| /** |
| * Fifth pass, produce Java byte code. |
| */ |
| public void byte_code(final InstructionList il, final MethodGen method, final ConstantPoolGen cp) { |
| exprs[0].byte_code(il, method, cp); |
| |
| if (unop != -1) { // Apply unary operand |
| if (unop == MINUS) { |
| il.append(InstructionConst.INEG); |
| } else { // == NOT |
| il.append(new PUSH(cp, 1)); |
| ASTFunDecl.push(); // Push TRUE |
| il.append(InstructionConst.IXOR); |
| ASTFunDecl.pop(); |
| } |
| } else { // Apply binary operand |
| BranchHandle bh = null; |
| |
| exprs[1].byte_code(il, method, cp); |
| |
| switch (kind) { |
| case PLUS: |
| il.append(InstructionConst.IADD); |
| ASTFunDecl.pop(); |
| break; |
| case MINUS: |
| il.append(InstructionConst.ISUB); |
| ASTFunDecl.pop(); |
| break; |
| case MULT: |
| il.append(InstructionConst.IMUL); |
| ASTFunDecl.pop(); |
| break; |
| case DIV: |
| il.append(InstructionConst.IDIV); |
| ASTFunDecl.pop(); |
| break; |
| case AND: |
| il.append(InstructionConst.IAND); |
| ASTFunDecl.pop(); |
| break; |
| case OR: |
| il.append(InstructionConst.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("Unhandled case: " + kind); |
| } |
| |
| 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(InstructionConst.NOP)); // May be optimized away later |
| ASTFunDecl.push(); |
| break; |
| |
| default: |
| break; |
| } |
| } |
| } |
| |
| /** |
| * 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 |
| } |
| } |
| |
| /** |
| * Fourth pass, produce Java code. |
| */ |
| public void code(final StringBuffer buf) { |
| if (unop != -1) { |
| exprs[0].code(buf); |
| final 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); |
| final String _body_int2 = ASTFunDecl.pop(); |
| final 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("Unhandled case: " + kind); |
| } |
| } |
| } |
| |
| @Override |
| public void dump(final String prefix) { |
| System.out.println(toString(prefix)); |
| |
| if (exprs != null) { |
| for (final ASTExpr expr : exprs) { |
| expr.dump(prefix + " "); |
| } |
| } |
| } |
| |
| /** |
| * Second and third pass |
| * |
| * @return type of expression |
| * @param expected type |
| */ |
| public int eval(final int expected) { |
| int childType = Const.T_UNKNOWN, t; |
| |
| is_simple = true; |
| |
| // Determine expected node type depending on used operator. |
| if (unop != -1) { |
| if (unop == MINUS) { |
| childType = type = Const.T_INT; // - |
| } else { |
| childType = type = Const.T_BOOLEAN; // ! |
| } |
| } else // Compute expected type |
| if (kind == PLUS || kind == MINUS || kind == MULT || kind == MOD || kind == DIV) { |
| childType = type = Const.T_INT; |
| } else if (kind == AND || kind == OR) { |
| childType = type = Const.T_BOOLEAN; |
| } else { // LEQ, GT, etc. |
| childType = Const.T_INT; |
| type = Const.T_BOOLEAN; |
| } |
| |
| // Get type of subexpressions |
| for (final ASTExpr expr : exprs) { |
| t = expr.eval(childType); |
| |
| if (t != childType) { |
| MiniC.addError(expr.getLine(), expr.getColumn(), |
| "Expression has not expected type " + Const.getTypeName(childType) + " but " + Const.getTypeName(t) + "."); |
| } |
| |
| is_simple = is_simple && expr.isSimple(); |
| } |
| |
| return type; |
| } |
| |
| public int getColumn() { |
| return column; |
| } |
| |
| public int getKind() { |
| return kind; |
| } |
| |
| public int getLine() { |
| return line; |
| } |
| |
| public int getType() { |
| return type; |
| } |
| |
| public int getUnOp() { |
| return unop; |
| } |
| |
| public boolean isSimple() { |
| return is_simple; |
| } |
| |
| public void setColumn(final int column) { |
| this.column = column; |
| } |
| |
| public void setKind(final int kind) { |
| this.kind = kind; |
| } |
| |
| public void setLine(final int line) { |
| this.line = line; |
| } |
| |
| public void setPosition(final int line, final int column) { |
| this.line = line; |
| this.column = column; |
| } |
| |
| public void setType(final int type) { |
| this.type = type; |
| } |
| |
| public void setUnOp(final int unop) { |
| this.unop = unop; |
| } |
| |
| /** |
| * @return name of node, its kind and the number of children. |
| */ |
| @Override |
| public String toString() { |
| String op = ""; |
| final 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 + "]<" + Const.getTypeName(type) + "> @" + line + ", " + column; |
| } |
| |
| /** |
| * First pass Overridden by subclasses. Traverse the whole parse tree recursively and drop redundant nodes. |
| */ |
| public ASTExpr traverse(final Environment env) { |
| this.env = env; |
| |
| if (kind == -1 && unop == -1) { |
| return exprs[0].traverse(env); // --> Replaced by successor |
| } |
| for (int i = 0; i < exprs.length; i++) { |
| exprs[i] = exprs[i].traverse(env); // References may change |
| } |
| |
| return this; |
| } |
| } |