blob: e3dc0dba78957bcadf20f2a2073e090aed4dbce6 [file] [log] [blame]
/*
* 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;
}
}