# include	"ctlmod.h"
# include	<ingres.h>
# include	<aux.h>
# include	<tree.h>
# include	<symbol.h>
# include	<sccs.h>
# include	<errors.h>

SCCSID(@(#)readqry.c	8.3	12/8/85)


QTREE   *readqry();
bool	leaf();

extern QTREE	*readtree();
extern QTREE	*trbuild();
extern QTREE	*readsym();
extern char	*need();
extern char	*xalloc();
extern int      clrrange();
extern int      declare();
extern int      markbuf();
extern int      freebuf();
extern int      nodepr();

/*
** READQRY
**
** 	Reads in query symbols from input pipe into core
**	locations and sets up information needed for later 
**	processing.
**
**	Returns ptr to root of querytree
**
**	Locbuf is a 'struct srcid' since that is the largest node of
**	a QMODE, SOURCEID, or RESULTVAR node.
*/

QTREE *
readqry(rdfn, fnparam, initialize)
int	(*rdfn)();	/* tree read function */
int	fnparam;	/* parameter to pass to rdfn */
bool	initialize;	/* if set, initialize Qbuf */
{
	register QTREE	*q;
	register QTREE	*rtval;
	register DESC	*d;
	int		mark;
	int		i;
	int		j;

#	ifdef xCTR1
	if (tTf(10, 8))
		printf("READQRY:\n");
#	endif

	if (initialize)
	{
		/* initialize for new query block */
		clrrange();
		Qt.qt_resvar = -1;
		Qt.qt_qmode = -1;
	}
	for (i = 0; i < MAXRANGE; i++)
		Qt.qt_remap[i] = i;

	mark = markbuf(Qbuf);

	/* read symbols from input */
	for (;;)
	{
		freebuf(Qbuf, mark);
		q = readsym(rdfn, fnparam);
		switch (q->sym.type)
		{
		  case QMODE:
			if (Qt.qt_qmode != -1)
				syserr("readqry: two qmodes");
			Qt.qt_qmode = q->sym.value.sym_data.i2type;
			break;

		  case RESULTVAR:
			if (Qt.qt_resvar != -1)
				syserr("readqry: two resultvars");
			Qt.qt_resvar = q->sym.value.sym_data.i2type;
			break;

		  case SOURCEID:
			d = (DESC *) xalloc(sizeof *d);
			bmove((char *) &q->sym.value.sym_srcid.srcdesc, (char *) d, sizeof *d);
			i = q->sym.value.sym_srcid.srcvar;
			j = declare(i, d);
			if (j != i && initialize)
				syserr("readqry: declare(%d)=%d", i, j);
			Qt.qt_remap[i] = j;
			break;

		  case TREE:	/* beginning of tree, no more other stuff */
			q = readtree(q, rdfn, fnparam);
			rtval = trbuild(q);
			if (rtval == NULL)
				error(STACKFULL, 0);
			return (rtval);

		  default:
			syserr("readqry: bad symbol %d", q->sym.type);
		}
	}
}
/*
**  READSYM
**	reads in one symbol from pipe into symbol struct.
*/

QTREE *
readsym(rdfn, fnparam)
int	(*rdfn)();	/* tree read function */
char	*fnparam;
{
	register int	len;
	register int	t;
	register QTREE	*q;
	int		rlen;

	q = (QTREE *) need(Qbuf, QT_HDR_SIZ);
	if ((*rdfn)(fnparam, &q->sym, TYP_LEN_SIZ) < TYP_LEN_SIZ) 
		syserr("readsym: read sym");
	rlen = len = q->sym.len & I1MASK;
	t = q->sym.type;

	switch (t)
	{
	  case AND:
		if (len < 6)
			len = 6;
		break;

	  case ROOT:
	  case AGHEAD:
		if (len < 8)
			len = 8;
		break;
	}

	q->sym.len = len;


	if (len != 0)
	{
		/* this will be contiguous with above need call */
		need(Qbuf, len);
	}
	if (rlen != 0)
	{
		if ((*rdfn)(fnparam, &q->sym.value, rlen) < rlen) 
			syserr("readsym: read val (sym=%d,%d)", t, rlen);
	}

	switch (t)
	{
	  case ROOT:
		q->sym.value.sym_root.rootuser = TRUE;
		break;
	  case AGHEAD:
		q->sym.value.sym_root.rootuser = FALSE;
		break;
	}
# ifdef xCTR1
	if (tTf(10, 9))
		nodepr(q);
# endif xCTR1

	return (q);
}
/*
**  READTREE
**
** 	reads in tree symbols into a buffer up to a root (end) symbol
**
*/

QTREE *
readtree(tresym, rdfn, fnparam)
QTREE	*tresym;
int	(*rdfn)();
char	*fnparam;
{
	register QTREE	*q;
	register QTREE	*rtval;

	rtval = tresym;

	for(;;)
	{
		/* space for left & right pointers */
		q = readsym(rdfn, fnparam);
		if (q->sym.type == ROOT)
			return (rtval);
	}
}
/*
**  TRBUILD -- Rebuild a tree in memory
**
**	Trbuild is called with a pointer to the TREE node of
**	a query already in memory. It rebuilds the pointer
**	structure assuming the querytree is in postfix order.
**
**	Parameters:
**		bufptr - a pointer to the TREE node
**
**	Returns:
**		NULL - Internal stack overflow (STACKSIZ)
**		pointer to the ROOT node
**
**	Side Effects:
**		All left & right pointers are rebuilt.
**
**	Called By:
**		readqry
**
**	Syserrs:
**		syserr if there are too many leaf nodes or too
**		few child nodes
*/


QTREE *
trbuild(bufptr)
QTREE	*bufptr;
{
	register QTREE 	**stackptr;
	register char	*p;
	register SYMBOL	*s;
	QTREE		*treestack[STACKSIZ];


	stackptr = treestack;

/*XXX*/	for (p = (char *) bufptr;; p += QT_HDR_SIZ + ((s->len + 3) & 0374))
	{
		s = &((QTREE *)p)->sym;
		((QTREE *)p)->left = ((QTREE *)p)->right = 0;

		/* reunite p with left and right children on stack, if any*/
		if (!leaf((QTREE *) p))		/* this node has children */
		{
			if (s->type != UOP)
				if (stackptr <= treestack) 
				{
				err:
					syserr("trbuild:too few nodes");
				}
				else
					((QTREE *)p)->right = *(--stackptr);
			if (s->type != AOP)
				if (stackptr <= treestack) 
					goto err;
				else
					((QTREE *)p)->left = *(--stackptr);
		}

		/*
		** If this is a ROOT node then the tree is complete.
		** verify that there are no extra nodes in the
		** treestack.
		*/
		if (s->type == ROOT)	 	/* root node */
		{
			if (stackptr != treestack)
				syserr("trbuild:xtra nodes");
			return ((QTREE *)p);
		}

		/* stack p */
		if (stackptr-treestack >= STACKSIZ) 
			return (NULL);	/* error:stack full */
		*(stackptr++) = (QTREE *) p;

	}
}


bool
leaf(p)
QTREE *p;
{
	switch (p->sym.type)
	{
	  case VAR:
	  case TREE:
	  case QLEND:
	  case INT:
	  case FLOAT:
	  case CHAR:
	  case COP:
		return(TRUE);

	  default:
		return(FALSE);
	}
}
