package net.ptnkjke.jbeditor.utils;
import org.apache.bcel.generic.*;
import java.util.ArrayList;
import java.util.Arrays;
/**
* Created by Lopatin on 06.07.2014.
*/
public class JByteParser {
private InstructionList instructions = new InstructionList();
private ArrayList<InstructionHandle> instructionHandleList = new ArrayList<InstructionHandle>();
private ArrayList<BranchStruct> branchStructs = new ArrayList<>();
private ArrayList<SelectStruct> selectStructs = new ArrayList<>();
public InstructionList getInstructions() {
return instructions;
}
public void parse(String code, ConstantPoolGen ccg) {
InstructionList list;
String[] lines = code.split("\n");
String[] wLines = new String[lines.length];
for (int i = 0; i < lines.length; i++) {
String line = lines[i];
String tLine = line;
// Убираем последние и первые пробелы, комментарии
if (line.indexOf("//") != -1) {
tLine = line.substring(0, line.indexOf("//"));
}
tLine = tLine.replaceAll("\\s+$", "").replaceAll("^\\s+", "");
wLines[i] = tLine;
}
int curLine = 0;
int lastLine;
while (wLines.length != curLine) {
lastLine = curLine;
curLine += parseLine(wLines, curLine);
if (lastLine == curLine) {
break;
}
}
// Обработка BranchStructs!
for (BranchStruct branchStruct : branchStructs) {
InstructionHandle instructionHandle = getHandleByPos(branchStruct.label);
branchStruct.instruction.setTarget(instructionHandle);
}
// Обработка TABLESELECT + LOOCKUPSELECT
for (SelectStruct selectStruct : selectStructs) {
InstructionHandle target = getHandleByPos(selectStruct.target);
Select select = selectStruct.instruction;
select.setTarget(target);
int counter = 0;
for (Integer i : selectStruct.instructs) {
InstructionHandle handle = getHandleByPos(i);
select.getTargets()[counter] = handle;
counter++;
}
}
}
public InstructionHandle getHandleByPos(int target) {
int b = 0;
for (InstructionHandle handle : instructionHandleList) {
if (b == target) {
return handle;
}
b += handle.getInstruction().getLength();
}
return null;
}
/**
* Сколько строк обработано
*
* @return
*/
private int parseLine(String[] lines, int numLine) {
String[] _s = lines[numLine].split(" ");
String instructionName = _s[0];
String[] args = Arrays.copyOfRange(_s, 1, _s.length);
InstructionHandle instructionHandle = null;
Instruction instruction = null;
// ARITHMETIC
switch (instructionName) {
case "dadd":
instruction = new DADD();
break;
case "ddiv":
instruction = new DDIV();
break;
case "dmul":
instruction = new DMUL();
break;
case "dneg":
instruction = new DNEG();
break;
case "drem":
instruction = new DREM();
break;
case "dsub":
instruction = new DSUB();
break;
case "fadd":
instruction = new FADD();
break;
case "fdiv":
instruction = new FDIV();
break;
case "fmul":
instruction = new FMUL();
break;
case "fneg":
instruction = new FNEG();
break;
case "frem":
instruction = new FREM();
break;
case "fsub":
instruction = new FSUB();
break;
case "iadd":
instruction = new IADD();
break;
case "iand":
instruction = new IAND();
break;
case "idiv":
instruction = new IDIV();
break;
case "imul":
instruction = new IMUL();
break;
case "ineg":
instruction = new INEG();
break;
case "ior":
instruction = new IOR();
break;
case "irem":
instruction = new IREM();
break;
case "ishl":
instruction = new ISHL();
break;
case "ishr":
instruction = new ISHR();
break;
case "isub":
instruction = new ISUB();
break;
case "iushr":
instruction = new IUSHR();
break;
case "ixor":
instruction = new IXOR();
break;
case "ladd":
instruction = new LADD();
break;
case "land":
instruction = new LAND();
break;
case "ldiv":
instruction = new LDIV();
break;
case "lmul":
instruction = new LMUL();
break;
case "lneg":
instruction = new LNEG();
break;
case "lor":
instruction = new LOR();
break;
case "lrem":
instruction = new LREM();
break;
case "lshl":
instruction = new LSHL();
break;
case "lshr":
instruction = new LSHR();
break;
case "lsub":
instruction = new LSUB();
break;
case "lushr":
instruction = new LUSHR();
break;
case "lxor":
instruction = new LXOR();
break;
}
if (instruction != null) {
instructionHandle = instructions.append((ArithmeticInstruction) instruction);
instructionHandleList.add(instructionHandle);
return 1;
}
// ARRAYINSTRUCTION
switch (instructionName) {
case "aaload":
instruction = new AALOAD();
break;
case "aastore":
instruction = new AASTORE();
break;
case "baload":
instruction = new BALOAD();
break;
case "bastore":
instruction = new BASTORE();
break;
case "caload":
instruction = new CALOAD();
break;
case "castore":
instruction = new CASTORE();
break;
case "daload":
instruction = new DALOAD();
break;
case "dastore":
instruction = new DASTORE();
break;
case "faload":
instruction = new FALOAD();
break;
case "fastore":
instruction = new FASTORE();
break;
case "iaload":
instruction = new IALOAD();
break;
case "iastore":
instruction = new IASTORE();
break;
case "laload":
instruction = new LALOAD();
break;
case "lastore":
instruction = new LASTORE();
break;
case "saload":
instruction = new SALOAD();
break;
case "sastore":
instruction = new SASTORE();
break;
}
if (instruction != null) {
instructionHandle = instructions.append((ArrayInstruction) instruction);
instructionHandleList.add(instructionHandle);
return 1;
}
// BRANCHINSTRUCTION
switch (instructionName) {
case "goto":
instruction = new GOTO(null);
break;
case "goto_w":
instruction = new GOTO_W(null);
break;
case "if_acmpeq":
instruction = new IF_ACMPEQ(null);
break;
case "if_acmne":
instruction = new IF_ACMPNE(null);
break;
case "if_icmpeq":
instruction = new IF_ICMPEQ(null);
break;
case "if_icmpge":
instruction = new IF_ICMPGE(null);
break;
case "if_icmpgt":
instruction = new IF_ICMPGT(null);
break;
case "if_icmple":
instruction = new IF_ICMPLE(null);
break;
case "if_icmplt":
instruction = new IF_ICMPLT(null);
break;
case "if_icmpne":
instruction = new IF_ICMPNE(null);
break;
case "ifeq":
instruction = new IFEQ(null);
break;
case "ifge":
instruction = new IFGE(null);
break;
case "ifgt":
instruction = new IFGT(null);
break;
case "ifle":
instruction = new IFLE(null);
break;
case "iflt":
instruction = new IFLT(null);
break;
case "ifne":
instruction = new IFNE(null);
break;
case "ifnonnull":
instruction = new IFNONNULL(null);
break;
case "ifnull":
instruction = new IFNULL(null);
break;
case "jsr":
instruction = new JSR(null);
break;
case "jsr_w":
instruction = new JSR_W(null);
break;
}
if (instruction != null) {
instructionHandle = instructions.append((BranchInstruction) instruction);
instructionHandleList.add(instructionHandle);
branchStructs.add(new BranchStruct((BranchInstruction) instruction, Integer.parseInt(args[0])));
return 1;
}
switch (instructionName) {
case "tableswitch":
int size = Integer.parseInt(args[0]);
int[] match = new int[size];
InstructionHandle[] targets = new InstructionHandle[size];
InstructionHandle defaultTarget = null;
instruction = new TABLESWITCH(match, targets, defaultTarget);
instructionHandle = instructions.append((TABLESWITCH) instruction);
instructionHandleList.add(instructionHandle);
int counter = 0;
int[] instructions_arr = new int[size];
for (int c = numLine + 1; c < numLine + 1 + size; c++) {
String tLine = lines[c];
String[] subs = tLine.split(":");
match[counter] = Integer.parseInt(subs[0].replaceAll(" ", ""));
instructions_arr[counter] = Integer.parseInt(subs[1].replaceAll(" ", ""));
counter++;
}
String def_string = lines[numLine + 1 + size];
String[] def_subs = def_string.split(":");
int target = Integer.parseInt(def_subs[1].replaceAll(" ", ""));
selectStructs.add(new SelectStruct((TABLESWITCH) instruction, instructions_arr, target));
return 1 + size + 1;
case "lookupswitch":
size = Integer.parseInt(args[0]);
match = new int[size];
targets = new InstructionHandle[size];
defaultTarget = null;
instruction = new LOOKUPSWITCH(match, targets, defaultTarget);
instructionHandle = instructions.append((LOOKUPSWITCH) instruction);
instructionHandleList.add(instructionHandle);
counter = 0;
instructions_arr = new int[size];
for (int c = numLine + 1; c < numLine + 1 + size; c++) {
String tLine = lines[c];
String[] subs = tLine.split(":");
match[counter] = Integer.parseInt(subs[0].replaceAll(" ", ""));
instructions_arr[counter] = Integer.parseInt(subs[1].replaceAll(" ", ""));
counter++;
}
def_string = lines[numLine + 1 + size];
def_subs = def_string.split(":");
target = Integer.parseInt(def_subs[1].replaceAll(" ", ""));
selectStructs.add(new SelectStruct((LOOKUPSWITCH) instruction, instructions_arr, target));
return 1 + size + 1;
}
// CONVERSIONINTRUCTION
switch (instructionName) {
case "d2i":
instruction = new D2I();
break;
case "f2i":
instruction = new F2I();
break;
case "l2i":
instruction = new L2I();
break;
case "d2f":
instruction = new D2F();
break;
case "i2f":
instruction = new I2F();
break;
case "l2f":
instruction = new L2F();
break;
case "d2l":
instruction = new D2L();
break;
case "f2l":
instruction = new F2L();
break;
case "i2l":
instruction = new I2L();
break;
case "f2d":
instruction = new F2D();
break;
case "i2d":
instruction = new I2D();
break;
case "l2d":
instruction = new L2D();
break;
case "i2b":
instruction = new I2B();
break;
case "i2c":
instruction = new I2C();
break;
case "i2s":
instruction = new I2S();
break;
}
if (instruction != null) {
instructionHandle = instructions.append((ConversionInstruction) instruction);
instructionHandleList.add(instructionHandle);
return 1;
}
// CPINSTRUCTION
int n;
switch (instructionName) {
case "anewarray":
n = Integer.parseInt(args[0]);
instruction = new ANEWARRAY(n);
break;
case "checkcast":
n = Integer.parseInt(args[0]);
instruction = new CHECKCAST(n);
break;
case "instanceof":
n = Integer.parseInt(args[0]);
instruction = new INSTANCEOF(n);
break;
case "ldc":
n = Integer.parseInt(args[0]);
instruction = new LDC(n);
break;
case "ldc2_w":
n = Integer.parseInt(args[0]);
instruction = new LDC2_W(n);
n = Integer.parseInt(args[0]);
break;
case "multianewarray":
n = Integer.parseInt(args[0]);
Short sh = Short.parseShort(args[1]);
instruction = new MULTIANEWARRAY(n, sh);
break;
case "getfield":
n = Integer.parseInt(args[0]);
instruction = new GETFIELD(n);
break;
case "getstatic":
n = Integer.parseInt(args[0]);
instruction = new GETSTATIC(n);
break;
case "putstatic":
n = Integer.parseInt(args[0]);
instruction = new PUTSTATIC(n);
break;
case "invokeinterface":
n = Integer.parseInt(args[0]);
int nargs = Integer.parseInt(args[1]);
instruction = new INVOKEINTERFACE(n, nargs);
break;
case "invokestatic":
n = Integer.parseInt(args[0]);
instruction = new INVOKESTATIC(n);
break;
case "invokevirtual":
n = Integer.parseInt(args[0]);
instruction = new INVOKEVIRTUAL(n);
break;
case "putfield":
n = Integer.parseInt(args[0]);
instruction = new PUTFIELD(n);
break;
case "invokedynamic":
n = Integer.parseInt(args[0]);
int index = Integer.parseInt(args[1]);
instruction = new INVOKEDYNAMIC((short) n, index);
break;
case "invokespecial":
n = Integer.parseInt(args[0]);
instruction = new INVOKESPECIAL(n);
break;
case "new":
n = Integer.parseInt(args[0]);
instruction = new NEW(n);
break;
}
if (instruction != null) {
instructionHandle = instructions.append((CPInstruction) instruction);
instructionHandleList.add(instructionHandle);
return 1;
}
// LOCALVARIABLEINSTRUCTION
int num;
switch (instructionName) {
case "aload":
num = Integer.parseInt(args[0]);
instruction = new ALOAD(num);
break;
case "aload_0":
instruction = new ALOAD(0);
break;
case "aload_1":
instruction = new ALOAD(1);
break;
case "aload_2":
instruction = new ALOAD(2);
break;
case "aload_3":
instruction = new ALOAD(3);
break;
case "dload":
num = Integer.parseInt(args[0]);
instruction = new DLOAD(num);
break;
case "dload_0":
instruction = new DLOAD(0);
break;
case "dload_1":
instruction = new DLOAD(1);
break;
case "dload_2":
instruction = new DLOAD(2);
break;
case "dload_3":
instruction = new DLOAD(3);
break;
case "fload":
num = Integer.parseInt(args[0]);
instruction = new FLOAD(num);
break;
case "fload_0":
instruction = new FLOAD(0);
break;
case "fload_1":
instruction = new FLOAD(1);
break;
case "fload_2":
instruction = new FLOAD(2);
break;
case "fload_3":
instruction = new FLOAD(3);
break;
case "iload":
num = Integer.parseInt(args[0]);
instruction = new ILOAD(num);
break;
case "iload_0":
instruction = new ILOAD(0);
break;
case "iload_1":
instruction = new ILOAD(1);
break;
case "iload_2":
instruction = new ILOAD(2);
break;
case "iload_3":
instruction = new ILOAD(3);
break;
case "lload":
num = Integer.parseInt(args[0]);
instruction = new LLOAD(num);
break;
case "lload_0":
instruction = new LLOAD(0);
break;
case "lload_1":
instruction = new LLOAD(1);
break;
case "lload_2":
instruction = new LLOAD(2);
break;
case "lload_3":
instruction = new LLOAD(3);
break;
case "astore":
num = Integer.parseInt(args[0]);
instruction = new ASTORE(num);
break;
case "astore_0":
instruction = new ASTORE(0);
break;
case "astore_1":
instruction = new ASTORE(1);
break;
case "astore_2":
instruction = new ASTORE(2);
break;
case "astore_3":
instruction = new ASTORE(3);
break;
case "dstore":
num = Integer.parseInt(args[0]);
instruction = new ASTORE(num);
break;
case "dstore_0":
instruction = new DSTORE(0);
break;
case "dstore_1":
instruction = new DSTORE(1);
break;
case "dstore_2":
instruction = new DSTORE(2);
break;
case "dstore_3":
instruction = new DSTORE(3);
break;
case "fstore":
num = Integer.parseInt(args[0]);
instruction = new FSTORE(num);
break;
case "fstore_0":
instruction = new FSTORE(0);
break;
case "fstore_1":
instruction = new FSTORE(1);
break;
case "fstore_2":
instruction = new FSTORE(2);
break;
case "fstore_3":
instruction = new FSTORE(3);
break;
case "istore":
num = Integer.parseInt(args[0]);
instruction = new ISTORE(num);
break;
case "istore_0":
instruction = new ISTORE(0);
break;
case "istore_1":
instruction = new ISTORE(1);
break;
case "istore_2":
instruction = new ISTORE(2);
break;
case "istore_3":
instruction = new ISTORE(3);
break;
case "lstore":
num = Integer.parseInt(args[0]);
instruction = new LSTORE(num);
break;
case "lstore_0":
instruction = new LSTORE(0);
break;
case "lstore_1":
instruction = new LSTORE(1);
break;
case "lstore_2":
instruction = new LSTORE(2);
break;
case "lstore_3":
instruction = new LSTORE(3);
break;
case "iinc":
num = Integer.parseInt(args[0]);
int num2 = Integer.parseInt(args[1]);
instruction = new IINC(num, num2);
break;
}
if (instruction != null) {
instructionHandle = instructions.append((LocalVariableInstruction) instruction);
instructionHandleList.add(instructionHandle);
return 1;
}
// RETURNINSTRUCTION
switch (instructionName) {
case "areturn":
instruction = new ARETURN();
break;
case "dreturn":
instruction = new DRETURN();
break;
case "freturn":
instruction = new FRETURN();
break;
case "ireturn":
instruction = new IRETURN();
break;
case "lreturn":
instruction = new LRETURN();
break;
case "return":
instruction = new RETURN();
break;
}
if (instruction != null) {
instructionHandle = instructions.append((ReturnInstruction) instruction);
instructionHandleList.add(instructionHandle);
return 1;
}
// STACKINSTRUCTION
switch (instructionName) {
case "dup":
instruction = new DUP();
break;
case "dup2":
instruction = new DUP2();
break;
case "dup_x1":
instruction = new DUP_X1();
break;
case "dup_x2":
instruction = new DUP_X2();
break;
case "dup2_x1":
instruction = new DUP2_X1();
break;
case "dup2_x2":
instruction = new DUP2_X2();
break;
case "pop":
instruction = new POP();
break;
case "pop2":
instruction = new POP2();
break;
case "swap":
instruction = new SWAP();
break;
}
if (instruction != null) {
instructionHandle = instructions.append((StackInstruction) instruction);
instructionHandleList.add(instructionHandle);
return 1;
}
// OTHERINSTRUCTION
switch (instructionName) {
case "aconst_null":
instruction = new ACONST_NULL();
break;
case "arraylength":
instruction = new ARRAYLENGTH();
break;
case "athrow":
instruction = new ATHROW();
break;
case "breakpoint":
instruction = new BREAKPOINT();
break;
case "dcmpg":
instruction = new DCMPG();
break;
case "dconst_0":
instruction = new DCONST(0);
break;
case "dconst_1":
instruction = new DCONST(1);
break;
case "fcmpg":
instruction = new FCMPG();
break;
case "fcmpl":
instruction = new FCMPL();
break;
case "fconst_0":
instruction = new FCONST(0);
break;
case "fconst_1":
instruction = new FCONST(1);
break;
case "fconst_2":
instruction = new FCONST(2);
break;
case "iconst_m1":
instruction = new ICONST(-1);
break;
case "iconst_0":
instruction = new ICONST(0);
break;
case "iconst_1":
instruction = new ICONST(1);
break;
case "iconst_2":
instruction = new ICONST(2);
break;
case "iconst_3":
instruction = new ICONST(3);
break;
case "iconst_4":
instruction = new ICONST(4);
break;
case "iconst_5":
instruction = new ICONST(5);
break;
case "impdep1":
instruction = new IMPDEP1();
break;
case "impdep2":
instruction = new IMPDEP2();
break;
case "lcmp":
instruction = new LCMP();
break;
case "lconst_0":
instruction = new LCONST(0);
case "lconst_1":
instruction = new LCONST(1);
break;
case "monitorenter":
instruction = new MONITORENTER();
break;
case "monitorexit":
instruction = new MONITOREXIT();
break;
case "newarray":
Byte b = Byte.parseByte(args[0]);
instruction = new NEWARRAY(b);
break;
case "nop":
instruction = new NOP();
break;
case "ret":
Integer integer = Integer.parseInt(args[0]);
instruction = new RET(integer);
break;
case "sipush":
Short sh = Short.parseShort(args[0]);
instruction = new SIPUSH(sh);
break;
case "bipush":
Byte byt = Byte.parseByte(args[0]);
instruction = new BIPUSH(byt);
break;
}
if (instruction != null) {
instructionHandle = instructions.append(instruction);
instructionHandleList.add(instructionHandle);
return 1;
}
try {
throw new Exception("");
} catch (Exception e) {
e.printStackTrace();
}
return 0;
}
private class BranchStruct {
BranchInstruction instruction;
int label;
BranchStruct(BranchInstruction instruction, int label) {
this.instruction = instruction;
this.label = label;
}
}
private class SelectStruct {
Select instruction;
int[] instructs;
int target;
SelectStruct(Select instruction, int[] instructs, int target) {
this.instruction = instruction;
this.instructs = instructs;
this.target = target;
}
}
}