예제 #1
0
        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);
        }
예제 #2
0
        private static IEnumerable <Production <SYMBOL_ENUM, TREE_NODE> > unfoldErrorProductions_NOT_USED(StringRep <SYMBOL_ENUM> symbolsRep,
                                                                                                          IEnumerable <Production <SYMBOL_ENUM, TREE_NODE> > productions,
                                                                                                          SYMBOL_ENUM eofSymbol, SYMBOL_ENUM syntaxErrorSymbol)
        {
            var result          = new Productions <SYMBOL_ENUM, TREE_NODE>(symbolsRep, productions, eofSymbol, syntaxErrorSymbol, s => { });
            var new_productions = new List <Production <SYMBOL_ENUM, TREE_NODE> >();

            // compute all non-terminals that serve as aliases for terminals
            // alias is a symbol that can be substituted by single terminal, for example
            // a := A | B (this is alias)
            // a := A B (this is not an alias)
            // we start with terminals, because they serve as aliases too (to themselves)
            DynamicDictionary <SYMBOL_ENUM, HashSet <SYMBOL_ENUM> > term_aliases = result.Terminals
                                                                                   .Select(it => Tuple.Create(it, new HashSet <SYMBOL_ENUM>(new[] { it })))
                                                                                   .ToDefaultDynamicDictionary();

            // this is not cover set algorithm!
            while (true)
            {
                int count = term_aliases.Count;

                foreach (SYMBOL_ENUM non_term in result.NonTerminals.Where(it => !term_aliases.ContainsKey(it)))
                {
                    bool found = true;

                    foreach (Production <SYMBOL_ENUM, TREE_NODE> prod in result.FilterByLhs(non_term))
                    {
                        if (prod.RhsSymbols.Count != 1 || !term_aliases.ContainsKey(prod.RhsSymbols.Single()))
                        {
                            found = false;
                            break;
                        }
                    }

                    if (found)
                    {
                        term_aliases[non_term].AddRange(result.FilterByLhs(non_term).Select(it => term_aliases[it.RhsSymbols.Single()]).Flatten());
                    }
                }

                if (count == term_aliases.Count)
                {
                    break;
                }
            }

            // check the placement of error token in every error production
            foreach (Production <SYMBOL_ENUM, TREE_NODE> prod in productions)
            {
                IEnumerable <SYMBOL_ENUM> error_symbols = prod.RhsSymbols.Where(it => it.Equals(result.SyntaxErrorSymbol));
                if (error_symbols.Any())
                {
                    new_productions.Add(prod);
                }
                else if (error_symbols.Count() > 1)
                {
                    throw new ArgumentException("Only one syntax error token per production: " + prod.PositionDescription);
                }
                else
                {
                    int idx = prod.RhsSymbols.IndexOf(result.SyntaxErrorSymbol);
                    if (idx != prod.RhsSymbols.Count - 2)
                    {
                        throw new ArgumentException("Syntax error token has to be next to last: " + prod.PositionDescription);
                    }
                    SYMBOL_ENUM recovery_symbol = prod.RhsSymbols[idx + 1];
                    if (!term_aliases.ContainsKey(recovery_symbol))
                    {
                        throw new ArgumentException("There has to be a terminal or alias non-terminal after syntax error token: " + prod.PositionDescription);
                    }
                    else if (result.NonTerminals.Contains(recovery_symbol))
                    {
                        foreach (SYMBOL_ENUM term in term_aliases[recovery_symbol])
                        {
                            new_productions.Add(new Production <SYMBOL_ENUM, TREE_NODE>(
                                                    symbolsRep,
                                                    prod.LhsNonTerminal,
                                                    prod.Recursive,
                                                    prod.RhsSymbols.SkipTail(1).Concat(term), // replacing aliased terminal
                                                    prod.UserAction,
                                                    prod.IdentityOuterFunctionParamIndex));
                        }
                    }
                    else
                    {
                        new_productions.Add(prod);
                    }
                }
            }

            return(new_productions);
        }