CanonSharp/CanonSharp.Common/LexicalAnalyzer/DeterministicFiniteAutomation.cs
jackfiled 3c0d51cec5 feat: 正则词法识别器 (#1)
Reviewed-on: https://git.bupt-hpc.cn/jackfiled/CanonSharp/pulls/1
Co-authored-by: jackfiled <xcrenchangjun@outlook.com>
Co-committed-by: jackfiled <xcrenchangjun@outlook.com>
2024-07-29 16:59:29 +08:00

97 lines
3.4 KiB
C#

namespace CanonSharp.Common.LexicalAnalyzer;
public class DeterministicState(HashSet<NondeterministicState> closure) : IEquatable<DeterministicState>
{
public Guid Id { get; } = Guid.NewGuid();
public Dictionary<char, DeterministicState> Transaction { get; } = [];
public HashSet<NondeterministicState> Closure { get; } = closure;
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);
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);
}
else
{
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(transaction.Value);
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);
}
}