/// <summary> /// Computes a new set of <see cref="GeneratorStateItem"/> objects based on items in the current <see cref="GeneratorState"/> /// identified by the specified <see cref="LanguageElementType"/> /// </summary> /// <param name="languageElementType">A <see cref="LanguageElementType"/> object.</param> /// <returns>A <see cref="HashSet{GeneratorStateItem}"/> containing items identified by <paramref name="languageElementType"/>.</returns> /// <remarks> /// If this <see cref="GeneratorState"/> contains a <see cref="GeneratorRuleItem"/> representing an LR(0) item of the /// form <value>X→Y₁…○Z…Yₓ</value> and <see cref="LanguageElementType"/> is <value>Z</value>, the /// result will contain a <see cref="GeneratorRuleItem"/> representing an LR(0) item of the /// form <value>X→Y₁…Z○…Yₓ</value>. /// </remarks> public HashSet <GeneratorStateItem> Apply(LanguageElementType languageElementType) { HashSet <GeneratorStateItem> result = null; foreach (var item in Items.Where(item => item.RuleItem.DotElement == languageElementType)) { if (result == null) { result = new HashSet <GeneratorStateItem>(); } result.Add(new GeneratorStateItem(new GeneratorRuleItem(item.RuleItem.Rule, item.RuleItem.Dot + 1))); } return(result); }
private void ComputeClosure(IGrammar grammar, HashSet <GeneratorStateItem> items) { // Continue to loop until new more elements are added to the state. // bool stateModified = true; while (stateModified) { HashSet <GeneratorStateItem> newItems = new HashSet <GeneratorStateItem>(); // Iterate over the current elements in the state and determine (possible) new // elements to be added. // foreach (GeneratorStateItem item in items) { LanguageElementType languageElement = item.RuleItem.DotElement; if (languageElement != null && languageElement.ElementType == LanguageElementTypes.Nonterminal) { NonterminalType nonterminal = (NonterminalType)languageElement; foreach (RuleType rule in nonterminal.Rules) { GeneratorStateItem newItem = new GeneratorStateItem(new GeneratorRuleItem(rule, 0)); newItems.Add(newItem); } } } // Exit loop if all potential new elements already exist in state. Otherwise, add new elements // and repeat process. // if (newItems.IsSubsetOf(items)) { stateModified = false; } else { items.UnionWith(newItems); } } }
/// <summary> /// Retrieves all rule definitions from the specified <see cref="Type"/> and adds them to the <see cref="Grammar"/>. /// </summary> /// <param name="type">A <see cref="Type"/> containing rule definitions.</param> /// <param name="name">The name of the grammar being loaded as defined by <see cref="GrammarAttribute"/>. Specify <value>null</value> to load <paramref name="type"/> regardless of grammar name.</param> public void LoadRules(Type type, string name) { // Ensure type is in specified grammar. // if (!IsGrammarType(type, name)) { return; } // Load rules defined by type. // foreach (MethodInfo method in type.GetMethods()) { ParameterInfo[] parameters = method.GetParameters(); if (MethodIsRule(method, parameters)) { // Determine priority associated with rule. // int priority = 0; object[] attributes = method.GetCustomAttributes(typeof(RuleAttribute), false); if (attributes.Length > 0) { RuleAttribute attribute = attributes[0] as RuleAttribute; if (attribute != null) { priority = attribute.Priority; } } // Find the grammer language elements associated with each parameter member. // NonterminalType lhs = null; List <LanguageElementType> rhs = new List <LanguageElementType>(); for (int idx = 0; idx < parameters.Length; ++idx) { Type parameterType = parameters[idx].ParameterType; if (idx == 0) { NonterminalType nonterminal; if (m_nonterminals.TryGetValue(parameterType, out nonterminal)) { lhs = nonterminal; } else { throw new InvalidOperationException(); } } else { NonterminalType nonterminal; if (m_nonterminals.TryGetValue(parameterType, out nonterminal)) { rhs.Add(nonterminal); } else { TerminalType terminal; if (m_terminals.TryGetValue(parameterType, out terminal)) { rhs.Add(terminal); } else { // If parameterType is currently not defined by the grammar, attempt to process it // now. This occurs when OptionalTerminal<> and OptionalNonterminal<> types // appear in the RHS side of a rule. // LanguageElementType languageElementType = Load(parameterType, name); if (languageElementType != null) { rhs.Add(languageElementType); LoadRules(parameterType, name); } else { throw new InvalidOperationException("Unrecognized rule argument."); } } } } } // Create the rule. // RuleType rule = new RuleType(method, priority, lhs, rhs.ToArray()); lhs.Rules.Add(rule); } } }
private void ComputeFollow() { StartNonterminal.Follow.Add(StopTerminal); // Continue adding elements until no more changes to FOLLOW are made. // bool change = true; while (change) { change = false; // Iterate over all nonterminals and their rules. // foreach (NonterminalType x in m_nonterminals.Values) { foreach (RuleType rule in x.Rules) { // For rules of the form X -> ... Y B1 B2 ... Bn, add FIRST(Bi) (excluding e) // to FOLLOW(Y) if FIRST(Bj) contains e for all j < i. Add FOLLOW(X) to // FOLLOW(Y) if FIRST(Bi) contains e for all i. // for (int idx = 0; idx < rule.Rhs.Length; ++idx) { if (rule.Rhs[idx].ElementType == LanguageElementTypes.Nonterminal) { NonterminalType y = (NonterminalType)rule.Rhs[idx]; bool epsilonInAllB = true; for (int j = idx + 1; j < rule.Rhs.Length; ++j) { LanguageElementType b = rule.Rhs[j]; HashSet <TerminalType> bFirst = b.First.GetSetExcludingEpsilon(); if (bFirst.Count > 0 && !bFirst.IsSubsetOf(y.Follow)) { y.Follow.UnionWith(bFirst); change = true; } if (!b.First.ContainsEpsilon) { epsilonInAllB = false; break; } } if (epsilonInAllB) { if (x.Follow.Count > 0 && !x.Follow.IsSubsetOf(y.Follow)) { y.Follow.UnionWith(x.Follow); change = true; } } } } } } } }
/// <summary> /// Computes a new set of <see cref="GeneratorStateItem"/> objects based on items in the current <see cref="GeneratorState"/> /// identified by the specified <see cref="LanguageElementType"/> /// </summary> /// <param name="languageElementType">A <see cref="LanguageElementType"/> object.</param> /// <returns>A <see cref="HashSet{GeneratorStateItem}"/> containing items identified by <paramref name="languageElementType"/>.</returns> /// <remarks> /// If this <see cref="GeneratorState"/> contains a <see cref="GeneratorRuleItem"/> representing an LR(0) item of the /// form <value>X→Y₁…○Z…Yₓ</value> and <see cref="LanguageElementType"/> is <value>Z</value>, the /// result will contain a <see cref="GeneratorRuleItem"/> representing an LR(0) item of the /// form <value>X→Y₁…Z○…Yₓ</value>. /// </remarks> public HashSet<GeneratorStateItem> Apply(LanguageElementType languageElementType) { HashSet<GeneratorStateItem> result = null; foreach (var item in Items.Where(item => item.RuleItem.DotElement == languageElementType)) { if (result == null) { result = new HashSet<GeneratorStateItem>(); } result.Add(new GeneratorStateItem(new GeneratorRuleItem(item.RuleItem.Rule, item.RuleItem.Dot + 1))); } return result; }