private void Reducer(int lookahead = -1) { while (!R.IsEmpty) { GssReducePath <T> path = R.Dequeue(); int X = path.Rule.OutcomeToken; int m = path.Size; GssNode <T> u = path.LeftNode; State k = u.State; T z; if (m == 0) { z = producer.GetDefault(X, (IStackLookback <T>)u); } else { path.CopyDataTo(nodeBuffer); T Λ = producer.CreateBranch( path.Rule, new ArraySlice <T>(nodeBuffer, 0, path.Size), lookback: path.LeftNode); int c = u.Layer; T currentValue; var Nkey = GetNKey(X, c); if (N.TryGetValue(Nkey, out currentValue)) { z = producer.Merge(currentValue, Λ, (IStackLookback <T>)u); } else { z = Λ; } N[Nkey] = z; } State l; var action = ParserAction.Decode(transition(k, X)); switch (action.Kind) { case ParserActionKind.Shift: l = action.State; break; case ParserActionKind.ShiftReduce: // Goto-Reduce action PlanShiftReduce( u, X, z, action.ProductionId, action.Size); continue; default: throw new InvalidOperationException( "Internal error: Non-term action should be shift or shift-reduce, but got " + Enum.GetName(typeof(ParserActionKind), action.Kind)); } bool stateAlreadyExists = gss.GetFrontNode(l, lookahead) != null; // Goto on non-term produced by rule. var newLink = gss.Push(u, l, z, lookahead); if (lookahead < 0) { continue; } if (stateAlreadyExists) { if (newLink != null && m != 0) { GetReductions(l, lookahead); for (int i = 0; i != pendingReductionsCount; ++i) { var red = pendingReductions[i]; if (red.Size != 0) { R.Enqueue(newLink, red.Rule, red.Size); } } } } else { var w = gss.GetFrontNode(l, lookahead); GetReductions(l, lookahead); //foreach (var red in reductions) for (int i = 0; i != pendingReductionsCount; ++i) { var red = pendingReductions[i]; if (red.Size == 0) { R.Enqueue(w, red.Rule, 0); } } if (m != 0) { for (int i = 0; i != pendingReductionsCount; ++i) { var red = pendingReductions[i]; if (red.Size != 0) { R.Enqueue(newLink, red.Rule, red.Size); } } } } } }