/// <summary> /// Gets the set of terminal symbols that could follow the nonterminal symbol s /// in the current item-set. /// </summary> /// <param name="s"></param> /// <returns></returns> public IEnumerable <ITerminalSymbol> Follows(INonterminalSymbol s) { var result = new HashSet <ITerminalSymbol>(); foreach (var e in items.Where(i => !i.AtEnd && i.NextSymbol == s)) { ProductionRule rule = e.Rule; int index; for (index = e.DotPosition + 1; index < rule.rhs.Length; ++index) { foreach (var t in rule.rhs[index].First) { result.Add(t); } if (!rule.rhs[index].CanBeEmpty) { break; } } if (index == rule.rhs.Length) { // This wasn't documented properly I don't think // Also add the lookahead of the matched item if the rule can match at the end of the rule. result.Add(e.Lookahead[0]); } } return(result); }
public State CreateInitialState(INonterminalSymbol s) { var state = new State(); foreach (var rule in s.Rules) { state.items.Add(new Item(rule, 0)); } ExpandClosure(state); return(state); }
public State CreateInitialState(INonterminalSymbol s) { // Hack to find the "eof" symbol ITerminalSymbol eof = (ITerminalSymbol)s.Rules.First().rhs[1]; var state = new State(); foreach (var rule in s.Rules) { state.items.Add(new Item(rule, 0, eof)); } return(state); }
public void Reduce(Token next, object value, INonterminalSymbol pushedSymbol) { stack.Push(new StackItem(Current.nonterminalGotos[pushedSymbol.GotoIndex], value)); Accept(next); }
public Parser(INonterminalSymbol <Result> grammar, ParserGenerator algorithm, params Terminal[] whitespace) { strategy = algorithm switch { ParserGenerator.LR0 => new LR0ParserGenerator(), ParserGenerator.SLR => new SLRParserGenerator(), ParserGenerator.CLR => new CLRParserGenerator(), ParserGenerator.LALR => new LALRParserGenerator(), _ => throw new ArgumentException(nameof(algorithm)) }; visitedStates = new HashSet <State>(strategy); eof = Terminal.Eof; // Set up symbol metadata startSymbol = new Symbol <Result, Context>("start"); startSymbol.Match(grammar, eof, (x, y) => x); symbols = startSymbol.ReachableSymbols.ToList(); terminals = grammar.ReachableTerminals.ToList(); nonterminals = symbols.OfType <INonterminalSymbol>().ToList(); tokenizer = grammar.MakeTokenizer(whitespace); terminals.Add(eof); // Ensure it's at the end // Set up terminals epsilon = Terminal.Empty; // !! Dont think this is needed ?? // Mark potentially empty symbols MarkCanBeEmpty(); ComputeFirstSets(); // Index all the rules int index = 0; rules = new List <ProductionRule>(); rules.AddRange(nonterminals.SelectMany(s => s.Rules)); foreach (var r in rules) { r.Index = index++; } index = 0; foreach (var t in terminals) { t.TerminalIndex = index++; } index = 0; foreach (var t in nonterminals) { t.GotoIndex = index++; } // Compute the state tables // The initial state. initialState = strategy.CreateInitialState(startSymbol); strategy.ExpandClosure(initialState); visitedStates.Add(initialState); // Compute transitions for the state ComputeGotos(initialState); // ComputeActions(initialState); // Compute actions for all states. foreach (var state in visitedStates) { ComputeActions(state); } } HashSet <State> visitedStates;