Browse Source

temporary version. You cannot compile them. I'll discard the changes but want to check in for record.


git-svn-id: http://anonsvn.jboss.org/repos/javassist/trunk@127 30ef5769-5b8d-40dd-aea6-55b5d6557bb3
tags/rel_3_17_1_ga
chiba 20 years ago
parent
commit
be3a1d153f
2 changed files with 252 additions and 62 deletions
  1. 15
    10
      src/main/javassist/compiler/CodeGen.java
  2. 237
    52
      src/main/javassist/compiler/TypeChecker.java

+ 15
- 10
src/main/javassist/compiler/CodeGen.java View File

} }


public void compileExpr(ASTree expr) throws CompileError { public void compileExpr(ASTree expr) throws CompileError {
doTypeCheck(expr);
expr = doTypeCheck(expr);
expr.accept(this); expr.accept(this);
} }


public boolean compileBooleanExpr(boolean branchIf, ASTree expr) public boolean compileBooleanExpr(boolean branchIf, ASTree expr)
throws CompileError throws CompileError
{ {
doTypeCheck(expr);
expr = doTypeCheck(expr);
return booleanExpr(branchIf, expr); return booleanExpr(branchIf, expr);
} }


public void doTypeCheck(ASTree expr) throws CompileError {
if (typeChecker != null)
/* This returns a different expression from the given one
* if the given expression has been modified.
*/
private ASTree doTypeCheck(ASTree expr) throws CompileError {
if (typeChecker != null) {
expr.accept(typeChecker); expr.accept(typeChecker);
ASTree expr2 = typeChecker.modifiedExpr;
return expr2 == null ? expr : expr2;
}
else
return expr;
} }


public void atASTList(ASTList n) throws CompileError { fatal(); } public void atASTList(ASTList n) throws CompileError { fatal(); }
int op = st.getOperator(); int op = st.getOperator();
if (op == EXPR) { if (op == EXPR) {
ASTree expr = st.getLeft(); ASTree expr = st.getLeft();
doTypeCheck(expr);
expr = doTypeCheck(expr);
if (expr instanceof AssignExpr) if (expr instanceof AssignExpr)
atAssignExpr((AssignExpr)expr, false); atAssignExpr((AssignExpr)expr, false);
else if (isPlusPlusExpr(expr)) { else if (isPlusPlusExpr(expr)) {
*/ */
ASTree init = d.getInitializer(); ASTree init = d.getInitializer();
if (init != null) { if (init != null) {
doTypeCheck(init);
init = doTypeCheck(init);
atVariableAssign(null, '=', null, d, init, false); atVariableAssign(null, '=', null, d, init, false);
} }
} }
int k = lookupBinOp(token); int k = lookupBinOp(token);
if (k >= 0) { if (k >= 0) {
expr.oprand1().accept(this); expr.oprand1().accept(this);
ASTree right = expr.oprand2();
if (right == null)
return; // see TypeChecker.atBinExpr().

int type1 = exprType; int type1 = exprType;
int dim1 = arrayDim; int dim1 = arrayDim;
String cname1 = className; String cname1 = className;
ASTree right = expr.oprand2();
right.accept(this); right.accept(this);
if (dim1 != arrayDim) if (dim1 != arrayDim)
throw new CompileError("incompatible array types"); throw new CompileError("incompatible array types");

+ 237
- 52
src/main/javassist/compiler/TypeChecker.java View File



import javassist.CtClass; import javassist.CtClass;
import javassist.CtField; import javassist.CtField;
import javassist.Modifier;
import javassist.ClassPool; import javassist.ClassPool;
import javassist.NotFoundException; import javassist.NotFoundException;
import javassist.compiler.ast.*; import javassist.compiler.ast.*;
import javassist.bytecode.*; import javassist.bytecode.*;


/**
* This class does type checking and, if needed, transformes the original
* abstract syntax tree. The resulting tree is available from
* this.modifiedExpr.
*/
public class TypeChecker extends Visitor implements Opcode, TokenId { public class TypeChecker extends Visitor implements Opcode, TokenId {
static final String javaLangObject = "java.lang.Object"; static final String javaLangObject = "java.lang.Object";
static final String jvmJavaLangObject = "java/lang/Object"; static final String jvmJavaLangObject = "java/lang/Object";
protected int exprType; // VOID, NULL, CLASS, BOOLEAN, INT, ... protected int exprType; // VOID, NULL, CLASS, BOOLEAN, INT, ...
protected int arrayDim; protected int arrayDim;
protected String className; // JVM-internal representation protected String className; // JVM-internal representation
protected ASTree modifiedExpr; // null if the given expr was not changed


protected MemberResolver resolver; protected MemberResolver resolver;
protected CtClass thisClass; protected CtClass thisClass;
exprType = CLASS; exprType = CLASS;
arrayDim = 0; arrayDim = 0;
className = MemberResolver.javaToJvmName(cname); className = MemberResolver.javaToJvmName(cname);
modifiedExpr = null;
} }
} }


atMultiNewArray(type, classname, size); atMultiNewArray(type, classname, size);
else { else {
size.head().accept(this); size.head().accept(this);
if (modifiedExpr != null)
size.setHead(modifiedExpr);

exprType = type; exprType = type;
arrayDim = 1; arrayDim = 1;
modifiedExpr = null;
if (type == CLASS) if (type == CLASS)
className = resolveClassName(classname); className = resolveClassName(classname);
else else


++count; ++count;
s.accept(this); s.accept(this);
if (modifiedExpr != null)
size.setHead(modifiedExpr);
} }


modifiedExpr = null;
exprType = type; exprType = type;
arrayDim = dim; arrayDim = dim;
if (type == CLASS) if (type == CLASS)
int varArray = d.getArrayDim(); int varArray = d.getArrayDim();
String varClass = d.getClassName(); String varClass = d.getClassName();


if (op != '=')
if (op != '=') {
atVariable(var); atVariable(var);
if (modifiedExpr != null)
expr.setOprand1(modifiedExpr);
}


right.accept(this); right.accept(this);
if (modifiedExpr != null)
expr.setOprand2(modifiedExpr);

exprType = varType; exprType = varType;
arrayDim = varArray; arrayDim = varArray;
className = varClass; className = varClass;
modifiedExpr = null;
} }


