/// <summary> /// Performs the given action on the given stack, branches, and current index based on the current item. /// Returns whether the action was to accept. /// </summary> /// <param name="syntax"></param> /// <param name="stateStack"></param> /// <param name="currentBranches"></param> /// <param name="action"></param> /// <param name="currentIndex"></param> /// <returns></returns> protected bool PerformAction(bool syntax, Terminal <T> currentItem, Stack <KeyValuePair <int, GrammarElement <T> > > stateStack, List <SyntaxNode <T> > currentBranches, ParserAction <T> action, ref int currentIndex) { if (action is ShiftAction <T> ) { Shift(stateStack, currentItem, action); currentIndex++; } else if (action is ReduceAction <T> ) { Reduce(syntax, stateStack, currentBranches, action, ref currentIndex); currentIndex++; } else if (action is AcceptAction <T> ) { return(true); } return(false); }
/// <summary> /// Reduces the given action, reflecting the changes on the given stack, branches, and index. /// </summary> /// <param name="syntax"></param> /// <param name="stateStack"></param> /// <param name="currentBranches"></param> /// <param name="action"></param> protected void Reduce(bool syntax, Stack <KeyValuePair <int, GrammarElement <T> > > stateStack, List <SyntaxNode <T> > currentBranches, ParserAction <T> action, ref int currentIndex) { if (action is ReduceAction <T> ) { var r = (ReduceAction <T>)action; var e = new List <GrammarElement <T> >(); //pop the number of elements in the RHS of the item for (var c = 0; c < r.ReduceItem.ProductionElements.Length; c++) { e.Add(stateStack.Pop().Value); } e.Reverse(); //create a new branch with the value as the LHS of the reduction item. var newBranch = new SyntaxNode <T>(r.ReduceItem.LeftHandSide); //Determine whether to add each element to the new branch based on whether it should be kept. foreach (GrammarElement <T> element in e) { if (element is NonTerminal <T> ) { if (element.Keep || syntax) { //find the first branch that matches the reduce element SyntaxNode <T> b = currentBranches.Last(a => a.Value.Equals(element)); newBranch.AddChild(b); currentBranches.Remove(b); } else { //find the first branch that matches the reduce element SyntaxNode <T> b = currentBranches.Last(a => a.Value.Equals(element)); //get the children of the branch since we don't want the current value IEnumerable <SyntaxNode <T> > branches = b.GetChildren(); //add the children newBranch.AddChildren(branches); currentBranches.Remove(b); } } else { //if we should keep the terminal object, then add it to the new branch if (element == null || element.Keep || syntax) { newBranch.AddChild(new SyntaxNode <T>(element)); } } } currentBranches.Add(newBranch); //push the LHS non-terminal and the next state stateStack.Push(new KeyValuePair <int, GrammarElement <T> >(ParseTable.GotoTable[stateStack.Peek().Key, r.ReduceItem.LeftHandSide].Value, r.ReduceItem.LeftHandSide)); currentIndex--; } }
/// <summary> /// Shifts the given action based on the given item, reflecting the given changes on the given stack. /// </summary> /// <param name="stateStack"></param> /// <param name="item"></param> /// <param name="action"></param> protected static void Shift(Stack <KeyValuePair <int, GrammarElement <T> > > stateStack, Terminal <T> item, ParserAction <T> action) { //push the state and item stateStack.Push(new KeyValuePair <int, GrammarElement <T> >(((ShiftAction <T>)action).NextState, item)); }