/// <summary>Legal as long as there are at least two items on the state's stack.</summary> public virtual bool IsLegal(State state, IList <ParserConstraint> constraints) { // some of these quotes come directly from Zhang Clark 09 if (state.finished) { return(false); } if (state.stack.Size() <= 1) { return(false); } // at least one of the two nodes on top of stack must be non-temporary if (ShiftReduceUtils.IsTemporary(state.stack.Peek()) && ShiftReduceUtils.IsTemporary(state.stack.Pop().Peek())) { return(false); } if (ShiftReduceUtils.IsTemporary(state.stack.Peek())) { if (side == BinaryTransition.Side.Left) { return(false); } if (!ShiftReduceUtils.IsEquivalentCategory(label, state.stack.Peek().Value())) { return(false); } } if (ShiftReduceUtils.IsTemporary(state.stack.Pop().Peek())) { if (side == BinaryTransition.Side.Right) { return(false); } if (!ShiftReduceUtils.IsEquivalentCategory(label, state.stack.Pop().Peek().Value())) { return(false); } } // don't allow binarized labels if it makes the state have a stack // of size 1 and a queue of size 0 if (state.stack.Size() == 2 && IsBinarized() && state.EndOfQueue()) { return(false); } // when the stack contains only two nodes, temporary resulting // nodes from binary reduce must be left-headed if (state.stack.Size() == 2 && IsBinarized() && side == BinaryTransition.Side.Right) { return(false); } // when the queue is empty and the stack contains more than two // nodes, with the third node from the top being temporary, binary // reduce can be applied only if the resulting node is non-temporary if (state.EndOfQueue() && state.stack.Size() > 2 && ShiftReduceUtils.IsTemporary(state.stack.Pop().Pop().Peek()) && IsBinarized()) { return(false); } // when the stack contains more than two nodes, with the third // node from the top being temporary, temporary resulting nodes // from binary reduce must be left-headed if (state.stack.Size() > 2 && ShiftReduceUtils.IsTemporary(state.stack.Pop().Pop().Peek()) && IsBinarized() && side == BinaryTransition.Side.Right) { return(false); } if (constraints == null) { return(true); } Tree top = state.stack.Peek(); int leftTop = ShiftReduceUtils.LeftIndex(top); int rightTop = ShiftReduceUtils.RightIndex(top); Tree next = state.stack.Pop().Peek(); int leftNext = ShiftReduceUtils.LeftIndex(next); // The binary transitions are affected by constraints in the // following two circumstances. If a transition would cross the // left boundary of a constraint, that is illegal. If the // transition is exactly the right size for the constraint and // would make a temporary node, that is also illegal. foreach (ParserConstraint constraint in constraints) { if (leftTop == constraint.start) { // can't binary reduce away from a tree which doesn't match a constraint if (rightTop == constraint.end - 1) { if (!ShiftReduceUtils.ConstraintMatchesTreeTop(top, constraint)) { return(false); } else { continue; } } else { if (rightTop >= constraint.end) { continue; } else { // can't binary reduce if it would make the tree cross the left boundary return(false); } } } // top element is further left than the constraint, so // there's no harm to be done by binary reduce if (leftTop < constraint.start) { continue; } // top element is past the end of the constraint, so it must already be satisfied if (leftTop >= constraint.end) { continue; } // now leftTop > constraint.start and < constraint.end, eg inside the constraint // the next case is no good because it crosses the boundary if (leftNext < constraint.start) { return(false); } if (leftNext > constraint.start) { continue; } // can't transition to a binarized node when there's a constraint that matches. if (rightTop == constraint.end - 1 && IsBinarized()) { return(false); } } return(true); }