CanonSharp/CanonSharp.Common/LexicalAnalyzer/DeterministicFiniteAutomation.cs

97 lines
3.4 KiB
C#
Raw Normal View History

2024-07-27 14:56:28 +08:00
namespace CanonSharp.Common.LexicalAnalyzer;
public class DeterministicState(HashSet<NondeterministicState> closure) : IEquatable<DeterministicState>
2024-07-27 14:56:28 +08:00
{
public Guid Id { get; } = Guid.NewGuid();
public Dictionary<char, DeterministicState> Transaction { get; } = [];
public HashSet<NondeterministicState> Closure { get; } = closure;
2024-07-27 14:56:28 +08:00
public bool Equals(DeterministicState? other) => other is not null && Id.Equals(other.Id);
public override bool Equals(object? obj) => obj is DeterministicState other && Equals(other);
public override int GetHashCode() => Id.GetHashCode();
}
public class DeterministicFiniteAutomation
{
public DeterministicState Start { get; }
public HashSet<DeterministicState> FinalStates { get; }
private DeterministicFiniteAutomation(DeterministicState start, HashSet<DeterministicState> finalStates)
{
Start = start;
FinalStates = finalStates;
}
private record Pair(HashSet<NondeterministicState> States, DeterministicState State);
public static DeterministicFiniteAutomation Create(NondeterministicFiniteAutomation nfa)
{
Dictionary<NondeterministicStateSet, DeterministicState> map = [];
HashSet<DeterministicState> visited = [];
Queue<Pair> queue = [];
HashSet<DeterministicState> finalStates = [];
HashSet<NondeterministicState> startClosure = nfa.Start.CalculateEmptyClosure();
DeterministicState start = new(startClosure);
2024-07-27 14:56:28 +08:00
map.Add(new NondeterministicStateSet(startClosure), start);
queue.Enqueue(new Pair(startClosure, start));
while (queue.TryDequeue(out Pair? pair))
{
if (pair.States.Any(s => nfa.FinalStates.Contains(s)))
{
finalStates.Add(pair.State);
}
Dictionary<char, HashSet<NondeterministicState>> next = [];
foreach (NondeterministicState state in pair.States)
{
foreach (KeyValuePair<EmptyChar, HashSet<NondeterministicState>> transaction in
2024-07-27 14:56:28 +08:00
state.Transactions.Where(p => !p.Key.IsEmpty))
{
HashSet<NondeterministicState> closure = [];
foreach (NondeterministicState s in transaction.Value)
{
closure.UnionWith(s.CalculateEmptyClosure());
}
if (next.TryGetValue(transaction.Key.Char, out HashSet<NondeterministicState>? n))
{
n.UnionWith(closure);
}
else
{
next.Add(transaction.Key.Char, closure);
}
2024-07-27 14:56:28 +08:00
}
}
foreach (KeyValuePair<char, HashSet<NondeterministicState>> transaction in next)
2024-07-27 14:56:28 +08:00
{
NondeterministicStateSet set = new(transaction.Value);
if (!map.TryGetValue(set, out DeterministicState? nextState))
{
nextState = new DeterministicState(transaction.Value);
2024-07-27 14:56:28 +08:00
map.Add(set, nextState);
}
pair.State.Transaction.Add(transaction.Key, nextState);
if (visited.Add(nextState))
{
queue.Enqueue(new Pair(transaction.Value, nextState));
}
}
}
return new DeterministicFiniteAutomation(start, finalStates);
}
}