Skip to content

Commit

Permalink
Merge pull request #1488 from VladiStep/fixDisasmFreeze
Browse files Browse the repository at this point in the history
A fix of the "Disassembly" freeze.
  • Loading branch information
colinator27 authored Dec 30, 2023
2 parents 81198a2 + c2ad930 commit a66883c
Show file tree
Hide file tree
Showing 3 changed files with 57 additions and 33 deletions.
15 changes: 10 additions & 5 deletions UndertaleModLib/Decompiler/Assembler.cs
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
using System.Collections.Generic;
using System.Diagnostics;
using System.Globalization;
using System.IO;
using System.Linq;
using System.Text;
using System.Text.RegularExpressions;
Expand Down Expand Up @@ -41,6 +42,9 @@ public static class Assembler
{ "pushref", -11 }
};

private static readonly Regex callInstrRegex = new(@"^(.*)\(argc=(.*)\)$", RegexOptions.Compiled);
private static readonly Regex codeEntryRegex = new(@"^\(locals=(.*)\,\s*argc=(.*)\)$", RegexOptions.Compiled);

// TODO: Improve the error messages

public static UndertaleInstruction AssembleOne(string source, IList<UndertaleFunction> funcs, IList<UndertaleVariable> vars, IList<UndertaleString> strg, Dictionary<string, UndertaleVariable> localvars = null, UndertaleData data = null)
Expand Down Expand Up @@ -205,7 +209,7 @@ public static UndertaleInstruction AssembleOne(string source, IList<UndertaleFun
break;

case UndertaleInstruction.InstructionType.CallInstruction:
Match match = Regex.Match(line, @"^(.*)\(argc=(.*)\)$");
Match match = callInstrRegex.Match(line);
if (!match.Success)
throw new Exception("Call instruction format error");

Expand Down Expand Up @@ -254,15 +258,16 @@ private static int ParseResourceName(string line, UndertaleData data)

public static List<UndertaleInstruction> Assemble(string source, IList<UndertaleFunction> funcs, IList<UndertaleVariable> vars, IList<UndertaleString> strg, UndertaleData data = null)
{
var lines = source.Replace("\r", "", StringComparison.InvariantCulture).Split('\n');
StringReader strReader = new(source);
uint addr = 0;
Dictionary<string, uint> labels = new Dictionary<string, uint>();
Dictionary<UndertaleInstruction, string> labelTargets = new Dictionary<UndertaleInstruction, string>();
List<UndertaleInstruction> instructions = new List<UndertaleInstruction>();
Dictionary<string, UndertaleVariable> localvars = new Dictionary<string, UndertaleVariable>();
foreach (var fullline in lines)
string fullLine;
while ((fullLine = strReader.ReadLine()) is not null)
{
string line = fullline;
string line = fullLine;
if (line.Length == 0)
continue;

Expand All @@ -279,7 +284,7 @@ public static List<UndertaleInstruction> Assemble(string source, IList<Undertale
throw new Exception($"Failed to find code entry with name \"{codeName}\".");
string info = line.Substring(space + 1);

Match match = Regex.Match(info, @"^\(locals=(.*)\,\s*argc=(.*)\)$");
Match match = codeEntryRegex.Match(info);
if (!match.Success)
throw new Exception("Sub-code entry format error");
code.LocalsCount = ushort.Parse(match.Groups[1].Value);
Expand Down
6 changes: 4 additions & 2 deletions UndertaleModLib/Decompiler/Decompiler.cs
Original file line number Diff line number Diff line change
Expand Up @@ -3997,11 +3997,13 @@ public static void BuildSubFunctionCache(UndertaleData data)
data.KnownSubFunctions = new Dictionary<string, UndertaleFunction>();
GlobalDecompileContext globalDecompileContext = new GlobalDecompileContext(data, false);
// TODO: Is this necessary?
// Doesn't the latter `Parallel.ForEach()` already cover this?
foreach (var func in data.Functions)
{
if (func.Name.Content.StartsWith("gml_Script_"))
{
var funcName = func.Name.Content.Substring("gml_Script_".Length);
var funcName = func.Name.Content[("gml_Script_".Length)..];
data.KnownSubFunctions.TryAdd(funcName, func);
}
}
Expand All @@ -4024,7 +4026,7 @@ public static void BuildSubFunctionCache(UndertaleData data)
{
lock (data.KnownSubFunctions)
{
data.KnownSubFunctions.Add(assign.Destination.Var.Name.Content, funcDef.Function);
data.KnownSubFunctions.TryAdd(assign.Destination.Var.Name.Content, funcDef.Function);
}
}
}
Expand Down
69 changes: 43 additions & 26 deletions UndertaleModTool/Editors/UndertaleCodeEditor.xaml.cs
Original file line number Diff line number Diff line change
Expand Up @@ -557,6 +557,8 @@ private void UpdateGettext(UndertaleCode gettextCode)
}

public static Dictionary<string, string> gettextJSON = null;
private static readonly Regex gettextRegex = new("scr_gettext\\(\\\"(.*?)\\\"\\)", RegexOptions.Compiled);
private static readonly Regex getlangRegex = new("scr_84_get_lang_string(?:.*?)\\(\\\"(.*?)\\\"\\)", RegexOptions.Compiled);
private string UpdateGettextJSON(string json)
{
try
Expand Down Expand Up @@ -677,42 +679,57 @@ private async Task DecompileCode(UndertaleCode code, bool first, LoaderDialog ex
mainWindow.ShowError(exc.ToString());
}
if (decompiled != null)
// Add `// string` at the end of lines with `scr_gettext()` or `scr_84_get_lang_string()`
if (decompiled is not null)
{
string[] decompiledLines;
if (gettext != null && decompiled.Contains("scr_gettext"))
StringReader decompLinesReader;
StringBuilder decompLinesBuilder;
Dictionary<string, string> currDict = null;
Regex currRegex = null;
if (gettext is not null && decompiled.Contains("scr_gettext"))
{
decompiledLines = decompiled.Split('\n');
for (int i = 0; i < decompiledLines.Length; i++)
{
var matches = Regex.Matches(decompiledLines[i], "scr_gettext\\(\\\"(\\w*)\\\"\\)");
foreach (Match match in matches)
{
if (match.Success)
{
if (gettext.TryGetValue(match.Groups[1].Value, out string text))
decompiledLines[i] += $" // {text}";
}
}
}
decompiled = string.Join('\n', decompiledLines);
currDict = gettext;
currRegex = gettextRegex;
}
else if (gettextJSON is not null && decompiled.Contains("scr_84_get_lang_string"))
{
currDict = gettextJSON;
currRegex = getlangRegex;
}
else if (gettextJSON != null && decompiled.Contains("scr_84_get_lang_string"))
if (currDict is not null && currRegex is not null)
{
decompiledLines = decompiled.Split('\n');
for (int i = 0; i < decompiledLines.Length; i++)
decompLinesReader = new(decompiled);
decompLinesBuilder = new();
string line;
while ((line = decompLinesReader.ReadLine()) is not null)
{
var matches = Regex.Matches(decompiledLines[i], "scr_84_get_lang_string(\\w*)\\(\\\"(\\w*)\\\"\\)");
foreach (Match match in matches)
// Not `currRegex.Match()`, because one line could contain several calls
// if the "Profile mode" is enabled.
var matches = currRegex.Matches(line).Where(m => m.Success).ToArray();
if (matches.Length > 0)
{
if (match.Success)
decompLinesBuilder.Append($"{line} // ");
for (int i = 0; i < matches.Length; i++)
{
if (gettextJSON.TryGetValue(match.Groups[^1].Value, out string text))
decompiledLines[i] += $" // {text}";
Match match = matches[i];
if (!currDict.TryGetValue(match.Groups[1].Value, out string text))
continue;
if (i != matches.Length - 1) // If not the last
decompLinesBuilder.Append($"{text}; ");
else
decompLinesBuilder.Append(text + '\n');
}
}
else
{
decompLinesBuilder.Append(line + '\n');
}
}
decompiled = string.Join('\n', decompiledLines);
decompiled = decompLinesBuilder.ToString();
}
}
Expand Down

0 comments on commit a66883c

Please sign in to comment.