public _LR0Item(CfgRule rule, int rightIndex) { Left = rule.Left; _hashCode = Left.GetHashCode(); if (!rule.IsNil) { Right = new string[rule.Right.Count]; rule.Right.CopyTo(Right, 0); for (var i = 0; i < Right.Length; i++) { var right = rule.Right[i]; _hashCode ^= right.GetHashCode(); Right[i] = right; } } else { Right = new string[] { } }; _hashCode ^= rightIndex; RightIndex = rightIndex; }
public IList <CfgMessage> TryToLR1ParseTable(out CfgLR1ParseTable parseTable, LRTableKind kind = LRTableKind.Lalr1, IProgress <CfgLRProgress> progress = null) { var result = new List <CfgMessage>(); var start = GetAugmentedStartId(StartSymbol); var lrfa = _ToLRFA(progress); var trnsCfg = _LRFAToLRExtendedGrammar(lrfa, progress); trnsCfg.RebuildCache(); var closure = new List <_LRFA>(); parseTable = new CfgLR1ParseTable(); var itemSets = new List <_LR0ItemSet>(); lrfa.FillClosure(closure); var i = 0; foreach (var p in closure) { itemSets.Add(p.Accept); parseTable.Add(new Dictionary <string, (int RuleOrStateId, string Left, string[] Right)>()); ++i; } i = 0; foreach (var p in closure) { foreach (var trn in p.Transitions) { var idx = closure.IndexOf(trn.Value); parseTable[i].Add( trn.Key, (idx, null, null) ); } foreach (var item in p.Accept.Items) { if (item.IsEnd && Equals(item.Left, start)) { parseTable[i].Add( "#EOS", (-1, null, null)); } } ++i; } var follows = trnsCfg.FillFollows(); // work on our reductions now // each rule has a follows set associated with it var map = new Dictionary <CfgRule, ICollection <string> >(_Lalr1MergeRuleComparer.Default); foreach (var rule in trnsCfg.Rules) { ICollection <string> f; if (!map.TryGetValue(rule, out f)) { map.Add(rule, follows[rule.Left]); } else { foreach (var o in follows[rule.Left]) { if (!f.Contains(o)) { f.Add(o); } } } } var j = 0; foreach (var mapEntry in map) { if (null != progress) { progress.Report(new CfgLRProgress(CfgLRStatus.ComputingReductions, j)); } var rule = mapEntry.Key; var lr = rule.IsNil?_LRExtendedSymbol.Parse(rule.Left):_LRExtendedSymbol.Parse(rule.Right[rule.Right.Count - 1]); var left = _LRExtendedSymbol.Parse(rule.Left).Id; var right = new List <string>(); foreach (var s in rule.Right) { right.Add(_LRExtendedSymbol.Parse(s).Id); } var newRule = new CfgRule(left, right); if (newRule.IsNil) { lr.To = lr.From; } if (!Equals(left, start)) { foreach (var f in mapEntry.Value) { // build the rule data var rr = new string[newRule.Right.Count]; for (var ri = 0; ri < rr.Length; ri++) { rr[ri] = newRule.Right[ri]; } var iid = _LRExtendedSymbol.Parse(f).Id; (int RuleOrStateId, string Left, string[] Right)tuple; var rid = Rules.IndexOf(newRule); var newTuple = (RuleOrStateId : rid, Left : newRule.Left, Right : rr); // this gets rid of duplicate entries which crop up in the table if (!parseTable[lr.To].TryGetValue(iid, out tuple)) { parseTable[lr.To].Add(iid, newTuple); } else { if (null == tuple.Right) { var nr = Rules[rid]; var msg = new CfgMessage(ErrorLevel.Warning, CfgErrors.ShiftReduceConflict, string.Format("Shift-Reduce conflict on rule {0}, token {1}", nr, iid), nr.Line, nr.Column, nr.Position, FileOrUrl); if (!result.Contains(msg)) { result.Add(msg); } } else { if (rid != tuple.RuleOrStateId) { var nr = Rules[rid]; var msg = new CfgMessage(ErrorLevel.Error, CfgErrors.ReduceReduceConflict, string.Format("Reduce-Reduce conflict on rule {0}, token {1}", nr, iid), nr.Line, nr.Column, nr.Position, FileOrUrl); if (!result.Contains(msg)) { result.Add(msg); } } } } } } ++j; } return(result); }
public IList <CfgMessage> TryToGlrParseTable(out CfgGlrParseTable parseTable, LRTableKind kind = LRTableKind.Lalr1, IProgress <CfgLRProgress> progress = null) { var result = new List <CfgMessage>(); var start = GetAugmentedStartId(StartSymbol); var lrfa = _ToLRFA(progress); var trnsCfg = _LRFAToLRExtendedGrammar(lrfa, progress); trnsCfg.RebuildCache(); var closure = new List <_LRFA>(); parseTable = new CfgGlrParseTable(); var itemSets = new List <_LR0ItemSet>(); lrfa.FillClosure(closure); var i = 0; foreach (var p in closure) { itemSets.Add(p.Accept); parseTable.Add(new Dictionary <string, ICollection <(int RuleOrStateId, string Left, string[] Right)> >()); ++i; } i = 0; foreach (var p in closure) { foreach (var trn in p.Transitions) { var idx = closure.IndexOf(trn.Value); ICollection <(int RuleOrStateId, string Left, string[] Right)> pcol; if (!parseTable[i].TryGetValue(trn.Key, out pcol)) { pcol = new List <(int RuleOrStateId, string Left, string[] Right)>(); parseTable[i].Add(trn.Key, pcol); } pcol.Add( (idx, null, null) ); } foreach (var item in p.Accept.Items) { if (item.IsEnd && Equals(item.Left, start)) { ICollection <(int RuleOrStateId, string Left, string[] Right)> pcol; if (!parseTable[i].TryGetValue("#EOS", out pcol)) { pcol = new List <(int RuleOrStateId, string Left, string[] Right)>(); parseTable[i].Add("#EOS", pcol); } pcol.Add( (-1, null, null)); //break; } } ++i; } var follows = trnsCfg.FillFollows(); // work on our reductions now // each rule has a follows set associated with it var map = new Dictionary <CfgRule, ICollection <string> >(_Lalr1MergeRuleComparer.Default); foreach (var rule in trnsCfg.Rules) { ICollection <string> f; if (!map.TryGetValue(rule, out f)) { map.Add(rule, follows[rule.Left]); } else { foreach (var o in follows[rule.Left]) { if (!f.Contains(o)) { f.Add(o); } } } } var j = 0; foreach (var mapEntry in map) { if (null != progress) { progress.Report(new CfgLRProgress(CfgLRStatus.ComputingReductions, j)); } var rule = mapEntry.Key; var lr = rule.IsNil ? _LRExtendedSymbol.Parse(rule.Left) : _LRExtendedSymbol.Parse(rule.Right[rule.Right.Count - 1]); var left = _LRExtendedSymbol.Parse(rule.Left).Id; var right = new List <string>(); foreach (var s in rule.Right) { right.Add(_LRExtendedSymbol.Parse(s).Id); } var newRule = new CfgRule(left, right); if (newRule.IsNil) { lr.To = lr.From; } if (!Equals(left, start)) { foreach (var f in mapEntry.Value) { // build the rule data var rr = new string[newRule.Right.Count]; for (var ri = 0; ri < rr.Length; ri++) { rr[ri] = newRule.Right[ri]; } var iid = _LRExtendedSymbol.Parse(f).Id; var rid = Rules.IndexOf(newRule); var newTuple = (RuleOrStateId : rid, Left : newRule.Left, Right : rr); // this handles duplicate entries which crop up in the table ICollection <(int RuleOrStateId, string Left, string[] Right)> pcol; if (!parseTable[lr.To].TryGetValue(iid, out pcol)) { pcol = new List <(int RuleOrStateId, string Left, string[] Right)>(); parseTable[lr.To].Add(iid, pcol); } var found = false; foreach (var t in pcol) { if (t.Left == newTuple.Left && t.RuleOrStateId == newTuple.RuleOrStateId) { if ((t.Right == null && newTuple.Right == null) || t.Right?.Length == newTuple.Right?.Length) { if (t.Right != null) { found = true; for (var ii = 0; ii < t.Right.Length; ++ii) { if (t.Right[ii] != newTuple.Right[ii]) { found = false; break; } } } } } if (found) { break; } } if (!found) { pcol.Add(newTuple); } } } ++j; } return(result); }
_LRFA _ToLRFA(IProgress <CfgLRProgress> progress) { if (null != progress) { progress.Report(new CfgLRProgress(CfgLRStatus.ComputingStates, 0)); } var moves = new Dictionary <KeyValuePair <_LR0ItemSet, string>, _LR0ItemSet>(); // TODO: this takes a long time sometimes var map = new Dictionary <_LR0ItemSet, _LRFA>(); // create an augmented grammar - add rule {start} -> [[StartId]] var ss = StartSymbol; var start = new CfgRule(GetAugmentedStartId(ss), new string[] { ss }); var cl = new _LR0ItemSet(); cl.AddItem(new _LR0Item(start, 0)); _FillLRClosureInPlace(progress, cl); var lrfa = new _LRFA(); lrfa.Accept = cl; var items = cl.Items.Count; map.Add(cl, lrfa); var done = false; int oc; while (!done) { done = true; var arr = new _LR0ItemSet[map.Keys.Count]; map.Keys.CopyTo(arr, 0); for (var i = 0; i < arr.Length; ++i) { var itemSet = arr[i]; foreach (var item in itemSet.Items) { var next = item.Next; if (!item.IsEnd) { _LR0ItemSet n; var key = new KeyValuePair <_LR0ItemSet, string>(itemSet, next); if (!moves.TryGetValue(key, out n)) { n = _FillLRMove(itemSet, next, progress); moves.Add(key, n); } if (!map.ContainsKey(n)) { done = false; var npda = new _LRFA(); npda.Accept = n; map.Add(n, npda); items += n.Items.Count; if (null != progress) { progress.Report(new CfgLRProgress(CfgLRStatus.ComputingConfigurations, items)); } } map[itemSet].Transitions[next] = map[n]; } } } if (!done) { oc = map.Count; if (null != progress) { progress.Report(new CfgLRProgress(CfgLRStatus.ComputingStates, oc)); } } } return(lrfa); }