//****************************************************************** #region [ReplaceCurrentMatchingBranch() Method] //****************************************************************** /// <summary> /// Replaces the sub-tree dominated by the CurrentParseTreeNode, /// using the tree dominated by the ReplacePatternRoot as a pattern. /// Corresponding nodes (matched by a find-pattern node with the /// same label as the replace-pattern node) are copied from the /// MatchingNodes stack and their features are merged with features /// from the replace pattern. The replaced nodes in the new sub-tree /// are also stored in the ReplacedNodes stack. /// </summary> public void ReplaceCurrentMatchingBranch() { Debug.WriteLineIf(VerboseDebugging, "ReplaceAlgorithm.ReplaceCurrentMatchingBranch() called."); //************************************************************** // Validate the current state. if (ParseTreeRoot == null) { string sMessage = "ReplaceCurrentMatchingBranch() " + "called with an invalid state: " + "ParseTreeRoot is null."; throw new Exception(sMessage); } if (MatchingNodes.Count < 1) { string sMessage = "ReplaceCurrentMatchingBranch() " + "called with an invalid state: " + "MatchingNodes is empty."; throw new Exception(sMessage); } foreach (SyntaxNodePair oNodePair in MatchingNodes) { if (oNodePair.ParseTreeNode == null) { string sMessage = "ReplaceCurrentMatchingBranch() " + "called with an invalid state: " + "MatchingNodes contains an item where " + ".ParseTreeNode is null."; throw new Exception(sMessage); } if (oNodePair.FindPatternNode == null) { string sMessage = "ReplaceCurrentMatchingBranch() " + "called with an invalid state: " + "MatchingNodes contains an item where " + ".FindPatternNode is null."; throw new Exception(sMessage); } } if (ReplacedNodes.Count > 0) { string sMessage = "ReplaceCurrentMatchingBranch() " + "called with an invalid state: " + "ReplacedNodes is not empty."; throw new Exception(sMessage); } if (CurrentParseTreeNode == null) { string sMessage = "ReplaceCurrentMatchingBranch() " + "called with an invalid state: " + "CurrentParseTreeNode is null."; throw new Exception(sMessage); } //************************************************************** // Clear the ReplacedNodes list. ReplacedNodes.Clear(); //************************************************************** // If ReplacePatternRoot is null, use an empty SyntaxNode (one // with no features and no children) instead. SyntaxNode oReplacePatternRoot = ReplacePatternRoot; if (oReplacePatternRoot == null) { oReplacePatternRoot = new SyntaxNode(); } //************************************************************** // Use the oReplacePatternRoot and the MatchingNodes list to // create a new branch to replace the CurrentParseTreeNode. SyntaxNode oNewBranch = CopyNodeAndChildren(oReplacePatternRoot); //************************************************************** // BUGBUG: We may need to make another pass through the new // branch to: // // (1) copy features (or substrings) from another node using a // path <../DP/NP/featurename>. // // (2) recompute any feature values after other features have // changed (like changes to the word string because // morphology strings have changed). //************************************************************** // If the new branch is null, use an empty SyntaxNode (one with // no features and no children) instead, and add this to the // ReplacedNodes list. if (oNewBranch == null) { oNewBranch = new SyntaxNode(); SyntaxNodeTriple oNodeTriple = new SyntaxNodeTriple(); oNodeTriple.ParseTreeNode = oNewBranch; oNodeTriple.FindPatternNode = null; oNodeTriple.ReplacePatternNode = new SyntaxNode(); ReplacedNodes.Push(oNodeTriple); } Debug.Assert(ReplacedNodes.Count > 0); //************************************************************** // If the CurrentParseTreeNode has a parent node, find its // index in the parent's ChildNodes collection, and replace the // child at that index with the new branch. SyntaxNode oParent = CurrentParseTreeNode.ParentNode; if (oParent != null) { int iIndex = oParent.ChildNodes.IndexOf(CurrentParseTreeNode); oParent.ChildNodes.Insert(iIndex, oNewBranch); oParent.ChildNodes.Remove(CurrentParseTreeNode); } //************************************************************** // If the CurrentParseTreeNode is the same as the ParseTreeRoot, // replace the ParseTreeRoot with the new branch. if (CurrentParseTreeNode == ParseTreeRoot) { ParseTreeRoot = oNewBranch; } //************************************************************** // Set CurrentParseTreeNode to the new branch. CurrentParseTreeNode = oNewBranch; //************************************************************** // Dump the ReplacedNodes list for verbose debugging. if (VerboseDebugging) { foreach (SyntaxNodeTriple oNodeTriple in ReplacedNodes) { Debug.Assert(oNodeTriple.ParseTreeNode != null); Debug.Assert(oNodeTriple.ReplacePatternNode != null); } Debug.WriteLine("ReplacedNodes: " + ReplacedNodes.ToString() + "."); } Debug.WriteLineIf(VerboseDebugging, "ReplaceAlgorithm.ReplaceCurrentMatchingBranch() returns."); }
//****************************************************************** #region [FindNextMatchingBranch() Method] //****************************************************************** /// <summary> /// Moves the CurrentParseTreeNode forward in the parse tree, until /// the sub-tree dominated by this node matches the pattern /// dominated by FindPatternRoot. If CurrentParseTreeNode is null /// when this method is called, the search starts with the first /// node in the parse tree. Otherwise, the search continues with the /// next node in the tree. If a matching sub-tree is found, true is /// returned and the MatchingNodes stack contains the list of /// matching node pairs. If no match is found, CurrentParseTreeNode /// is set to null and false is returned. /// </summary> public bool FindNextMatchingBranch() { Debug.WriteLineIf(VerboseDebugging, "FindAlgorithm.FindNextMatchingBranch() called."); //************************************************************** // Validate the current state. if (CurrentParseTreeNode != null) { SyntaxNode oNode = CurrentParseTreeNode; while (oNode != ParseTreeRoot) { if (oNode.ParentNode == null) { string sMessage = "FindNextMatchingBranch() " + "called with an invalid state: " + "the ParseTreeRoot tree does not contain " + "the CurrentParseTreeNode."; throw new Exception(sMessage); } oNode = oNode.ParentNode; } } //************************************************************** // Clear the lists of MatchingNodes and ReplacedNodes. MatchingNodes.Clear(); ReplacedNodes.Clear(); //************************************************************** // Save the previous value of the CurrentParseTreeNode. SyntaxNode oPreviousParseTreeNode = CurrentParseTreeNode; //************************************************************** // Move the CurrentParseTreeNode to the next branch to compare: // // If CurrentParseTreeNode is null, start with the first // parse-tree node in post order. // // Otherwise, move to the next node in post order. // // Note: The parse tree is traversed in post-order (parent after // its children) to prevent infinite recursion that could occur // if an XP node was replaced by a node with XP children, and // then the rule was applied recursively to these children. if (CurrentParseTreeNode == null) { CurrentParseTreeNode = GetFirstNodeInPostOrder(ParseTreeRoot); } else { CurrentParseTreeNode = GetNextNodeInPostOrder(CurrentParseTreeNode); } //************************************************************** // Check if the previous branch should be deleted. // // When the ReplaceCurrentMatchingBranch() method needs to // delete the current parse-tree node, it sets it to an empty // node (one with no features and no children) instead. This is // so we can use the current parse-tree node to determine where // to find the next node to compare. // // If the previous branch is an empty node (with no features and // no children), delete it. if (oPreviousParseTreeNode != null) { if ((oPreviousParseTreeNode.Features.Count == 0) && (oPreviousParseTreeNode.ChildNodes.Count == 0)) { //****************************************************** // Remove the empty node from its parent's ChildNodes // collection. If the empty node is the same as the // ParseTreeRoot, set the ParseTreeRoot to null. SyntaxNode oParent = oPreviousParseTreeNode.ParentNode; if (oParent != null) { oParent.ChildNodes.Remove(oPreviousParseTreeNode); } if (oPreviousParseTreeNode == ParseTreeRoot) { ParseTreeRoot = null; } } } //************************************************************** // If FindPatternRoot is null, nothing can match this pattern. // In this case, set CurrentParseTreeNode to null so there will // be no comparisons and false will be returned. if (FindPatternRoot == null) { CurrentParseTreeNode = null; } //************************************************************** // Traverse the parse tree (in post order), looking for a match, // until there are no more nodes to traverse. Return true if a // match is found. while (CurrentParseTreeNode != null) { //********************************************************** // Return true if the current branch matches the pattern. if (CurrentBranchMatchesPattern()) { Debug.Assert(MatchingNodes.Count > 0); Debug.Assert(ReplacedNodes.Count == 0); Debug.Assert(CurrentParseTreeNode != null); Debug.WriteLineIf(VerboseDebugging, "FindAlgorithm.FindNextMatchingBranch() returns " + "true."); return(true); } //********************************************************** // Move to the next node in post order. CurrentParseTreeNode = GetNextNodeInPostOrder(CurrentParseTreeNode); } //************************************************************** // A matching branch was not found, so return false. Debug.Assert(MatchingNodes.Count == 0); Debug.Assert(ReplacedNodes.Count == 0); Debug.Assert(CurrentParseTreeNode == null); Debug.WriteLineIf(VerboseDebugging, "FindAlgorithm.FindNextMatchingBranch() returns false."); return(false); }