/* 
 * Some grammar independent code.
 * This file is copied into Lpars.c.
 */

# ifndef NORCSID
static char *rcsid = "$Header$";
# endif

#define LLSTSIZ	1024
static short	LLstack[LLSTSIZ];		/* Recovery stack */
short *		LLptr;				/* ptr in it */
#define		LLmax (&LLstack[LLSTSIZ-1])	/* if beyond this, overflow */
int		LLscd;				/* lookahead done or not? */
int		LLb,LLi;
int		LLsymb;
int		LLcsymb;
static int	LLlevel;
static short *	LLbase;

static struct LLsaved {
	int LLs_i, LLs_b, LLs_s, LLs_c, LLs_t;
	short *LLs_p, *LLs_x;
} LLsaved[LL_MAX];

/* In this file are defined: */
extern		LLcheck();
extern		LLscan();
extern		LLpush();
extern		LLlpush();
extern int	LLpop();
extern int	LLsskip();
static		LLerror();
extern		LLnewlevel();
extern		LLoldlevel();

LLcheck() {
	register c;
	/* 
	 * The symbol to be checked is on the stack.
	 */
	if (!LLscd) {
		if ((c = LL_LEXI()) <= 0) c = EOFILE;
		LLsymb = c;
	}
	else LLscd = 0;
	if (LLsymb == *--LLptr) return;
	/* 
	 * If we come here, an error has been detected.
	 * LLpop will try and recover
	 */
	LLptr++;
	while (LLindex[LLsymb] < 0) {
		LLerror(0);
		if ((LLsymb = LL_LEXI()) <= 0) LLsymb = EOFILE;
	}
	LLcsymb = LLindex[LLsymb];
	LLb = LLbyte[LLcsymb];
	LLi = LLcsymb>>3;
	LLscd = 1;
	if (!LLpop()) LLerror(*LLptr);
	LLscd = 0;
}

LLscan(t) {
	/*
	 * Check if the next symbol is equal to the parameter
	 */
	if (!LLscd) {
		if ((LLsymb = LL_LEXI()) <= 0) LLsymb = EOFILE;
	}
	else LLscd = 0;
	if (LLsymb == t) return;
	/*
	 * If we come here, an error has been detected
	 */
	LLpush(t);
	LLscd = 1;
	while (LLindex[LLsymb] < 0) {
		LLerror(0);
		if ((LLsymb = LL_LEXI()) <= 0) LLsymb = EOFILE;
	}
	LLcsymb = LLindex[LLsymb];
	LLb = LLbyte[LLcsymb];
	LLi = LLcsymb>>3;
	if (!LLpop()) LLerror(t);
	LLscd = 0;
}

LLpush(t) {
	if (LLptr == LLmax) {
		LLerror(-1);
	} 	
	*LLptr++ = t;
}

LLlpush(d) {
	register i;
	register short *p;
	
	p = &LLlists[d];
	i = *p++;
	while(i--) {
		if (LLptr == LLmax) {
			LLerror(-1);
		}
		*LLptr++ = *p++;
	}
}

LLsskip() {
	/*
	 * Error recovery, and not only that!
	 * Skip symbols until one is found that is on the stack.
	 * Return 1 if it is on top of the stack
	 */
	register short *t;
	register i;

	for (;;) {
		if (!LLscd) {
lab:
			if ((i = LL_LEXI()) <= 0) i = EOFILE;
			LLsymb = i;
			if ((i = LLindex[i]) < 0) {
				LLerror(0);
				goto lab;
				/*
				 * Ugly, but we want speed
			 	 * on possibly correct symbols !!
			 	 * So, no breaks out of "for (;;)"
			 	 */
			}
			LLcsymb = i;
			LLb = LLbyte[i];
			LLi = (i>>3);
			LLscd = 1;
		}
		t = LLptr-1;
		i = *t;
		if (!((i<=0 && LLsets[LLi-i]&LLb)||i==LLsymb)) {
			while (--t >= LLbase) {
				/*
			 	 * If the element on the stack is negative,
			 	 * its opposite is an index in the setarray,
			 	 * otherwise it is a terminal symbol
			 	 */
				i = *t;
				if ((i<=0&&LLsets[LLi-i]&LLb)||i==LLsymb){
					break;
				}
			}
			if (t >= LLbase) break;
			LLerror(0);
			LLscd = 0;
		}
		else {
			return 1;
		}
	}
	return t == LLptr - 1;
}

LLpop() {
	register i;

	i = LLsskip();
	LLptr--;
	return i;
}

static
LLerror(d) {

	LLmessage(d);
	if (d < 0) exit(1);
}

LLnewlevel() {
	register struct LLsaved *p;

	if (!LLlevel++) {
		LLptr = LLstack;
		LLbase = LLstack;
		LLpush(EOFILE);
	}
	else {
		if (LLlevel > LL_MAX) LLerror(-1);
		p = &LLsaved[LLlevel - 2];
		p->LLs_p = LLptr;
		p->LLs_i = LLi;
		p->LLs_b = LLb;
		p->LLs_s = LLsymb;
		p->LLs_t = LLcsymb;
		p->LLs_c = LLscd;
		p->LLs_x = LLbase;
		LLbase = LLptr;
		LLpush(EOFILE);
	}
}

LLoldlevel() {
	register struct LLsaved *p;

	LLcheck();
	if (--LLlevel) {
		p = &LLsaved[LLlevel-1]; 
		LLptr = p->LLs_p;
		LLi = p->LLs_i;
		LLb = p->LLs_b;
		LLsymb = p->LLs_s;
		LLcsymb = p->LLs_t;
		LLbase = p->LLs_x;
		LLscd = p->LLs_c;
	}
}

