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 } }
protected void arrayAccess(ASTree array, ASTree index) throws CompileError { array.accept(this); int type = exprType; int dim = arrayDim; if (dim == 0) throw new CompileError("bad array access"); String cname = className; index.accept(this); if (typePrecedence(exprType) != P_INT || arrayDim > 0) throw new CompileError("bad array index"); exprType = type; arrayDim = dim - 1; className = cname; }
private String checkCastExpr(CastExpr expr, String name) throws CompileError { final String msg = "invalid cast"; ASTree oprand = expr.getOprand(); int dim = expr.getArrayDim(); int type = expr.getType(); oprand.accept(this); int srcType = exprType; if (invalidDim(srcType, arrayDim, className, type, dim, name, true) || srcType == VOID || type == VOID) throw new CompileError(msg); if (type == CLASS) { if (!isRefType(srcType)) throw new CompileError(msg); return toJvmArrayName(name, dim); } else if (dim > 0) return toJvmTypeName(type, dim); else return null; // built-in type }
private void atStringPlusEq(Expr expr, int type, int dim, String cname, ASTree right) throws CompileError { if (!jvmJavaLangString.equals(cname)) badAssign(expr); convToString(type, dim); // the value might be null. right.accept(this); convToString(exprType, arrayDim); bytecode.addInvokevirtual(javaLangString, "concat", "(Ljava/lang/String;)Ljava/lang/String;"); exprType = CLASS; arrayDim = 0; className = jvmJavaLangString; }
public void atStmnt(Stmnt st) throws CompileError { if (st == null) return; // empty int op = st.getOperator(); if (op == EXPR) { ASTree expr = st.getLeft(); doTypeCheck(expr); if (expr instanceof AssignExpr) atAssignExpr((AssignExpr) expr, false); else if (isPlusPlusExpr(expr)) { Expr e = (Expr) expr; atPlusPlus(e.getOperator(), e.oprand1(), e, false); } else { expr.accept(this); if (is2word(exprType, arrayDim)) bytecode.addOpcode(POP2); else if (exprType != VOID) bytecode.addOpcode(POP); } } else if (op == DECL || op == BLOCK) { ASTList list = st; while (list != null) { ASTree h = list.head(); list = list.tail(); if (h != null) h.accept(this); } } else if (op == IF) atIfStmnt(st); else if (op == WHILE || op == DO) atWhileStmnt(st, op == WHILE); else if (op == FOR) atForStmnt(st); else if (op == BREAK || op == CONTINUE) atBreakStmnt(st, op == BREAK); else if (op == TokenId.RETURN) atReturnStmnt(st); else if (op == THROW) atThrowStmnt(st); else if (op == TRY) atTryStmnt(st); else if (op == SWITCH) atSwitchStmnt(st); else if (op == SYNCHRONIZED) atSyncStmnt(st); else { // LABEL, SWITCH label stament might be null?. hasReturned = false; throw new CompileError("sorry, not supported statement: TokenId " + op); } }
/* 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; }
protected void atAssignCore(Expr expr, int op, ASTree right, int type, int dim, String cname) throws CompileError { if (op == PLUS_E && dim == 0 && type == CLASS) atStringPlusEq(expr, type, dim, cname, right); else { right.accept(this); if (invalidDim(exprType, arrayDim, className, type, dim, cname, false) || (op != '=' && dim > 0)) badAssign(expr); if (op != '=') { int token = assignOps[op - MOD_E]; int k = lookupBinOp(token); if (k < 0) fatal(); atArithBinExpr(expr, token, k, type); } } if (op != '=' || (dim == 0 && !isRefType(type))) atNumCastExpr(exprType, type); // type check should be done here. }
public void doTypeCheck(ASTree expr) throws CompileError { if (typeChecker != null) expr.accept(typeChecker); }
public void compileExpr(ASTree expr) throws CompileError { doTypeCheck(expr); expr.accept(this); }