public override IList <IList <string> > ToDisjunctions(EbnfDocument parent, Cfg cfg) { var _listId = cfg.GetUniqueId("implicitlist"); IDictionary <string, object> attrs = new Dictionary <string, object>(); attrs.Add("collapse", true); cfg.AttributeSets.Add(_listId, attrs); var expr = new EbnfOrExpression(new EbnfOrExpression(new EbnfConcatExpression(Expression, new EbnfRefExpression(_listId)), Expression), null); foreach (var nt in expr.ToDisjunctions(parent, cfg)) { CfgRule r = new CfgRule(); r.Left = _listId; foreach (var s in nt) { if (1 < r.Right.Count && null == s) { continue; } r.Right.Add(s); } if (!cfg.Rules.Contains(r)) { cfg.Rules.Add(r); } } return(new List <IList <string> >(new IList <string>[] { new List <string>(new string[] { _listId }) })); }
public IList <CfgMessage> EliminateFirstFirstConflicts() { var result = new List <CfgMessage>(); foreach (var nt in new List <string>(_EnumNonTerminals())) { var rules = FillNonTerminalRules(nt); var rights = new List <IList <string> >(); foreach (var rule in rules) { rights.Add(rule.Right); } while (true) { var pfx = rights.GetLongestCommonPrefix(); if (pfx.IsNullOrEmpty()) { break; } // obv first first conflict var nnt = GetTransformId(nt); var suffixes = new List <IList <string> >(); foreach (var rule in rules) { if (rule.Right.StartsWith(pfx)) { rights.Remove(rule.Right); suffixes.Add(new List <string>(rule.Right.SubRange(pfx.Count))); result.Add(new CfgMessage(CfgErrorLevel.Message, -1, string.Format("Removing rule {0} because it is part of a first-first conflict.", rule))); Rules.Remove(rule); } } var newRule = new CfgRule(nt); newRule.Right.AddRange(pfx); newRule.Right.Add(nnt); result.Add(new CfgMessage(CfgErrorLevel.Message, -1, string.Format("Adding rule {0} to resolve first-first conflict.", newRule))); if (!Rules.Contains(newRule)) { Rules.Add(newRule); } foreach (var suffix in suffixes) { newRule = new CfgRule(nnt); newRule.Right.AddRange(suffix); result.Add(new CfgMessage(CfgErrorLevel.Message, -1, string.Format("Adding rule {0} to resolve first-first conflict.", newRule))); if (!Rules.Contains(newRule)) { Rules.Add(newRule); } } var attrs = new Dictionary <string, object>(); attrs.Add("collapse", true); AttributeSets.Add(nnt, attrs); } } return(result); }
public IList <CfgMessage> EliminateLeftRecursion() { var result = new List <CfgMessage>(); var ic = Rules.Count; for (var i = 0; i < ic; ++i) { var rule = Rules[i]; if (rule.IsDirectlyLeftRecursive) { result.Add(new CfgMessage(CfgErrorLevel.Message, -1, string.Format("Removing rule {0} because it is directly left recursive.", rule))); Rules.Remove(rule); var newId = GetTransformId(rule.Left); var col = new List <string>(); var c = rule.Right.Count; for (var j = 1; j < c; ++j) { col.Add(rule.Right[j]); } col.Add(newId); var d = new Dictionary <string, object>(); AttributeSets.Add(newId, d); d.Add("collapse", true); var newRule = new CfgRule(newId); newRule.Right.AddRange(col); result.Add(new CfgMessage(CfgErrorLevel.Message, -1, string.Format("Adding rule {1} to replace rule {0}", rule, newRule))); if (!Rules.Contains(newRule)) { Rules.Add(newRule); } var rr = new CfgRule(newId); result.Add(new CfgMessage(CfgErrorLevel.Message, -1, string.Format("Adding rule {1} to replace rule {0}", rule, rr))); if (!Rules.Contains(rr)) { Rules.Add(rr); } foreach (var r in Rules) { if (Equals(r.Left, rule.Left)) { if (!r.IsDirectlyLeftRecursive) { r.Right.Add(newId); } } } } } return(result); }
/// <summary> /// Computes the FOLLOWS sets for the grammar /// </summary> /// <param name="firsts">The precomputed firsts sets. These will be computed if this is null.</param> /// <param name="result">The result to fill. If null, a new dictionary will be created.</param> /// <returns>The result, filled with FOLLOWS sets grouped by non-terminal</returns> public IDictionary <string, ICollection <string> > FillFollows(IDictionary <string, ICollection <string> > firsts = null, IDictionary <string, ICollection <string> > result = null) { if (null == result) { result = new Dictionary <string, ICollection <string> >(); } var done = false; if (null == firsts) { firsts = FillFirsts(); } var ss = StartSymbol; // augment the grammar S' -> S #EOS CfgRule start = new CfgRule(GetTransformId(ss), ss, "#EOS"); foreach (var rule in new CfgRule[] { start }.Concat(Rules)) { if (rule.IsNil) { ICollection <string> col; if (!result.TryGetValue(rule.Left, out col)) { col = new HashSet <string>(); result.Add(rule.Left, col); } if (!col.Contains(rule.Left)) { col.Add(rule.Left); } } else { var ic = rule.Right.Count; for (var i = 1; i < ic; ++i) { var prev = rule.Right[i - 1]; var sym = rule.Right[i]; if (IsNonTerminal(prev)) { ICollection <string> col; if (!result.TryGetValue(prev, out col)) { col = new HashSet <string>(); result.Add(prev, col); } foreach (var s in firsts[sym]) { // we'll need the following symbol's follows if (null == s) { if (!col.Contains(sym)) { col.Add(sym); } } else if (!col.Contains(s)) { col.Add(s); } } } } var last = rule.Right[ic - 1]; if (IsNonTerminal(last)) { ICollection <string> col; if (!result.TryGetValue(last, out col)) { col = new HashSet <string>(); result.Add(last, col); } if (!col.Contains(rule.Left)) { col.Add(rule.Left); } } } } done = false; const int LIMIT = 10000; var il = 0; while (!done) { done = true; foreach (var kvp in result) { foreach (var s in new List <string>(kvp.Value)) { if (IsNonTerminal(s)) { kvp.Value.Remove(s); ICollection <string> col; if (result.TryGetValue(s, out col)) { foreach (var sss in col) { if (!kvp.Value.Contains(sss)) { if (sss != s) { kvp.Value.Add(sss); done = false; } } } } } } } ++il; if (LIMIT < il) { throw new CfgException("Loop detected in follows computation - follows limit exceeded.", 16); } } return(result); }