import Jakarta.util.*; import java.io.ByteArrayOutputStream; import java.io.File; import java.io.FileInputStream; import java.io.FileNotFoundException; import java.io.FileOutputStream; import java.io.InputStream; import java.io.InputStreamReader; import java.io.IOException; import java.io.ObjectOutputStream; import java.io.PrintWriter; import java.io.Reader; import java.io.Serializable; import java.io.UnsupportedEncodingException; import java.io.Writer; import java.net.URI; import java.util.Hashtable; import java.util.List; import java.util.Stack; import java.util.EmptyStackException; import java.util.Vector; //************************************************** // Class AstCursor //************************************************** public class AstCursor { // node references the current node of the cursor // in the case of node deletions and replacements, // NextIsSet to true, and next is set to the next node // to search. root is the root of the AST to search public AstNode node; // cursor references this node boolean NextIsSet; // set true by Sibling, Delete, Replace public AstNode next; // set by Sibling, Delete, Replace AstNode root; // root of the search tree AstNode CurrElem; // next element in list (used for // searching lists only! AstNode NextElem; // for list-searching only! // AstCursor constructor just nullifies all of its data members public AstCursor() { node = null; NextIsSet = false; next = null; root = null; } // note: to scan an AST rooted at t, use the following // AstCursor c; // for (c.First(t); c.More(); c.PlusPlus()) { ... } public AstNode Root() { return root; } public void First() { First( root ); } // First(r) finds first nonstructural node (i.e., the first // node that isn't an AstListNode or an AstOptNode) in the // tree rooted by r. First also remembers the root of the // tree. If no such node can be found, data member node == null. public void First( AstNode r ) { root = r; node = r; NextIsSet = false; next = null; while ( node != null && ( node instanceof AstListNode || node instanceof AstOptNode ) ) { GetNext(); } } // More() returns true if there are additional nodes to // examine in the AST rooted at root. public boolean More() { return node != null; } // PlusPlus() repositions the cursor on the next nonstructural // node of the AST. If there is no such node, data member node // is set to null. public void PlusPlus() { // got next printable node GetNext(); while ( node != null && ( node instanceof AstListNode || node instanceof AstOptNode ) ) { GetNext(); } } // GetNext() is a method that is internal to the AstCursor class, // and should not be exported. It does the primitive work of // advancing a cursor to the next structural or nonstructural // node of a tree. It is an internal method (i.e., one that isn't // exported) as it is shared by several exported methods of // AstCursor class. void GetNext() { // Step 1: check if the next pointer has already been determined // by the Replace() or Delete() methods. if so, use it // and exit if ( NextIsSet ) { NextIsSet = false; node = next; next = null; return; } if ( node == null ) return; // Step 2: else, if there is a child, return it if ( node.arg[0] != null ) { node = node.arg[0]; return; } // Step 3: else, skip to next sibling skip(); } // skip() is an internal method (i.e., one that is not exported) by AstClass. // it does the work of advancing a cursor to its immediate sibling or relative // (but not child). It is internal to AstClass as it is shared by several // exported methods. void skip() { // Step 1: if we're already positioned on the next node (virtually) // then actually position the cursor before performing a skip if ( NextIsSet ) { NextIsSet = false; node = next; next = null; } if ( node == root ) { node = null; return; } // Step 1: if there is a right sibling, return it if ( node.right != null ) { node = node.right; return; } // Step 2: otherwise, begin examining ancestors // if the ancestor is a root (the starting node of // the search) or the ancestor is null, terminate // the search. Otherwise, continue to search for // an ancestor with a nonnull right pointer. while ( true ) { node = node.up; // Step 2a: stop if we're at the top of the AST or we're at // the root. if ( node == null || node == root ) { node = null; return; } // Step 2b: otherwise, proceed to right sibling if ( node.right != null ) { node = node.right; return; } // Step 2c: else, go up. } } // ContinueFrom(k) is an internal method to AstCursor. It tells the cursor // advancement methods that the next node to examine in the tree is node k. // ContinueFrom(k) is called by Sibling(), Replace(), and Delete(); void ContinueFrom( AstNode k ) { NextIsSet = true; next = k; node = null; } public void Position( AstNode x ) { AstNode parentNode; if ( x != null ) { // validate x as a child of r parentNode = x; while ( parentNode != null ) { if ( parentNode == root ) break; parentNode = parentNode.up; } if ( parentNode == null ) { // x is not a child of root node = null; return; } } node = x; NextIsSet = false; } public void Position( AstNode r, AstNode x ) { root = r; Position( x ); } // Sibling() allows one to skip the searching of the current node's children // and to proceed directly to searching the current node's sibling (or next // relative. A typical use for this would be (a) locate a particular node // in an AST, and (knowing that a recurrence of that node will never happen // in its children) to continue searching from the node's sibling: // // example: // AstCursor c = new AstCursor(); // // for (c.First(t); c.More(); c.PlusPlus()) { // if (c instanceof $TEqn.AstClass) { // ... found an instance of the Class construct // c.Sibling(); // won't find another instance of Class construct // // as classes aren't nested in Java/Jakarta // } // } public void Sibling() { // Step 1: skip to sibling skip(); // Step 2: after a skip, we need to remember where to continue // after the next advancement ContinueFrom( node ); } // Replace(k) swaps the AST rooted at the current node with the tree // rooted at k. An AST search continues from node k. // Note: special case if k == root; root is updated. public void Replace( AstNode withnode ) { // Step 1: if we are replacing the root node of the // search, then update the root variable if ( this.node == root ) root = withnode; // Step 2: now replace this with withnode, and continue // from withnode ContinueFrom( node.Replace( withnode ) ); } // Delete() the current node. Accomplished by repositioning the cursor on its // Sibling (as this is where the search will continue), followed by a deletion // of the original node. public void Delete() { // delete node AstNode todelete = node; NextElem = CurrElem.right; // Step 1: position cursor after this node Sibling(); // Step 2: now delete the node itself todelete.Delete(); } public void AddAfter( AstList y ) { node.AddAfter( y ); } public void AddBefore( AstList y ) { node.AddBefore( y ); } // print() unparses the AST rooted at the current node // reduce2java() reduces the Jakarta AST to Java code // reduce2ast() reduces the Jakarta AST constructors in Java public void print() { node.print(); } public void reduce2java( AstProperties props ) { node.reduce2java( props ); } public AstNode find( String node_type ) { Class query_class; try { query_class = Class.forName( node_type ); } catch ( Exception e ) { return ( null ); } return ( find( query_class ) ); } public AstNode find( Class query_class ) { Class anc_class; while ( node != null ) { anc_class = node.getClass(); while ( anc_class != null ) { if ( anc_class == query_class ) return ( node ); anc_class = anc_class.getSuperclass(); } PlusPlus(); } return ( null ); } //************************************************** // Unlike the above versions of find, this method takes a String // naming an unqualified base type. It scans and gets the class name // for each node, converts it to a base type and compares to the // type desired. //************************************************** public AstNode findBaseType( String baseType ) { String csr_base_type; while ( node != null ) { csr_base_type = Util.baseType( node ); if ( baseType.compareTo( csr_base_type ) == 0 ) return ( node ); PlusPlus(); } return ( null ); } //*************************************************** // The following methods were added to make list traversals // with cursors easier //*************************************************** public void FirstElement( AstNode e ) { if ( ! ( e instanceof AstList ) ) if ( e == null ) e.fatalError( "FirstElement called with null pointer" ); else e.fatalError( "Non-list node of type " + e.getClass().getName() + " called with FirstElement()" ); if ( e.arg[0]==null ) { node = null; return; } CurrElem = e.arg[0]; node = CurrElem.arg[0]; NextElem = null; return; } public boolean MoreElement() { return CurrElem != null; } public void NextElement() { // position on correct next element if ( NextElem != null ) { CurrElem = NextElem; NextElem = null; } else CurrElem = CurrElem.right; if ( CurrElem == null ) node = null; else node = CurrElem.arg[0]; } }