diff --git a/BasicNumber.cs b/BasicNumber.cs
new file mode 100644
index 0000000..0ab63c4
--- /dev/null
+++ b/BasicNumber.cs
@@ -0,0 +1,60 @@
+using System;
+using System.Collections.Generic;
+using System.Text;
+
+namespace SuperBASIC
+{
+	enum NumberType{
+		Ans,
+		Number,
+		Operand
+	};
+
+	struct BasicNumber
+	{
+		internal NumberType type;
+
+		readonly Runtime runtime;
+		readonly private float number;
+		readonly private int operand;
+
+		internal BasicNumber(Runtime rt, float v)
+		{
+			type = NumberType.Number;
+			number = v;
+			operand = 0;
+			runtime = rt;
+		}
+		internal BasicNumber(Runtime rt)
+		{
+			type = NumberType.Ans;
+			number = 0;
+			operand = 0;
+			runtime = rt;
+		}
+		internal BasicNumber(Runtime rt, int v)
+		{
+			type = NumberType.Operand;
+			number = 0;
+			operand = v;
+			runtime = rt;
+		}
+
+		internal int GetOperand()
+		{
+			return operand;
+		}
+
+		public float GetValue()
+		{
+			if (type == NumberType.Number)
+			{
+				return number;
+			} 
+			else
+			{
+				return runtime.GetRegister();
+			}
+		}
+	}
+}
diff --git a/Bytecode.cs b/Bytecode.cs
new file mode 100644
index 0000000..f69a8ba
--- /dev/null
+++ b/Bytecode.cs
@@ -0,0 +1,16 @@
+using System;
+using System.Collections.Generic;
+using System.Text;
+
+namespace SuperBASIC
+{
+	class Bytecode
+	{
+		internal List<BasicNumber> bytecode;
+
+		internal Bytecode()
+		{
+			bytecode = new List<BasicNumber>();
+		}
+	}
+}
diff --git a/Functions/Multiply.cs b/Functions/Multiply.cs
new file mode 100644
index 0000000..cbfb8e8
--- /dev/null
+++ b/Functions/Multiply.cs
@@ -0,0 +1,14 @@
+using System;
+using System.Collections.Generic;
+using System.Text;
+
+namespace SuperBASIC.Functions
+{
+	class Multiply : IFunction
+	{
+		float IFunction.Apply(List<BasicNumber> arguments)
+		{
+			return arguments[0].GetValue() * arguments[1].GetValue();
+		}
+	}
+}
diff --git a/Functions/Print.cs b/Functions/Print.cs
new file mode 100644
index 0000000..eb359d7
--- /dev/null
+++ b/Functions/Print.cs
@@ -0,0 +1,15 @@
+using System;
+using System.Collections.Generic;
+using System.Text;
+
+namespace SuperBASIC.Functions
+{
+	class Print : IFunction
+	{
+		float IFunction.Apply(List<BasicNumber> arguments)
+		{
+			Console.WriteLine(arguments[0].GetValue());
+			return 0f;
+		}
+	}
+}
diff --git a/IFunction.cs b/IFunction.cs
new file mode 100644
index 0000000..006d617
--- /dev/null
+++ b/IFunction.cs
@@ -0,0 +1,11 @@
+using System;
+using System.Collections.Generic;
+using System.Text;
+
+namespace SuperBASIC
+{
+	interface IFunction
+	{
+		public float Apply(List<BasicNumber> arguments);
+	}
+}
diff --git a/Library.cs b/Library.cs
new file mode 100644
index 0000000..dee7876
--- /dev/null
+++ b/Library.cs
@@ -0,0 +1,29 @@
+using System;
+using System.Collections.Generic;
+using System.Text;
+
+namespace SuperBASIC
+{
+	class Library
+	{
+		internal List<IFunction> functions;
+		internal List<int> arities;
+		internal Dictionary<string, int> nameResolution;
+
+		public Library()
+		{
+			functions = new List<IFunction>();
+			arities = new List<int>();
+			nameResolution = new Dictionary<string, int>();
+		}
+
+		public int AddFunction(IFunction fn, int arity, string name)
+		{
+			int idx = functions.Count;
+			functions.Add(fn);
+			arities.Add(arity);
+			nameResolution[name] = idx;
+			return idx;
+		}
+	}
+}
diff --git a/Parser.cs b/Parser.cs
new file mode 100644
index 0000000..f0716e3
--- /dev/null
+++ b/Parser.cs
@@ -0,0 +1,86 @@
+using System;
+using System.Collections.Generic;
+using System.Text;
+using System.IO;
+using System.Text.RegularExpressions;
+
+namespace SuperBASIC
+{
+	class Parser
+	{
+
+		[Serializable]
+		public class ParseException : Exception
+		{
+			public ParseException() { }
+			public ParseException(string message) : base(message) { }
+			public ParseException(string message, Exception inner) : base(message, inner) { }
+			protected ParseException(
+			  System.Runtime.Serialization.SerializationInfo info,
+			  System.Runtime.Serialization.StreamingContext context) : base(info, context) { }
+		}
+
+		readonly Library library;
+		readonly Runtime runtime;
+		public Parser(Runtime rt)
+		{
+			runtime = rt;
+			library = rt.lib;
+		}
+
+		public Bytecode ParseFile(string filepath)
+		{
+			Bytecode c = new Bytecode();
+			string[] sourceLines = File.ReadAllLines(filepath);
+			Regex lws = new Regex(@"\s+");
+			Regex leadings = new Regex(@"^\s+");
+			Regex trailings = new Regex(@"\s+$");
+			List<string> codeLines = new List<string>();
+
+			foreach (string line in sourceLines)
+			{
+				string l = lws.Replace(line, " ");
+				l = leadings.Replace(l, "");
+				l = trailings.Replace(l, "");
+
+				if(l != String.Empty)
+				{
+					codeLines.Add(l);
+				}
+			}
+
+			foreach(string line in codeLines)
+			{
+				var components = line.Split(' ');
+
+				if(!library.nameResolution.ContainsKey(components[0]))
+				{
+					throw new ParseException("Unknown operation \"" + components[0] + "\"");
+				}
+
+				int opcode = library.nameResolution[components[0]];
+				int arity = library.arities[opcode];
+
+				if(arity != components.Length-1)
+				{
+					throw new ParseException("Operation " + components[0] + " was provided with the wrong number of arguments: Expected "+arity.ToString()+" found "+(components.Length-1).ToString());
+				}
+
+				c.bytecode.Add(new BasicNumber(runtime, opcode));
+				foreach (string elem in components.AsSpan(1))
+				{
+					if (elem != "$")
+					{
+						c.bytecode.Add(new BasicNumber(runtime, float.Parse(elem)));
+					}
+					else
+					{
+						c.bytecode.Add(new BasicNumber(runtime));
+					}
+				}
+			}
+
+			return c;
+		}
+	}
+}
diff --git a/Program.cs b/Program.cs
new file mode 100644
index 0000000..feff13b
--- /dev/null
+++ b/Program.cs
@@ -0,0 +1,18 @@
+using System;
+using System.IO;
+
+namespace SuperBASIC
+{
+	class Program
+	{
+		static void Main(string[] args)
+		{
+			Library lib = new Library();
+			lib.AddFunction(new Functions.Print(), 1, "PRINT");
+			lib.AddFunction(new Functions.Multiply(), 2, "MULTIPLY");
+			Runtime r = new Runtime(lib);
+			r.OpenFile(Directory.GetCurrentDirectory() + "\\Test.basic");
+			r.Run();
+		}
+	}
+}
diff --git a/Runtime.cs b/Runtime.cs
new file mode 100644
index 0000000..65f5f63
--- /dev/null
+++ b/Runtime.cs
@@ -0,0 +1,45 @@
+using System;
+using System.Collections.Generic;
+using System.Text;
+
+namespace SuperBASIC
+{
+	class Runtime
+	{
+		float register;
+		internal Library lib;
+		Bytecode code;
+
+		public Runtime(Library library)
+		{
+			lib = library;
+		}
+
+		public void OpenFile(string path)
+		{
+			code = new Parser(this).ParseFile(path);
+		}
+
+		public void Run()
+		{
+			for(int idx = 0; idx < code.bytecode.Count;)
+			{
+				int opcode = code.bytecode[idx].GetOperand();
+				int arity = lib.arities[opcode];
+				IFunction op = lib.functions[opcode];
+				var args = code.bytecode.GetRange(idx + 1, arity);
+				SetRegister(op.Apply(args));
+				idx += arity + 1;
+			}
+		}
+
+		internal void SetRegister(float value)
+		{
+			register = value;
+		}
+		internal float GetRegister()
+		{
+			return register;
+		}
+	}
+}
diff --git a/SuperBASIC.csproj b/SuperBASIC.csproj
new file mode 100644
index 0000000..fdb69aa
--- /dev/null
+++ b/SuperBASIC.csproj
@@ -0,0 +1,14 @@
+<Project Sdk="Microsoft.NET.Sdk">
+
+  <PropertyGroup>
+    <OutputType>Exe</OutputType>
+    <TargetFramework>netcoreapp3.1</TargetFramework>
+  </PropertyGroup>
+
+  <ItemGroup>
+    <None Update="Test.basic">
+      <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
+    </None>
+  </ItemGroup>
+
+</Project>
diff --git a/SuperBASIC.sln b/SuperBASIC.sln
new file mode 100644
index 0000000..d445c26
--- /dev/null
+++ b/SuperBASIC.sln
@@ -0,0 +1,25 @@
+
+Microsoft Visual Studio Solution File, Format Version 12.00
+# Visual Studio Version 16
+VisualStudioVersion = 16.0.30907.101
+MinimumVisualStudioVersion = 10.0.40219.1
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "SuperBASIC", "SuperBASIC.csproj", "{51942D92-4C96-4FD9-AA5B-C35661E3B063}"
+EndProject
+Global
+	GlobalSection(SolutionConfigurationPlatforms) = preSolution
+		Debug|Any CPU = Debug|Any CPU
+		Release|Any CPU = Release|Any CPU
+	EndGlobalSection
+	GlobalSection(ProjectConfigurationPlatforms) = postSolution
+		{51942D92-4C96-4FD9-AA5B-C35661E3B063}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+		{51942D92-4C96-4FD9-AA5B-C35661E3B063}.Debug|Any CPU.Build.0 = Debug|Any CPU
+		{51942D92-4C96-4FD9-AA5B-C35661E3B063}.Release|Any CPU.ActiveCfg = Release|Any CPU
+		{51942D92-4C96-4FD9-AA5B-C35661E3B063}.Release|Any CPU.Build.0 = Release|Any CPU
+	EndGlobalSection
+	GlobalSection(SolutionProperties) = preSolution
+		HideSolutionNode = FALSE
+	EndGlobalSection
+	GlobalSection(ExtensibilityGlobals) = postSolution
+		SolutionGuid = {B03097C8-5C88-49D7-BD8F-EF905E9827EA}
+	EndGlobalSection
+EndGlobal
diff --git a/Test.basic b/Test.basic
new file mode 100644
index 0000000..15dbbd5
--- /dev/null
+++ b/Test.basic
@@ -0,0 +1,2 @@
+MULTIPLY 2 3
+PRINT $
\ No newline at end of file