/// <summary> /// Removes useless symbols from the grammar. /// Assumes that the language is nonempty. /// </summary> public ContextFreeGrammar RemoveUselessSymbols() { HashSet <Nonterminal> useful_backwards = new HashSet <Nonterminal>(); //Lemma 4.1, p. 88, Hopcroft-Ullman #region backward reachability var variableNodeMap = new Dictionary <Nonterminal, VariableNode>(); foreach (Nonterminal v in this.variables) { variableNodeMap[v] = new VariableNode(); } List <ProductionNode> productionLeaves = new List <ProductionNode>(); foreach (Nonterminal v in this.variables) { VariableNode parent = variableNodeMap[v]; foreach (Production p in this.productionMap[v]) { var children = Array.ConvertAll(new List <Nonterminal>(p.GetVariables()).ToArray(), w => variableNodeMap[w]); ProductionNode pn = new ProductionNode(parent, children); if (children.Length == 0) { productionLeaves.Add(pn); } else { foreach (VariableNode child in children) { child.parents.Add(pn); } } } } foreach (ProductionNode leaf in productionLeaves) { leaf.PropagateMark(); } foreach (Nonterminal v in this.variables) { if (variableNodeMap[v].isMarked) { useful_backwards.Add(v); } } #endregion if (!useful_backwards.Contains(this.startSymbol)) { throw new AutomataException(AutomataExceptionKind.LanguageOfGrammarIsEmpty); } ContextFreeGrammar g1 = this.RestrictToVariables(useful_backwards); HashSet <Nonterminal> useful_forwards = new HashSet <Nonterminal>(); //Lemma 4.2, p. 89, Hopcroft-Ullman #region forward reachability Stack <Nonterminal> stack = new Stack <Nonterminal>(); stack.Push(g1.StartSymbol); useful_forwards.Add(g1.StartSymbol); while (stack.Count > 0) { Nonterminal v = stack.Pop(); foreach (Production p in g1.GetProductions(v)) { foreach (Nonterminal u in p.GetVariables()) { if (!useful_forwards.Contains(u)) { useful_forwards.Add(u); stack.Push(u); } } } } #endregion ContextFreeGrammar g2 = g1.RestrictToVariables(useful_forwards); return(g2); }
/// <summary> /// Return all useful nonterminal symbols. If checkBackwardsOnly is true, assume that all symbols are reachable from the start symbol. /// </summary> public HashSet <string> GetUsefulNonterminals(bool checkBackwardsOnly) { HashSet <Nonterminal> useful_backwards = new HashSet <Nonterminal>(); //Lemma 4.1, p. 88, Hopcroft-Ullman #region backward reachability var variableNodeMap = new Dictionary <Nonterminal, VariableNode>(); foreach (Nonterminal v in this.variables) { variableNodeMap[v] = new VariableNode(); } List <ProductionNode> productionLeaves = new List <ProductionNode>(); foreach (Nonterminal v in this.variables) { VariableNode parent = variableNodeMap[v]; foreach (Production p in this.productionMap[v]) { var children = Array.ConvertAll(new List <Nonterminal>(p.GetVariables()).ToArray(), w => variableNodeMap[w]); ProductionNode pn = new ProductionNode(parent, children); if (children.Length == 0) { productionLeaves.Add(pn); } else { foreach (VariableNode child in children) { child.parents.Add(pn); } } } } foreach (ProductionNode leaf in productionLeaves) { leaf.PropagateMark(); } foreach (Nonterminal v in this.variables) { if (variableNodeMap[v].isMarked) { useful_backwards.Add(v); } } #endregion //returns the empty set because the language is empty if (!useful_backwards.Contains(this.startSymbol)) { return(new HashSet <string>()); } //don't bother to check forward if (checkBackwardsOnly) { var res = new HashSet <string>(); foreach (var nt in useful_backwards) { res.Add(nt.Name); } return(res); } ContextFreeGrammar g1 = this.RestrictToVariables(useful_backwards); HashSet <Nonterminal> useful_forwards = new HashSet <Nonterminal>(); //Lemma 4.2, p. 89, Hopcroft-Ullman #region forward reachability Stack <Nonterminal> stack = new Stack <Nonterminal>(); stack.Push(g1.StartSymbol); useful_forwards.Add(g1.StartSymbol); while (stack.Count > 0) { Nonterminal v = stack.Pop(); foreach (Production p in g1.GetProductions(v)) { foreach (Nonterminal u in p.GetVariables()) { if (!useful_forwards.Contains(u)) { useful_forwards.Add(u); stack.Push(u); } } } } #endregion HashSet <string> usefulSymbols = new HashSet <string>(); foreach (var nt in useful_forwards) { if (useful_backwards.Contains(nt)) { usefulSymbols.Add(nt.Name); } } return(usefulSymbols); }
internal ProductionNode(VariableNode parent, params VariableNode[] children) { this.parent = parent; this.children = new HashSet <VariableNode>(children); }