Beispiel #1
0
        private IEnumerable <SYMBOL_ENUM> recursiveTrackBySet(SYMBOL_ENUM nonTerm)
        {
            var         track   = new LinkedList <SYMBOL_ENUM>();
            SYMBOL_ENUM current = nonTerm;

            while (true)
            {
                SYMBOL_ENUM sym;
                if (!covers[nonTerm].TryGetValue(SymbolChunk.Create(current), out sym))
                {
                    if (current.Equals(nonTerm))
                    {
                        return(track);
                    }
                    else
                    {
                        throw new NotImplementedException("Internal error");
                    }
                }
                track.AddFirst(sym);
                if (sym.Equals(nonTerm))
                {
                    return(track);
                }

                current = sym;
            }
        }
Beispiel #2
0
 private IEnumerable <SymbolChunk <SYMBOL_ENUM> > enumerate(int width)
 {
     if (width == 1)
     {
         return(symbols.Select(it => SymbolChunk.Create(it)));
     }
     else
     {
         return(enumerate(width - 1).Select(chunk => symbols.Select(s => SymbolChunk.Create(chunk.Symbols.Concat(s)))).Flatten());
     }
 }
        private void bootstrapFromFirstSets(SYMBOL_ENUM symbol)
        {
            SymbolChunkSet <SYMBOL_ENUM> follow_set = followSets[symbol];

            // in all RHS of productions find our symbol
            foreach (Production <SYMBOL_ENUM, TREE_NODE> prod in productions.ProductionsWithNoErrorSymbol())
            {
                for (int i = 0; i < prod.RhsSymbols.Count(); ++i)
                {
                    // we are above our symbol on RHS of the production
                    if (prod.RhsSymbols[i].Equals(symbol))
                    {
                        // get first set of what can happen AFTER our symbol -- this will be follow set by definition
                        SymbolChunkSet <SYMBOL_ENUM> chunk_set
                            = firstSets.GetFirstsOf(prod.RhsSymbols.Skip(i + 1), terminals, syntaxErrorSymbol, lookaheadWidth);

                        {
                            SymbolChunkSet <SYMBOL_ENUM> tmp = new SymbolChunkSet <SYMBOL_ENUM>();

                            // add LHS non-terminal at the end of too short chunks as generator
                            // because what follows LHS also follows given symbol
                            foreach (SymbolChunk <SYMBOL_ENUM> chunk in chunk_set.Chunks)
                            {
                                if (chunk.Count < lookaheadWidth)
                                {
                                    tmp.Add(chunk.Append(prod.LhsNonTerminal));
                                }
                                else
                                {
                                    tmp.Add(chunk);
                                }
                            }

                            chunk_set = tmp;
                        }

                        if (chunk_set.IsEmpty)
                        {
                            chunk_set.Add(SymbolChunk.Create(prod.LhsNonTerminal));
                        }

                        follow_set.Add(chunk_set);
                    }
                }
            }
        }
        /// <summary>
        /// Add from lower to highest, symbols in single call are equal
        /// </summary>
        public void AddOperator(AssociativityEnum assoc, params SYMBOL_ENUM[] opSymbols)
        {
            if (priorityGroupCounter == 0)
            {
                ++runningPriority;
            }

            foreach (SYMBOL_ENUM op_symbol in opSymbols)
            {
                addEntry(this.operators, new SymbolPrecedence <SYMBOL_ENUM>(SymbolPrecedence.ModeEnum.BasicOperatorSearch)
                {
                    Symbols       = SymbolChunk.Create(op_symbol),
                    Associativity = assoc,
                    Priority      = runningPriority
                }, symbolsRep);
            }
        }
        private void bootstrapFromFirstSets(SYMBOL_ENUM symbol)
        {
            SymbolChunkSet <SYMBOL_ENUM> current_set = horizonSets[symbol];

            // in all RHS of productions find our symbol
            foreach (Production <SYMBOL_ENUM, TREE_NODE> prod in productions.Entries)
            {
                if (symbol.Equals(prod.LhsNonTerminal) || coverSets[symbol].Contains(SymbolChunk.Create(prod.LhsNonTerminal)))
                {
                    continue;
                }

                for (int i = 0; i < prod.RhsSymbols.Count(); ++i)
                {
                    // we are on our symbol on RHS of the production
                    if (prod.RhsSymbols[i].Equals(symbol))
                    {
                        // get first set of what can happen AFTER our symbol -- this will be our horizon
                        SymbolChunkSet <SYMBOL_ENUM> src_set = firstSets.GetFirstsOf(prod.RhsSymbols.Skip(i + 1), terminals, syntaxErrorSymbol, lookaheadWidth);

                        SymbolChunkSet <SYMBOL_ENUM> chunk_set = new SymbolChunkSet <SYMBOL_ENUM>();
                        // add follow set at the end of too short chunks
                        foreach (SymbolChunk <SYMBOL_ENUM> chunk in src_set.Chunks)
                        {
                            if (chunk.Count < lookaheadWidth)
                            {
                                chunk_set.Add(SymbolChunkSet.MultiConcat(chunk, followSets[prod.LhsNonTerminal], lookaheadWidth));
                            }
                            else
                            {
                                chunk_set.Add(chunk);
                            }
                        }


                        if (chunk_set.IsEmpty)
                        {
                            chunk_set.Add(followSets[prod.LhsNonTerminal]);
                        }

                        current_set.Add(chunk_set);
                    }
                }
            }
        }
        private CoverSets <SYMBOL_ENUM> initCoverSets()
        {
            var cover_sets = new CoverSets <SYMBOL_ENUM>();

            foreach (SYMBOL_ENUM sym in terminals)
            {
                var set = new SymbolChunkSet <SYMBOL_ENUM>();
                set.Add(SymbolChunk.Create(sym));
                cover_sets.Add(sym, set, sym);
            }

            // fill non terminals with everything found in the productions, terminals will stay as they are added here
            // non terminals will serve as generators
            foreach (SYMBOL_ENUM non_term in nonTerminals)
            {
                var set = new SymbolChunkSet <SYMBOL_ENUM>();
                foreach (Production <SYMBOL_ENUM, TREE_NODE> prod in productions.FilterByLhs(non_term))
                {
                    foreach (SYMBOL_ENUM sym in prod.RhsSymbols)
                    {
                        // if we have error symbol inside production it means LHS cover all non-terminals, because
                        // error symbol for that LHS covers everything except what stands after error symbol (stop marker)
                        // thus, everything except stop marker plus stop marker gives --> everything
                        if (sym.Equals(syntaxErrorSymbol))
                        {
                            set.Add(terminals.Select(it => SymbolChunk.Create(it)));
                        }
                        else
                        {
                            set.Add(SymbolChunk.Create(sym));
                        }
                    }
                }

                cover_sets.Add(non_term, set, non_term);
            }

            return(cover_sets);
        }
        private void initFirstSets()
        {
            firstSets = new FirstSets <SYMBOL_ENUM>(lookaheadWidth);

            foreach (SYMBOL_ENUM sym in terminals)
            {
                var set = new SymbolChunkSet <SYMBOL_ENUM>();
                set.Add(SymbolChunk.Create(sym));
                firstSets.Add(sym, set);
            }

            foreach (SYMBOL_ENUM sym in nonTerminals)
            {
                var set = new SymbolChunkSet <SYMBOL_ENUM>();

                // iterate over all productions for this symbol except for error recovery productions
                foreach (Production <SYMBOL_ENUM, TREE_NODE> prod in productions
                         .FilterByLhs(sym)
                         .Where(it => !it.RhsSymbols.Contains(syntaxErrorSymbol)))
                {
                    // we take only terminals from front
                    IEnumerable <SYMBOL_ENUM> first_chunk = prod.RhsSymbols.TakeWhile(it => terminals.Contains(it));
                    int count = first_chunk.Count();

                    if (count >= lookaheadWidth) // we have more than enough
                    {
                        set.Add(SymbolChunk.Create(first_chunk.Take(lookaheadWidth)));
                    }
                    // we have less, but there was no more here
                    else if (count == prod.RhsSymbols.Count)
                    {
                        set.Add(SymbolChunk.Create(first_chunk));
                    }
                }

                firstSets.Add(sym, set);
            }
        }
