public static string BytecodeToInfix(EzSembleContext context, byte[] Bytes) { //string MEOWDEBUG_OLD_DISSEMBLE = MEOWDEBUG_OldDissemble(Bytes); var bigEndianReverseBytes = Bytes.Reverse().ToArray(); Stack <string> stack = new Stack <string>(); Queue <string> garbage = new Queue <string>(); string popLastNonGarbageAndStoreGarbage(bool wantNumber = false) { var popped = stack.Pop(); //while (popped == "~" || popped == ".") //{ // garbage.Enqueue(popped); // popped = stack.Pop(); //} if (wantNumber) { return(popped.Trim('(', ')')); } else { return(popped); } } void restoreGarbage() { while (garbage.Count > 0) { stack.Push(garbage.Dequeue()); } } for (int i = 0; i < Bytes.Length; i++) { var b = Bytes[i]; if (b >= 0 && b <= 0x7F) { stack.Push($"{b - 64}"); } else if (b == 0xA5) { int j = 0; while (Bytes[i + j + 1] != 0 || Bytes[i + j + 2] != 0) { j += 2; } string text = context.IsBigEndian ? Encoding.BigEndianUnicode.GetString(Bytes, i + 1, j) : Encoding.Unicode.GetString(Bytes, i + 1, j); if (text.Contains('"') || text.Contains('\r') || text.Contains('\n')) { throw new Exception("Illegal character in string literal"); } stack.Push($"\"{text}\""); i += j + 2; } else if (b == 0x80) { if (!context.IsBigEndian) { stack.Push($"{BitConverter.ToSingle(Bytes, i + 1)}"); } else { stack.Push($"{BitConverter.ToSingle(bigEndianReverseBytes, (bigEndianReverseBytes.Length - 1) - (i + 1) - 4)}"); } i += 4; } else if (b == 0x81) { if (!context.IsBigEndian) { stack.Push($"{BitConverter.ToDouble(Bytes, i + 1)}"); } else { stack.Push($"{BitConverter.ToDouble(bigEndianReverseBytes, (bigEndianReverseBytes.Length - 1) - (i + 1) - 8)}"); } i += 8; } else if (b == 0x82) { if (!context.IsBigEndian) { stack.Push($"{BitConverter.ToInt32(Bytes, i + 1)}"); } else { stack.Push($"{BitConverter.ToInt32(bigEndianReverseBytes, (bigEndianReverseBytes.Length - 1) - (i + 1) - 4)}"); } i += 4; } else if (b == 0x84) { var id = popLastNonGarbageAndStoreGarbage(true); restoreGarbage(); stack.Push($"{context.GetFunctionInfo(int.Parse(id)).Name}()"); } else if (b == 0x85) { var arg1 = popLastNonGarbageAndStoreGarbage(); var id = popLastNonGarbageAndStoreGarbage(true); restoreGarbage(); stack.Push($"{context.GetFunctionInfo(int.Parse(id)).Name}({arg1})"); } else if (b == 0x86) { var arg2 = popLastNonGarbageAndStoreGarbage(); var arg1 = popLastNonGarbageAndStoreGarbage(); var id = popLastNonGarbageAndStoreGarbage(true); restoreGarbage(); stack.Push($"{context.GetFunctionInfo(int.Parse(id)).Name}({arg1}, {arg2})"); } else if (b == 0x87) { var arg3 = popLastNonGarbageAndStoreGarbage(); var arg2 = popLastNonGarbageAndStoreGarbage(); var arg1 = popLastNonGarbageAndStoreGarbage(); var id = popLastNonGarbageAndStoreGarbage(true); restoreGarbage(); stack.Push($"{context.GetFunctionInfo(int.Parse(id)).Name}({arg1}, {arg2}, {arg3})"); } else if (b == 0x88) { var arg4 = popLastNonGarbageAndStoreGarbage(); var arg3 = popLastNonGarbageAndStoreGarbage(); var arg2 = popLastNonGarbageAndStoreGarbage(); var arg1 = popLastNonGarbageAndStoreGarbage(); var id = popLastNonGarbageAndStoreGarbage(true); restoreGarbage(); stack.Push($"{context.GetFunctionInfo(int.Parse(id)).Name}({arg1}, {arg2}, {arg3}, {arg4})"); } else if (b == 0x89) { var arg5 = popLastNonGarbageAndStoreGarbage(); var arg4 = popLastNonGarbageAndStoreGarbage(); var arg3 = popLastNonGarbageAndStoreGarbage(); var arg2 = popLastNonGarbageAndStoreGarbage(); var arg1 = popLastNonGarbageAndStoreGarbage(); var id = popLastNonGarbageAndStoreGarbage(true); restoreGarbage(); stack.Push($"{context.GetFunctionInfo(int.Parse(id)).Name}({arg1}, {arg2}, {arg3}, {arg4}, {arg5})"); } else if (b == 0x8A) { var arg6 = popLastNonGarbageAndStoreGarbage(); var arg5 = popLastNonGarbageAndStoreGarbage(); var arg4 = popLastNonGarbageAndStoreGarbage(); var arg3 = popLastNonGarbageAndStoreGarbage(); var arg2 = popLastNonGarbageAndStoreGarbage(); var arg1 = popLastNonGarbageAndStoreGarbage(); var id = popLastNonGarbageAndStoreGarbage(true); restoreGarbage(); stack.Push($"{context.GetFunctionInfo(int.Parse(id)).Name}({arg1}, {arg2}, {arg3}, {arg4}, {arg5}, {arg6})"); } else if (OperatorsByByte.ContainsKey(b)) { var item2 = popLastNonGarbageAndStoreGarbage(); var item1 = popLastNonGarbageAndStoreGarbage(); restoreGarbage(); stack.Push($"{GetExpressionWithParenthesesIfContainsOperator(item1, OperatorsByByte[b])} " + $"{OperatorsByByte[b]} {GetExpressionWithParenthesesIfContainsOperator(item2, OperatorsByByte[b])}"); } else if (b == 0xA6) { //if (stack.Count > 2) //{ // var stackContents = new string[stack.Count]; // int j = stack.Count - 1; // while (stack.Count > 0) // { // var latest = stack.Pop(); // stackContents[j] = latest; // j--; // } // stack.Push($"({string.Join(" ", stackContents)})"); // Console.WriteLine("TEST"); //} //else //{ // stack.Push($"({stack.Pop()})"); //} stack.Push($"({stack.Pop()})"); } else if (b >= 0xA7 && b <= 0xAE) { byte regIndex = (byte)(b - 0xA7); var item = popLastNonGarbageAndStoreGarbage(); restoreGarbage(); stack.Push($"SetREG{regIndex}({item})"); } else if (b >= 0xAF && b <= 0xB6) { byte regIndex = (byte)(b - 0xAF); stack.Push($"GetREG{regIndex}()"); } else if (b == 0xB7) { var item = stack.Pop(); stack.Push($"AbortIfFalse({item})"); } else if (b == 0xA1) { //break; } else { stack.Push($"#{b:X2}"); } } return(string.Join(" ", stack)); }
public static Expr BytecodeToInfix(EzSembleContext context, byte[] Bytes) { var bigEndianReverseBytes = Bytes.Reverse().ToArray(); Stack <Expr> exprs = new Stack <Expr>(); List <Expr> popArgs(int amount) { List <Expr> args = new List <Expr>(); for (int i = 0; i < amount; i++) { args.Add(exprs.Pop()); } args.Reverse(); return(args); } for (int i = 0; i < Bytes.Length; i++) { var b = Bytes[i]; if (b >= 0 && b <= 0x7F) { exprs.Push(new ConstExpr { Value = (sbyte)(b - 64) }); } else if (b == 0xA5) { int j = 0; while (Bytes[i + j + 1] != 0 || Bytes[i + j + 2] != 0) { j += 2; } string text = context.IsBigEndian ? Encoding.BigEndianUnicode.GetString(Bytes, i + 1, j) : Encoding.Unicode.GetString(Bytes, i + 1, j); if (text.Contains('"') || text.Contains('\r') || text.Contains('\n')) { throw new Exception("Illegal character in string literal"); } exprs.Push(new ConstExpr { Value = text }); i += j + 2; } else if (b == 0x80) { float val; if (!context.IsBigEndian) { val = BitConverter.ToSingle(Bytes, i + 1); } else { val = BitConverter.ToSingle(bigEndianReverseBytes, (bigEndianReverseBytes.Length - 1) - (i + 1) - 4); } exprs.Push(new ConstExpr { Value = val }); i += 4; } else if (b == 0x81) { double val; if (!context.IsBigEndian) { val = BitConverter.ToDouble(Bytes, i + 1); } else { val = BitConverter.ToDouble(bigEndianReverseBytes, (bigEndianReverseBytes.Length - 1) - (i + 1) - 8); } exprs.Push(new ConstExpr { Value = val }); i += 8; } else if (b == 0x82) { int val; if (!context.IsBigEndian) { val = BitConverter.ToInt32(Bytes, i + 1); } else { val = BitConverter.ToInt32(bigEndianReverseBytes, (bigEndianReverseBytes.Length - 1) - (i + 1) - 4); } exprs.Push(new ConstExpr { Value = val }); i += 4; } else if (b == 0x84) { exprs.Push(new FunctionCall { Args = popArgs(0), Name = context.GetFunctionInfo(exprs.Pop().AsInt()).Name }); } else if (b == 0x85) { exprs.Push(new FunctionCall { Args = popArgs(1), Name = context.GetFunctionInfo(exprs.Pop().AsInt()).Name }); } else if (b == 0x86) { exprs.Push(new FunctionCall { Args = popArgs(2), Name = context.GetFunctionInfo(exprs.Pop().AsInt()).Name }); } else if (b == 0x87) { exprs.Push(new FunctionCall { Args = popArgs(3), Name = context.GetFunctionInfo(exprs.Pop().AsInt()).Name }); } else if (b == 0x88) { exprs.Push(new FunctionCall { Args = popArgs(4), Name = context.GetFunctionInfo(exprs.Pop().AsInt()).Name }); } else if (b == 0x89) { exprs.Push(new FunctionCall { Args = popArgs(5), Name = context.GetFunctionInfo(exprs.Pop().AsInt()).Name }); } else if (b == 0x8A) { exprs.Push(new FunctionCall { Args = popArgs(6), Name = context.GetFunctionInfo(exprs.Pop().AsInt()).Name }); } else if (OperatorsByByte.ContainsKey(b)) { if (OperatorsByByte[b] == "N") { exprs.Push(new UnaryExpr { Op = "N", Arg = exprs.Pop() }); } else { exprs.Push(new BinaryExpr { Op = OperatorsByByte[b], Rhs = exprs.Pop(), Lhs = exprs.Pop() }); } } else if (b == 0xA6) { Expr top = exprs.Peek(); top.IfFalse = FalseCond.CONTINUE; } else if (b >= 0xA7 && b <= 0xAE) { byte regIndex = (byte)(b - 0xA7); exprs.Push(new FunctionCall { Args = popArgs(1), Name = $"SetREG{regIndex}" }); } else if (b >= 0xAF && b <= 0xB6) { byte regIndex = (byte)(b - 0xAF); exprs.Push(new FunctionCall { Args = popArgs(0), Name = $"GetREG{regIndex}" }); } else if (b == 0xB7) { Expr top = exprs.Peek(); top.IfFalse = FalseCond.ABORT; } else if (b == 0xB8) { // exprs.Push(new FunctionCall { Args = popArgs(1), Name = "StateGroupArg" }); FunctionCall func = new FunctionCall { Args = popArgs(1), Name = "StateGroupArg" }; ConstExpr ce = func.Args[0] as ConstExpr; // Console.WriteLine($"{ce} {ce.Value.GetType()}"); exprs.Push(func); } else if (b == 0xB9) { exprs.Push(new CallResult()); } else if (b == 0xBA) { // This opcode just returns a constant value 0x7FFFFFFF // But use higher-level representation of it exprs.Push(new CallOngoing()); } else if (b == 0xA1) { //break; } else { exprs.Push(new Unknown { Opcode = b }); } } if (exprs.Count != 1) { throw new Exception("Could not parse expr. Remaining stack: " + string.Join("; ", exprs) + $"; = {string.Join(" ", Bytes.Select(x => x.ToString("X2")))}"); } return(exprs.Pop()); }