private bool Analyze(OptimizationContext context, NdState initialState) { var processed = new List <NdState> [context.Count]; for (var i = 0; i < processed.Length; i++) { processed[i] = new List <NdState>(); } var overflowProtection = 0; var stack = new Stack <NdState>(); stack.Push(initialState); while (stack.Count > 0) { if (stack.Count > context.Count) { // Bailout if stack starts to explode return(false); } else if (overflowProtection++ >= context.Count * 250) { // Or if we're just taking too long return(false); } var current = stack.Pop(); if (current.AAndBAreSameState() || !validPositionsForB[current.PositionB] || processed[current.PositionA].Any(item => current.PracticallyEquivalent(item, context, stack))) { // Already processed this state. continue; } processed[current.PositionA].Add(current); NdStateView view; if (current.AdvancesB < current.AdvancesA || context[current.PositionA].Matches(InstructionType.Return)) { view = current.B; } else { view = current.A; } if (!Step(context, stack, view, current)) { return(false); } } return(true); }
// TODO: Not used anywhere public NdAnalyzer(OptimizationContext context, int posA, int posB, ushort variable) { this.Variable = variable; var graphs = CreateVariableUsageGraphs(context); var initialState = new NdState(Variable, graphs, context.VariableAllocator, posA, posB); validPositionsForB = CalculatePositionsWhereBMightHaveBeen(context, posA, variable); var bounds = context.Backtracer.GetBoundsAt(posB, false); initialState = initialState .SetMinBounds(bounds.MinBounds) .SetMaxBounds(bounds.MaxBounds); Result = Analyze(context, initialState); }
private bool Step(OptimizationContext context, Stack <NdState> stack, NdStateView view, NdState state) { var instruction = context[view.Position]; switch (instruction.Type) { case InstructionType.BoundsCheck: switch (state.CheckBounds(instruction.Offset + view.Advances)) { case EvaluationResult.Success: stack.Push(view.Move(1)); break; case EvaluationResult.Fail: stack.Push(view.WithPosition(context.GetLabelPosition(instruction.Label))); break; case EvaluationResult.Inconclusive: stack.Push(view.Move(1).SetMinBounds(instruction.Offset + view.Advances)); stack.Push(view.WithPosition(context.GetLabelPosition(instruction.Label)).SetMaxBounds(instruction.Offset + view.Advances)); break; } break; case InstructionType.Char: switch (state.CheckChars(context, instruction, instruction.Offset + view.Advances)) { case EvaluationResult.Success: stack.Push(view.Move(1)); break; case EvaluationResult.Fail: stack.Push(view.WithPosition(context.GetLabelPosition(instruction.Label))); break; case EvaluationResult.Inconclusive: stack.Push(view.Move(1).MatchSuccess(context, instruction, instruction.Offset + view.Advances)); stack.Push(view.WithPosition(context.GetLabelPosition(instruction.Label)).MatchFail(context, instruction, instruction.Offset + view.Advances)); break; } break; case InstructionType.Jump: stack.Push(view.WithPosition(context.GetLabelPosition(instruction.Label))); break; case InstructionType.Call: return(false); case InstructionType.Advance: if (instruction.Offset < 0) { return(false); } stack.Push(view.AdvanceAndMoveOneForward(instruction.Offset)); break; case InstructionType.StorePosition: stack.Push(view.StoreAndMoveOneForward(instruction.Data1)); break; case InstructionType.RestorePosition: if (view.Vars[instruction.Data1] == -1) { return(false); } stack.Push(view.WithAdvancesAndMoveOneForward(view.Vars[instruction.Data1])); break; case InstructionType.MarkLabel: case InstructionType.Capture: if (instruction.Data2 != Variable) { return(false); } break; case InstructionType.Return: stack.Push(state); break; default: throw new NotImplementedException(); } return(true); }
public ViewB(NdState state) { this.state = state; }
public bool PracticallyEquivalent(NdState other, OptimizationContext context, Stack <NdState> stack) { var diff = AdvancesB - other.AdvancesB; if (PositionA == other.PositionA && PositionB == other.PositionB && AdvancesA - other.AdvancesA == AdvancesB - other.AdvancesB && ((MinBounds == -1 && other.MinBounds == -1) || (MinBounds == other.MinBounds + diff)) && ((MaxBounds == int.MaxValue && other.MaxBounds == int.MaxValue) || (MaxBounds == other.MaxBounds + diff)) && MatchingCharacters.Count >= other.MatchingCharacters.Count && FailingCharacters.Count >= other.FailingCharacters.Count) { for (var i = 0; i < VarAs.Length; i++) { if (VarAs[i] != other.VarAs[i] && VarAs[i] != other.VarAs[i] + diff) { return(false); } } for (var i = 0; i < VarBs.Length; i++) { if (VarBs[i] != other.VarBs[i] && VarBs[i] != other.VarBs[i] + diff) { return(false); } } var newState = new Lazy <NdState>(() => new NdState(other.Variable, other.Vug, other.PositionA, other.PositionB, other.AdvancesA, other.AdvancesB, other.MinBounds, other.MaxBounds, other.VarAs, other.VarBs, other.MatchingCharacters.Clone(), other.FailingCharacters.Clone())); var addAdditionalCondition = false; // TODO: Check that this has at least every match / fail that other has too. for (var i = 0; i < other.MatchingCharacters.Count; i++) { for (var j = 0; j < other.MatchingCharacters[i].Count; j++) { var current = other.MatchingCharacters[i][j]; if (!MatchingCharacters[i].Any(item => item.Data1 == current.Data1 && item.Data2 == current.Data2)) { if (diff == 0) { return(false); } addAdditionalCondition = true; newState.Value.MatchingCharacters[i] = newState.Value.MatchingCharacters[i].Where(item => item != current).ToList(); } } } for (var i = 0; i < other.FailingCharacters.Count; i++) { for (var j = 0; j < other.FailingCharacters[i].Count; j++) { var current = other.FailingCharacters[i][j]; if (!FailingCharacters[i].Any(item => item.Data1 == current.Data1 && item.Data2 == current.Data2)) { if (diff == 0) { return(false); } addAdditionalCondition = true; newState.Value.FailingCharacters[i] = newState.Value.FailingCharacters[i].Where(item => item != current).ToList(); } } } if (addAdditionalCondition) { stack.Push(newState.Value); } return(true); } return(false); }