V10/cmd/twig/path.c

#include <stdio.h>
#include "common.h"
#include "code.h"
#include "sym.h"
#include "machine.h"

/*
 * Routines to enumerate paths of a tree.  Firt call path_setup to
 * initialize the internal data structure.  Each component of the
 * path may be consecutively retrieved by calling path_getsym.
 */

/*
 * For trees, a path is defined to be the sequence of nodes and edges
 * from the root to a leaf.  A path is represented here as a list of
 * path components.  Each component is represented by the following
 * strucutre and may either be a pointer to a node or an integer.
 * If the integer is i then the next component is the ith child of the
 * previous component in the list.  For example, "a 3 b 1 c" is a path
 * for the tree "a(x,y,b(c,k))".  The tag field indicates whether the
 * component is a node or a branch.
 *	When the component represents a node then the node field points
 * the corresponding Node structure.  When the component is a branch then
 * branch is the index of the current branch followed (1 is leftmost...)
 * and node is a list of all unexamined children.
 */
struct path {
	int tag;
#define		P_NODE	0
#define		P_BRANCH	1
	int branch;
	Node *node;
};

/*
 * The path component list is stored in the path array.  Path_length
 * is the length of the path.  Path_ptr points to the first unread
 * component of the path component list. (see path_getsym
 * and path_build for details)
 */
struct path path[2*MAXPATH];
static int path_length;
static struct path *path_ptr = NULL;

/*
 * Given a tree, path_setup updates the path array with the leftmost
 * of a subtree starting at root.  The leftmost path is produced by
 * following the leftmost branch of every encountered interior node 
 * starting at the root.  Note that this routine can be used to layout
 * the leftmost branch of a subtree into part of the path array and for
 * initializing the path array with the leftmost path of the whole tree.
 */
void
path_setup(root)
	Node *root;
{
	for(;;) {
		register struct path *pp = &path[path_length++];
		Node *ep;
		assert (root!=NULL);

		/* Place node in the component list */
		pp->tag = P_NODE;
		pp->node = root;

		/* If leaf encountered exit */
		if ((ep=root->children)==NULL)
			break;

		/*
		 * Mark that the left branch (i.e. 1st in our numbering
		 * scheme) was followed.
		 */
		pp = &path[path_length++];
		pp->tag = P_BRANCH;
		pp->branch = 1;
		pp->node = ep->siblings;
		root = ep;
	}
	path_ptr = path;
}

/*
 * Path_build generates the next path of the tree and returns 0 if
 * there are no more paths.  Each path can be associated
 * with exactly one leaf.  Hence the ordering of paths generated by
 * this routine is the same as a left to right ordering of the leaves.
 */
path_build()
{
	Node *np, *ep;
	struct path *pp = &path[path_length-1];

	/*
	 * Assert that the end of the last path was indeed
	 * a leaf.
	 */
	assert (pp->tag == P_NODE);
	assert ((pp->node)->children == NULL);

	/*
	 * back up until we find a node that still has children
	 */
	pp--;
	while (pp >= &path[1] && pp->node==NULL) pp -= 2;

	/*
	 * If we hit the beginning of the path array, there are
	 * no more leaves and hence no more paths.
	 */
	if (pp < &path[1]) {
		/* reset path_length */
		path_length = 0;
		return(0);
	}

	/*
	 * append the new leftmost branch onto the rest of
	 * the path component list.
	 */
	pp->branch++;
	np = pp->node;
	pp->node = np->siblings;
	path_length = pp-path+1;
	path_setup(np);
	return(1);
}

/*
 * Get the next component in the path component list.
 * When the end of a path is reached, NULL is returned and
 * the next call will retrieve the first component of the next path.
 * EOF is returned if there are no more paths.
 * A return value of 1 indicates that the value returned in mi is
 * valid.
 */
int
path_getsym(mi)
	register struct machine_input *mi;
{
	if(path_ptr > &path[path_length]) {
		/*
		 * When the end of that path is passed, generate the
		 * next path.
		 */
		if(!path_build())
			return(EOF);
		path_ptr = path;
	}
	if (path_ptr == &path[path_length]) {
		/*
		 * Path_ptr just encountered the end of
		 * the path, return a marker value
		 * to notify caller.
		 */
		mi->value = 0;
		path_ptr++;
		return(NULL);
	} else if (path_ptr->tag != P_BRANCH) {
		/*
		 * Translate the right machine input value
		 */
		mi->sym = (path_ptr->node)->sym;
		switch((mi->sym)->attr) {

		case A_NODE:
			mi->value = MV_NODE((mi->sym)->unique);
			break;

		case A_LABEL:
			mi->value = MV_LABEL((mi->sym)->unique);
			break;

		default:
			assert(0);
		}
	} else {
		mi->value = MV_BRANCH(path_ptr->branch);
	}
	path_ptr++;
	return(1);
}

/*
 * Prints out path for debugging
 */
void
prpath()
{
	register int i;
	for(i=0; i < path_length; i++) {
		struct path *pp = &path[i];
		if (pp->tag==P_NODE) {
			struct node *np = pp->node;
			printf("[%s]", (np->sym)->name);
		} else {
			assert (pp->tag == P_BRANCH);
			printf("%d", pp->branch);
		}
	}
	putchar('\n');

}