Overhaul EB compiler and decompiler

This commit is contained in:
jeffman 2015-03-22 19:55:34 -04:00
parent 5dd4cc9f2a
commit 1802ce35d3
26 changed files with 2806 additions and 811 deletions

View File

@ -7,71 +7,74 @@ using System.IO;
namespace ScriptTool
{
public class M12Compiler : ICompiler
public class Compiler : ICompiler
{
private static IEnumerable<M12ControlCode> controlCodes;
private static string[] charLookup;
private const string hexChars = "0123456789ABCDEFabcdef";
private const string ebCharLookup = " !\"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZØØØØØ`abcdefghijklmnopqrstuvwxyz{|}~\\";
public IEnumerable<IControlCode> ControlCodes { get; set; }
public Dictionary<string, int> AddressMap { get; set; }
public Func<byte[], int, bool> ControlCodePredicate { get; set; }
static M12Compiler()
public Compiler(IEnumerable<IControlCode> controlCodes,
Func<byte[], int, bool> controlCodePredicate)
{
controlCodes = M12ControlCode.Codes;
charLookup = File.ReadAllLines("m12-text-table.txt");
}
ControlCodes = controlCodes;
ControlCodePredicate = controlCodePredicate;
public M12Compiler()
{
AddressMap = new Dictionary<string, int>();
}
public static bool IsHexByte(string str)
{
if (str == null || str.Length > 2)
try
{
return false;
}
for (int i = 0; i < str.Length; i++)
{
if (hexChars.IndexOf(str[i]) == -1)
{
return false;
}
}
Convert.ToByte(str, 16);
return true;
}
public static bool IsValidChar(char c)
{
if (!ebCharLookup.Contains(c))
catch
{
return false;
}
if (c == 'Ø')
{
return false;
}
return true;
}
public static byte GetByte(char c)
private byte GetByte(char c, IDictionary<byte, string> charLookup)
{
return (byte)(ebCharLookup.IndexOf(c) + 0x50);
return charLookup.First(kv => kv.Value[0] == c).Key; // lazy
}
public IList<string> ScanString(string str, bool scanCodesOnly)
public void ScanString(string str, ref int referenceAddress, IDictionary<byte, string> charLookup, bool scanCodesOnly)
{
ISet<IControlCode> codes;
IList<string> references;
ScanString(str, ref referenceAddress, charLookup, scanCodesOnly, out references, out codes);
}
public void ScanString(string str, IDictionary<byte, string> charLookup, bool scanCodesOnly,
out IList<string> references)
{
int temp = 0;
return ScanString(str, ref temp, scanCodesOnly);
ISet<IControlCode> codes;
ScanString(str, ref temp, charLookup, scanCodesOnly, out references, out codes);
}
public IList<string> ScanString(string str, ref int referenceAddress, bool scanCodesOnly)
public void ScanString(string str, IDictionary<byte, string> charLookup, bool scanCodesOnly,
out ISet<IControlCode> codes)
{
var references = new List<string>();
int temp = 0;
IList<string> references;
ScanString(str, ref temp, charLookup, scanCodesOnly, out references, out codes);
}
public void ScanString(string str, IDictionary<byte, string> charLookup, bool scanCodesOnly,
out IList<string> references, out ISet<IControlCode> controlCodes)
{
int temp = 0;
ScanString(str, ref temp, charLookup, scanCodesOnly, out references, out controlCodes);
}
public void ScanString(string str, ref int referenceAddress, IDictionary<byte, string> charLookup, bool scanCodesOnly,
out IList<string> references, out ISet<IControlCode> controlCodes)
{
references = new List<string>();
controlCodes = new HashSet<IControlCode>();
for (int i = 0; i < str.Length; )
{
@ -83,6 +86,12 @@ namespace ScriptTool
string[] codeStrings = str.Substring(i + 1, str.IndexOf(']', i + 1) - i - 1)
.Split(' ');
IControlCode code = ControlCodes.FirstOrDefault(c => c.IsMatch(codeStrings));
if (!controlCodes.Contains(code))
{
controlCodes.Add(code);
}
foreach (var codeString in codeStrings)
{
if (codeString[0] == '_')
@ -137,25 +146,21 @@ namespace ScriptTool
{
if (!scanCodesOnly)
{
if (!IsValidChar(str[i]))
throw new Exception("Invalid character: " + str[i]);
GetByte(str[i], charLookup); // just check if it's valid
referenceAddress++;
}
}
i++;
}
}
return references;
}
public void CompileString(string str, IList<byte> buffer, ref int referenceAddress)
public void CompileString(string str, IList<byte> buffer, ref int referenceAddress, IDictionary<byte, string> charLookup)
{
CompileString(str, buffer, ref referenceAddress, -1);
CompileString(str, buffer, ref referenceAddress, charLookup, -1);
}
public void CompileString(string str, IList<byte> buffer, ref int referenceAddress, int padLength)
public void CompileString(string str, IList<byte> buffer, ref int referenceAddress, IDictionary<byte, string> charLookup, int padLength)
{
int previousBufferSize = buffer.Count;
@ -170,7 +175,7 @@ namespace ScriptTool
.Split(' ');
// Match the code
M12ControlCode code = controlCodes.FirstOrDefault(c => c.IsMatch(codeStrings));
IControlCode code = ControlCodes.FirstOrDefault(c => c.IsMatch(codeStrings));
if (code == null)
{
@ -194,44 +199,7 @@ namespace ScriptTool
throw new Exception("Invalid control code");
// Parse
foreach (var codeString in codeStrings)
{
if (codeString[0] == '_')
{
if (codeString[codeString.Length - 1] != '_')
throw new Exception("Reference has no closing underscore");
if (codeString.Length <= 2)
throw new Exception("Reference is empty");
string label = codeString.Substring(1, codeString.Length - 2);
int pointer = AddressMap[label];
if (!code.AbsoluteAddressing)
{
pointer -= referenceAddress;
}
else
{
pointer |= 0x8000000;
}
if (buffer != null)
buffer.AddInt(pointer);
referenceAddress += 4;
}
else if (IsHexByte(codeString))
{
byte value = byte.Parse(codeString, System.Globalization.NumberStyles.HexNumber);
buffer.Add(value);
referenceAddress++;
}
else
{
throw new Exception(String.Format(
"Encountered invalid code string at position {0}: {1}", i, codeString));
}
}
code.Compile(codeStrings, buffer, ref referenceAddress, AddressMap);
}
i = str.IndexOf(']', i + 1) + 1;
@ -251,12 +219,11 @@ namespace ScriptTool
{
if (!(str[i] == '\r') && !(str[i] == '\n'))
{
if (!IsValidChar(str[i]))
throw new Exception("Invalid character: " + str[i]);
byte value = GetByte(str[i], charLookup);
byte value = GetByte(str[i]);
if (buffer != null)
buffer.Add(value);
referenceAddress++;
}
i++;
@ -267,6 +234,7 @@ namespace ScriptTool
if (padLength != -1)
{
int bytesWritten = buffer.Count - previousBufferSize;
if (bytesWritten > padLength)
throw new Exception("Exceeded pad length");
@ -274,6 +242,7 @@ namespace ScriptTool
{
if (buffer != null)
buffer.Add(0);
referenceAddress++;
}
}

View File

@ -7,21 +7,20 @@ using System.IO;
namespace ScriptTool
{
class M12Decompiler : IDecompiler
class Decompiler : IDecompiler
{
private static IEnumerable<IControlCode> controlCodes;