private void atArrayAssign(Expr expr, int op, Expr array, private void atArrayAssign(Expr expr, int op, Expr array,
ASTree right) throws CompileError ASTree right) throws CompileError
{ {
atArrayRead(array.oprand1(), array.oprand2());
atArrayRead(array);
if (modifiedExpr != null)
expr.setOprand1(modifiedExpr);

int aType = exprType; int aType = exprType;
int aDim = arrayDim; int aDim = arrayDim;
String cname = className; String cname = className;
right.accept(this); right.accept(this);
if (modifiedExpr != null)
expr.setOprand2(modifiedExpr);

exprType = aType; exprType = aType;
arrayDim = aDim; arrayDim = aDim;
className = cname; className = cname;
modifiedExpr = null;
} }


protected void atFieldAssign(Expr expr, int op, ASTree left, ASTree right) protected void atFieldAssign(Expr expr, int op, ASTree left, ASTree right)
throws CompileError throws CompileError
{ {
CtField f = fieldAccess(left);
atFieldRead(f);
CtField f = atFieldRead(left);
int fType = exprType; int fType = exprType;
int fDim = arrayDim; int fDim = arrayDim;
String cname = className; String cname = className;
if (modifiedExpr != null)
expr.setOprand1(modifiedExpr);

if (Modifier.isFinal(f.getModifiers()))
throw new CompileError("assignment to a final field");

right.accept(this); right.accept(this);
if (modifiedExpr != null)
expr.setOprand2(modifiedExpr);

exprType = fType; exprType = fType;
arrayDim = fDim; arrayDim = fDim;
className = cname; className = cname;
modifiedExpr = null;
} }


public void atCondExpr(CondExpr expr) throws CompileError { public void atCondExpr(CondExpr expr) throws CompileError {
booleanExpr(expr.condExpr()); booleanExpr(expr.condExpr());
if (modifiedExpr != null)
expr.setCond(modifiedExpr);

expr.thenExpr().accept(this); expr.thenExpr().accept(this);
if (modifiedExpr != null)
expr.setThen(modifiedExpr);

int type1 = exprType; int type1 = exprType;
int dim1 = arrayDim; int dim1 = arrayDim;
String cname1 = className; String cname1 = className;
expr.elseExpr().accept(this); expr.elseExpr().accept(this);
if (modifiedExpr != null)
expr.setElse(modifiedExpr);


if (dim1 == 0 && dim1 == arrayDim) if (dim1 == 0 && dim1 == arrayDim)
if (CodeGen.rightIsStrong(type1, exprType)) if (CodeGen.rightIsStrong(type1, exprType))
expr.setElse(new CastExpr(type1, 0, expr.elseExpr())); expr.setElse(new CastExpr(type1, 0, expr.elseExpr()));
exprType = type1; exprType = type1;
} }

