public void atExpr(Expr expr) throws CompileError { // array access, member access, // (unary) +, (unary) -, ++, --, !, ~ int token = expr.getOperator(); ASTree oprand = expr.oprand1(); if (token == '.') { String member = ((Symbol) expr.oprand2()).get(); if (member.equals("class")) atClassObject(expr); // .class else atFieldRead(expr); } else if (token == MEMBER) { // field read /* MEMBER ('#') is an extension by Javassist. * The compiler internally uses # for compiling .class * expressions such as "int.class". */ atFieldRead(expr); } else if (token == ARRAY) atArrayRead(oprand, expr.oprand2()); else if (token == PLUSPLUS || token == MINUSMINUS) atPlusPlus(token, oprand, expr, true); else if (token == '!') { if (!booleanExpr(false, expr)) { bytecode.addIndex(7); bytecode.addIconst(1); bytecode.addOpcode(Opcode.GOTO); bytecode.addIndex(4); } bytecode.addIconst(0); } else if (token == CALL) // method call fatal(); else { expr.oprand1().accept(this); int type = typePrecedence(exprType); if (arrayDim > 0) badType(expr); if (token == '-') { if (type == P_DOUBLE) bytecode.addOpcode(DNEG); else if (type == P_FLOAT) bytecode.addOpcode(FNEG); else if (type == P_LONG) bytecode.addOpcode(LNEG); else if (type == P_INT) { bytecode.addOpcode(INEG); exprType = INT; // type may be BYTE, ... } else badType(expr); } else if (token == '~') { if (type == P_INT) { bytecode.addIconst(-1); bytecode.addOpcode(IXOR); exprType = INT; // type may be BYTE. ... } else if (type == P_LONG) { bytecode.addLconst(-1); bytecode.addOpcode(LXOR); } else badType(expr); } else if (token == '+') { if (type == P_OTHER) badType(expr); // do nothing. ignore. } else fatal(); } }
public void atArrayPlusPlus(int token, boolean isPost, Expr expr, boolean doDup) throws CompileError { arrayAccess(expr.oprand1(), expr.oprand2()); int t = exprType; int dim = arrayDim; if (dim > 0) badType(expr); bytecode.addOpcode(DUP2); bytecode.addOpcode(getArrayReadOp(t, arrayDim)); int dup_code = is2word(t, dim) ? DUP2_X2 : DUP_X2; atPlusPlusCore(dup_code, doDup, token, isPost, expr); bytecode.addOpcode(getArrayWriteOp(t, dim)); }
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 }
protected static void badAssign(Expr expr) throws CompileError { String msg; if (expr == null) msg = "incompatible type for assignment"; else msg = "incompatible type for " + expr.getName(); throw new CompileError(msg); }
public void atClassObject(Expr expr) throws CompileError { ASTree op1 = expr.oprand1(); if (!(op1 instanceof Symbol)) throw new CompileError("fatal error: badly parsed .class expr"); String cname = ((Symbol) op1).get(); if (cname.startsWith("[")) { int i = cname.indexOf("[L"); if (i >= 0) { String name = cname.substring(i + 2, cname.length() - 1); String name2 = resolveClassName(name); if (!name.equals(name2)) { /* For example, to obtain String[].class, * "[Ljava.lang.String;" (not "[Ljava/lang/String"!) * must be passed to Class.forName(). */ name2 = MemberResolver.jvmToJavaName(name2); StringBuffer sbuf = new StringBuffer(); while (i-- >= 0) sbuf.append('['); sbuf.append('L').append(name2).append(';'); cname = sbuf.toString(); } } } else { cname = resolveClassName(MemberResolver.javaToJvmName(cname)); cname = MemberResolver.jvmToJavaName(cname); } atClassObject2(cname); exprType = CLASS; arrayDim = 0; className = "java/lang/Class"; }
protected void atAssignExpr(AssignExpr expr, boolean doDup) throws CompileError { // =, %=, &=, *=, /=, +=, -=, ^=, |=, <<=, >>=, >>>= int op = expr.getOperator(); ASTree left = expr.oprand1(); ASTree right = expr.oprand2(); if (left instanceof Variable) atVariableAssign(expr, op, (Variable) left, ((Variable) left).getDeclarator(), right, doDup); else { if (left instanceof Expr) { Expr e = (Expr) left; if (e.getOperator() == ARRAY) { atArrayAssign(expr, op, (Expr) left, right, doDup); return; } } atFieldAssign(expr, op, left, right, doDup); } }
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); } }
private void atArrayAssign(Expr expr, int op, Expr array, ASTree right, boolean doDup) throws CompileError { arrayAccess(array.oprand1(), array.oprand2()); if (op != '=') { bytecode.addOpcode(DUP2); bytecode.addOpcode(getArrayReadOp(exprType, arrayDim)); } int aType = exprType; int aDim = arrayDim; String cname = className; atAssignCore(expr, op, right, aType, aDim, cname); if (doDup) if (is2word(aType, aDim)) bytecode.addOpcode(DUP2_X2); else bytecode.addOpcode(DUP_X2); bytecode.addOpcode(getArrayWriteOp(aType, aDim)); exprType = aType; arrayDim = aDim; className = cname; }
private void atPlusPlus(int token, ASTree oprand, Expr expr, boolean doDup) throws CompileError { boolean isPost = oprand == null; // ++i or i++? if (isPost) oprand = expr.oprand2(); if (oprand instanceof Variable) { Declarator d = ((Variable) oprand).getDeclarator(); int t = exprType = d.getType(); arrayDim = d.getArrayDim(); int var = getLocalVar(d); if (arrayDim > 0) badType(expr); if (t == DOUBLE) { bytecode.addDload(var); if (doDup && isPost) bytecode.addOpcode(DUP2); bytecode.addDconst(1.0); bytecode.addOpcode(token == PLUSPLUS ? DADD : DSUB); if (doDup && !isPost) bytecode.addOpcode(DUP2); bytecode.addDstore(var); } else if (t == LONG) { bytecode.addLload(var); if (doDup && isPost) bytecode.addOpcode(DUP2); bytecode.addLconst((long) 1); bytecode.addOpcode(token == PLUSPLUS ? LADD : LSUB); if (doDup && !isPost) bytecode.addOpcode(DUP2); bytecode.addLstore(var); } else if (t == FLOAT) { bytecode.addFload(var); if (doDup && isPost) bytecode.addOpcode(DUP); bytecode.addFconst(1.0f); bytecode.addOpcode(token == PLUSPLUS ? FADD : FSUB); if (doDup && !isPost) bytecode.addOpcode(DUP); bytecode.addFstore(var); } else if (t == BYTE || t == CHAR || t == SHORT || t == INT) { if (doDup && isPost) bytecode.addIload(var); int delta = token == PLUSPLUS ? 1 : -1; if (var > 0xff) { bytecode.addOpcode(WIDE); bytecode.addOpcode(IINC); bytecode.addIndex(var); bytecode.addIndex(delta); } else { bytecode.addOpcode(IINC); bytecode.add(var); bytecode.add(delta); } if (doDup && !isPost) bytecode.addIload(var); } else badType(expr); } else { if (oprand instanceof Expr) { Expr e = (Expr) oprand; if (e.getOperator() == ARRAY) { atArrayPlusPlus(token, isPost, e, doDup); return; } } atFieldPlusPlus(token, isPost, oprand, expr, doDup); } }
protected static void badType(Expr expr) throws CompileError { throw new CompileError("invalid type for " + expr.getName()); }