public virtual SyntaxNode Visit(AbstractVisitor visitor) { return(visitor.Visit(this)); }
public SyntaxNode Parse(Queue <LexicalElement> input, HashSet <Item> startPoint, Type acceptNode, List <ParserConfiguration> history = null, List <SyntaxException> exceptions = null, AbstractVisitor visitor = null) { Stack <SyntaxNode> nodeStack = new Stack <SyntaxNode>(); Stack <AnalyzerState> stateStack = new Stack <AnalyzerState>(); stateStack.Push(Slr1Table.States[startPoint]); if (visitor == null) { visitor = PassthroughVisitor.Instance; } while (true) { try { if (input.Count == 0) { if (nodeStack.Count > 0 && nodeStack.Peek().GetType() == acceptNode) { history?.Add(new ParserConfiguration(nodeStack, stateStack, input, null)); break; } var reducibleRules = new List <ProductionRule>(from item in stateStack.Peek().ItemSet where item.Cursor == item.ProductionRule.Length select item.ProductionRule); if (reducibleRules.Count != 1) { var l = FindRightMostTerminal(nodeStack.Peek()); throw new SyntaxException($"Multiple or No Reducible Rule, last token \"{l.StringValue}\" at {l.LineNumber}:[{l.StartIndex}, {l.EndIndex}). Expected {String.Join(", ", from pred in stateStack.Peek().Action.Keys select pred.Name)}"); } var reducibleRule = reducibleRules[0]; history?.Add(new ParserConfiguration(nodeStack, stateStack, input, new ReduceOperation() { ReduceBy = reducibleRule })); var argNodes = new SyntaxNode[reducibleRule.Length]; for (int i = argNodes.Length - 1; i >= 0; --i) { stateStack.Pop(); argNodes[i] = nodeStack.Pop(); } nodeStack.Push(visitor.Visit(reducibleRule.Produce(argNodes))); stateStack.Push(stateStack.Peek().GotoTable[reducibleRule.Key]); } else { var cur = input.Peek(); bool matched = false; foreach (var action in stateStack.Peek().Action) { if (action.Key.Predicate(cur)) { matched = true; var operation = action.Value; switch (operation) { case ShiftOperation so: history?.Add(new ParserConfiguration(nodeStack, stateStack, input, so)); input.Dequeue(); nodeStack.Push(new TerminalNode(cur)); stateStack.Push(so.NextState); break; case ReduceOperation ro: var reducibleRule = ro.ReduceBy; history?.Add(new ParserConfiguration(nodeStack, stateStack, input, ro)); var argNodes = new SyntaxNode[reducibleRule.Length]; for (int i = argNodes.Length - 1; i >= 0; --i) { stateStack.Pop(); argNodes[i] = nodeStack.Pop(); } nodeStack.Push(visitor.Visit(reducibleRule.Produce(argNodes))); stateStack.Push(stateStack.Peek().GotoTable[reducibleRule.Key]); break; default: throw new SyntaxException("Internal Error: Unknown Operation"); } } } if (!matched) { throw new SyntaxException($"Unknown Token \"{cur.StringValue}\" at {cur.LineNumber}:[{cur.StartIndex}, {cur.EndIndex}), no matching operation. Expected {String.Join(", ", from pred in stateStack.Peek().Action.Keys select pred.Name)}"); } } } catch (SyntaxException e) { exceptions?.Add(e); var ero = new ErrorRecoveryOperation(); history?.Add(new ParserConfiguration(nodeStack, stateStack, input, ero)); if (input.Count == 0) { var ex = new SyntaxException("Error Recovery Failed: Unable to Reduce"); ero.Success = false; exceptions.Add(ex); throw ex; } List <object> intersection = new List <object>(); intersection.AddRange(Slr1Table.AllowedErrorRecoveryKey.Keys.Intersect(stateStack.Peek().GotoTable.Keys)); while (intersection.Count == 0 && stateStack.Count > 0) { stateStack.Pop(); nodeStack.Pop(); intersection.AddRange(Slr1Table.AllowedErrorRecoveryKey.Keys.Intersect(stateStack.Peek().GotoTable.Keys)); } if (intersection.Count == 0) { var ex = new SyntaxException("Error Recovery Failed: No Recoverable State"); ero.Success = false; exceptions.Add(ex); throw ex; } var nextKey = intersection.First(); bool matched = false; while (!matched && input.Count > 0) { foreach (var follow in Slr1Table.FollowSets[nextKey]) { if (follow is TerminalPredicate tp && tp.Predicate(input.Peek())) { matched = true; break; } input.Dequeue(); } } if (!matched) { var ex = new SyntaxException("Error Recovery Failed: No Followable Input"); ero.Success = false; exceptions.Add(ex); throw ex; } var nextState = stateStack.Peek().GotoTable[nextKey]; var nextNode = Slr1Table.AllowedErrorRecoveryKey[nextKey](); stateStack.Push(nextState); nodeStack.Push(visitor.Visit(nextNode)); ero.Success = true; } } return(nodeStack.Pop()); }