private static IEnumerable <IEnumerable <SYMBOL_ENUM> > unAliasProductionRhs(SYMBOL_ENUM symbol, SYMBOL_ENUM[] expansion, Production <SYMBOL_ENUM, TREE_NODE> production, SYMBOL_ENUM startSymbol, SYMBOL_ENUM syntaxErrorSymbol, ref UnAliasing change) { if (production.RhsSymbols.All(it => !it.Equals(symbol))) { return new[] { production.RhsSymbols } } ; // todo: remove this condition when recovery points will be improved if (expansion.Length > 1 && (production.LhsNonTerminal.Equals(startSymbol) || production.RhsSymbols.Any(it => it.Equals(syntaxErrorSymbol)))) { change = UnAliasing.Forbidden; return(new[] { production.RhsSymbols }); } change = UnAliasing.Expansion; // a lot of memory allocation, but code is much simpler than otherwise // for aliased symbol use its expansions, for others -- just the given symbol SYMBOL_ENUM[][] replacements = production.RhsSymbols.Select(it => it.Equals(symbol) ? expansion : new[] { it }).ToArray(); CycleCounter[] counters = replacements.Select(it => CycleCounter.Create(it.Length)).ToArray(); var result = new List <IEnumerable <SYMBOL_ENUM> >(); do { // has to pin down collection to avoid local capture result.Add(replacements.SyncZip(counters).Select(it => it.Item1[it.Item2.Value]).ToArray()); }while (counters.Iterate()); return(result); }
private static IEnumerable <Production <SYMBOL_ENUM, TREE_NODE> > unfoldIdentityProductions(StringRep <SYMBOL_ENUM> symbolsRep, IEnumerable <Production <SYMBOL_ENUM, TREE_NODE> > productions, SYMBOL_ENUM eofSymbol, SYMBOL_ENUM syntaxErrorSymbol) { var used_aliases = new HashSet <SYMBOL_ENUM>(); while (true) { var result = new Productions <SYMBOL_ENUM, TREE_NODE>(symbolsRep, productions, eofSymbol, syntaxErrorSymbol, s => {}); List <Production <SYMBOL_ENUM, TREE_NODE> > new_productions = null; CoverSets <SYMBOL_ENUM> cover_sets = new BuilderCoverSets <SYMBOL_ENUM, TREE_NODE>(result, lookaheadWidth: 1).ComputeCoverSets(); foreach (SYMBOL_ENUM non_term in result.NonTerminals) { if (!used_aliases.Contains(non_term) && !cover_sets.IsRecursive(non_term) && result.isAlias(non_term)) { used_aliases.Add(non_term); // todo: this won't work for multi-param alias rules SYMBOL_ENUM[] expansions = result.FilterByLhs(non_term).Select(it => it.RhsSymbols.Single()).ToArray(); new_productions = new List <Production <SYMBOL_ENUM, TREE_NODE> >(); UnAliasing change = UnAliasing.NoChange; foreach (Production <SYMBOL_ENUM, TREE_NODE> p in productions.Where(it => !it.LhsNonTerminal.Equals(non_term))) { new_productions.AddRange( unAliasProductionRhs(non_term, expansions, p, result.StartSymbol, syntaxErrorSymbol, ref change) .Select(rhs => new Production <SYMBOL_ENUM, TREE_NODE>( symbolsRep, p.LhsNonTerminal, p.Recursive, rhs, p.UserAction, // todo: this won't work for multi-param alias rules p.IdentityOuterFunctionParamIndex))); // we need to break right-away, otherwise "change" variable could be changed in next expansion to "expanded" if (change == UnAliasing.Forbidden) { break; } } if (change == UnAliasing.Expansion) { break; } else { new_productions = null; } } } // all non terminals checked or productions were expanded if (new_productions == null) { break; } else { productions = new_productions; } } return(productions); }