private void printShiftReduceConflicts(TextWriter reportOutput) { foreach (State state in parserStates) { if (stateResolvedAt[state.StateNumber] == LookaheadComplexity.Unresolved) { BitVectorSet shiftSymbols = new BitVectorSet(grammar.NumTerminals); foreach (Transition trans in state.Transitions) { if (trans is TerminalTransition) { shiftSymbols.Add(trans.TransitionSymbol); } } BitVectorSet reduceSymbols = new BitVectorSet(grammar.NumTerminals); foreach (BitVectorSet lookaheadSet in lookaheadSets[stateLookaheadIndex[state.StateNumber]]) { reduceSymbols.UnionWith(lookaheadSet); } foreach (int terminal in shiftSymbols.GetIntersectionWith(reduceSymbols)) { reportOutput.WriteLine("Warning: shift/reduce conflict in state {0} on symbol '{1}'.", state.StateNumber, grammar.SymbolNames[terminal]); } } } }
private void printItemHTML(Item item, BitVectorSet conflictSymbols, TextWriter writer) { writer.Write(getSymbolPrintName(item.Production.LHSSymbol)); writer.Write(" ::="); for (int i = 0; i < item.Production.RHSSymbols.Count; i++) { if (i == item.Position) { writer.Write(" ·"); if ((item.Production.RHSSymbols[i] < grammar.NumTerminals) && conflictSymbols.Contains(item.Production.RHSSymbols[i])) { writer.Write(" <span style=\"color:red\">{0}</span>", getSymbolPrintName(item.Production.RHSSymbols[i])); } else { writer.Write(" " + getSymbolPrintName(item.Production.RHSSymbols[i])); } } else { writer.Write(" " + getSymbolPrintName(item.Production.RHSSymbols[i])); } } if (item.IsFinal) { writer.Write(" ·"); } }
//tenhle overload se volá po posledním výpočtu lookaheadů, kde jsme ochotni tolerovat i shift/reduce //konflikty, kde budeme preferovat shift; proto tento overload zjišťuje, zda se v daném automatu //nacházejí i reduce/reduce konflikty, se kterými už bychom si neuměli rozumně poradit private bool checkForConflicts(LookaheadComplexity lastStage, out bool reduceReduceConflictsInAutomaton) { bool conflictsInAutomaton = false; reduceReduceConflictsInAutomaton = false; foreach (State state in parserStates) { if (stateResolvedAt[state.StateNumber] == LookaheadComplexity.Unresolved) { BitVectorSet accumulator = new BitVectorSet(grammar.NumTerminals); BitVectorSet reduceAccumulator = new BitVectorSet(grammar.NumTerminals); foreach (Transition trans in state.Transitions) { if (trans is TerminalTransition) { accumulator.Add(trans.TransitionSymbol); } } bool conflictsInThisState = false; foreach (BitVectorSet lookaheadSet in lookaheadSets[stateLookaheadIndex[state.StateNumber]]) { if (!reduceAccumulator.IsDisjointWith(lookaheadSet)) { conflictsInThisState = true; reduceReduceConflictsInAutomaton = true; break; } else { if (!accumulator.IsDisjointWith(lookaheadSet)) { conflictsInThisState = true; } reduceAccumulator.UnionWith(lookaheadSet); } } if (conflictsInThisState) { conflictsInAutomaton = true; } else { numInconsistentStates--; stateResolvedAt[state.StateNumber] = lastStage; } } } return(conflictsInAutomaton); }
//projde všechny dosud nevyřešené stavy a podívá se, jestli byla minulá fáze výpočtu dostatečná //na to, aby rozřešila konflikty, které se v nich objevují; parametr lastStage popisuje, jak vypadala //poslední fáze výpočtu a můžeme tak pro diagnostické důvody sledovat, které stavy jsou vyřešeny //v kterém stádiu výpočtu private bool checkForConflicts(LookaheadComplexity lastStage) { bool conflictsInAutomaton = false; foreach (State state in parserStates) { if (stateResolvedAt[state.StateNumber] == LookaheadComplexity.Unresolved) { BitVectorSet accumulator = new BitVectorSet(grammar.NumTerminals); //inicializujeme akumulační proměnnou na množinu terminálů, které v daném stavu můžeme přečíst foreach (Transition trans in state.Transitions) { if (trans is TerminalTransition) { accumulator.Add(trans.TransitionSymbol); } } bool conflictsInThisState = false; //akumulační proměnná prochází kolem všech lookahead množin a testuje se s nimi na disjunktnost, //sama potom přebírá jejich prvky (nemusíme tak testovat každou dvojici množin) foreach (BitVectorSet lookaheadSet in lookaheadSets[stateLookaheadIndex[state.StateNumber]]) { if (!accumulator.IsDisjointWith(lookaheadSet)) { conflictsInThisState = true; break; } else { accumulator.UnionWith(lookaheadSet); } } if (conflictsInThisState) { conflictsInAutomaton = true; } else { numInconsistentStates--; stateResolvedAt[state.StateNumber] = lastStage; } } } return(conflictsInAutomaton); }
private void printLookahead(BitVectorSet lookaheadSet, BitVectorSet conflictSymbols, TextWriter writer) { StringBuilder lookaheadSetString = new StringBuilder(); lookaheadSetString.Append('{'); foreach (int lookaheadSymbol in lookaheadSet) { if (conflictSymbols.Contains(lookaheadSymbol)) lookaheadSetString.AppendFormat("<span style=\"color:red\">{0}</span>", getSymbolPrintName(lookaheadSymbol)); else lookaheadSetString.Append(getSymbolPrintName(lookaheadSymbol)); lookaheadSetString.Append(", "); } lookaheadSetString.Remove(lookaheadSetString.Length - 2, 2); lookaheadSetString.Append('}'); writer.Write(lookaheadSetString.ToString()); }
private void printShiftReduceConflicts(TextWriter reportOutput) { foreach (State state in parserStates) if (stateResolvedAt[state.StateNumber] == LookaheadComplexity.Unresolved) { BitVectorSet shiftSymbols = new BitVectorSet(grammar.NumTerminals); foreach (Transition trans in state.Transitions) if (trans is TerminalTransition) shiftSymbols.Add(trans.TransitionSymbol); BitVectorSet reduceSymbols = new BitVectorSet(grammar.NumTerminals); foreach (BitVectorSet lookaheadSet in lookaheadSets[stateLookaheadIndex[state.StateNumber]]) reduceSymbols.UnionWith(lookaheadSet); foreach (int terminal in shiftSymbols.GetIntersectionWith(reduceSymbols)) reportOutput.WriteLine("Warning: shift/reduce conflict in state {0} on symbol '{1}'.", state.StateNumber, grammar.SymbolNames[terminal]); } }
private void printLookahead(BitVectorSet lookaheadSet, BitVectorSet conflictSymbols, TextWriter writer) { StringBuilder lookaheadSetString = new StringBuilder(); lookaheadSetString.Append('{'); foreach (int lookaheadSymbol in lookaheadSet) { if (conflictSymbols.Contains(lookaheadSymbol)) { lookaheadSetString.AppendFormat("<span style=\"color:red\">{0}</span>", getSymbolPrintName(lookaheadSymbol)); } else { lookaheadSetString.Append(getSymbolPrintName(lookaheadSymbol)); } lookaheadSetString.Append(", "); } lookaheadSetString.Remove(lookaheadSetString.Length - 2, 2); lookaheadSetString.Append('}'); writer.Write(lookaheadSetString.ToString()); }
private void printItemHTML(Item item, BitVectorSet conflictSymbols, TextWriter writer) { writer.Write(getSymbolPrintName(item.Production.LHSSymbol)); writer.Write(" ::="); for (int i = 0; i < item.Production.RHSSymbols.Count; i++) { if (i == item.Position) { writer.Write(" ·"); if ((item.Production.RHSSymbols[i] < grammar.NumTerminals) && conflictSymbols.Contains(item.Production.RHSSymbols[i])) writer.Write(" <span style=\"color:red\">{0}</span>", getSymbolPrintName(item.Production.RHSSymbols[i])); else writer.Write(" " + getSymbolPrintName(item.Production.RHSSymbols[i])); } else writer.Write(" " + getSymbolPrintName(item.Production.RHSSymbols[i])); } if (item.IsFinal) writer.Write(" ·"); }
/// <summary> /// Computes the ParseTable and GotoTable of a Grammar's ParserData, logging the automata's graph /// to a logfile should the <i>grammar</i> prove to be non-LALR(1) or should the caller explicitly /// state he wants a log. Any reports generated by the processor will be sent to the <i>reportOutput</i> /// TextWriter instance. /// </summary> /// <param name="grammar">The Grammar whose tables are to be computed. GrammarDefinition ought to be /// set and filled with appropriate data and ParserData should be initialized.</param> /// <param name="logfileName">The name of the file to which the automaton is to be logged; <b>null</b> /// if logging should be disabled.</param> /// <param name="explicitLogging">A Boolean value determining whether the automaton should be /// written to the logfile even though there are no inconsistencies.</param> /// <param name="reportOutput">The TextWriter to which the report should be written; <b>null</b> /// if reporting should be disabled.</param> public void ComputeTables(Grammar grammar, string logfileName, bool explicitLogging, TextWriter reportOutput) { // INICIALIZACE this.grammar = grammar; //inicializace a výpočet productionsByRHSNonterminals productionsByRHSNonterminals = new List <Production> [grammar.GrammarDefinition.NumNonterminals]; for (int nonterminal = 0; nonterminal < productionsByRHSNonterminals.Length; nonterminal++) { productionsByRHSNonterminals[nonterminal] = new List <Production>(); } foreach (Production production in grammar.Productions) { foreach (int rhsSymbol in production.RHSSymbols) { if (rhsSymbol >= grammar.NumTerminals) { productionsByRHSNonterminals[rhsSymbol - grammar.NumTerminals].Add(production); } } } //inicializace transitionsByNonterminals, hodnoty jsou do seznamů posléze nasázeny ve funkci //exploreTransitions, která zároveň vyrábí LR(0) automat transitionsByNonterminals = new List <NonterminalTransition> [grammar.NumNonterminals]; for (int nonterminal = 0; nonterminal < grammar.NumNonterminals; nonterminal++) { transitionsByNonterminals[nonterminal] = new List <NonterminalTransition>(); } numNonterminalTransitions = 0; conflictingItems = new List <List <Item> >(); lookaheadSets = new List <List <BitVectorSet> >(); parserStates = new List <State>(); // TVORBA LR(0) AUTOMATU //vytvoříme počáteční ItemSet a nastartujeme rekurzivní //exploreTransitions Item startItem = new Item(grammar.Productions[0], 0); ItemSet startIS = new ItemSet(); startIS.Add(startItem); startIS.CloseItemSet(grammar); State initialState = new State(0, startIS); parserStates.Add(initialState); //spočítá nám parserStates, hrany mezi nimi, nonterminalTransitions (počet neterminálních hran) //a transitionsByNonterminals exploreTransitions(initialState); //tenhle kousek inicializace si musel počkat na dopočítání stavů automatu stateLookaheadIndex = new int[parserStates.Count]; for (int i = 0; i < parserStates.Count; i++) { stateLookaheadIndex[i] = -1; } //původní hodnota Look stateResolvedAt = new LookaheadComplexity[parserStates.Count]; // ŘEŠENÍ NEDETERMINISTICKÝCH STAVŮ (KONFLIKTŮ) numInconsistentStates = 0; foreach (State state in parserStates) { List <Item> finalItems = new List <Item>(); stateResolvedAt[state.StateNumber] = LookaheadComplexity.LR0; foreach (Item item in state.ItemSet) { if (item.IsFinal) { finalItems.Add(item); } } if (finalItems.Count >= 2) { stateLookaheadIndex[state.StateNumber] = numInconsistentStates; stateResolvedAt[state.StateNumber] = LookaheadComplexity.Unresolved; numInconsistentStates++; conflictingItems.Add(finalItems); } else if (finalItems.Count >= 1) { bool canRead = false; foreach (Transition trans in state.Transitions) { if (trans is TerminalTransition) { canRead = true; break; } } if (canRead) { stateLookaheadIndex[state.StateNumber] = numInconsistentStates; stateResolvedAt[state.StateNumber] = LookaheadComplexity.Unresolved; numInconsistentStates++; conflictingItems.Add(finalItems); } } } if (numInconsistentStates > 0) { //Vstupní gramatika není LR(0), bude tedy třeba spočítat lookahead množiny pro nekonzistentní //stavy. Použijeme postup DeRemera a Pennella, kdy se pokusíme každý nekonzistení stav nejdříve //vyřešit pomocí SLR(1) lookahead množin a až poté případně přikročíme k výpočtu LALR(1) lookaheadů. //Krok 1. Určit, které neterminály jsou nulovatelné. computeNullableNonterminals(); //Krok 2. Spočítat SLR(1) lookaheady. //Připravíme se na počítání Read a SLR-Follow množin a pokusíme se vyřešit konflikty //pouze pomocí SLR(1) lookaheadů. //Direct Read množina pro každou neterminální hranu initDR = (trans => { BitVectorSet set = new BitVectorSet(grammar.NumTerminals); foreach (Transition nextTrans in trans.Destination.Transitions) { if (nextTrans is TerminalTransition) { set.Add(nextTrans.TransitionSymbol); } } return(set); }); read = new BitVectorSet[numNonterminalTransitions]; N_reads = new int[numNonterminalTransitions]; reads = new ReadsOracle(this); if (!forceLalr1) { getNontermIndex = (nonterm => nonterm - grammar.NumTerminals); //původní hodnota pro nějaký neterminál bude sjednocení Read množin všech hran označených //tímto neterminálem; vyplývá téměř přímo z definice výpočtu Follow množin SLR(1) parserů initSLR = (nonterm => { BitVectorSet set = new BitVectorSet(grammar.NumTerminals); foreach (NonterminalTransition trans in transitionsByNonterminals[nonterm - grammar.NumTerminals]) { if (N_reads[getTransNumber(trans)] == 0) { digraphTraverse <NonterminalTransition>(trans, N_reads, read, reads, initDR, getTransNumber); } set.UnionWith(read[getTransNumber(trans)]); } return(set); }); slr_follow = new BitVectorSet[grammar.NumNonterminals]; N_slr = new int[grammar.NumNonterminals]; slr_follows = new SLROracle(this); foreach (State state in parserStates) { if (stateResolvedAt[state.StateNumber] == LookaheadComplexity.Unresolved) { List <BitVectorSet> stateLookaheads = new List <BitVectorSet>(); foreach (Item conflictItem in conflictingItems[stateLookaheadIndex[state.StateNumber]]) { if (N_slr[getNontermIndex(conflictItem.Production.LHSSymbol)] == 0) { digraphTraverse <int>(conflictItem.Production.LHSSymbol, N_slr, slr_follow, slr_follows, initSLR, getNontermIndex); } stateLookaheads.Add(slr_follow[getNontermIndex(conflictItem.Production.LHSSymbol)]); } lookaheadSets.Add(stateLookaheads); } } } //Krok 3. Spočítat LALR(1) lookaheady. //Pokud SLR(1) lookaheady nevyřešily všechny konflikty, spočteme pro nedořešené stavy //LALR(1) lookaheady. if (forceLalr1 || checkForConflicts(LookaheadComplexity.SLR1)) { initRead = (trans => { if (N_reads[getTransNumber(trans)] == 0) { digraphTraverse <NonterminalTransition>(trans, N_reads, read, reads, initDR, getTransNumber); } return(new BitVectorSet(read[getTransNumber(trans)])); }); follow = new BitVectorSet[numNonterminalTransitions]; N_includes = new int[numNonterminalTransitions]; includes = new IncludesOracle(this); foreach (State state in parserStates) { if (stateResolvedAt[state.StateNumber] == LookaheadComplexity.Unresolved) { List <BitVectorSet> stateLookaheads = new List <BitVectorSet>(); foreach (Item conflictItem in conflictingItems[stateLookaheadIndex[state.StateNumber]]) { BitVectorSet lookaheadSet = new BitVectorSet(grammar.NumTerminals); foreach (NonterminalTransition trans in lookback(state, conflictItem)) { if (N_includes[getTransNumber(trans)] == 0) { digraphTraverse <NonterminalTransition>(trans, N_includes, follow, includes, initRead, getTransNumber); } lookaheadSet.UnionWith(follow[getTransNumber(trans)]); } stateLookaheads.Add(lookaheadSet); } //v případě, že je tohle naše první počítání lookahead množin, tak musíme //založit pro stav novou položku v seznamu lookaheadSets; v opačném případě //přepíšeme tu, kterou jsme vytvořili při počítání minulém if (forceLalr1) { lookaheadSets.Add(stateLookaheads); } else { lookaheadSets[stateLookaheadIndex[state.StateNumber]] = stateLookaheads; } } } //Krok 4. Ověřit parser //Pokud parser stále obsahuje konflikty, vypíšeme uživateli do logu podobu stavového //automatu a vyznačíme v ní konflikty. Pokud parser konflikty neobsahuje, zapíšeme //poznatky do tabulek a máme hotovo. bool reduceReduceConflicts; bool conflicts = checkForConflicts(LookaheadComplexity.LALR1, out reduceReduceConflicts); if (reduceReduceConflicts) { if (logfileName != null) { printAutomatonStates(logfileName); throw new GrammarException(string.Format("Reduce/reduce conflicts detected in the resulting parser.\r\nThe grammar isn't LALR(1).\r\nCheck the log file {0} for details.", logfileName)); } else { throw new GrammarException("Reduce/reduce conflicts detected in the resulting parser.\r\nThe grammar isn't LALR(1)."); } } else if (conflicts) { if (reportOutput != null) { printShiftReduceConflicts(reportOutput); } } } } ParserAction[,] parseTable = new ParserAction[parserStates.Count, grammar.NumTerminals]; int[,] gotoTable = new int[parserStates.Count, grammar.NumNonterminals]; for (int i = 0; i < parserStates.Count; i++) { for (int j = 0; j < grammar.NumNonterminals; j++) { gotoTable[i, j] = -1; } } for (int stateNumber = 0; stateNumber < parserStates.Count; stateNumber++) { if (stateLookaheadIndex[stateNumber] >= 0) { for (int i = 0; i < conflictingItems[stateLookaheadIndex[stateNumber]].Count; i++) { ParserAction action = new ParserAction(); action.ActionType = ParserActionType.Reduce; action.Argument = conflictingItems[stateLookaheadIndex[stateNumber]][i].Production.ProductionCode; foreach (int symbol in lookaheadSets[stateLookaheadIndex[stateNumber]][i]) { parseTable[stateNumber, symbol] = action; } } } else { foreach (Item item in parserStates[stateNumber].ItemSet) { if (item.IsFinal) { ParserAction action = new ParserAction(); action.ActionType = ParserActionType.Reduce; action.Argument = item.Production.ProductionCode; for (int symbol = 0; symbol < grammar.NumTerminals; symbol++) { parseTable[stateNumber, symbol] = action; } } } } foreach (Transition trans in parserStates[stateNumber].Transitions) { if (trans is TerminalTransition) { parseTable[stateNumber, trans.TransitionSymbol].ActionType = ParserActionType.Shift; parseTable[stateNumber, trans.TransitionSymbol].Argument = trans.Destination.StateNumber; } else { gotoTable[stateNumber, trans.TransitionSymbol - grammar.NumTerminals] = trans.Destination.StateNumber; } } } grammar.ParserData.ParseTable = parseTable; grammar.ParserData.GotoTable = gotoTable; if (explicitLogging) { printAutomatonStates(logfileName); } if (reportOutput != null) { printSuccessReport(reportOutput); } }
private void printStatesHTML(TextWriter writer) { writer.WriteLine("<h2>Parser states</h2>"); if (numInconsistentStates > 0) { writer.Write("<b>States with inconsistencies:</b> "); StringBuilder inconsistentStatesString = new StringBuilder(); foreach (State state in parserStates) { if (stateResolvedAt[state.StateNumber] == LookaheadComplexity.Unresolved) { inconsistentStatesString.AppendFormat("<a href=\"#State{0}\">{0}</a>, ", state.StateNumber); } } inconsistentStatesString.Remove(inconsistentStatesString.Length - 2, 2); writer.WriteLine(inconsistentStatesString.ToString()); } foreach (State state in parserStates) { writer.Write("<a name=\"State{0}\" id=\"State{0}\"/>", state.StateNumber); if (stateResolvedAt[state.StateNumber] == LookaheadComplexity.Unresolved) { writer.WriteLine("<h3 style=\"color:red\">State {0}</h3>", state.StateNumber); } else { writer.WriteLine("<h3>State {0}</h3>", state.StateNumber); } writer.WriteLine("<b>Items:</b>"); writer.WriteLine("<ul>"); BitVectorSet conflictSymbols = new BitVectorSet(grammar.NumTerminals); if (stateResolvedAt[state.StateNumber] == LookaheadComplexity.Unresolved) { //najde symboly, pro které je tento stav nedeterministický, úpravou algoritmu na hledání //konfliktů použitém v metodě checkForConflicts BitVectorSet accumulator = new BitVectorSet(grammar.NumTerminals); foreach (Transition trans in state.Transitions) { if (trans is TerminalTransition) { accumulator.Add(trans.TransitionSymbol); } } foreach (BitVectorSet lookaheadSet in lookaheadSets[stateLookaheadIndex[state.StateNumber]]) { BitVectorSet newConflictSymbols = accumulator.GetIntersectionWith(lookaheadSet); accumulator.UnionWith(lookaheadSet); conflictSymbols.UnionWith(newConflictSymbols); } } if (stateResolvedAt[state.StateNumber] == LookaheadComplexity.LR0) { //žádný lookahead foreach (Item item in state.ItemSet) { writer.Write("<li>"); printItemHTML(item, conflictSymbols, writer); writer.WriteLine("</li>"); } } else { //nejdřív vypíšeme finální itemy a jejich lookahead množiny; pro každý konfliktní symbol //v lookahead množině navíc vypíšeme cestu, jakou se do lookahead množiny dostal for (int i = 0; i < conflictingItems[stateLookaheadIndex[state.StateNumber]].Count; i++) { writer.Write("<li>"); printItemHTML(conflictingItems[stateLookaheadIndex[state.StateNumber]][i], conflictSymbols, writer); writer.WriteLine("<br>"); printLookahead(lookaheadSets[stateLookaheadIndex[state.StateNumber]][i], conflictSymbols, writer); if (!conflictSymbols.IsDisjointWith(lookaheadSets[stateLookaheadIndex[state.StateNumber]][i])) { writer.WriteLine("<br>"); printSymbolExplanations(state, conflictingItems[stateLookaheadIndex[state.StateNumber]][i], conflictSymbols.GetIntersectionWith(lookaheadSets[stateLookaheadIndex[state.StateNumber]][i]), writer); } writer.WriteLine("</li>"); } //pak vypíšeme zbylé itemy foreach (Item item in state.ItemSet) { if (!item.IsFinal) { writer.Write("<li>"); printItemHTML(item, conflictSymbols, writer); writer.WriteLine("</li>"); } } } writer.WriteLine("</ul>"); writer.Write("<b>Accessing states:</b> "); StringBuilder accessingStatesString = new StringBuilder(); foreach (State accessingState in state.AccessingStates) { accessingStatesString.AppendFormat("<a href=\"#State{0}\">{0}</a>, ", accessingState.StateNumber); } if (accessingStatesString.Length > 0) { accessingStatesString.Remove(accessingStatesString.Length - 2, 2); } writer.Write(accessingStatesString.ToString()); writer.WriteLine("<br>"); writer.Write("<b>Transitions:</b> "); StringBuilder transitionsString = new StringBuilder(); foreach (Transition trans in state.Transitions) { transitionsString.AppendFormat("<a href=\"#State{0}\">{0}</a>({1}), ", trans.Destination.StateNumber, getSymbolPrintName(trans.TransitionSymbol)); } if (transitionsString.Length > 0) { transitionsString.Remove(transitionsString.Length - 2, 2); } writer.Write(transitionsString.ToString()); writer.WriteLine("<br>"); } }
private void printSymbolExplanations(State state, Item finalItem, BitVectorSet conflictSymbols, TextWriter writer) { //Vyrazíme ze všech vrcholů (vrcholy jsou tady neterminální hrany automatu) //ležících v lookback(state, finalItem), které mají ve follow množině nějaký konfliktní symbol. //Prohledáváním do hloubkyv grafu relace 'includes' najdeme nejbližší vrcholy, které mají v Read //množinách dohromady všechny hledané konfliktní symboly. Posléze vyrazíme z těchto nalezených vrcholů, //tentokrát po hranách relace 'reads' a budeme hledat nejbližší vrcholy, které mají v Direct Read množinách //dohromady všechny hledané symboly. Z posledně nalezených vrcholů už jsme vždy schopni vystopovat //cestu zpět přes reads, includes a lookback hrany až k původnímu konfliktnímu itemu. //pole předků a značky u navštívených vrcholů pro oba grafy NonterminalTransition[] includesPredecessors = new NonterminalTransition[numNonterminalTransitions]; bool[] includesExplored = new bool[numNonterminalTransitions]; NonterminalTransition[] readsPredecessors = new NonterminalTransition[numNonterminalTransitions]; bool[] readsExplored = new bool[numNonterminalTransitions]; BitVectorSet symbolsLeftToExplain = new BitVectorSet(conflictSymbols); //BFS fronty pro oba průchody obou grafů Queue <NonterminalTransition> includesTransitions = new Queue <NonterminalTransition>(); Queue <NonterminalTransition> readsTransitions = new Queue <NonterminalTransition>(); //vrcholy, které mají v DR množinách konfliktní symboly List <NonterminalTransition> rootTransitions = new List <NonterminalTransition>(); //procházení po lookback hranách foreach (NonterminalTransition trans in lookback(state, finalItem)) { if (!follow[getTransNumber(trans)].IsDisjointWith(conflictSymbols)) { includesTransitions.Enqueue(trans); includesExplored[getTransNumber(trans)] = true; } } //průchod přes includes hrany while ((includesTransitions.Count > 0) && (!symbolsLeftToExplain.IsEmpty())) { NonterminalTransition trans = includesTransitions.Dequeue(); BitVectorSet readSet = read[getTransNumber(trans)]; if (!readSet.IsDisjointWith(symbolsLeftToExplain)) { BitVectorSet symbolsJustExplained = readSet.GetIntersectionWith(symbolsLeftToExplain); symbolsLeftToExplain -= symbolsJustExplained; readsTransitions.Enqueue(trans); readsExplored[getTransNumber(trans)] = true; } foreach (NonterminalTransition next in includes.GetNeighboursFor(trans)) { if (!includesExplored[getTransNumber(next)]) { includesPredecessors[getTransNumber(next)] = trans; includesExplored[getTransNumber(next)] = true; includesTransitions.Enqueue(next); } } } //reset hledaných symbolů a průchod přes reads hrany symbolsLeftToExplain = new BitVectorSet(conflictSymbols); while ((readsTransitions.Count > 0) && (!symbolsLeftToExplain.IsEmpty())) { NonterminalTransition trans = readsTransitions.Dequeue(); BitVectorSet DRSet = initDR(trans); if (!DRSet.IsDisjointWith(symbolsLeftToExplain)) { BitVectorSet symbolsJustExplained = DRSet.GetIntersectionWith(symbolsLeftToExplain); symbolsLeftToExplain -= symbolsJustExplained; rootTransitions.Add(trans); } foreach (NonterminalTransition next in reads.GetNeighboursFor(trans)) { if (!readsExplored[getTransNumber(next)]) { readsPredecessors[getTransNumber(next)] = trans; readsExplored[getTransNumber(next)] = true; readsTransitions.Enqueue(next); } } } //teď už jen vystopujeme všechny potřebné cesty z neterminální hrany, která obsahovala konfliktní //symbol ve své DR množině, až k itemu, kde tímto symbolem přispěla a způsobila konflikt foreach (NonterminalTransition root in rootTransitions) { Stack <NonterminalTransition> readsPath = new Stack <NonterminalTransition>(); Stack <NonterminalTransition> includesPath = new Stack <NonterminalTransition>(); NonterminalTransition trans = root; while (readsPredecessors[getTransNumber(trans)] != null) { readsPath.Push(trans); trans = readsPredecessors[getTransNumber(trans)]; } while (includesPredecessors[getTransNumber(trans)] != null) { includesPath.Push(trans); trans = includesPredecessors[getTransNumber(trans)]; } writer.Write("({0}, ", state.StateNumber); printItemHTML(finalItem, conflictSymbols, writer); writer.Write(") <b><i>lookback</i></b> (<a href=\"#State{0}\">{0}</a>, {1})", trans.Source.StateNumber, getSymbolPrintName(trans.TransitionSymbol)); foreach (NonterminalTransition transition in includesPath) { writer.Write(" <b><i>includes</i></b> (<a href=\"#State{0}\">{0}</a>, {1})", transition.Source.StateNumber, getSymbolPrintName(transition.TransitionSymbol)); } foreach (NonterminalTransition transition in readsPath) { writer.Write(" <b><i>reads</i></b> (<a href=\"#State{0}\">{0}</a>, {1})", transition.Source.StateNumber, getSymbolPrintName(transition.TransitionSymbol)); } writer.Write(" and {"); StringBuilder explainedSymbolsString = new StringBuilder(); foreach (int explainedSymbol in initDR(root).GetIntersectionWith(conflictSymbols)) { explainedSymbolsString.AppendFormat("<span style=\"color:red\">{0}</span>, ", getSymbolPrintName(explainedSymbol)); } explainedSymbolsString.Remove(explainedSymbolsString.Length - 2, 2); writer.Write(explainedSymbolsString.ToString()); writer.Write("} ⊂ <b>DR</b>(" + root.Source.StateNumber.ToString() + ", " + getSymbolPrintName(root.TransitionSymbol) + ")"); writer.WriteLine("<br>"); } }
private void printSymbolExplanations(State state, Item finalItem, BitVectorSet conflictSymbols, TextWriter writer) { //Vyrazíme ze všech vrcholů (vrcholy jsou tady neterminální hrany automatu) //ležících v lookback(state, finalItem), které mají ve follow množině nějaký konfliktní symbol. //Prohledáváním do hloubkyv grafu relace 'includes' najdeme nejbližší vrcholy, které mají v Read //množinách dohromady všechny hledané konfliktní symboly. Posléze vyrazíme z těchto nalezených vrcholů, //tentokrát po hranách relace 'reads' a budeme hledat nejbližší vrcholy, které mají v Direct Read množinách //dohromady všechny hledané symboly. Z posledně nalezených vrcholů už jsme vždy schopni vystopovat //cestu zpět přes reads, includes a lookback hrany až k původnímu konfliktnímu itemu. //pole předků a značky u navštívených vrcholů pro oba grafy NonterminalTransition[] includesPredecessors = new NonterminalTransition[numNonterminalTransitions]; bool[] includesExplored = new bool[numNonterminalTransitions]; NonterminalTransition[] readsPredecessors = new NonterminalTransition[numNonterminalTransitions]; bool[] readsExplored = new bool[numNonterminalTransitions]; BitVectorSet symbolsLeftToExplain = new BitVectorSet(conflictSymbols); //BFS fronty pro oba průchody obou grafů Queue<NonterminalTransition> includesTransitions = new Queue<NonterminalTransition>(); Queue<NonterminalTransition> readsTransitions = new Queue<NonterminalTransition>(); //vrcholy, které mají v DR množinách konfliktní symboly List<NonterminalTransition> rootTransitions = new List<NonterminalTransition>(); //procházení po lookback hranách foreach (NonterminalTransition trans in lookback(state, finalItem)) { if (!follow[getTransNumber(trans)].IsDisjointWith(conflictSymbols)) { includesTransitions.Enqueue(trans); includesExplored[getTransNumber(trans)] = true; } } //průchod přes includes hrany while ((includesTransitions.Count > 0) && (!symbolsLeftToExplain.IsEmpty())) { NonterminalTransition trans = includesTransitions.Dequeue(); BitVectorSet readSet = read[getTransNumber(trans)]; if (!readSet.IsDisjointWith(symbolsLeftToExplain)) { BitVectorSet symbolsJustExplained = readSet.GetIntersectionWith(symbolsLeftToExplain); symbolsLeftToExplain -= symbolsJustExplained; readsTransitions.Enqueue(trans); readsExplored[getTransNumber(trans)] = true; } foreach (NonterminalTransition next in includes.GetNeighboursFor(trans)) if (!includesExplored[getTransNumber(next)]) { includesPredecessors[getTransNumber(next)] = trans; includesExplored[getTransNumber(next)] = true; includesTransitions.Enqueue(next); } } //reset hledaných symbolů a průchod přes reads hrany symbolsLeftToExplain = new BitVectorSet(conflictSymbols); while ((readsTransitions.Count > 0) && (!symbolsLeftToExplain.IsEmpty())) { NonterminalTransition trans = readsTransitions.Dequeue(); BitVectorSet DRSet = initDR(trans); if (!DRSet.IsDisjointWith(symbolsLeftToExplain)) { BitVectorSet symbolsJustExplained = DRSet.GetIntersectionWith(symbolsLeftToExplain); symbolsLeftToExplain -= symbolsJustExplained; rootTransitions.Add(trans); } foreach (NonterminalTransition next in reads.GetNeighboursFor(trans)) if (!readsExplored[getTransNumber(next)]) { readsPredecessors[getTransNumber(next)] = trans; readsExplored[getTransNumber(next)] = true; readsTransitions.Enqueue(next); } } //teď už jen vystopujeme všechny potřebné cesty z neterminální hrany, která obsahovala konfliktní //symbol ve své DR množině, až k itemu, kde tímto symbolem přispěla a způsobila konflikt foreach (NonterminalTransition root in rootTransitions) { Stack<NonterminalTransition> readsPath = new Stack<NonterminalTransition>(); Stack<NonterminalTransition> includesPath = new Stack<NonterminalTransition>(); NonterminalTransition trans = root; while (readsPredecessors[getTransNumber(trans)] != null) { readsPath.Push(trans); trans = readsPredecessors[getTransNumber(trans)]; } while (includesPredecessors[getTransNumber(trans)] != null) { includesPath.Push(trans); trans = includesPredecessors[getTransNumber(trans)]; } writer.Write("({0}, ", state.StateNumber); printItemHTML(finalItem, conflictSymbols, writer); writer.Write(") <b><i>lookback</i></b> (<a href=\"#State{0}\">{0}</a>, {1})", trans.Source.StateNumber, getSymbolPrintName(trans.TransitionSymbol)); foreach (NonterminalTransition transition in includesPath) writer.Write(" <b><i>includes</i></b> (<a href=\"#State{0}\">{0}</a>, {1})", transition.Source.StateNumber, getSymbolPrintName(transition.TransitionSymbol)); foreach (NonterminalTransition transition in readsPath) writer.Write(" <b><i>reads</i></b> (<a href=\"#State{0}\">{0}</a>, {1})", transition.Source.StateNumber, getSymbolPrintName(transition.TransitionSymbol)); writer.Write(" and {"); StringBuilder explainedSymbolsString = new StringBuilder(); foreach (int explainedSymbol in initDR(root).GetIntersectionWith(conflictSymbols)) explainedSymbolsString.AppendFormat("<span style=\"color:red\">{0}</span>, ", getSymbolPrintName(explainedSymbol)); explainedSymbolsString.Remove(explainedSymbolsString.Length - 2, 2); writer.Write(explainedSymbolsString.ToString()); writer.Write("} ⊂ <b>DR</b>(" + root.Source.StateNumber.ToString() + ", " + getSymbolPrintName(root.TransitionSymbol) + ")"); writer.WriteLine("<br>"); } }
private void printStatesHTML(TextWriter writer) { writer.WriteLine("<h2>Parser states</h2>"); if (numInconsistentStates > 0) { writer.Write("<b>States with inconsistencies:</b> "); StringBuilder inconsistentStatesString = new StringBuilder(); foreach (State state in parserStates) if (stateResolvedAt[state.StateNumber] == LookaheadComplexity.Unresolved) inconsistentStatesString.AppendFormat("<a href=\"#State{0}\">{0}</a>, ", state.StateNumber); inconsistentStatesString.Remove(inconsistentStatesString.Length - 2, 2); writer.WriteLine(inconsistentStatesString.ToString()); } foreach (State state in parserStates) { writer.Write("<a name=\"State{0}\" id=\"State{0}\"/>", state.StateNumber); if (stateResolvedAt[state.StateNumber] == LookaheadComplexity.Unresolved) writer.WriteLine("<h3 style=\"color:red\">State {0}</h3>", state.StateNumber); else writer.WriteLine("<h3>State {0}</h3>", state.StateNumber); writer.WriteLine("<b>Items:</b>"); writer.WriteLine("<ul>"); BitVectorSet conflictSymbols = new BitVectorSet(grammar.NumTerminals); if (stateResolvedAt[state.StateNumber] == LookaheadComplexity.Unresolved) { //najde symboly, pro které je tento stav nedeterministický, úpravou algoritmu na hledání //konfliktů použitém v metodě checkForConflicts BitVectorSet accumulator = new BitVectorSet(grammar.NumTerminals); foreach (Transition trans in state.Transitions) if (trans is TerminalTransition) accumulator.Add(trans.TransitionSymbol); foreach (BitVectorSet lookaheadSet in lookaheadSets[stateLookaheadIndex[state.StateNumber]]) { BitVectorSet newConflictSymbols = accumulator.GetIntersectionWith(lookaheadSet); accumulator.UnionWith(lookaheadSet); conflictSymbols.UnionWith(newConflictSymbols); } } if (stateResolvedAt[state.StateNumber] == LookaheadComplexity.LR0) { //žádný lookahead foreach (Item item in state.ItemSet) { writer.Write("<li>"); printItemHTML(item, conflictSymbols, writer); writer.WriteLine("</li>"); } } else { //nejdřív vypíšeme finální itemy a jejich lookahead množiny; pro každý konfliktní symbol //v lookahead množině navíc vypíšeme cestu, jakou se do lookahead množiny dostal for (int i = 0; i < conflictingItems[stateLookaheadIndex[state.StateNumber]].Count; i++) { writer.Write("<li>"); printItemHTML(conflictingItems[stateLookaheadIndex[state.StateNumber]][i], conflictSymbols, writer); writer.WriteLine("<br>"); printLookahead(lookaheadSets[stateLookaheadIndex[state.StateNumber]][i], conflictSymbols, writer); if (!conflictSymbols.IsDisjointWith(lookaheadSets[stateLookaheadIndex[state.StateNumber]][i])) { writer.WriteLine("<br>"); printSymbolExplanations(state, conflictingItems[stateLookaheadIndex[state.StateNumber]][i], conflictSymbols.GetIntersectionWith(lookaheadSets[stateLookaheadIndex[state.StateNumber]][i]), writer); } writer.WriteLine("</li>"); } //pak vypíšeme zbylé itemy foreach (Item item in state.ItemSet) if (!item.IsFinal) { writer.Write("<li>"); printItemHTML(item, conflictSymbols, writer); writer.WriteLine("</li>"); } } writer.WriteLine("</ul>"); writer.Write("<b>Accessing states:</b> "); StringBuilder accessingStatesString = new StringBuilder(); foreach (State accessingState in state.AccessingStates) accessingStatesString.AppendFormat("<a href=\"#State{0}\">{0}</a>, ", accessingState.StateNumber); if (accessingStatesString.Length > 0) accessingStatesString.Remove(accessingStatesString.Length - 2, 2); writer.Write(accessingStatesString.ToString()); writer.WriteLine("<br>"); writer.Write("<b>Transitions:</b> "); StringBuilder transitionsString = new StringBuilder(); foreach (Transition trans in state.Transitions) transitionsString.AppendFormat("<a href=\"#State{0}\">{0}</a>({1}), ", trans.Destination.StateNumber, getSymbolPrintName(trans.TransitionSymbol)); if (transitionsString.Length > 0) transitionsString.Remove(transitionsString.Length - 2, 2); writer.Write(transitionsString.ToString()); writer.WriteLine("<br>"); } }