#include "common"
#define ERROR	0
#define COMPARE	1
#define SHIFT	2
#define REDUCE	3
#define ACCEPT	4

#define STSIZE	40

struct token stack[STSIZE];	/* the parser stack */
int stused;			/* space used in stack */
int sthigh;			/* high water mark */

struct token *ps;	/* ps[1] is leftmost token to reduce */

copy(p) struct at *p;
	{ps[1].flags = p->flags;
	ps[1].type = p->type;
	ps[1].value = p->value;
	ps[1].bias = p->bias;
	ps[1].size = p->size;
	ps[1].prev = p->prev;
	ps[1].tbran = p->tbran;
	ps[1].fbran = p->fbran; }

int shift;			/* TRUE if next token ready */

char next()
	{if (!shift) {e.type = lex(); shift = TRUE; }
	if (e.type < KOND) return (e.type);
	return (IDENT); }

char insert[] {-1, SCOLON, COMMA, IDENT, RPAREN, RBRAK, QUOTES,
		LPAREN, WHILE, EOF, -1};

struct token f;		/* error token */

/*
int profile[STSIZE];
*/

parse() {extern int yygo[], yypgo[], yyr1[], yyr2[], yyact[], yypact[];
	extern char name[];
	int eflag, n, state, type, *ap, *gp;

	eflag = 0;
	shift = FALSE;

	stused = 0;
	stack[0].state = 0;
	ps = &stack[stused];
	state = ps[0].state;

	while (TRUE)
		{ap = &yyact[yypact[state + 1]];
		if (*ap >> 12 == COMPARE)
			{type = eflag > 0 ? f.type : next();
			do if (type != (*ap & 07777)) ap++;
				while (*++ap >> 12 == COMPARE);
			}
		n = *ap & 07777;
		switch (*ap >> 12) {
	 case ERROR:	if ((f.type = insert[++eflag]) >= 0)
				continue;
			error("syntax: %s deleted", s(&e));
			eflag = -1;
			shift = FALSE;
			continue;

	 case SHIFT:	ps[1].start = elc->value;
			ps[1].sbias = elc->bias;
			state = n;
			if (eflag)
				{copy(&f);
				error("syntax: %s added before %s",
					s(&f), s(&e));
				eflag = -1; }
			else {
				if (!skip && test(&e, DCLF))
					{e.value = add(name, 0, MEM, 0, 2);
					e.flags = 0; }
				if (debug > 1) error("shift %s", s(&e));
				copy(&e);
				eflag = 0;
				shift = FALSE;
				}
			break;

	 case REDUCE:	if (debug > 1) error("reduce %d", n);
			sthigh = stused;
			stused =- yyr2[n]; ps = &stack[stused];
			state = ps[0].state;
			yyactr(n);
			for (gp = &yygo[yypgo[yyr1[n]]];
				*gp >= 0 && *gp != state; gp =+ 2) ;
			state = *++gp; break;

	 case ACCEPT:	return;
					}
		if (stused++ >= STSIZE)
			{error("stack overflow");
			exit(TRUE); }
/*
		profile[stused]++;
*/
		(++ps)[0].state = state;
		}
	}

main(argc, argv) int argc; char *argv[];
	{struct symbol *p, *pt;
	int bad, better, i, j;
	extern int errors, hiwater, osize, shorter, longer;

	if (argc != 4 || (fin = open(argv[1], 0)) < 0
		|| (fsyms = creat(argv[2], 0666)) < 0
		|| (fcode = creat(argv[3], 0666)) < 0)
		{error("bad args");
		exit(TRUE); }

	init();		/* setup symbol table */
	add(".abs", DEFF, MEM, 0, 2);	/* first 4 entries are elcs */
	(elc = add(".text", DEFF, MEM, 0, 2))->bias = 1;
	add(".data", DEFF, MEM, 0, 2)->bias = 2;
	add(".bss", DEFF, MEM, 0, 2)->bias = 3;

	line = 1;	/* set starting line no. */
	spsave = sptop;	/* start new local region */
	settoelc(dot);	/* set dot to elc */
	parse();	/* compile */
	endlocal(NULL);	/* end new local region */
	settoelc(tlist);	/* dump pending jump targets */
	pipe(-1);	/* drain the pipe */

	pt = &symtab[spused];
	setvb(symtab, spused, 0);
	do {
		i = 0; bad = better = FALSE;
		for (p = symtab; p != pt; p++)
			{if (p->bias > 3)
				{if ((j = symtab[i].bias) <= 3)
					{p->value =+ symtab[j].value;
					p->bias = symtab[j].bias;
					better = TRUE; }
				else if (p->bias != i) bad = TRUE; }
			i++; }
		} while (bad && better);
	if (bad && !better) error("circular definitions");

	for (p = symtab; p != pt; p++)
		{write(fsyms, p->name, 8);
		i = (test(p, PUBF) ? 040 : 0) |
			(p->bias <= 3 ? p->bias + 1 : 040);
		write(fsyms, &i, 2);
		if (i == 040) write(fsyms, &(p->size), 2);
		else write(fsyms, &(p->value), 2);
		}

	if (debug)
		{select(1);
		printf("%d lines, %d table entries\n", line, spused);
	for (p = symtab; p != pt; p++)
		printf("%c%c%c%c %s = %o + %o\n",
			test(p, PUBF) ? 'g' : ' ',
			test(p, DEFF) ? 'd' : ' ',
			test(p, DCLF) ? 'l' : ' ',
			test(p, BYTF) ? 'b' : ' ',
			sn(p->name), p->value, p->bias);
/*
		printf("stack profile -");
		for (i = 0; i < STSIZE; i++) {
			if (i % 10 == 0) putchar('\n');
			printf(" %d", profile[i]); }
		putchar('\n');
*/
		printf("%d%s%d%s%d%s%d%s\n",
			osize, "-word pipe, filled to ",
			hiwater, " made ",
			shorter, " shorter, left ",
			longer, " longer");
		flush(); }
	exit(errors > 0); }

#define	v0	&ps[0]
#define	v1	&ps[1]
#define	v2	&ps[2]
#define	v3	&ps[3]
#define v4	&ps[4]

#include "tables"
