public void atBinExpr(BinExpr expr) throws CompileError { int token = expr.getOperator(); /* arithmetic operators: +, -, *, /, %, |, ^, &, <<, >>, >>> */ int k = lookupBinOp(token); if (k >= 0) { expr.oprand1().accept(this); ASTree right = expr.oprand2(); if (right == null) return; // see TypeChecker.atBinExpr(). int type1 = exprType; int dim1 = arrayDim; String cname1 = className; right.accept(this); if (dim1 != arrayDim) throw new CompileError("incompatible array types"); if (token == '+' && dim1 == 0 && (type1 == CLASS || exprType == CLASS)) atStringConcatExpr(expr, type1, dim1, cname1); else atArithBinExpr(expr, token, k, type1); } else { /* equation: &&, ||, ==, !=, <=, >=, <, > */ if (!booleanExpr(true, expr)) { bytecode.addIndex(7); bytecode.addIconst(0); // false bytecode.addOpcode(Opcode.GOTO); bytecode.addIndex(4); } bytecode.addIconst(1); // true } }
private int compileOprands(BinExpr expr) throws CompileError { expr.oprand1().accept(this); int type1 = exprType; int dim1 = arrayDim; expr.oprand2().accept(this); if (dim1 != arrayDim) if (type1 != NULL && exprType != NULL) throw new CompileError("incompatible array types"); else if (exprType == NULL) arrayDim = dim1; if (type1 == NULL) return exprType; else return type1; }
/* Produces the opcode to branch if the condition is true. * The oprand (branch offset) is not produced. * * @return true if the compiled code is GOTO (always branch). * GOTO is not produced. */ private boolean booleanExpr(boolean branchIf, ASTree expr) throws CompileError { boolean isAndAnd; int op = getCompOperator(expr); if (op == EQ) { // ==, !=, ... BinExpr bexpr = (BinExpr) expr; int type1 = compileOprands(bexpr); // here, arrayDim might represent the array dim. of the left oprand // if the right oprand is NULL. compareExpr(branchIf, bexpr.getOperator(), type1, bexpr); } else if (op == '!') return booleanExpr(!branchIf, ((Expr) expr).oprand1()); else if ((isAndAnd = (op == ANDAND)) || op == OROR) { BinExpr bexpr = (BinExpr) expr; if (booleanExpr(!isAndAnd, bexpr.oprand1())) { exprType = BOOLEAN; arrayDim = 0; return true; } else { int pc = bytecode.currentPc(); bytecode.addIndex(0); // correct later if (booleanExpr(isAndAnd, bexpr.oprand2())) bytecode.addOpcode(Opcode.GOTO); bytecode.write16bit(pc, bytecode.currentPc() - pc + 3); if (branchIf != isAndAnd) { bytecode.addIndex(6); // skip GOTO instruction bytecode.addOpcode(Opcode.GOTO); } } } else if (isAlwaysBranch(expr, branchIf)) { // Opcode.GOTO is not added here. The caller must add it. exprType = BOOLEAN; arrayDim = 0; return true; // always branch } else { // others expr.accept(this); if (exprType != BOOLEAN || arrayDim != 0) throw new CompileError("boolean expr is required"); bytecode.addOpcode(branchIf ? IFNE : IFEQ); } exprType = BOOLEAN; arrayDim = 0; return false; }