CanonSharp/CanonSharp.Common/LexicalAnalyzer/DeterministicFiniteAutomation.cs
2024-07-27 14:56:28 +08:00

92 lines
3.2 KiB
C#

namespace CanonSharp.Common.LexicalAnalyzer;
public class DeterministicState : IEquatable<DeterministicState>
{
public Guid Id { get; } = Guid.NewGuid();
public Dictionary<char, DeterministicState> Transaction { get; } = [];
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();
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
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);
}
next.Add(transaction.Key.Char, closure);
}
}
foreach (KeyValuePair<char,HashSet<NondeterministicState>> transaction in next)
{
NondeterministicStateSet set = new(transaction.Value);
if (!map.TryGetValue(set, out DeterministicState? nextState))
{
nextState = new DeterministicState();
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);
}
}