/// <summary> /// Performs syntax analysis against a sequence of terminals according to the <see cref="Grammar"/> used to create the <see cref="Parser"/>. /// </summary> /// <param name="terminalReader">Retrieves a sequence of <see cref="Terminal"/> objects.</param> /// <returns>If syntax analysis succeeds, returns the <see cref="Nonterminal"/> associated with <see cref="Grammar.StartNonterminal"/>. Otherwise, <value>null</value> is returned.</returns> public Nonterminal Parse(ITerminalReader terminalReader) { ParserStack stack = new ParserStack(); stack.Push(null, InitialState); Terminal terminal = terminalReader.ReadTerminal(); while (terminal != null) { if (terminal.ElementType.Ignore) { terminal = terminalReader.ReadTerminal(); } else { ParserAction action = stack.Peek().State.GetAction(terminal.ElementType); LinguaTrace.TraceEvent(TraceEventType.Information, LinguaTraceId.ID_PARSE_ACTION, "{0}", action); if (action == null) { return(null); } switch (action.ActionType) { case ParserActionTypes.Accept: { ParserActionAccept reduce = (ParserActionAccept)action; RuleType rule = reduce.Rule; Nonterminal lhs = Reduce(stack, rule); return(lhs); } case ParserActionTypes.Shift: { ParserActionShift shift = (ParserActionShift)action; stack.Push(terminal, shift.State); terminal = terminalReader.ReadTerminal(); } break; case ParserActionTypes.Reduce: { ParserActionReduce reduce = (ParserActionReduce)action; RuleType rule = reduce.Rule; Nonterminal lhs = Reduce(stack, rule); // Push the LHS nonterminal on the stack. // stack.Push(lhs, stack.Peek().State.GetGoto(lhs.ElementType)); } break; default: throw new InvalidOperationException(string.Format("Unrecognized action type {0}.", action.ActionType)); } } } ; return(null); }
/// <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); }