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;
}
}
}
}
}
}