public void Run(IntermediateOutput code, string function) { SheepFunction?sheepFunction = null; foreach (var f in code.Functions) { if (string.Equals(f.Name, function, StringComparison.OrdinalIgnoreCase)) { sheepFunction = f; break; } } if (sheepFunction.HasValue == false) { throw new Exception("Unknown function"); } SheepContext c = new SheepContext(); c.FullCode = code; c.CodeBuffer = new SheepCodeBuffer(new System.IO.MemoryStream(sheepFunction.Value.Code)); c.FunctionOffset = sheepFunction.Value.CodeOffset; c.InstructionOffset = 0; prepareVariables(c); _context.Push(c); execute(c); _context.Pop(); }
void prepareVariables(SheepContext context) { for (int i = 0; i < context.FullCode.Symbols.Count; i++) { if (context.FullCode.Symbols[i].Type == SheepSymbolType.Int) { context.Variables.Add(new StackItem(SheepSymbolType.Int, context.FullCode.Symbols[i].InitialIntValue)); } else if (context.FullCode.Symbols[i].Type == SheepSymbolType.Float) { context.Variables.Add(new StackItem(SheepSymbolType.Float, context.FullCode.Symbols[i].InitialIntValue)); } else if (context.FullCode.Symbols[i].Type == SheepSymbolType.String) { context.Variables.Add(new StackItem(SheepSymbolType.String, context.FullCode.Symbols[i].InitialStringValue)); } else { throw new Exception("Unsupported variable type"); } } }
void execute(SheepContext context) { context.CodeBuffer.BaseStream.Seek(context.InstructionOffset, System.IO.SeekOrigin.Begin); while (!context.Suspended && context.CodeBuffer.BaseStream.Position < context.CodeBuffer.BaseStream.Length) { if (context.InstructionOffset != context.CodeBuffer.BaseStream.Position) { context.CodeBuffer.BaseStream.Seek(context.InstructionOffset, System.IO.SeekOrigin.Begin); } SheepInstruction instruction = (SheepInstruction)context.CodeBuffer.ReadByte(); context.InstructionOffset++; int iparam1, iparam2; float fparam1, fparam2; switch (instruction) { case SheepInstruction.SitnSpin: break; case SheepInstruction.Yield: throw new NotImplementedException(); case SheepInstruction.CallSysFunctionV: context.InstructionOffset += 4; callVoidFunction(this, context.Stack, context.FullCode.Imports, context.CodeBuffer.ReadInt32()); break; case SheepInstruction.CallSysFunctionI: context.InstructionOffset += 4; callIntFunction(this, context.Stack, context.FullCode.Imports, context.CodeBuffer.ReadInt32()); break; case SheepInstruction.CallSysFunctionF: case SheepInstruction.CallSysFunctionS: throw new NotImplementedException(); case SheepInstruction.Branch: case SheepInstruction.BranchGoto: context.InstructionOffset = context.CodeBuffer.ReadUInt32() - context.FunctionOffset; break; case SheepInstruction.BranchIfZero: if (context.Stack.Peek().Type == SheepSymbolType.Int) { if (context.Stack.Peek().IValue == 0) { context.InstructionOffset = context.CodeBuffer.ReadUInt32() - context.FunctionOffset; } else { context.CodeBuffer.ReadInt32(); // throw it away context.InstructionOffset += 4; } context.Stack.Pop(); } else { throw new Exception("expected integer on stack"); } break; case SheepInstruction.BeginWait: context.InWaitSection = true; break; case SheepInstruction.EndWait: context.InWaitSection = false; // TODO: call end wait callback break; case SheepInstruction.ReturnV: return; case SheepInstruction.StoreI: storeI(context.Stack, context.Variables, context.CodeBuffer.ReadInt32()); context.InstructionOffset += 4; break; case SheepInstruction.StoreF: storeF(context.Stack, context.Variables, context.CodeBuffer.ReadInt32()); context.InstructionOffset += 4; break; case SheepInstruction.StoreS: storeS(context.Stack, context.Variables, context.CodeBuffer.ReadInt32()); context.InstructionOffset += 4; break; case SheepInstruction.LoadI: loadI(context.Stack, context.Variables, context.CodeBuffer.ReadInt32()); context.InstructionOffset += 4; break; case SheepInstruction.LoadF: loadF(context.Stack, context.Variables, context.CodeBuffer.ReadInt32()); context.InstructionOffset += 4; break; case SheepInstruction.LoadS: throw new NotImplementedException(); case SheepInstruction.PushI: context.Stack.Push(new StackItem(SheepSymbolType.Int, context.CodeBuffer.ReadInt32())); context.InstructionOffset += 4; break; case SheepInstruction.PushF: context.Stack.Push(new StackItem(SheepSymbolType.Float, context.CodeBuffer.ReadSingle())); context.InstructionOffset += 4; break; case SheepInstruction.PushS: context.Stack.Push(new StackItem(SheepSymbolType.String, context.CodeBuffer.ReadInt32())); context.InstructionOffset += 4; break; case SheepInstruction.Pop: context.Stack.Pop(); break; case SheepInstruction.AddI: addI(context.Stack); break; case SheepInstruction.AddF: addF(context.Stack); break; case SheepInstruction.SubtractI: subI(context.Stack); break; case SheepInstruction.SubtractF: subF(context.Stack); break; case SheepInstruction.MultiplyI: mulI(context.Stack); break; case SheepInstruction.MultiplyF: mulF(context.Stack); break; case SheepInstruction.DivideI: divI(context.Stack); break; case SheepInstruction.DivideF: divF(context.Stack); break; case SheepInstruction.NegateI: negI(context.Stack); break; case SheepInstruction.NegateF: negF(context.Stack); break; case SheepInstruction.IsEqualI: get2Ints(context.Stack, out iparam1, out iparam2); if (iparam1 == iparam2) { context.Stack.Push(new StackItem(SheepSymbolType.Int, 1)); } else { context.Stack.Push(new StackItem(SheepSymbolType.Int, 0)); } break; case SheepInstruction.IsEqualF: get2Floats(context.Stack, out fparam1, out fparam2); if (fparam1 == fparam2) { context.Stack.Push(new StackItem(SheepSymbolType.Int, 1)); } else { context.Stack.Push(new StackItem(SheepSymbolType.Int, 0)); } break; case SheepInstruction.NotEqualI: get2Ints(context.Stack, out iparam1, out iparam2); if (iparam1 != iparam2) { context.Stack.Push(new StackItem(SheepSymbolType.Int, 1)); } else { context.Stack.Push(new StackItem(SheepSymbolType.Int, 0)); } break; case SheepInstruction.NotEqualF: get2Floats(context.Stack, out fparam1, out fparam2); if (fparam1 != fparam2) { context.Stack.Push(new StackItem(SheepSymbolType.Int, 1)); } else { context.Stack.Push(new StackItem(SheepSymbolType.Int, 0)); } break; case SheepInstruction.IsGreaterI: get2Ints(context.Stack, out iparam1, out iparam2); if (iparam1 > iparam2) { context.Stack.Push(new StackItem(SheepSymbolType.Int, 1)); } else { context.Stack.Push(new StackItem(SheepSymbolType.Int, 0)); } break; case SheepInstruction.IsGreaterF: get2Floats(context.Stack, out fparam1, out fparam2); if (fparam1 > fparam2) { context.Stack.Push(new StackItem(SheepSymbolType.Int, 1)); } else { context.Stack.Push(new StackItem(SheepSymbolType.Int, 0)); } break; case SheepInstruction.IsLessI: get2Ints(context.Stack, out iparam1, out iparam2); if (iparam1 < iparam2) { context.Stack.Push(new StackItem(SheepSymbolType.Int, 1)); } else { context.Stack.Push(new StackItem(SheepSymbolType.Int, 0)); } break; case SheepInstruction.IsLessF: get2Floats(context.Stack, out fparam1, out fparam2); if (fparam1 < fparam2) { context.Stack.Push(new StackItem(SheepSymbolType.Int, 1)); } else { context.Stack.Push(new StackItem(SheepSymbolType.Int, 0)); } break; case SheepInstruction.IsGreaterEqualI: get2Ints(context.Stack, out iparam1, out iparam2); if (iparam1 >= iparam2) { context.Stack.Push(new StackItem(SheepSymbolType.Int, 1)); } else { context.Stack.Push(new StackItem(SheepSymbolType.Int, 0)); } break; case SheepInstruction.IsGreaterEqualF: get2Floats(context.Stack, out fparam1, out fparam2); if (fparam1 >= fparam2) { context.Stack.Push(new StackItem(SheepSymbolType.Int, 1)); } else { context.Stack.Push(new StackItem(SheepSymbolType.Int, 0)); } break; case SheepInstruction.IsLessEqualI: get2Ints(context.Stack, out iparam1, out iparam2); if (iparam1 <= iparam2) { context.Stack.Push(new StackItem(SheepSymbolType.Int, 1)); } else { context.Stack.Push(new StackItem(SheepSymbolType.Int, 0)); } break; case SheepInstruction.IsLessEqualF: get2Floats(context.Stack, out fparam1, out fparam2); if (fparam1 <= fparam2) { context.Stack.Push(new StackItem(SheepSymbolType.Int, 1)); } else { context.Stack.Push(new StackItem(SheepSymbolType.Int, 0)); } break; case SheepInstruction.IToF: itof(context.Stack, context.CodeBuffer.ReadInt32()); context.InstructionOffset += 4; break; case SheepInstruction.FToI: ftoi(context.Stack, context.CodeBuffer.ReadInt32()); context.InstructionOffset += 4; break; case SheepInstruction.And: andi(context.Stack); break; case SheepInstruction.Or: ori(context.Stack); break; case SheepInstruction.Not: noti(context.Stack); break; case SheepInstruction.GetString: if (context.Stack.Peek().Type != SheepSymbolType.String) { throw new Exception("Expected string on stack"); } break; case SheepInstruction.DebugBreakpoint: throw new Exception("DebugBreakpoint instruction not supported yet."); default: throw new Exception("Unknown instruction"); } } }