📄 codegen.java
字号:
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: &&, ||, ==, !=, <=, >=, <, > */ booleanExpr(true, expr); bytecode.addIndex(7); bytecode.addIconst(0); // false bytecode.addOpcode(Opcode.GOTO); bytecode.addIndex(4); bytecode.addIconst(1); // true } } /* arrayDim values of the two oprands must be equal. * If an oprand type is not a numeric type, this method * throws an exception. */ private void atArithBinExpr(Expr expr, int token, int index, int type1) throws CompileError { if (arrayDim != 0) badTypes(expr); int type2 = exprType; if (token == LSHIFT || token == RSHIFT || token == ARSHIFT) if (type2 == INT || type2 == SHORT || type2 == CHAR || type2 == BYTE) exprType = type1; else badTypes(expr); else convertOprandTypes(type1, type2, expr); int p = typePrecedence(exprType); if (p >= 0) { int op = binOp[index + p + 1]; if (op != NOP) { if (p == P_INT && exprType != BOOLEAN) exprType = INT; // type1 may be BYTE, ... bytecode.addOpcode(op); return; } } badTypes(expr); } private void atStringConcatExpr(Expr expr, int type1, int dim1, String cname1) throws CompileError { int type2 = exprType; int dim2 = arrayDim; boolean type2Is2 = is2word(type2, dim2); boolean type2IsString = (type2 == CLASS && jvmJavaLangString.equals(className)); if (type2Is2) convToString(type2, dim2); if (is2word(type1, dim1)) { bytecode.addOpcode(DUP_X2); bytecode.addOpcode(POP); } else bytecode.addOpcode(SWAP); // even if type1 is String, the left operand might be null. convToString(type1, dim1); bytecode.addOpcode(SWAP); if (!type2Is2 && !type2IsString) convToString(type2, dim2); bytecode.addInvokevirtual(javaLangString, "concat", "(Ljava/lang/String;)Ljava/lang/String;"); exprType = CLASS; arrayDim = 0; className = jvmJavaLangString; } private void convToString(int type, int dim) throws CompileError { final String method = "valueOf"; if (isRefType(type) || dim > 0) bytecode.addInvokestatic(javaLangString, method, "(Ljava/lang/Object;)Ljava/lang/String;"); else if (type == DOUBLE) bytecode.addInvokestatic(javaLangString, method, "(D)Ljava/lang/String;"); else if (type == FLOAT) bytecode.addInvokestatic(javaLangString, method, "(F)Ljava/lang/String;"); else if (type == LONG) bytecode.addInvokestatic(javaLangString, method, "(J)Ljava/lang/String;"); else if (type == BOOLEAN) bytecode.addInvokestatic(javaLangString, method, "(Z)Ljava/lang/String;"); else if (type == CHAR) bytecode.addInvokestatic(javaLangString, method, "(C)Ljava/lang/String;"); else if (type == VOID) throw new CompileError("void type expression"); else /* INT, BYTE, SHORT */ bytecode.addInvokestatic(javaLangString, method, "(I)Ljava/lang/String;"); } /* Produces the opcode to branch if the condition is true. * The oprand is not produced. * * @return true if the compiled code is GOTO (always branch). */ 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 == '!') booleanExpr(!branchIf, ((Expr)expr).oprand1()); else if ((isAndAnd = (op == ANDAND)) || op == OROR) { BinExpr bexpr = (BinExpr)expr; booleanExpr(!isAndAnd, bexpr.oprand1()); int pc = bytecode.currentPc(); bytecode.addIndex(0); // correct later booleanExpr(isAndAnd, bexpr.oprand2()); 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)) { bytecode.addOpcode(Opcode.GOTO); 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; } private static boolean isAlwaysBranch(ASTree expr, boolean branchIf) { if (expr instanceof Keyword) { int t = ((Keyword)expr).get(); return branchIf ? t == TRUE : t == FALSE; } return false; } static int getCompOperator(ASTree expr) throws CompileError { if (expr instanceof Expr) { Expr bexpr = (Expr)expr; int token = bexpr.getOperator(); if (token == '!') return '!'; else if ((bexpr instanceof BinExpr) && token != OROR && token != ANDAND && token != '&' && token != '|') return EQ; // ==, !=, ... else return token; } return ' '; // others } 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; } private static final int ifOp[] = { EQ, IF_ICMPEQ, IF_ICMPNE, NEQ, IF_ICMPNE, IF_ICMPEQ, LE, IF_ICMPLE, IF_ICMPGT, GE, IF_ICMPGE, IF_ICMPLT, '<', IF_ICMPLT, IF_ICMPGE, '>', IF_ICMPGT, IF_ICMPLE }; private static final int ifOp2[] = { EQ, IFEQ, IFNE, NEQ, IFNE, IFEQ, LE, IFLE, IFGT, GE, IFGE, IFLT, '<', IFLT, IFGE, '>', IFGT, IFLE }; /* Produces the opcode to branch if the condition is true. * The oprands are not produced. * * Parameter expr - compare expression ==, !=, <=, >=, <, > */ private void compareExpr(boolean branchIf, int token, int type1, BinExpr expr) throws CompileError { if (arrayDim == 0) convertOprandTypes(type1, exprType, expr); int p = typePrecedence(exprType); if (p == P_OTHER || arrayDim > 0) if (token == EQ) bytecode.addOpcode(branchIf ? IF_ACMPEQ : IF_ACMPNE); else if (token == NEQ) bytecode.addOpcode(branchIf ? IF_ACMPNE : IF_ACMPEQ); else badTypes(expr); else if (p == P_INT) { int op[] = ifOp; for (int i = 0; i < op.length; i += 3) if (op[i] == token) { bytecode.addOpcode(op[i + (branchIf ? 1 : 2)]); return; } badTypes(expr); } else { if (p == P_DOUBLE) if (token == '<' || token == LE) bytecode.addOpcode(DCMPG); else bytecode.addOpcode(DCMPL); else if (p == P_FLOAT) if (token == '<' || token == LE) bytecode.addOpcode(FCMPG); else bytecode.addOpcode(FCMPL); else if (p == P_LONG) bytecode.addOpcode(LCMP); // 1: >, 0: =, -1: < else fatal(); int[] op = ifOp2; for (int i = 0; i < op.length; i += 3) if (op[i] == token) { bytecode.addOpcode(op[i + (branchIf ? 1 : 2)]); return; } badTypes(expr); } } protected static void badTypes(Expr expr) throws CompileError { throw new CompileError("invalid types for " + expr.getName()); } private static final int P_DOUBLE = 0; private static final int P_FLOAT = 1; private static final int P_LONG = 2; private static final int P_INT = 3; private static final int P_OTHER = -1; protected static boolean isRefType(int type) { return type == CLASS || type == NULL; } private static int typePrecedence(int type) { if (type == DOUBLE) return P_DOUBLE; else if (type == FLOAT) return P_FLOAT; else if (type == LONG) return P_LONG; else if (isRefType(type)) return P_OTHER; else if (type == VOID) return P_OTHER; // this is wrong, but ... else return P_INT; // BOOLEAN, BYTE, CHAR, SHORT, INT } // used in TypeChecker. static boolean isP_INT(int type) { return typePrecedence(type) == P_INT; } // used in TypeChecker. static boolean rightIsStrong(int type1, int type2) { int type1_p = typePrecedence(type1); int type2_p = typePrecedence(type2); return type1_p >= 0 && type2_p >= 0 && type1_p > type2_p; } private static final int[] castOp = { /* D F L I */ /* double */ NOP, D2F, D2L, D2I, /* float */ F2D, NOP, F2L, F2I, /* long */ L2D, L2F, NOP, L2I, /* other */ I2D, I2F, I2L, NOP }; /* do implicit type conversion. * arrayDim values of the two oprands must be zero. */ private void convertOprandTypes(int type1, int type2, Expr expr) throws CompileError { boolean rightStrong; int type1_p = typePrecedence(type1); int type2_p = typePrecedence(type2); if (type2_p < 0 && type1_p < 0) // not primitive types return; if (type2_p < 0 || type1_p < 0) // either is not a primitive type badTypes(expr); int op, result_type; if (type1_p <= type2_p) { rightStrong = false; exprType = type1; op = castOp[type2_p * 4 + type1_p]; result_type = type1_p; } else { rightStrong = true; op = castOp[type1_p * 4 + type2_p]; result_type = type2_p; } if (rightStrong) { if (result_type == P_DOUBLE || result_type == P_LONG) { if (type1_p == P_DOUBLE || type1_p == P_LONG) bytecode.addOpcode(DUP2_X2); else bytecode.addOpcode(DUP2_X1); bytecode.addOpcode(POP2); bytecode.addOpcode(op); bytecode.addOpcode(DUP2_X2); bytecode.addOpcode(POP2); } else if (result_type == P_FLOAT) { if (type1_p == P_LONG) { bytecode.addOpcode(DUP_X2); bytecode.addOpcode(POP); } else bytecode.addOpcode(SWAP); bytecode.addOpcode(op); bytecode.addOpcode(SWAP); } else fatal(); } else if (op != NOP) bytecode.addOpcode(op); } public void atCastExpr(CastExpr expr) throws CompileError { String cname = resolveClassName(expr.getClassName()); String toClass = checkCastExpr(expr, cname); int srcType = exprType; exprType = expr.getType(); arrayDim = expr.getArrayDim(); className = cname; if (toClass == null) atNumCastExpr(srcType, exprType); // built-in type else bytecode.addCheckcast(toClass); } public void atInstanceOfExpr(InstanceOfExpr expr) throws CompileError { String cname = resolveClassName(expr.getClassName()); String toClass = checkCastExpr(expr, cname); bytecode.addInstanceof(toClass); exprType = BOOLEAN; arrayDim = 0; } 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 } void atNumCastExpr(int srcType, int destType) throws CompileError { if (srcType == destType) return; int op, op2; int stype = typePrecedence(srcType); int dtype = typePrecedence(destType); if (0 <= stype && stype < 3) op = castOp[stype * 4 + dtype]; else op = NOP; if (destType == DOUBLE) op2 = I2D; else if (destType == FLOAT) op2 = I2F; else if (destType == LONG) op2 = I2L; else if (destType == SHORT) op2 = I2S; else if (destType == CHAR) op2 = I2C; else if (destType == BYTE) op2 = I2B; else op2 = NOP;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -