public static UndertaleInstruction AssembleOne(string source, IList <UndertaleFunction> funcs, IList <UndertaleVariable> vars, IList <UndertaleString> strg, Dictionary <string, UndertaleVariable> localvars, out string label, UndertaleData data = null, Func <int, UndertaleInstruction.InstanceType?> lookOnStack = null) { label = null; string line = source; UndertaleInstruction instr = new UndertaleInstruction(); string opcode = line; int space = opcode.IndexOf(' '); if (space >= 0) { opcode = line.Substring(0, space); line = line.Substring(space + 1).Trim(); } else { line = ""; } string[] types = opcode.Split('.'); if (types.Length > 3) { throw new Exception("Too many type parameters"); } instr.Kind = (UndertaleInstruction.Opcode)Enum.Parse(typeof(UndertaleInstruction.Opcode), types[0], true); if (types.Length >= 2) { instr.Type1 = UndertaleInstructionUtil.FromOpcodeParam(types[1]); } if (types.Length >= 3) { instr.Type2 = UndertaleInstructionUtil.FromOpcodeParam(types[2]); } switch (UndertaleInstruction.GetInstructionType(instr.Kind)) { case UndertaleInstruction.InstructionType.SingleTypeInstruction: if (instr.Kind == UndertaleInstruction.Opcode.Dup) { instr.DupExtra = Byte.Parse(line); line = ""; } break; case UndertaleInstruction.InstructionType.DoubleTypeInstruction: break; case UndertaleInstruction.InstructionType.ComparisonInstruction: instr.ComparisonKind = (UndertaleInstruction.ComparisonType)Enum.Parse(typeof(UndertaleInstruction.ComparisonType), line, true); line = ""; break; case UndertaleInstruction.InstructionType.GotoInstruction: if (line[0] == '$') { instr.JumpOffset = Int32.Parse(line.Substring(1)); } else { if (line == "[drop]") { instr.JumpOffsetPopenvExitMagic = true; if (data?.GeneralInfo?.BytecodeVersion <= 14) { instr.JumpOffset = -1048576; // I really don't know at this point. Magic for little endian 00 00 F0 } } else { label = line; } } line = ""; break; case UndertaleInstruction.InstructionType.PopInstruction: if (instr.Type1 == UndertaleInstruction.DataType.Int16) { // Special scenario - the swap instruction // TODO: Figure out the proper syntax, see #129 instr.SwapExtra = Byte.Parse(line); } else { UndertaleInstruction.InstanceType inst = instr.TypeInst; instr.Destination = ParseVariableReference(line, vars, localvars, ref inst, instr, lookOnStack, data); instr.TypeInst = inst; } line = ""; break; case UndertaleInstruction.InstructionType.PushInstruction: switch (instr.Type1) { case UndertaleInstruction.DataType.Double: instr.Value = Double.Parse(line, CultureInfo.InvariantCulture); break; case UndertaleInstruction.DataType.Float: instr.Value = Single.Parse(line, CultureInfo.InvariantCulture); break; case UndertaleInstruction.DataType.Int32: int ival; if (Int32.TryParse(line, out ival)) { instr.Value = ival; } else { instr.Value = (int)ParseResourceName(line, data); } break; case UndertaleInstruction.DataType.Int64: long lval; if (Int64.TryParse(line, out lval)) { instr.Value = lval; } else { instr.Value = (long)ParseResourceName(line, data); } break; case UndertaleInstruction.DataType.Boolean: instr.Value = bool.Parse(line); break; case UndertaleInstruction.DataType.Variable: UndertaleInstruction.InstanceType inst2 = instr.TypeInst; instr.Value = ParseVariableReference(line, vars, localvars, ref inst2, instr, lookOnStack, data); instr.TypeInst = inst2; break; case UndertaleInstruction.DataType.String: instr.Value = ParseStringReference(line, strg); break; case UndertaleInstruction.DataType.Int16: short sval; if (Int16.TryParse(line, out sval)) { instr.Value = sval; } else { instr.Value = (short)ParseResourceName(line, data); } break; } line = ""; break; case UndertaleInstruction.InstructionType.CallInstruction: Match match = Regex.Match(line, @"^(.*)\(argc=(.*)\)$"); if (!match.Success) { throw new Exception("Call instruction format error"); } UndertaleFunction func = funcs.ByName(match.Groups[1].Value); if (func == null) { throw new Exception("Function not found: " + match.Groups[1].Value); } instr.Function = new UndertaleInstruction.Reference <UndertaleFunction>() { Target = func }; instr.ArgumentsCount = UInt16.Parse(match.Groups[2].Value); line = ""; break; case UndertaleInstruction.InstructionType.BreakInstruction: instr.Value = Int16.Parse(line); line = ""; break; } if (line != "") { throw new Exception("Excess parameters"); } return(instr); }
public static UndertaleInstruction AssembleOne(string source, IList <UndertaleFunction> funcs, IList <UndertaleVariable> vars, IList <UndertaleString> strg, Dictionary <string, UndertaleVariable> localvars, out string label, UndertaleInstruction.InstanceType?instTypeOnStack) { label = null; string line = source; UndertaleInstruction instr = new UndertaleInstruction(); string opcode = line; int space = opcode.IndexOf(' '); if (space >= 0) { opcode = line.Substring(0, space); line = line.Substring(space + 1).Trim(); } else { line = ""; } string[] types = opcode.Split('.'); if (types.Length > 3) { throw new Exception("Too many type parameters"); } instr.Kind = (UndertaleInstruction.Opcode)Enum.Parse(typeof(UndertaleInstruction.Opcode), types[0], true); if (types.Length >= 2) { instr.Type1 = UndertaleInstructionUtil.FromOpcodeParam(types[1]); } if (types.Length >= 3) { instr.Type2 = UndertaleInstructionUtil.FromOpcodeParam(types[2]); } switch (UndertaleInstruction.GetInstructionType(instr.Kind)) { case UndertaleInstruction.InstructionType.SingleTypeInstruction: if (instr.Kind == UndertaleInstruction.Opcode.Dup) { instr.DupExtra = Byte.Parse(line); line = ""; } break; case UndertaleInstruction.InstructionType.DoubleTypeInstruction: break; case UndertaleInstruction.InstructionType.ComparisonInstruction: instr.ComparisonKind = (UndertaleInstruction.ComparisonType)Enum.Parse(typeof(UndertaleInstruction.ComparisonType), line, true); line = ""; break; case UndertaleInstruction.InstructionType.GotoInstruction: if (line[0] == '$') { instr.JumpOffset = Int32.Parse(line.Substring(1)); } else { label = line; } line = ""; break; case UndertaleInstruction.InstructionType.PopInstruction: UndertaleInstruction.InstanceType inst = instr.TypeInst; instr.Destination = ParseVariableReference(line, vars, localvars, ref inst, instTypeOnStack); instr.TypeInst = inst; line = ""; break; case UndertaleInstruction.InstructionType.PushInstruction: switch (instr.Type1) { case UndertaleInstruction.DataType.Double: instr.Value = Double.Parse(line, CultureInfo.InvariantCulture); break; case UndertaleInstruction.DataType.Float: instr.Value = Single.Parse(line, CultureInfo.InvariantCulture); break; case UndertaleInstruction.DataType.Int32: instr.Value = Int32.Parse(line); break; case UndertaleInstruction.DataType.Int64: instr.Value = Int64.Parse(line); break; case UndertaleInstruction.DataType.Boolean: instr.Value = Boolean.Parse(line); break; case UndertaleInstruction.DataType.Variable: UndertaleInstruction.InstanceType inst2 = instr.TypeInst; instr.Value = ParseVariableReference(line, vars, localvars, ref inst2, instTypeOnStack); instr.TypeInst = inst2; break; case UndertaleInstruction.DataType.String: instr.Value = ParseStringReference(line, strg); break; case UndertaleInstruction.DataType.Int16: instr.Value = Int16.Parse(line); break; } line = ""; break; case UndertaleInstruction.InstructionType.CallInstruction: Match match = Regex.Match(line, @"^(.*)\(argc=(.*)\)$"); if (!match.Success) { throw new Exception("Call instruction format error"); } UndertaleFunction func = funcs.ByName(match.Groups[1].Value); if (func == null) { throw new Exception("Function not found: " + match.Groups[1].Value); } instr.Function = new UndertaleInstruction.Reference <UndertaleFunction>() { Target = func }; instr.ArgumentsCount = UInt16.Parse(match.Groups[2].Value); line = ""; break; case UndertaleInstruction.InstructionType.BreakInstruction: instr.Value = Int16.Parse(line); line = ""; break; } if (line != "") { throw new Exception("Excess parameters"); } return(instr); }