/// <summary> /// Gets all nonterminals defined by the <see cref="Grammar" />. /// </summary> /// <returns>An array of <see cref="NonterminalType" /> that represents all nonterminals defined by the <see cref="Grammar" />.</returns> public NonterminalType[] GetNonterminals() { var nonterminals = new NonterminalType[_nonterminals.Values.Count]; _nonterminals.Values.CopyTo(nonterminals, 0); return(nonterminals); }
/// <summary> /// Gets the <see cref="ParserState"/> associated with a <see cref="NonterminalType"/> as defined by <see cref="Gotos"/>. /// </summary> /// <param name="nonterminalType">A <see cref="NonterminalType"/> object.</param> /// <returns>The <see cref="ParserState"/> associated with <paramref name="nonterminalType"/> as defined by <see cref="Gotos"/>. /// Returns <value>null</value> if no such <see cref="ParserState"/> exists.</returns> public ParserState GetGoto(NonterminalType nonterminalType) { ParserState state; if (m_gotos.TryGetValue(nonterminalType, out state)) { return(state); } return(null); }
/// <summary> /// Retrieves the terminal or nonterminal definition from the specified <see cref="Type"/> and adds it to the /// <see cref="Grammar"/>. /// </summary> /// <param name="type">A <see cref="Type"/> containing a terminal or nonterminal definition.</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> /// <returns>The <see cref="LanguageElementType"/> added to the <see cref="Grammar"/>. If the specified <see cref="Type"/> /// did not represent a terminal or nonterminal definition, <value>null</value> is returned. /// </returns> public LanguageElementType Load(Type type, string name) { if (TypeIsTerminal(type, name)) { TerminalType terminalType = new TerminalType(type); m_terminals.Add(type, terminalType); return(terminalType); } if (TypeIsNonterminal(type, name)) { NonterminalType nonterminalType = new NonterminalType(type); m_nonterminals.Add(type, nonterminalType); return(nonterminalType); } return(null); }
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> /// Initializes a new instance of the <see cref="RuleType"/> class. /// </summary> /// <param name="methodInfo">The <see cref="MethodInfo"/> associated with this <see cref="RuleType"/>.</param> /// <param name="priority">The priority of this rule used to resolve conflicts with other rules during parser generation.</param> /// <param name="lhs">The <see cref="NonterminalType"/> representing the LHS of this rule.</param> /// <param name="rhs">The collection of <see cref="LanguageElementType"/> representing the RHS of this rule.</param> public RuleType(MethodInfo methodInfo, int priority, NonterminalType lhs, LanguageElementType[] rhs) { var sb = new StringBuilder(); sb.Append(methodInfo.Name); sb.Append("["); string prefix = null; foreach (var parameter in methodInfo.GetParameters()) { sb.Append(prefix); prefix = ","; sb.Append(parameter.ParameterType.Name); } sb.Append("]"); var name = sb.ToString(); FullName = string.Format("{0}::{1}", methodInfo.DeclaringType.FullName, name); Name = name; _delegate = parameters => methodInfo.Invoke(null, parameters); Priority = priority; _lhs = lhs; Rhs = rhs; }
/// <summary> /// Initializes a new instance of the <see cref="RuleType"/> class. /// </summary> /// <param name="methodInfo">The <see cref="MethodInfo"/> associated with this <see cref="RuleType"/>.</param> /// <param name="priority">The priority of this rule used to resolve conflicts with other rules during parser generation.</param> /// <param name="lhs">The <see cref="NonterminalType"/> representing the LHS of this rule.</param> /// <param name="rhs">The collection of <see cref="LanguageElementType"/> representing the RHS of this rule.</param> public RuleType(MethodInfo methodInfo, int priority, NonterminalType lhs, LanguageElementType[] rhs) { StringBuilder sb = new StringBuilder(); sb.Append(methodInfo.Name); sb.Append("["); string prefix = null; foreach (ParameterInfo parameter in methodInfo.GetParameters()) { sb.Append(prefix); prefix = ","; sb.Append(parameter.ParameterType.Name); } sb.Append("]"); string name = sb.ToString(); m_fullName = string.Format("{0}::{1}", methodInfo.DeclaringType.FullName, name); m_name = name; m_delegate = delegate(LanguageElement[] parameters) { methodInfo.Invoke(null, parameters); }; m_priority = priority; m_lhs = lhs; m_rhs = rhs; }
/// <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> /// Constructs a new <see cref="Parser"/> which can recoganize the specified <see cref="IGrammar"/>. /// </summary> /// <param name="grammar">The <see cref="IGrammar"/> to be recognized by the <see cref="Parser"/>.</param> /// <returns>A <see cref="ParserGeneratorResult"/> containing <see cref="Parser"/> and information pertaining to the /// success or failure of the generation process. /// </returns> public ParserGeneratorResult GenerateParser(IGrammar grammar) { List <ParserGeneratorParserConflict> conflicts = new List <ParserGeneratorParserConflict>(); List <GeneratorState> states = CreateStates(grammar); // Create a parser state for each generator state. // Dictionary <GeneratorState, ParserState> parserStates = new Dictionary <GeneratorState, ParserState>(); foreach (GeneratorState state in states) { parserStates.Add(state, new ParserState(state.Id)); } foreach (GeneratorState state in states) { LinguaTrace.TraceEvent(TraceEventType.Verbose, LinguaTraceId.ID_GENERATE_PROCESS_STATE, "{0}", state); List <GeneratorStateItem> items = new List <GeneratorStateItem>(state.Items); items.Sort(); // Construct the list of actions associated with the parser state. // Dictionary <TerminalType, ParserAction> actions = new Dictionary <TerminalType, ParserAction>(); Dictionary <ParserAction, GeneratorRuleItem> actionRules = new Dictionary <ParserAction, GeneratorRuleItem>(); foreach (GeneratorStateItem item in items) { LinguaTrace.TraceEvent(TraceEventType.Verbose, LinguaTraceId.ID_GENERATE_PROCESS_ITEM, "{0}", item); if (item.RuleItem.DotElement == null) { foreach (TerminalType terminal in item.RuleItem.Rule.Lhs.Follow) { LinguaTrace.TraceEvent(TraceEventType.Verbose, LinguaTraceId.ID_GENERATE_PROCESS_TERMINAL, "{0}", terminal); if (actions.ContainsKey(terminal)) { ParserGeneratorParserConflict conflict = new ParserGeneratorParserConflict( actionRules[actions[terminal]].ToString(), item.RuleItem.ToString()); LinguaTrace.TraceEvent(TraceEventType.Information, LinguaTraceId.ID_GENERATE_PROCESS_CONFLICT, "{0}", conflict); conflicts.Add(conflict); } else if (item.RuleItem.Rule.Lhs.IsStart && terminal.IsStop) { ParserAction action = new ParserActionAccept(item.RuleItem.Rule); LinguaTrace.TraceEvent(TraceEventType.Information, LinguaTraceId.ID_GENERATE_PROCESS_ACTION, "{0}", action); actions.Add(terminal, action); actionRules.Add(action, item.RuleItem); } else { ParserAction action = new ParserActionReduce(item.RuleItem.Rule); LinguaTrace.TraceEvent(TraceEventType.Information, LinguaTraceId.ID_GENERATE_PROCESS_ACTION, "{0}", action); actions.Add(terminal, action); actionRules.Add(action, item.RuleItem); } } } else if (item.RuleItem.DotElement.ElementType == LanguageElementTypes.Terminal) { TerminalType terminal = (TerminalType)item.RuleItem.DotElement; if (actions.ContainsKey(terminal)) { ParserGeneratorParserConflict conflict = new ParserGeneratorParserConflict( actionRules[actions[terminal]].ToString(), item.RuleItem.ToString()); LinguaTrace.TraceEvent(TraceEventType.Information, LinguaTraceId.ID_GENERATE_PROCESS_CONFLICT, "{0}", conflict); conflicts.Add(conflict); } else { ParserAction action = new ParserActionShift(parserStates[state.Transitions[terminal]]); LinguaTrace.TraceEvent(TraceEventType.Information, LinguaTraceId.ID_GENERATE_PROCESS_ACTION, "{0}", action); actions.Add(terminal, action); actionRules.Add(action, item.RuleItem); } } } // Construct the GOTO table // Dictionary <NonterminalType, ParserState> gotos = new Dictionary <NonterminalType, ParserState>(); foreach (KeyValuePair <LanguageElementType, GeneratorState> transition in state.Transitions) { if (transition.Key.ElementType == LanguageElementTypes.Nonterminal) { NonterminalType nonterminal = (NonterminalType)transition.Key; gotos.Add(nonterminal, parserStates[transition.Value]); } } // Update the parser state. // ParserState parserState = parserStates[state]; foreach (KeyValuePair <TerminalType, ParserAction> action in actions) { parserState.Actions.Add(action.Key, action.Value); } foreach (KeyValuePair <NonterminalType, ParserState> gotoItem in gotos) { parserState.Gotos.Add(gotoItem.Key, gotoItem.Value); } } Parser parser = new Parser(parserStates[states[0]]); ParserGeneratorResult result = new ParserGeneratorResult(parser, conflicts); return(result); }
/// <summary> /// Gets the <see cref="ParserState"/> associated with a <see cref="NonterminalType"/> as defined by <see cref="Gotos"/>. /// </summary> /// <param name="nonterminalType">A <see cref="NonterminalType"/> object.</param> /// <returns>The <see cref="ParserState"/> associated with <paramref name="nonterminalType"/> as defined by <see cref="Gotos"/>. /// Returns <value>null</value> if no such <see cref="ParserState"/> exists.</returns> public ParserState GetGoto(NonterminalType nonterminalType) { ParserState state; return _gotos.TryGetValue(nonterminalType, out state) ? state : null; }
/// <summary> /// Gets all nonterminals defined by the <see cref="Grammar" />. /// </summary> /// <returns>An array of <see cref="NonterminalType" /> that represents all nonterminals defined by the <see cref="Grammar" />.</returns> public NonterminalType[] GetNonterminals() { NonterminalType[] nonterminals = new NonterminalType[m_nonterminals.Values.Count]; m_nonterminals.Values.CopyTo(nonterminals, 0); return nonterminals; }
/// <summary> /// Retrieves the terminal or nonterminal definition from the specified <see cref="Type"/> and adds it to the /// <see cref="Grammar"/>. /// </summary> /// <param name="type">A <see cref="Type"/> containing a terminal or nonterminal definition.</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> /// <returns>The <see cref="LanguageElementType"/> added to the <see cref="Grammar"/>. If the specified <see cref="Type"/> /// did not represent a terminal or nonterminal definition, <value>null</value> is returned. /// </returns> public LanguageElementType Load(Type type, string name) { if (TypeIsTerminal(type, name)) { TerminalType terminalType = new TerminalType(type); m_terminals.Add(type, terminalType); return terminalType; } if (TypeIsNonterminal(type, name)) { NonterminalType nonterminalType = new NonterminalType(type); m_nonterminals.Add(type, nonterminalType); return nonterminalType; } return null; }
/// <summary> /// Gets the <see cref="ParserState"/> associated with a <see cref="NonterminalType"/> as defined by <see cref="Gotos"/>. /// </summary> /// <param name="nonterminalType">A <see cref="NonterminalType"/> object.</param> /// <returns>The <see cref="ParserState"/> associated with <paramref name="nonterminalType"/> as defined by <see cref="Gotos"/>. /// Returns <value>null</value> if no such <see cref="ParserState"/> exists.</returns> public ParserState GetGoto(NonterminalType nonterminalType) { ParserState state; if (m_gotos.TryGetValue(nonterminalType, out state)) { return state; } return null; }