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)); }
private void FormatBranch(StringBuilder sb, Segment range) { sb.AppendLine("{"); for (Int32 i = range.From + 1; i < range.To; i++) { JsmInstruction instruction = _instructions[i]; sb.Append('\t').AppendLine(instruction.ToString()); } sb.AppendLine("}"); }
public static List <JsmInstruction> Merge(List <JsmInstruction> instructions, HashSet <Int32> labelIndices) { List <JsmInstruction> result = new List <JsmInstruction>(instructions.Count); for (Int32 i = 0; i < instructions.Count; i++) { JsmInstruction instruction = instructions[i]; result.Add(instruction); if (labelIndices.Contains(i)) { continue; } if (!(instructions[i] is JPF newJpf)) { continue; } if (i + 1 < instructions.Count && instructions[i + 1] is JMP nextJmp) { newJpf.Inverse(nextJmp); } if (!(result[result.Count - 2] is JPF oldJpf)) { continue; } if (oldJpf.Index != newJpf.Index) { continue; } Int32 currentIndex = result.LastIndex(); oldJpf.Union(newJpf); result.RemoveLast(); oldJpf.Index--; for (Int32 k = 0; k < instructions.Count; k++) { if (instructions[k] is IJumpToInstruction jmp && jmp.Index >= currentIndex && jmp != oldJpf) { jmp.Index--; } } } return(result); }
public override String ToString() { StringBuilder sb = new StringBuilder(); sb.Append("while("); sb.Append((JPF)_instructions[_segment.From]); sb.AppendLine(")"); sb.AppendLine("{"); for (Int32 i = _segment.From + 1; i < _segment.To; i++) { JsmInstruction instruction = _instructions[i]; sb.Append('\t').AppendLine(instruction.ToString()); } sb.AppendLine("}"); return(base.ToString()); }
public IndexedInstruction(Int32 index, JsmInstruction instruction) { Index = index; Instruction = instruction; }