CLanguage by praeclarum

<PackageReference Include="CLanguage" Version="0.5.26" />

 CInterpreter

public class CInterpreter
using CLanguage.Types; using System; using System.Linq; namespace CLanguage.Interpreter { public class CInterpreter { private Executable exe; private BaseFunction entrypoint; public readonly Value[] Stack; public int SP; private readonly ExecutionFrame[] Frames; private int FI; public int CpuSpeed = 1000; public int SleepTime { get; set; } public int RemainingTime { get; set; } public ExecutionFrame CallerFrame { get { if (0 > FI - 1 || FI - 1 >= Frames.Length) return null; return Frames[FI - 1]; } } public ExecutionFrame ActiveFrame { get { if (0 > FI || FI >= Frames.Length) return null; return Frames[FI]; } } public CInterpreter(Executable exe, int maxStack = 1024, int maxFrames = 24) { this.exe = exe; Stack = new Value[maxStack]; Frames = (from i in Enumerable.Range(0, maxFrames) select new ExecutionFrame()).ToArray(); } public Value ReadRelativeMemory(int frameOffset) { int num = ActiveFrame.FP + frameOffset; return Stack[num]; } public Value ReadMemory(int address) { return Stack[address]; } public Value ReadArg(int index) { CFunctionType functionType = ActiveFrame.Function.FunctionType; int frameOffset; if (index < functionType.Parameters.Count) frameOffset = functionType.Parameters[index].Offset; else { if (index != functionType.Parameters.Count || !functionType.IsInstance) throw new ArgumentOutOfRangeException("Cannot read argument #" + index); frameOffset = -1; } return ReadRelativeMemory(frameOffset); } public void Call(Value functionAddress) { Call(exe.Functions[functionAddress.PointerValue]); } public void Call(BaseFunction function) { if (FI + 1 >= Frames.Length) { string name = function.Name; string text = (ActiveFrame != null) ? ActiveFrame.Function.Name : "?"; Reset(); throw new ExecutionException("Stack overflow while calling '" + name + "' from '" + text + "'"); } FI++; ExecutionFrame activeFrame = ActiveFrame; activeFrame.Function = function; activeFrame.FP = SP; activeFrame.IP = 0; function.Init(this); } public void Push(Value value) { Stack[SP++] = value; } public void Return() { ExecutionFrame activeFrame = ActiveFrame; CFunctionType functionType = activeFrame.Function.FunctionType; int num = 0; foreach (CFunctionType.Parameter parameter in functionType.Parameters) { num += parameter.ParameterType.NumValues; } if (functionType.IsInstance) num++; CompiledFunction compiledFunction; if ((compiledFunction = (activeFrame.Function as CompiledFunction)) != null) { foreach (CompiledVariable localVariable in compiledFunction.LocalVariables) { num += localVariable.VariableType.NumValues; } } int numValues = functionType.ReturnType.NumValues; int num2 = SP - num; int num3 = num2 - numValues; for (int i = 0; i < numValues; i++) { Stack[num3 + i] = Stack[SP - numValues + i]; } SP = num2; FI--; } public void Reset(string entrypoint) { this.entrypoint = exe.Functions.FirstOrDefault((BaseFunction x) => x.Name == entrypoint); Reset(); } private void Reset() { FI = -1; SP = 0; foreach (CompiledVariable global in exe.Globals) { if (global.InitialValue != null) { for (int i = 0; i < global.InitialValue.Length; i++) { Stack[global.Offset + i] = global.InitialValue[i]; } } SP += global.VariableType.NumValues; } SleepTime = 0; if (entrypoint != null) Call(entrypoint); } public void Step() { Step(1000000); } public void Step(int microseconds) { if (ActiveFrame != null) { if (microseconds <= SleepTime) SleepTime -= microseconds; else { RemainingTime = microseconds - SleepTime; SleepTime = 0; try { while (RemainingTime > 0 && ActiveFrame != null) { ActiveFrame.Function.Step(this); } } catch (Exception) { Reset(); throw; } } } } } }