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; } }
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); } }
// 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))); }