public static PacmanValue Ret(int address, PacmanEnvironmentFrame environmentFrame, int profileAddress) { return new PacmanValue(PacmanTag.Ret) { IntValue = address, EnvironmentFrameValue = environmentFrame, ProfileAddress = profileAddress }; }
private static PacmanEnvironmentFrame GetEnvironmentFrame( PacmanEnvironmentFrame currentEnvironmentFrame, int n) { var ans = currentEnvironmentFrame; for (var i = 0; i < n; ++i) { ans = ans.Parent; } if (!ans.IsValid) { throw new Exception(); // TODO } return ans; }
public static PacmanValue Closure(int address, PacmanEnvironmentFrame environmentFrame) { return new PacmanValue(PacmanTag.Closure) { IntValue = address, EnvironmentFrameValue = environmentFrame }; }
private static PacmanValue ExecuteAi( List<PacmanInstruction> code, int pc, PacmanEnvironmentFrame initialEnvironmentFrame, int tick) { const bool PROFILE = false; var iter = 0; var dataStack = new List<PacmanValue>(); var controlStack = new List<PacmanValue>() { new PacmanValue(PacmanTag.Stop) }; var currentEnvironmentFrame = initialEnvironmentFrame; var profileData = new Dictionary<string, int>(); var funcCallData = new Dictionary<int, int>(); while (true) { if (PROFILE) { var profileKey = string.Join(", ", controlStack .Where(i => i.Tag == PacmanTag.Ret) .Select(i => i.ProfileAddress.ToString()) .LastOrDefault()); int profileValue; profileData.TryGetValue(profileKey, out profileValue); profileData[profileKey] = profileValue + 1; } ++iter; PacmanValue xx, yy; PacmanEnvironmentFrame frame, newFrame; PacmanInstruction inst = code[pc]; int funcCallDataValue; switch (inst.Opcode) { case PacmanOpcode.Ldc: dataStack.Add(PacmanValue.Int(inst.Operands[0])); ++pc; break; case PacmanOpcode.Ld: frame = GetEnvironmentFrame(currentEnvironmentFrame, inst.Operands[0]); dataStack.Add(frame.Values[inst.Operands[1]]); ++pc; break; case PacmanOpcode.Add: DoMath(dataStack, (x, y) => x + y); ++pc; break; case PacmanOpcode.Sub: DoMath(dataStack, (x, y) => x - y); ++pc; break; case PacmanOpcode.Mul: DoMath(dataStack, (x, y) => x * y); ++pc; break; case PacmanOpcode.Div: DoMath(dataStack, (x, y) => (int)Math.Floor((double)x / (double)y)); ++pc; break; case PacmanOpcode.Ceq: DoMath(dataStack, (x, y) => x == y ? 1 : 0); ++pc; break; case PacmanOpcode.Cgt: DoMath(dataStack, (x, y) => x > y ? 1 : 0); ++pc; break; case PacmanOpcode.Cgte: DoMath(dataStack, (x, y) => x >= y ? 1 : 0); ++pc; break; case PacmanOpcode.Atom: xx = dataStack.Pop(); dataStack.Add(PacmanValue.Int(xx.Tag == PacmanTag.Int ? 1 : 0)); ++pc; break; case PacmanOpcode.Cons: yy = dataStack.Pop(); xx = dataStack.Pop(); dataStack.Add(PacmanValue.Cons(xx, yy)); ++pc; break; case PacmanOpcode.Car: xx = dataStack.Pop(); xx.VerifyTag(PacmanTag.Cons); dataStack.Add(xx.Item1); ++pc; break; case PacmanOpcode.Cdr: xx = dataStack.Pop(); xx.VerifyTag(PacmanTag.Cons); dataStack.Add(xx.Item2); ++pc; break; case PacmanOpcode.Sel: case PacmanOpcode.Tsel: xx = dataStack.Pop(); xx.VerifyTag(PacmanTag.Int); if (inst.Opcode == PacmanOpcode.Sel) { controlStack.Add(PacmanValue.Join(pc + 1)); } pc = xx.IntValue == 0 ? inst.Operands[1] : inst.Operands[0]; break; case PacmanOpcode.Join: xx = controlStack.Pop(); xx.VerifyTag(PacmanTag.Join); pc = xx.IntValue; break; case PacmanOpcode.Ldf: dataStack.Add(PacmanValue.Closure(inst.Operands[0], currentEnvironmentFrame)); ++pc; break; case PacmanOpcode.Tap: case PacmanOpcode.Ap: xx = dataStack.Pop(); xx.VerifyTag(PacmanTag.Closure); newFrame = new PacmanEnvironmentFrame() { Parent = currentEnvironmentFrame, IsValid = true, Values = new List<PacmanValue>() }; for (var i = 0; i < inst.Operands[0]; ++i) { newFrame.Values.Add(dataStack.Pop()); } newFrame.Values.Reverse(); if (inst.Opcode == PacmanOpcode.Ap) { controlStack.Add(PacmanValue.Ret(pc + 1, currentEnvironmentFrame, xx.IntValue)); if (PROFILE) { funcCallData.TryGetValue(xx.IntValue, out funcCallDataValue); funcCallData[xx.IntValue] = funcCallDataValue + 1; } } currentEnvironmentFrame = newFrame; pc = xx.IntValue; break; case PacmanOpcode.Rtn: xx = controlStack.Pop(); if (xx.Tag == PacmanTag.Stop) { Program.LogDebug(tick, "iters = {0}", iter); if (PROFILE) { Program.LogProfileInfo(tick, profileData, funcCallData); } return dataStack.Pop(); } xx.VerifyTag(PacmanTag.Ret); pc = xx.IntValue; currentEnvironmentFrame = xx.EnvironmentFrameValue; break; case PacmanOpcode.Dum: newFrame = new PacmanEnvironmentFrame() { Parent = currentEnvironmentFrame, IsValid = false, Values = new List<PacmanValue>() }; for (var i = 0; i < inst.Operands[0]; ++i) { newFrame.Values.Add(null); } currentEnvironmentFrame = newFrame; ++pc; break; case PacmanOpcode.Rap: case PacmanOpcode.Trap: xx = dataStack.Pop(); xx.VerifyTag(PacmanTag.Closure); newFrame = xx.EnvironmentFrameValue; if (newFrame.IsValid || newFrame.Values.Count != inst.Operands[0] || currentEnvironmentFrame != newFrame) { throw new Exception(); // TODO } newFrame.Values.Clear(); for (var i = 0; i < inst.Operands[0]; ++i) { newFrame.Values.Add(dataStack.Pop()); } newFrame.Values.Reverse(); if (inst.Opcode == PacmanOpcode.Rap) { controlStack.Add(PacmanValue.Ret(pc + 1, currentEnvironmentFrame.Parent, xx.IntValue)); if (PROFILE) { funcCallData.TryGetValue(xx.IntValue, out funcCallDataValue); funcCallData[xx.IntValue] = funcCallDataValue + 1; } } newFrame.IsValid = true; currentEnvironmentFrame = newFrame; pc = xx.IntValue; break; case PacmanOpcode.Stop: return dataStack.Pop(); case PacmanOpcode.St: frame = GetEnvironmentFrame(currentEnvironmentFrame, inst.Operands[0]); xx = dataStack.Pop(); frame.Values[inst.Operands[1]] = xx; ++pc; break; case PacmanOpcode.Dbug: xx = dataStack.Pop(); Program.LogDebug(tick, "DBUG: '{0}'", xx); ++pc; break; case PacmanOpcode.Brk: ++pc; break; default: throw new Exception(); // TODO } } }