92 lines
3.2 KiB
C#
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);
|
|
}
|
|
}
|