modifiedExpr = null;
} }


public void atBinExpr(BinExpr expr) throws CompileError { public void atBinExpr(BinExpr expr) throws CompileError {
int token = expr.getOperator(); int token = expr.getOperator();
int k = CodeGen.lookupBinOp(token); int k = CodeGen.lookupBinOp(token);
if (k >= 0) {
if (k < 0) {
/* equation: &&, ||, ==, !=, <=, >=, <, >
*/
booleanExpr(expr);
}
else {
/* arithmetic operators: +, -, *, /, %, |, ^, &, <<, >>, >>> /* arithmetic operators: +, -, *, /, %, |, ^, &, <<, >>, >>>
*/ */
if (token == '+') {
if (token != '+')
atNonPlusExpr(expr, token);
else {
Expr e = atPlusExpr(expr); Expr e = atPlusExpr(expr);
if (e != null) { if (e != null) {
/* String concatenation has been translated into /* String concatenation has been translated into
* an expression using StringBuffer. * an expression using StringBuffer.
*/ */
e = CallExpr.makeCall(Expr.make('.', e, e = CallExpr.makeCall(Expr.make('.', e,
new Member("toString")), null);
expr.setLeft(e);
expr.setOprand2(null); // <---- look at this!
new Member("toString")), null);
className = jvmJavaLangString; className = jvmJavaLangString;
modifiedExpr = e; // expr will be replaced with e.
} }
} }
else {
expr.oprand1().accept(this);
int type1 = exprType;
expr.oprand2().accept(this);
computeBinExprType(expr, token, type1);
}
} }
else {
/* equation: &&, ||, ==, !=, <=, >=, <, >
*/
booleanExpr(expr);
}

private void atNonPlusExpr(BinExpr expr, int token) throws CompileError {
ASTree left = expr.oprand1();
ASTree right = expr.oprand2();

left.accept(this);
if (modifiedExpr != null) {
left = modifiedExpr;
expr.setOprand1(left);
}

int type1 = exprType;
right.accept(this);
if (modifiedExpr != null) {
right = modifiedExpr;
expr.setOprand2(right);
} }

modifiedExpr = computeConstExpr(token, left, right);
computeBinExprType(expr, token, type1);
} }


