Created
April 28, 2020 22:18
-
-
Save GuyInGrey/b13e77ec5597c6d0271892bc048fa855 to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
using System; | |
using System.Collections.Generic; | |
using System.IO; | |
using System.Linq; | |
using System.Text; | |
using System.Text.RegularExpressions; | |
using System.Windows.Forms; | |
using Microsoft.VisualBasic; | |
using Tether; | |
namespace Modules | |
{ | |
public class BinaryBasedInterpreter : TetherModule, ITrayMenu | |
{ | |
string[] Script; | |
Dictionary<byte, int> Labels; | |
byte[] Memory; | |
int CurrentLine; | |
byte[] Input; | |
bool Running; | |
int Delay = 10; | |
bool Processing = false; | |
string Buffer = ""; | |
static Dictionary<byte, string> Instructions = new Dictionary<byte, string>() | |
{ | |
{ 0b00000000, "exit" }, | |
{ 0b00000001, "print" }, | |
{ 0b00000010, "set" }, | |
{ 0b00000011, "dump" }, | |
{ 0b10000000, "printnumval" }, | |
{ 0b00001000, "label" }, | |
{ 0b00001001, "jump" }, | |
{ 0b00001010, "jumpif" }, | |
{ 0b00000100, "==" }, | |
{ 0b00000101, "<" }, | |
{ 0b00000110, ">" }, | |
{ 0b00010000, "math" }, | |
{ 0b00010001, "+" }, | |
{ 0b00010010, "-" }, | |
{ 0b00010011, "*" }, | |
{ 0b00010100, "/" }, | |
}; | |
public override ModuleInfo GetInfo() => new ModuleInfo() | |
{ | |
Name = "BinaryBasedInterpreter", | |
}; | |
public void Reset() | |
{ | |
Running = false; | |
Memory = new byte[256]; | |
CurrentLine = 0; | |
Buffer = ""; | |
Labels = new Dictionary<byte, int>(); | |
for (var l = 0; l < Script.Length; l++) | |
{ | |
var parts = GetParts(l); | |
if (parts.Item1 == 0 && parts.Item2 == 0b00001000) | |
{ | |
parts = GetParts(l + 1); | |
Labels.Add(GetValue(l + 1).Value, l + 2); | |
} | |
} | |
} | |
public MenuItem GetMenu() | |
{ | |
var menu = new MenuItem(); | |
menu.Text = "Interpreter"; | |
var items = new List<MenuItem>() | |
{ | |
new MenuItem("Load Script", (a, b) => | |
{ | |
var s = Interaction.InputBox("What script what you like to load?","Input Script Name",""); | |
Script = File.ReadAllText(@"Scripts\" + s).Split('\n'); | |
Reset(); | |
this.Log("Loaded Script: " + s); | |
}), | |
new MenuItem("Start/Resume", (a, b) => | |
{ | |
Running = true; | |
}), | |
}; | |
items.ForEach(i => menu.MenuItems.Add(i)); | |
return menu; | |
} | |
public override void Startup() | |
{ | |
StartTimer(() => | |
{ | |
if (Running && !Processing) | |
{ | |
Process(); | |
} | |
}, 0, Delay); | |
} | |
public (int, byte) GetParts(int lineIndex) | |
{ | |
try | |
{ | |
var line = Script[lineIndex]; | |
var comment = line.IndexOf("//"); | |
if (comment != -1) | |
{ | |
line = line.Substring(0, comment); | |
} | |
line = line.Trim(); | |
line = Regex.Replace(line, @"\s+", string.Empty); | |
var intPart = line.Substring(0, 2); | |
var bytePart = line.Substring(2, 8); | |
return (Convert.ToInt32(intPart, 2), Convert.ToByte(bytePart, 2)); | |
} | |
catch (Exception e) | |
{ | |
Console.WriteLine(e.Message + "\n\n" + e.StackTrace); | |
this.Log("Parsing Error - Line " + CurrentLine); | |
Running = false; | |
return (100, 0); | |
} | |
} | |
public void Process() | |
{ | |
if (CurrentLine >= Script.Length) | |
{ | |
this.Log("Program hit ending and unsafely termianted. Use the exit instruction."); | |
Running = false; | |
return; | |
} | |
this.Log("Processing line " + CurrentLine); | |
Processing = true; | |
var parts = GetParts(CurrentLine); | |
if (parts.Item1 == 100) { return; } | |
if (parts.Item1 != 0) | |
{ | |
this.Log("Expected Instruction Type - Line " + CurrentLine); | |
Running = false; | |
return; | |
} | |
if (!Instructions.ContainsKey(parts.Item2)) | |
{ | |
this.Log("Invalid Instruction - Line " + CurrentLine); | |
Running = false; | |
return; | |
} | |
var instruction = Instructions[parts.Item2]; | |
switch (instruction) | |
{ | |
case "exit": | |
this.Log("Execution Stopped By Script"); | |
Running = false; | |
CurrentLine = 0; | |
break; | |
case "print": | |
var val = GetValue(CurrentLine + 1); | |
if (val is null) { return; } | |
if (val < 32 || val > 126) { CurrentLine++; break; } | |
Buffer += Encoding.ASCII.GetString(new[] { val.Value }); | |
CurrentLine++; | |
break; | |
case "set": | |
var val2 = GetValue(CurrentLine + 1); | |
if (val2 is null) { return; } | |
var val3 = GetValue(CurrentLine + 2); | |
if (val3 is null) { return; } | |
Memory[val2.Value] = val3.Value; | |
CurrentLine += 2; | |
break; | |
case "dump": | |
if (Running) | |
{ | |
this.Log(Buffer); | |
Buffer = ""; | |
} | |
else | |
{ | |
Buffer += "\n"; | |
} | |
break; | |
case "printnumval": | |
val = GetValue(CurrentLine + 1); | |
if (val is null) { return; } | |
Buffer += ((int)val.Value).ToString(); | |
CurrentLine++; | |
break; | |
case "jump": | |
var val4 = GetValue(CurrentLine + 1); | |
if (val4 is null) { return; } | |
CurrentLine = Labels[val4.Value] - 1; | |
break; | |
case "jumpif": | |
var val5 = GetValue(CurrentLine + 1); | |
if (val5 is null) { return; } | |
var val6 = GetValue(CurrentLine + 2); | |
if (val6 is null) { return; } | |
var op = Instructions[GetParts(CurrentLine + 3).Item2]; | |
var val7 = GetValue(CurrentLine + 4); | |
if (val7 is null) { return; } | |
var result = false; | |
switch (op) | |
{ | |
case "==": | |
result = val6 == val7; | |
break; | |
case "<": | |
result = val6 < val7; | |
break; | |
case ">": | |
result = val6 > val7; | |
break; | |
} | |
if (result) { CurrentLine = Labels[val5.Value] - 1; } | |
else { CurrentLine += 4; } | |
break; | |
case "math": | |
var toSet = GetValue(CurrentLine + 1); | |
if (toSet is null) { return; } | |
var left = GetValue(CurrentLine + 2); | |
if (left is null) { return; } | |
op = Instructions[GetParts(CurrentLine + 3).Item2]; | |
var right = GetValue(CurrentLine + 4); | |
if (right is null) { return; } | |
switch (op) | |
{ | |
case "+": | |
Memory[toSet.Value] = (byte)(left + right); | |
break; | |
case "-": | |
Memory[toSet.Value] = (byte)(left - right); | |
break; | |
case "*": | |
Memory[toSet.Value] = (byte)(left * right); | |
break; | |
case "/": | |
Memory[toSet.Value] = (byte)(left / right); | |
break; | |
} | |
CurrentLine += 4; | |
break; | |
case "label": | |
CurrentLine++; | |
break; | |
} | |
CurrentLine++; | |
Processing = false; | |
} | |
public byte? GetValue(int line) | |
{ | |
var parts = GetParts(line); | |
if (parts.Item1 == 100) { return null; } | |
if (parts.Item1 == 1) | |
{ | |
return parts.Item2; | |
} | |
else if (parts.Item1 == 2) | |
{ | |
return Memory[parts.Item2]; | |
} | |
else | |
{ | |
this.Log("Expected Value Type - Line " + CurrentLine); | |
Running = false; | |
return byte.MaxValue; | |
} | |
} | |
public string Run(string input) | |
{ | |
Script = input.Split('\n'); | |
Reset(); | |
var parts = GetParts(CurrentLine); | |
do | |
{ | |
Process(); | |
parts = GetParts(CurrentLine); | |
} while (!(parts.Item1 == 0 && parts.Item2 == 0 || CurrentLine >= Script.Length)); | |
return Buffer; | |
} | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment