private void ValidateGrammar() { var createAst = _grammar.LanguageFlags.IsSet(LanguageFlags.CreateAst); var invalidTransSet = new NonTerminalSet(); foreach (var nt in _grammarData.NonTerminals) { if (nt.Flags.IsSet(TermFlags.IsTransient)) { //List non-terminals cannot be marked transient - otherwise there may be some ambiguities and inconsistencies if (nt.Flags.IsSet(TermFlags.IsList)) { _language.Errors.Add(GrammarErrorLevel.Error, null, Resources.ErrListCannotBeTransient, nt.Name); } //Count number of non-punctuation child nodes in each production foreach (var prod in nt.Productions) { if (CountNonPunctuationTerms(prod) > 1) { invalidTransSet.Add(nt); } } } //Validate error productions foreach (var prod in nt.Productions) { if (prod.Flags.IsSet(ProductionFlags.IsError)) { var lastTerm = prod.RValues[prod.RValues.Count - 1]; if (!(lastTerm is Terminal) || lastTerm == _grammar.SyntaxError) { _language.Errors.Add(GrammarErrorLevel.Warning, null, Resources.ErrLastTermOfErrorProd, nt.Name); } // "The last term of error production must be a terminal. NonTerminal: {0}" } } } if (invalidTransSet.Count > 0) { _language.Errors.Add(GrammarErrorLevel.Error, null, Resources.ErrTransientNtMustHaveOneTerm, invalidTransSet.ToString()); } }
private static void ComputeNonTerminalsNullability(GrammarData data) { var undecided = data.NonTerminals; while (undecided.Count > 0) { var newUndecided = new NonTerminalSet(); foreach (var nt in undecided) { if (!ComputeNullability(nt)) { newUndecided.Add(nt); } } if (undecided.Count == newUndecided.Count) { return; //we didn't decide on any new, so we're done } undecided = newUndecided; } }