// expr must be a + expression.
/* This method deals with string concatenation. It converts a +
* expression on String such as:
* "value:" + i + "."
* into:
* new StringBuffer().append("value:").append(i).append(".")
* .toString()
*
* This method also inserts a cast operator for the right operand
* if needed.
*
* EXPR must be a + expression.
*
* atPlusExpr() returns null if the expression is not a string
* concatenation.
*/
private Expr atPlusExpr(BinExpr expr) throws CompileError { private Expr atPlusExpr(BinExpr expr) throws CompileError {
ASTree left = expr.oprand1(); ASTree left = expr.oprand1();
ASTree right = expr.oprand2(); ASTree right = expr.oprand2();
if (right == null) {
/* this expression has been already type-checked since it is
string concatenation.
see atBinExpr() above.
*/
exprType = CLASS;
arrayDim = 0;
className = jvmJavaLangString;
return null;
}


if (isPlusExpr(left)) { if (isPlusExpr(left)) {
Expr newExpr = atPlusExpr((BinExpr)left); Expr newExpr = atPlusExpr((BinExpr)left);
if (newExpr != null) { if (newExpr != null) {
right.accept(this); right.accept(this);
if (modifiedExpr != null)
right = modifiedExpr;

exprType = CLASS; exprType = CLASS;
arrayDim = 0; arrayDim = 0;
className = "java/lang/StringBuffer"; className = "java/lang/StringBuffer";
modifiedExpr = null;
return makeAppendCall(newExpr, right); return makeAppendCall(newExpr, right);
} }
} }
int type1 = exprType; int type1 = exprType;
int dim1 = arrayDim; int dim1 = arrayDim;
String cname = className; String cname = className;
if (modifiedExpr != null) {
left = modifiedExpr;
expr.setOprand1(left);
}

right.accept(this); right.accept(this);
if (modifiedExpr != null) {
right = modifiedExpr;
expr.setOprand2(right);
}

modifiedExpr = computeConstExpr('+', left, right);
if ((type1 == CLASS && dim1 == 0 && jvmJavaLangString.equals(cname)) if ((type1 == CLASS && dim1 == 0 && jvmJavaLangString.equals(cname))
|| (exprType == CLASS && arrayDim == 0 || (exprType == CLASS && arrayDim == 0
&& jvmJavaLangString.equals(className))) {
ASTList sbufClass = ASTList.make(new Symbol("java"),
new Symbol("lang"), new Symbol("StringBuffer"));
ASTree e = new NewExpr(sbufClass, null);
&& jvmJavaLangString.equals(className)))
{
exprType = CLASS; exprType = CLASS;
arrayDim = 0; arrayDim = 0;
className = "java/lang/StringBuffer";
return makeAppendCall(makeAppendCall(e, left), right);
if (modifiedExpr != null) {
// this expression is constant.
className = jvmJavaLangString;
return null;
}
else {
className = "java/lang/StringBuffer";
ASTList sbufClass = ASTList.make(new Symbol("java"),
new Symbol("lang"),
new Symbol("StringBuffer"));
ASTree e = new NewExpr(sbufClass, null);
return makeAppendCall(makeAppendCall(e, left), right);
}
} }
else { else {
computeBinExprType(expr, '+', type1); computeBinExprType(expr, '+', type1);


if (CodeGen.isP_INT(exprType)) if (CodeGen.isP_INT(exprType))
exprType = INT; // type1 may be BYTE, ... exprType = INT; // type1 may be BYTE, ...

arrayDim = 0;
// don't change the value of modifiedExpr.
} }


private void booleanExpr(ASTree expr) private void booleanExpr(ASTree expr)
throws CompileError throws CompileError
{ {
ASTree modExpr = null;
int op = CodeGen.getCompOperator(expr); int op = CodeGen.getCompOperator(expr);
if (op == EQ) { // ==, !=, ... if (op == EQ) { // ==, !=, ...
BinExpr bexpr = (BinExpr)expr; BinExpr bexpr = (BinExpr)expr;
bexpr.oprand1().accept(this); bexpr.oprand1().accept(this);
if (modifiedExpr != null)
bexpr.setOprand1(modifiedExpr);

int type1 = exprType; int type1 = exprType;
int dim1 = arrayDim; int dim1 = arrayDim;
bexpr.oprand2().accept(this); bexpr.oprand2().accept(this);
if (modifiedExpr != null)
bexpr.setOprand2(modifiedExpr);

if (dim1 == 0 && arrayDim == 0) if (dim1 == 0 && arrayDim == 0)
insertCast(bexpr, type1, exprType); insertCast(bexpr, type1, exprType);
} }
else if (op == '!')
else if (op == '!') {
((Expr)expr).oprand1().accept(this); ((Expr)expr).oprand1().accept(this);
if (modifiedExpr != null)
((Expr)expr).setOprand1(modifiedExpr);
}
else if (op == ANDAND || op == OROR) { else if (op == ANDAND || op == OROR) {
BinExpr bexpr = (BinExpr)expr; BinExpr bexpr = (BinExpr)expr;
bexpr.oprand1().accept(this); bexpr.oprand1().accept(this);
if (modifiedExpr != null)
bexpr.setOprand1(modifiedExpr);

bexpr.oprand2().accept(this); bexpr.oprand2().accept(this);
if (modifiedExpr != null)
bexpr.setOprand2(modifiedExpr);
} }
else // others
else { // others
expr.accept(this); expr.accept(this);
modExpr = modifiedExpr;
}


exprType = BOOLEAN; exprType = BOOLEAN;
arrayDim = 0; arrayDim = 0;
modifiedExpr = modExpr;
} }


private void insertCast(BinExpr expr, int type1, int type2) private void insertCast(BinExpr expr, int type1, int type2)
exprType = type1; exprType = type1;
} }


private ASTree computeConstExpr(int op, ASTree left, ASTree right) {
if (left instanceof StringL && right instanceof StringL && op == '+')
return new StringL(((StringL)left).get() + ((StringL)right).get());
else if (left instanceof IntConst)
return ((IntConst)left).compute(op, right);
else if (left instanceof DoubleConst)
return ((DoubleConst)left).compute(op, right);
else
return null; // not constant expression
}

