diff --git a/group19/527220084/xukai_coding/coding-common/src/main/java/org/xukai/coderising/stack/InfixExpr.java b/group19/527220084/xukai_coding/coding-common/src/main/java/org/xukai/coderising/stack/InfixExpr.java index bec5202645..b285a214b8 100644 --- a/group19/527220084/xukai_coding/coding-common/src/main/java/org/xukai/coderising/stack/InfixExpr.java +++ b/group19/527220084/xukai_coding/coding-common/src/main/java/org/xukai/coderising/stack/InfixExpr.java @@ -1,137 +1,76 @@ package org.xukai.coderising.stack; -import com.google.common.collect.Maps; -import com.sun.org.apache.bcel.internal.generic.IFNE; +import java.util.List; +import java.util.Stack; -import java.util.HashMap; public class InfixExpr { - - public static enum TypeToken { - - add('+',0),substruct('-',1),devide('/',3),plus('*',2); - - TypeToken(char token, Integer priority) { - this.token = token; - this.priority = priority; - } - - private char token; - - private Integer priority; - } - String expr = null; public InfixExpr(String expr) { this.expr = expr; } -//3*20+12*5-40/2 - public Double evaluate() { - HashMap map = new HashMap<>(); - map.put("+",0); - map.put("-",1); - map.put("/",3); - map.put("*",2); - - - Stack tokenStack = new Stack(); - Stack numStack = new Stack(); - char[] chars = expr.toCharArray(); - boolean isNem = true; - for (int i = 0; i < expr.length(); i++) { -// if (expr.charAt(i) == TypeToken.add.token || expr.charAt(i) == TypeToken.substruct.token) { -// isNem = true; -// if (!tokenStack.isEmpty() && (char)tokenStack.pop() == '*') { -// Float num2 = Float.valueOf(numStack.pop().toString()); -// Float num1 = Float.valueOf(numStack.pop().toString()); -// numStack.push(num1*num2); -// } else if (!tokenStack.isEmpty() && ((char)tokenStack.pop()) == '/') { -// Float num2 = Float.valueOf(numStack.pop().toString()); -// Float num1 = Float.valueOf(numStack.pop().toString()); -// numStack.push(num1/num2); -// } -// tokenStack.push(expr.charAt(i)); -// } else if (expr.charAt(i) == TypeToken.devide.token){ -// isNem = true; -// tokenStack.push(expr.charAt(i)); -// } else if (expr.charAt(i) == TypeToken.plus.token){ -// isNem = true; -// tokenStack.push(expr.charAt(i)); -// } else if (String.valueOf(expr.charAt(i)).matches("\\d{1}")){ -// if (isNem) { -// numStack.push((expr.charAt(i))); -// } else { -// numStack.push(numStack.pop().toString() + (expr.charAt(i))); -// } -// isNem = false; -// -// } else { -// throw new RuntimeException(); -// } - String token = (expr.charAt(i)) + ""; - Integer priprity = map.get(token); - if (priprity != null) { - //表示是运算符 - if (!tokenStack.isEmpty() && priprity < map.get(tokenStack.peek())) { - Float num2 = Float.valueOf(numStack.pop().toString()); - Float num1 = Float.valueOf(numStack.pop().toString()); - String pop = tokenStack.pop()+""; - if (pop.equals("-")) { - numStack.push(num1 - num2); - } else if (pop.equals("*")){ - numStack.push(num1 * num2); - } else if (pop.equals("/")){ - numStack.push(num1 / num2); - } else { - throw new RuntimeException(); + public float evaluate() { + + + TokenParser parser = new TokenParser(); + List tokens = parser.parse(this.expr); + + + Stack opStack = new Stack<>(); + Stack numStack = new Stack<>(); + + for(Token token : tokens){ + + if (token.isOperator()){ + + if(opStack.isEmpty()){ + + opStack.push(token); + } else{ + + while(!opStack.isEmpty() + && !token.hasHigherPriority(opStack.peek())){ + Token prevOperator = opStack.pop(); + Float f2 = numStack.pop(); + Float f1 = numStack.pop(); + Float result = calculate(prevOperator.toString(), f1,f2); + numStack.push(result); + } - - } - tokenStack.push(token); - isNem = true; - } else if(token.matches("\\d{1}")) { - //表示是数字 - if (isNem) { - numStack.push(token); - } else { - numStack.push(numStack.pop().toString() + token); + opStack.push(token); } - isNem = false; - } else { - throw new RuntimeException(); + } + if(token.isNumber()){ + numStack.push(new Float(token.getIntValue())); } } - while (!tokenStack.isEmpty()) { - System.out.println(tokenStack.size()); - if (tokenStack.peek().equals("+")) { - Float num2 = Float.valueOf(numStack.pop().toString()); - Float num1 = Float.valueOf(numStack.pop().toString()); - numStack.push(num1+num2+""); - } else if (tokenStack.peek().equals("-")) { - Float num2 = Float.valueOf(numStack.pop().toString()); - Float num1 = Float.valueOf(numStack.pop().toString()); - numStack.push(num1-num2+""); - } else if (tokenStack.peek().equals("/")) { - Float num2 = Float.valueOf(numStack.pop().toString()); - Float num1 = Float.valueOf(numStack.pop().toString()); - numStack.push(num1/num2+""); - } else if (tokenStack.peek().equals("*")) { - Float num2 = Float.valueOf(numStack.pop().toString()); - Float num1 = Float.valueOf(numStack.pop().toString()); - numStack.push(num1*num2+""); - } else { - throw new RuntimeException(); - } - tokenStack.pop(); + + while(!opStack.isEmpty()){ + Token token = opStack.pop(); + Float f2 = numStack.pop(); + Float f1 = numStack.pop(); + numStack.push(calculate(token.toString(), f1,f2)); } -// System.out.println(Double.valueOf(numStack.pop().toString())); - return Double.valueOf(numStack.pop().toString()); + + + return numStack.pop().floatValue(); } - - public static void main(String[] args) { - + private Float calculate(String op, Float f1, Float f2){ + if(op.equals("+")){ + return f1+f2; + } + if(op.equals("-")){ + return f1-f2; + } + if(op.equals("*")){ + return f1*f2; + } + if(op.equals("/")){ + return f1/f2; + } + throw new RuntimeException(op + " is not supported"); } diff --git a/group19/527220084/xukai_coding/coding-common/src/main/java/org/xukai/coderising/stack/InfixExpr2.java b/group19/527220084/xukai_coding/coding-common/src/main/java/org/xukai/coderising/stack/InfixExpr2.java new file mode 100644 index 0000000000..00302fa05c --- /dev/null +++ b/group19/527220084/xukai_coding/coding-common/src/main/java/org/xukai/coderising/stack/InfixExpr2.java @@ -0,0 +1,104 @@ +package org.xukai.coderising.stack; + +import java.util.HashMap; + +public class InfixExpr2 { + + public static enum TypeToken { + + add('+',0),substruct('-',1),devide('/',3),plus('*',2); + + TypeToken(char token, Integer priority) { + this.token = token; + this.priority = priority; + } + + private char token; + + private Integer priority; + } + + String expr = null; + + public InfixExpr2(String expr) { + this.expr = expr; + } +//3*20+12*5-40/2 + public Double evaluate() { + HashMap map = new HashMap<>(); + map.put("+",0); + map.put("-",1); + map.put("/",3); + map.put("*",2); + + + Stack tokenStack = new Stack(); + Stack numStack = new Stack(); + char[] chars = expr.toCharArray(); + boolean isNem = true; + for (int i = 0; i < expr.length(); i++) { + String token = (expr.charAt(i)) + ""; + Integer priprity = map.get(token); + if (priprity != null) { + //表示是运算符 + if (!tokenStack.isEmpty() && priprity < map.get(tokenStack.peek())) { + Float num2 = Float.valueOf(numStack.pop().toString()); + Float num1 = Float.valueOf(numStack.pop().toString()); + String pop = tokenStack.pop()+""; + if (pop.equals("-")) { + numStack.push(num1 - num2); + } else if (pop.equals("*")){ + numStack.push(num1 * num2); + } else if (pop.equals("/")){ + numStack.push(num1 / num2); + } else { + throw new RuntimeException(); + } + + } + tokenStack.push(token); + isNem = true; + } else if(token.matches("\\d{1}")) { + //表示是数字 + if (isNem) { + numStack.push(token); + } else { + numStack.push(numStack.pop().toString() + token); + } + isNem = false; + } else { + throw new RuntimeException(); + } + } + while (!tokenStack.isEmpty()) { + System.out.println(tokenStack.size()); + if (tokenStack.peek().equals("+")) { + Float num2 = Float.valueOf(numStack.pop().toString()); + Float num1 = Float.valueOf(numStack.pop().toString()); + numStack.push(num1+num2+""); + } else if (tokenStack.peek().equals("-")) { + Float num2 = Float.valueOf(numStack.pop().toString()); + Float num1 = Float.valueOf(numStack.pop().toString()); + numStack.push(num1-num2+""); + } else if (tokenStack.peek().equals("/")) { + Float num2 = Float.valueOf(numStack.pop().toString()); + Float num1 = Float.valueOf(numStack.pop().toString()); + numStack.push(num1/num2+""); + } else if (tokenStack.peek().equals("*")) { + Float num2 = Float.valueOf(numStack.pop().toString()); + Float num1 = Float.valueOf(numStack.pop().toString()); + numStack.push(num1*num2+""); + } else { + throw new RuntimeException(); + } + tokenStack.pop(); + } +// System.out.println(Double.valueOf(numStack.pop().toString())); + return Double.valueOf(numStack.pop().toString()); + } + + + + + +} diff --git a/group19/527220084/xukai_coding/coding-common/src/main/java/org/xukai/coderising/stack/InfixToPostfix2.java b/group19/527220084/xukai_coding/coding-common/src/main/java/org/xukai/coderising/stack/InfixToPostfix2.java new file mode 100644 index 0000000000..71a483b29f --- /dev/null +++ b/group19/527220084/xukai_coding/coding-common/src/main/java/org/xukai/coderising/stack/InfixToPostfix2.java @@ -0,0 +1,87 @@ +package org.xukai.coderising.stack; + +import java.util.List; +import java.util.Stack; + +/** + * 将中缀表达式转换为后缀表达式: + 与转换为前缀表达式相似,遵循以下步骤: + (1) 初始化两个栈:运算符栈S1和储存中间结果的栈S2; + (2) 从左至右扫描中缀表达式; + (3) 遇到操作数时,将其压入S2; + (4) 遇到运算符时,比较其与S1栈顶运算符的优先级: + (4-1) 如果S1为空,或栈顶运算符为左括号“(”,则直接将此运算符入栈; + (4-2) 否则,若优先级比栈顶运算符的高,也将运算符压入S1(注意转换为前缀表达式时是优先级较高或相同,而这里则不包括相同的情况); + (4-3) 否则,将S1栈顶的运算符弹出并压入到S2中,再次转到(4-1)与S1中新的栈顶运算符相比较; + (5) 遇到括号时: + (5-1) 如果是左括号“(”,则直接压入S1; + (5-2) 如果是右括号“)”,则依次弹出S1栈顶的运算符,并压入S2,直到遇到左括号为止,此时将这一对括号丢弃; + (6) 重复步骤(2)至(5),直到表达式的最右边; + (7) 将S1中剩余的运算符依次弹出并压入S2; + (8) 依次弹出S2中的元素并输出,结果的逆序即为中缀表达式对应的后缀表达式(转换为前缀表达式时不用逆序)。 + + 例如,将中缀表达式“1+((2+3)×4)-5”转换为后缀表达式的过程如下: + 扫描到的元素 S2(栈底->栈顶) S1 (栈底->栈顶) 说明 + 1 1 空 数字,直接入栈 + + 1 + S1为空,运算符直接入栈 + ( 1 + ( 左括号,直接入栈 + ( 1 + ( ( 同上 + 2 1 2 + ( ( 数字 + + 1 2 + ( ( + S1栈顶为左括号,运算符直接入栈 + 3 1 2 3 + ( ( + 数字 + ) 1 2 3 + + ( 右括号,弹出运算符直至遇到左括号 + × 1 2 3 + + ( × S1栈顶为左括号,运算符直接入栈 + 4 1 2 3 + 4 + ( × 数字 + ) 1 2 3 + 4 × + 右括号,弹出运算符直至遇到左括号 + - 1 2 3 + 4 × + - -与+优先级相同,因此弹出+,再压入- + 5 1 2 3 + 4 × + 5 - 数字 + 到达最右端 1 2 3 + 4 × + 5 - 空 S1中剩余的运算符 + 因此结果为“1 2 3 + 4 × + 5 -”(注意需要逆序输出)。 + * @author xukai + * @desc + * @date 2017-04-22-14:10 + */ +public class InfixToPostfix2 { + + + private static TokenParser tokenParser = new TokenParser(); + + public static String toPostFixExpr(String expr){ + + List tokens = tokenParser.parse(expr); + + Stack s1 = new Stack(); + Stack s2 = new Stack(); + + for (Token token : tokens) { + if (token.isNumber()) { + s2.push(token); + } else { + while (token.isOperator() && !s1.isEmpty()) { + if (!token.hasHigherPriority(s1.peek())) { + s2.push(s1.pop()); + continue; + } + break; + } + s1.push(token); + } + } + while (!s1.isEmpty()) { + s2.push(s1.pop()); + } + StringBuilder stringBuilder = new StringBuilder(); + while (!s2.isEmpty()) { + Token token = s2.pop(); + s1.push(token); + } + while (!s1.isEmpty()) { + Token token = s1.pop(); + stringBuilder.append(token.toString()).append(" "); + } + + return stringBuilder.substring(0,stringBuilder.length() - 1); + } + + +} diff --git a/group19/527220084/xukai_coding/coding-common/src/main/java/org/xukai/coderising/stack/PostfixExpr.java b/group19/527220084/xukai_coding/coding-common/src/main/java/org/xukai/coderising/stack/PostfixExpr.java new file mode 100644 index 0000000000..98e849c4ff --- /dev/null +++ b/group19/527220084/xukai_coding/coding-common/src/main/java/org/xukai/coderising/stack/PostfixExpr.java @@ -0,0 +1,57 @@ +package org.xukai.coderising.stack; + +import java.util.List; +import java.util.Stack; + +/** + * 与前缀表达式类似,只是顺序是从左至右: + 从左至右扫描表达式,遇到数字时,将数字压入堆栈,遇到运算符时,弹出栈顶的两个数,用运算符对它们做相应的计算(次顶元素 op 栈顶元素),并将结果入栈;重复上述过程直到表达式最右端,最后运算得出的值即为表达式的结果。 + 例如后缀表达式“3 4 + 5 × 6 -”: + (1) 从左至右扫描,将3和4压入堆栈; + (2) 遇到+运算符,因此弹出4和3(4为栈顶元素,3为次顶元素,注意与前缀表达式做比较),计算出3+4的值,得7,再将7入栈; + (3) 将5入栈; + (4) 接下来是×运算符,因此弹出5和7,计算出7×5=35,将35入栈; + (5) 将6入栈; + (6) 最后是-运算符,计算出35-6的值,即29,由此得出最终结果。 + */ +public class PostfixExpr { +String expr = null; + + public PostfixExpr(String expr) { + this.expr = expr; + } + + public float evaluate() { + TokenParser parser = new TokenParser(); + List tokens = parser.parse(this.expr); + + + Stack numStack = new Stack<>(); + for(Token token : tokens){ + if(token.isNumber()){ + numStack.push(new Float(token.getIntValue())); + } else{ + Float f2 = numStack.pop(); + Float f1 = numStack.pop(); + numStack.push(calculate(token.toString(),f1,f2)); + } + } + return numStack.pop().floatValue(); + } + + private Float calculate(String op, Float f1, Float f2){ + if(op.equals("+")){ + return f1+f2; + } + if(op.equals("-")){ + return f1-f2; + } + if(op.equals("*")){ + return f1*f2; + } + if(op.equals("/")){ + return f1/f2; + } + throw new RuntimeException(op + " is not supported"); + } +} diff --git a/group19/527220084/xukai_coding/coding-common/src/main/java/org/xukai/coderising/stack/PostfixExprTest.java b/group19/527220084/xukai_coding/coding-common/src/main/java/org/xukai/coderising/stack/PostfixExprTest.java new file mode 100644 index 0000000000..178fc23836 --- /dev/null +++ b/group19/527220084/xukai_coding/coding-common/src/main/java/org/xukai/coderising/stack/PostfixExprTest.java @@ -0,0 +1,47 @@ +package org.xukai.coderising.stack; + + + +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); + } + } + + @Test + public void testTo(){ + String poseExpr = InfixToPostfix2.toPostFixExpr("10-2*3+50"); + System.out.println(poseExpr); + } + +} diff --git a/group19/527220084/xukai_coding/coding-common/src/main/java/org/xukai/coderising/stack/PrefixExpr.java b/group19/527220084/xukai_coding/coding-common/src/main/java/org/xukai/coderising/stack/PrefixExpr.java new file mode 100644 index 0000000000..cab9831ec2 --- /dev/null +++ b/group19/527220084/xukai_coding/coding-common/src/main/java/org/xukai/coderising/stack/PrefixExpr.java @@ -0,0 +1,60 @@ +package org.xukai.coderising.stack; + +import java.util.List; +import java.util.Stack; + +/** + * 从右至左扫描表达式,遇到数字时,将数字压入堆栈,遇到运算符时,弹出栈顶的两个数,用运算符对它们做相应的计算(栈顶元素 op 次顶元素),并将结果入栈;重复上述过程直到表达式最左端,最后运算得出的值即为表达式的结果。 + 例如前缀表达式“- × + 3 4 5 6”: + (1) 从右至左扫描,将6、5、4、3压入堆栈; + (2) 遇到+运算符,因此弹出3和4(3为栈顶元素,4为次顶元素,注意与后缀表达式做比较),计算出3+4的值,得7,再将7入栈; + (3) 接下来是×运算符,因此弹出7和5,计算出7×5=35,将35入栈; + (4) 最后是-运算符,计算出35-6的值,即29,由此得出最终结果。 + 可以看出,用计算机计算前缀表达式的值是很容易的。 + * @author xukai + * @desc + * @date 2017-04-22-13:49 + */ +public class PrefixExpr { + + + private String expr; + + public PrefixExpr(String expr) { + this.expr = expr; + } + + public float evaluate(){ + + TokenParser tokenParser = new TokenParser(); + List tokens = tokenParser.parse(expr); + + Stack numStack = new Stack(); + Stack oprStack = new Stack(); + + for (int i = tokens.size() - 1; i > -1; i--) { + if (tokens.get(i).isNumber()) { + numStack.push(new Float(tokens.get(i).getIntValue())); + } else { + Float num1 = numStack.pop(); + Float num2 = numStack.pop(); + numStack.push(caculate(tokens.get(i).toString(), num1, num2)); + } + } + + return numStack.pop(); + } + + private Float caculate(String oper, Float num1, Float num2){ + if (oper.equals("+")) { + return num1 + num2; + } else if (oper.equals("-")) { + return num1 - num2; + } else if (oper.equals("/")) { + return num1 / num2; + } else if (oper.equals("*")) { + return num1 * num2; + } + throw new RuntimeException("illeagal operation token"); + } +} diff --git a/group19/527220084/xukai_coding/coding-common/src/main/java/org/xukai/coderising/stack/PrefixExprTest.java b/group19/527220084/xukai_coding/coding-common/src/main/java/org/xukai/coderising/stack/PrefixExprTest.java new file mode 100644 index 0000000000..bc0e4b53e4 --- /dev/null +++ b/group19/527220084/xukai_coding/coding-common/src/main/java/org/xukai/coderising/stack/PrefixExprTest.java @@ -0,0 +1,45 @@ +package org.xukai.coderising.stack; + +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); + } + + + } + +} diff --git a/group19/527220084/xukai_coding/coding-common/src/main/java/org/xukai/coderising/stack/Token.java b/group19/527220084/xukai_coding/coding-common/src/main/java/org/xukai/coderising/stack/Token.java new file mode 100644 index 0000000000..e10eabb1f4 --- /dev/null +++ b/group19/527220084/xukai_coding/coding-common/src/main/java/org/xukai/coderising/stack/Token.java @@ -0,0 +1,50 @@ +package org.xukai.coderising.stack; + +import java.util.Arrays; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +class Token { + public static final List OPERATORS = Arrays.asList("+", "-", "*", "/"); + private static final Map priorities = new HashMap<>(); + static { + priorities.put("+", 1); + priorities.put("-", 1); + priorities.put("*", 2); + priorities.put("/", 2); + } + static final int OPERATOR = 1; + static final int NUMBER = 2; + String value; + int type; + 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 int getIntValue() { + return Integer.valueOf(value).intValue(); + } + public String toString(){ + return value; + } + + public boolean hasHigherPriority(Token t){ + if(!this.isOperator() && !t.isOperator()){ + throw new RuntimeException("numbers can't compare priority"); + } + return priorities.get(this.value) - priorities.get(t.value) > 0; + } + + + +} \ No newline at end of file diff --git a/group19/527220084/xukai_coding/coding-common/src/main/java/org/xukai/coderising/stack/TokenParser.java b/group19/527220084/xukai_coding/coding-common/src/main/java/org/xukai/coderising/stack/TokenParser.java new file mode 100644 index 0000000000..03e214bf1b --- /dev/null +++ b/group19/527220084/xukai_coding/coding-common/src/main/java/org/xukai/coderising/stack/TokenParser.java @@ -0,0 +1,57 @@ +package org.xukai.coderising.stack; + +import java.util.ArrayList; +import java.util.List; + +public class TokenParser { + + + public List parse(String expr) { + List tokens = new ArrayList<>(); + + int i = 0; + + while (i < expr.length()) { + + char c = expr.charAt(i); + + if (isOperator(c)) { + + Token t = new Token(Token.OPERATOR, String.valueOf(c)); + tokens.add(t); + i++; + + } else if (Character.isDigit(c)) { + + int nextOperatorIndex = indexOfNextOperator(i, expr); + String value = expr.substring(i, nextOperatorIndex); + Token t = new Token(Token.NUMBER, value); + tokens.add(t); + i = nextOperatorIndex; + + } else{ + System.out.println("char :["+c+"] is not number or operator,ignore"); + i++; + } + + } + return tokens; + } + + private int indexOfNextOperator(int i, String expr) { + + while (Character.isDigit(expr.charAt(i))) { + i++; + if (i == expr.length()) { + break; + } + } + return i; + + } + + private boolean isOperator(char c) { + String sc = String.valueOf(c); + return Token.OPERATORS.contains(sc); + } +} diff --git a/group19/527220084/xukai_coding/coding-common/src/main/java/org/xukai/jvm/attr/CodeAttr.java b/group19/527220084/xukai_coding/coding-common/src/main/java/org/xukai/jvm/attr/CodeAttr.java index d0c8ef4e32..fb08ebc8e2 100644 --- a/group19/527220084/xukai_coding/coding-common/src/main/java/org/xukai/jvm/attr/CodeAttr.java +++ b/group19/527220084/xukai_coding/coding-common/src/main/java/org/xukai/jvm/attr/CodeAttr.java @@ -2,6 +2,8 @@ import org.xukai.jvm.clz.ClassFile; +import org.xukai.jvm.cmd.ByteCodeCommand; +import org.xukai.jvm.cmd.CommandParser; import org.xukai.jvm.loader.ByteCodeIterator; public class CodeAttr extends AttributeInfo { @@ -16,21 +18,23 @@ public String getCode() { return code; } - //private ByteCodeCommand[] cmds ; - //public ByteCodeCommand[] getCmds() { - // return cmds; - //} + 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*/) { + 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) { @@ -48,15 +52,14 @@ public static CodeAttr parse(ClassFile clzFile, ByteCodeIterator iter){ int maxLocals = iter.nextToInt(2); int codeLength = iter.nextToInt(4); String code = iter.nextToString(codeLength); - System.out.println(code); - CodeAttr codeAttr = new CodeAttr(attributeNameIndex, attributeLength, maxStack, maxLocals, codeLength, code); + ByteCodeCommand[] cmds = CommandParser.parse(clzFile, code); + CodeAttr codeAttr = new CodeAttr(attributeNameIndex, attributeLength, maxStack, maxLocals, codeLength, code, cmds); int exceptionTableLength = iter.nextToInt(2); if (exceptionTableLength > 0) { iter.nextToInt(exceptionTableLength); System.out.println("解析exception"); } int subAttributeCount = iter.nextToInt(2); - System.out.println("subAttributeCount" + subAttributeCount); if (subAttributeCount > 0) { for (int i = 0; i < subAttributeCount; i++) { AttributeInfo attributeInfo = AttributeInfo.parseAttribute(iter, clzFile); diff --git a/group19/527220084/xukai_coding/coding-common/src/main/java/org/xukai/jvm/clz/ClassFile.java b/group19/527220084/xukai_coding/coding-common/src/main/java/org/xukai/jvm/clz/ClassFile.java index a2b2dfb515..c8777fea97 100644 --- a/group19/527220084/xukai_coding/coding-common/src/main/java/org/xukai/jvm/clz/ClassFile.java +++ b/group19/527220084/xukai_coding/coding-common/src/main/java/org/xukai/jvm/clz/ClassFile.java @@ -81,13 +81,41 @@ public void print(){ } - 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 m :methods){ + + int nameIndex = m.getNameIndex(); + int descriptionIndex = m.getDescriptorIndex(); + + String name = this.getConstantPool().getUTF8String(nameIndex); + String desc = this.getConstantPool().getUTF8String(descriptionIndex); + if(name.equals(methodName) && desc.equals(paramAndReturnType)){ + return m; + } + } + return null; + } + public Method getMainMethod(){ + for(Method m :methods){ + int nameIndex = m.getNameIndex(); + int descIndex = m.getDescriptorIndex(); + String name = this.getConstantPool().getUTF8String(nameIndex); + String desc = this.getConstantPool().getUTF8String(descIndex); + if(name.equals("main") && desc.equals("([Ljava/lang/String;)V")){ + return m; + } + } + return null; + } } diff --git a/group19/527220084/xukai_coding/coding-common/src/main/java/org/xukai/jvm/cmd/BiPushCmd.java b/group19/527220084/xukai_coding/coding-common/src/main/java/org/xukai/jvm/cmd/BiPushCmd.java new file mode 100644 index 0000000000..bd1eb4bf11 --- /dev/null +++ b/group19/527220084/xukai_coding/coding-common/src/main/java/org/xukai/jvm/cmd/BiPushCmd.java @@ -0,0 +1,22 @@ +package org.xukai.jvm.cmd; + + +import org.xukai.jvm.clz.ClassFile; +import org.xukai.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/group19/527220084/xukai_coding/coding-common/src/main/java/org/xukai/jvm/cmd/ByteCodeCommand.java b/group19/527220084/xukai_coding/coding-common/src/main/java/org/xukai/jvm/cmd/ByteCodeCommand.java new file mode 100644 index 0000000000..edb68e1256 --- /dev/null +++ b/group19/527220084/xukai_coding/coding-common/src/main/java/org/xukai/jvm/cmd/ByteCodeCommand.java @@ -0,0 +1,129 @@ +package org.xukai.jvm.cmd; + + +import org.xukai.jvm.clz.ClassFile; +import org.xukai.jvm.constant.ConstantInfo; +import org.xukai.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/group19/527220084/xukai_coding/coding-common/src/main/java/org/xukai/jvm/cmd/CommandParser.java b/group19/527220084/xukai_coding/coding-common/src/main/java/org/xukai/jvm/cmd/CommandParser.java new file mode 100644 index 0000000000..e44fb1e05f --- /dev/null +++ b/group19/527220084/xukai_coding/coding-common/src/main/java/org/xukai/jvm/cmd/CommandParser.java @@ -0,0 +1,156 @@ +package org.xukai.jvm.cmd; + + +import org.xukai.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) { + + if ((codes == null) || (codes.length() == 0) || (codes.length() % 2) != 0) { + throw new RuntimeException("the orignal code is not correct"); + + } + + codes = codes.toUpperCase(); + + CommandIterator iter = new CommandIterator(codes); + List cmds = new ArrayList(); + + while (iter.hasNext()) { + String opCode = iter.next2CharAsString(); + + if (new_object.equals(opCode)) { + NewObjectCmd cmd = new NewObjectCmd(clzFile, opCode); + + cmd.setOprand1(iter.next2CharAsInt()); + cmd.setOprand2(iter.next2CharAsInt()); + + cmds.add(cmd); + } else if (invokespecial.equals(opCode)) { + InvokeSpecialCmd cmd = new InvokeSpecialCmd(clzFile, opCode); + cmd.setOprand1(iter.next2CharAsInt()); + cmd.setOprand2(iter.next2CharAsInt()); + // System.out.println( cmd.toString(clzFile.getConstPool())); + cmds.add(cmd); + } else if (invokevirtual.equals(opCode)) { + InvokeVirtualCmd cmd = new InvokeVirtualCmd(clzFile, opCode); + cmd.setOprand1(iter.next2CharAsInt()); + cmd.setOprand2(iter.next2CharAsInt()); + + cmds.add(cmd); + } else if (getfield.equals(opCode)) { + GetFieldCmd cmd = new GetFieldCmd(clzFile, opCode); + cmd.setOprand1(iter.next2CharAsInt()); + cmd.setOprand2(iter.next2CharAsInt()); + cmds.add(cmd); + } else if (getstatic.equals(opCode)) { + GetStaticFieldCmd cmd = new GetStaticFieldCmd(clzFile, opCode); + cmd.setOprand1(iter.next2CharAsInt()); + cmd.setOprand2(iter.next2CharAsInt()); + cmds.add(cmd); + } else if (putfield.equals(opCode)) { + PutFieldCmd cmd = new PutFieldCmd(clzFile, opCode); + cmd.setOprand1(iter.next2CharAsInt()); + cmd.setOprand2(iter.next2CharAsInt()); + cmds.add(cmd); + } else if (ldc.equals(opCode)) { + LdcCmd cmd = new LdcCmd(clzFile, opCode); + cmd.setOperand(iter.next2CharAsInt()); + cmds.add(cmd); + } else if (bipush.equals(opCode)) { + BiPushCmd cmd = new BiPushCmd(clzFile, opCode); + cmd.setOperand(iter.next2CharAsInt()); + cmds.add(cmd); + } else if (dup.equals(opCode) || aload_0.equals(opCode) || aload_1.equals(opCode) || aload_2.equals(opCode) + || iload_1.equals(opCode) || iload_2.equals(opCode) || iload_3.equals(opCode) + || fload_3.equals(opCode) || voidreturn.equals(opCode) || astore_1.equals(opCode)) { + + NoOperandCmd cmd = new NoOperandCmd(clzFile, opCode); + cmds.add(cmd); + } else { + throw new RuntimeException("Sorry, the java instruction " + opCode + " has not been implemented"); + } + + } + + calcuateOffset(cmds); + + ByteCodeCommand[] result = new ByteCodeCommand[cmds.size()]; + cmds.toArray(result); + return result; + } + + 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/group19/527220084/xukai_coding/coding-common/src/main/java/org/xukai/jvm/cmd/GetFieldCmd.java b/group19/527220084/xukai_coding/coding-common/src/main/java/org/xukai/jvm/cmd/GetFieldCmd.java new file mode 100644 index 0000000000..faa268b0d2 --- /dev/null +++ b/group19/527220084/xukai_coding/coding-common/src/main/java/org/xukai/jvm/cmd/GetFieldCmd.java @@ -0,0 +1,22 @@ +package org.xukai.jvm.cmd; + + +import org.xukai.jvm.clz.ClassFile; +import org.xukai.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/group19/527220084/xukai_coding/coding-common/src/main/java/org/xukai/jvm/cmd/GetStaticFieldCmd.java b/group19/527220084/xukai_coding/coding-common/src/main/java/org/xukai/jvm/cmd/GetStaticFieldCmd.java new file mode 100644 index 0000000000..4112f7cc56 --- /dev/null +++ b/group19/527220084/xukai_coding/coding-common/src/main/java/org/xukai/jvm/cmd/GetStaticFieldCmd.java @@ -0,0 +1,20 @@ +package org.xukai.jvm.cmd; + + +import org.xukai.jvm.clz.ClassFile; +import org.xukai.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/group19/527220084/xukai_coding/coding-common/src/main/java/org/xukai/jvm/cmd/InvokeSpecialCmd.java b/group19/527220084/xukai_coding/coding-common/src/main/java/org/xukai/jvm/cmd/InvokeSpecialCmd.java new file mode 100644 index 0000000000..7dd0b62407 --- /dev/null +++ b/group19/527220084/xukai_coding/coding-common/src/main/java/org/xukai/jvm/cmd/InvokeSpecialCmd.java @@ -0,0 +1,22 @@ +package org.xukai.jvm.cmd; + + +import org.xukai.jvm.clz.ClassFile; +import org.xukai.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/group19/527220084/xukai_coding/coding-common/src/main/java/org/xukai/jvm/cmd/InvokeVirtualCmd.java b/group19/527220084/xukai_coding/coding-common/src/main/java/org/xukai/jvm/cmd/InvokeVirtualCmd.java new file mode 100644 index 0000000000..77ba5c7460 --- /dev/null +++ b/group19/527220084/xukai_coding/coding-common/src/main/java/org/xukai/jvm/cmd/InvokeVirtualCmd.java @@ -0,0 +1,22 @@ +package org.xukai.jvm.cmd; + + +import org.xukai.jvm.clz.ClassFile; +import org.xukai.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/group19/527220084/xukai_coding/coding-common/src/main/java/org/xukai/jvm/cmd/LdcCmd.java b/group19/527220084/xukai_coding/coding-common/src/main/java/org/xukai/jvm/cmd/LdcCmd.java new file mode 100644 index 0000000000..2d8b1ae2f3 --- /dev/null +++ b/group19/527220084/xukai_coding/coding-common/src/main/java/org/xukai/jvm/cmd/LdcCmd.java @@ -0,0 +1,30 @@ +package org.xukai.jvm.cmd; + + +import org.xukai.jvm.clz.ClassFile; +import org.xukai.jvm.constant.ConstantInfo; +import org.xukai.jvm.constant.ConstantPool; +import org.xukai.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/group19/527220084/xukai_coding/coding-common/src/main/java/org/xukai/jvm/cmd/NewObjectCmd.java b/group19/527220084/xukai_coding/coding-common/src/main/java/org/xukai/jvm/cmd/NewObjectCmd.java new file mode 100644 index 0000000000..0ac1b33832 --- /dev/null +++ b/group19/527220084/xukai_coding/coding-common/src/main/java/org/xukai/jvm/cmd/NewObjectCmd.java @@ -0,0 +1,20 @@ +package org.xukai.jvm.cmd; + + +import org.xukai.jvm.clz.ClassFile; +import org.xukai.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/group19/527220084/xukai_coding/coding-common/src/main/java/org/xukai/jvm/cmd/NoOperandCmd.java b/group19/527220084/xukai_coding/coding-common/src/main/java/org/xukai/jvm/cmd/NoOperandCmd.java new file mode 100644 index 0000000000..63683e3865 --- /dev/null +++ b/group19/527220084/xukai_coding/coding-common/src/main/java/org/xukai/jvm/cmd/NoOperandCmd.java @@ -0,0 +1,24 @@ +package org.xukai.jvm.cmd; + + +import org.xukai.jvm.clz.ClassFile; +import org.xukai.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/group19/527220084/xukai_coding/coding-common/src/main/java/org/xukai/jvm/cmd/OneOperandCmd.java b/group19/527220084/xukai_coding/coding-common/src/main/java/org/xukai/jvm/cmd/OneOperandCmd.java new file mode 100644 index 0000000000..6498b64289 --- /dev/null +++ b/group19/527220084/xukai_coding/coding-common/src/main/java/org/xukai/jvm/cmd/OneOperandCmd.java @@ -0,0 +1,28 @@ +package org.xukai.jvm.cmd; + + +import org.xukai.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/group19/527220084/xukai_coding/coding-common/src/main/java/org/xukai/jvm/cmd/PutFieldCmd.java b/group19/527220084/xukai_coding/coding-common/src/main/java/org/xukai/jvm/cmd/PutFieldCmd.java new file mode 100644 index 0000000000..0a5987e4c3 --- /dev/null +++ b/group19/527220084/xukai_coding/coding-common/src/main/java/org/xukai/jvm/cmd/PutFieldCmd.java @@ -0,0 +1,20 @@ +package org.xukai.jvm.cmd; + + +import org.xukai.jvm.clz.ClassFile; +import org.xukai.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/group19/527220084/xukai_coding/coding-common/src/main/java/org/xukai/jvm/cmd/TwoOperandCmd.java b/group19/527220084/xukai_coding/coding-common/src/main/java/org/xukai/jvm/cmd/TwoOperandCmd.java new file mode 100644 index 0000000000..b423f989ae --- /dev/null +++ b/group19/527220084/xukai_coding/coding-common/src/main/java/org/xukai/jvm/cmd/TwoOperandCmd.java @@ -0,0 +1,67 @@ +package org.xukai.jvm.cmd; + + +import org.xukai.jvm.clz.ClassFile; +import org.xukai.jvm.constant.ClassInfo; +import org.xukai.jvm.constant.ConstantInfo; +import org.xukai.jvm.constant.ConstantPool; +import org.xukai.jvm.constant.FieldRefInfo; +import org.xukai.jvm.constant.MethodRefInfo; + +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/group19/527220084/xukai_coding/coding-common/src/main/java/org/xukai/jvm/constant/ClassInfo.java b/group19/527220084/xukai_coding/coding-common/src/main/java/org/xukai/jvm/constant/ClassInfo.java index bf7171a966..1adde177f3 100644 --- a/group19/527220084/xukai_coding/coding-common/src/main/java/org/xukai/jvm/constant/ClassInfo.java +++ b/group19/527220084/xukai_coding/coding-common/src/main/java/org/xukai/jvm/constant/ClassInfo.java @@ -15,7 +15,12 @@ public void setUtf8Index(int utf8Index) { public int getType() { return type; } - + + @Override + public void accept(Visitor visitor) { + visitor.visitClassInfo(this); + } + public String getClassName() { int index = getUtf8Index(); UTF8Info utf8Info = (UTF8Info)constantPool.getConstantInfo(index); diff --git a/group19/527220084/xukai_coding/coding-common/src/main/java/org/xukai/jvm/constant/ConstantInfo.java b/group19/527220084/xukai_coding/coding-common/src/main/java/org/xukai/jvm/constant/ConstantInfo.java index 24323692e9..ffae0e4e83 100644 --- a/group19/527220084/xukai_coding/coding-common/src/main/java/org/xukai/jvm/constant/ConstantInfo.java +++ b/group19/527220084/xukai_coding/coding-common/src/main/java/org/xukai/jvm/constant/ConstantInfo.java @@ -25,5 +25,24 @@ 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 visitString(StringInfo info); + + public void visitNameAndType(NameAndTypeInfo info); + + public void visitMethodRef(MethodRefInfo info); + + public void visitFieldRef(FieldRefInfo info); + + public void visitClassInfo(ClassInfo info); + + public void visistUTF8(UTF8Info info); + + + } } diff --git a/group19/527220084/xukai_coding/coding-common/src/main/java/org/xukai/jvm/constant/ConstantPool.java b/group19/527220084/xukai_coding/coding-common/src/main/java/org/xukai/jvm/constant/ConstantPool.java index ff4aa4b906..d9cc6f0f56 100644 --- a/group19/527220084/xukai_coding/coding-common/src/main/java/org/xukai/jvm/constant/ConstantPool.java +++ b/group19/527220084/xukai_coding/coding-common/src/main/java/org/xukai/jvm/constant/ConstantPool.java @@ -23,7 +23,7 @@ public ConstantInfo getConstantInfo(int index){ public String getUTF8String(int index){ return ((UTF8Info)this.constantInfos.get(index)).getValue(); } - public Object getSize() { + public int getSize() { return this.constantInfos.size() -1; } } diff --git a/group19/527220084/xukai_coding/coding-common/src/main/java/org/xukai/jvm/constant/FieldRefInfo.java b/group19/527220084/xukai_coding/coding-common/src/main/java/org/xukai/jvm/constant/FieldRefInfo.java index f0b846f47c..d9b5281155 100644 --- a/group19/527220084/xukai_coding/coding-common/src/main/java/org/xukai/jvm/constant/FieldRefInfo.java +++ b/group19/527220084/xukai_coding/coding-common/src/main/java/org/xukai/jvm/constant/FieldRefInfo.java @@ -11,7 +11,12 @@ public FieldRefInfo(ConstantPool pool) { public int getType() { return type; } - + + @Override + public void accept(Visitor visitor) { + visitor.visitFieldRef(this); + } + public int getClassInfoIndex() { return classInfoIndex; } diff --git a/group19/527220084/xukai_coding/coding-common/src/main/java/org/xukai/jvm/constant/MethodRefInfo.java b/group19/527220084/xukai_coding/coding-common/src/main/java/org/xukai/jvm/constant/MethodRefInfo.java index a0c02fedaf..28b80235d9 100644 --- a/group19/527220084/xukai_coding/coding-common/src/main/java/org/xukai/jvm/constant/MethodRefInfo.java +++ b/group19/527220084/xukai_coding/coding-common/src/main/java/org/xukai/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/group19/527220084/xukai_coding/coding-common/src/main/java/org/xukai/jvm/constant/NameAndTypeInfo.java b/group19/527220084/xukai_coding/coding-common/src/main/java/org/xukai/jvm/constant/NameAndTypeInfo.java index c88c848d3a..66d235641d 100644 --- a/group19/527220084/xukai_coding/coding-common/src/main/java/org/xukai/jvm/constant/NameAndTypeInfo.java +++ b/group19/527220084/xukai_coding/coding-common/src/main/java/org/xukai/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/group19/527220084/xukai_coding/coding-common/src/main/java/org/xukai/jvm/constant/NullConstantInfo.java b/group19/527220084/xukai_coding/coding-common/src/main/java/org/xukai/jvm/constant/NullConstantInfo.java index 0aa452b866..732e8a42cf 100644 --- a/group19/527220084/xukai_coding/coding-common/src/main/java/org/xukai/jvm/constant/NullConstantInfo.java +++ b/group19/527220084/xukai_coding/coding-common/src/main/java/org/xukai/jvm/constant/NullConstantInfo.java @@ -9,5 +9,10 @@ public NullConstantInfo(){ public int getType() { return -1; } - + + @Override + public void accept(Visitor visitor) { + + } + } diff --git a/group19/527220084/xukai_coding/coding-common/src/main/java/org/xukai/jvm/constant/StringInfo.java b/group19/527220084/xukai_coding/coding-common/src/main/java/org/xukai/jvm/constant/StringInfo.java index 31a3c52910..0fc28b142c 100644 --- a/group19/527220084/xukai_coding/coding-common/src/main/java/org/xukai/jvm/constant/StringInfo.java +++ b/group19/527220084/xukai_coding/coding-common/src/main/java/org/xukai/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/group19/527220084/xukai_coding/coding-common/src/main/java/org/xukai/jvm/constant/UTF8Info.java b/group19/527220084/xukai_coding/coding-common/src/main/java/org/xukai/jvm/constant/UTF8Info.java index caf1c19918..ae5200371e 100644 --- a/group19/527220084/xukai_coding/coding-common/src/main/java/org/xukai/jvm/constant/UTF8Info.java +++ b/group19/527220084/xukai_coding/coding-common/src/main/java/org/xukai/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/group19/527220084/xukai_coding/coding-common/src/main/java/org/xukai/jvm/method/Method.java b/group19/527220084/xukai_coding/coding-common/src/main/java/org/xukai/jvm/method/Method.java index 6cd71db72c..27585d73b1 100644 --- a/group19/527220084/xukai_coding/coding-common/src/main/java/org/xukai/jvm/method/Method.java +++ b/group19/527220084/xukai_coding/coding-common/src/main/java/org/xukai/jvm/method/Method.java @@ -4,6 +4,7 @@ import org.xukai.jvm.attr.AttributeInfo; import org.xukai.jvm.attr.CodeAttr; import org.xukai.jvm.clz.ClassFile; +import org.xukai.jvm.cmd.ByteCodeCommand; import org.xukai.jvm.constant.UTF8Info; import org.xukai.jvm.loader.ByteCodeIterator; @@ -25,6 +26,7 @@ public ClassFile getClzFile() { public int getNameIndex() { return nameIndex; } + public int getDescriptorIndex() { return descriptorIndex; } @@ -55,6 +57,10 @@ public String getMethodName(){ public String getMethodDescription(){ return ((UTF8Info)clzFile.getConstantPool().getConstantInfo(this.descriptorIndex)).getValue(); } + + public ByteCodeCommand[] getCmds() { + return this.getCodeAttr().getCmds(); + } @@ -77,12 +83,5 @@ public static Method parse(ClassFile clzFile, ByteCodeIterator iter){ } - public static void main(String[] args) { - CodeAttr codeAttr = new CodeAttr(1, 1, 1, 1, 1, ""); - System.out.println(codeAttr instanceof AttributeInfo); - AttributeInfo codeAttr2 = new CodeAttr(1, 1, 1, 1, 1, ""); - System.out.println(codeAttr2 instanceof CodeAttr); - } - } diff --git a/group19/527220084/xukai_coding/coding-common/src/main/java/org/xukai/jvm/print/ClassFilePrinter.java b/group19/527220084/xukai_coding/coding-common/src/main/java/org/xukai/jvm/print/ClassFilePrinter.java new file mode 100644 index 0000000000..4c78dc1796 --- /dev/null +++ b/group19/527220084/xukai_coding/coding-common/src/main/java/org/xukai/jvm/print/ClassFilePrinter.java @@ -0,0 +1,48 @@ +package org.xukai.jvm.print; + + +import org.xukai.jvm.clz.ClassFile; +import org.xukai.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 = "D:\\java\\IDEA-Workspace\\coding2017\\group19\\527220084\\xukai_coding\\coding-common\\target\\classes"; + ClassFileLoader loader = new ClassFileLoader(); + loader.addClassPath(path); + String className = "org.xukai.jvm.test.EmployeeV1"; + + ClassFile clzFile = loader.loadClass(className); + + ClassFilePrinter printer = new ClassFilePrinter(clzFile); + + printer.print(); + } +} diff --git a/group19/527220084/xukai_coding/coding-common/src/main/java/org/xukai/jvm/print/ConstantPoolPrinter.java b/group19/527220084/xukai_coding/coding-common/src/main/java/org/xukai/jvm/print/ConstantPoolPrinter.java new file mode 100644 index 0000000000..b1ec2eda79 --- /dev/null +++ b/group19/527220084/xukai_coding/coding-common/src/main/java/org/xukai/jvm/print/ConstantPoolPrinter.java @@ -0,0 +1,85 @@ +package org.xukai.jvm.print; + + +import org.xukai.jvm.constant.ClassInfo; +import org.xukai.jvm.constant.ConstantInfo; +import org.xukai.jvm.constant.ConstantPool; +import org.xukai.jvm.constant.FieldRefInfo; +import org.xukai.jvm.constant.MethodRefInfo; +import org.xukai.jvm.constant.NameAndTypeInfo; +import org.xukai.jvm.constant.StringInfo; +import org.xukai.jvm.constant.UTF8Info; + +public class ConstantPoolPrinter { + ConstantPool pool; + ConstantPoolPrinter(ConstantPool pool){ + this.pool = pool; + } + public void print(){ + + System.out.println("Constant Pool:"); + + ConstantInfo.Visitor visitor = new ConstantInfo.Visitor() { + + @Override + public void visitString(StringInfo info) { + StringBuilder buffer = new StringBuilder(); + buffer.append("String #").append(info.getIndex()); + System.out.println(buffer); + + } + + @Override + public void visitNameAndType(NameAndTypeInfo info) { + StringBuilder buffer = new StringBuilder(); + buffer.append("NameAndType #").append(info.getIndex1()).append(":#") + .append(info.getIndex2()); + System.out.println(buffer); + + } + + @Override + public void visitMethodRef(MethodRefInfo info) { + StringBuilder buffer = new StringBuilder(); + buffer.append("MethodRef #").append(info.getClassInfoIndex()).append(".#") + .append(info.getNameAndTypeIndex()).append(" ").append(info.getClassName()).append(".").append + (info.getMethodName()).append(info.getParamAndReturnType()); + System.out.println(buffer); + + } + + @Override + public void visitFieldRef(FieldRefInfo info) { + StringBuilder buffer = new StringBuilder(); + buffer.append("FieldRef #").append(info.getClassInfoIndex()).append(".#") + .append(info.getNameAndTypeIndex()); + System.out.println(buffer); + + } + + @Override + public void visitClassInfo(ClassInfo info) { + StringBuilder buffer = new StringBuilder(); + buffer.append("Class #").append(info.getUtf8Index()) + .append(" ").append(info.getClassName()); + + System.out.println(buffer); + + } + + @Override + public void visistUTF8(UTF8Info info) { + StringBuilder buffer = new StringBuilder(); + buffer.append("UTF8 ").append(info.getValue()); + System.out.println(buffer); + + } + }; + + for(int i=1; i <= pool.getSize(); i++){ + ConstantInfo constantInfo = pool.getConstantInfo(i); + System.out.print("#"+i+"="); + constantInfo.accept(visitor); + } + } +} diff --git a/group19/527220084/xukai_coding/coding-common/src/main/java/org/xukai/jvm/test/ClassFileloaderTest.java b/group19/527220084/xukai_coding/coding-common/src/main/java/org/xukai/jvm/test/ClassFileloaderTest.java index c4fad12ff6..08e65bedce 100644 --- a/group19/527220084/xukai_coding/coding-common/src/main/java/org/xukai/jvm/test/ClassFileloaderTest.java +++ b/group19/527220084/xukai_coding/coding-common/src/main/java/org/xukai/jvm/test/ClassFileloaderTest.java @@ -8,6 +8,10 @@ import org.junit.Test; import org.xukai.jvm.clz.ClassFile; import org.xukai.jvm.clz.ClassIndex; +import org.xukai.jvm.cmd.BiPushCmd; +import org.xukai.jvm.cmd.ByteCodeCommand; +import org.xukai.jvm.cmd.OneOperandCmd; +import org.xukai.jvm.cmd.TwoOperandCmd; import org.xukai.jvm.constant.ClassInfo; import org.xukai.jvm.constant.ConstantPool; import org.xukai.jvm.constant.MethodRefInfo; @@ -303,7 +307,82 @@ private void assertMethodEquals(ConstantPool pool,Method m , String expectedName Assert.assertEquals(expectedDesc, methodDesc); Assert.assertEquals(expectedCode, code); } - - + + + @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); + } + + }