private void SolveLeftRecursion(IEnumerable <Symbol>[] alphas) { if (alphas.Length == 0) { return; } var primeSymbol = Grammer.AddRule(); primeSymbol.RHSList.Add(Expression.E); foreach (var alpha in alphas) { primeSymbol.RHSList.Add(Expression.Create(alpha.Append(primeSymbol))); } var betas = RHSList.Where(e => e.Value[0] != this).ToArray(); RHSList.Clear(); foreach (var beta in betas) { if (beta.IsEpsilon) { RHSList.Add(Expression.Create(primeSymbol)); } else { RHSList.Add(beta.Append(primeSymbol)); } } //here we should apply left factoring on the prime symbol but the Grammer will do that. }
internal void SetRHS(string rhs) { RHSList.Clear(); var expressions = rhs.Replace(" ", "").Split(new char[] { Grammer.ExpressionSeperator }, StringSplitOptions.RemoveEmptyEntries); foreach (var expText in expressions) { RHSList.Add(Expression.Create(expText.Select(s => Grammer.Symbols[s]))); } }
internal IReadOnlyCollection <TerminalSymbol> FindFirst(HashSet <NonTerminalSymbol> path) { if (path.Add(this) == false || First.Count > 0) { return(First); } foreach (var exp in RHSList.OrderBy(e => e[0] is TerminalSymbol ? 0 : 1)) { bool doneFromExpression = false; foreach (var symbol in exp) { switch (symbol) { case TerminalSymbol terminal: _first.Add(terminal); doneFromExpression = true; break; case NonTerminalSymbol nonTerminal: foreach (var firstSymbol in nonTerminal.FindFirst(path).Except(new TerminalSymbol[] { Epsilon.E })) { _first.Add(firstSymbol); } if (nonTerminal.First.Contains(Epsilon.E) == false) { doneFromExpression = true; } break; default: break; } if (doneFromExpression) { break; } } if (doneFromExpression == false) { _first.Add(Epsilon.E); } } path.Remove(this); return(First); }
internal void ApplyLeftFactoring() { var trie = TrieNode.CreateRoot(); foreach (var exp in RHSList) { if (exp.IsEpsilon) { continue; } trie.AddExpression(exp); } var alphas = trie.GetMinCommonExpressions(); alphas.Add(Expression.E); var groupedExpressions = alphas.ToDictionary(a => a, a => new List <Expression>()); //Group them by there alpha and if non then epsilon is its alpha foreach (var exp in RHSList) { var expAlpha = alphas.FirstOrDefault(a => exp.StartsWith(a)) ?? Expression.E; groupedExpressions[expAlpha].Add(exp); } RHSList.Clear(); var primes = new List <NonTerminalSymbol>(); foreach (var grp in groupedExpressions) { if (grp.Key == Expression.E) { RHSList.AddRange(grp.Value); } else { var primeSymbol = Grammer.AddRule(); primeSymbol.RHSList.AddRange(grp.Value.Select(e => e.SubExpression(grp.Key.Count))); RHSList.Add(Expression.Create(grp.Key.Value.Append(primeSymbol))); primes.Add(primeSymbol); } } foreach (var prime in primes) { prime.ApplyLeftFactoring(); } }
/// <remarks>Solves only 1-level indirect recursion</remarks> internal void SolveIndirectLeftRecusrion() { var newRHS = new List <Expression>(RHSList.Count + 10); foreach (var exp in RHSList) { if ((exp[0] as NonTerminalSymbol)?.RHSList.Any(re => re.Value[0] == this) ?? false) { newRHS.AddRange((exp[0] as NonTerminalSymbol).RHSList.Select(re => re.Append(exp.SubExpression(1)))); } else { newRHS.Add(exp); } } RHSList.Clear(); RHSList.AddRange(newRHS); SolveLeftRecursion(CalcAlphas()); }
private IEnumerable <Symbol>[] CalcAlphas() => RHSList.Where(e => e.Value[0] == this) .Select(e => e.Value.Skip(1)) .ToArray();