public Grammar(TSymbol start, IDictionary <TSymbol, IProduction <TSymbol>[]> productions) { Start = start; Productions = productions; WhichProduction = new Dictionary <uint, IProduction <TSymbol> >(); Automatons = new Dictionary <TSymbol, Dfa <TSymbol> >(); // Here we prepare automatons for each symbol. uint productionMarker = 1; foreach (var symbolProductions in Productions) { var automatons = new List <Lexer.DfaUtils.MinimizedDfa <TSymbol> >(); foreach (var production in symbolProductions.Value) { automatons.Add(Dfa <TSymbol> .RegexDfa(production.Rhs, productionMarker)); WhichProduction[productionMarker] = production; productionMarker++; } Automatons[symbolProductions.Key] = Dfa <TSymbol> .ProductDfa(automatons.ToArray()); } Nullable = GrammarUtils <TSymbol> .ComputeNullable(Automatons); First = GrammarUtils <TSymbol> .ComputeFirst(Automatons, Nullable); Follow = GrammarUtils <TSymbol> .ComputeFollow(Automatons, Nullable, First); SymbolListLeftRecursion = GrammarUtils <TSymbol> .HasLeftRecursion(Automatons, Nullable); TargetStatesDictionary = GrammarUtils <TSymbol> .computeTargetStatesDictionary(Automatons); AccStateOwnerDictionary = GrammarUtils <TSymbol> .computeAccStateOwnerDictionary(Automatons); }
// For testing purposes only! public void InjectAutomatons(Dictionary <TSymbol, Dfa <TSymbol> > automatons) { this.Automatons = automatons; TargetStatesDictionary = GrammarUtils <TSymbol> .computeTargetStatesDictionary(Automatons); AccStateOwnerDictionary = GrammarUtils <TSymbol> .computeAccStateOwnerDictionary(Automatons); }
// returns either a list of successfull parsed results or a singleton list with failure private IEnumerable <ItParseResult <TSymbol> > ParseTerm(TSymbol term, MemoizedInput <ParseLeaf <TSymbol> > word, MemoizedInput <ParseLeaf <TSymbol> > .Iterator iterator) { var dfa = _grammar.Automatons[term]; // stack for backtracking - <position in word, current state of appropriate DFA> var st = new Stack <ParseState>(); var children = new Stack <IParseTree <TSymbol> >(); bool accepted = false; var eof = ParserUtils <TSymbol> .GetEOF(); ItError <TSymbol> furthest = null; st.Push(new ParseState(dfa.Start, 0, iterator)); while (st.Any()) { var parseState = st.Peek(); var node = parseState.State; var it = parseState.Iterator; TSymbol currentSymbol = (it != word.End) ? it.Current.Symbol : eof; if (node.Accepting > 0 && (currentSymbol.Equals(eof) || _grammar.Follow[term].Contains(currentSymbol))) { accepted = true; var parsedChildren = children.ToList(); parsedChildren.Reverse(); var parsedTree = new ParseBranch <TSymbol>( iterator != word.End ? GetFragmentRange( iterator.Current.Fragment, (children.Any() ? children.Peek().Fragment : iterator.Current.Fragment)) : null, term, _grammar.WhichProduction[node.Accepting], parsedChildren); yield return(new ItOK <TSymbol>(parsedTree, it)); } var trans = node.Transitions; var ind = parseState.TransitionIndex; for (; ind < trans.Count; ind++) { if (GrammarUtils <TSymbol> .IsDead(trans[ind].Value)) { continue; } if (_grammar.InFirstPlus(trans[ind].Key, currentSymbol)) { if (trans[ind].Key.IsTerminal) { children.Push(new ParseLeaf <TSymbol>(it != word.End ? it.Current.Fragment : null, currentSymbol)); // TODO It would be better to have special END fragment st.Push(new ParseState(trans[ind].Value, 0, it != word.End ? it.Next() : word.End)); break; } else { IEnumerator <ItParseResult <TSymbol> > resultIt = ParseTerm(trans[ind].Key, word, it).GetEnumerator(); resultIt.MoveNext(); if (resultIt.Current) { var res = resultIt.Current as ItOK <TSymbol>; children.Push(res.Tree); st.Push(new ParseState(trans[ind].Value, 0, res.Iterator, resultIt)); break; } else { var res = resultIt.Current as ItError <TSymbol>; if (furthest == null || res.Iterator > furthest.Iterator) { furthest = res; } } } } } parseState.TransitionIndex = ind; // could not find next parsing transition if (ind >= trans.Count) { if (furthest == null || it > furthest.Iterator) { furthest = new ItError <TSymbol>(it, term); } Backtrack(st, children); } } if (accepted) { yield break; } else { yield return(furthest ?? new ItError <TSymbol>(iterator, term)); } }