bool CheckGrammar(out string reason) { reason = string.Empty; // First Rule cannot be intermediate. if (ProductionRules.First().IsIntermediate) { reason = "First rule cannot be marked as intermediate."; return(false); } // All Rule.Name UNION Terminal.Name Must be unique var allNames = ProductionRules.Select(pr => pr.Name).Union(TerminalSymbols.Select(ts => ts.Name)); var duplicateNames = allNames.GroupBy(s => s).Where(g => g.Count() > 1); if (duplicateNames.Any()) { reason = "Duplicate names: " + string.Join(", ", duplicateNames.Select(duplicateName => duplicateName.Key)); return(false); } // Each Rule should have a Non Null "Group" as the RHS - ie Produces has been called var nullRhsProductionRuleNames = ProductionRules.Where(pr => pr.Rhs == null || pr.Rhs.Count == 0).Select(pr => pr.Name); if (nullRhsProductionRuleNames.Any()) { reason = "Rules which don't produce anything: " + string.Join(", ", nullRhsProductionRuleNames); return(false); } // A 'target' (i.e element of a RulePart) must exist in the list of Rule.Name UNION Terminal.Name var badTargetRuleNames = ProductionRules.Where(pr => pr.Rhs.Any(rp => rp.AsEnumerable().Any(target => !allNames.Contains(target.Split(new char[] { ' ' }, StringSplitOptions.RemoveEmptyEntries).First())))).Select(r => r.Name);; if (badTargetRuleNames.Any()) { reason = "Rules which produce unknown targets: " + string.Join(", ", badTargetRuleNames); return(false); } // A RuleOrTerminal should not have a RulePart where the first RuleOrTerminal is the rule. var directLeftRecursion = ProductionRules.Where(r => r.Rhs.AsEnumerable().Where(rp => rp.Count() > 0 && rp[0] == r.Name).Any()); if (directLeftRecursion.Any()) { reason = "Direct left recursion: " + string.Join(", ", directLeftRecursion); return(false); } return(true); }
public override string ToString() { StringBuilder result = new StringBuilder(); TerminalSymbols.ForEach(symbol => { if (symbol != Helper.IdentitySymbol && symbol != Helper.EmptySymbol) { result.Append(String.Format("{0}, ", symbol)); } }); result.Remove(result.Length - 2, 2); result.Append(";" + Environment.NewLine); NonterminalSymbols.ForEach(symbol => result.Append(String.Format("{0}, ", symbol))); result.Remove(result.Length - 2, 2); result.Append(";" + Environment.NewLine); result.Append(Rules.GetString()); result.Append(";" + Environment.NewLine); result.Append(StartSymbol); return(result.ToString()); }