private static unsafe Jsm.ExecutableSegment MakeScript(Operation *operation, UInt16 count) { List <JsmInstruction> instructions = new List <JsmInstruction>(count / 2); LabeledStack stack = new LabeledStack(); LabelBuilder labelBuilder = new LabelBuilder(count); for (Int32 i = 0; i < count; i++) { Jsm.Opcode opcode = operation->Opcode; Int32 parameter = operation->Parameter; operation++; stack.CurrentLabel = i; IJsmExpression expression = Jsm.Expression.TryMake(opcode, parameter, stack); if (expression != null) { stack.Push(expression); continue; } JsmInstruction instruction = JsmInstruction.TryMake(opcode, parameter, stack); if (instruction != null) { labelBuilder.TraceInstruction(i, stack.CurrentLabel, new IndexedInstruction(instructions.Count, instruction)); instructions.Add(instruction); continue; } throw new NotSupportedException(opcode.ToString()); } if (stack.Count != 0) { throw new InvalidProgramException("Stack unbalanced."); } if (!(instructions.First() is LBL)) { throw new InvalidProgramException("Script must start with a label."); } if (!(instructions.Last() is IRET)) { throw new InvalidProgramException("Script must end with a return."); } // Switch from opcodes to instructions HashSet <Int32> labelIndices = labelBuilder.Commit(); // Merge similar instructions instructions = InstructionMerger.Merge(instructions, labelIndices); // Combine instructions to logical blocks IReadOnlyList <Jsm.IJsmControl> controls = Jsm.Control.Builder.Build(instructions); // Arrange instructions by segments and return root return(Jsm.Segment.Builder.Build(instructions, controls)); }
public static JsmInstruction TryMake(Jsm.Opcode opcode, Int32 parameter, IStack <IJsmExpression> stack) { if (Factories.TryGetValue(opcode, out var make)) { return(make(parameter, stack)); } return(null); }
private static IJsmExpression TryMakeInternal(Jsm.Opcode opcode, int param, IStack <IJsmExpression> stack) { switch (opcode) { case Jsm.Opcode.PSHN_L: return(new PSHN_L(param)); case Jsm.Opcode.PSHAC: return(new PSHAC(new Jsm.FieldObjectId(param))); case Jsm.Opcode.PSHI_L: return(new PSHI_L(new ScriptResultId(param))); case Jsm.Opcode.PSHM_B: return(new PSHM_B(new GlobalVariableId <byte>(param))); case Jsm.Opcode.PSHM_W: return(new PSHM_W(new GlobalVariableId <ushort>(param))); case Jsm.Opcode.PSHM_L: return(new PSHM_L(new GlobalVariableId <uint>(param))); case Jsm.Opcode.PSHSM_B: return(new PSHSM_B(new GlobalVariableId <sbyte>(param))); case Jsm.Opcode.PSHSM_W: return(new PSHSM_W(new GlobalVariableId <short>(param))); case Jsm.Opcode.PSHSM_L: return(new PSHSM_L(new GlobalVariableId <int>(param))); case Jsm.Opcode.CAL: return(CAL.Read(param, stack)); //case Opcode.MovieReady: // return new Instruction.MovieReady(stack.Pop(), stack.Pop()); } return(null); }
private static IJsmExpression TryMakeInternal(Jsm.Opcode opcode, Int32 param, IStack <IJsmExpression> stack) { switch (opcode) { case Jsm.Opcode.PSHN_L: return(new PSHN_L(param)); case Jsm.Opcode.PSHAC: return(new PSHAC(new Jsm.FieldObjectId(param))); case Jsm.Opcode.PSHI_L: return(new PSHI_L(new ScriptResultId(param))); case Jsm.Opcode.PSHM_B: return(new PSHM_B(new GlobalVariableId <Byte>(param))); case Jsm.Opcode.PSHM_W: return(new PSHM_W(new GlobalVariableId <UInt16>(param))); case Jsm.Opcode.PSHM_L: return(new PSHM_L(new GlobalVariableId <UInt32>(param))); case Jsm.Opcode.PSHSM_B: return(new PSHSM_B(new GlobalVariableId <SByte>(param))); case Jsm.Opcode.PSHSM_W: return(new PSHSM_W(new GlobalVariableId <Int16>(param))); case Jsm.Opcode.PSHSM_L: return(new PSHSM_L(new GlobalVariableId <Int32>(param))); case Jsm.Opcode.CAL: return(CAL.Read(param, stack)); //case Opcode.MOVIEREADY: // return new Instruction.MOVIEREADY(stack.Pop(), stack.Pop()); } return(null); }
public static IJsmExpression TryMake(Jsm.Opcode opcode, int param, IStack <IJsmExpression> stack) { var result = TryMakeInternal(opcode, param, stack); return(result?.Evaluate(StatelessServices.Instance)); // Simplify the expression }