public void atCastExpr(CastExpr expr) throws CompileError { public void atCastExpr(CastExpr expr) throws CompileError {
String cname = resolveClassName(expr.getClassName()); String cname = resolveClassName(expr.getClassName());
expr.getOprand().accept(this); expr.getOprand().accept(this);
if (modifiedExpr != null)
expr.setOprand(modifiedExpr);

exprType = expr.getType(); exprType = expr.getType();
arrayDim = expr.getArrayDim(); arrayDim = expr.getArrayDim();
className = cname; className = cname;
modifiedExpr = null;
} }


public void atInstanceOfExpr(InstanceOfExpr expr) throws CompileError { public void atInstanceOfExpr(InstanceOfExpr expr) throws CompileError {
expr.getOprand().accept(this); expr.getOprand().accept(this);
if (modifiedExpr != null)
expr.setOprand(modifiedExpr);

exprType = BOOLEAN; exprType = BOOLEAN;
arrayDim = 0; arrayDim = 0;
modifiedExpr = null;
} }


public void atExpr(Expr expr) throws CompileError { public void atExpr(Expr expr) throws CompileError {
atFieldRead(expr); atFieldRead(expr);
} }
else if (token == ARRAY) else if (token == ARRAY)
atArrayRead(oprand, expr.oprand2());
atArrayRead(expr);
else if (token == PLUSPLUS || token == MINUSMINUS) else if (token == PLUSPLUS || token == MINUSMINUS)
atPlusPlus(token, oprand, expr); atPlusPlus(token, oprand, expr);
else if (token == '!') else if (token == '!')
else if (token == CALL) // method call else if (token == CALL) // method call
fatal(); fatal();
else { else {
expr.oprand1().accept(this);
if (token == '-' || token == '~')
oprand.accept(this);
if (modifiedExpr != null) {
oprand = modifiedExpr;
expr.setOprand1(oprand);
}

modifiedExpr = computeConstExpr(token, oprand);
if (token == '-' || token == '~') {
if (CodeGen.isP_INT(exprType)) if (CodeGen.isP_INT(exprType))
exprType = INT; // type may be BYTE, ... exprType = INT; // type may be BYTE, ...
}
} }
} }


private ASTree computeConstExpr(int op, ASTree oprand) {
if (oprand instanceof IntConst) {
IntConst c = (IntConst)oprand;
long v = c.get();
if (op == '-')
v = -v;
else if (op == '~')
v = ~v;

c.set(v);
}
else if (oprand instanceof DoubleConst) {
DoubleConst c = (DoubleConst)oprand;
if (op == '-')
c.set(-c.get());
}

return null;
}

public void atCallExpr(CallExpr expr) throws CompileError { public void atCallExpr(CallExpr expr) throws CompileError {
String mname = null; String mname = null;
CtClass targetClass = null; CtClass targetClass = null;
ASTree target = e.oprand1(); ASTree target = e.oprand1();
try { try {
target.accept(this); target.accept(this);
if (modifiedExpr != null)
e.setOprand1(modifiedExpr);
} }
catch (NoFieldException nfe) { catch (NoFieldException nfe) {
if (nfe.getExpr() != target) if (nfe.getExpr() != target)
MemberResolver.Method minfo MemberResolver.Method minfo
= atMethodCallCore(targetClass, mname, args); = atMethodCallCore(targetClass, mname, args);
expr.setMethod(minfo); expr.setMethod(minfo);
modifiedExpr = null;
} }


private static void badMethod() throws CompileError { private static void badMethod() throws CompileError {
} }


/** /**
* modifiedExpr is not set.
*
* @return a pair of the class declaring the invoked method * @return a pair of the class declaring the invoked method
* and the MethodInfo of that method. Never null. * and the MethodInfo of that method. Never null.
*/ */
while (args != null) { while (args != null) {
ASTree a = args.head(); ASTree a = args.head();
a.accept(this); a.accept(this);
if (modifiedExpr != null)
args.setHead(modifiedExpr);

types[i] = exprType; types[i] = exprType;
dims[i] = arrayDim; dims[i] = arrayDim;
cnames[i] = className; cnames[i] = className;
} }
} }


