コード例 #1
0
        static void AddScriptFromFile(string path)
        {
            string scriptSource = File.ReadAllText(path);
            string gmlWeirdName = "gml_Script_" + Path.GetFileNameWithoutExtension(path);

            // Make a code entry.
            UndertaleCode codeEntry = new UndertaleCode
            {
                Name = Data.Strings.MakeString(gmlWeirdName)
            };

            Data.Code.Add(codeEntry);

            // Make a code locals entry.
            UndertaleCodeLocals locals = new UndertaleCodeLocals
            {
                Name = codeEntry.Name
            };

            // Make a `var arguments;` entry.
            UndertaleCodeLocals.LocalVar argsLocal = new UndertaleCodeLocals.LocalVar
            {
                Name  = Data.Strings.MakeString("arguments"),
                Index = 0
            };

            // Glue everything together.
            locals.Locals.Add(argsLocal);
            Data.CodeLocals.Add(locals);

            // Set code locals entry for the code entry.
            codeEntry.LocalsCount = 1;
            //codeEntry.GenerateLocalVarDefinitions(codeEntry.FindReferencedLocalVars(), locals); // fails here.

            // FINALLY compile our script.
            Data.Code.ByName(gmlWeirdName).ReplaceGML(scriptSource, Data);

            // ... and actually add it like a script...
            var scr = new UndertaleScript
            {
                Code = Data.Code.ByName(gmlWeirdName),
                Name = Data.Strings.MakeString(Path.GetFileNameWithoutExtension(path))
            };

            Data.Scripts.Add(scr);

            // ... oh, and don't forget to add a *function* reference.
            var funcentry = new UndertaleFunction
            {
                Name = Data.Strings.MakeString(Path.GetFileNameWithoutExtension(path))
            };

            Data.Functions.Add(funcentry);
        }
コード例 #2
0
    public static UndertaleFunction EnsureDefined(this IList <UndertaleFunction> list, string name, IList <UndertaleString> strg, bool fast = false)
    {
        UndertaleFunction func = fast ? null : list.ByName(name);

        if (func == null)
        {
            var str = strg.MakeString(name, out int id);
            func = new UndertaleFunction()
            {
                Name         = str,
                NameStringID = id
            };
            list.Add(func);
        }
        return(func);
    }
コード例 #3
0
        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);
        }
コード例 #4
0
        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);
        }