using System.Text; namespace CompilerDesignIFlr1 { internal class LR1Closure { internal static int GlobalIndex = 0; internal int Index = 0; internal LR1Creator LR1Creator; internal HashSet Units { get; set; } = []; internal Dictionary Next { get; set; } = []; internal LR1Closure(LR1Creator lr1Creator) { LR1Creator = lr1Creator; Index = GlobalIndex++; } internal LR1Closure(LR1Creator lr1Creator, List units) { Units.UnionWith(units); Index = GlobalIndex++; LR1Creator = lr1Creator; AddMissingUnits(); CalculateProspects(); } internal void CalculateProspects() { bool haveChange = true; while (haveChange) { haveChange = false; foreach (var unit in Units) { var left = unit.Name; var units = UnitsHaveDotBefore(left); HashSet 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 UnitsHaveDotBefore(string name) { List res = []; foreach (LR1Unit unit in Units) { if (unit.Next() == name) res.Add(unit); } return res; } // 对于文法 X => yz... // 该方法返回 A => .XB 中的B 以及B可能为空时其后的元素 internal List GetProspectsOf(LR1Unit unit) { if (unit.Name == LR1Creator.StartSymbol) return ["End"]; //if(unit.Prospect.Count != 0) //{ // throw new Exception("有环???"); //} List 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 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(value.Select(x => x.Clone())); if (set.IsSubsetOf(Units)) continue; haveNew = true; addingUnits.UnionWith(set); } } Units.UnionWith(addingUnits); } } internal List NextClosures() { List ans = []; Dictionary> 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 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(); } } }