diff --git a/group24/494800949/EmployeeV1-javap.txt b/group24/494800949/EmployeeV1-javap.txt new file mode 100644 index 0000000000..466714a1dd --- /dev/null +++ b/group24/494800949/EmployeeV1-javap.txt @@ -0,0 +1,164 @@ +$ javap -verbose EmployeeV1 +警告: 二进制文件EmployeeV1包含com.coderising.jvm.test.EmployeeV1 +Classfile /H:/sourceCode/coding2017/group24/494800949/EmployeeV1.class + Last modified 2017-4-9; size 1056 bytes + MD5 checksum 8454b8999ccc9a2ae26a405d47558825 + Compiled from "EmployeeV1.java" +public class com.coderising.jvm.test.EmployeeV1 + minor version: 0 + major version: 52 + flags: ACC_PUBLIC, ACC_SUPER +Constant pool: + #1 = Class #2 // com/coderising/jvm/test/EmployeeV1 + #2 = Utf8 com/coderising/jvm/test/EmployeeV1 + #3 = Class #4 // java/lang/Object + #4 = Utf8 java/lang/Object + #5 = Utf8 name + #6 = Utf8 Ljava/lang/String; + #7 = Utf8 age + #8 = Utf8 I + #9 = Utf8 + #10 = Utf8 (Ljava/lang/String;I)V + #11 = Utf8 Code + #12 = Methodref #3.#13 // java/lang/Object."":()V + #13 = NameAndType #9:#14 // "":()V + #14 = Utf8 ()V + #15 = Fieldref #1.#16 // com/coderising/jvm/test/EmployeeV1.name:Ljava/lang/String; + #16 = NameAndType #5:#6 // name:Ljava/lang/String; + #17 = Fieldref #1.#18 // com/coderising/jvm/test/EmployeeV1.age:I + #18 = NameAndType #7:#8 // age:I + #19 = Utf8 LineNumberTable + #20 = Utf8 LocalVariableTable + #21 = Utf8 this + #22 = Utf8 Lcom/coderising/jvm/test/EmployeeV1; + #23 = Utf8 setName + #24 = Utf8 (Ljava/lang/String;)V + #25 = Utf8 setAge + #26 = Utf8 (I)V + #27 = Utf8 sayHello + #28 = Fieldref #29.#31 // java/lang/System.out:Ljava/io/PrintStream; + #29 = Class #30 // java/lang/System + #30 = Utf8 java/lang/System + #31 = NameAndType #32:#33 // out:Ljava/io/PrintStream; + #32 = Utf8 out + #33 = Utf8 Ljava/io/PrintStream; + #34 = String #35 // Hello , this is class Employee + #35 = Utf8 Hello , this is class Employee + #36 = Methodref #37.#39 // java/io/PrintStream.println:(Ljava/lang/String;)V + #37 = Class #38 // java/io/PrintStream + #38 = Utf8 java/io/PrintStream + #39 = NameAndType #40:#24 // println:(Ljava/lang/String;)V + #40 = Utf8 println + #41 = Utf8 main + #42 = Utf8 ([Ljava/lang/String;)V + #43 = String #44 // Andy + #44 = Utf8 Andy + #45 = Methodref #1.#46 // com/coderising/jvm/test/EmployeeV1."":(Ljava/lang/String;I)V + #46 = NameAndType #9:#10 // "":(Ljava/lang/String;I)V + #47 = Methodref #1.#48 // com/coderising/jvm/test/EmployeeV1.sayHello:()V + #48 = NameAndType #27:#14 // sayHello:()V + #49 = Utf8 args + #50 = Utf8 [Ljava/lang/String; + #51 = Utf8 p + #52 = Utf8 SourceFile + #53 = Utf8 EmployeeV1.java +{ + public com.coderising.jvm.test.EmployeeV1(java.lang.String, int); + descriptor: (Ljava/lang/String;I)V + flags: ACC_PUBLIC + Code: + stack=2, locals=3, args_size=3 + 0: aload_0 + 1: invokespecial #12 // Method java/lang/Object."":()V + 4: aload_0 + 5: aload_1 + 6: putfield #15 // Field name:Ljava/lang/String; + 9: aload_0 + 10: iload_2 + 11: putfield #17 // Field age:I + 14: return + LineNumberTable: + line 9: 0 + line 10: 4 + line 11: 9 + line 12: 14 + LocalVariableTable: + Start Length Slot Name Signature + 0 15 0 this Lcom/coderising/jvm/test/EmployeeV1; + 0 15 1 name Ljava/lang/String; + 0 15 2 age I + + public void setName(java.lang.String); + descriptor: (Ljava/lang/String;)V + flags: ACC_PUBLIC + Code: + stack=2, locals=2, args_size=2 + 0: aload_0 + 1: aload_1 + 2: putfield #15 // Field name:Ljava/lang/String; + 5: return + LineNumberTable: + line 15: 0 + line 16: 5 + LocalVariableTable: + Start Length Slot Name Signature + 0 6 0 this Lcom/coderising/jvm/test/EmployeeV1; + 0 6 1 name Ljava/lang/String; + + public void setAge(int); + descriptor: (I)V + flags: ACC_PUBLIC + Code: + stack=2, locals=2, args_size=2 + 0: aload_0 + 1: iload_1 + 2: putfield #17 // Field age:I + 5: return + LineNumberTable: + line 18: 0 + line 19: 5 + LocalVariableTable: + Start Length Slot Name Signature + 0 6 0 this Lcom/coderising/jvm/test/EmployeeV1; + 0 6 1 age I + + public void sayHello(); + descriptor: ()V + flags: ACC_PUBLIC + Code: + stack=2, locals=1, args_size=1 + 0: getstatic #28 // Field java/lang/System.out:Ljava/io/PrintStream; + 3: ldc #34 // String Hello , this is class Employee + 5: invokevirtual #36 // Method java/io/PrintStream.println:(Ljava/lang/String;)V + 8: return + LineNumberTable: + line 21: 0 + line 22: 8 + LocalVariableTable: + Start Length Slot Name Signature + 0 9 0 this Lcom/coderising/jvm/test/EmployeeV1; + + public static void main(java.lang.String[]); + descriptor: ([Ljava/lang/String;)V + flags: ACC_PUBLIC, ACC_STATIC + Code: + stack=4, locals=2, args_size=1 + 0: new #1 // class com/coderising/jvm/test/EmployeeV1 + 3: dup + 4: ldc #43 // String Andy + 6: bipush 29 + 8: invokespecial #45 // Method "":(Ljava/lang/String;I)V + 11: astore_1 + 12: aload_1 + 13: invokevirtual #47 // Method sayHello:()V + 16: return + LineNumberTable: + line 24: 0 + line 25: 12 + line 27: 16 + LocalVariableTable: + Start Length Slot Name Signature + 0 17 0 args [Ljava/lang/String; + 12 5 1 p Lcom/coderising/jvm/test/EmployeeV1; +} +SourceFile: "EmployeeV1.java" diff --git a/group24/494800949/src/main/java/com/coding/mini_jvm/src/com/coderising/jvm/attr/CodeAttr.java b/group24/494800949/src/main/java/com/coding/mini_jvm/src/com/coderising/jvm/attr/CodeAttr.java index ee04b856d7..b1685c4314 100644 --- a/group24/494800949/src/main/java/com/coding/mini_jvm/src/com/coderising/jvm/attr/CodeAttr.java +++ b/group24/494800949/src/main/java/com/coding/mini_jvm/src/com/coderising/jvm/attr/CodeAttr.java @@ -2,6 +2,8 @@ import com.coding.mini_jvm.src.com.coderising.jvm.clz.ClassFile; +import com.coding.mini_jvm.src.com.coderising.jvm.cmd.ByteCodeCommand; +import com.coding.mini_jvm.src.com.coderising.jvm.cmd.CommandParser; import com.coding.mini_jvm.src.com.coderising.jvm.loader.ByteCodeIterator; public class CodeAttr extends AttributeInfo { @@ -13,21 +15,23 @@ public String getCode() { return code; } - //private ByteCodeCommand[] cmds ; - //public ByteCodeCommand[] getCmds() { - // return cmds; - //} - private LineNumberTable lineNumTable; + private ByteCodeCommand[] cmds; + + public ByteCodeCommand[] getCmds() { + return cmds; + } + + private LineNumberTable lineNumTable; private LocalVariableTable localVarTable; - private StackMapTable stackMapTable; - - public CodeAttr(int attrNameIndex, int attrLen, int maxStack, int maxLocals, int codeLen,String code /*ByteCodeCommand[] cmds*/) { + private StackMapTable stackMapTable; + + public CodeAttr(int attrNameIndex, int attrLen, int maxStack, int maxLocals, int codeLen, String code ,ByteCodeCommand[] cmds) { super(attrNameIndex, attrLen); this.maxStack = maxStack; this.maxLocals = maxLocals; this.codeLen = codeLen; this.code = code; - //this.cmds = cmds; + this.cmds = cmds; } public void setLineNumberTable(LineNumberTable t) { @@ -47,9 +51,9 @@ public static CodeAttr parse(ClassFile clzFile, ByteCodeIterator iter){ int maxStack = iter.readTwoBytesToInt(); int maxLocal = iter.readTwoBytesToInt(); int codeLen = iter.readFourBytesToInt(); - String code = iter.readBytesToString(codeLen); - CodeAttr codeAttr = new CodeAttr(attrNameIndex, attrLen, maxStack, maxLocal, codeLen, code); - + String code = iter.readBytesToHexString(codeLen); + ByteCodeCommand[] cmds = CommandParser.parse(clzFile, code); + CodeAttr codeAttr = new CodeAttr(attrNameIndex, attrLen, maxStack, maxLocal, codeLen, code, cmds); //异常表长度 int exceptionTableLen = iter.readTwoBytesToInt(); if (exceptionTableLen > 0) { diff --git a/group24/494800949/src/main/java/com/coding/mini_jvm/src/com/coderising/jvm/clz/ClassFile.java b/group24/494800949/src/main/java/com/coding/mini_jvm/src/com/coderising/jvm/clz/ClassFile.java index 047c65195f..6c88b9fff5 100644 --- a/group24/494800949/src/main/java/com/coding/mini_jvm/src/com/coderising/jvm/clz/ClassFile.java +++ b/group24/494800949/src/main/java/com/coding/mini_jvm/src/com/coderising/jvm/clz/ClassFile.java @@ -11,6 +11,7 @@ public class ClassFile { + private static final String MAIN_METHOD_NAME = "main"; private int minorVersion; private int majorVersion; @@ -79,13 +80,33 @@ public void print(){ System.out.println("Super Class Name:"+ getSuperClassName()); } - private String getClassName(){ + public String getClassName(){ int thisClassIndex = this.clzIndex.getThisClassIndex(); ClassInfo thisClass = (ClassInfo)this.getConstantPool().getConstantInfo(thisClassIndex); return thisClass.getClassName(); } - private String getSuperClassName(){ + public String getSuperClassName(){ ClassInfo superClass = (ClassInfo)this.getConstantPool().getConstantInfo(this.clzIndex.getSuperClassIndex()); return superClass.getClassName(); } + + public Method getMethod(String methodName, String paramAndReturnType){ + for (Method method : methods) { + String name = method.getClzFile().getConstantPool().getUTF8String(method.getNameIndex()); + if (methodName.equals(name)) { + return method; + } + } + + return null; + } + public Method getMainMethod(){ + for (Method method : methods) { + String name = method.getClzFile().getConstantPool().getUTF8String(method.getNameIndex()); + if (MAIN_METHOD_NAME.equals(name)) { + return method; + } + } + return null; + } } diff --git a/group24/494800949/src/main/java/com/coding/mini_jvm/src/com/coderising/jvm/cmd/BiPushCmd.java b/group24/494800949/src/main/java/com/coding/mini_jvm/src/com/coderising/jvm/cmd/BiPushCmd.java new file mode 100644 index 0000000000..eb7dafa79d --- /dev/null +++ b/group24/494800949/src/main/java/com/coding/mini_jvm/src/com/coderising/jvm/cmd/BiPushCmd.java @@ -0,0 +1,21 @@ +package com.coding.mini_jvm.src.com.coderising.jvm.cmd; + +import com.coding.mini_jvm.src.com.coderising.jvm.clz.ClassFile; +import com.coding.mini_jvm.src.com.coderising.jvm.constant.ConstantPool; + +public class BiPushCmd extends OneOperandCmd { + + public BiPushCmd(ClassFile clzFile,String opCode) { + super(clzFile,opCode); + + } + + @Override + public String toString(ConstantPool pool) { + + return this.getOffset()+": "+ this.getOpCode()+" " + this.getReadableCodeText() + " " + this.getOperand(); + } + + + +} diff --git a/group24/494800949/src/main/java/com/coding/mini_jvm/src/com/coderising/jvm/cmd/ByteCodeCommand.java b/group24/494800949/src/main/java/com/coding/mini_jvm/src/com/coderising/jvm/cmd/ByteCodeCommand.java new file mode 100644 index 0000000000..b44d66c880 --- /dev/null +++ b/group24/494800949/src/main/java/com/coding/mini_jvm/src/com/coderising/jvm/cmd/ByteCodeCommand.java @@ -0,0 +1,127 @@ +package com.coding.mini_jvm.src.com.coderising.jvm.cmd; + +import com.coding.mini_jvm.src.com.coderising.jvm.clz.ClassFile; +import com.coding.mini_jvm.src.com.coderising.jvm.constant.ConstantInfo; +import com.coding.mini_jvm.src.com.coderising.jvm.constant.ConstantPool; + +import java.util.HashMap; +import java.util.Map; + +public abstract class ByteCodeCommand { + + String opCode; + ClassFile clzFile; + private int offset; + + private static Map codeMap = new HashMap(); + + static { + codeMap.put("01", "aconst_null"); + + codeMap.put("BB", "new"); + codeMap.put("37", "lstore"); + codeMap.put("B7", "invokespecial"); + codeMap.put("B6", "invokevirtual"); + codeMap.put("B4", "getfield"); + codeMap.put("B5", "putfield"); + codeMap.put("B2", "getstatic"); + + codeMap.put("2A", "aload_0"); + codeMap.put("2B", "aload_1"); + codeMap.put("2C", "aload_2"); + + codeMap.put("10", "bipush"); + codeMap.put("15", "iload"); + codeMap.put("1A", "iload_0"); + codeMap.put("1B", "iload_1"); + codeMap.put("1C", "iload_2"); + codeMap.put("1D", "iload_3"); + + codeMap.put("25", "fload_3"); + + codeMap.put("1E", "lload_0"); + + codeMap.put("24", "fload_2"); + codeMap.put("4C", "astore_1"); + + codeMap.put("A2", "if_icmp_ge"); + codeMap.put("A4", "if_icmple"); + + codeMap.put("A7", "goto"); + + codeMap.put("B1", "return"); + codeMap.put("AC", "ireturn"); + codeMap.put("AE", "freturn"); + + codeMap.put("03", "iconst_0"); + codeMap.put("04", "iconst_1"); + + codeMap.put("3C", "istore_1"); + codeMap.put("3D", "istore_2"); + + codeMap.put("59", "dup"); + + codeMap.put("60", "iadd"); + codeMap.put("84", "iinc"); + + codeMap.put("12", "ldc"); + } + + + + + + protected ByteCodeCommand(ClassFile clzFile, String opCode){ + this.clzFile = clzFile; + this.opCode = opCode; + } + + protected ClassFile getClassFile() { + return clzFile; + } + + public int getOffset() { + return offset; + } + + public void setOffset(int offset) { + this.offset = offset; + } + protected ConstantInfo getConstantInfo(int index){ + return this.getClassFile().getConstantPool().getConstantInfo(index); + } + + protected ConstantPool getConstantPool(){ + return this.getClassFile().getConstantPool(); + } + + + + public String getOpCode() { + return opCode; + } + + public abstract int getLength(); + + + + + public String toString(){ + + StringBuffer buffer = new StringBuffer(); + buffer.append(this.opCode); + + return buffer.toString(); + } + public abstract String toString(ConstantPool pool); + + public String getReadableCodeText(){ + String txt = codeMap.get(opCode); + if(txt == null){ + return opCode; + } + return txt; + } + + //public abstract void execute(StackFrame frame,FrameResult result); +} diff --git a/group24/494800949/src/main/java/com/coding/mini_jvm/src/com/coderising/jvm/cmd/CommandParser.java b/group24/494800949/src/main/java/com/coding/mini_jvm/src/com/coderising/jvm/cmd/CommandParser.java new file mode 100644 index 0000000000..dd01d38872 --- /dev/null +++ b/group24/494800949/src/main/java/com/coding/mini_jvm/src/com/coderising/jvm/cmd/CommandParser.java @@ -0,0 +1,150 @@ +package com.coding.mini_jvm.src.com.coderising.jvm.cmd; + +import com.coding.mini_jvm.src.com.coderising.jvm.clz.ClassFile; + +import java.util.ArrayList; +import java.util.List; +public class CommandParser { + + public static final String aconst_null = "01"; + public static final String new_object = "BB"; + public static final String lstore = "37"; + public static final String invokespecial = "B7"; + public static final String invokevirtual = "B6"; + public static final String getfield = "B4"; + public static final String putfield = "B5"; + public static final String getstatic = "B2"; + public static final String ldc = "12"; + public static final String dup = "59"; + public static final String bipush = "10"; + public static final String aload_0 = "2A"; + public static final String aload_1 = "2B"; + public static final String aload_2 = "2C"; + public static final String iload = "15"; + public static final String iload_1 = "1B"; + public static final String iload_2 = "1C"; + public static final String iload_3 = "1D"; + public static final String fload_3 = "25"; + + public static final String voidreturn = "B1"; + public static final String ireturn = "AC"; + public static final String freturn = "AE"; + + public static final String astore_1 = "4C"; + public static final String if_icmp_ge = "A2"; + public static final String if_icmple = "A4"; + public static final String goto_no_condition = "A7"; + public static final String iconst_0 = "03"; + public static final String iconst_1 = "04"; + public static final String istore_1 = "3C"; + public static final String istore_2 = "3D"; + public static final String iadd = "60"; + public static final String iinc = "84"; + + public static ByteCodeCommand[] parse(ClassFile clzFile, String codes) { + CommandIterator cmdIter = new CommandIterator(codes); + List cmds = new ArrayList<>(); + //2ab7000c2a2bb5000f2a1cb50011b1 + while (cmdIter.hasNext()) { + String operCode = cmdIter.next2CharAsString().toUpperCase(); + switch (operCode) { + case bipush: + BiPushCmd cmd = new BiPushCmd(clzFile, operCode); + cmd.setOperand(cmdIter.next2CharAsInt()); + cmds.add(cmd); + break; + case getfield: + GetFieldCmd getFieldCmd = new GetFieldCmd(clzFile, operCode); + getFieldCmd.setOprand1(cmdIter.next2CharAsInt()); + getFieldCmd.setOprand2(cmdIter.next2CharAsInt()); + cmds.add(getFieldCmd); + break; + case getstatic: + GetStaticFieldCmd getStaticFieldCmd = new GetStaticFieldCmd(clzFile, operCode); + getStaticFieldCmd.setOprand1(cmdIter.next2CharAsInt()); + getStaticFieldCmd.setOprand2(cmdIter.next2CharAsInt()); + cmds.add(getStaticFieldCmd); + break; + case invokespecial: + InvokeSpecialCmd invokeSpecialCmd = new InvokeSpecialCmd(clzFile, operCode); + invokeSpecialCmd.setOprand1(cmdIter.next2CharAsInt()); + invokeSpecialCmd.setOprand2(cmdIter.next2CharAsInt()); + cmds.add(invokeSpecialCmd); + break; + case invokevirtual: + InvokeVirtualCmd invokeVirtualCmd = new InvokeVirtualCmd(clzFile, operCode); + invokeVirtualCmd.setOprand1(cmdIter.next2CharAsInt()); + invokeVirtualCmd.setOprand2(cmdIter.next2CharAsInt()); + cmds.add(invokeVirtualCmd); + break; + case ldc: + LdcCmd ldcCmd = new LdcCmd(clzFile, operCode); + ldcCmd.setOperand(cmdIter.next2CharAsInt()); + cmds.add(ldcCmd); + break; + case new_object: + NewObjectCmd newObjectCmd = new NewObjectCmd(clzFile, operCode); + newObjectCmd.setOprand1(cmdIter.next2CharAsInt()); + newObjectCmd.setOprand2(cmdIter.next2CharAsInt()); + cmds.add(newObjectCmd); + break; + case putfield: + PutFieldCmd putFieldCmd = new PutFieldCmd(clzFile, operCode); + putFieldCmd.setOprand1(cmdIter.next2CharAsInt()); + putFieldCmd.setOprand2(cmdIter.next2CharAsInt()); + cmds.add(putFieldCmd); + break; + case astore_1: + case aload_0: + case aload_1: + case iload_1: + case iload_2: + case istore_1: + case voidreturn: + case dup: + NoOperandCmd noOperandCmd = new NoOperandCmd(clzFile, operCode); + cmds.add(noOperandCmd); + break; + default: + throw new RuntimeException("this oper [ " +operCode+ " ]not impl yet"); + } + } + calcuateOffset(cmds); + return cmds.toArray(new ByteCodeCommand[cmds.size()]); + } + + private static void calcuateOffset(List cmds) { + + int offset = 0; + for (ByteCodeCommand cmd : cmds) { + cmd.setOffset(offset); + offset += cmd.getLength(); + } + + } + + private static class CommandIterator { + String codes = null; + int pos = 0; + + CommandIterator(String codes) { + this.codes = codes; + } + + public boolean hasNext() { + return pos < this.codes.length(); + } + + public String next2CharAsString() { + String result = codes.substring(pos, pos + 2); + pos += 2; + return result; + } + + public int next2CharAsInt() { + String s = this.next2CharAsString(); + return Integer.valueOf(s, 16).intValue(); + } + + } +} diff --git a/group24/494800949/src/main/java/com/coding/mini_jvm/src/com/coderising/jvm/cmd/GetFieldCmd.java b/group24/494800949/src/main/java/com/coding/mini_jvm/src/com/coderising/jvm/cmd/GetFieldCmd.java new file mode 100644 index 0000000000..5801068cb0 --- /dev/null +++ b/group24/494800949/src/main/java/com/coding/mini_jvm/src/com/coderising/jvm/cmd/GetFieldCmd.java @@ -0,0 +1,21 @@ +package com.coding.mini_jvm.src.com.coderising.jvm.cmd; + +import com.coding.mini_jvm.src.com.coderising.jvm.clz.ClassFile; +import com.coding.mini_jvm.src.com.coderising.jvm.constant.ConstantPool; + +public class GetFieldCmd extends TwoOperandCmd { + + public GetFieldCmd(ClassFile clzFile,String opCode) { + super(clzFile,opCode); + } + + @Override + public String toString(ConstantPool pool) { + + return super.getOperandAsField(pool); + } + + + + +} diff --git a/group24/494800949/src/main/java/com/coding/mini_jvm/src/com/coderising/jvm/cmd/GetStaticFieldCmd.java b/group24/494800949/src/main/java/com/coding/mini_jvm/src/com/coderising/jvm/cmd/GetStaticFieldCmd.java new file mode 100644 index 0000000000..e577d1b56c --- /dev/null +++ b/group24/494800949/src/main/java/com/coding/mini_jvm/src/com/coderising/jvm/cmd/GetStaticFieldCmd.java @@ -0,0 +1,20 @@ +package com.coding.mini_jvm.src.com.coderising.jvm.cmd; + + +import com.coding.mini_jvm.src.com.coderising.jvm.clz.ClassFile; +import com.coding.mini_jvm.src.com.coderising.jvm.constant.ConstantPool; + +public class GetStaticFieldCmd extends TwoOperandCmd { + + public GetStaticFieldCmd(ClassFile clzFile,String opCode) { + super(clzFile,opCode); + + } + + @Override + public String toString(ConstantPool pool) { + + return super.getOperandAsField(pool); + } + +} diff --git a/group24/494800949/src/main/java/com/coding/mini_jvm/src/com/coderising/jvm/cmd/InvokeSpecialCmd.java b/group24/494800949/src/main/java/com/coding/mini_jvm/src/com/coderising/jvm/cmd/InvokeSpecialCmd.java new file mode 100644 index 0000000000..2900bb2c60 --- /dev/null +++ b/group24/494800949/src/main/java/com/coding/mini_jvm/src/com/coderising/jvm/cmd/InvokeSpecialCmd.java @@ -0,0 +1,22 @@ +package com.coding.mini_jvm.src.com.coderising.jvm.cmd; + + +import com.coding.mini_jvm.src.com.coderising.jvm.clz.ClassFile; +import com.coding.mini_jvm.src.com.coderising.jvm.constant.ConstantPool; + +public class InvokeSpecialCmd extends TwoOperandCmd { + + public InvokeSpecialCmd(ClassFile clzFile,String opCode) { + super(clzFile,opCode); + + } + + @Override + public String toString(ConstantPool pool) { + + return super.getOperandAsMethod(pool); + } + + + +} diff --git a/group24/494800949/src/main/java/com/coding/mini_jvm/src/com/coderising/jvm/cmd/InvokeVirtualCmd.java b/group24/494800949/src/main/java/com/coding/mini_jvm/src/com/coderising/jvm/cmd/InvokeVirtualCmd.java new file mode 100644 index 0000000000..ff7f0fdf14 --- /dev/null +++ b/group24/494800949/src/main/java/com/coding/mini_jvm/src/com/coderising/jvm/cmd/InvokeVirtualCmd.java @@ -0,0 +1,22 @@ +package com.coding.mini_jvm.src.com.coderising.jvm.cmd; + + +import com.coding.mini_jvm.src.com.coderising.jvm.clz.ClassFile; +import com.coding.mini_jvm.src.com.coderising.jvm.constant.ConstantPool; + +public class InvokeVirtualCmd extends TwoOperandCmd { + + public InvokeVirtualCmd(ClassFile clzFile,String opCode) { + super(clzFile,opCode); + } + + @Override + public String toString(ConstantPool pool) { + + return super.getOperandAsMethod(pool); + } + + + + +} diff --git a/group24/494800949/src/main/java/com/coding/mini_jvm/src/com/coderising/jvm/cmd/LdcCmd.java b/group24/494800949/src/main/java/com/coding/mini_jvm/src/com/coderising/jvm/cmd/LdcCmd.java new file mode 100644 index 0000000000..abaeae3a9e --- /dev/null +++ b/group24/494800949/src/main/java/com/coding/mini_jvm/src/com/coderising/jvm/cmd/LdcCmd.java @@ -0,0 +1,30 @@ +package com.coding.mini_jvm.src.com.coderising.jvm.cmd; + + +import com.coding.mini_jvm.src.com.coderising.jvm.clz.ClassFile; +import com.coding.mini_jvm.src.com.coderising.jvm.constant.ConstantInfo; +import com.coding.mini_jvm.src.com.coderising.jvm.constant.ConstantPool; +import com.coding.mini_jvm.src.com.coderising.jvm.constant.StringInfo; + +public class LdcCmd extends OneOperandCmd { + + public LdcCmd(ClassFile clzFile,String opCode) { + super(clzFile,opCode); + } + + @Override + public String toString(ConstantPool pool) { + + ConstantInfo info = (ConstantInfo)pool.getConstantInfo(this.getOperand()); + + String value = "TBD"; + if(info instanceof StringInfo){ + StringInfo strInfo = (StringInfo)info; + value = strInfo.toString(); + } + + return this.getOffset()+":"+this.getOpCode()+" " + this.getReadableCodeText() + " "+ value; + + } + +} diff --git a/group24/494800949/src/main/java/com/coding/mini_jvm/src/com/coderising/jvm/cmd/NewObjectCmd.java b/group24/494800949/src/main/java/com/coding/mini_jvm/src/com/coderising/jvm/cmd/NewObjectCmd.java new file mode 100644 index 0000000000..db90b82a35 --- /dev/null +++ b/group24/494800949/src/main/java/com/coding/mini_jvm/src/com/coderising/jvm/cmd/NewObjectCmd.java @@ -0,0 +1,19 @@ +package com.coding.mini_jvm.src.com.coderising.jvm.cmd; + +import com.coding.mini_jvm.src.com.coderising.jvm.clz.ClassFile; +import com.coding.mini_jvm.src.com.coderising.jvm.constant.ConstantPool; + +public class NewObjectCmd extends TwoOperandCmd{ + + public NewObjectCmd(ClassFile clzFile, String opCode){ + super(clzFile,opCode); + } + + @Override + public String toString(ConstantPool pool) { + + return super.getOperandAsClassInfo(pool); + } + + +} diff --git a/group24/494800949/src/main/java/com/coding/mini_jvm/src/com/coderising/jvm/cmd/NoOperandCmd.java b/group24/494800949/src/main/java/com/coding/mini_jvm/src/com/coderising/jvm/cmd/NoOperandCmd.java new file mode 100644 index 0000000000..3cd045f6d3 --- /dev/null +++ b/group24/494800949/src/main/java/com/coding/mini_jvm/src/com/coderising/jvm/cmd/NoOperandCmd.java @@ -0,0 +1,24 @@ +package com.coding.mini_jvm.src.com.coderising.jvm.cmd; + + +import com.coding.mini_jvm.src.com.coderising.jvm.clz.ClassFile; +import com.coding.mini_jvm.src.com.coderising.jvm.constant.ConstantPool; + +public class NoOperandCmd extends ByteCodeCommand{ + + public NoOperandCmd(ClassFile clzFile, String opCode) { + super(clzFile, opCode); + } + + @Override + public String toString(ConstantPool pool) { + return this.getOffset()+":" +this.getOpCode() + " "+ this.getReadableCodeText(); + } + + + + public int getLength(){ + return 1; + } + +} diff --git a/group24/494800949/src/main/java/com/coding/mini_jvm/src/com/coderising/jvm/cmd/OneOperandCmd.java b/group24/494800949/src/main/java/com/coding/mini_jvm/src/com/coderising/jvm/cmd/OneOperandCmd.java new file mode 100644 index 0000000000..696764c3e7 --- /dev/null +++ b/group24/494800949/src/main/java/com/coding/mini_jvm/src/com/coderising/jvm/cmd/OneOperandCmd.java @@ -0,0 +1,27 @@ +package com.coding.mini_jvm.src.com.coderising.jvm.cmd; + +import com.coding.mini_jvm.src.com.coderising.jvm.clz.ClassFile; + +public abstract class OneOperandCmd extends ByteCodeCommand { + + private int operand; + + public OneOperandCmd(ClassFile clzFile,String opCode) { + super(clzFile, opCode); + + } + public int getOperand() { + + return this.operand; + } + + public void setOperand(int oprand1) { + this.operand = oprand1; + + } + public int getLength(){ + return 2; + } + + +} diff --git a/group24/494800949/src/main/java/com/coding/mini_jvm/src/com/coderising/jvm/cmd/PutFieldCmd.java b/group24/494800949/src/main/java/com/coding/mini_jvm/src/com/coderising/jvm/cmd/PutFieldCmd.java new file mode 100644 index 0000000000..6f6ecd0eb1 --- /dev/null +++ b/group24/494800949/src/main/java/com/coding/mini_jvm/src/com/coderising/jvm/cmd/PutFieldCmd.java @@ -0,0 +1,20 @@ +package com.coding.mini_jvm.src.com.coderising.jvm.cmd; + + +import com.coding.mini_jvm.src.com.coderising.jvm.clz.ClassFile; +import com.coding.mini_jvm.src.com.coderising.jvm.constant.ConstantPool; + +public class PutFieldCmd extends TwoOperandCmd { + + public PutFieldCmd(ClassFile clzFile,String opCode) { + super(clzFile,opCode); + } + + @Override + public String toString(ConstantPool pool) { + + return super.getOperandAsField(pool); + } + + +} diff --git a/group24/494800949/src/main/java/com/coding/mini_jvm/src/com/coderising/jvm/cmd/TwoOperandCmd.java b/group24/494800949/src/main/java/com/coding/mini_jvm/src/com/coderising/jvm/cmd/TwoOperandCmd.java new file mode 100644 index 0000000000..78475ac911 --- /dev/null +++ b/group24/494800949/src/main/java/com/coding/mini_jvm/src/com/coderising/jvm/cmd/TwoOperandCmd.java @@ -0,0 +1,63 @@ +package com.coding.mini_jvm.src.com.coderising.jvm.cmd; + +import com.coding.mini_jvm.src.com.coderising.jvm.clz.ClassFile; +import com.coding.mini_jvm.src.com.coderising.jvm.constant.*; + +public abstract class TwoOperandCmd extends ByteCodeCommand{ + + int oprand1 = -1; + int oprand2 = -1; + + public int getOprand1() { + return oprand1; + } + + public void setOprand1(int oprand1) { + this.oprand1 = oprand1; + } + + public void setOprand2(int oprand2) { + this.oprand2 = oprand2; + } + + public int getOprand2() { + return oprand2; + } + + public TwoOperandCmd(ClassFile clzFile,String opCode) { + super(clzFile, opCode); + } + + public int getIndex(){ + int oprand1 = this.getOprand1(); + int oprand2 = this.getOprand2(); + int index = oprand1 << 8 | oprand2; + return index; + } + + protected String getOperandAsClassInfo(ConstantPool pool){ + int index = getIndex(); + String codeTxt = getReadableCodeText(); + ClassInfo info = (ClassInfo)pool.getConstantInfo(index); + return this.getOffset()+":"+this.getOpCode()+" "+ codeTxt +" "+ info.getClassName(); + } + + protected String getOperandAsMethod(ConstantPool pool){ + int index = getIndex(); + String codeTxt = getReadableCodeText(); + ConstantInfo constInfo = this.getConstantInfo(index); + MethodRefInfo info = (MethodRefInfo)this.getConstantInfo(index); + return this.getOffset()+":"+this.getOpCode()+" " + codeTxt +" "+ info.toString(); + } + + protected String getOperandAsField(ConstantPool pool){ + int index = getIndex(); + + String codeTxt = getReadableCodeText(); + FieldRefInfo info = (FieldRefInfo)this.getConstantInfo(index); + return this.getOffset()+":"+this.getOpCode()+" " + codeTxt +" "+ info.toString(); + } + public int getLength(){ + return 3; + } +} diff --git a/group24/494800949/src/main/java/com/coding/mini_jvm/src/com/coderising/jvm/constant/ClassInfo.java b/group24/494800949/src/main/java/com/coding/mini_jvm/src/com/coderising/jvm/constant/ClassInfo.java index 227bb010a1..489e8c7c7c 100644 --- a/group24/494800949/src/main/java/com/coding/mini_jvm/src/com/coderising/jvm/constant/ClassInfo.java +++ b/group24/494800949/src/main/java/com/coding/mini_jvm/src/com/coderising/jvm/constant/ClassInfo.java @@ -15,10 +15,15 @@ public void setUtf8Index(int utf8Index) { public int getType() { return type; } - + public String getClassName() { int index = getUtf8Index(); UTF8Info utf8Info = (UTF8Info)constantPool.getConstantInfo(index); return utf8Info.getValue(); } + + @Override + public void accept(Visitor visitor) { + visitor.visitClassInfo(this); + } } diff --git a/group24/494800949/src/main/java/com/coding/mini_jvm/src/com/coderising/jvm/constant/ConstantInfo.java b/group24/494800949/src/main/java/com/coding/mini_jvm/src/com/coderising/jvm/constant/ConstantInfo.java index e7c849ca59..7a9200f669 100644 --- a/group24/494800949/src/main/java/com/coding/mini_jvm/src/com/coderising/jvm/constant/ConstantInfo.java +++ b/group24/494800949/src/main/java/com/coding/mini_jvm/src/com/coderising/jvm/constant/ConstantInfo.java @@ -2,7 +2,6 @@ public abstract class ConstantInfo { public static final int UTF8_INFO = 1; - public static final int FLOAT_INFO = 4; public static final int CLASS_INFO = 7; public static final int STRING_INFO = 8; public static final int FIELD_INFO = 9; @@ -25,5 +24,15 @@ public ConstantPool getConstantPool() { public ConstantInfo getConstantInfo(int index){ return this.constantPool.getConstantInfo(index); } - + + public abstract void accept(Visitor visitor); + + public static interface Visitor{ + public void visitClassInfo(ClassInfo info); + public void visitFieldRef(FieldRefInfo info); + public void visitMethodRef(MethodRefInfo info); + public void visitNameAndType(NameAndTypeInfo info); + public void visitString(StringInfo info); + public void visistUTF8(UTF8Info info); + } } diff --git a/group24/494800949/src/main/java/com/coding/mini_jvm/src/com/coderising/jvm/constant/FieldRefInfo.java b/group24/494800949/src/main/java/com/coding/mini_jvm/src/com/coderising/jvm/constant/FieldRefInfo.java index 1808a35c65..bca8e0b32b 100644 --- a/group24/494800949/src/main/java/com/coding/mini_jvm/src/com/coderising/jvm/constant/FieldRefInfo.java +++ b/group24/494800949/src/main/java/com/coding/mini_jvm/src/com/coderising/jvm/constant/FieldRefInfo.java @@ -11,7 +11,7 @@ public FieldRefInfo(ConstantPool pool) { public int getType() { return type; } - + public int getClassInfoIndex() { return classInfoIndex; } @@ -51,4 +51,11 @@ public String getFieldType(){ NameAndTypeInfo typeInfo = (NameAndTypeInfo)this.getConstantInfo(this.getNameAndTypeIndex()); return typeInfo.getTypeInfo(); } + + + @Override + public void accept(Visitor visitor) { + visitor.visitFieldRef(this); + } + } diff --git a/group24/494800949/src/main/java/com/coding/mini_jvm/src/com/coderising/jvm/constant/MethodRefInfo.java b/group24/494800949/src/main/java/com/coding/mini_jvm/src/com/coderising/jvm/constant/MethodRefInfo.java index dc62d438e6..4664a79cf4 100644 --- a/group24/494800949/src/main/java/com/coding/mini_jvm/src/com/coderising/jvm/constant/MethodRefInfo.java +++ b/group24/494800949/src/main/java/com/coding/mini_jvm/src/com/coderising/jvm/constant/MethodRefInfo.java @@ -14,7 +14,12 @@ public MethodRefInfo(ConstantPool pool) { public int getType() { return type; } - + + @Override + public void accept(Visitor visitor) { + visitor.visitMethodRef(this); + } + public int getClassInfoIndex() { return classInfoIndex; } diff --git a/group24/494800949/src/main/java/com/coding/mini_jvm/src/com/coderising/jvm/constant/NameAndTypeInfo.java b/group24/494800949/src/main/java/com/coding/mini_jvm/src/com/coderising/jvm/constant/NameAndTypeInfo.java index b8b9da7353..f1c59a0d5e 100644 --- a/group24/494800949/src/main/java/com/coding/mini_jvm/src/com/coderising/jvm/constant/NameAndTypeInfo.java +++ b/group24/494800949/src/main/java/com/coding/mini_jvm/src/com/coderising/jvm/constant/NameAndTypeInfo.java @@ -25,8 +25,13 @@ public void setIndex2(int index2) { public int getType() { return type; } - - + + @Override + public void accept(Visitor visitor) { + visitor.visitNameAndType(this); + } + + public String getName(){ ConstantPool pool = this.getConstantPool(); UTF8Info utf8Info1 = (UTF8Info)pool.getConstantInfo(index1); diff --git a/group24/494800949/src/main/java/com/coding/mini_jvm/src/com/coderising/jvm/constant/NullConstantInfo.java b/group24/494800949/src/main/java/com/coding/mini_jvm/src/com/coderising/jvm/constant/NullConstantInfo.java index bf19f681d8..16ec6a1e2f 100644 --- a/group24/494800949/src/main/java/com/coding/mini_jvm/src/com/coderising/jvm/constant/NullConstantInfo.java +++ b/group24/494800949/src/main/java/com/coding/mini_jvm/src/com/coderising/jvm/constant/NullConstantInfo.java @@ -9,5 +9,9 @@ public NullConstantInfo(){ public int getType() { return -1; } - + + @Override + public void accept(Visitor visitor) { + } + } diff --git a/group24/494800949/src/main/java/com/coding/mini_jvm/src/com/coderising/jvm/constant/StringInfo.java b/group24/494800949/src/main/java/com/coding/mini_jvm/src/com/coderising/jvm/constant/StringInfo.java index 05a4afad6a..d18ac12305 100644 --- a/group24/494800949/src/main/java/com/coding/mini_jvm/src/com/coderising/jvm/constant/StringInfo.java +++ b/group24/494800949/src/main/java/com/coding/mini_jvm/src/com/coderising/jvm/constant/StringInfo.java @@ -10,7 +10,12 @@ public StringInfo(ConstantPool pool) { public int getType() { return type; } - + + @Override + public void accept(Visitor visitor) { + visitor.visitString(this); + } + public int getIndex() { return index; } diff --git a/group24/494800949/src/main/java/com/coding/mini_jvm/src/com/coderising/jvm/constant/UTF8Info.java b/group24/494800949/src/main/java/com/coding/mini_jvm/src/com/coderising/jvm/constant/UTF8Info.java index 61f20ed8f1..81160db29e 100644 --- a/group24/494800949/src/main/java/com/coding/mini_jvm/src/com/coderising/jvm/constant/UTF8Info.java +++ b/group24/494800949/src/main/java/com/coding/mini_jvm/src/com/coderising/jvm/constant/UTF8Info.java @@ -16,6 +16,12 @@ public void setLength(int length) { public int getType() { return type; } + + @Override + public void accept(Visitor visitor) { + visitor.visistUTF8(this); + } + @Override public String toString() { return "UTF8Info [type=" + type + ", length=" + length + ", value=" + value +")]"; diff --git a/group24/494800949/src/main/java/com/coding/mini_jvm/src/com/coderising/jvm/loader/ByteCodeIterator.java b/group24/494800949/src/main/java/com/coding/mini_jvm/src/com/coderising/jvm/loader/ByteCodeIterator.java index 1fe59b5bdb..cf2db01a36 100644 --- a/group24/494800949/src/main/java/com/coding/mini_jvm/src/com/coderising/jvm/loader/ByteCodeIterator.java +++ b/group24/494800949/src/main/java/com/coding/mini_jvm/src/com/coderising/jvm/loader/ByteCodeIterator.java @@ -27,6 +27,15 @@ public String readBytesToString(int len) { } + public String readBytesToHexString(int len) { + byte[] bs = new byte[len]; + System.arraycopy(bytes, cursor, bs, 0, len); + String ret = Util.byteToHexString(bs); + cursor += len; + return ret; + } + + public int readTwoBytesToInt() { int ret = Util.bytes2Int(bytes, cursor, U2); cursor += U2; diff --git a/group24/494800949/src/main/java/com/coding/mini_jvm/src/com/coderising/jvm/method/Method.java b/group24/494800949/src/main/java/com/coding/mini_jvm/src/com/coderising/jvm/method/Method.java index fd5734e6b6..b848e6b515 100644 --- a/group24/494800949/src/main/java/com/coding/mini_jvm/src/com/coderising/jvm/method/Method.java +++ b/group24/494800949/src/main/java/com/coding/mini_jvm/src/com/coderising/jvm/method/Method.java @@ -3,6 +3,7 @@ import com.coding.mini_jvm.src.com.coderising.jvm.attr.CodeAttr; import com.coding.mini_jvm.src.com.coderising.jvm.clz.ClassFile; +import com.coding.mini_jvm.src.com.coderising.jvm.cmd.ByteCodeCommand; import com.coding.mini_jvm.src.com.coderising.jvm.loader.ByteCodeIterator; public class Method { @@ -48,7 +49,6 @@ public static Method parse(ClassFile clzFile, ByteCodeIterator iter){ int nameIndex = iter.readTwoBytesToInt(); int descIndex = iter.readTwoBytesToInt(); Method method = new Method(clzFile, accessFlag, nameIndex, descIndex); - System.out.println(clzFile.getConstantPool().getUTF8String(descIndex)); int attrCount = iter.readTwoBytesToInt(); if (attrCount > 1) throw new RuntimeException("other attrbute not impl yet"); @@ -58,9 +58,12 @@ public static Method parse(ClassFile clzFile, ByteCodeIterator iter){ CodeAttr codeAttr = CodeAttr.parse(clzFile, iter); method.setCodeAttr(codeAttr); } else - throw new RuntimeException("not impl yet"); + throw new RuntimeException(" attribute[ " + attrNameIndex + " ] not impl yet"); } return method; } + public ByteCodeCommand[] getCmds() { + return this.getCodeAttr().getCmds(); + } } diff --git a/group24/494800949/src/main/java/com/coding/mini_jvm/src/com/coderising/jvm/print/ClassFilePrinter.java b/group24/494800949/src/main/java/com/coding/mini_jvm/src/com/coderising/jvm/print/ClassFilePrinter.java new file mode 100644 index 0000000000..39553dd48c --- /dev/null +++ b/group24/494800949/src/main/java/com/coding/mini_jvm/src/com/coderising/jvm/print/ClassFilePrinter.java @@ -0,0 +1,45 @@ +package com.coding.mini_jvm.src.com.coderising.jvm.print; + +import com.coding.mini_jvm.src.com.coderising.jvm.clz.ClassFile; +import com.coding.mini_jvm.src.com.coderising.jvm.loader.ClassFileLoader; + +public class ClassFilePrinter { + ClassFile clzFile = null; + public ClassFilePrinter(ClassFile clzFile){ + this.clzFile = clzFile; + } + + public void print(){ + + if(clzFile.getAccessFlag().isPublicClass()){ + System.out.println("Access flag : public "); + } + System.out.println("Class Name:"+ clzFile.getClassName()); + + System.out.println("Super Class Name:"+ clzFile.getSuperClassName()); + + System.out.println("minor version:" + clzFile.getMinorVersion()); + + System.out.println("major version:" + clzFile.getMinorVersion()); + + ConstantPoolPrinter cnstPoolPrinter = new ConstantPoolPrinter(clzFile.getConstantPool()); + cnstPoolPrinter.print(); + + + + + } + + public static void main(String[] args){ + String path = "H:\\sourceCode\\coding2017\\group24\\494800949"; + ClassFileLoader loader = new ClassFileLoader(); + loader.addClassPath(path); + String className = "EmployeeV1"; + + ClassFile clzFile = loader.loadClass(className); + + ClassFilePrinter printer = new ClassFilePrinter(clzFile); + + printer.print(); + } +} diff --git a/group24/494800949/src/main/java/com/coding/mini_jvm/src/com/coderising/jvm/print/ConstantPoolPrinter.java b/group24/494800949/src/main/java/com/coding/mini_jvm/src/com/coderising/jvm/print/ConstantPoolPrinter.java new file mode 100644 index 0000000000..baa0e8ead4 --- /dev/null +++ b/group24/494800949/src/main/java/com/coding/mini_jvm/src/com/coderising/jvm/print/ConstantPoolPrinter.java @@ -0,0 +1,34 @@ +package com.coding.mini_jvm.src.com.coderising.jvm.print; + + +import com.coding.mini_jvm.src.com.coderising.jvm.constant.ConstantInfo; +import com.coding.mini_jvm.src.com.coderising.jvm.constant.ConstantPool; + +import java.util.Formatter; + +public class ConstantPoolPrinter { + ConstantPool pool; + + ConstantPoolPrinter(ConstantPool pool) { + this.pool = pool; + } + + public void print() { + + System.out.println("Constant Pool:"); + + for (int i = 1; i <= (int)pool.getSize(); i++){ + ConstantInfo constantInfo = pool.getConstantInfo(i); + Formatter formatter = new Formatter(System.out); + formatter.format("%5s", "#"+i); + constantInfo.accept(new SimpleVistor()); + } + } + + public static void main(String[] args) { +// Formatter f = new Formatter(System.out); +// f.format("%-15s %-5s %-10s\n", "Item", "Qty", "Price"); +// f.format("%-15s %-5s %-10s\n", "----", "----", "-----"); + + } +} diff --git a/group24/494800949/src/main/java/com/coding/mini_jvm/src/com/coderising/jvm/print/SimpleVistor.java b/group24/494800949/src/main/java/com/coding/mini_jvm/src/com/coderising/jvm/print/SimpleVistor.java new file mode 100644 index 0000000000..e10e7885ba --- /dev/null +++ b/group24/494800949/src/main/java/com/coding/mini_jvm/src/com/coderising/jvm/print/SimpleVistor.java @@ -0,0 +1,56 @@ +package com.coding.mini_jvm.src.com.coderising.jvm.print; + +import com.coding.mini_jvm.src.com.coderising.jvm.constant.*; + +import java.util.Formatter; + +/** + * Created by Administrator on 2017/4/23 0023. + */ +public class SimpleVistor implements ConstantInfo.Visitor { + private Formatter formatter = new Formatter(System.out); + private String format = " = %-20s %-20s %-100s\n"; + private static final String HASH_KEY = "#"; + private static final String DOUBLE_SLASH = "// "; + private static final String DOT = "."; + private static final String COLON = ":"; + + @Override + public void visitClassInfo(ClassInfo info) { + formatter.format(format, "Class", + HASH_KEY + info.getUtf8Index(), + DOUBLE_SLASH + info.getClassName()); + } + + @Override + public void visitFieldRef(FieldRefInfo info) { + NameAndTypeInfo nameAndTypeInfo = (NameAndTypeInfo)info.getConstantInfo(info.getNameAndTypeIndex()); + formatter.format(format, "Fieldref", + HASH_KEY + info.getClassInfoIndex() + DOT + HASH_KEY + info.getNameAndTypeIndex(), + DOUBLE_SLASH + info.getClassName() + DOT + nameAndTypeInfo.getName() + COLON + nameAndTypeInfo.getTypeInfo()); + } + + @Override + public void visitMethodRef(MethodRefInfo info) { + formatter.format(format, "Methodref", + HASH_KEY + info.getClassInfoIndex() + DOT + HASH_KEY + info.getNameAndTypeIndex(), + DOUBLE_SLASH + info.getClassName() + DOT + info.getMethodName()); + } + + @Override + public void visitNameAndType(NameAndTypeInfo info) { + formatter.format(format, "NameAndType", + HASH_KEY + info.getIndex1() + COLON + HASH_KEY + info.getIndex2(), + DOUBLE_SLASH + info.getName() + COLON + info.getTypeInfo()); + } + + @Override + public void visitString(StringInfo info) { + formatter.format(format, "String", HASH_KEY + info.getIndex(), DOUBLE_SLASH + info.toString()); + } + + @Override + public void visistUTF8(UTF8Info info) { + formatter.format(format, "Utf8", info.getValue(), ""); + } +} diff --git a/group24/494800949/src/main/java/com/coding/week6/exprNew/InfixExpr.java b/group24/494800949/src/main/java/com/coding/week6/exprNew/InfixExpr.java new file mode 100644 index 0000000000..3962b49fce --- /dev/null +++ b/group24/494800949/src/main/java/com/coding/week6/exprNew/InfixExpr.java @@ -0,0 +1,57 @@ +package com.coding.week6.exprNew; + +import com.coding.weak1.Stack; + +import java.util.List; + +public class InfixExpr { + String expr = null; + + public InfixExpr(String expr) { + this.expr = expr; + } + + + public float evaluate() { + + Stack operatorStack = new Stack(); + Stack numberStack = new Stack(); + fillStack(numberStack, operatorStack); + while (!operatorStack.isEmpty()) { + Operator symbol = (Operator) operatorStack.pop(); + float operTop1 = (float) numberStack.pop(); + float operTop2 = (float) numberStack.pop(); + numberStack.push(symbol.apply(operTop2, operTop1)); + } + return (float)numberStack.pop(); + } + + public void fillStack(Stack numberStack, Stack operatorStack) { + TokenParser tokenParser = new TokenParser(); + List tokens = tokenParser.parse(expr); + for (Token token : tokens) { + if (token.isNumber()) { + numberStack.push(token.getFloatValue()); + } + else if (token.isOperator()) { + Operator o = token.getOperator(); + if (operatorStack.isEmpty()) { + operatorStack.push(o); + }else { + Operator top = (Operator)operatorStack.peek(); + if (o.hasHigherPriority(top)) { + operatorStack.push(o); + } else { + float operTop1 = (float) numberStack.pop(); + float operTop2 = (float) numberStack.pop(); + numberStack.push(top.apply(operTop2, operTop1)); + operatorStack.pop(); + operatorStack.push(o); + } + } + } + + } + } + +} diff --git a/group24/494800949/src/main/java/com/coding/week6/exprNew/Operator.java b/group24/494800949/src/main/java/com/coding/week6/exprNew/Operator.java new file mode 100644 index 0000000000..f6b4681e46 --- /dev/null +++ b/group24/494800949/src/main/java/com/coding/week6/exprNew/Operator.java @@ -0,0 +1,75 @@ +package com.coding.week6.exprNew; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +/** + * Created by Administrator on 2017/4/22 0022. + */ +public enum Operator { + ADD("+", 1) { + public float apply(float x, float y){ + return x + y; + } + }, + + SUB("-", 1) { + @Override + public float apply(float x, float y) { + return x - y; + } + }, + + MULT("*", 2) { + @Override + public float apply(float x, float y) { + return x * y; + } + }, + + DIVI("/", 2) { + @Override + public float apply(float x, float y) { + return x / y; + } + }; + private String symbol; + private int priority; + + Operator(String symbol, int priority) { + this.symbol = symbol; + this.priority = priority; + } + + public boolean hasHigherPriority(Operator o) { + return this.priority > o.priority; + } + + public String symbol() { + return symbol; + } + + public static List symbols() { + List symbos = new ArrayList<>(); + for (Operator o : Operator.values()) { + symbos.add(o.symbol); + } + return symbos; + } + + public abstract float apply(float x, float y); + + private static final Map map = new HashMap(); + + static { + for (Operator o : Operator.values()) { + map.put(o.symbol, o); + } + } + + public static Map getOperatorMap() { + return map; + } +} diff --git a/group24/494800949/src/main/java/com/coding/week6/exprNew/Token.java b/group24/494800949/src/main/java/com/coding/week6/exprNew/Token.java new file mode 100644 index 0000000000..c925a22705 --- /dev/null +++ b/group24/494800949/src/main/java/com/coding/week6/exprNew/Token.java @@ -0,0 +1,63 @@ +package com.coding.week6.exprNew; + +/** + * Created by Administrator on 2017/4/22 0022. + */ +public class Token { + + private int type; + private String value; + + static final int NUMBER = 1; + static final int OPERATOR = 2; + static final int LEFT_BRACKET = 3; + static final int RIGHT_BRACKET = 4; + public Token(int type, String value) { + this.type = type; + this.value = value; + } + + + public boolean isNumber(){ + return type == NUMBER; + } + + public boolean isOperator(){ + return type == OPERATOR; + } + + public boolean isLeftBracket() { + return type == LEFT_BRACKET; + } + + public boolean isRightBracket() { + return type == RIGHT_BRACKET; + } + + public float getFloatValue() { + if (isNumber()) + return Integer.valueOf(value); + else + throw new RuntimeException("not a number"); + } + + public String toString() { + return value; + } + + + public Operator getOperator() { + if (isOperator()) { + return Operator.getOperatorMap().get(value); + } else { + throw new RuntimeException("not a operator"); + } + } + + + public String getValue() { + return value; + } + + +} diff --git a/group24/494800949/src/main/java/com/coding/week6/exprNew/TokenParser.java b/group24/494800949/src/main/java/com/coding/week6/exprNew/TokenParser.java new file mode 100644 index 0000000000..52757dc0c7 --- /dev/null +++ b/group24/494800949/src/main/java/com/coding/week6/exprNew/TokenParser.java @@ -0,0 +1,60 @@ +package com.coding.week6.exprNew; + +import java.util.ArrayList; +import java.util.List; + +/** + * Created by Administrator on 2017/4/22 0022. + */ +public class TokenParser { + + private static List operators = Operator.symbols(); + public List parse(String expr) { + List tokens = new ArrayList<>(); + int i = 0; + while (i < expr.length()) { + char c = expr.charAt(i); + Token token; + if (Character.isDigit(c)) { + int nextOperIndex = getNextOperIndex(i, expr); + String n = expr.substring(i, nextOperIndex); + token = new Token(Token.NUMBER, n); + tokens.add(token); + i = nextOperIndex; + } else if (isOperator(c)) { + token = new Token(Token.OPERATOR, c+""); + tokens.add(token); + i++; + } else if (String.valueOf(c).matches("\\s")){ + i++; + } else if (c == '(') { + token = new Token(Token.LEFT_BRACKET, String.valueOf(c)); + tokens.add(token); + i++; + } else if (c == ')') { + token = new Token(Token.RIGHT_BRACKET, String.valueOf(c)); + tokens.add(token); + i++; + } else { + throw new RuntimeException(c +" is not number or support operator"); + } + } + return tokens; + } + + private int getNextOperIndex(int i, String expr) { + while (Character.isDigit(expr.charAt(i))) { + i++; + if (i == expr.length()) { + break; + } + } + return i; + } + + private boolean isOperator(char c) { + return operators.contains(String.valueOf(c)); + } + + +} diff --git a/group24/494800949/src/main/java/com/coding/week7/InfixToPostfix.java b/group24/494800949/src/main/java/com/coding/week7/InfixToPostfix.java new file mode 100644 index 0000000000..6717f571ee --- /dev/null +++ b/group24/494800949/src/main/java/com/coding/week7/InfixToPostfix.java @@ -0,0 +1,69 @@ +package com.coding.week7; + +import com.coding.week6.exprNew.Operator; +import com.coding.week6.exprNew.Token; +import com.coding.week6.exprNew.TokenParser; + +import java.util.ArrayList; +import java.util.List; +import java.util.Stack; + +public class InfixToPostfix { + + public static List convert(String expr) { + /** + 1 建立符号栈 + 2 顺序扫描中序表达式 + a) 是数字, 直接输出 + b) 是运算符 + i : “(” 直接入栈 + ii : “)” 将符号栈中的元素依次出栈并输出, 直到 “(“, “(“只出栈, 不输出 + iii: 其他符号, 将符号栈中的元素依次出栈并输出, 直到 遇到比当前符号优先级更低的符号或者”(“。 将当前符号入栈。 + 3 扫描完后, 将栈中剩余符号依次输出 + */ + List targetTokens = new ArrayList<>(); + TokenParser tokenParser = new TokenParser(); + List sourceTokes = tokenParser.parse(expr); + Stack operStack = new Stack(); + for (Token token : sourceTokes) { + if (token.isNumber()) { + targetTokens.add(token); + } else { + //左括号 + if (token.isLeftBracket()) { + operStack.push(token); + //右括号 + } else if (token.isRightBracket()) { + while (!operStack.isEmpty()) { + Token t = operStack.peek(); + if (t.isLeftBracket()) { + operStack.pop(); + break; + } else { + targetTokens.add(operStack.pop()); + } + } + //普通运算符 + } else { + Operator oper = token.getOperator(); + if (!operStack.isEmpty()) { + Token t = operStack.peek(); + while (!t.isLeftBracket() && !oper.hasHigherPriority(t.getOperator()) && !operStack.isEmpty()) { + t = operStack.pop(); + targetTokens.add(t); + } + } + operStack.push(token); + } + } + } + //将栈中操作符全部输出 + while (!operStack.isEmpty()) { + targetTokens.add(operStack.pop()); + } + return targetTokens; + } + + + +} diff --git a/group24/494800949/src/main/java/com/coding/week7/PostfixExpr.java b/group24/494800949/src/main/java/com/coding/week7/PostfixExpr.java new file mode 100644 index 0000000000..8fb78e6a8d --- /dev/null +++ b/group24/494800949/src/main/java/com/coding/week7/PostfixExpr.java @@ -0,0 +1,39 @@ +package com.coding.week7; + +import com.coding.week6.exprNew.Operator; +import com.coding.week6.exprNew.Token; +import com.coding.week6.exprNew.TokenParser; + +import java.util.List; +import java.util.Stack; + +public class PostfixExpr { + String expr = null; + final Stack numStack; + final Stack operStack; + + public PostfixExpr(String expr) { + this.expr = expr; + this.numStack = new Stack<>(); + this.operStack = new Stack<>(); + } + + public float evaluate() { + TokenParser parser = new TokenParser(); + List tokens = parser.parse(expr); + for (Token token : tokens) { + if (token.isNumber()) { + numStack.push(token.getFloatValue()); + } else if (token.isOperator()) { + if (numStack.size() >= 2) { + Float num1 = numStack.pop(); + Float num2 = numStack.pop(); + Float result = token.getOperator().apply(num2, num1); + numStack.push(result); + } + } + } + return numStack.pop(); + } + +} diff --git a/group24/494800949/src/main/java/com/coding/week7/PrefixExpr.java b/group24/494800949/src/main/java/com/coding/week7/PrefixExpr.java new file mode 100644 index 0000000000..1bb8e4fd8a --- /dev/null +++ b/group24/494800949/src/main/java/com/coding/week7/PrefixExpr.java @@ -0,0 +1,43 @@ +package com.coding.week7; + +import com.coding.week6.exprNew.Operator; +import com.coding.week6.exprNew.Token; +import com.coding.week6.exprNew.TokenParser; + +import java.util.Collections; +import java.util.List; +import java.util.Stack; + +public class PrefixExpr { + String expr = null; + final Stack numStack; + final Stack operStack; + + public PrefixExpr(String expr) { + this.expr = expr; + numStack = new Stack<>(); + operStack = new Stack<>(); + } + + public float evaluate() { + TokenParser parser = new TokenParser(); + parser.parse(expr); + List tokens = parser.parse(expr); + Collections.reverse(tokens); + for (Token token : tokens) { + if (token.isNumber()) { + numStack.push(token.getFloatValue()); + } else if (token.isOperator()) { + if (numStack.size() >= 2) { + Float num1 = numStack.pop(); + Float num2 = numStack.pop(); + Float result = token.getOperator().apply(num1, num2); + numStack.push(result); + } + } + } + return numStack.pop(); + } + + +} diff --git a/group24/494800949/src/test/java/com/coding/mini_jvm/test/ClassFileloaderTest.java b/group24/494800949/src/test/java/com/coding/mini_jvm/test/ClassFileloaderTest.java index 00812bcd80..b9561f243b 100644 --- a/group24/494800949/src/test/java/com/coding/mini_jvm/test/ClassFileloaderTest.java +++ b/group24/494800949/src/test/java/com/coding/mini_jvm/test/ClassFileloaderTest.java @@ -2,6 +2,10 @@ import com.coding.mini_jvm.src.com.coderising.jvm.clz.ClassFile; import com.coding.mini_jvm.src.com.coderising.jvm.clz.ClassIndex; +import com.coding.mini_jvm.src.com.coderising.jvm.cmd.BiPushCmd; +import com.coding.mini_jvm.src.com.coderising.jvm.cmd.ByteCodeCommand; +import com.coding.mini_jvm.src.com.coderising.jvm.cmd.OneOperandCmd; +import com.coding.mini_jvm.src.com.coderising.jvm.cmd.TwoOperandCmd; import com.coding.mini_jvm.src.com.coderising.jvm.constant.*; import com.coding.mini_jvm.src.com.coderising.jvm.field.Field; import com.coding.mini_jvm.src.com.coderising.jvm.loader.ClassFileLoader; @@ -244,4 +248,79 @@ private void assertMethodEquals(ConstantPool pool,Method m , String expectedName Assert.assertEquals(expectedDesc, methodDesc); Assert.assertEquals(expectedCode, code); } + + /***************************第四次jvm测试用例 **************************/ + @Test + public void testByteCodeCommand(){ + { + Method initMethod = this.clzFile.getMethod("", "(Ljava/lang/String;I)V"); + ByteCodeCommand[] cmds = initMethod.getCmds(); + + assertOpCodeEquals("0: aload_0", cmds[0]); + assertOpCodeEquals("1: invokespecial #12", cmds[1]); + assertOpCodeEquals("4: aload_0", cmds[2]); + assertOpCodeEquals("5: aload_1", cmds[3]); + assertOpCodeEquals("6: putfield #15", cmds[4]); + assertOpCodeEquals("9: aload_0", cmds[5]); + assertOpCodeEquals("10: iload_2", cmds[6]); + assertOpCodeEquals("11: putfield #17", cmds[7]); + assertOpCodeEquals("14: return", cmds[8]); + } + + { + Method setNameMethod = this.clzFile.getMethod("setName", "(Ljava/lang/String;)V"); + ByteCodeCommand [] cmds = setNameMethod.getCmds(); + + assertOpCodeEquals("0: aload_0", cmds[0]); + assertOpCodeEquals("1: aload_1", cmds[1]); + assertOpCodeEquals("2: putfield #15", cmds[2]); + assertOpCodeEquals("5: return", cmds[3]); + + } + + { + Method sayHelloMethod = this.clzFile.getMethod("sayHello", "()V"); + ByteCodeCommand [] cmds = sayHelloMethod.getCmds(); + + assertOpCodeEquals("0: getstatic #28", cmds[0]); + assertOpCodeEquals("3: ldc #34", cmds[1]); + assertOpCodeEquals("5: invokevirtual #36", cmds[2]); + assertOpCodeEquals("8: return", cmds[3]); + + } + + { + Method mainMethod = this.clzFile.getMainMethod(); + + ByteCodeCommand [] cmds = mainMethod.getCmds(); + + assertOpCodeEquals("0: new #1", cmds[0]); + assertOpCodeEquals("3: dup", cmds[1]); + assertOpCodeEquals("4: ldc #43", cmds[2]); + assertOpCodeEquals("6: bipush 29", cmds[3]); + assertOpCodeEquals("8: invokespecial #45", cmds[4]); + assertOpCodeEquals("11: astore_1", cmds[5]); + assertOpCodeEquals("12: aload_1", cmds[6]); + assertOpCodeEquals("13: invokevirtual #47", cmds[7]); + assertOpCodeEquals("16: return", cmds[8]); + } + + } + + private void assertOpCodeEquals(String expected, ByteCodeCommand cmd){ + + String acctual = cmd.getOffset()+": "+cmd.getReadableCodeText(); + + if(cmd instanceof OneOperandCmd){ + if(cmd instanceof BiPushCmd){ + acctual += " " + ((OneOperandCmd)cmd).getOperand(); + } else{ + acctual += " #" + ((OneOperandCmd)cmd).getOperand(); + } + } + if(cmd instanceof TwoOperandCmd){ + acctual += " #" + ((TwoOperandCmd)cmd).getIndex(); + } + Assert.assertEquals(expected, acctual); + } } diff --git a/group24/494800949/src/test/java/com/coding/week6/exprNew/InfixExprTestTest.java b/group24/494800949/src/test/java/com/coding/week6/exprNew/InfixExprTestTest.java new file mode 100644 index 0000000000..9939878611 --- /dev/null +++ b/group24/494800949/src/test/java/com/coding/week6/exprNew/InfixExprTestTest.java @@ -0,0 +1,78 @@ +package com.coding.week6.exprNew; + + +import org.junit.After; +import org.junit.Assert; +import org.junit.Before; +import org.junit.Test; + +/** + * Created by Administrator on 2017/4/16 0016. + */ +public class InfixExprTestTest { + @Before + public void setUp() throws Exception { + } + + @After + public void tearDown() throws Exception { + } + + @Test + public void testEvaluate() { + //InfixExpr expr = new InfixExpr("300*20+12*5-20/4"); + + { + InfixExpr expr = new InfixExpr("2+3*4+5"); + Assert.assertEquals(19.0, expr.evaluate(), 0.001f); + } + { + InfixExpr expr = new InfixExpr("3*20+12*5-40/2"); + Assert.assertEquals(100.0, expr.evaluate(), 0.001f); + } + + { + InfixExpr expr = new InfixExpr("3*20/2"); + Assert.assertEquals(30, expr.evaluate(), 0.001f); + } + + { + InfixExpr expr = new InfixExpr("20/2*3|"); + Assert.assertEquals(30, expr.evaluate(), 0.001f); + } + + { + InfixExpr expr = new InfixExpr("10-30+50"); + Assert.assertEquals(30, expr.evaluate(), 0.001f); + } + + } + + +// @Test +// public void testFillStack() { +// InfixExpr expr = new InfixExpr("10-30+50"); +// expr.fillStack(); +// Assert.assertEquals(expr.printNumberStack(), "50.0,-20.0"); +// Assert.assertEquals(expr.printOperatorStack(), "+"); +// expr = new InfixExpr("3*20+12*5-40/2"); +// expr.fillStack(); +// Assert.assertEquals(expr.printNumberStack(), "2.0,40.0,60.0,60.0"); +// Assert.assertEquals(expr.printOperatorStack(), "/,-,+"); +// expr = new InfixExpr("3*20/2"); +// expr.fillStack(); +// Assert.assertEquals(expr.printNumberStack(), "2.0,60.0"); +// Assert.assertEquals(expr.printOperatorStack(), "/"); +// expr = new InfixExpr("20/2*3"); +// expr.fillStack(); +// Assert.assertEquals(expr.printNumberStack(), "3.0,10.0"); +// Assert.assertEquals(expr.printOperatorStack(), "*"); +// expr = new InfixExpr("10-30+50"); +// expr.fillStack(); +// Assert.assertEquals(expr.printNumberStack(), "50.0,-20.0"); +// Assert.assertEquals(expr.printOperatorStack(), "+"); +// } + + + +} \ No newline at end of file diff --git a/group24/494800949/src/test/java/com/coding/week6/exprNew/TokenParserTest.java b/group24/494800949/src/test/java/com/coding/week6/exprNew/TokenParserTest.java new file mode 100644 index 0000000000..1e202ed615 --- /dev/null +++ b/group24/494800949/src/test/java/com/coding/week6/exprNew/TokenParserTest.java @@ -0,0 +1,18 @@ +package com.coding.week6.exprNew; + +import org.junit.Test; + +import java.util.List; + +/** + * Created by Administrator on 2017/4/22 0022. + */ +public class TokenParserTest { + + @Test + public void testParse() throws Exception { + TokenParser tokenParser = new TokenParser(); + List tokens = tokenParser.parse("3* 20+1 2*5-40/2"); + System.out.println(tokens); + } +} \ No newline at end of file diff --git a/group24/494800949/src/test/java/com/coding/week7/InfixToPostfixTest.java b/group24/494800949/src/test/java/com/coding/week7/InfixToPostfixTest.java new file mode 100644 index 0000000000..54a59316d6 --- /dev/null +++ b/group24/494800949/src/test/java/com/coding/week7/InfixToPostfixTest.java @@ -0,0 +1,34 @@ +package com.coding.week7; + +import com.coding.week6.exprNew.Token; +import org.junit.Assert; +import org.junit.Test; + +import java.util.List; + +/** + * Created by Administrator on 2017/4/23 0023. + */ +public class InfixToPostfixTest { + + @Test + public void testConvert() throws Exception { + { + String expr = "9+(3-1)*3+10/2";//"9 3 1-3*+ 10 2/+" + List tokens = InfixToPostfix.convert(expr); + System.out.println(tokens); + Assert.assertEquals("9", tokens.get(0).toString()); + Assert.assertEquals("3", tokens.get(1).toString()); + Assert.assertEquals("1", tokens.get(2).toString()); + Assert.assertEquals("-", tokens.get(3).toString()); + Assert.assertEquals("3", tokens.get(4).toString()); + Assert.assertEquals("*", tokens.get(5).toString()); + Assert.assertEquals("+", tokens.get(6).toString()); + Assert.assertEquals("10", tokens.get(7).toString()); + Assert.assertEquals("2", tokens.get(8).toString()); + Assert.assertEquals("/", tokens.get(9).toString()); + Assert.assertEquals("+", tokens.get(10).toString()); + } + + } +} \ No newline at end of file diff --git a/group24/494800949/src/test/java/com/coding/week7/PostfixExprTest.java b/group24/494800949/src/test/java/com/coding/week7/PostfixExprTest.java new file mode 100644 index 0000000000..bde078a97e --- /dev/null +++ b/group24/494800949/src/test/java/com/coding/week7/PostfixExprTest.java @@ -0,0 +1,41 @@ +package com.coding.week7; + + + +import org.junit.After; +import org.junit.Assert; +import org.junit.Before; +import org.junit.Test; + + + +public class PostfixExprTest { + + @Before + public void setUp() throws Exception { + } + + @After + public void tearDown() throws Exception { + } + + @Test + public void testEvaluate() { + { + PostfixExpr expr = new PostfixExpr("6 5 2 3 + 8 * + 3 + *"); + Assert.assertEquals(288, expr.evaluate(),0.0f); + } + { + //9+(3-1)*3+10/2 + PostfixExpr expr = new PostfixExpr("9 3 1-3*+ 10 2/+"); + Assert.assertEquals(20, expr.evaluate(),0.0f); + } + + { + //10-2*3+50 + PostfixExpr expr = new PostfixExpr("10 2 3 * - 50 +"); + Assert.assertEquals(54, expr.evaluate(),0.0f); + } + } + +} diff --git a/group24/494800949/src/test/java/com/coding/week7/PrefixExprTest.java b/group24/494800949/src/test/java/com/coding/week7/PrefixExprTest.java new file mode 100644 index 0000000000..bb2061303e --- /dev/null +++ b/group24/494800949/src/test/java/com/coding/week7/PrefixExprTest.java @@ -0,0 +1,45 @@ +package com.coding.week7; + +import org.junit.After; +import org.junit.Assert; +import org.junit.Before; +import org.junit.Test; + + +public class PrefixExprTest { + + @Before + public void setUp() throws Exception { + } + + @After + public void tearDown() throws Exception { + } + + @Test + public void testEvaluate() { + { + // 2*3+4*5 + PrefixExpr expr = new PrefixExpr("+ * 2 3* 4 5"); + Assert.assertEquals(26, expr.evaluate(),0.001f); + } + { + // 4*2 + 6+9*2/3 -8 + PrefixExpr expr = new PrefixExpr("-++6/*2 9 3 * 4 2 8"); + Assert.assertEquals(12, expr.evaluate(),0.001f); + } + { + //(3+4)*5-6 + PrefixExpr expr = new PrefixExpr("- * + 3 4 5 6"); + Assert.assertEquals(29, expr.evaluate(),0.001f); + } + { + //1+((2+3)*4)-5 + PrefixExpr expr = new PrefixExpr("- + 1 * + 2 3 4 5"); + Assert.assertEquals(16, expr.evaluate(),0.001f); + } + + + } + +}