diff --git a/group24/121111914/src/com/github/ipk2015/coding2017/basic/stack/expr/InfixExpr.java b/group24/121111914/src/com/github/ipk2015/coding2017/basic/stack/expr/InfixExpr.java new file mode 100644 index 0000000000..1e597a2b24 --- /dev/null +++ b/group24/121111914/src/com/github/ipk2015/coding2017/basic/stack/expr/InfixExpr.java @@ -0,0 +1,83 @@ +package com.github.ipk2015.coding2017.basic.stack.expr; + +import com.github.ipk2015.coding2017.basic.stack.Stack; + +public class InfixExpr { + String expr = null; + + public InfixExpr(String expr) { + this.expr = expr; + } + + public float evaluate() { + String[] elements = getElementArray(expr); + + Stack numStack = new Stack(); + Stack operStack = new Stack(); + + manageMultiAndDivOper(elements,numStack,operStack); + + return manageAddAndMinusOper(numStack,operStack); + } + + private void manageMultiAndDivOper(String[] elements,Stack numStack,Stack operStack){ + float preElement,nextElement; + for(int i = 0; i < elements.length;i++){ + if(i%2 == 0){ + numStack.push(Float.valueOf(elements[i])); + }else{ + + if(elements[i].equals("+") || elements[i].equals("-")){ + operStack.push(elements[i]); + }else{ + preElement = (Float)numStack.pop(); + i++; + nextElement = Float.valueOf(elements[i]); + numStack.push(doBaseOper(preElement,nextElement,elements[i-1])); + } + } + } + } + + private float manageAddAndMinusOper(Stack numStack,Stack operStack){ + float result = 0f;; + while(!operStack.isEmpty()){ + result = doBaseOper(result,(Float)numStack.pop(),(String)operStack.pop()); + } + result += (Float)numStack.pop(); + return result; + } + + private float doBaseOper(float preData,float nextData,String oper){ + switch(oper){ + case "+": + return preData+nextData; + case "-": + return preData-nextData; + case "*": + return preData*nextData; + case "/": + return preData/nextData; + default: + throw new RuntimeException("could not recognise oper:"+oper); + } + } + + public String[] getElementArray(String expression){ + char[] charArray = expression.toCharArray(); + StringBuffer stringBuffer = new StringBuffer(); + + for(int i = 0;i items = new ArrayList(); + + private static class LineNumberItem{ + int startPC; + int lineNum; + public int getStartPC() { + return startPC; + } + public void setStartPC(int startPC) { + this.startPC = startPC; + } + public int getLineNum() { + return lineNum; + } + public void setLineNum(int lineNum) { + this.lineNum = lineNum; + } + } + public void addLineNumberItem(LineNumberItem item){ + this.items.add(item); + } + public LineNumberTable(int attrNameIndex, int attrLen) { + super(attrNameIndex, attrLen); + + } + + public static LineNumberTable parse(ByteCodeIterator iter){ + int attrNameIndex = iter.nextUNToInt(2); + int attrLength = iter.nextUNToInt(4); + LineNumberTable lineNumberTable = new LineNumberTable(attrNameIndex,attrLength); + int lineNumTableLen = iter.nextUNToInt(2); + for(int i = 0;i < lineNumTableLen;i++){ + LineNumberItem lineNumberItem = new LineNumberItem(); + lineNumberItem.setStartPC(iter.nextUNToInt(2)); + lineNumberItem.setLineNum(iter.nextUNToInt(2)); + lineNumberTable.addLineNumberItem(lineNumberItem); + } + return lineNumberTable; + } + + + +} diff --git a/group24/121111914/src/com/github/ipk2015/coding2017/minijvm/attr/LocalVariableItem.java b/group24/121111914/src/com/github/ipk2015/coding2017/minijvm/attr/LocalVariableItem.java new file mode 100644 index 0000000000..b1c6f61348 --- /dev/null +++ b/group24/121111914/src/com/github/ipk2015/coding2017/minijvm/attr/LocalVariableItem.java @@ -0,0 +1,39 @@ +package com.github.ipk2015.coding2017.minijvm.attr; + +public class LocalVariableItem { + private int startPC; + private int length; + private int nameIndex; + private int descIndex; + private int index; + public int getStartPC() { + return startPC; + } + public void setStartPC(int startPC) { + this.startPC = startPC; + } + public int getLength() { + return length; + } + public void setLength(int length) { + this.length = length; + } + public int getNameIndex() { + return nameIndex; + } + public void setNameIndex(int nameIndex) { + this.nameIndex = nameIndex; + } + public int getDescIndex() { + return descIndex; + } + public void setDescIndex(int descIndex) { + this.descIndex = descIndex; + } + public int getIndex() { + return index; + } + public void setIndex(int index) { + this.index = index; + } +} diff --git a/group24/121111914/src/com/github/ipk2015/coding2017/minijvm/attr/LocalVariableTable.java b/group24/121111914/src/com/github/ipk2015/coding2017/minijvm/attr/LocalVariableTable.java new file mode 100644 index 0000000000..d8c3563b2b --- /dev/null +++ b/group24/121111914/src/com/github/ipk2015/coding2017/minijvm/attr/LocalVariableTable.java @@ -0,0 +1,41 @@ +package com.github.ipk2015.coding2017.minijvm.attr; + + +import java.util.ArrayList; +import java.util.List; + + +import com.github.ipk2015.coding2017.minijvm.loader.ByteCodeIterator; + + + +public class LocalVariableTable extends AttributeInfo{ + + List items = new ArrayList(); + + public LocalVariableTable(int attrNameIndex, int attrLen) { + super(attrNameIndex, attrLen); + } + + public static LocalVariableTable parse(ByteCodeIterator iter){ + int attrNameIndex = iter.nextUNToInt(2); + int attrLength = iter.nextUNToInt(4); + LocalVariableTable table = new LocalVariableTable(attrNameIndex,attrLength); + int tableLen = iter.nextUNToInt(2); + for(int i = 0;i < tableLen;i++){ + LocalVariableItem item = new LocalVariableItem(); + item.setStartPC(iter.nextUNToInt(2)); + item.setLength(iter.nextUNToInt(2)); + item.setNameIndex(iter.nextUNToInt(2)); + item.setDescIndex(iter.nextUNToInt(2)); + item.setIndex(iter.nextUNToInt(2)); + table.addLocalVariableItem(item); + } + return table; + } + private void addLocalVariableItem(LocalVariableItem item) { + this.items.add(item); + } + + +} diff --git a/group24/121111914/src/com/github/ipk2015/coding2017/minijvm/attr/StackMapTable.java b/group24/121111914/src/com/github/ipk2015/coding2017/minijvm/attr/StackMapTable.java new file mode 100644 index 0000000000..5d86caa022 --- /dev/null +++ b/group24/121111914/src/com/github/ipk2015/coding2017/minijvm/attr/StackMapTable.java @@ -0,0 +1,29 @@ +package com.github.ipk2015.coding2017.minijvm.attr; + +import com.github.ipk2015.coding2017.minijvm.loader.ByteCodeIterator; + +public class StackMapTable extends AttributeInfo{ + + private String originalCode; + + public StackMapTable(int attrNameIndex, int attrLen) { + super(attrNameIndex, attrLen); + } + + public static StackMapTable parse(ByteCodeIterator iter){ + int index = iter.nextUNToInt(2); + int len = iter.nextUNToInt(4); + StackMapTable t = new StackMapTable(index,len); + + //后面的StackMapTable太过复杂, 不再处理, 只把原始的代码读进来保存 + String code = iter.nextUNToHexString(len); + t.setOriginalCode(code); + + return t; + } + + private void setOriginalCode(String code) { + this.originalCode = code; + + } +} diff --git a/group24/121111914/src/com/github/ipk2015/coding2017/minijvm/clz/ClassFile.java b/group24/121111914/src/com/github/ipk2015/coding2017/minijvm/clz/ClassFile.java index 4b64635076..5cecfc3bff 100644 --- a/group24/121111914/src/com/github/ipk2015/coding2017/minijvm/clz/ClassFile.java +++ b/group24/121111914/src/com/github/ipk2015/coding2017/minijvm/clz/ClassFile.java @@ -1,7 +1,12 @@ package com.github.ipk2015.coding2017.minijvm.clz; +import java.util.ArrayList; +import java.util.List; + import com.github.ipk2015.coding2017.minijvm.constant.ClassInfo; import com.github.ipk2015.coding2017.minijvm.constant.ConstantPool; +import com.github.ipk2015.coding2017.minijvm.field.Field; +import com.github.ipk2015.coding2017.minijvm.method.Method; public class ClassFile { @@ -11,7 +16,8 @@ public class ClassFile { private AccessFlag accessFlag; private ClassIndex clzIndex; private ConstantPool pool; - + private List fields = new ArrayList(); + private List methods = new ArrayList(); public ClassIndex getClzIndex() { return clzIndex; @@ -48,7 +54,18 @@ public void setClassIndex(ClassIndex clzIndex) { this.clzIndex = clzIndex; } - + public void addField(Field f){ + this.fields.add(f); + } + public List getFields(){ + return this.fields; + } + public void addMethod(Method m){ + this.methods.add(m); + } + public List getMethods() { + return methods; + } public void print(){ diff --git a/group24/121111914/src/com/github/ipk2015/coding2017/minijvm/field/Field.java b/group24/121111914/src/com/github/ipk2015/coding2017/minijvm/field/Field.java new file mode 100644 index 0000000000..37757878d6 --- /dev/null +++ b/group24/121111914/src/com/github/ipk2015/coding2017/minijvm/field/Field.java @@ -0,0 +1,41 @@ +package com.github.ipk2015.coding2017.minijvm.field; + +import com.github.ipk2015.coding2017.minijvm.constant.ConstantPool; +import com.github.ipk2015.coding2017.minijvm.loader.ByteCodeIterator; + +public class Field { + private int accessFlag; + private int nameIndex; + private int descriptorIndex; + + + + private ConstantPool pool; + + public Field( int accessFlag, int nameIndex, int descriptorIndex,ConstantPool pool) { + + this.accessFlag = accessFlag; + this.nameIndex = nameIndex; + this.descriptorIndex = descriptorIndex; + this.pool = pool; + } + + + + + public static Field parse(ConstantPool pool,ByteCodeIterator iter){ + int accessFlag = iter.nextUNToInt(2); + int nameIndex = iter.nextUNToInt(2); + int descriptorIndex = iter.nextUNToInt(2); + int attrCount = iter.nextUNToInt(2); + if(attrCount != 0){ + throw new RuntimeException("字段的属性不为0"); + } + return new Field(accessFlag,nameIndex,descriptorIndex,pool); + } + + public String toString(){ + + return pool.getUTF8String(nameIndex)+":"+pool.getUTF8String(descriptorIndex); + } +} diff --git a/group24/121111914/src/com/github/ipk2015/coding2017/minijvm/loader/ByteCodeIterator.java b/group24/121111914/src/com/github/ipk2015/coding2017/minijvm/loader/ByteCodeIterator.java index 85e970c64a..141331fe4b 100644 --- a/group24/121111914/src/com/github/ipk2015/coding2017/minijvm/loader/ByteCodeIterator.java +++ b/group24/121111914/src/com/github/ipk2015/coding2017/minijvm/loader/ByteCodeIterator.java @@ -25,4 +25,7 @@ public byte[] nextUNToArray(int n){ pos=pos+n; return bytes; } + public void back(int n) { + this.pos -= n; + } } diff --git a/group24/121111914/src/com/github/ipk2015/coding2017/minijvm/loader/ClassFileParser.java b/group24/121111914/src/com/github/ipk2015/coding2017/minijvm/loader/ClassFileParser.java index bdbbb66271..b12e564b88 100644 --- a/group24/121111914/src/com/github/ipk2015/coding2017/minijvm/loader/ClassFileParser.java +++ b/group24/121111914/src/com/github/ipk2015/coding2017/minijvm/loader/ClassFileParser.java @@ -3,7 +3,9 @@ import java.io.UnsupportedEncodingException; +import java.util.ArrayList; import java.util.Arrays; +import java.util.List; import com.github.ipk2015.coding2017.minijvm.clz.AccessFlag; import com.github.ipk2015.coding2017.minijvm.clz.ClassFile; @@ -17,6 +19,8 @@ import com.github.ipk2015.coding2017.minijvm.constant.NullConstantInfo; import com.github.ipk2015.coding2017.minijvm.constant.StringInfo; import com.github.ipk2015.coding2017.minijvm.constant.UTF8Info; +import com.github.ipk2015.coding2017.minijvm.field.Field; +import com.github.ipk2015.coding2017.minijvm.method.Method; import com.github.ipk2015.coding2017.minijvm.util.Util; @@ -44,6 +48,18 @@ public ClassFile parse(byte[] codes) { ClassIndex classIndex = parseClassInfex(iterator); classFile.setClassIndex(classIndex); + parseInterfaces(iterator); + + List parseFields = parseFields(constantPool,iterator); + for(Field f:parseFields){ + classFile.addField(f); + } + + List parseMethods = parseMethods(classFile,iterator); + for(Method m:parseMethods){ + classFile.addMethod(m); + } + return classFile; } @@ -145,5 +161,30 @@ private void meetUTF8Info(ConstantPool pool,ByteCodeIterator iter){ pool.addConstantInfo(info); } + private void parseInterfaces(ByteCodeIterator iter) { + int interfaceCount = iter.nextUNToInt(2); + + System.out.println("interfaceCount:" + interfaceCount); + + // TODO : 如果实现了interface, 这里需要解析 + } + + private List parseFields(ConstantPool pool,ByteCodeIterator iter){ + List list = new ArrayList(); + int count = iter.nextUNToInt(2); + for(int i = 0;i < count;i++){ + list.add(Field.parse(pool, iter)); + } + return list; + } + + private List parseMethods(ClassFile classFile,ByteCodeIterator iter){ + List list = new ArrayList(); + int count = iter.nextUNToInt(2); + for(int i = 0;i < count;i++){ + list.add(Method.parse(classFile, iter)); + } + return list; + } } diff --git a/group24/121111914/src/com/github/ipk2015/coding2017/minijvm/method/Method.java b/group24/121111914/src/com/github/ipk2015/coding2017/minijvm/method/Method.java new file mode 100644 index 0000000000..3298a36d6b --- /dev/null +++ b/group24/121111914/src/com/github/ipk2015/coding2017/minijvm/method/Method.java @@ -0,0 +1,70 @@ +package com.github.ipk2015.coding2017.minijvm.method; + +import com.github.ipk2015.coding2017.minijvm.attr.AttributeInfo; +import com.github.ipk2015.coding2017.minijvm.attr.CodeAttr; +import com.github.ipk2015.coding2017.minijvm.clz.ClassFile; +import com.github.ipk2015.coding2017.minijvm.loader.ByteCodeIterator; + +public class Method { + + private int accessFlag; + private int nameIndex; + private int descriptorIndex; + + private CodeAttr codeAttr; + + private ClassFile clzFile; + + + public ClassFile getClzFile() { + return clzFile; + } + + public int getNameIndex() { + return nameIndex; + } + public int getDescriptorIndex() { + return descriptorIndex; + } + + public CodeAttr getCodeAttr() { + return codeAttr; + } + + public void setCodeAttr(CodeAttr code) { + this.codeAttr = code; + } + + public Method(ClassFile clzFile,int accessFlag, int nameIndex, int descriptorIndex) { + this.clzFile = clzFile; + this.accessFlag = accessFlag; + this.nameIndex = nameIndex; + this.descriptorIndex = descriptorIndex; + } + + + + + + public static Method parse(ClassFile clzFile, ByteCodeIterator iter){ + int accessFlag = iter.nextUNToInt(2); + int nameIndex = iter.nextUNToInt(2); + int descriptorIndex = iter.nextUNToInt(2); + Method method = new Method(clzFile,accessFlag,nameIndex,descriptorIndex); + int attrCount = iter.nextUNToInt(2); + for(int i = 0;i < attrCount;i++){ + addAttr(clzFile,method,iter); + } + return method; + } + private static void addAttr(ClassFile clzFile,Method method,ByteCodeIterator iter){ + int nameIndex = iter.nextUNToInt(2); + iter.back(2); + String attrName = clzFile.getConstantPool().getUTF8String(nameIndex); + if(AttributeInfo.CODE.equalsIgnoreCase(attrName)){ + method.setCodeAttr(CodeAttr.parse(clzFile, iter)); + }else{ + throw new RuntimeException("方法的此属性不存在:"+attrName); + } + } +} diff --git a/group24/121111914/src/com/github/ipk2015/coding2017/minijvm/test/ClassFileloaderTest.java b/group24/121111914/src/com/github/ipk2015/coding2017/minijvm/test/ClassFileloaderTest.java index 911b8356a7..0a3979119d 100644 --- a/group24/121111914/src/com/github/ipk2015/coding2017/minijvm/test/ClassFileloaderTest.java +++ b/group24/121111914/src/com/github/ipk2015/coding2017/minijvm/test/ClassFileloaderTest.java @@ -3,6 +3,7 @@ import java.io.IOException; +import java.util.List; import org.junit.After; import org.junit.Assert; @@ -16,8 +17,10 @@ import com.github.ipk2015.coding2017.minijvm.constant.MethodRefInfo; import com.github.ipk2015.coding2017.minijvm.constant.NameAndTypeInfo; import com.github.ipk2015.coding2017.minijvm.constant.UTF8Info; +import com.github.ipk2015.coding2017.minijvm.field.Field; import com.github.ipk2015.coding2017.minijvm.loader.ClassFileLoader; import com.github.ipk2015.coding2017.minijvm.loader.ClassFileLoader1; +import com.github.ipk2015.coding2017.minijvm.method.Method; @@ -205,5 +208,76 @@ public void testClassIndex(){ Assert.assertEquals("java/lang/Object", superClassInfo.getClassName()); } + /** + * 下面是第三次JVM课应实现的测试用例 + */ + @Test + public void testReadFields(){ + + List fields = clzFile.getFields(); + Assert.assertEquals(2, fields.size()); + { + Field f = fields.get(0); + Assert.assertEquals("name:Ljava/lang/String;", f.toString()); + } + { + Field f = fields.get(1); + Assert.assertEquals("age:I", f.toString()); + } + } + @Test + public void testMethods(){ + + List methods = clzFile.getMethods(); + ConstantPool pool = clzFile.getConstantPool(); + + { + Method m = methods.get(0); + assertMethodEquals(pool,m, + "", + "(Ljava/lang/String;I)V", + "2ab7000c2a2bb5000f2a1cb50011b1"); + + } + { + Method m = methods.get(1); + assertMethodEquals(pool,m, + "setName", + "(Ljava/lang/String;)V", + "2a2bb5000fb1"); + + } + { + Method m = methods.get(2); + assertMethodEquals(pool,m, + "setAge", + "(I)V", + "2a1bb50011b1"); + } + { + Method m = methods.get(3); + assertMethodEquals(pool,m, + "sayHello", + "()V", + "b2001c1222b60024b1"); + + } + { + Method m = methods.get(4); + assertMethodEquals(pool,m, + "main", + "([Ljava/lang/String;)V", + "bb000159122b101db7002d4c2bb6002fb1"); + } + } + + private void assertMethodEquals(ConstantPool pool,Method m , String expectedName, String expectedDesc,String expectedCode){ + String methodName = pool.getUTF8String(m.getNameIndex()); + String methodDesc = pool.getUTF8String(m.getDescriptorIndex()); + String code = m.getCodeAttr().getCode(); + Assert.assertEquals(expectedName, methodName); + Assert.assertEquals(expectedDesc, methodDesc); + Assert.assertEquals(expectedCode, code); + } }