207 lines
7.0 KiB
C#
207 lines
7.0 KiB
C#
using System;
|
|
using System.Collections.Generic;
|
|
using System.ComponentModel;
|
|
using System.Linq;
|
|
using System.Text;
|
|
using System.Threading.Tasks;
|
|
|
|
namespace CompilerDesignIFlr1
|
|
{
|
|
internal class LR1Closure
|
|
{
|
|
internal static int GlobalIndex = 0;
|
|
internal int Index = 0;
|
|
internal LR1Creator LR1Creator;
|
|
internal HashSet<LR1Unit> Units { get; set; } = [];
|
|
internal Dictionary<string, int> Next { get; set; } = [];
|
|
|
|
internal LR1Closure(LR1Creator lr1Creator)
|
|
{
|
|
LR1Creator = lr1Creator;
|
|
Index = GlobalIndex++;
|
|
}
|
|
|
|
internal LR1Closure(LR1Creator lr1Creator, List<LR1Unit> units)
|
|
{
|
|
Units.UnionWith(units);
|
|
Index = GlobalIndex++;
|
|
LR1Creator = lr1Creator;
|
|
AddMissingUnits();
|
|
CalculateProspects();
|
|
}
|
|
|
|
internal void CalculateProspects()
|
|
{
|
|
//Queue<LR1Unit> queue = [];
|
|
//var startUnit = Units.Where(x=>x.Name == LR1Creator.StartSymbol).First();
|
|
//startUnit.Prospect.Add("End");
|
|
|
|
//queue.Enqueue(startUnit);
|
|
//while (queue.Count > 0)
|
|
//{
|
|
// var unit = queue.Dequeue();
|
|
// var left = unit.Name;
|
|
// var units = UnitsHaveDotBefore(left);
|
|
// var next = unit.Next();
|
|
// if (next is not null && !LR1Creator.TokenUnit.ContainsKey(next))
|
|
// foreach (var item in Units.Where(x => x.Name == next))
|
|
// queue.Enqueue(item);
|
|
// HashSet<string> prospect = units
|
|
// .Select(x => GetProspectsOf(x))
|
|
// .Aggregate(
|
|
// new HashSet<string>(),
|
|
// (set, x) =>
|
|
// {
|
|
// set.UnionWith(x);
|
|
// return set;
|
|
// }
|
|
// );
|
|
// unit.Prospect.UnionWith(prospect);
|
|
//}
|
|
|
|
bool haveChange = true;
|
|
while (haveChange)
|
|
{
|
|
haveChange = false;
|
|
foreach (var unit in Units)
|
|
{
|
|
var left = unit.Name;
|
|
var units = UnitsHaveDotBefore(left);
|
|
HashSet<string> prospect = units
|
|
.Select(x => GetProspectsOf(x))
|
|
.Aggregate(
|
|
unit.Prospect,
|
|
(set, x) =>
|
|
{
|
|
set.UnionWith(x);
|
|
return set;
|
|
}
|
|
);
|
|
if (!prospect.IsSubsetOf(unit.Prospect))
|
|
haveChange = true;
|
|
unit.Prospect.UnionWith(prospect);
|
|
}
|
|
}
|
|
}
|
|
|
|
internal List<LR1Unit> UnitsHaveDotBefore(string name)
|
|
{
|
|
List<LR1Unit> res = [];
|
|
foreach (LR1Unit unit in Units)
|
|
{
|
|
if (unit.Next() == name)
|
|
res.Add(unit);
|
|
}
|
|
return res;
|
|
}
|
|
// 对于文法 X => yz...
|
|
// 该方法返回 A => .XB 中的B 以及B可能为空时其后的元素
|
|
internal List<string> GetProspectsOf(LR1Unit unit)
|
|
{
|
|
if (unit.Name == LR1Creator.StartSymbol)
|
|
return ["End"];
|
|
//if(unit.Prospect.Count != 0)
|
|
//{
|
|
// throw new Exception("有环???");
|
|
//}
|
|
|
|
List<string> ans = unit.PointPosition + 1 == unit.Grammar.Count ? [.. unit.Prospect] : [];
|
|
for (int i = unit.PointPosition + 1; i < unit.Grammar.Count; i++)
|
|
{
|
|
var units = LR1Creator.GetUnits(unit.Grammar[i]);
|
|
ans.AddRange(LR1Creator.FirstGroup[unit.Grammar[i]]);
|
|
if (units.All(x => !x.Nullable()))
|
|
break;
|
|
else if (i == unit.Grammar.Count - 1)
|
|
ans.AddRange(unit.Prospect);
|
|
}
|
|
return ans;
|
|
}
|
|
internal void AddMissingUnits()
|
|
{
|
|
bool haveNew = true;
|
|
while (haveNew)
|
|
{
|
|
HashSet<LR1Unit> addingUnits = [];
|
|
haveNew = false;
|
|
foreach (LR1Unit unit in Units)
|
|
{
|
|
string? next = unit.Next();
|
|
if (next is null)
|
|
continue;
|
|
if (LR1Creator.GrammarUnit.TryGetValue(next, out var value))
|
|
{
|
|
var set = new HashSet<LR1Unit>(value.Select(x => x.Clone()));
|
|
if (set.IsSubsetOf(Units))
|
|
continue;
|
|
haveNew = true;
|
|
addingUnits.UnionWith(set);
|
|
}
|
|
}
|
|
Units.UnionWith(addingUnits);
|
|
}
|
|
}
|
|
internal List<LR1Closure> NextClosures()
|
|
{
|
|
List<LR1Closure> ans = [];
|
|
Dictionary<string, List<LR1Unit>> nextSteps = [];
|
|
foreach(LR1Unit unit in Units)
|
|
{
|
|
string? next = unit.Next();
|
|
if (next is null)
|
|
continue;
|
|
if (nextSteps.TryGetValue(next, out var units))
|
|
units.Add(unit);
|
|
else
|
|
nextSteps.Add(next, [unit]);
|
|
}
|
|
foreach(var (next,value) in nextSteps)
|
|
{
|
|
var closure = new LR1Closure(LR1Creator, value.Select(x => x.ToNext()).ToList());
|
|
var existClosure = LR1Creator.Closures.Values.Where(x => x.Equals(closure)).FirstOrDefault();
|
|
if(existClosure is not null)
|
|
{
|
|
LR1Closure.GlobalIndex--;
|
|
Next.Add(next,existClosure.Index);
|
|
continue;
|
|
}
|
|
ans.Add(closure);
|
|
Next.Add(next, closure.Index);
|
|
}
|
|
return ans;
|
|
}
|
|
|
|
internal List<LR1Unit> GetReduceUnits()
|
|
=> Units.Where(x => x.ReadyToReduce()).ToList();
|
|
|
|
public override bool Equals(object? obj)
|
|
{
|
|
if (obj is not LR1Closure closure || obj is null)
|
|
return false;
|
|
|
|
return closure.Units.Count == Units.Count && closure.Units.Select(x => Units.Where(y => y.Equals(x)).Any()).All(x=> x);
|
|
}
|
|
|
|
public override int GetHashCode()
|
|
{
|
|
int hash = 0;
|
|
foreach (var unit in Units.OrderBy(e => e.GetHashCode()))
|
|
{
|
|
hash ^= unit.GetHashCode();
|
|
}
|
|
return hash;
|
|
}
|
|
|
|
public override string ToString()
|
|
{
|
|
StringBuilder sb = new();
|
|
sb.Append($"闭包{Index}:\n");
|
|
foreach (var unit in Units)
|
|
{
|
|
sb.Append(unit + "\n");
|
|
}
|
|
return sb.ToString();
|
|
}
|
|
}
|
|
}
|