private ContextFreeGrammar(GrammarSymbol[] nonterminals, GrammarSymbol[] terminals, Production[] rules, GrammarSymbol starting) { // doesnt check for exception, careful this.nonterminals = nonterminals; this.terminals = terminals; this.alphabet = nonterminals.Concat(terminals).ToArray(); this.rules = rules; this.starting = starting; }
public ContextFreeGrammar GetChomskyNormalForm() { var newNonterminals = new List<GrammarSymbol>(nonterminals); var newRules = new List<Production>(rules); var toBeAddedRules = new List<Production>(); var newStarting = new GrammarSymbol("S0", false); newNonterminals.Add(newStarting); newRules.Add(new Production(newStarting, new Sentence(new[] { starting }))); for (int i = 0; i < newRules.Count; i++) { var rule = newRules[i]; var sentence = rule.DirectDerivative.ToArray(); if (rule.DirectDerivative.HasNonsolitaryTerminal) { var encountered = new List<GrammarSymbol>(); for (int j = 0; j < sentence.Length; j++) { var symbol = sentence[j]; if (symbol.IsTerminal) { string label = "N" + symbol.ToString(); GrammarSymbol newSymbol = encountered.FirstOrDefault((s) => s.Matches(label)); if (newSymbol == null) { newSymbol = new GrammarSymbol(label, false); encountered.Add(newSymbol); newNonterminals.Add(newSymbol); toBeAddedRules.Add(new Production(newSymbol, new Sentence(new[] { symbol }))); } sentence[j] = newSymbol; } } } newRules[i] = new Production(rule.Original, new Sentence(sentence)); } newRules.AddRange(toBeAddedRules); toBeAddedRules = new List<Production>(); for (int i = 0; i < newRules.Count; i++) { var rule = newRules[i]; var sentence = rule.DirectDerivative; var newSentence = sentence.ToArray(); if (sentence.HasMoreThanTwoNonterminals) { GrammarSymbol nextSymbol = rule.Original; int n = newSentence.Length; for (int j = 0; j < n - 2; j++) { var currentSymbol = nextSymbol; nextSymbol = new GrammarSymbol(rule.Original.ToString() + (i + 1).ToString(), false); newNonterminals.Add(nextSymbol); toBeAddedRules.Add(new Production(currentSymbol, new Sentence(new[] { newSentence[j], nextSymbol }))); } newRules[i] = new Production(nextSymbol, new Sentence(new[] { newSentence[n - 2], newSentence[n - 1] })); // order is somewhat scrambled } } newRules.AddRange(toBeAddedRules); toBeAddedRules = new List<Production>(); bool noEpsilonLeft = false; while (!noEpsilonLeft) { noEpsilonLeft = true; foreach (var rule in newRules) if (rule.DirectDerivative.IsEmpty && rule.Original != newStarting) { GrammarSymbol nullable = rule.Original; bool isLastRule = newRules.Count((r) => r.Original == nullable) == 0; if (!isLastRule) for (int i = 0; i < newRules.Count(); i++) { var oldSymbol = newRules[i].Original; var sentence = newRules[i].DirectDerivative.ToArray(); int n = sentence.Length; Debug.Assert(n < 3); if (n == 1 && sentence[0] == nullable) AddIfNotExist(ref newRules, new Production(oldSymbol, Sentence.Empty)); else if (n == 2) { if (sentence[0] == sentence[1] && sentence[0] == nullable) { AddIfNotExist(ref newRules, new Production(oldSymbol, Sentence.Empty)); AddIfNotExist(ref newRules, new Production(oldSymbol, new Sentence(new[] { sentence[0] }))); } else if (sentence[0] == nullable) AddIfNotExist(ref newRules, new Production(oldSymbol, new Sentence(new[] { sentence[1] }))); else if (sentence[1] == nullable) AddIfNotExist(ref newRules, new Production(oldSymbol, new Sentence(new[] { sentence[0] }))); } } else { for (int i = 0; i < newRules.Count(); i++) { var oldSymbol = newRules[i].Original; var sentence = newRules[i].DirectDerivative.ToArray(); int n = sentence.Length; Debug.Assert(n < 3); if (n == 1 && sentence[0] == nullable) AddIfNotExist(ref newRules, new Production(oldSymbol, Sentence.Empty)); else if (n == 2) { if (sentence[0] == sentence[1] && sentence[0] == nullable) AddIfNotExist(ref newRules, new Production(oldSymbol, Sentence.Empty)); else if (sentence[0] == nullable) AddIfNotExist(ref newRules, new Production(oldSymbol, new Sentence(new[] { sentence[1] }))); else AddIfNotExist(ref newRules, new Production(oldSymbol, new Sentence(new[] { sentence[0] }))); } } newNonterminals.Remove(nullable); } newRules.Remove(rule); toBeAddedRules = new List<Production>(); noEpsilonLeft = false; break; } } bool noUnitRuleLeft = false; while (!noUnitRuleLeft) { noUnitRuleLeft = true; foreach (var rule in newRules) { bool isUnitRule = rule.DirectDerivative.Length == 1 && !rule.DirectDerivative.First().IsTerminal; if (isUnitRule) { newRules.Remove(rule); var toBeReplaced = rule.DirectDerivative.First(); var replacement = rule.Original; for (int i = 0; i < newRules.Count(); i++) { var oldSymbol = newRules[i].Original; var sentence = newRules[i].DirectDerivative.ToArray(); if (oldSymbol == toBeReplaced) toBeAddedRules.Add(new Production(replacement, new Sentence(sentence))); } newNonterminals.Remove(toBeReplaced); newRules.AddRange(toBeAddedRules); toBeAddedRules = new List<Production>(); noUnitRuleLeft = false; break; } } } return new ContextFreeGrammar(newNonterminals.ToArray(), this.terminals, newRules.ToArray(), newStarting); }
private void AddIfNotExist(ref List<Production> newRules, Production toBeAdded) { foreach (Production rule in newRules) if (rule.Original == toBeAdded.Original && rule.DirectDerivative.SequenceEqual(toBeAdded.DirectDerivative)) return; newRules.Add(toBeAdded); }
public ContextFreeGrammar GetChomskyNormalForm() { var newNonterminals = new List <GrammarSymbol>(nonterminals); var newRules = new List <Production>(rules); var toBeAddedRules = new List <Production>(); var newStarting = new GrammarSymbol("S0", false); newNonterminals.Add(newStarting); newRules.Add(new Production(newStarting, new Sentence(new[] { starting }))); for (int i = 0; i < newRules.Count; i++) { var rule = newRules[i]; var sentence = rule.DirectDerivative.ToArray(); if (rule.DirectDerivative.HasNonsolitaryTerminal) { var encountered = new List <GrammarSymbol>(); for (int j = 0; j < sentence.Length; j++) { var symbol = sentence[j]; if (symbol.IsTerminal) { string label = "N" + symbol.ToString(); GrammarSymbol newSymbol = encountered.FirstOrDefault((s) => s.Matches(label)); if (newSymbol == null) { newSymbol = new GrammarSymbol(label, false); encountered.Add(newSymbol); newNonterminals.Add(newSymbol); toBeAddedRules.Add(new Production(newSymbol, new Sentence(new[] { symbol }))); } sentence[j] = newSymbol; } } } newRules[i] = new Production(rule.Original, new Sentence(sentence)); } newRules.AddRange(toBeAddedRules); toBeAddedRules = new List <Production>(); for (int i = 0; i < newRules.Count; i++) { var rule = newRules[i]; var sentence = rule.DirectDerivative; var newSentence = sentence.ToArray(); if (sentence.HasMoreThanTwoNonterminals) { GrammarSymbol nextSymbol = rule.Original; int n = newSentence.Length; for (int j = 0; j < n - 2; j++) { var currentSymbol = nextSymbol; nextSymbol = new GrammarSymbol(rule.Original.ToString() + (i + 1).ToString(), false); newNonterminals.Add(nextSymbol); toBeAddedRules.Add(new Production(currentSymbol, new Sentence(new[] { newSentence[j], nextSymbol }))); } newRules[i] = new Production(nextSymbol, new Sentence(new[] { newSentence[n - 2], newSentence[n - 1] })); // order is somewhat scrambled } } newRules.AddRange(toBeAddedRules); toBeAddedRules = new List <Production>(); bool noEpsilonLeft = false; while (!noEpsilonLeft) { noEpsilonLeft = true; foreach (var rule in newRules) { if (rule.DirectDerivative.IsEmpty && rule.Original != newStarting) { GrammarSymbol nullable = rule.Original; bool isLastRule = newRules.Count((r) => r.Original == nullable) == 0; if (!isLastRule) { for (int i = 0; i < newRules.Count(); i++) { var oldSymbol = newRules[i].Original; var sentence = newRules[i].DirectDerivative.ToArray(); int n = sentence.Length; Debug.Assert(n < 3); if (n == 1 && sentence[0] == nullable) { AddIfNotExist(ref newRules, new Production(oldSymbol, Sentence.Empty)); } else if (n == 2) { if (sentence[0] == sentence[1] && sentence[0] == nullable) { AddIfNotExist(ref newRules, new Production(oldSymbol, Sentence.Empty)); AddIfNotExist(ref newRules, new Production(oldSymbol, new Sentence(new[] { sentence[0] }))); } else if (sentence[0] == nullable) { AddIfNotExist(ref newRules, new Production(oldSymbol, new Sentence(new[] { sentence[1] }))); } else if (sentence[1] == nullable) { AddIfNotExist(ref newRules, new Production(oldSymbol, new Sentence(new[] { sentence[0] }))); } } } } else { for (int i = 0; i < newRules.Count(); i++) { var oldSymbol = newRules[i].Original; var sentence = newRules[i].DirectDerivative.ToArray(); int n = sentence.Length; Debug.Assert(n < 3); if (n == 1 && sentence[0] == nullable) { AddIfNotExist(ref newRules, new Production(oldSymbol, Sentence.Empty)); } else if (n == 2) { if (sentence[0] == sentence[1] && sentence[0] == nullable) { AddIfNotExist(ref newRules, new Production(oldSymbol, Sentence.Empty)); } else if (sentence[0] == nullable) { AddIfNotExist(ref newRules, new Production(oldSymbol, new Sentence(new[] { sentence[1] }))); } else { AddIfNotExist(ref newRules, new Production(oldSymbol, new Sentence(new[] { sentence[0] }))); } } } newNonterminals.Remove(nullable); } newRules.Remove(rule); toBeAddedRules = new List <Production>(); noEpsilonLeft = false; break; } } } bool noUnitRuleLeft = false; while (!noUnitRuleLeft) { noUnitRuleLeft = true; foreach (var rule in newRules) { bool isUnitRule = rule.DirectDerivative.Length == 1 && !rule.DirectDerivative.First().IsTerminal; if (isUnitRule) { newRules.Remove(rule); var toBeReplaced = rule.DirectDerivative.First(); var replacement = rule.Original; for (int i = 0; i < newRules.Count(); i++) { var oldSymbol = newRules[i].Original; var sentence = newRules[i].DirectDerivative.ToArray(); if (oldSymbol == toBeReplaced) { toBeAddedRules.Add(new Production(replacement, new Sentence(sentence))); } } newNonterminals.Remove(toBeReplaced); newRules.AddRange(toBeAddedRules); toBeAddedRules = new List <Production>(); noUnitRuleLeft = false; break; } } } return(new ContextFreeGrammar(newNonterminals.ToArray(), this.terminals, newRules.ToArray(), newStarting)); }