package com.github.wdn.coding2017.jvm.cmd;
import com.github.wdn.coding2017.jvm.clz.ClassFile;
import java.util.ArrayList;
import java.util.List;
/**
* Created by Administrator on 2017/4/21 0021.
*/
public class CommandParser {
public static final String nop = "00";
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) {
List<ByteCodeCommand> cmdList = new ArrayList<>();
CommandIterator commandIterator = new CommandIterator(codes);
while (commandIterator.hasNext()) {
String cmdCode = commandIterator.read2ToString();
cmdCode = cmdCode.toUpperCase();
if (cmdCode.equals(new_object)) {
NewObjectCmd cmd = new NewObjectCmd(clzFile, cmdCode);
cmd.setOprand1(commandIterator.read2ToInt());
cmd.setOprand2(commandIterator.read2ToInt());
cmdList.add(cmd);
}else if (cmdCode.equals(invokespecial)) {
InvokeSpecialCmd cmd = new InvokeSpecialCmd(clzFile,cmdCode);
cmd.setOprand1(commandIterator.read2ToInt());
cmd.setOprand2(commandIterator.read2ToInt());
cmdList.add(cmd);
} else if (getstatic.equals(cmdCode)) {
GetStaticFieldCmd cmd = new GetStaticFieldCmd(clzFile, cmdCode);
cmd.setOprand1(commandIterator.read2ToInt());
cmd.setOprand2(commandIterator.read2ToInt());
cmdList.add(cmd);
} else if (putfield.equals(cmdCode)) {
PutFieldCmd cmd = new PutFieldCmd(clzFile, cmdCode);
cmd.setOprand1(commandIterator.read2ToInt());
cmd.setOprand2(commandIterator.read2ToInt());
cmdList.add(cmd);
} else if (ldc.equals(cmdCode)) {
LdcCmd cmd = new LdcCmd(clzFile, cmdCode);
cmd.setOperand(commandIterator.read2ToInt());
cmdList.add(cmd);
} else if (bipush.equals(cmdCode)) {
BiPushCmd cmd = new BiPushCmd(clzFile, cmdCode);
cmd.setOperand(commandIterator.read2ToInt());
cmdList.add(cmd);
} else if (invokevirtual.equals(cmdCode)) {
InvokeVirtualCmd cmd = new InvokeVirtualCmd(clzFile, cmdCode);
cmd.setOprand1(commandIterator.read2ToInt());
cmd.setOprand2(commandIterator.read2ToInt());
cmdList.add(cmd);
}else if (dup.equals(cmdCode) || aload_0.equals(cmdCode) || aload_1.equals(cmdCode) || aload_2.equals(cmdCode)
|| iload_1.equals(cmdCode) || iload_2.equals(cmdCode) || iload_3.equals(cmdCode)
|| fload_3.equals(cmdCode) || voidreturn.equals(cmdCode) || astore_1.equals(cmdCode)) {
NoOperandCmd cmd = new NoOperandCmd(clzFile, cmdCode);
cmdList.add(cmd);
}else{
throw new RuntimeException("未知的指令类型:"+cmdCode);
}
}
calcuateOffset(cmdList);
ByteCodeCommand[] result = new ByteCodeCommand[cmdList.size()];
cmdList.toArray(result);
return result;
}
private static void calcuateOffset(List<ByteCodeCommand> cmds) {
int offset = 0;
for (ByteCodeCommand cmd : cmds) {
cmd.setOffset(offset);
offset += cmd.getLength();
}
}
private static class CommandIterator{
private String codes;
int offset = 0;
public CommandIterator(String codes){
this.codes = codes;
}
public boolean hasNext(){
return offset < codes.length();
}
public int read2ToInt(){
String s = this.read2ToString();
return Integer.valueOf(s, 16).intValue();
}
public String read2ToString(){
String result = codes.substring(offset,offset+2);
offset+=2;
return result;
}
}
}