/// <summary> /// Productions MUST BE: /// - left factored /// - without left recursions /// </summary> /// <param name="productions">Processed productions</param> public void FillByProcessedProductions(IEnumerable <Production> productions, Nonterminal axiom) { // A -> alpha foreach (var production in productions) { var useProductionAction = AutomateAction.FromProduction(production); // FIRST(alpha) var first = Helper.First(productions, production.RightPart); foreach (var terminal in first) { this[production.LeftPart, terminal] = useProductionAction; } if (first.Contains(GeneralizedTerminal.Epsilon)) { // FOLLOW(A) var follow = Helper.Follow(productions, production.LeftPart, axiom); foreach (var terminal in follow) { this[production.LeftPart, terminal] = useProductionAction; } } } }
private StepResults Step(out Error error) { if (_stack.Count == 0) #region When stack is empty { if (_tokenStream.Current.Type == TokenType.EndOfText) #region ACCEPT { error = null; return(StepResults.AcceptInput); } #endregion else #region REJECT: EOF EXPECTED { error = new Error(_tokenStream.Current, ErrorKind.Syntax, "End of input expected"); return(StepResults.RejectInput); } #endregion } #endregion else #region When stack is not empty { Symbol magazineSymbol = _stack.Peek(); ConcreteTerminal inputTerminal = new ConcreteTerminal(_tokenStream.Current); if (magazineSymbol is Nonterminal) { var magazineNonterminal = (Nonterminal)magazineSymbol; AutomateAction action = _controlTable[magazineNonterminal, inputTerminal]; if (action == null && CanBeEpsilon(magazineNonterminal)) { _stack.Pop(); error = null; return(StepResults.InProgress); } if (action == null) // common error handling { error = new Error(_tokenStream.Current, ErrorKind.Syntax, GenerateErrorMessage(magazineNonterminal, inputTerminal)); return(StepResults.RejectInput); } switch (action.Kind) { case AutomateActionKind.UseProduction: _stack.Pop(); // delete disclosing nonterminal Production production = action.GetProduction(); if (!production.RightPart.IsEpsilonChain) { production.RightPart.ReverseForEach(s => _stack.Push(s)); // and push right parts of productions } ConstructSyntaxTree(production); break; case AutomateActionKind.HandleError: // custom error handling break; default: break; } error = null; return(StepResults.InProgress); } else // magazineSymbol is Terminal { var magazineTerminal = (Terminal)magazineSymbol; if (magazineTerminal.IsAppropriateTerminal(inputTerminal)) { _stack.Pop(); _tokenStream.MoveNext(); SubstituteTreeTerminalByActualValue(magazineTerminal, inputTerminal); error = null; return(StepResults.InProgress); } else { error = new Error(_tokenStream.Current, ErrorKind.Syntax, GenerateErrorMessage(magazineTerminal, inputTerminal)); return(StepResults.RejectInput); } } } #endregion }