add: nfa2dfa算法
This commit is contained in:
		@@ -7,7 +7,6 @@
 | 
				
			|||||||
    </PropertyGroup>
 | 
					    </PropertyGroup>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    <ItemGroup>
 | 
					    <ItemGroup>
 | 
				
			||||||
      <Folder Include="Abstractions\" />
 | 
					 | 
				
			||||||
      <None Include="../.gitignore" />
 | 
					      <None Include="../.gitignore" />
 | 
				
			||||||
      <None Include="../.editorconfig" />
 | 
					      <None Include="../.editorconfig" />
 | 
				
			||||||
    </ItemGroup>
 | 
					    </ItemGroup>
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -0,0 +1,91 @@
 | 
				
			|||||||
 | 
					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);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										49
									
								
								CanonSharp.Common/LexicalAnalyzer/EmptyChar.cs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										49
									
								
								CanonSharp.Common/LexicalAnalyzer/EmptyChar.cs
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,49 @@
 | 
				
			|||||||
 | 
					namespace CanonSharp.Common.LexicalAnalyzer;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					public class EmptyChar : IEquatable<EmptyChar>
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    public bool IsEmpty { get; }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    public char Char { get; }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    public static EmptyChar Empty => new();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    private EmptyChar()
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        IsEmpty = true;
 | 
				
			||||||
 | 
					        Char = char.MaxValue;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    public EmptyChar(char c)
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        IsEmpty = false;
 | 
				
			||||||
 | 
					        Char = c;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    public bool Equals(EmptyChar? other)
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        if (other is null)
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            return false;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        if (IsEmpty)
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            return other.IsEmpty;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        return Char == other.Char;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    public override bool Equals(object? obj) => obj is EmptyChar other && Equals(other);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    public override int GetHashCode()
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        return IsEmpty.GetHashCode() ^ Char.GetHashCode();
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    public override string ToString()
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        return IsEmpty ? "ε" : Char.ToString();
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
@@ -0,0 +1,76 @@
 | 
				
			|||||||
 | 
					namespace CanonSharp.Common.LexicalAnalyzer;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					public class NondeterministicState : IEquatable<NondeterministicState>
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    public Guid Id { get; } = Guid.NewGuid();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    public Dictionary<EmptyChar, HashSet<NondeterministicState>> Transactions { get; } = [];
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    public bool Equals(NondeterministicState? other) => other is not null && Id.Equals(other.Id);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    public void AddTransaction(EmptyChar c, NondeterministicState state)
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        if (Transactions.TryGetValue(c, out HashSet<NondeterministicState>? states))
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            states.Add(state);
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        else
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            Transactions.Add(c, [state]);
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    public override bool Equals(object? obj) => obj is NondeterministicState other && Equals(other);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    public override int GetHashCode() => Id.GetHashCode();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    public HashSet<NondeterministicState> CalculateEmptyClosure()
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        HashSet<NondeterministicState> result = [];
 | 
				
			||||||
 | 
					        Queue<NondeterministicState> queue = [];
 | 
				
			||||||
 | 
					        queue.Enqueue(this);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        while (queue.TryDequeue(out NondeterministicState? state))
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            result.Add(state);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            if (!state.Transactions.TryGetValue(EmptyChar.Empty, out HashSet<NondeterministicState>? next))
 | 
				
			||||||
 | 
					            {
 | 
				
			||||||
 | 
					                continue;
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            foreach (NondeterministicState s in next.Where(s => !result.Contains(s)))
 | 
				
			||||||
 | 
					            {
 | 
				
			||||||
 | 
					                queue.Enqueue(s);
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        return result;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					public class NondeterministicStateSet(HashSet<NondeterministicState> states) : IEquatable<NondeterministicStateSet>
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    private readonly HashSet<NondeterministicState> _states = states;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    public bool Equals(NondeterministicStateSet? other)
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        if (other is null)
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            return false;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        return _states.Count == other._states.Count && _states.All(s => other._states.Contains(s));
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    public override bool Equals(object? obj) => obj is NondeterministicStateSet other && Equals(other);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    public override int GetHashCode() => _states.Aggregate(0, (current, state) => current ^ state.GetHashCode());
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					public class NondeterministicFiniteAutomation(NondeterministicState start, HashSet<NondeterministicState> finalStates)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    public NondeterministicState Start { get; } = start;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    public HashSet<NondeterministicState> FinalStates { get; } = finalStates;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										109
									
								
								CanonSharp.Common/LexicalAnalyzer/RegularExpression.cs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										109
									
								
								CanonSharp.Common/LexicalAnalyzer/RegularExpression.cs
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,109 @@
 | 
				
			|||||||
 | 
					namespace CanonSharp.Common.LexicalAnalyzer;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					public abstract class RegularExpression
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    public abstract NondeterministicFiniteAutomation Convert2Nfa();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    public static RegularExpression Empty => new EmptyExpression();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    public static RegularExpression Single(char c) => new SymbolExpression(c);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    public static RegularExpression Alternate(RegularExpression left, RegularExpression right) =>
 | 
				
			||||||
 | 
					        new AlternationExpression(left, right);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    public static RegularExpression Concatenate(RegularExpression first, RegularExpression second) =>
 | 
				
			||||||
 | 
					        new ConcatenationExpression(first, second);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    public static RegularExpression Kleene(RegularExpression inner) => new KleeneExpression(inner);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					public class EmptyExpression : RegularExpression
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    public override NondeterministicFiniteAutomation Convert2Nfa()
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        NondeterministicState final = new();
 | 
				
			||||||
 | 
					        NondeterministicState start = new();
 | 
				
			||||||
 | 
					        start.AddTransaction(EmptyChar.Empty, final);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        return new NondeterministicFiniteAutomation(start, [final]);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					public class SymbolExpression(char symbol) : RegularExpression
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    public char Symbol { get; } = symbol;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    public override NondeterministicFiniteAutomation Convert2Nfa()
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        NondeterministicState final = new();
 | 
				
			||||||
 | 
					        NondeterministicState start = new();
 | 
				
			||||||
 | 
					        start.AddTransaction(new EmptyChar(Symbol), final);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        return new NondeterministicFiniteAutomation(start, [final]);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					public class AlternationExpression(RegularExpression left, RegularExpression right) : RegularExpression
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    public RegularExpression Left { get; } = left;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    public RegularExpression Right { get; } = right;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    public override NondeterministicFiniteAutomation Convert2Nfa()
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        NondeterministicFiniteAutomation left = Left.Convert2Nfa();
 | 
				
			||||||
 | 
					        NondeterministicFiniteAutomation right = Right.Convert2Nfa();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        NondeterministicState final = new();
 | 
				
			||||||
 | 
					        foreach (NondeterministicState state in left.FinalStates.Concat(right.FinalStates))
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            state.AddTransaction(EmptyChar.Empty, final);
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        NondeterministicState start = new();
 | 
				
			||||||
 | 
					        start.AddTransaction(EmptyChar.Empty, left.Start);
 | 
				
			||||||
 | 
					        start.AddTransaction(EmptyChar.Empty, right.Start);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        return new NondeterministicFiniteAutomation(start, [final]);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					public class ConcatenationExpression(RegularExpression first, RegularExpression second) : RegularExpression
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    public RegularExpression First { get; } = first;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    public RegularExpression Second { get; } = second;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    public override NondeterministicFiniteAutomation Convert2Nfa()
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        NondeterministicFiniteAutomation first = First.Convert2Nfa();
 | 
				
			||||||
 | 
					        NondeterministicFiniteAutomation second = Second.Convert2Nfa();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        foreach (NondeterministicState state in first.FinalStates)
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            state.AddTransaction(EmptyChar.Empty, second.Start);
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        return new NondeterministicFiniteAutomation(first.Start, second.FinalStates);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					public class KleeneExpression(RegularExpression inner) : RegularExpression
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    public RegularExpression Inner { get; } = inner;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    public override NondeterministicFiniteAutomation Convert2Nfa()
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        NondeterministicFiniteAutomation inner = Inner.Convert2Nfa();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        NondeterministicState final = new();
 | 
				
			||||||
 | 
					        final.AddTransaction(EmptyChar.Empty, inner.Start);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        foreach (NondeterministicState state in inner.FinalStates)
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            state.AddTransaction(EmptyChar.Empty, final);
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        return new NondeterministicFiniteAutomation(final, [final]);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
@@ -5,9 +5,4 @@
 | 
				
			|||||||
    <GenerateDocumentationFile>true</GenerateDocumentationFile>
 | 
					    <GenerateDocumentationFile>true</GenerateDocumentationFile>
 | 
				
			||||||
  </PropertyGroup>
 | 
					  </PropertyGroup>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  <ItemGroup>
 | 
					 | 
				
			||||||
    <Compile Include="LexicalAnalyzer\RegularExpression.fs" />
 | 
					 | 
				
			||||||
    <Compile Include="LexicalAnalyzer\NondeterministicFiniteAutomation.fs" />
 | 
					 | 
				
			||||||
  </ItemGroup>
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
</Project>
 | 
					</Project>
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1,38 +0,0 @@
 | 
				
			|||||||
module CanonSharp.Parser.LexicalAnalyzer.NondeterministicFiniteAutomation
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
open System
 | 
					 | 
				
			||||||
open System.Collections.Generic
 | 
					 | 
				
			||||||
open CanonSharp.Parser.LexicalAnalyzer.RegularExpression
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
type NondeterministicState(id: Guid, transaction: Option<char> -> list<NondeterministicState>) =
 | 
					 | 
				
			||||||
    member val id = id
 | 
					 | 
				
			||||||
    member val transaction = transaction
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    override this.GetHashCode() = this.id.GetHashCode()
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    new() = NondeterministicState(Guid.NewGuid(), fun a -> list.Empty)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
type NondeterministicFiniteAutomation(states: HashSet<NondeterministicState>, entryTransaction: Option<char> -> list<NondeterministicState>) =
 | 
					 | 
				
			||||||
    member val states = states
 | 
					 | 
				
			||||||
    member val entryTransaction = entryTransaction
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
let convertEmptyToNonDeterministicFiniteAutomation (expression: EmptyExpression) =
 | 
					 | 
				
			||||||
    let final = NondeterministicState()
 | 
					 | 
				
			||||||
    let transaction (a: Option<char>) =
 | 
					 | 
				
			||||||
        match a with
 | 
					 | 
				
			||||||
        | Some _ -> list.Empty
 | 
					 | 
				
			||||||
        | None -> [final]
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    let states = HashSet()
 | 
					 | 
				
			||||||
    let _ = states.Add(final)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    NondeterministicFiniteAutomation(states, transaction)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
let convertToNondeterministicFiniteAutomation expression: RegularExpression =
 | 
					 | 
				
			||||||
    match expression with
 | 
					 | 
				
			||||||
        | EmptyExpression ->
 | 
					 | 
				
			||||||
@@ -1,12 +0,0 @@
 | 
				
			|||||||
module CanonSharp.Parser.LexicalAnalyzer.RegularExpression
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
type RegularExpression =
 | 
					 | 
				
			||||||
    | EmptyExpression
 | 
					 | 
				
			||||||
    | SymbolExpression of symbol: char
 | 
					 | 
				
			||||||
    | AlternationExpression of left: RegularExpression * right : RegularExpression
 | 
					 | 
				
			||||||
    | ConcatenationExpression of first: RegularExpression * second : RegularExpression
 | 
					 | 
				
			||||||
    | KleeneExpression of expression: RegularExpression
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
let convertToNondeterministicFiniteAutomation expression =
 | 
					 | 
				
			||||||
    match expression with
 | 
					 | 
				
			||||||
    | EmptyExpression emptyExpression ->
 | 
					 | 
				
			||||||
@@ -0,0 +1,77 @@
 | 
				
			|||||||
 | 
					using CanonSharp.Common.LexicalAnalyzer;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					namespace CanonSharp.Tests.LexicalAnalyzerTests;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					public class RegularExpressionTests
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    [Fact]
 | 
				
			||||||
 | 
					    public void KleeneTest()
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        RegularExpression expression = RegularExpression.Concatenate(
 | 
				
			||||||
 | 
					            RegularExpression.Kleene(RegularExpression.Single('a')),
 | 
				
			||||||
 | 
					            RegularExpression.Single('b'));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        NondeterministicFiniteAutomation automation = expression.Convert2Nfa();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        automation.Start.Transactions.TryGetValue(EmptyChar.Empty, out HashSet<NondeterministicState>? next);
 | 
				
			||||||
 | 
					        Assert.NotNull(next);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        Assert.Contains(next, s => s.Transactions.ContainsKey(new EmptyChar('a')));
 | 
				
			||||||
 | 
					        Assert.Contains(next, s => s.Transactions.ContainsKey(new EmptyChar('b')));
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    [Fact]
 | 
				
			||||||
 | 
					    public void AlternateTest()
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        RegularExpression expression = RegularExpression.Alternate(
 | 
				
			||||||
 | 
					            RegularExpression.Kleene(RegularExpression.Single('a')),
 | 
				
			||||||
 | 
					            RegularExpression.Single('b'));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        NondeterministicFiniteAutomation automation = expression.Convert2Nfa();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        automation.Start.Transactions.TryGetValue(EmptyChar.Empty, out HashSet<NondeterministicState>? next);
 | 
				
			||||||
 | 
					        Assert.NotNull(next);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        Assert.Contains(next, s => s.Transactions.ContainsKey(new EmptyChar('b')));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        NondeterministicState? state = (from item in next
 | 
				
			||||||
 | 
					            where item.Transactions[EmptyChar.Empty].Count == 2
 | 
				
			||||||
 | 
					            select item).FirstOrDefault();
 | 
				
			||||||
 | 
					        Assert.NotNull(state);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        Assert.Contains(state.Transactions[EmptyChar.Empty],
 | 
				
			||||||
 | 
					            s => s.Transactions.ContainsKey(new EmptyChar('a')));
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    [Fact]
 | 
				
			||||||
 | 
					    public void ConvertTest()
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        RegularExpression expression = RegularExpression.Alternate(
 | 
				
			||||||
 | 
					            RegularExpression.Kleene(RegularExpression.Single('a')),
 | 
				
			||||||
 | 
					            RegularExpression.Single('b'));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        NondeterministicFiniteAutomation automation = expression.Convert2Nfa();
 | 
				
			||||||
 | 
					        DeterministicFiniteAutomation dfa = DeterministicFiniteAutomation.Create(automation);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        DeterministicState state2 = dfa.Start.Transaction['a'];
 | 
				
			||||||
 | 
					        Assert.Equal(state2, state2.Transaction['a']);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        DeterministicState state3 = dfa.Start.Transaction['b'];
 | 
				
			||||||
 | 
					        Assert.Empty(state3.Transaction);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        Assert.Equal(3, dfa.FinalStates.Count);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    [Fact]
 | 
				
			||||||
 | 
					    public void NondeterministicStateSetTest()
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        Dictionary<NondeterministicStateSet, char> map = [];
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        NondeterministicState key1 = new();
 | 
				
			||||||
 | 
					        NondeterministicState key2 = new();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        map.Add(new NondeterministicStateSet([key1, key2]), 'a');
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        Assert.Equal('a', map[new NondeterministicStateSet([key2, key1])]);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
		Reference in New Issue
	
	Block a user