Beispiel #8
0
        // if we have clear action to do (shift/reduce) pass it forward
        // if not, here we try to recover from syntax error
        private ActionRecoveryEnum getActionOrRecover(int nodeId,
                                                      out IEnumerable <ParseAction <SYMBOL_ENUM, TREE_NODE> > parseActions,
                                                      bool startWithRecovering)
        {
            ActionRecoveryEnum success_result = ActionRecoveryEnum.Success;

            while (true)
            {
                if (startWithRecovering)
                {
                    parseActions = null;
                }
                else
                {
                    // in normal run we ignore grammar conflicts, user should get conflicts just once, at validating stage
                    parseActions = actionTable.Get(nodeId, stackMaster.InputView);
                }

                startWithRecovering = false;

                if (parseActions != null)
                {
                    ++consecutiveCorrectActionsCount;
                    // it could be success after naive recovery
                    return(success_result);
                }



                // trying to recover from old recovery point
                if (stackMaster.IsForked)
                {
                    return(ActionRecoveryEnum.SyntaxError);
                }
                else
                {
                    // make a lazy message
                    if (!callUserErrorHandler(stackMaster.InputHead, () => "No action defined at node " + nodeId
                                              + " for input \"" + SymbolChunk.Create(stackMaster.InputTokens.Take(lookaheadWidth)).ToString(symbolsRep) + "\" with stack \""
                                              + String.Join(" ", stackMaster.Stack.TakeTail(historyHorizon)
                                                            .Select(it => symbolsRep.Get(it.Symbol))) + "\"."))
                    {
                        return(ActionRecoveryEnum.StopParsing);
                    }

                    consecutiveCorrectActionsCount = 0;
                    IEnumerable <NfaCell <SYMBOL_ENUM, TREE_NODE> > recovery_items;

                    if (stack.FindLastWhere(it => it.IsRecoverable, it => it.RecoveryItems, out recovery_items))
                    {
                        if (options.Trace)
                        {
                            parseLog.Last.Value.Recovered = true;
                        }

                        // we would like to get minimal recovery item
                        // i.e. the one which wastes the minimum of the input in order to recover
                        NfaCell <SYMBOL_ENUM, TREE_NODE> min_recovery_item = recovery_items
                                                                             .ArgMin(rec => stackMaster.Input
                                                                             // for each recovery item compute the count of required tokens from input
                                                                                     .TakeWhile(it => !rec.MatchesRecoveryTerminal(it.Token) && !it.Token.Equals(EofSymbol)).Count())
                                                                             // not single, because we could hit EOF in several cases
                                                                             .First();

                        parseActions = new[] { new ParseAction <SYMBOL_ENUM, TREE_NODE>(false, ReductionAction.Create(min_recovery_item)) };

                        stackMaster.AdvanceInputWhile(it => !min_recovery_item.MatchesRecoveryTerminal(it.Token) && !it.Token.Equals(EofSymbol));

                        // we hit the wall
                        if (IsEndOfInput)
                        {
                            return(ActionRecoveryEnum.SyntaxError);
                        }

                        stackMaster.AdvanceInput(); // advance past the marker

                        // setting stack as if we were the old recovery point
                        // (sometimes we really are, because the last element on the stack can be recovery point)
                        stackMaster.RemoveLastWhile(it => !it.IsRecoverable);

                        return(ActionRecoveryEnum.Recovered);
                    }
                    else if (IsEndOfInput)
                    {
                        return(ActionRecoveryEnum.SyntaxError);
                    }
                    else
                    {
                        if (options.Trace)
                        {
                            parseLog.Last.Value.Recovered = true;
                        }

                        // there is no recovery rule defined by the user so try to
                        // "fix" the errors step by step
                        stackMaster.AdvanceInput();
                        // further success will be in fact the result of recovery
                        success_result = ActionRecoveryEnum.Recovered;
                    }
                }
            }
        }
 public void AddReduceShiftPattern(AssociativityEnum assoc, SYMBOL_ENUM inputSymbol, SYMBOL_ENUM reduceProduction,
                                   IEnumerable <SYMBOL_ENUM> stackOperators, SYMBOL_ENUM shiftProduction, params SYMBOL_ENUM[] restShiftProductions)
 {
     AddReduceShiftPattern(assoc, SymbolChunk.Create(inputSymbol), reduceProduction, stackOperators, shiftProduction, restShiftProductions);
 }
 public void AddReduceReducePattern(AssociativityEnum assoc, SYMBOL_ENUM inputSymbol, SYMBOL_ENUM production, params SYMBOL_ENUM[] restProductions)
 {
     AddReduceReducePattern(assoc, SymbolChunk.Create(inputSymbol), production, restProductions);
 }
 private SymbolPrecedence <SYMBOL_ENUM> findOperator(SYMBOL_ENUM opSymbol)
 {
     return(findOperator(SymbolChunk.Create(opSymbol)));
 }