public void StateToStringShouldCreateCorrectFormat() { var state = new PredictionState( new DottedRule( Production.From( NonTerminal.From("A"), NonTerminal.From("B"), NonTerminal.From("C")), 1), 0, null); Assert.AreEqual("A -> B\u25CFC\t\t(0)", state.ToString()); }
/// <summary> /// Implements a check for leo quasi complete items /// </summary> /// <param name="state">the state to check for quasi completeness</param> /// <returns>true if quasi complete, false otherwise</returns> private bool IsNextStateQuasiComplete(PredictionState state) { var production = state.DottedRule.Production; var symbolCount = production.Count; if (symbolCount == 0) { return(true); } var nextDot = state.DottedRule.Dot + 1; var isComplete = nextDot == production.Count; if (isComplete) { return(true); } // if all subsequent symbols are nullable for (var i = nextDot; i < production.Count; i++) { var nextSymbol = production[nextDot]; var isSymbolNullable = IsSymbolNullable(nextSymbol); if (!isSymbolNullable) { return(false); } // From Page 4 of Leo's paper: // // "on a non-empty deterministic reduction path there always // exists a topmost item if S =+> S is impossible. // The easiest way to avoid problems in this respect is to augment // the grammar with a new start symbol S'. // this means adding the rule S'=>S as the start." // // to fix this, check if S can derive S. Basically if we are in the StartState state // and the StartState state is found and is nullable, exit with false if (Grammar.Start.Is(production) && Grammar.Start.Is(nextSymbol)) { return(false); } } return(true); }
private void Predict(PredictionState evidence, int location) { var nonTerminal = evidence.DottedRule.PostDotSymbol as NonTerminal; Debug.Assert(nonTerminal != null); var rulesForNonTerminal = Grammar.ProductionsFor(nonTerminal); foreach (var production in rulesForNonTerminal) { PredictProduction(location, production); } var isNullable = Grammar.IsTransitiveNullable(nonTerminal); if (isNullable) { PredictAycockHorspool(evidence, location); } }