/* modifiedExpr is not set.
*/
void setReturnType(String desc) throws CompileError { void setReturnType(String desc) throws CompileError {
int i = desc.indexOf(')'); int i = desc.indexOf(')');
if (i < 0) if (i < 0)
} }
} }


private void atFieldRead(ASTree expr) throws CompileError {
atFieldRead(fieldAccess(expr));
}

private void atFieldRead(CtField f) throws CompileError {
private CtField atFieldRead(ASTree expr) throws CompileError {
CtField f = fieldAccess(expr);
FieldInfo finfo = f.getFieldInfo2(); FieldInfo finfo = f.getFieldInfo2();
String type = finfo.getDescriptor(); String type = finfo.getDescriptor();


className = type.substring(i + 1, type.indexOf(';', i + 1)); className = type.substring(i + 1, type.indexOf(';', i + 1));
else else
className = null; className = null;

modifiedExpr = null; ??
return f;
} }


protected CtField fieldAccess(ASTree expr) throws CompileError { protected CtField fieldAccess(ASTree expr) throws CompileError {
else if (op == '.') else if (op == '.')
try { try {
e.oprand1().accept(this); e.oprand1().accept(this);
if (modifiedExpr != null)
e.setOprand1(modifiedExpr);

if (exprType == CLASS && arrayDim == 0) if (exprType == CLASS && arrayDim == 0)
return resolver.lookupFieldByJvmName(className, return resolver.lookupFieldByJvmName(className,
(Symbol)e.oprand2()); (Symbol)e.oprand2());
exprType = CLASS; exprType = CLASS;
arrayDim = 0; arrayDim = 0;
className =jvmJavaLangClass; className =jvmJavaLangClass;
modifiedExpr = null;
} }


public void atArrayLength(Expr expr) throws CompileError { public void atArrayLength(Expr expr) throws CompileError {
expr.oprand1().accept(this); expr.oprand1().accept(this);
if (modifiedExpr != null)
expr.setOprand1(modifiedExpr);

exprType = INT; exprType = INT;
arrayDim = 0; arrayDim = 0;
modifiedExpr = null;
} }


public void atArrayRead(ASTree array, ASTree index)
throws CompileError
{
public void atArrayRead(Expr expr) throws CompileError {
ASTree array = expr.oprand1();
array.accept(this); array.accept(this);
if (modifiedExpr != null)
expr.setOprand1(modifiedExpr);

int type = exprType; int type = exprType;
int dim = arrayDim; int dim = arrayDim;
String cname = className; String cname = className;

ASTree index = expr.oprand2();
index.accept(this); index.accept(this);
if (modifiedExpr != null)
expr.setOprand2(modifiedExpr);

exprType = type; exprType = type;
arrayDim = dim - 1; arrayDim = dim - 1;
className = cname; className = cname;
modifiedExpr = null;
} }


private void atPlusPlus(int token, ASTree oprand, Expr expr) private void atPlusPlus(int token, ASTree oprand, Expr expr)
Declarator d = ((Variable)oprand).getDeclarator(); Declarator d = ((Variable)oprand).getDeclarator();
exprType = d.getType(); exprType = d.getType();
arrayDim = d.getArrayDim(); arrayDim = d.getArrayDim();
modifiedExpr = null;
} }
else { else {
if (oprand instanceof Expr) { if (oprand instanceof Expr) {
Expr e = (Expr)oprand; Expr e = (Expr)oprand;
if (e.getOperator() == ARRAY) { if (e.getOperator() == ARRAY) {
atArrayRead(e.oprand1(), e.oprand2());
atArrayRead(e);
// arrayDim should be 0. // arrayDim should be 0.
int t = exprType; int t = exprType;
if (t == INT || t == BYTE || t == CHAR || t == SHORT) if (t == INT || t == BYTE || t == CHAR || t == SHORT)


protected void atFieldPlusPlus(ASTree oprand) throws CompileError protected void atFieldPlusPlus(ASTree oprand) throws CompileError
{ {
CtField f = fieldAccess(oprand);
atFieldRead(f);
atFieldRead(oprand);
int t = exprType; int t = exprType;
if (t == INT || t == BYTE || t == CHAR || t == SHORT) if (t == INT || t == BYTE || t == CHAR || t == SHORT)
exprType = INT; exprType = INT;

Loading…
Cancel
Save