CLanguage by praeclarum

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

 CInterpreter

public class CInterpreter
using CLanguage.Compiler; using CLanguage.Types; using System; using System.Collections.Generic; using System.Linq; using System.Runtime.CompilerServices; using System.Text; namespace CLanguage.Interpreter { [System.Runtime.CompilerServices.NullableContext(1)] [System.Runtime.CompilerServices.Nullable(0)] public class CInterpreter { private Executable exe; [System.Runtime.CompilerServices.Nullable(2)] private BaseFunction entrypoint; public readonly Value[] Stack; public int SP; private readonly ExecutionFrame[] Frames; private int FI; public int CpuSpeed = 1000; private static readonly BaseFunction unusedStackFrameFunction = new InternalFunction("unused", "", CFunctionType.VoidProcedure); public Executable Executable => exe; public int YieldedValue { get; set; } public int SleepTime { get; set; } public int RemainingTime { get; set; } [System.Runtime.CompilerServices.Nullable(2)] public ExecutionFrame ActiveFrame { [System.Runtime.CompilerServices.NullableContext(2)] get { if (0 > FI || FI >= Frames.Length) return null; return Frames[FI]; } } public int CallStackDepth => 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(unusedStackFrameFunction)).ToArray(); } public Value ReadMemory(int address) { return Stack[address]; } public string ReadStringWithEncoding(int address, Encoding encoding) { byte b = (byte)Stack[address]; List<byte> list = new List<byte>(); while (b != 0) { list.Add(b); address++; b = (byte)Stack[address]; } byte[] array = list.ToArray(); return encoding.GetString(array, 0, array.Length); } public string ReadString(int address) { return ReadStringWithEncoding(address, Encoding.UTF8); } public Value ReadThis() { ExecutionFrame activeFrame = ActiveFrame; if (activeFrame == null) return 0; if (!activeFrame.Function.FunctionType.IsInstance) return 0; int num = -1; int num2 = activeFrame.FP + num; return Stack[num2]; } public Value ReadArg(int index) { ExecutionFrame activeFrame = ActiveFrame; if (activeFrame == null) return 0; CFunctionType functionType = activeFrame.Function.FunctionType; int num; if (index < functionType.Parameters.Count) num = functionType.Parameters[index].Offset; else { if (index != functionType.Parameters.Count || !functionType.IsInstance) throw new ArgumentOutOfRangeException("Cannot read argument #" + index.ToString()); num = -1; } int num2 = activeFrame.FP + num; return Stack[num2]; } 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?.Function.Name ?? "?"; Reset(); throw new ExecutionException("Stack overflow while calling '" + name + "' from '" + text + "'"); } FI++; ExecutionFrame obj = Frames[FI]; obj.Function = function; obj.FP = SP; obj.IP = 0; function.Init(this); } public void Push(Value value) { Stack[SP++] = value; } public void Yield(int yieldedValue) { YieldedValue = yieldedValue; } public void Return() { ExecutionFrame activeFrame = ActiveFrame; if (activeFrame == null) throw new InvalidOperationException("Cannot call Return with no 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 = activeFrame.Function as CompiledFunction; if (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.StackOffset + i] = global.InitialValue[i]; } } SP += global.VariableType.NumValues; } SleepTime = 0; if (entrypoint != null) Call(entrypoint); } public void Run() { Step(1000000); } public static void Run(string code) { CInterpreter cInterpreter = new CInterpreter(CCompiler.Compile(code), 1024, 24); cInterpreter.Reset("main"); cInterpreter.Run(); } [Obsolete("Please use Run() which Steps for 1 machine second.")] 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 { ExecutionFrame activeFrame = ActiveFrame; while (activeFrame != null && RemainingTime > 0) { RemainingTime -= CpuSpeed; activeFrame.Function.Step(this, activeFrame); activeFrame = ActiveFrame; if (YieldedValue != 0) break; } } catch (Exception) { Reset(); throw; } } } } public Value RunFunction(Value functionAddress, int microseconds) { Call(functionAddress); return StepFunction(microseconds); } public Value RunFunction(Value functionAddress, Value arg0, int microseconds) { Push(arg0); Call(functionAddress); return StepFunction(microseconds); } public Value RunFunction(Value functionAddress, Value arg0, Value arg1, int microseconds) { Push(arg0); Push(arg1); Call(functionAddress); return StepFunction(microseconds); } public Value RunFunction(Value functionAddress, Value arg0, Value arg1, Value arg2, int microseconds) { Push(arg0); Push(arg1); Push(arg2); Call(functionAddress); return StepFunction(microseconds); } private Value StepFunction(int microseconds) { if (ActiveFrame == null) return 0; int fI = FI; CType cType = ActiveFrame?.Function.FunctionType.ReturnType; if (microseconds <= SleepTime) SleepTime -= microseconds; else { RemainingTime = microseconds - SleepTime; SleepTime = 0; try { ExecutionFrame activeFrame = ActiveFrame; while (activeFrame != null && FI >= fI && RemainingTime > 0) { RemainingTime -= CpuSpeed; activeFrame.Function.Step(this, activeFrame); activeFrame = ActiveFrame; if (YieldedValue != 0) break; } } catch (Exception) { Reset(); throw; } } while (FI >= fI) { CType cType2 = ActiveFrame?.Function.FunctionType.ReturnType; if (cType2 == null) break; if (!cType2.IsVoid) { int numValues = cType2.NumValues; for (int i = 0; i < numValues; i++) { Stack[SP++] = 0; } } Return(); } Value result = 0; int num = cType?.NumValues ?? 0; for (int j = 0; j < num; j++) { result = Stack[--SP]; } return result; } } }